From 3477e27021dbe9366c3c1aaba80feb72f1138b29 Mon Sep 17 00:00:00 2001 From: Martin Rudalics Date: Sun, 27 Jul 2014 15:21:30 +0200 Subject: [PATCH] Complete pixelwise frame/window resizing, add horizontal scrollbar support. * frame.el (frame-notice-user-settings): Rewrite using frame-initial-frame-tool-bar-height. * menu-bar.el (menu-bar-horizontal-scroll-bar) (menu-bar-no-horizontal-scroll-bar): New functions. (menu-bar-showhide-scroll-bar-menu): Add bindings for horizontal scroll bars. * scroll-bar.el (scroll-bar-lines) (set-horizontal-scroll-bar-mode) (get-horizontal-scroll-bar-mode, horizontal-scroll-bar-mode) (scroll-bar-horizontal-drag-1, scroll-bar-horizontal-drag) (scroll-bar-toolkit-horizontal-scroll): New functions. (horizontal-scroll-bar-mode) (previous-horizontal-scroll-bar-mode) (horizontal-scroll-bar-mode-explicit): New variables. (horizontal-scroll-bar-mode): New option. (toggle-horizontal-scroll-bar): Do something. (top-level): Bind horizontal-scroll-bar mouse-1. * startup.el (tool-bar-originally-present): Remove variable. (command-line): Don't set tool-bar-originally-present. * window.el (window-min-height): Update doc-string. (window--dump-frame): Dump horizontal scroll bar values. (window--min-size-1): Handle minibuffer window separately. Count in margins and horizontal scroll bar. Return safe value iff IGNORE equals 'safe. (frame-windows-min-size): New function (used by frame resizing routines). (fit-frame-to-buffer, fit-window-to-buffer): Count in horizontal scroll bars. (window--sanitize-window-sizes): New function. (window-split-min-size): Remove. (split-window): Count divider-width. Don't use `window-split-min-size' any more. Reword error messages. Sanitize windows sizes after splitting. * buffer.h (struct buffer): New fields scroll_bar_height and horizontal_scroll_bar_type. * buffer.c (bset_scroll_bar_height) (bset_horizontal_scroll_bar_type): New functions. (Fbuffer_swap_text): Handle old_pointm field. (init_buffer_once): Set defaults for scroll_bar_height and horizontal_scroll_bar_type. (syms_of_buffer): New variables scroll_bar_height and horizontal_scroll_bar_type. * dispextern.h (window_part): Rename ON_SCROLL_BAR to ON_VERTICAL_SCROLL_BAR. Add ON_HORIZONTAL_SCROLL_BAR. (set_vertical_scroll_bar): Remove prototype. (x_change_tool_bar_height): Add prototype. * dispnew.c (adjust_frame_glyphs_for_frame_redisplay) (window_to_frame_vpos, update_frame_1, scrolling, init_display): Use FRAME_TOTAL_COLS and FRAME_TOTAL_LINES instead of FRAME_COLS and FRAME_LINES. (adjust_frame_glyphs_for_window_redisplay): Rearrange lines. (update_window): Start mode_line_row->y after horizontal scroll bar. (change_frame_size_1): Call adjust_frame_size. (init_display): When changing the size of a tty frame do not pass height of menu bar. (Qframe_windows_min_size): New symbol. * frame.h (struct frame): List tool bar fields after menu bar fields. Add official, total_lines, horizontal_scroll_bars, config_scroll_bar_height and config_scroll_bar_lines fields. (FRAME_HAS_HORIZONTAL_SCROLL_BARS) (FRAME_CONFIG_SCROLL_BAR_HEIGHT, FRAME_CONFIG_SCROLL_BAR_LINES) (FRAME_SCROLL_BAR_AREA_HEIGHT, FRAME_SCROLL_BAR_COLS) (FRAME_SCROLL_BAR_LINES, FRAME_TOTAL_LINES, SET_FRAME_LINES) (FRAME_WINDOWS_HEIGHT): New macros. (SET_FRAME_HEIGHT, FRAME_TEXT_LINES_TO_PIXEL_HEIGHT) (FRAME_PIXEL_Y_TO_LINE, FRAME_PIXEL_HEIGHT_TO_TEXT_LINES) (FRAME_TEXT_TO_PIXEL_HEIGHT): Separately count top margin and horizontal scroll bar. (frame_inhibit_resize, adjust_frame_size) (frame_windows_min_size): Add declarations. (Qscroll_bar_height, Qhorizontal_scroll_bars) (x_set_scroll_bar_default_height, x_set_left_fringe) (x_set_right_fringe, x_set_vertical_scroll_bars) (x_set_horizontal_scroll_bars, x_set_scroll_bar_width) (x_set_scroll_bar_height): Add external declarations. * frame.c: (frame_inhibit_resize, frame_windows_min_size) (adjust_frame_size): New functions. (make_frame): Initial horizontal_scroll_bars field. Use SET_FRAME_LINES. Don't allow horizontal scroll bar in minibuffer window. (make_initial_frame, make_terminal_frame): No horizontal scroll bar in initial and terminal frames. Use adjust_frame_size. (Fframe_total_cols): Fix doc-string. (Fframe_total_lines, Fscroll_bar_height): New Lisp functions. (Fset_frame_height, Fset_frame_width, Fset_frame_size): Rewrite using adjust_frame_size. (Qscroll_bar_height, Qhorizontal_scroll_bars) (Qframe_windows_min_size): New symbols. (x_set_frame_parameters): Remove call of check_frame_size. (x_report_frame_params): Return scroll_bar_height value. (x_set_left_fringe, x_set_right_fringe): New functions. (adjust_frame_height, x_set_internal_border_width) (x_set_fringe_width): Remove. (x_set_internal_border_width, x_set_vertical_scroll_bars) (x_set_scroll_bar_width, x_set_right_divider_width) (x_set_bottom_divider_width): Rewrite using adjust_frame_size. (x_set_horizontal_scroll_bars, x_set_scroll_bar_height): New functions. (x_figure_window_size): Rewrite to make frame display the expected number of lines. (Vdefault_frame_scroll_bars): Rewrite doc-string. (Vdefault_frame_horizontal_scroll_bars) (Vframe_initial_frame_tool_bar_height) (frame_inhibit_implied_resize): New variables. * fringe.c (compute_fringe_widths): Remove. * gtkutil.h (YG_SB_MIN, YG_SB_MAX, YG_SB_RANGE): Define. (xg_create_horizontal_scroll_bar) (xg_update_horizontal_scrollbar_pos) (xg_set_toolkit_horizontal_scroll_bar_thumb) (xg_get_default_scrollbar_height) (xg_clear_under_internal_border): Extern. * gtkutil.c (xg_frame_resized): Don't call do_pending_window_change. (xg_frame_set_char_size): Use adjust_frame_size. (style_changed_cb): Call update_theme_scrollbar_height and x_set_scroll_bar_default_height. (x_wm_set_size_hint): Don't call check_frame_size. (update_theme_scrollbar_height) (xg_get_default_scrollbar_height) (xg_create_horizontal_scroll_bar) (xg_update_horizontal_scrollbar_pos) (xg_set_toolkit_horizontal_scroll_bar_thumb): New functions. (xg_create_scroll_bar): Set horizontal slot of bar. (xg_initialize): Call update_theme_scrollbar_height. (xg_clear_under_internal_border): No more static. * insdel.c (adjust_suspend_auto_hscroll): New function. (adjust_markers_for_delete, adjust_markers_for_insert) (adjust_markers_for_replace): Call adjust_suspend_auto_hscroll. * keyboard.c (readable_events, discard_mouse_events) (make_lispy_event): Handle horizontal scroll bar click events. (Fsuspend_emacs): When changing the size of a tty frame do not pass height of menu bar. (Qbefore_handle, Qhorizontal_handle, Qafter_handle, Qleft) (Qright, Qleftmost, Qrightmost): New symbols. * menu.c (Fx_popup_dialog): Use FRAME_TOTAL_LINES instead of FRAME_LINES. * minibuf.c (read_minibuf): Initialize suspend_auto_hscroll. * nsfns.m (x_set_internal_border_width): New function. * nsterm.m (ns_draw_fringe_bitmap, ns_set_vertical_scroll_bar): Remove extended fringe code. (x_set_window_size, x_new_font): Don't call compute_fringe_widths. * term.c (Fresume_tty): When changing the size of a tty frame do not pass height of menu bar. (clear_tty_hooks, set_tty_hooks): Clear horizontal_scroll_bar_hook. (init_tty): Frame has no horizontal scroll bars. * termhooks.h (enum scroll_bar_part): Add scroll_bar_move_ratio, scroll_bar_before_handle, scroll_bar_horizontal_handle, scroll_bar_after_handle, scroll_bar_left_arrow, scroll_bar_right_arrow, scroll_bar_to_leftmost and scroll_bar_to_rightmost entries. (enum event_kind): Add HORIZONTAL_SCROLL_BAR_CLICK_EVENT (struct terminal): Add set_horizontal_scroll_bar_hook. * w32console.c (initialize_w32_display): Clear horizontal_scroll_bar_hook. * w32fns.c (x_set_mouse_color): Use FRAME_W32_DISPLAY instead of FRAME_X_DISPLAY. (x_clear_under_internal_border, x_set_internal_border_width): New functions. (x_set_menu_bar_lines): Rewrite using frame_inhibit_resize. Set windows_or_buffers_changed when adding the menu bar. (x_set_tool_bar_lines): Rewrite using adjust_frame_size. (x_change_tool_bar_height, x_set_scroll_bar_default_height) (w32_createhscrollbar): New functions. (w32_createscrollbar): Rename to w32_createvscrollbar. (w32_createwindow): Init WND_HSCROLLBAR_INDEX. (w32_name_of_message): Replace WM_EMACS_CREATESCROLLBAR by WM_EMACS_CREATEVSCROLLBAR and WM_EMACS_CREATEHSCROLLBAR. Add WM_EMACS_SHOWCURSOR. (w32_wnd_proc): Handle WM_HSCROLL case. In WM_WINDOWPOSCHANGING case do not artificially impose WM size hints. Handle WM_EMACS_SHOWCURSOR case. Replace WM_EMACS_CREATESCROLLBAR case by WM_EMACS_CREATEVSCROLLBAR and WM_EMACS_CREATEHSCROLLBAR cases. (my_create_tip_window): Replace WND_SCROLLBAR_INDEX by WND_VSCROLLBAR_INDEX and WND_HSCROLLBAR_INDEX. (unwind_create_frame_1): Remove. (Fx_create_frame): Make both scrollbars the system standard width and height. Use official field of frame structure to inhibit running window-configuration-change-hook. (x_create_tip_frame): Call SET_FRAME_LINES and change_frame_size pixelwise. Handle frame's official field. (w32_frame_parm_handlers): Remove x_set_fringe_width entries. Add x_set_scroll_bar_height, x_set_horizontal_scroll_bars, x_set_left_fringe and x_set_right_fringe. * w32inevt.c (resize_event, maybe_generate_resize_event): Do not pass height of menu bar to change_frame_size. * w32menu.c (set_frame_menubar): Rewrite using frame_inhibit_resize. * w32term.h (struct w32_display_info): Add horizontal_scroll_bar_cursor and cursor_display_counter. (struct scroll_bar): Add horizontal. (HORIZONTAL_SCROLL_BAR_INSIDE_HEIGHT) (HORIZONTAL_SCROLL_BAR_LEFT_RANGE) (HORIZONTAL_SCROLL_BAR_INSIDE_WIDTH) (HORIZONTAL_SCROLL_BAR_LEFT_BORDER) (HORIZONTAL_SCROLL_BAR_RIGHT_BORDER) (HORIZONTAL_SCROLL_BAR_TOP_BORDER) (HORIZONTAL_SCROLL_BAR_BOTTOM_BORDER) (HORIZONTAL_SCROLL_BAR_MIN_HANDLE): New macros. (WM_EMACS_CREATEVSCROLLBAR, WM_EMACS_CREATEHSCROLLBAR): Define instead of WM_EMACS_CREATESCROLLBAR. (WND_VSCROLLBAR_INDEX, WND_HSCROLLBAR_INDEX): Define instead of WND_SCROLLBAR_INDEX. * w32term.c (horizontal_scroll_bar_min_handle) (horizontal_scroll_bar_left_border) (horizontal_scroll_bar_right_border): New integers. (x_set_frame_alpha): Replace x_highlight_frame by w32_focus_frame. (x_window_to_scroll_bar): New argument "type". Update callers accordingly. (w32_set_horizontal_scroll_bar_thumb) (x_horizontal_scroll_bar_report_motion) (w32_set_horizontal_scroll_bar) (w32_horizontal_scroll_bar_handle_click) (x_horizontal_scroll_bar_report_motion): New functions. (w32_mouse_position): Discriminate horizontal and vertical scrollbar cases. (my_create_scrollbar): Replace with two new functions my_create_vscrollbar and my_create_hscrollbar. (x_scroll_bar_create): New argument "horizontal". Update callers accordingly. (x_scroll_bar_remove, w32_condemn_scroll_bars) (w32_redeem_scroll_bar, x_scroll_bar_clear): Handle horizontal scroll bar case. (w32_read_socket): Handle WM_HSCROLL cae. (x_new_font): Don't recompute fringe widths. Use frame_inhibit_resize. Calculate new menu bar height iff we build without toolkit. Always clear under internal border. (x_set_window_size): Don't check frame size or recompute fringes. Reset fullscreen status before applying sizes. Always resize as requested by pixelwise argument. Don't call do_pending_window_change. (x_wm_set_size_hint): Add call for FRAME_SCROLL_BAR_AREA_HEIGHT. (w32_initialize_display_info): Initialize dpyinfo's horizontal_scroll_bar_cursor entry. (w32_create_terminal): Add set_horizontal_scroll_bar_hook. (w32_initialize): Init horizontal_scroll_bar_min_handle and horizontal_scroll_bar_left_border. (w32fullscreen_hook): Intermittently resize window to normal when switching from fullscreen to maximized state. (run_window_configuration_change_hook): Don't run it if frame is not official yet. (unwind_change_frame): Remove. (Fset_window_configuration): Rewrite using frame's official field. * widget.c (set_frame_size): Don't call compute_fringe_widths. (EmacsFrameSetCharSize): Obey frame_inhibit_resize. * window.h (struct window): New fields old_pointm, horizontal_scroll_bar, horizontal_scroll_bar_type, hscroll_whole, scroll_bar_height and suspend_auto_hscroll. (wset_horizontal_scroll_bar, wset_horizontal_scroll_bar_type): New functions. (sanitize_window_sizes): Extern. (MINI_NON_ONLY_WINDOW_P, MINI_ONLY_WINDOW_P, WINDOW_PSEUDO_P) (WINDOW_TOPMOST_P, WINDOW_HAS_HORIZONTAL_SCROLL_BAR) (WINDOW_CONFIG_SCROLL_BAR_HEIGHT) (WINDOW_CONFIG_SCROLL_BAR_LINES) (WINDOW_SCROLL_BAR_LINES, WINDOW_SCROLL_BAR_AREA_HEIGHT): New macros. (WINDOW_LEFT_FRINGE_COLS, WINDOW_RIGHT_FRINGE_COLS) (WINDOW_FRINGE_COLS, WINDOW_FRINGE_EXTENDED_P): Remove macros. (WINDOW_VERTICAL_SCROLL_BAR_TYPE) (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT) (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT) (WINDOW_HAS_VERTICAL_SCROLL_BAR): Minor rewrite. (WINDOW_BOX_HEIGHT_NO_MODE_LINE, WINDOW_BOX_TEXT_HEIGHT) (WINDOW_SCROLL_BAR_AREA_Y): Count in scroll bar height. * window.c (wset_old_pointm, Fwindow_scroll_bar_height) (Fwindow_old_point, sanitize_window_sizes): New functions. (Qwindow_sanitize_window_sizes): New symbol. (window_body_height): Count in horizontal scroll bar. (set_window_hscroll, Fscroll_left, Fscroll_right): Set suspend_auto_hscroll slot. (Fwindow_inside_edges): Count fringes pixelwise. (coordinates_in_window, Fcoordinates_in_window_p): Consider horizontal scroll bar. (check_frame_size, adjust_window_margins): Remove functions and corresponding calls. (set_window_buffer): Initialize old_pointm and horizontal scroll bars. (temp_output_buffer_show): Reset hscroll related fields. Initialize old_pointm. (make_parent_window): Initialize old_pointm. (make_window): Initialize old_pointm, horizontal scroll bar type, and scroll bar height. (resize_frame_windows): Don't count top margin in new sizes. Don't use safe sizes when shrinking a frame; let the window manager do the clipping. (Fsplit_window_internal): Inherit horizontal scroll bar type and height. (Fdelete_window_internal): Unchain old_pointm marker. (window_scroll_pixel_based, Fscroll_other_window): Adjust old_pointm. (Fwindow_text_width, Fwindow_text_height): New argument "pixelwise". (struct saved_window): New fields, old_pointm, hscroll_whole, suspend_auto_hscroll, scroll_bar_height and horizontal_scroll_bar_type. (Fset_window_configuration, save_window_save): Set new fields of saved_window. (apply_window_adjustment): Don't call adjust_window_margins. (set_window_margins): Don't change margins if new sizes don't fit into window. (set_window_scroll_bars): New argument "horizontal_type". Handle horizontal scroll bars. Don't change scroll bars if they don't fit into window. (Fset_window_scroll_bars): New argument "horizontal_type". (Fwindow_scroll_bars): Return values for horizontal scroll bars. (compare_window_configurations): Compare horizontal scroll bar settings. * xdisp.c (window_text_bottom_y, window_box_height): Count in horizontal scroll bar height. (pixel_to_glyph_coords, init_xdisp): Use FRAME_TOTAL_LINES instead of FRAME_LINES. (remember_mouse_glyph): Case ON_SCROLL_BAR changed to ON_VERTICAL_SCROLL_BAR. (with_echo_area_buffer): Initialize old_pointm. (with_echo_area_buffer_unwind_data): Store old_pointm values in vector. (unwind_with_echo_area_buffer): Handle old_pointm. (update_tool_bar): Set do_update when the tool bar window has at least one line (since this is what the user sets). (MAX_FRAME_TOOL_BAR_HEIGHT): Remove macro. (redisplay_tool_bar): Return early when toolbar has zero lines. Call x_change_tool_bar_height. Don't use max_tool_bar_height. (hscroll_window_tree): Handle suspension of auto_hscroll and old_pointm. (set_horizontal_scroll_bar): New function. (redisplay_window): Set ignore_mouse_drag_p when tool bar has more than one line. Handle horizontal scroll bars. (note_mouse_highlight): Handle horizontal scrol bars. (expose_frame): Set dimensions of XRectangle from frame's text sizes. (Vvoid_text_area_pointer): Update doc-string. * xfns.c (x_set_menu_bar_lines): Use adjust_frame_size. (x_change_tool_bar_height, x_set_scroll_bar_default_height) (x_set_internal_border_width): New functions. (x_set_tool_bar_lines): Call x_change_tool_bar_height. (unwind_create_frame_1): Remove. (Fx_create_frame): Handle horizontal scroll bars. Use official field of frame structure to inhibit running window-configuration-change-hook. (x_create_tip_frame): Call SET_FRAME_LINES and change_frame_size pixelwise. Handle frame's official field. (x_frame_parm_handlers): Add x_set_scroll_bar_height, x_set_horizontal_scroll_bars, x_set_left_fringe, x_set_right_fringe. * xmenu.c (update_frame_menubar, free_frame_menubar): Use adjust_frame_size. * xterm.h (struct x_display_info): Add horizontal_scroll_bar_cursor and Xatom_Horizontal_Scrollbar slots. (struct scroll_bar): Add horizontal slot. (HORIZONTAL_SCROLL_BAR_INSIDE_HEIGHT) (HORIZONTAL_SCROLL_BAR_LEFT_RANGE) (HORIZONTAL_SCROLL_BAR_INSIDE_WIDTH): New macros. (HORIZONTAL_SCROLL_BAR_LEFT_BORDER) (HORIZONTAL_SCROLL_BAR_RIGHT_BORDER) (HORIZONTAL_SCROLL_BAR_TOP_BORDER) (HORIZONTAL_SCROLL_BAR_BOTTOM_BORDER) (HORIZONTAL_SCROLL_BAR_MIN_HANDLE): Define. (x_clear_under_internal_border): Remove. * xterm.c (XTmouse_position): Handle horizontal scroll bars. (x_window_to_scroll_bar): New argument TYPE. Update callers. (x_send_scroll_bar_event, x_scroll_bar_create): New arguments HORIZONTAL. Update callers. (horizontal_action_hook_id): New action hook id. (x_horizontal_scroll_bar_to_input_event) (x_create_horizontal_toolkit_scroll_bar) (xt_horizontal_action_hook) (x_set_toolkit_horizontal_scroll_bar_thumb) (XTset_horizontal_scroll_bar, x_net_wm_state) (x_horizontal_scroll_bar_report_motion): New functions. (xg_scroll_callback, x_scroll_bar_handle_click): Handle horizontal scroll bars. (SCROLL_BAR_HORIZONTAL_NAME): Define. (XTset_vertical_scroll_bar): Attempt to clear areas not covered by scroll bar. (XTcondemn_scroll_bars, XTredeem_scroll_bar): Rewrite. Handle horizontal scroll bars. (handle_one_xevent): Handle horizontal scroll bar events. Call x_net_wm_state. (x_set_window_size_1, x_wm_set_size_hint): Don't call check_frame_size. (x_set_window_size): Don't call check_frame_size and do_pending_window_change. (x_term_init): Init horizontal_scroll_bar_cursor display info. (x_create_terminal): Add set_horizontal_scroll_bar_hook. (x_scroll_bar_set_handle): Add some checks when calling x_clear_area. --- lisp/ChangeLog | 36 ++ lisp/frame.el | 77 ++-- lisp/menu-bar.el | 36 +- lisp/scroll-bar.el | 236 ++++++++-- lisp/startup.el | 15 - lisp/window.el | 104 +++-- src/ChangeLog | 363 +++++++++++++++ src/buffer.c | 42 +- src/buffer.h | 7 +- src/dispextern.h | 7 +- src/dispnew.c | 241 +++------- src/eval.c | 6 +- src/frame.c | 809 ++++++++++++++++++++++----------- src/frame.h | 288 +++++++----- src/fringe.c | 92 ---- src/gtkutil.c | 220 ++++++++- src/gtkutil.h | 21 +- src/insdel.c | 22 + src/keyboard.c | 56 ++- src/minibuf.c | 1 + src/nsfns.m | 47 +- src/nsterm.h | 35 +- src/nsterm.m | 213 +++++---- src/term.c | 4 +- src/termhooks.h | 32 +- src/w32console.c | 1 + src/w32fns.c | 348 +++++++++------ src/w32inevt.c | 7 +- src/w32menu.c | 3 +- src/w32term.c | 615 +++++++++++++++++++------ src/w32term.h | 103 +++-- src/widget.c | 19 +- src/window.c | 824 +++++++++++++++++++++++++++------- src/window.h | 297 +++++++----- src/xdisp.c | 189 +++++--- src/xfns.c | 263 ++++++----- src/xmenu.c | 23 +- src/xterm.c | 1068 ++++++++++++++++++++++++++++++++++++++------ src/xterm.h | 48 +- 39 files changed, 4966 insertions(+), 1852 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 454dc823ef7..3f97396ca02 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,39 @@ +2014-07-27 Martin Rudalics + + * frame.el (frame-notice-user-settings): Rewrite using + frame-initial-frame-tool-bar-height. + * menu-bar.el (menu-bar-horizontal-scroll-bar) + (menu-bar-no-horizontal-scroll-bar): New functions. + (menu-bar-showhide-scroll-bar-menu): Add bindings for horizontal + scroll bars. + * scroll-bar.el (scroll-bar-lines) + (set-horizontal-scroll-bar-mode) + (get-horizontal-scroll-bar-mode, horizontal-scroll-bar-mode) + (scroll-bar-horizontal-drag-1, scroll-bar-horizontal-drag) + (scroll-bar-toolkit-horizontal-scroll): New functions. + (horizontal-scroll-bar-mode) + (previous-horizontal-scroll-bar-mode) + (horizontal-scroll-bar-mode-explicit): New variables. + (horizontal-scroll-bar-mode): New option. + (toggle-horizontal-scroll-bar): Do something. + (top-level): Bind horizontal-scroll-bar mouse-1. + * startup.el (tool-bar-originally-present): Remove variable. + (command-line): Don't set tool-bar-originally-present. + * window.el (window-min-height): Update doc-string. + (window--dump-frame): Dump horizontal scroll bar values. + (window--min-size-1): Handle minibuffer window separately. + Count in margins and horizontal scroll bar. Return safe value + iff IGNORE equals 'safe. + (frame-windows-min-size): New function (used by frame resizing + routines). + (fit-frame-to-buffer, fit-window-to-buffer): Count in horizontal + scroll bars. + (window--sanitize-window-sizes): New function. + (window-split-min-size): Remove. + (split-window): Count divider-width. Don't use + `window-split-min-size' any more. Reword error messages. + Sanitize windows sizes after splitting. + 2014-07-27 Thien-Thi Nguyen Use `defvar-local' more. diff --git a/lisp/frame.el b/lisp/frame.el index 9a170134e3d..d3e84d21024 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -256,60 +256,43 @@ there (in decreasing order of priority)." ;; If the initial frame is still around, apply initial-frame-alist ;; and default-frame-alist to it. (when (frame-live-p frame-initial-frame) - ;; When tool-bar has been switched off, correct the frame size ;; by the lines added in x-create-frame for the tool-bar and ;; switch `tool-bar-mode' off. (when (display-graphic-p) - (let ((tool-bar-lines (or (assq 'tool-bar-lines initial-frame-alist) - (assq 'tool-bar-lines window-system-frame-alist) - (assq 'tool-bar-lines default-frame-alist)))) - (when (and tool-bar-originally-present - (or (null tool-bar-lines) - (null (cdr tool-bar-lines)) - (eq 0 (cdr tool-bar-lines)))) - (let* ((char-height (frame-char-height frame-initial-frame)) - (image-height tool-bar-images-pixel-height) - (margin (cond ((and (consp tool-bar-button-margin) - (integerp (cdr tool-bar-button-margin)) - (> tool-bar-button-margin 0)) - (cdr tool-bar-button-margin)) - ((and (integerp tool-bar-button-margin) - (> tool-bar-button-margin 0)) - tool-bar-button-margin) - (t 0))) - (relief (if (and (integerp tool-bar-button-relief) - (> tool-bar-button-relief 0)) - tool-bar-button-relief 3)) - (lines (/ (+ image-height - (* 2 margin) - (* 2 relief) - (1- char-height)) - char-height)) - (height (frame-parameter frame-initial-frame 'height)) - (newparms (list (cons 'height (- height lines)))) - (initial-top (cdr (assq 'top - frame-initial-geometry-arguments))) + (let ((tool-bar-lines + (or (assq 'tool-bar-lines initial-frame-alist) + (assq 'tool-bar-lines window-system-frame-alist) + (assq 'tool-bar-lines default-frame-alist)))) + ;; Shrink frame by its initial tool bar height iff either zero + ;; tool bar lines have been requested in one of the frame's + ;; alists or tool bar mode has been turned off explicitly in + ;; the user's init file. + (when (and tool-bar-lines + (> frame-initial-frame-tool-bar-height 0) + (or (not tool-bar-mode) + (null (cdr tool-bar-lines)) + (eq 0 (cdr tool-bar-lines)))) + (set-frame-height + frame-initial-frame (- (frame-text-height frame-initial-frame) + frame-initial-frame-tool-bar-height) + nil t) + (let* ((initial-top + (cdr (assq 'top frame-initial-geometry-arguments))) (top (frame-parameter frame-initial-frame 'top))) (when (and (consp initial-top) (eq '- (car initial-top))) (let ((adjusted-top - (cond ((and (consp top) - (eq '+ (car top))) - (list '+ - (+ (cadr top) - (* lines char-height)))) - ((and (consp top) - (eq '- (car top))) - (list '- - (- (cadr top) - (* lines char-height)))) - (t (+ top (* lines char-height)))))) - (setq newparms - (append newparms - `((top . ,adjusted-top)) - nil)))) - (modify-frame-parameters frame-initial-frame newparms) - (tool-bar-mode -1))))) + (cond + ((and (consp top) (eq '+ (car top))) + (list '+ (+ (cadr top) + frame-initial-frame-tool-bar-height))) + ((and (consp top) (eq '- (car top))) + (list '- (- (cadr top) + frame-initial-frame-tool-bar-height))) + (t (+ top frame-initial-frame-tool-bar-height))))) + (modify-frame-parameters + frame-initial-frame '((top . adjusted-top)))))) + (tool-bar-mode -1)))) ;; The initial frame we create above always has a minibuffer. ;; If the user wants to remove it, or make it a minibuffer-only diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el index c816488c6d1..5ad4bed49b8 100644 --- a/lisp/menu-bar.el +++ b/lisp/menu-bar.el @@ -887,8 +887,35 @@ by \"Save Options\" in Custom buffers.") (interactive) (customize-set-variable 'scroll-bar-mode nil)) +(defun menu-bar-horizontal-scroll-bar () + "Display horizontal scroll bars on each window." + (interactive) + (customize-set-variable 'horizontal-scroll-bar-mode t)) + +(defun menu-bar-no-horizontal-scroll-bar () + "Turn off horizontal scroll bars." + (interactive) + (customize-set-variable 'horizontal-scroll-bar-mode nil)) + (defvar menu-bar-showhide-scroll-bar-menu (let ((menu (make-sparse-keymap "Scroll-bar"))) + (bindings--define-key menu [horizontal] + '(menu-item "Horizontal" + menu-bar-horizontal-scroll-bar + :help "Horizontal scroll bar" + :visible (display-graphic-p) + :button (:radio . (eq (cdr (assq 'horizontal-scroll-bars + (frame-parameters))) + t)))) + + (bindings--define-key menu [none-horizontal] + '(menu-item "None-horizontal" + menu-bar-no-horizontal-scroll-bar + :help "Turn off horizontal scroll bars" + :visible (display-graphic-p) + :button (:radio . (eq (cdr (assq 'horizontal-scroll-bars + (frame-parameters))) + nil)))) (bindings--define-key menu [right] '(menu-item "On the Right" @@ -896,7 +923,8 @@ by \"Save Options\" in Custom buffers.") :help "Scroll-bar on the right side" :visible (display-graphic-p) :button (:radio . (eq (cdr (assq 'vertical-scroll-bars - (frame-parameters))) 'right)))) + (frame-parameters))) + 'right)))) (bindings--define-key menu [left] '(menu-item "On the Left" @@ -904,7 +932,8 @@ by \"Save Options\" in Custom buffers.") :help "Scroll-bar on the left side" :visible (display-graphic-p) :button (:radio . (eq (cdr (assq 'vertical-scroll-bars - (frame-parameters))) 'left)))) + (frame-parameters))) + 'left)))) (bindings--define-key menu [none] '(menu-item "None" @@ -912,7 +941,8 @@ by \"Save Options\" in Custom buffers.") :help "Turn off scroll-bar" :visible (display-graphic-p) :button (:radio . (eq (cdr (assq 'vertical-scroll-bars - (frame-parameters))) nil)))) + (frame-parameters))) + nil)))) menu)) (defun menu-bar-frame-for-menubar () diff --git a/lisp/scroll-bar.el b/lisp/scroll-bar.el index 2990e8e5ffa..09f30d5d3f0 100644 --- a/lisp/scroll-bar.el +++ b/lisp/scroll-bar.el @@ -70,16 +70,36 @@ SIDE must be the symbol `left' or `right'." (frame-char-width))) (0)))) +(defun scroll-bar-lines () + "Return the height, measured in lines, of the horizontal scrollbar." + (let* ((wsb (window-scroll-bars)) + (htype (nth 5 wsb)) + (lines (nth 4 wsb))) + (cond + (htype lines) + ((frame-parameter nil 'horizontal-scroll-bars) + ;; nil means it's a non-toolkit scroll bar (which is currently + ;; impossible), and its width in columns is 14 pixels rounded up. + (ceiling (or (frame-parameter nil 'scroll-bar-height) 14) + (frame-char-width))) + (0)))) + ;;;; Helpful functions for enabling and disabling scroll bars. (defvar scroll-bar-mode) +(defvar horizontal-scroll-bar-mode) (defvar previous-scroll-bar-mode nil) +(defvar previous-horizontal-scroll-bar-mode nil) (defvar scroll-bar-mode-explicit nil "Non-nil means `set-scroll-bar-mode' should really do something. This is nil while loading `scroll-bar.el', and t afterward.") +(defvar horizontal-scroll-bar-mode-explicit nil + "Non-nil means `set-horizontal-scroll-bar-mode' should really do something. +This is nil while loading `scroll-bar.el', and t afterward.") + (defun set-scroll-bar-mode (value) "Set the scroll bar mode to VALUE and put the new value into effect. See the `scroll-bar-mode' variable for possible values to use." @@ -92,6 +112,18 @@ See the `scroll-bar-mode' variable for possible values to use." (modify-all-frames-parameters (list (cons 'vertical-scroll-bars scroll-bar-mode))))) +(defun set-horizontal-scroll-bar-mode (value) + "Set the horizontal scroll bar mode to VALUE and put the new value into effect. +See the `horizontal-scroll-bar-mode' variable for possible values to use." + (if horizontal-scroll-bar-mode + (setq previous-horizontal-scroll-bar-mode horizontal-scroll-bar-mode)) + + (setq horizontal-scroll-bar-mode value) + + (when horizontal-scroll-bar-mode-explicit + (modify-all-frames-parameters (list (cons 'horizontal-scroll-bars + horizontal-scroll-bar-mode))))) + (defcustom scroll-bar-mode default-frame-scroll-bars "Specify whether to have vertical scroll bars, and on which side. Possible values are nil (no scroll bars), `left' (scroll bars on left) @@ -108,14 +140,32 @@ Setting the variable with a customization buffer also takes effect." :initialize 'custom-initialize-default :set (lambda (_sym val) (set-scroll-bar-mode val))) +(defcustom horizontal-scroll-bar-mode default-frame-horizontal-scroll-bars + "Specify whether to have horizontal scroll bars, and on which side. +To set this variable in a Lisp program, use `set-horizontal-scroll-bar-mode' +to make it take real effect. +Setting the variable with a customization buffer also takes effect." + :type '(choice (const :tag "none (nil)" nil) + (const t)) + :group 'frames + ;; The default value for :initialize would try to use :set + ;; when processing the file in cus-dep.el. + :initialize 'custom-initialize-default + :set (lambda (_sym val) (set-horizontal-scroll-bar-mode val))) + ;; We just set scroll-bar-mode, but that was the default. ;; If it is set again, that is for real. (setq scroll-bar-mode-explicit t) +(setq horizontal-scroll-bar-mode-explicit t) (defun get-scroll-bar-mode () (declare (gv-setter set-scroll-bar-mode)) scroll-bar-mode) +(defun get-horizontal-scroll-bar-mode () + (declare (gv-setter set-horizontal-scroll-bar-mode)) + horizontal-scroll-bar-mode) + (define-minor-mode scroll-bar-mode "Toggle vertical scroll bars on all frames (Scroll Bar mode). With a prefix argument ARG, enable Scroll Bar mode if ARG is @@ -126,8 +176,21 @@ This command applies to all frames that exist and frames to be created in the future." :variable ((get-scroll-bar-mode) . (lambda (v) (set-scroll-bar-mode - (if v (or previous-scroll-bar-mode - default-frame-scroll-bars)))))) + (if v (or previous-scroll-bar-mode + default-frame-scroll-bars)))))) + +(define-minor-mode horizontal-scroll-bar-mode + "Toggle horizontal scroll bars on all frames (Horizontal Scroll Bar mode). +With a prefix argument ARG, enable Horizontal Scroll Bar mode if +ARG is positive, and disable it otherwise. If called from Lisp, +enable the mode if ARG is omitted or nil. + +This command applies to all frames that exist and frames to be +created in the future." + :variable ((get-horizontal-scroll-bar-mode) + . (lambda (v) (set-horizontal-scroll-bar-mode + (if v (or previous-scroll-bar-mode + default-frame-horizontal-scroll-bars)))))) (defun toggle-scroll-bar (arg) "Toggle whether or not the selected frame has vertical scroll bars. @@ -147,12 +210,21 @@ when they are turned on; if it is nil, they go on the left." (if (> arg 0) (or scroll-bar-mode default-frame-scroll-bars)))))) -(defun toggle-horizontal-scroll-bar (_arg) +(defun toggle-horizontal-scroll-bar (arg) "Toggle whether or not the selected frame has horizontal scroll bars. -With arg, turn horizontal scroll bars on if and only if arg is positive. -Horizontal scroll bars aren't implemented yet." +With arg, turn horizontal scroll bars on if and only if arg is positive." (interactive "P") - (error "Horizontal scroll bars aren't implemented yet")) + (if (null arg) + (setq arg + (if (cdr (assq 'horizontal-scroll-bars + (frame-parameters (selected-frame)))) + -1 1)) + (setq arg (prefix-numeric-value arg))) + (modify-frame-parameters + (selected-frame) + (list (cons 'horizontal-scroll-bars + (if (> arg 0) + (or horizontal-scroll-bar-mode default-frame-horizontal-scroll-bars)))))) ;;;; Buffer navigation using the scroll bar. @@ -249,6 +321,45 @@ If you click outside the slider, the window scrolls to bring the slider there." (with-current-buffer (window-buffer window) (setq point-before-scroll before-scroll)))) +;; Scroll the window to the proper position for EVENT. +(defun scroll-bar-horizontal-drag-1 (event) + (let* ((start-position (event-start event)) + (window (nth 0 start-position)) + (portion-whole (nth 2 start-position)) + (unit (frame-char-width (window-frame window)))) + (set-window-hscroll + window (/ (1- (+ (car portion-whole) unit)) unit)))) + +(defun scroll-bar-horizontal-drag (event) + "Scroll the window horizontally by dragging the scroll bar slider. +If you click outside the slider, the window scrolls to bring the slider there." + (interactive "e") + (let* (done + (echo-keystrokes 0) + (end-position (event-end event)) + (window (nth 0 end-position)) + (before-scroll)) + (with-current-buffer (window-buffer window) + (setq before-scroll point-before-scroll)) + (save-selected-window + (select-window window) + (setq before-scroll + (or before-scroll (point)))) + (scroll-bar-horizontal-drag-1 event) + (track-mouse + (while (not done) + (setq event (read-event)) + (if (eq (car-safe event) 'mouse-movement) + (setq event (read-event))) + (cond ((eq (car-safe event) 'scroll-bar-movement) + (scroll-bar-horizontal-drag-1 event)) + (t + ;; Exit when we get the drag event; ignore that event. + (setq done t))))) + (sit-for 0) + (with-current-buffer (window-buffer window) + (setq point-before-scroll before-scroll)))) + (defun scroll-bar-scroll-down (event) "Scroll the window's top line down to the location of the scroll bar click. EVENT should be a scroll bar click." @@ -300,47 +411,92 @@ EVENT should be a scroll bar click." (window (nth 0 end-position)) (part (nth 4 end-position)) before-scroll) - (cond ((eq part 'end-scroll)) - (t - (with-current-buffer (window-buffer window) - (setq before-scroll point-before-scroll)) - (save-selected-window - (select-window window) - (setq before-scroll (or before-scroll (point))) - (cond ((eq part 'above-handle) - (scroll-up '-)) - ((eq part 'below-handle) - (scroll-up nil)) - ((eq part 'ratio) - (let* ((portion-whole (nth 2 end-position)) - (lines (scroll-bar-scale portion-whole - (1- (window-height))))) - (scroll-up (cond ((not (zerop lines)) lines) - ((< (car portion-whole) 0) -1) - (t 1))))) - ((eq part 'up) - (scroll-up -1)) - ((eq part 'down) - (scroll-up 1)) - ((eq part 'top) - (set-window-start window (point-min))) - ((eq part 'bottom) - (goto-char (point-max)) - (recenter)) - ((eq part 'handle) - (scroll-bar-drag-1 event)))) - (sit-for 0) - (with-current-buffer (window-buffer window) - (setq point-before-scroll before-scroll)))))) - + (cond + ((eq part 'end-scroll)) + (t + (with-current-buffer (window-buffer window) + (setq before-scroll point-before-scroll)) + (save-selected-window + (select-window window) + (setq before-scroll (or before-scroll (point))) + (cond + ((eq part 'above-handle) + (scroll-up '-)) + ((eq part 'below-handle) + (scroll-up nil)) + ((eq part 'ratio) + (let* ((portion-whole (nth 2 end-position)) + (lines (scroll-bar-scale portion-whole + (1- (window-height))))) + (scroll-up (cond ((not (zerop lines)) lines) + ((< (car portion-whole) 0) -1) + (t 1))))) + ((eq part 'up) + (scroll-up -1)) + ((eq part 'down) + (scroll-up 1)) + ((eq part 'top) + (set-window-start window (point-min))) + ((eq part 'bottom) + (goto-char (point-max)) + (recenter)) + ((eq part 'handle) + (scroll-bar-drag-1 event)))) + (sit-for 0) + (with-current-buffer (window-buffer window) + (setq point-before-scroll before-scroll)))))) +(defun scroll-bar-toolkit-horizontal-scroll (event) + (interactive "e") + (let* ((end-position (event-end event)) + (window (nth 0 end-position)) + (part (nth 4 end-position)) + before-scroll) + (cond + ((eq part 'end-scroll)) + (t + (with-current-buffer (window-buffer window) + (setq before-scroll point-before-scroll)) + (save-selected-window + (select-window window) + (setq before-scroll (or before-scroll (point))) + (cond + ((eq part 'before-handle) + (scroll-right 4)) + ((eq part 'after-handle) + (scroll-left 4)) + ((eq part 'ratio) + (let* ((portion-whole (nth 2 end-position)) + (columns (scroll-bar-scale portion-whole + (1- (window-width))))) + (scroll-right + (cond + ((not (zerop columns)) + columns) + ((< (car portion-whole) 0) -1) + (t 1))))) + ((eq part 'left) + (scroll-right 1)) + ((eq part 'right) + (scroll-left 1)) + ((eq part 'leftmost) + (goto-char (line-beginning-position))) + ((eq part 'rightmost) + (goto-char (line-end-position))) + ((eq part 'horizontal-handle) + (scroll-bar-horizontal-drag-1 event)))) + (sit-for 0) + (with-current-buffer (window-buffer window) + (setq point-before-scroll before-scroll)))))) ;;;; Bindings. ;; For now, we'll set things up to work like xterm. (cond ((and (boundp 'x-toolkit-scroll-bars) x-toolkit-scroll-bars) (global-set-key [vertical-scroll-bar mouse-1] - 'scroll-bar-toolkit-scroll)) + 'scroll-bar-toolkit-scroll) + (global-set-key [horizontal-scroll-bar mouse-1] + 'scroll-bar-toolkit-horizontal-scroll)) (t (global-set-key [vertical-scroll-bar mouse-1] 'scroll-bar-scroll-up) diff --git a/lisp/startup.el b/lisp/startup.el index d984e6269ae..144d732272f 100644 --- a/lisp/startup.el +++ b/lisp/startup.el @@ -719,9 +719,6 @@ It is the default value of the variable `top-level'." (defconst tool-bar-images-pixel-height 24 "Height in pixels of images in the tool-bar.") -(defvar tool-bar-originally-present nil - "Non-nil if tool-bars are present before user and site init files are read.") - (defvar handle-args-function-alist '((nil . tty-handle-args)) "Functions for processing window-system dependent command-line arguments. Window system startup files should add their own function to this @@ -1042,18 +1039,6 @@ please check its value") (or (eq initial-window-system 'pc) (tty-register-default-colors)) - ;; Record whether the tool-bar is present before the user and site - ;; init files are processed. frame-notice-user-settings uses this - ;; to determine if the tool-bar has been disabled by the init files, - ;; and the frame needs to be resized. - (when (fboundp 'frame-notice-user-settings) - (let ((tool-bar-lines (or (assq 'tool-bar-lines initial-frame-alist) - (assq 'tool-bar-lines default-frame-alist)))) - (setq tool-bar-originally-present - (and tool-bar-lines - (cdr tool-bar-lines) - (not (eq 0 (cdr tool-bar-lines))))))) - (let ((old-scalable-fonts-allowed scalable-fonts-allowed) (old-face-ignored-fonts face-ignored-fonts)) diff --git a/lisp/window.el b/lisp/window.el index e1c79659773..a7dcd9a6612 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -378,9 +378,9 @@ Anything less might crash Emacs.") (defcustom window-min-height 4 "The minimum total height, in lines, of any window. The value has to accommodate one text line, a mode and header -line, and a bottom divider, if present. A value less than -`window-safe-min-height' is ignored. The value of this variable -is honored when windows are resized or split. +line, a horizontal scroll bar and a bottom divider, if present. +A value less than `window-safe-min-height' is ignored. The value +of this variable is honored when windows are resized or split. Applications should never rebind this variable. To resize a window to a height less than the one specified here, an @@ -1137,11 +1137,12 @@ dumping to it." (format "frame text pixel: %s x %s cols/lines: %s x %s\n" (frame-text-width frame) (frame-text-height frame) (frame-text-cols frame) (frame-text-lines frame)) - (format "tool: %s scroll: %s fringe: %s border: %s right: %s bottom: %s\n\n" + (format "tool: %s scroll: %s/%s fringe: %s border: %s right: %s bottom: %s\n\n" (if (fboundp 'tool-bar-height) (tool-bar-height frame t) "0") (frame-scroll-bar-width frame) + (frame-scroll-bar-height frame) (frame-fringe-width frame) (frame-border-width frame) (frame-right-divider-width frame) @@ -1262,12 +1263,14 @@ of WINDOW." value) (with-current-buffer (window-buffer window) (cond + ((window-minibuffer-p window) + (if pixelwise (frame-char-height (window-frame window)) 1)) ((and (not (window--size-ignore-p window ignore)) (window-size-fixed-p window horizontal)) ;; The minimum size of a fixed size window is its size. (window-size window horizontal pixelwise)) - ((or (eq ignore 'safe) (eq ignore window)) - ;; If IGNORE equals `safe' or WINDOW return the safe values. + ((eq ignore 'safe) + ;; If IGNORE equals `safe' return the safe value. (window-safe-min-size window horizontal pixelwise)) (horizontal ;; For the minimum width of a window take fringes and @@ -1278,8 +1281,11 @@ of WINDOW." ;; `window-min-width'. (let* ((char-size (frame-char-size window t)) (fringes (window-fringes window)) + (margins (window-margins window)) (pixel-width (+ (window-safe-min-size window t t) + (* (or (car margins) 0) char-size) + (* (or (cdr margins) 0) char-size) (car fringes) (cadr fringes) (window-scroll-bar-width window) (window-right-divider-width window)))) @@ -1301,6 +1307,7 @@ of WINDOW." (pixel-height (+ (window-safe-min-size window nil t) (window-header-line-height window) + (window-scroll-bar-height window) (window-mode-line-height window) (window-bottom-divider-width window)))) (if pixelwise @@ -1508,6 +1515,18 @@ by which WINDOW can be shrunk." (window--min-delta-1 window (- size minimum) horizontal ignore trail noup pixelwise))))) +(defun frame-windows-min-size (&optional frame horizontal pixelwise) + "Return minimum number of lines of FRAME's windows. +HORIZONTAL non-nil means return number of columns of FRAME's +windows. PIXELWISE non-nil means return sizes in pixels." + (setq frame (window-normalize-frame frame)) + (let* ((root (frame-root-window frame)) + (mini (window-next-sibling root))) + (+ (window-min-size root horizontal nil pixelwise) + (if (and mini (not horizontal)) + (window-min-size mini horizontal nil pixelwise) + 0)))) + (defun window--max-delta-1 (window delta &optional horizontal ignore trail noup pixelwise) "Internal function of `window-max-delta'." (if (not (window-parent window)) @@ -2984,6 +3003,28 @@ routines." pixel-delta (/ pixel-delta (frame-char-height frame))))) +(defun window--sanitize-window-sizes (frame horizontal) + "Assert that all windows on FRAME are large enough. +If necessary and possible, make sure that every window on frame +FRAME has its minimum height. Optional argument HORIZONTAL +non-nil means to make sure that every window on frame FRAME has +its minimum width. The minimumm height/width of a window is the +respective value returned by `window-min-size' for that window. + +Return t if all windows were resized appropriately. Return nil +if at least one window could not be resized as requested, which +may happen when the FRAME is not large enough to accomodate it." + (let ((value t)) + (walk-window-tree + (lambda (window) + (let ((delta (- (window-min-size window horizontal nil t) + (window-size window horizontal t)))) + (when (> delta 0) + (if (window-resizable-p window delta horizontal nil t) + (window-resize window delta horizontal nil t) + (setq value nil)))))) + value)) + (defun adjust-window-trailing-edge (window delta &optional horizontal pixelwise) "Move WINDOW's bottom edge by DELTA lines. Optional argument HORIZONTAL non-nil means move WINDOW's right @@ -4241,20 +4282,6 @@ showing BUFFER-OR-NAME." ;; If a window doesn't show BUFFER, unrecord BUFFER in it. (unrecord-window-buffer window buffer))))) -;;; Splitting windows. -(defun window-split-min-size (&optional horizontal pixelwise) - "Return minimum height of any window when splitting windows. -Optional argument HORIZONTAL non-nil means return minimum width." - (cond - (pixelwise - (if horizontal - (window-min-pixel-width) - (window-min-pixel-height))) - (horizontal - (max window-min-width window-safe-min-width)) - (t - (max window-min-height window-safe-min-height)))) - (defun split-window (&optional window size side pixelwise) "Make a new window adjacent to WINDOW. WINDOW must be a valid window and defaults to the selected one. @@ -4318,6 +4345,9 @@ frame. The selected window is not changed by this function." (pixel-size (when (numberp size) (window--size-to-pixel window size horizontal pixelwise t))) + (divider-width (if horizontal + (frame-right-divider-width frame) + (frame-bottom-divider-width frame))) atom-root) (window--check frame) (catch 'done @@ -4419,19 +4449,14 @@ frame. The selected window is not changed by this function." (cond (resize ;; SIZE unspecified, resizing. - (when (and (not (window-sizable-p - parent (- new-pixel-size) horizontal nil t)) - ;; Try again with minimum split size. - (setq new-pixel-size - (max new-pixel-size - (window-split-min-size horizontal t))) - (not (window-sizable-p - parent (- new-pixel-size) horizontal nil t))) - (error "Window %s too small for splitting 1" parent))) - ((> (+ new-pixel-size (window-min-size window horizontal nil t)) + (unless (window-sizable-p + parent (- new-pixel-size divider-width) horizontal nil t) + (error "Window %s too small for splitting (1)" parent))) + ((> (+ new-pixel-size divider-width + (window-min-size window horizontal nil t)) old-pixel-size) ;; SIZE unspecified, no resizing. - (error "Window %s too small for splitting 2" window)))) + (error "Window %s too small for splitting (2)" window)))) ((and (>= pixel-size 0) (or (>= pixel-size old-pixel-size) (< new-pixel-size @@ -4439,19 +4464,19 @@ frame. The selected window is not changed by this function." ;; SIZE specified as new size of old window. If the new size ;; is larger than the old size or the size of the new window ;; would be less than the safe minimum, signal an error. - (error "Window %s too small for splitting 3" window)) + (error "Window %s too small for splitting (3)" window)) (resize ;; SIZE specified, resizing. (unless (window-sizable-p - parent (- new-pixel-size) horizontal nil t) + parent (- new-pixel-size divider-width) horizontal nil t) ;; If we cannot resize the parent give up. - (error "Window %s too small for splitting 4" parent))) + (error "Window %s too small for splitting (4)" parent))) ((or (< new-pixel-size (window-safe-min-pixel-size window horizontal)) (< (- old-pixel-size new-pixel-size) (window-safe-min-pixel-size window horizontal))) ;; SIZE specification violates minimum size restrictions. - (error "Window %s too small for splitting 5" window))) + (error "Window %s too small for splitting (5)" window))) (window--resize-reset frame horizontal) @@ -4522,6 +4547,9 @@ frame. The selected window is not changed by this function." (set-window-parameter (window-parent new) 'window-atom t)) (set-window-parameter new 'window-atom t))) + ;; Sanitize sizes. + (window--sanitize-window-sizes frame horizontal) + (run-window-configuration-change-hook frame) (run-window-scroll-functions new) (window--check frame) @@ -7116,7 +7144,10 @@ FRAME." (value (window-text-pixel-size nil t t workarea-width workarea-height t)) (width (+ (car value) (window-right-divider-width))) - (height (+ (cdr value) (window-bottom-divider-width)))) + (height + (+ (cdr value) + (window-bottom-divider-width) + (nth 3 (window-scroll-bars))))) ;; Don't change height or width when the window's size is fixed ;; in either direction or ONLY forbids it. (cond @@ -7275,6 +7306,7 @@ accessible position." ;; height. Its width remains fixed. (setq height (+ (cdr (window-text-pixel-size nil nil t nil (frame-pixel-height) t)) + (nth 3 (window-scroll-bars window)) (window-bottom-divider-width))) ;; Round height. (unless pixelwise diff --git a/src/ChangeLog b/src/ChangeLog index 6843cfac089..28fc913903c 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,366 @@ +2014-07-27 Martin Rudalics + + * buffer.h (struct buffer): New fields scroll_bar_height and + horizontal_scroll_bar_type. + * buffer.c (bset_scroll_bar_height) + (bset_horizontal_scroll_bar_type): New functions. + (Fbuffer_swap_text): Handle old_pointm field. + (init_buffer_once): Set defaults for scroll_bar_height and + horizontal_scroll_bar_type. + (syms_of_buffer): New variables scroll_bar_height and + horizontal_scroll_bar_type. + * dispextern.h (window_part): Rename ON_SCROLL_BAR to + ON_VERTICAL_SCROLL_BAR. Add ON_HORIZONTAL_SCROLL_BAR. + (set_vertical_scroll_bar): Remove prototype. + (x_change_tool_bar_height): Add prototype. + * dispnew.c (adjust_frame_glyphs_for_frame_redisplay) + (window_to_frame_vpos, update_frame_1, scrolling, init_display): + Use FRAME_TOTAL_COLS and FRAME_TOTAL_LINES instead of FRAME_COLS + and FRAME_LINES. + (adjust_frame_glyphs_for_window_redisplay): Rearrange lines. + (update_window): Start mode_line_row->y after horizontal scroll + bar. + (change_frame_size_1): Call adjust_frame_size. + (init_display): When changing the size of a tty frame do not + pass height of menu bar. + (Qframe_windows_min_size): New symbol. + * frame.h (struct frame): List tool bar fields after menu bar + fields. Add official, total_lines, horizontal_scroll_bars, + config_scroll_bar_height and config_scroll_bar_lines fields. + (FRAME_HAS_HORIZONTAL_SCROLL_BARS) + (FRAME_CONFIG_SCROLL_BAR_HEIGHT, FRAME_CONFIG_SCROLL_BAR_LINES) + (FRAME_SCROLL_BAR_AREA_HEIGHT, FRAME_SCROLL_BAR_COLS) + (FRAME_SCROLL_BAR_LINES, FRAME_TOTAL_LINES, SET_FRAME_LINES) + (FRAME_WINDOWS_HEIGHT): New macros. + (SET_FRAME_HEIGHT, FRAME_TEXT_LINES_TO_PIXEL_HEIGHT) + (FRAME_PIXEL_Y_TO_LINE, FRAME_PIXEL_HEIGHT_TO_TEXT_LINES) + (FRAME_TEXT_TO_PIXEL_HEIGHT): Separately count top margin and + horizontal scroll bar. + (frame_inhibit_resize, adjust_frame_size) + (frame_windows_min_size): Add declarations. + (Qscroll_bar_height, Qhorizontal_scroll_bars) + (x_set_scroll_bar_default_height, x_set_left_fringe) + (x_set_right_fringe, x_set_vertical_scroll_bars) + (x_set_horizontal_scroll_bars, x_set_scroll_bar_width) + (x_set_scroll_bar_height): Add external declarations. + * frame.c: (frame_inhibit_resize, frame_windows_min_size) + (adjust_frame_size): New functions. + (make_frame): Initial horizontal_scroll_bars field. Use + SET_FRAME_LINES. Don't allow horizontal scroll bar in + minibuffer window. + (make_initial_frame, make_terminal_frame): No horizontal scroll + bar in initial and terminal frames. Use adjust_frame_size. + (Fframe_total_cols): Fix doc-string. + (Fframe_total_lines, Fscroll_bar_height): New Lisp functions. + (Fset_frame_height, Fset_frame_width, Fset_frame_size): Rewrite + using adjust_frame_size. + (Qscroll_bar_height, Qhorizontal_scroll_bars) + (Qframe_windows_min_size): New symbols. + (x_set_frame_parameters): Remove call of check_frame_size. + (x_report_frame_params): Return scroll_bar_height value. + (x_set_left_fringe, x_set_right_fringe): New functions. + (adjust_frame_height, x_set_internal_border_width) + (x_set_fringe_width): Remove. + (x_set_internal_border_width, x_set_vertical_scroll_bars) + (x_set_scroll_bar_width, x_set_right_divider_width) + (x_set_bottom_divider_width): Rewrite using adjust_frame_size. + (x_set_horizontal_scroll_bars, x_set_scroll_bar_height): New + functions. + (x_figure_window_size): Rewrite to make frame display the + expected number of lines. + (Vdefault_frame_scroll_bars): Rewrite doc-string. + (Vdefault_frame_horizontal_scroll_bars) + (Vframe_initial_frame_tool_bar_height) + (frame_inhibit_implied_resize): New variables. + * fringe.c (compute_fringe_widths): Remove. + * gtkutil.h (YG_SB_MIN, YG_SB_MAX, YG_SB_RANGE): Define. + (xg_create_horizontal_scroll_bar) + (xg_update_horizontal_scrollbar_pos) + (xg_set_toolkit_horizontal_scroll_bar_thumb) + (xg_get_default_scrollbar_height) + (xg_clear_under_internal_border): Extern. + * gtkutil.c (xg_frame_resized): Don't call + do_pending_window_change. + (xg_frame_set_char_size): Use adjust_frame_size. + (style_changed_cb): Call update_theme_scrollbar_height and + x_set_scroll_bar_default_height. + (x_wm_set_size_hint): Don't call check_frame_size. + (update_theme_scrollbar_height) + (xg_get_default_scrollbar_height) + (xg_create_horizontal_scroll_bar) + (xg_update_horizontal_scrollbar_pos) + (xg_set_toolkit_horizontal_scroll_bar_thumb): New functions. + (xg_create_scroll_bar): Set horizontal slot of bar. + (xg_initialize): Call update_theme_scrollbar_height. + (xg_clear_under_internal_border): No more static. + * insdel.c (adjust_suspend_auto_hscroll): New function. + (adjust_markers_for_delete, adjust_markers_for_insert) + (adjust_markers_for_replace): Call adjust_suspend_auto_hscroll. + * keyboard.c (readable_events, discard_mouse_events) + (make_lispy_event): Handle horizontal scroll bar click events. + (Fsuspend_emacs): When changing the size of a tty frame do not + pass height of menu bar. + (Qbefore_handle, Qhorizontal_handle, Qafter_handle, Qleft) + (Qright, Qleftmost, Qrightmost): New symbols. + * menu.c (Fx_popup_dialog): Use FRAME_TOTAL_LINES instead of + FRAME_LINES. + * minibuf.c (read_minibuf): Initialize suspend_auto_hscroll. + * nsfns.m (x_set_internal_border_width): New function. + * nsterm.m (ns_draw_fringe_bitmap, ns_set_vertical_scroll_bar): + Remove extended fringe code. + (x_set_window_size, x_new_font): Don't call + compute_fringe_widths. + * term.c (Fresume_tty): When changing the size of a tty frame do + not pass height of menu bar. + (clear_tty_hooks, set_tty_hooks): Clear + horizontal_scroll_bar_hook. + (init_tty): Frame has no horizontal scroll bars. + * termhooks.h (enum scroll_bar_part): Add scroll_bar_move_ratio, + scroll_bar_before_handle, scroll_bar_horizontal_handle, + scroll_bar_after_handle, scroll_bar_left_arrow, + scroll_bar_right_arrow, scroll_bar_to_leftmost and + scroll_bar_to_rightmost entries. + (enum event_kind): Add HORIZONTAL_SCROLL_BAR_CLICK_EVENT + (struct terminal): Add set_horizontal_scroll_bar_hook. + * w32console.c (initialize_w32_display): Clear + horizontal_scroll_bar_hook. + * w32fns.c (x_set_mouse_color): Use FRAME_W32_DISPLAY instead of + FRAME_X_DISPLAY. + (x_clear_under_internal_border, x_set_internal_border_width): + New functions. + (x_set_menu_bar_lines): Rewrite using frame_inhibit_resize. Set + windows_or_buffers_changed when adding the menu bar. + (x_set_tool_bar_lines): Rewrite using adjust_frame_size. + (x_change_tool_bar_height, x_set_scroll_bar_default_height) + (w32_createhscrollbar): New functions. + (w32_createscrollbar): Rename to w32_createvscrollbar. + (w32_createwindow): Init WND_HSCROLLBAR_INDEX. + (w32_name_of_message): Replace WM_EMACS_CREATESCROLLBAR by + WM_EMACS_CREATEVSCROLLBAR and WM_EMACS_CREATEHSCROLLBAR. Add + WM_EMACS_SHOWCURSOR. + (w32_wnd_proc): Handle WM_HSCROLL case. In WM_WINDOWPOSCHANGING + case do not artificially impose WM size hints. Handle + WM_EMACS_SHOWCURSOR case. Replace WM_EMACS_CREATESCROLLBAR case + by WM_EMACS_CREATEVSCROLLBAR and WM_EMACS_CREATEHSCROLLBAR + cases. + (my_create_tip_window): Replace WND_SCROLLBAR_INDEX by + WND_VSCROLLBAR_INDEX and WND_HSCROLLBAR_INDEX. + (unwind_create_frame_1): Remove. + (Fx_create_frame): Make both scrollbars the system standard + width and height. Use official field of frame structure to + inhibit running window-configuration-change-hook. + (x_create_tip_frame): Call SET_FRAME_LINES and change_frame_size + pixelwise. Handle frame's official field. + (w32_frame_parm_handlers): Remove x_set_fringe_width + entries. Add x_set_scroll_bar_height, + x_set_horizontal_scroll_bars, x_set_left_fringe and + x_set_right_fringe. + * w32inevt.c (resize_event, maybe_generate_resize_event): Do not + pass height of menu bar to change_frame_size. + * w32menu.c (set_frame_menubar): Rewrite using + frame_inhibit_resize. + * w32term.h (struct w32_display_info): Add + horizontal_scroll_bar_cursor and cursor_display_counter. + (struct scroll_bar): Add horizontal. + (HORIZONTAL_SCROLL_BAR_INSIDE_HEIGHT) + (HORIZONTAL_SCROLL_BAR_LEFT_RANGE) + (HORIZONTAL_SCROLL_BAR_INSIDE_WIDTH) + (HORIZONTAL_SCROLL_BAR_LEFT_BORDER) + (HORIZONTAL_SCROLL_BAR_RIGHT_BORDER) + (HORIZONTAL_SCROLL_BAR_TOP_BORDER) + (HORIZONTAL_SCROLL_BAR_BOTTOM_BORDER) + (HORIZONTAL_SCROLL_BAR_MIN_HANDLE): New macros. + (WM_EMACS_CREATEVSCROLLBAR, WM_EMACS_CREATEHSCROLLBAR): Define + instead of WM_EMACS_CREATESCROLLBAR. + (WND_VSCROLLBAR_INDEX, WND_HSCROLLBAR_INDEX): Define instead of + WND_SCROLLBAR_INDEX. + * w32term.c (horizontal_scroll_bar_min_handle) + (horizontal_scroll_bar_left_border) + (horizontal_scroll_bar_right_border): New integers. + (x_set_frame_alpha): Replace x_highlight_frame by + w32_focus_frame. + (x_window_to_scroll_bar): New argument "type". Update callers + accordingly. + (w32_set_horizontal_scroll_bar_thumb) + (x_horizontal_scroll_bar_report_motion) + (w32_set_horizontal_scroll_bar) + (w32_horizontal_scroll_bar_handle_click) + (x_horizontal_scroll_bar_report_motion): New functions. + (w32_mouse_position): Discriminate horizontal and vertical + scrollbar cases. + (my_create_scrollbar): Replace with two new functions + my_create_vscrollbar and my_create_hscrollbar. + (x_scroll_bar_create): New argument "horizontal". Update + callers accordingly. + (x_scroll_bar_remove, w32_condemn_scroll_bars) + (w32_redeem_scroll_bar, x_scroll_bar_clear): Handle horizontal + scroll bar case. + (w32_read_socket): Handle WM_HSCROLL cae. + (x_new_font): Don't recompute fringe widths. Use + frame_inhibit_resize. Calculate new menu bar height iff we + build without toolkit. Always clear under internal border. + (x_set_window_size): Don't check frame size or recompute + fringes. Reset fullscreen status before applying sizes. Always + resize as requested by pixelwise argument. Don't call + do_pending_window_change. + (x_wm_set_size_hint): Add call for FRAME_SCROLL_BAR_AREA_HEIGHT. + (w32_initialize_display_info): Initialize dpyinfo's + horizontal_scroll_bar_cursor entry. + (w32_create_terminal): Add set_horizontal_scroll_bar_hook. + (w32_initialize): Init horizontal_scroll_bar_min_handle and + horizontal_scroll_bar_left_border. + (w32fullscreen_hook): Intermittently resize window to normal + when switching from fullscreen to maximized state. + (run_window_configuration_change_hook): Don't run it if frame is + not official yet. + (unwind_change_frame): Remove. + (Fset_window_configuration): Rewrite using frame's official field. + * widget.c (set_frame_size): Don't call compute_fringe_widths. + (EmacsFrameSetCharSize): Obey frame_inhibit_resize. + * window.h (struct window): New fields old_pointm, + horizontal_scroll_bar, horizontal_scroll_bar_type, hscroll_whole, + scroll_bar_height and suspend_auto_hscroll. + (wset_horizontal_scroll_bar, wset_horizontal_scroll_bar_type): + New functions. + (sanitize_window_sizes): Extern. + (MINI_NON_ONLY_WINDOW_P, MINI_ONLY_WINDOW_P, WINDOW_PSEUDO_P) + (WINDOW_TOPMOST_P, WINDOW_HAS_HORIZONTAL_SCROLL_BAR) + (WINDOW_CONFIG_SCROLL_BAR_HEIGHT) + (WINDOW_CONFIG_SCROLL_BAR_LINES) + (WINDOW_SCROLL_BAR_LINES, WINDOW_SCROLL_BAR_AREA_HEIGHT): New + macros. + (WINDOW_LEFT_FRINGE_COLS, WINDOW_RIGHT_FRINGE_COLS) + (WINDOW_FRINGE_COLS, WINDOW_FRINGE_EXTENDED_P): Remove macros. + (WINDOW_VERTICAL_SCROLL_BAR_TYPE) + (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT) + (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT) + (WINDOW_HAS_VERTICAL_SCROLL_BAR): Minor rewrite. + (WINDOW_BOX_HEIGHT_NO_MODE_LINE, WINDOW_BOX_TEXT_HEIGHT) + (WINDOW_SCROLL_BAR_AREA_Y): Count in scroll bar height. + * window.c (wset_old_pointm, Fwindow_scroll_bar_height) + (Fwindow_old_point, sanitize_window_sizes): New functions. + (Qwindow_sanitize_window_sizes): New symbol. + (window_body_height): Count in horizontal scroll bar. + (set_window_hscroll, Fscroll_left, Fscroll_right): Set + suspend_auto_hscroll slot. + (Fwindow_inside_edges): Count fringes pixelwise. + (coordinates_in_window, Fcoordinates_in_window_p): Consider + horizontal scroll bar. + (check_frame_size, adjust_window_margins): Remove functions and + corresponding calls. + (set_window_buffer): Initialize old_pointm and horizontal scroll + bars. + (temp_output_buffer_show): Reset hscroll related fields. + Initialize old_pointm. + (make_parent_window): Initialize old_pointm. + (make_window): Initialize old_pointm, horizontal scroll bar type, + and scroll bar height. + (resize_frame_windows): Don't count top margin in new sizes. + Don't use safe sizes when shrinking a frame; let the window + manager do the clipping. + (Fsplit_window_internal): Inherit horizontal scroll bar type and + height. + (Fdelete_window_internal): Unchain old_pointm marker. + (window_scroll_pixel_based, Fscroll_other_window): Adjust + old_pointm. + (Fwindow_text_width, Fwindow_text_height): New argument + "pixelwise". + (struct saved_window): New fields, old_pointm, hscroll_whole, + suspend_auto_hscroll, scroll_bar_height and + horizontal_scroll_bar_type. + (Fset_window_configuration, save_window_save): Set new fields of + saved_window. + (apply_window_adjustment): Don't call adjust_window_margins. + (set_window_margins): Don't change margins if new sizes don't + fit into window. + (set_window_scroll_bars): New argument "horizontal_type". + Handle horizontal scroll bars. Don't change scroll bars if they + don't fit into window. + (Fset_window_scroll_bars): New argument "horizontal_type". + (Fwindow_scroll_bars): Return values for horizontal scroll bars. + (compare_window_configurations): Compare horizontal scroll bar + settings. + * xdisp.c (window_text_bottom_y, window_box_height): Count in + horizontal scroll bar height. + (pixel_to_glyph_coords, init_xdisp): Use FRAME_TOTAL_LINES + instead of FRAME_LINES. + (remember_mouse_glyph): Case ON_SCROLL_BAR changed to + ON_VERTICAL_SCROLL_BAR. + (with_echo_area_buffer): Initialize old_pointm. + (with_echo_area_buffer_unwind_data): Store old_pointm values in + vector. + (unwind_with_echo_area_buffer): Handle old_pointm. + (update_tool_bar): Set do_update when the tool bar window has at + least one line (since this is what the user sets). + (MAX_FRAME_TOOL_BAR_HEIGHT): Remove macro. + (redisplay_tool_bar): Return early when toolbar has zero lines. + Call x_change_tool_bar_height. Don't use max_tool_bar_height. + (hscroll_window_tree): Handle suspension of auto_hscroll and + old_pointm. + (set_horizontal_scroll_bar): New function. + (redisplay_window): Set ignore_mouse_drag_p when tool bar has + more than one line. Handle horizontal scroll bars. + (note_mouse_highlight): Handle horizontal scrol bars. + (expose_frame): Set dimensions of XRectangle from frame's text + sizes. + (Vvoid_text_area_pointer): Update doc-string. + * xfns.c (x_set_menu_bar_lines): Use adjust_frame_size. + (x_change_tool_bar_height, x_set_scroll_bar_default_height) + (x_set_internal_border_width): New functions. + (x_set_tool_bar_lines): Call x_change_tool_bar_height. + (unwind_create_frame_1): Remove. + (Fx_create_frame): Handle horizontal scroll bars. Use official + field of frame structure to inhibit running + window-configuration-change-hook. + (x_create_tip_frame): Call SET_FRAME_LINES and change_frame_size + pixelwise. Handle frame's official field. + (x_frame_parm_handlers): Add x_set_scroll_bar_height, + x_set_horizontal_scroll_bars, x_set_left_fringe, + x_set_right_fringe. + * xmenu.c (update_frame_menubar, free_frame_menubar): Use + adjust_frame_size. + * xterm.h (struct x_display_info): Add + horizontal_scroll_bar_cursor and Xatom_Horizontal_Scrollbar + slots. + (struct scroll_bar): Add horizontal slot. + (HORIZONTAL_SCROLL_BAR_INSIDE_HEIGHT) + (HORIZONTAL_SCROLL_BAR_LEFT_RANGE) + (HORIZONTAL_SCROLL_BAR_INSIDE_WIDTH): New macros. + (HORIZONTAL_SCROLL_BAR_LEFT_BORDER) + (HORIZONTAL_SCROLL_BAR_RIGHT_BORDER) + (HORIZONTAL_SCROLL_BAR_TOP_BORDER) + (HORIZONTAL_SCROLL_BAR_BOTTOM_BORDER) + (HORIZONTAL_SCROLL_BAR_MIN_HANDLE): Define. + (x_clear_under_internal_border): Remove. + * xterm.c (XTmouse_position): Handle horizontal scroll bars. + (x_window_to_scroll_bar): New argument TYPE. Update callers. + (x_send_scroll_bar_event, x_scroll_bar_create): New arguments + HORIZONTAL. Update callers. + (horizontal_action_hook_id): New action hook id. + (x_horizontal_scroll_bar_to_input_event) + (x_create_horizontal_toolkit_scroll_bar) + (xt_horizontal_action_hook) + (x_set_toolkit_horizontal_scroll_bar_thumb) + (XTset_horizontal_scroll_bar, x_net_wm_state) + (x_horizontal_scroll_bar_report_motion): New functions. + (xg_scroll_callback, x_scroll_bar_handle_click): Handle + horizontal scroll bars. + (SCROLL_BAR_HORIZONTAL_NAME): Define. + (XTset_vertical_scroll_bar): Attempt to clear areas not covered + by scroll bar. + (XTcondemn_scroll_bars, XTredeem_scroll_bar): Rewrite. Handle + horizontal scroll bars. + (handle_one_xevent): Handle horizontal scroll bar events. Call + x_net_wm_state. + (x_set_window_size_1, x_wm_set_size_hint): Don't call + check_frame_size. + (x_set_window_size): Don't call check_frame_size and + do_pending_window_change. + (x_term_init): Init horizontal_scroll_bar_cursor display info. + (x_create_terminal): Add set_horizontal_scroll_bar_hook. + (x_scroll_bar_set_handle): Add some checks when calling + x_clear_area. + 2014-07-26 Paul Eggert Revert previous change. diff --git a/src/buffer.c b/src/buffer.c index 53cc25e2c8f..1973a93a57d 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -145,7 +145,8 @@ Lisp_Object Qmodification_hooks; Lisp_Object Qinsert_in_front_hooks; Lisp_Object Qinsert_behind_hooks; -Lisp_Object Qchoice, Qrange, Qleft, Qright, Qvertical_scroll_bar; +Lisp_Object Qchoice, Qrange, Qleft, Qright; +Lisp_Object Qvertical_scroll_bar, Qhorizontal_scroll_bar; static Lisp_Object Qoverwrite_mode, Qfraction; static void alloc_buffer_text (struct buffer *, ptrdiff_t); @@ -343,6 +344,11 @@ bset_scroll_bar_width (struct buffer *b, Lisp_Object val) b->INTERNAL_FIELD (scroll_bar_width) = val; } static void +bset_scroll_bar_height (struct buffer *b, Lisp_Object val) +{ + b->INTERNAL_FIELD (scroll_bar_height) = val; +} +static void bset_scroll_down_aggressively (struct buffer *b, Lisp_Object val) { b->INTERNAL_FIELD (scroll_down_aggressively) = val; @@ -368,6 +374,11 @@ bset_vertical_scroll_bar_type (struct buffer *b, Lisp_Object val) b->INTERNAL_FIELD (vertical_scroll_bar_type) = val; } static void +bset_horizontal_scroll_bar_type (struct buffer *b, Lisp_Object val) +{ + b->INTERNAL_FIELD (horizontal_scroll_bar_type) = val; +} +static void bset_word_wrap (struct buffer *b, Lisp_Object val) { b->INTERNAL_FIELD (word_wrap) = val; @@ -2429,6 +2440,14 @@ DEFUN ("buffer-swap-text", Fbuffer_swap_text, Sbuffer_swap_text, make_number (BUF_BEGV (XBUFFER (XWINDOW (w)->contents))), XWINDOW (w)->contents); + /* Blindly copied from pointm part. */ + if (MARKERP (XWINDOW (w)->old_pointm) + && (EQ (XWINDOW (w)->contents, buf1) + || EQ (XWINDOW (w)->contents, buf2))) + Fset_marker (XWINDOW (w)->old_pointm, + make_number + (BUF_BEGV (XBUFFER (XWINDOW (w)->contents))), + XWINDOW (w)->contents); if (MARKERP (XWINDOW (w)->start) && (EQ (XWINDOW (w)->contents, buf1) || EQ (XWINDOW (w)->contents, buf2))) @@ -5157,7 +5176,9 @@ init_buffer_once (void) bset_right_fringe_width (&buffer_defaults, Qnil); bset_fringes_outside_margins (&buffer_defaults, Qnil); bset_scroll_bar_width (&buffer_defaults, Qnil); + bset_scroll_bar_height (&buffer_defaults, Qnil); bset_vertical_scroll_bar_type (&buffer_defaults, Qt); + bset_horizontal_scroll_bar_type (&buffer_defaults, Qt); bset_indicate_empty_lines (&buffer_defaults, Qnil); bset_indicate_buffer_boundaries (&buffer_defaults, Qnil); bset_fringe_indicator_alist (&buffer_defaults, Qnil); @@ -5225,7 +5246,9 @@ init_buffer_once (void) XSETFASTINT (BVAR (&buffer_local_flags, right_fringe_width), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, fringes_outside_margins), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, scroll_bar_width), idx); ++idx; + XSETFASTINT (BVAR (&buffer_local_flags, scroll_bar_height), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, vertical_scroll_bar_type), idx); ++idx; + XSETFASTINT (BVAR (&buffer_local_flags, horizontal_scroll_bar_type), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, indicate_empty_lines), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, indicate_buffer_boundaries), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, fringe_indicator_alist), idx); ++idx; @@ -5446,6 +5469,7 @@ syms_of_buffer (void) DEFSYM (Qvertical_scroll_bar, "vertical-scroll-bar"); Fput (Qvertical_scroll_bar, Qchoice, list4 (Qnil, Qt, Qleft, Qright)); + DEFSYM (Qhorizontal_scroll_bar, "horizontal-scroll-bar"); DEFSYM (Qfraction, "fraction"); Fput (Qfraction, Qrange, Fcons (make_float (0.0), make_float (1.0))); @@ -5954,6 +5978,11 @@ in a window. To make the change take effect, call `set-window-buffer'. */); doc: /* Width of this buffer's scroll bars in pixels. A value of nil means to use the scroll bar width from the window's frame. */); + DEFVAR_PER_BUFFER ("scroll-bar-height", &BVAR (current_buffer, scroll_bar_height), + Qintegerp, + doc: /* Height of this buffer's scroll bars in pixels. +A value of nil means to use the scroll bar heiht from the window's frame. */); + DEFVAR_PER_BUFFER ("vertical-scroll-bar", &BVAR (current_buffer, vertical_scroll_bar_type), Qvertical_scroll_bar, doc: /* Position of this buffer's vertical scroll bar. @@ -5964,6 +5993,17 @@ A value of `left' or `right' means put the vertical scroll bar at that side of the window; a value of nil means don't show any vertical scroll bars. A value of t (the default) means do whatever the window's frame specifies. */); + DEFVAR_PER_BUFFER ("horizontal-scroll-bar", &BVAR (current_buffer, horizontal_scroll_bar_type), + Qnil, + doc: /* Position of this buffer's horizontal scroll bar. +The value takes effect whenever you tell a window to display this buffer; +for instance, with `set-window-buffer' or when `display-buffer' displays it. + +A value of `bottom' means put the horizontal scroll bar at the bottom of +the window; a value of nil means don't show any horizonal scroll bars. +A value of t (the default) means do whatever the window's frame +specifies. */); + DEFVAR_PER_BUFFER ("indicate-empty-lines", &BVAR (current_buffer, indicate_empty_lines), Qnil, doc: /* Visually indicate empty lines after the buffer end. diff --git a/src/buffer.h b/src/buffer.h index 3c29019554c..fd989925976 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -694,10 +694,12 @@ struct buffer othersize draw them between margin areas and text. */ Lisp_Object INTERNAL_FIELD (fringes_outside_margins); - /* Width and type of scroll bar areas for windows displaying + /* Width, height and types of scroll bar areas for windows displaying this buffer. */ Lisp_Object INTERNAL_FIELD (scroll_bar_width); + Lisp_Object INTERNAL_FIELD (scroll_bar_height); Lisp_Object INTERNAL_FIELD (vertical_scroll_bar_type); + Lisp_Object INTERNAL_FIELD (horizontal_scroll_bar_type); /* Non-nil means indicate lines not displaying text (in a style like vi). */ @@ -1135,7 +1137,8 @@ extern Lisp_Object Qbefore_change_functions; extern Lisp_Object Qafter_change_functions; extern Lisp_Object Qfirst_change_hook; extern Lisp_Object Qpriority, Qbefore_string, Qafter_string; -extern Lisp_Object Qchoice, Qrange, Qleft, Qright, Qvertical_scroll_bar; +extern Lisp_Object Qchoice, Qrange, Qleft, Qright; +extern Lisp_Object Qvertical_scroll_bar, Qhorizontal_scroll_bar; /* FOR_EACH_LIVE_BUFFER (LIST_VAR, BUF_VAR) followed by a statement is a `for' loop which iterates over the buffers from Vbuffer_alist. */ diff --git a/src/dispextern.h b/src/dispextern.h index 400de336965..bb6f1eb2b5e 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -118,7 +118,8 @@ enum window_part ON_RIGHT_FRINGE, ON_LEFT_MARGIN, ON_RIGHT_MARGIN, - ON_SCROLL_BAR, + ON_VERTICAL_SCROLL_BAR, + ON_HORIZONTAL_SCROLL_BAR, ON_RIGHT_DIVIDER, ON_BOTTOM_DIVIDER }; @@ -3163,6 +3164,7 @@ int display_prop_intangible_p (Lisp_Object, Lisp_Object, ptrdiff_t, ptrdiff_t); void resize_echo_area_exactly (void); int resize_mini_window (struct window *, int); void set_vertical_scroll_bar (struct window *); +void set_horizontal_scroll_bar (struct window *); int try_window (Lisp_Object, struct text_pos, int); void window_box (struct window *, enum glyph_row_area, int *, int *, int *, int *); @@ -3201,6 +3203,7 @@ extern bool help_echo_showing_p; extern Lisp_Object help_echo_string, help_echo_window; extern Lisp_Object help_echo_object, previous_help_echo_string; extern ptrdiff_t help_echo_pos; +extern int last_tool_bar_item; extern void reseat_at_previous_visible_line_start (struct it *); extern Lisp_Object lookup_glyphless_char_display (int, struct it *); extern ptrdiff_t compute_display_string_pos (struct text_pos *, @@ -3273,7 +3276,6 @@ void draw_fringe_bitmap (struct window *, struct glyph_row *, int); void draw_row_fringe_bitmaps (struct window *, struct glyph_row *); bool draw_window_fringes (struct window *, bool); bool update_window_fringes (struct window *, bool); -void compute_fringe_widths (struct frame *, bool); #ifdef HAVE_NTGUI void w32_init_fringe (struct redisplay_interface *); @@ -3390,6 +3392,7 @@ void gamma_correct (struct frame *, COLORREF *); #ifdef HAVE_WINDOW_SYSTEM void x_implicitly_set_name (struct frame *, Lisp_Object, Lisp_Object); +void x_change_tool_bar_height (struct frame *f, int); extern Lisp_Object tip_frame; extern Window tip_window; diff --git a/src/dispnew.c b/src/dispnew.c index 2d137b4abbd..289431d6dc4 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -72,7 +72,6 @@ struct dim static void update_frame_line (struct frame *, int); static int required_matrix_height (struct window *); static int required_matrix_width (struct window *); -static void change_frame_size_1 (struct frame *, int, int, bool, bool, bool, bool); static void increment_row_positions (struct glyph_row *, ptrdiff_t, ptrdiff_t); static void build_frame_matrix_from_window_tree (struct glyph_matrix *, struct window *); @@ -2016,12 +2015,12 @@ adjust_frame_glyphs_for_frame_redisplay (struct frame *f) /* Size of frame matrices must equal size of frame. Note that we are called for X frames with window widths NOT equal to the frame width (from CHANGE_FRAME_SIZE_1). */ - if (matrix_dim.width != FRAME_COLS (f) - || matrix_dim.height != FRAME_LINES (f)) + if (matrix_dim.width != FRAME_TOTAL_COLS (f) + || matrix_dim.height != FRAME_TOTAL_LINES (f)) return; - eassert (matrix_dim.width == FRAME_COLS (f) - && matrix_dim.height == FRAME_LINES (f)); + eassert (matrix_dim.width == FRAME_TOTAL_COLS (f) + && matrix_dim.height == FRAME_TOTAL_LINES (f)); /* Pointers to glyph memory in glyph rows are exchanged during the update phase of redisplay, which means in general that a @@ -2123,11 +2122,11 @@ adjust_frame_glyphs_for_window_redisplay (struct frame *f) w->left_col = 0; w->pixel_top = FRAME_MENU_BAR_HEIGHT (f); w->top_line = FRAME_MENU_BAR_LINES (f); + w->total_cols = FRAME_TOTAL_COLS (f); w->pixel_width = (FRAME_PIXEL_WIDTH (f) - 2 * FRAME_INTERNAL_BORDER_WIDTH (f)); - w->total_cols = FRAME_TOTAL_COLS (f); - w->pixel_height = FRAME_TOOL_BAR_HEIGHT (f); w->total_lines = FRAME_TOOL_BAR_LINES (f); + w->pixel_height = FRAME_TOOL_BAR_HEIGHT (f); allocate_matrices_for_window_redisplay (w); } #endif @@ -2956,7 +2955,7 @@ window_to_frame_vpos (struct window *w, int vpos) eassert (!FRAME_WINDOW_P (XFRAME (w->frame))); eassert (vpos >= 0 && vpos <= w->desired_matrix->nrows); vpos += WINDOW_TOP_EDGE_LINE (w); - eassert (vpos >= 0 && vpos <= FRAME_LINES (XFRAME (w->frame))); + eassert (vpos >= 0 && vpos <= FRAME_TOTAL_LINES (XFRAME (w->frame))); return vpos; } @@ -3421,7 +3420,7 @@ update_window (struct window *w, bool force_p) mode_line_row = MATRIX_MODE_LINE_ROW (desired_matrix); if (mode_line_row->mode_line_p && mode_line_row->enabled_p) { - mode_line_row->y = yb; + mode_line_row->y = yb + WINDOW_SCROLL_BAR_AREA_HEIGHT (w); update_window_line (w, MATRIX_ROW_VPOS (mode_line_row, desired_matrix), &mouse_face_overwritten_p); @@ -4537,7 +4536,7 @@ update_frame_1 (struct frame *f, bool force_p, bool inhibit_id_p, } } - pause_p = 0 < i && i < FRAME_LINES (f) - 1; + pause_p = 0 < i && i < FRAME_TOTAL_LINES (f) - 1; /* Now just clean up termcap drivers and set cursor, etc. */ if (!pause_p && set_cursor_p) @@ -4570,7 +4569,7 @@ update_frame_1 (struct frame *f, bool force_p, bool inhibit_id_p, cursor at the end of the prompt. If the mini-buffer is several lines high, find the last line that has any text on it. */ - row = FRAME_LINES (f); + row = FRAME_TOTAL_LINES (f); do { --row; @@ -4598,7 +4597,7 @@ update_frame_1 (struct frame *f, bool force_p, bool inhibit_id_p, if (col >= FRAME_CURSOR_X_LIMIT (f)) { /* If we have another row, advance cursor into it. */ - if (row < FRAME_LINES (f) - 1) + if (row < FRAME_TOTAL_LINES (f) - 1) { col = FRAME_LEFT_SCROLL_BAR_COLS (f); row++; @@ -4648,12 +4647,12 @@ scrolling (struct frame *frame) int unchanged_at_top, unchanged_at_bottom; int window_size; int changed_lines; - int *old_hash = alloca (FRAME_LINES (frame) * sizeof (int)); - int *new_hash = alloca (FRAME_LINES (frame) * sizeof (int)); - int *draw_cost = alloca (FRAME_LINES (frame) * sizeof (int)); - int *old_draw_cost = alloca (FRAME_LINES (frame) * sizeof (int)); + int *old_hash = alloca (FRAME_TOTAL_LINES (frame) * sizeof (int)); + int *new_hash = alloca (FRAME_TOTAL_LINES (frame) * sizeof (int)); + int *draw_cost = alloca (FRAME_TOTAL_LINES (frame) * sizeof (int)); + int *old_draw_cost = alloca (FRAME_TOTAL_LINES (frame) * sizeof (int)); register int i; - int free_at_end_vpos = FRAME_LINES (frame); + int free_at_end_vpos = FRAME_TOTAL_LINES (frame); struct glyph_matrix *current_matrix = frame->current_matrix; struct glyph_matrix *desired_matrix = frame->desired_matrix; @@ -4664,8 +4663,8 @@ scrolling (struct frame *frame) number of unchanged lines at the end. */ changed_lines = 0; unchanged_at_top = 0; - unchanged_at_bottom = FRAME_LINES (frame); - for (i = 0; i < FRAME_LINES (frame); i++) + unchanged_at_bottom = FRAME_TOTAL_LINES (frame); + for (i = 0; i < FRAME_TOTAL_LINES (frame); i++) { /* Give up on this scrolling if some old lines are not enabled. */ if (!MATRIX_ROW_ENABLED_P (current_matrix, i)) @@ -4687,7 +4686,7 @@ scrolling (struct frame *frame) if (old_hash[i] != new_hash[i]) { changed_lines++; - unchanged_at_bottom = FRAME_LINES (frame) - i - 1; + unchanged_at_bottom = FRAME_TOTAL_LINES (frame) - i - 1; } else if (i == unchanged_at_top) unchanged_at_top++; @@ -4697,10 +4696,10 @@ scrolling (struct frame *frame) /* If changed lines are few, don't allow preemption, don't scroll. */ if ((!FRAME_SCROLL_REGION_OK (frame) && changed_lines < baud_rate / 2400) - || unchanged_at_bottom == FRAME_LINES (frame)) + || unchanged_at_bottom == FRAME_TOTAL_LINES (frame)) return 1; - window_size = (FRAME_LINES (frame) - unchanged_at_top + window_size = (FRAME_TOTAL_LINES (frame) - unchanged_at_top - unchanged_at_bottom); if (FRAME_SCROLL_REGION_OK (frame)) @@ -4714,7 +4713,7 @@ scrolling (struct frame *frame) && window_size >= 18 && baud_rate > 2400 && (window_size >= 10 * scrolling_max_lines_saved (unchanged_at_top, - FRAME_LINES (frame) - unchanged_at_bottom, + FRAME_TOTAL_LINES (frame) - unchanged_at_bottom, old_hash, new_hash, draw_cost))) return 0; @@ -5471,52 +5470,11 @@ do_pending_window_change (bool safe) } } -/* Change the frame height and/or width. Values may be given as zero to - indicate no change is to take place. - - new_height and new_width refer to the text portion of the frame. It - doesn't matter for new_height, since text and total portion are the - same in that case. But new_width must be enlarged to get the total - width of the frame. - - If DELAY, assume we're being called from a signal handler, and - queue the change for later - perhaps the next redisplay. - Since this tries to resize windows, we can't call it - from a signal handler. - - SAFE means this function is called from a place where it's - safe to change frame sizes while a redisplay is in progress. */ - -void -change_frame_size (struct frame *f, int new_width, int new_height, - bool pretend, bool delay, bool safe, bool pixelwise) -{ - Lisp_Object tail, frame; - - if (FRAME_MSDOS_P (f)) - { - /* On MS-DOS, all frames use the same screen, so a change in - size affects all frames. Termcap now supports multiple - ttys. */ - FOR_EACH_FRAME (tail, frame) - if (! FRAME_WINDOW_P (XFRAME (frame))) - change_frame_size_1 (XFRAME (frame), new_width, new_height, - pretend, delay, safe, pixelwise); - } - else - change_frame_size_1 (f, new_width, new_height, pretend, delay, safe, - pixelwise); -} static void change_frame_size_1 (struct frame *f, int new_width, int new_height, bool pretend, bool delay, bool safe, bool pixelwise) { - int new_text_width, new_text_height, new_root_width; - int old_root_width = WINDOW_PIXEL_WIDTH (XWINDOW (FRAME_ROOT_WINDOW (f))); - int new_cols, new_lines; - ptrdiff_t count = SPECPDL_INDEX (); - /* If we can't deal with the change now, queue it for later. */ if (delay || (redisplaying_p && !safe)) { @@ -5524,123 +5482,63 @@ change_frame_size_1 (struct frame *f, int new_width, int new_height, f->new_height = new_height; f->new_pixelwise = pixelwise; delayed_size_change = 1; - return; - } - - /* This size-change overrides any pending one for this frame. */ - f->new_height = 0; - f->new_width = 0; - f->new_pixelwise = 0; - - /* If an argument is zero, set it to the current value. */ - if (pixelwise) - { - new_text_width = (new_width == 0) ? FRAME_TEXT_WIDTH (f) : new_width; - new_text_height = (new_height == 0) ? FRAME_TEXT_HEIGHT (f) : new_height; - /* Consider rounding here: Currently, the root window can be - larger than the frame in terms of columns/lines. */ - new_cols = new_text_width / FRAME_COLUMN_WIDTH (f); - new_lines = new_text_height / FRAME_LINE_HEIGHT (f); } else { - new_cols = (new_width == 0) ? FRAME_COLS (f) : new_width; - new_lines = (new_height == 0) ? FRAME_LINES (f) : new_height; - new_text_width = new_cols * FRAME_COLUMN_WIDTH (f); - new_text_height = new_lines * FRAME_LINE_HEIGHT (f); - } - - /* Compute width of windows in F. */ - /* Round up to the smallest acceptable size. */ - check_frame_size (f, &new_text_width, &new_text_height, 1); - - /* This is the width of the frame without vertical scroll bars and - fringe columns. Do this after rounding - see discussion of - bug#9723. */ - new_root_width = (new_text_width - + FRAME_SCROLL_BAR_AREA_WIDTH (f) - + FRAME_TOTAL_FRINGE_WIDTH (f)); - /* If we're not changing the frame size, quit now. */ - /* Frame width may be unchanged but the text portion may change, for - example, fullscreen and remove/add scroll bar. */ - if (new_text_height == FRAME_TEXT_HEIGHT (f) - && new_text_width == FRAME_TEXT_WIDTH (f) - && new_root_width == old_root_width - && (FRAME_PIXEL_HEIGHT (f) == - FRAME_TEXT_TO_PIXEL_HEIGHT (f, new_text_height)) - && (FRAME_PIXEL_WIDTH (f) == - FRAME_TEXT_TO_PIXEL_WIDTH (f, new_text_width))) - return; - - block_input (); - -#ifdef MSDOS - /* We only can set screen dimensions to certain values supported - by our video hardware. Try to find the smallest size greater - or equal to the requested dimensions. */ - dos_set_window_size (&new_lines, &new_cols); -#endif - - if (new_text_height != FRAME_TEXT_HEIGHT (f)) - { - resize_frame_windows (f, new_text_height, 0, 1); - - /* MSDOS frames cannot PRETEND, as they change frame size by - manipulating video hardware. */ - if ((FRAME_TERMCAP_P (f) && !pretend) || FRAME_MSDOS_P (f)) - FrameRows (FRAME_TTY (f)) = new_lines; - } - - if (new_text_width != FRAME_TEXT_WIDTH (f) - || new_root_width != old_root_width) - { - resize_frame_windows (f, new_root_width, 1, 1); - - /* MSDOS frames cannot PRETEND, as they change frame size by - manipulating video hardware. */ - if ((FRAME_TERMCAP_P (f) && !pretend) || FRAME_MSDOS_P (f)) - FrameCols (FRAME_TTY (f)) = new_cols; + /* This size-change overrides any pending one for this frame. */ + f->new_height = 0; + f->new_width = 0; + f->new_pixelwise = 0; -#if defined (HAVE_WINDOW_SYSTEM) && ! defined (USE_GTK) && ! defined (HAVE_NS) - if (WINDOWP (f->tool_bar_window)) + /* If an argument is zero, set it to the current value. */ + if (pixelwise) { - XWINDOW (f->tool_bar_window)->total_cols = new_cols; - XWINDOW (f->tool_bar_window)->pixel_width = new_root_width; + new_width = (new_width <= 0) ? FRAME_TEXT_WIDTH (f) : new_width; + new_height = (new_height <= 0) ? FRAME_TEXT_HEIGHT (f) : new_height; + } + else + { + new_width = (((new_width <= 0) ? FRAME_COLS (f) : new_width) + * FRAME_COLUMN_WIDTH (f)); + new_height = (((new_height <= 0) ? FRAME_LINES (f) : new_height) + * FRAME_LINE_HEIGHT (f)); } -#endif - } - - SET_FRAME_COLS (f, new_cols); - FRAME_LINES (f) = new_lines; - FRAME_TEXT_WIDTH (f) = new_text_width; - FRAME_TEXT_HEIGHT (f) = new_text_height; - FRAME_PIXEL_WIDTH (f) = FRAME_TEXT_TO_PIXEL_WIDTH (f, new_text_width); - FRAME_PIXEL_HEIGHT (f) = FRAME_TEXT_TO_PIXEL_HEIGHT (f, new_text_height); - { - struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f)); - int text_area_x, text_area_y, text_area_width, text_area_height; - - window_box (w, TEXT_AREA, &text_area_x, &text_area_y, &text_area_width, - &text_area_height); - if (w->cursor.x >= text_area_x + text_area_width) - w->cursor.hpos = w->cursor.x = 0; - if (w->cursor.y >= text_area_y + text_area_height) - w->cursor.vpos = w->cursor.y = 0; - } + /* Adjust frame size but make sure x_set_window_size does not + get called. */ + adjust_frame_size (f, new_width, new_height, 5, pretend); + } +} - adjust_frame_glyphs (f); - calculate_costs (f); - SET_FRAME_GARBAGED (f); - f->resized_p = 1; - unblock_input (); +/* Change text height/width of frame F. Values may be given as zero to + indicate that no change is needed. - record_unwind_current_buffer (); + If DELAY, assume we're being called from a signal handler, and queue + the change for later - perhaps the next redisplay. Since this tries + to resize windows, we can't call it from a signal handler. - run_window_configuration_change_hook (f); + SAFE means this function is called from a place where it's safe to + change frame sizes while a redisplay is in progress. */ +void +change_frame_size (struct frame *f, int new_width, int new_height, + bool pretend, bool delay, bool safe, bool pixelwise) +{ + Lisp_Object tail, frame; - unbind_to (count, Qnil); + if (FRAME_MSDOS_P (f)) + { + /* On MS-DOS, all frames use the same screen, so a change in + size affects all frames. Termcap now supports multiple + ttys. */ + FOR_EACH_FRAME (tail, frame) + if (! FRAME_WINDOW_P (XFRAME (frame))) + change_frame_size_1 (XFRAME (frame), new_width, new_height, + pretend, delay, safe, pixelwise); + } + else + change_frame_size_1 (f, new_width, new_height, pretend, delay, safe, + pixelwise); } /*********************************************************************** @@ -6171,7 +6069,8 @@ init_display (void) t->display_info.tty->top_frame = selected_frame; change_frame_size (XFRAME (selected_frame), FrameCols (t->display_info.tty), - FrameRows (t->display_info.tty), 0, 0, 1, 0); + FrameRows (t->display_info.tty) + - FRAME_MENU_BAR_LINES (f), 0, 0, 1, 0); /* Delete the initial terminal. */ if (--initial_terminal->reference_count == 0 @@ -6193,7 +6092,7 @@ init_display (void) { struct frame *sf = SELECTED_FRAME (); int width = FRAME_TOTAL_COLS (sf); - int height = FRAME_LINES (sf); + int height = FRAME_TOTAL_LINES (sf); /* If these sizes are so big they cause overflow, just ignore the change. It's not clear what better we could do. The rest of diff --git a/src/eval.c b/src/eval.c index 7d54ddb18f5..4b2e256a722 100644 --- a/src/eval.c +++ b/src/eval.c @@ -92,10 +92,8 @@ static EMACS_INT when_entered_debugger; /* FIXME: We should probably get rid of this! */ Lisp_Object Vsignaling_function; -/* If non-nil, Lisp code must not be run since some part of Emacs is - in an inconsistent state. Currently, x-create-frame uses this to - avoid triggering window-configuration-change-hook while the new - frame is half-initialized. */ +/* If non-nil, Lisp code must not be run since some part of Emacs is in + an inconsistent state. Currently unused. */ Lisp_Object inhibit_lisp_code; /* These would ordinarily be static, but they need to be visible to GDB. */ diff --git a/src/frame.c b/src/frame.c index 80046bee788..0501b1e2c9c 100644 --- a/src/frame.c +++ b/src/frame.c @@ -85,6 +85,7 @@ Lisp_Object Qright_divider_width, Qbottom_divider_width; Lisp_Object Qmouse_color; Lisp_Object Qminibuffer; Lisp_Object Qscroll_bar_width, Qvertical_scroll_bars; +Lisp_Object Qscroll_bar_height, Qhorizontal_scroll_bars; Lisp_Object Qvisibility; Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background; Lisp_Object Qscreen_gamma; @@ -116,7 +117,7 @@ Lisp_Object Qface_set_after_frame_default; static Lisp_Object Qfocus_in_hook; static Lisp_Object Qfocus_out_hook; static Lisp_Object Qdelete_frame_functions; - +static Lisp_Object Qframe_windows_min_size; static Lisp_Object Qgeometry, Qworkarea, Qmm_size, Qframes, Qsource; /* The currently selected frame. */ @@ -193,6 +194,48 @@ check_window_system (struct frame *f) : "Window system is not in use or not initialized"); } + +/* Return the value of frame parameter PROP in frame FRAME. */ +#ifdef HAVE_WINDOW_SYSTEM +Lisp_Object +get_frame_param (register struct frame *frame, Lisp_Object prop) +{ + register Lisp_Object tem; + + tem = Fassq (prop, frame->param_alist); + if (EQ (tem, Qnil)) + return tem; + return Fcdr (tem); +} +#endif + + +/* Return 1 if `frame-inhibit-implied-resize' is non-nil or fullscreen + state of frame F would be affected by a vertical (horizontal if + HORIZONTAL is true) resize. */ +bool +frame_inhibit_resize (struct frame *f, bool horizontal) +{ + + return (frame_inhibit_implied_resize + || !NILP (get_frame_param (f, Qfullscreen))); +} + +#if 0 +bool +frame_inhibit_resize (struct frame *f, bool horizontal) +{ + Lisp_Object fullscreen = get_frame_param (f, Qfullscreen); + + return (frame_inhibit_implied_resize + || EQ (fullscreen, Qfullboth) + || EQ (fullscreen, Qfullscreen) + || EQ (fullscreen, Qmaximized) + || (horizontal && EQ (fullscreen, Qfullwidth)) + || (!horizontal && EQ (fullscreen, Qfullheight))); +} +#endif + static void set_menu_bar_lines_1 (Lisp_Object window, int n) { @@ -324,6 +367,247 @@ predicates which report frame's specific UI-related capabilities. */) return type; } +int +frame_windows_min_size (Lisp_Object frame, Lisp_Object horizontal, Lisp_Object pixelwise) +{ + return XINT (call3 (Qframe_windows_min_size, frame, horizontal, pixelwise)); +} + + +/* Make sure windows sizes of frame F are OK. new_width and new_height + are in pixels. A value of -1 means no change is requested for that + size (but the frame may still have to be resized to accomodate + windows with their minimum sizes. + + The argument INHIBIT can assume the following values: + + 0 means to unconditionally call x_set_window_size even if sizes + apparently do not change. Fx_create_frame uses this to pass the + initial size to the window manager. + + 1 means to call x_set_window_size iff the pixel size really changes. + Fset_frame_size, Fset_frame_height, ... use this. + + 2 means to unconditionally call x_set_window_size provided + frame_inhibit_resize allows it. The menu bar code uses this. + + 3 means call x_set_window_size iff window minimum sizes must be + preserved or frame_inhibit_resize allows it, x_set_left_fringe, + x_set_scroll_bar_width, ... use this. + + 4 means call x_set_window_size iff window minimum sizes must be + preserved. x_set_tool_bar_lines, x_set_right_divider_width, ... use + this. BUT maybe the toolbar code shouldn't .... + + 5 means to never call x_set_window_size. change_frame_size uses + this. + + For 2 and 3 note that if frame_inhibit_resize inhibits resizing and + minimum sizes are not violated no internal resizing takes place + either. For 2, 3, 4 and 5 note that even if no x_set_window_size + call is issued, window sizes may have to be adjusted in order to + support minimum size constraints for the frame's windows. + + PRETEND is as for change_frame_size. */ +void +adjust_frame_size (struct frame *f, int new_width, int new_height, int inhibit, bool pretend) +{ + int unit_width = FRAME_COLUMN_WIDTH (f); + int unit_height = FRAME_LINE_HEIGHT (f); + int old_pixel_width = FRAME_PIXEL_WIDTH (f); + int old_pixel_height = FRAME_PIXEL_HEIGHT (f); + int new_pixel_width, new_pixel_height; + /* The following two values are calculated from the old frame pixel + sizes and any "new" settings for tool bar, menu bar and internal + borders. We do it this way to detect whether we have to call + x_set_window_size as consequence of the new settings. */ + int windows_width = FRAME_WINDOWS_WIDTH (f); + int windows_height = FRAME_WINDOWS_HEIGHT (f); + int min_windows_width, min_windows_height; + /* These are a bit tedious, maybe we should use a macro. */ + struct window *r = XWINDOW (FRAME_ROOT_WINDOW (f)); + int old_windows_width = WINDOW_PIXEL_WIDTH (r); + int old_windows_height + = (WINDOW_PIXEL_HEIGHT (r) + + (FRAME_HAS_MINIBUF_P (f) + ? WINDOW_PIXEL_HEIGHT (XWINDOW (FRAME_MINIBUF_WINDOW (f))) + : 0)); + int new_windows_width, new_windows_height; + int old_text_width = FRAME_TEXT_WIDTH (f); + int old_text_height = FRAME_TEXT_HEIGHT (f); + /* If a size is < 0 use the old value. */ + int new_text_width = (new_width >= 0) ? new_width : old_text_width; + int new_text_height = (new_height >= 0) ? new_height : old_text_height; + int new_cols, new_lines; + bool inhibit_horizontal, inhibit_vertical; + Lisp_Object frame; + + XSETFRAME (frame, f); + /* The following two values are calculated from the old window body + sizes and any "new" settings for scroll bars, dividers, fringes and + margins (though the latter should have been processed already). */ + min_windows_width = frame_windows_min_size (frame, Qt, Qt); + min_windows_height = frame_windows_min_size (frame, Qnil, Qt); + + if (inhibit >= 2 && inhibit <= 4) + /* If INHIBIT is in [2..4] inhibit if the "old" window sizes stay + within the limits and either frame_inhibit_resize tells us to do + so or INHIBIT equals 4. */ + { + inhibit_horizontal = ((windows_width >= min_windows_width + && (inhibit == 4 || frame_inhibit_resize (f, true))) + ? true : false); + inhibit_vertical = ((windows_height >= min_windows_height + && (inhibit == 4 || frame_inhibit_resize (f, false))) + ? true : false); + } + else + /* Otherwise inhibit if INHIBIT equals 5. */ + inhibit_horizontal = inhibit_vertical = inhibit == 5; + + new_pixel_width = ((inhibit_horizontal && (inhibit < 5)) + ? old_pixel_width + : max (FRAME_TEXT_TO_PIXEL_WIDTH (f, new_text_width), + min_windows_width + + 2 * FRAME_INTERNAL_BORDER_WIDTH (f))); + new_windows_width = new_pixel_width - 2 * FRAME_INTERNAL_BORDER_WIDTH (f); + new_text_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, new_pixel_width); + new_cols = new_text_width / unit_width; + + new_pixel_height = ((inhibit_vertical && (inhibit < 5)) + ? old_pixel_height + : max (FRAME_TEXT_TO_PIXEL_HEIGHT (f, new_text_height), + min_windows_height + + FRAME_TOP_MARGIN_HEIGHT (f) + + 2 * FRAME_INTERNAL_BORDER_WIDTH (f))); + new_windows_height = (new_pixel_height + - FRAME_TOP_MARGIN_HEIGHT (f) + - 2 * FRAME_INTERNAL_BORDER_WIDTH (f)); + new_text_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, new_pixel_height); + new_lines = new_text_height / unit_height; + +#ifdef HAVE_WINDOW_SYSTEM + if (FRAME_X_WINDOW (f) + && f->official + && ((!inhibit_horizontal + && (new_pixel_width != old_pixel_width + || inhibit == 0 || inhibit == 2)) + || (!inhibit_vertical + && (new_pixel_height != old_pixel_height + || inhibit == 0 || inhibit == 2)))) + /* We are either allowed to change the frame size or the minimum + sizes request such a change. Do not care for fixing minimum + sizes here, we do that eventually when we're called from + change_frame_size. */ + { + /* Make sure we respect fullheight and fullwidth. */ + if (inhibit_horizontal) + new_text_width = old_text_width; + else if (inhibit_vertical) + new_text_height = old_text_height; + + x_set_window_size (f, 0, new_text_width, new_text_height, 1); + f->resized_p = true; + + return; + } +#endif + + if (new_text_width == old_text_width + && new_text_height == old_text_height + && new_windows_width == old_windows_width + && new_windows_height == old_windows_height + && new_pixel_width == old_pixel_width + && new_pixel_height == old_pixel_height) + /* No change. Sanitize window sizes and return. */ + { + sanitize_window_sizes (frame, Qt); + sanitize_window_sizes (frame, Qnil); + + return; + } + + block_input (); + +#ifdef MSDOS + /* We only can set screen dimensions to certain values supported + by our video hardware. Try to find the smallest size greater + or equal to the requested dimensions. */ + dos_set_window_size (&new_lines, &new_cols); +#endif + + if (new_windows_width != old_windows_width) + { + resize_frame_windows (f, new_windows_width, 1, 1); + + /* MSDOS frames cannot PRETEND, as they change frame size by + manipulating video hardware. */ + if ((FRAME_TERMCAP_P (f) && !pretend) || FRAME_MSDOS_P (f)) + FrameCols (FRAME_TTY (f)) = new_cols; + +#if defined (HAVE_WINDOW_SYSTEM) && ! defined (USE_GTK) && ! defined (HAVE_NS) + if (WINDOWP (f->tool_bar_window)) + { + XWINDOW (f->tool_bar_window)->pixel_width = new_windows_width; + XWINDOW (f->tool_bar_window)->total_cols + = new_windows_width / unit_width; + } +#endif + } + + if (new_windows_height != old_windows_height + /* When the top margin has changed we have to recalculate the top + edges of all windows. No such calculation is necessary for the + left edges. */ + || WINDOW_TOP_PIXEL_EDGE (r) != FRAME_TOP_MARGIN_HEIGHT (f)) + { + resize_frame_windows (f, new_windows_height, 0, 1); + + /* MSDOS frames cannot PRETEND, as they change frame size by + manipulating video hardware. */ + if ((FRAME_TERMCAP_P (f) && !pretend) || FRAME_MSDOS_P (f)) + FrameRows (FRAME_TTY (f)) = new_lines; + } + + /* Assign new sizes. */ + FRAME_TEXT_WIDTH (f) = new_text_width; + FRAME_TEXT_HEIGHT (f) = new_text_height; + FRAME_PIXEL_WIDTH (f) = new_pixel_width; + FRAME_PIXEL_HEIGHT (f) = new_pixel_height; + SET_FRAME_COLS (f, new_cols); + SET_FRAME_LINES (f, new_lines); + + { + struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f)); + int text_area_x, text_area_y, text_area_width, text_area_height; + + window_box (w, TEXT_AREA, &text_area_x, &text_area_y, &text_area_width, + &text_area_height); + if (w->cursor.x >= text_area_x + text_area_width) + w->cursor.hpos = w->cursor.x = 0; + if (w->cursor.y >= text_area_y + text_area_height) + w->cursor.vpos = w->cursor.y = 0; + } + + /* Sanitize window sizes. */ + sanitize_window_sizes (frame, Qt); + sanitize_window_sizes (frame, Qnil); + + adjust_frame_glyphs (f); + calculate_costs (f); + SET_FRAME_GARBAGED (f); + + /* A frame was "resized" if one of its pixelsizes changed, even if its + X window wasn't resized at all. */ + f->resized_p = (new_pixel_width != old_pixel_width + || new_pixel_height != old_pixel_height); + + unblock_input (); + + run_window_configuration_change_hook (f); +} + + struct frame * make_frame (bool mini_p) { @@ -349,10 +633,12 @@ make_frame (bool mini_p) f->wants_modeline = true; f->redisplay = true; f->garbaged = true; + f->official = false; f->column_width = 1; /* !FRAME_WINDOW_P value. */ f->line_height = 1; /* !FRAME_WINDOW_P value. */ #ifdef HAVE_WINDOW_SYSTEM f->vertical_scroll_bar_type = vertical_scroll_bar_none; + f->horizontal_scroll_bars = false; f->want_fullscreen = FULLSCREEN_NONE; #if ! defined (USE_GTK) && ! defined (HAVE_NS) f->last_tool_bar_item = -1; @@ -382,10 +668,10 @@ make_frame (bool mini_p) /* 10 is arbitrary, just so that there is "something there." - Correct size will be set up later with change_frame_size. */ + Correct size will be set up later with adjust_frame_size. */ SET_FRAME_COLS (f, 10); - FRAME_LINES (f) = 10; + SET_FRAME_LINES (f, 10); SET_FRAME_WIDTH (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f)); SET_FRAME_HEIGHT (f, FRAME_LINES (f) * FRAME_LINE_HEIGHT (f)); @@ -423,11 +709,15 @@ make_frame (bool mini_p) } if (mini_p) - set_window_buffer (mini_window, - (NILP (Vminibuffer_list) - ? get_minibuffer (0) - : Fcar (Vminibuffer_list)), - 0, 0); + { + set_window_buffer (mini_window, + (NILP (Vminibuffer_list) + ? get_minibuffer (0) + : Fcar (Vminibuffer_list)), + 0, 0); + /* No horizontal scroll bars in minibuffers. */ + wset_horizontal_scroll_bar (mw, Qnil); + } fset_root_window (f, root_window); fset_selected_window (f, root_window); @@ -573,6 +863,7 @@ make_initial_frame (void) #ifdef HAVE_WINDOW_SYSTEM f->vertical_scroll_bar_type = vertical_scroll_bar_none; + FRAME_HAS_HORIZONTAL_SCROLL_BARS (f) = false; #endif /* The default value of menu-bar-mode is t. */ @@ -625,6 +916,7 @@ make_terminal_frame (struct terminal *terminal) #ifdef HAVE_WINDOW_SYSTEM f->vertical_scroll_bar_type = vertical_scroll_bar_none; + FRAME_HAS_HORIZONTAL_SCROLL_BARS (f) = false; #endif FRAME_MENU_BAR_LINES (f) = NILP (Vmenu_bar_mode) ? 0 : 1; @@ -748,7 +1040,7 @@ affects all frames on the same terminal device. */) { int width, height; get_tty_size (fileno (FRAME_TTY (f)->input), &width, &height); - change_frame_size (f, width, height, 0, 0, 0, 0); + adjust_frame_size (f, width, height, 5, 0); } adjust_frame_glyphs (f); @@ -1983,21 +2275,6 @@ If there is no window system support, this function does nothing. */) } -/* Return the value of frame parameter PROP in frame FRAME. */ - -#ifdef HAVE_WINDOW_SYSTEM -Lisp_Object -get_frame_param (register struct frame *frame, Lisp_Object prop) -{ - register Lisp_Object tem; - - tem = Fassq (prop, frame->param_alist); - if (EQ (tem, Qnil)) - return tem; - return Fcdr (tem); -} -#endif - /* Discard BUFFER from the buffer-list and buried-buffer-list of each frame. */ void @@ -2240,7 +2517,7 @@ If FRAME is omitted or nil, return information on the currently selected frame. ? (f->new_pixelwise ? (f->new_height / FRAME_LINE_HEIGHT (f)) : f->new_height) - : FRAME_LINES (f)) - FRAME_TOP_MARGIN (f); + : FRAME_LINES (f)); store_in_alist (&alist, Qheight, make_number (height)); width = (f->new_width ? (f->new_pixelwise @@ -2511,12 +2788,19 @@ DEFUN ("frame-text-lines", Fframe_text_lines, Sframe_text_lines, 0, 1, 0, } DEFUN ("frame-total-cols", Fframe_total_cols, Sframe_total_cols, 0, 1, 0, - doc: /* Return total columns of FRAME. */) + doc: /* Return number of total columns of FRAME. */) (Lisp_Object frame) { return make_number (FRAME_TOTAL_COLS (decode_any_frame (frame))); } +DEFUN ("frame-total-lines", Fframe_total_lines, Sframe_total_lines, 0, 1, 0, + doc: /* Return number of total lines of FRAME. */) + (Lisp_Object frame) +{ + return make_number (FRAME_TOTAL_LINES (decode_any_frame (frame))); +} + DEFUN ("frame-text-width", Fframe_text_width, Sframe_text_width, 0, 1, 0, doc: /* Return text area width of FRAME in pixels. */) (Lisp_Object frame) @@ -2538,6 +2822,13 @@ DEFUN ("frame-scroll-bar-width", Fscroll_bar_width, Sscroll_bar_width, 0, 1, 0, return make_number (FRAME_SCROLL_BAR_AREA_WIDTH (decode_any_frame (frame))); } +DEFUN ("frame-scroll-bar-height", Fscroll_bar_height, Sscroll_bar_height, 0, 1, 0, + doc: /* Return scroll bar height of FRAME in pixels. */) + (Lisp_Object frame) +{ + return make_number (FRAME_SCROLL_BAR_AREA_HEIGHT (decode_any_frame (frame))); +} + DEFUN ("frame-fringe-width", Ffringe_width, Sfringe_width, 0, 1, 0, doc: /* Return fringe width of FRAME in pixels. */) (Lisp_Object frame) @@ -2566,20 +2857,6 @@ DEFUN ("frame-bottom-divider-width", Fbottom_divider_width, Sbottom_divider_widt return make_number (FRAME_BOTTOM_DIVIDER_WIDTH (decode_any_frame (frame))); } -/* For requested height in *HEIGHTP, calculate new height of frame F in - character units and return true if actual height should be changed. */ - -static bool -adjust_frame_height (struct frame *f, int *heightp) -{ - if (FRAME_LINES (f) - FRAME_TOP_MARGIN (f) != *heightp) - { - *heightp += FRAME_TOP_MARGIN (f); - return 1; - } - return 0; -} - DEFUN ("set-frame-height", Fset_frame_height, Sset_frame_height, 2, 4, 0, doc: /* Specify that the frame FRAME has HEIGHT text lines. Optional third arg PRETEND non-nil means that redisplay should use @@ -2588,33 +2865,17 @@ not be changed. Optional fourth argument PIXELWISE non-nil means that FRAME should be HEIGHT pixels high. */) (Lisp_Object frame, Lisp_Object height, Lisp_Object pretend, Lisp_Object pixelwise) { - register struct frame *f = decode_live_frame (frame); + struct frame *f = decode_live_frame (frame); + int pixel_height; CHECK_TYPE_RANGED_INTEGER (int, height); - /* I think this should be done with a hook. */ -#ifdef HAVE_WINDOW_SYSTEM - if (FRAME_WINDOW_P (f)) - { - if (NILP (pixelwise)) - { - int h = XINT (height); - - if (adjust_frame_height (f, &h)) - x_set_window_size (f, 1, FRAME_COLS (f), h, 0); + pixel_height = (!NILP (pixelwise) + ? XINT (height) + : XINT (height) * FRAME_LINE_HEIGHT (f)); + if (pixel_height != FRAME_TEXT_HEIGHT (f)) + adjust_frame_size (f, -1, pixel_height, 1, !NILP (pretend)); - do_pending_window_change (0); - } - else if (XINT (height) != FRAME_TEXT_HEIGHT (f)) - { - x_set_window_size (f, 1, FRAME_TEXT_WIDTH (f), XINT (height), 1); - do_pending_window_change (0); - } - } - else -#endif - change_frame_size (f, 0, XINT (height), !NILP (pretend), 0, 0, - NILP (pixelwise) ? 0 : 1); return Qnil; } @@ -2626,31 +2887,17 @@ be changed. Optional fourth argument PIXELWISE non-nil means that FRAME should be WIDTH pixels wide. */) (Lisp_Object frame, Lisp_Object width, Lisp_Object pretend, Lisp_Object pixelwise) { - register struct frame *f = decode_live_frame (frame); + struct frame *f = decode_live_frame (frame); + int pixel_width; CHECK_TYPE_RANGED_INTEGER (int, width); - /* I think this should be done with a hook. */ -#ifdef HAVE_WINDOW_SYSTEM - if (FRAME_WINDOW_P (f)) - { - if (NILP (pixelwise)) - { - if (XINT (width) != FRAME_COLS (f)) - x_set_window_size (f, 1, XINT (width), FRAME_LINES (f), 0); + pixel_width = (!NILP (pixelwise) + ? XINT (width) + : XINT (width) * FRAME_COLUMN_WIDTH (f)); + if (pixel_width != FRAME_TEXT_WIDTH (f)) + adjust_frame_size (f, pixel_width, -1, 1, !NILP (pretend)); - do_pending_window_change (0); - } - else if (XINT (width) != FRAME_TEXT_WIDTH (f)) - { - x_set_window_size (f, 1, XINT (width), FRAME_TEXT_HEIGHT (f), 1); - do_pending_window_change (0); - } - } - else -#endif - change_frame_size (f, XINT (width), 0, !NILP (pretend), 0, 0, - NILP (pixelwise) ? 0 : 1); return Qnil; } @@ -2659,34 +2906,22 @@ DEFUN ("set-frame-size", Fset_frame_size, Sset_frame_size, 3, 4, 0, Optional argument PIXELWISE non-nil means to measure in pixels. */) (Lisp_Object frame, Lisp_Object width, Lisp_Object height, Lisp_Object pixelwise) { - register struct frame *f = decode_live_frame (frame); + struct frame *f = decode_live_frame (frame); + int pixel_width, pixel_height; CHECK_TYPE_RANGED_INTEGER (int, width); CHECK_TYPE_RANGED_INTEGER (int, height); - /* I think this should be done with a hook. */ -#ifdef HAVE_WINDOW_SYSTEM - if (FRAME_WINDOW_P (f)) - { - int h = XINT (height); - - if (!NILP (pixelwise) - ? (XINT (width) != FRAME_TEXT_WIDTH (f) - || h != FRAME_TEXT_HEIGHT (f) - || f->new_height || f->new_width) - : (adjust_frame_height (f, &h) - || XINT (width) != FRAME_COLS (f) - || f->new_height || f->new_width)) - { - x_set_window_size (f, 1, XINT (width), h, - NILP (pixelwise) ? 0 : 1); - do_pending_window_change (0); - } - } - else -#endif - change_frame_size (f, XINT (width), XINT (height), 0, 0, 0, - NILP (pixelwise) ? 0 : 1); + pixel_width = (!NILP (pixelwise) + ? XINT (width) + : XINT (width) * FRAME_COLUMN_WIDTH (f)); + pixel_height = (!NILP (pixelwise) + ? XINT (height) + : XINT (height) * FRAME_LINE_HEIGHT (f)); + + if (pixel_width != FRAME_TEXT_WIDTH (f) + || pixel_height != FRAME_TEXT_HEIGHT (f)) + adjust_frame_size (f, pixel_width, pixel_height, 1, 0); return Qnil; } @@ -2751,9 +2986,11 @@ static const struct frame_parm_table frame_parms[] = {"mouse-color", &Qmouse_color}, {"name", &Qname}, {"scroll-bar-width", &Qscroll_bar_width}, + {"scroll-bar-height", &Qscroll_bar_height}, {"title", &Qtitle}, {"unsplittable", &Qunsplittable}, {"vertical-scroll-bars", &Qvertical_scroll_bars}, + {"horizontal-scroll-bars", &Qhorizontal_scroll_bars}, {"visibility", &Qvisibility}, {"tool-bar-lines", &Qtool_bar_lines}, {"scroll-bar-foreground", &Qscroll_bar_foreground}, @@ -2786,7 +3023,7 @@ x_set_frame_parameters (struct frame *f, Lisp_Object alist) /* If both of these parameters are present, it's more efficient to set them both at once. So we wait until we've looked at the entire list before we set them. */ - int width = 0, height = 0; + int width, height; bool width_change = 0, height_change = 0; /* Same here. */ @@ -2964,9 +3201,6 @@ x_set_frame_parameters (struct frame *f, Lisp_Object alist) { Lisp_Object frame; - /* Make this 1, eventually. */ - check_frame_size (f, &width, &height, 1); - XSETFRAME (frame, f); if ((width_change || height_change) @@ -3117,6 +3351,14 @@ x_report_frame_params (struct frame *f, Lisp_Object *alistptr) for non-toolkit scroll bar. ruler-mode.el depends on this. */ : Qnil)); + store_in_alist (alistptr, Qscroll_bar_height, + (! FRAME_HAS_HORIZONTAL_SCROLL_BARS (f) + ? make_number (0) + : FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0 + ? make_number (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f)) + /* nil means "use default height" + for non-toolkit scroll bar. */ + : Qnil)); /* FRAME_X_WINDOW is not guaranteed to return an integer. E.g., on MS-Windows it returns a value whose type is HANDLE, which is actually a pointer. Explicit casting avoids compiler @@ -3393,58 +3635,66 @@ x_set_font_backend (struct frame *f, Lisp_Object new_value, Lisp_Object old_valu } } - void -x_set_fringe_width (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +x_set_left_fringe (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) { - compute_fringe_widths (f, 1); -#ifdef HAVE_X_WINDOWS - /* Must adjust this so window managers report correct number of columns. */ - if (FRAME_X_WINDOW (f) != 0) - x_wm_set_size_hint (f, 0, 0); -#endif + int unit = FRAME_COLUMN_WIDTH (f); + int old_width = FRAME_LEFT_FRINGE_WIDTH (f); + int new_width; + + new_width = (RANGED_INTEGERP (-INT_MAX, new_value, INT_MAX) + ? eabs (XINT (new_value)) : 8); + + if (new_width != old_width) + { + FRAME_LEFT_FRINGE_WIDTH (f) = new_width; + FRAME_FRINGE_COLS (f) /* Round up. */ + = (new_width + FRAME_RIGHT_FRINGE_WIDTH (f) + unit - 1) / unit; + + if (FRAME_X_WINDOW (f) != 0) + adjust_frame_size (f, -1, -1, 3, 0); + + SET_FRAME_GARBAGED (f); + } } + void -x_set_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval) +x_set_right_fringe (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) { - CHECK_TYPE_RANGED_INTEGER (int, arg); + int unit = FRAME_COLUMN_WIDTH (f); + int old_width = FRAME_RIGHT_FRINGE_WIDTH (f); + int new_width; - if (XINT (arg) == f->border_width) - return; + new_width = (RANGED_INTEGERP (-INT_MAX, new_value, INT_MAX) + ? eabs (XINT (new_value)) : 8); - if (FRAME_X_WINDOW (f) != 0) - error ("Cannot change the border width of a frame"); + if (new_width != old_width) + { + FRAME_RIGHT_FRINGE_WIDTH (f) = new_width; + FRAME_FRINGE_COLS (f) /* Round up. */ + = (new_width + FRAME_LEFT_FRINGE_WIDTH (f) + unit - 1) / unit; - f->border_width = XINT (arg); + if (FRAME_X_WINDOW (f) != 0) + adjust_frame_size (f, -1, -1, 3, 0); + + SET_FRAME_GARBAGED (f); + } } + void -x_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval) +x_set_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval) { - int old = FRAME_INTERNAL_BORDER_WIDTH (f); - CHECK_TYPE_RANGED_INTEGER (int, arg); - FRAME_INTERNAL_BORDER_WIDTH (f) = XINT (arg); - if (FRAME_INTERNAL_BORDER_WIDTH (f) < 0) - FRAME_INTERNAL_BORDER_WIDTH (f) = 0; -#ifdef USE_X_TOOLKIT - if (FRAME_X_OUTPUT (f)->edit_widget) - widget_store_internal_border (FRAME_X_OUTPUT (f)->edit_widget); -#endif - - if (FRAME_INTERNAL_BORDER_WIDTH (f) == old) + if (XINT (arg) == f->border_width) return; if (FRAME_X_WINDOW (f) != 0) - { - x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 1); - SET_FRAME_GARBAGED (f); - do_pending_window_change (0); - } - else - SET_FRAME_GARBAGED (f); + error ("Cannot change the border width of a frame"); + + f->border_width = XINT (arg); } void @@ -3456,18 +3706,13 @@ x_set_right_divider_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval) FRAME_RIGHT_DIVIDER_WIDTH (f) = XINT (arg); if (FRAME_RIGHT_DIVIDER_WIDTH (f) < 0) FRAME_RIGHT_DIVIDER_WIDTH (f) = 0; - - if (FRAME_RIGHT_DIVIDER_WIDTH (f) == old) - return; - - if (FRAME_X_WINDOW (f) != 0) + if (FRAME_RIGHT_DIVIDER_WIDTH (f) != old) { - x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 1); + adjust_frame_size (f, -1, -1, 4, 0); + adjust_frame_glyphs (f); SET_FRAME_GARBAGED (f); - do_pending_window_change (0); } - else - SET_FRAME_GARBAGED (f); + } void @@ -3479,18 +3724,12 @@ x_set_bottom_divider_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval FRAME_BOTTOM_DIVIDER_WIDTH (f) = XINT (arg); if (FRAME_BOTTOM_DIVIDER_WIDTH (f) < 0) FRAME_BOTTOM_DIVIDER_WIDTH (f) = 0; - - if (FRAME_BOTTOM_DIVIDER_WIDTH (f) == old) - return; - - if (FRAME_X_WINDOW (f) != 0) + if (FRAME_BOTTOM_DIVIDER_WIDTH (f) != old) { - x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 1); + adjust_frame_size (f, -1, -1, 4, 0); + adjust_frame_glyphs (f); SET_FRAME_GARBAGED (f); - do_pending_window_change (0); } - else - SET_FRAME_GARBAGED (f); } void @@ -3531,7 +3770,7 @@ x_set_vertical_scroll_bars (struct frame *f, Lisp_Object arg, Lisp_Object oldval if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f)) || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)) || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f)) - || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f))) + || (!NILP (arg) && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))) { FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = (NILP (arg) @@ -3551,12 +3790,34 @@ x_set_vertical_scroll_bars (struct frame *f, Lisp_Object arg, Lisp_Object oldval However, if the window hasn't been created yet, we shouldn't call x_set_window_size. */ if (FRAME_X_WINDOW (f)) - x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f), - FRAME_TEXT_HEIGHT (f), 1); - do_pending_window_change (0); + adjust_frame_size (f, -1, -1, 3, 0); + + SET_FRAME_GARBAGED (f); } } +void +x_set_horizontal_scroll_bars (struct frame *f, Lisp_Object arg, Lisp_Object oldval) +{ +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI) + if ((NILP (arg) && FRAME_HAS_HORIZONTAL_SCROLL_BARS (f)) + || (!NILP (arg) && !FRAME_HAS_HORIZONTAL_SCROLL_BARS (f))) + { + FRAME_HAS_HORIZONTAL_SCROLL_BARS (f) + = NILP (arg) ? false : true; + + /* We set this parameter before creating the X window for the + frame, so we can get the geometry right from the start. + However, if the window hasn't been created yet, we shouldn't + call x_set_window_size. */ + if (FRAME_X_WINDOW (f)) + adjust_frame_size (f, -1, -1, 3, 0); + + SET_FRAME_GARBAGED (f); + } +#endif +} + void x_set_scroll_bar_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval) { @@ -3567,9 +3828,9 @@ x_set_scroll_bar_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval) x_set_scroll_bar_default_width (f); if (FRAME_X_WINDOW (f)) - x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f), - FRAME_TEXT_HEIGHT (f), 1); - do_pending_window_change (0); + adjust_frame_size (f, -1, -1, 3, 0); + + SET_FRAME_GARBAGED (f); } else if (RANGED_INTEGERP (1, arg, INT_MAX) && XFASTINT (arg) != FRAME_CONFIG_SCROLL_BAR_WIDTH (f)) @@ -3577,18 +3838,46 @@ x_set_scroll_bar_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval) FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = XFASTINT (arg); FRAME_CONFIG_SCROLL_BAR_COLS (f) = (XFASTINT (arg) + unit - 1) / unit; if (FRAME_X_WINDOW (f)) - x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f), - FRAME_TEXT_HEIGHT (f), 1); - do_pending_window_change (0); + adjust_frame_size (f, -1, -1, 3, 0); + + SET_FRAME_GARBAGED (f); } - /* Eventually remove the following call. It should have been done by - x_set_window_size already. */ - change_frame_size (f, 0, 0, 0, 0, 0, 1); XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0; XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0; } +void +x_set_scroll_bar_height (struct frame *f, Lisp_Object arg, Lisp_Object oldval) +{ +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI) + int unit = FRAME_LINE_HEIGHT (f); + + if (NILP (arg)) + { + x_set_scroll_bar_default_height (f); + + if (FRAME_X_WINDOW (f)) + adjust_frame_size (f, -1, -1, 3, 0); + + SET_FRAME_GARBAGED (f); + } + else if (RANGED_INTEGERP (1, arg, INT_MAX) + && XFASTINT (arg) != FRAME_CONFIG_SCROLL_BAR_HEIGHT (f)) + { + FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = XFASTINT (arg); + FRAME_CONFIG_SCROLL_BAR_LINES (f) = (XFASTINT (arg) + unit - 1) / unit; + if (FRAME_X_WINDOW (f)) + adjust_frame_size (f, -1, -1, 3, 0); + + SET_FRAME_GARBAGED (f); + } + + XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.vpos = 0; + XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.y = 0; +#endif +} + void x_set_alpha (struct frame *f, Lisp_Object arg, Lisp_Object oldval) { @@ -4190,7 +4479,7 @@ On Nextstep, this just calls `ns-parse-geometry'. */) long x_figure_window_size (struct frame *f, Lisp_Object parms, bool toolbar_p) { - register Lisp_Object tem0, tem1, tem2; + Lisp_Object height, width, user_size, top, left, user_position; long window_prompting = 0; Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f); @@ -4200,58 +4489,54 @@ x_figure_window_size (struct frame *f, Lisp_Object parms, bool toolbar_p) SET_FRAME_WIDTH (f, DEFAULT_COLS * FRAME_COLUMN_WIDTH (f)); SET_FRAME_COLS (f, DEFAULT_COLS); SET_FRAME_HEIGHT (f, DEFAULT_ROWS * FRAME_LINE_HEIGHT (f)); - FRAME_LINES (f) = DEFAULT_ROWS; + SET_FRAME_LINES (f, DEFAULT_ROWS); /* Window managers expect that if program-specified positions are not (0,0), they're intentional, not defaults. */ f->top_pos = 0; f->left_pos = 0; - /* Ensure that old new_width and new_height will not override the - values set here. */ - /* ++KFS: This was specific to W32, but seems ok for all platforms */ - f->new_width = f->new_height = f->new_pixelwise = 0; + /* Ensure that earlier new_width and new_height settings won't + override what we specify below. */ + f->new_width = f->new_height = 0; - tem0 = x_get_arg (dpyinfo, parms, Qheight, 0, 0, RES_TYPE_NUMBER); - tem1 = x_get_arg (dpyinfo, parms, Qwidth, 0, 0, RES_TYPE_NUMBER); - tem2 = x_get_arg (dpyinfo, parms, Quser_size, 0, 0, RES_TYPE_NUMBER); - if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound)) + height = x_get_arg (dpyinfo, parms, Qheight, 0, 0, RES_TYPE_NUMBER); + width = x_get_arg (dpyinfo, parms, Qwidth, 0, 0, RES_TYPE_NUMBER); + if (!EQ (width, Qunbound) || !EQ (height, Qunbound)) { - if (!EQ (tem0, Qunbound)) + if (!EQ (width, Qunbound)) { - CHECK_NUMBER (tem0); - if (! (0 <= XINT (tem0) && XINT (tem0) <= INT_MAX)) - xsignal1 (Qargs_out_of_range, tem0); - FRAME_LINES (f) = XINT (tem0); + CHECK_NUMBER (width); + if (! (0 <= XINT (width) && XINT (width) <= INT_MAX)) + xsignal1 (Qargs_out_of_range, width); + + SET_FRAME_WIDTH (f, XINT (width) * FRAME_COLUMN_WIDTH (f)); } - if (!EQ (tem1, Qunbound)) + + if (!EQ (height, Qunbound)) { - CHECK_NUMBER (tem1); - if (! (0 <= XINT (tem1) && XINT (tem1) <= INT_MAX)) - xsignal1 (Qargs_out_of_range, tem1); - SET_FRAME_COLS (f, XINT (tem1)); + CHECK_NUMBER (height); + if (! (0 <= XINT (height) && XINT (height) <= INT_MAX)) + xsignal1 (Qargs_out_of_range, height); + + SET_FRAME_HEIGHT (f, XINT (height) * FRAME_LINE_HEIGHT (f)); } - if (!NILP (tem2) && !EQ (tem2, Qunbound)) + + user_size = x_get_arg (dpyinfo, parms, Quser_size, 0, 0, RES_TYPE_NUMBER); + if (!NILP (user_size) && !EQ (user_size, Qunbound)) window_prompting |= USSize; else window_prompting |= PSize; } - - /* This used to be done _before_ calling x_figure_window_size, but - since the height is reset here, this was really a no-op. I - assume that moving it here does what Gerd intended (although he - no longer can remember what that was... ++KFS, 2003-03-25. */ - - /* Add the tool-bar height to the initial frame height so that the - user gets a text display area of the size he specified with -g or - via .Xdefaults. Later changes of the tool-bar height don't - change the frame size. This is done so that users can create - tall Emacs frames without having to guess how tall the tool-bar - will get. */ - if (toolbar_p && FRAME_TOOL_BAR_HEIGHT (f)) + /* Add a tool bar height to the initial frame height so that the user + gets a text display area of the size he specified with -g or via + .Xdefaults. Later changes of the tool bar height don't change the + frame size. This is done so that users can create tall Emacs + frames without having to guess how tall the tool bar will get. */ + if (toolbar_p && FRAME_TOOL_BAR_LINES (f)) { - int margin, relief, bar_height; + int margin, relief; relief = (tool_bar_button_relief >= 0 ? tool_bar_button_relief @@ -4265,78 +4550,73 @@ x_figure_window_size (struct frame *f, Lisp_Object parms, bool toolbar_p) else margin = 0; - /* PXW: We should be able to not round here. */ - bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief; - FRAME_LINES (f) += (bar_height + FRAME_LINE_HEIGHT (f) - 1) / FRAME_LINE_HEIGHT (f); + FRAME_TOOL_BAR_HEIGHT (f) + = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief; + Vframe_initial_frame_tool_bar_height = make_number (FRAME_TOOL_BAR_HEIGHT (f)); } - compute_fringe_widths (f, 0); - - SET_FRAME_WIDTH (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f)); - SET_FRAME_HEIGHT(f, FRAME_LINES (f) * FRAME_LINE_HEIGHT (f)); - - tem0 = x_get_arg (dpyinfo, parms, Qtop, 0, 0, RES_TYPE_NUMBER); - tem1 = x_get_arg (dpyinfo, parms, Qleft, 0, 0, RES_TYPE_NUMBER); - tem2 = x_get_arg (dpyinfo, parms, Quser_position, 0, 0, RES_TYPE_NUMBER); - if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound)) + top = x_get_arg (dpyinfo, parms, Qtop, 0, 0, RES_TYPE_NUMBER); + left = x_get_arg (dpyinfo, parms, Qleft, 0, 0, RES_TYPE_NUMBER); + user_position = x_get_arg (dpyinfo, parms, Quser_position, 0, 0, RES_TYPE_NUMBER); + if (! EQ (top, Qunbound) || ! EQ (left, Qunbound)) { - if (EQ (tem0, Qminus)) + if (EQ (top, Qminus)) { f->top_pos = 0; window_prompting |= YNegative; } - else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus) - && CONSP (XCDR (tem0)) - && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (tem0)), INT_MAX)) + else if (CONSP (top) && EQ (XCAR (top), Qminus) + && CONSP (XCDR (top)) + && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (top)), INT_MAX)) { - f->top_pos = - XINT (XCAR (XCDR (tem0))); + f->top_pos = - XINT (XCAR (XCDR (top))); window_prompting |= YNegative; } - else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus) - && CONSP (XCDR (tem0)) - && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (tem0)))) + else if (CONSP (top) && EQ (XCAR (top), Qplus) + && CONSP (XCDR (top)) + && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (top)))) { - f->top_pos = XINT (XCAR (XCDR (tem0))); + f->top_pos = XINT (XCAR (XCDR (top))); } - else if (EQ (tem0, Qunbound)) + else if (EQ (top, Qunbound)) f->top_pos = 0; else { - CHECK_TYPE_RANGED_INTEGER (int, tem0); - f->top_pos = XINT (tem0); + CHECK_TYPE_RANGED_INTEGER (int, top); + f->top_pos = XINT (top); if (f->top_pos < 0) window_prompting |= YNegative; } - if (EQ (tem1, Qminus)) + if (EQ (left, Qminus)) { f->left_pos = 0; window_prompting |= XNegative; } - else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus) - && CONSP (XCDR (tem1)) - && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (tem1)), INT_MAX)) + else if (CONSP (left) && EQ (XCAR (left), Qminus) + && CONSP (XCDR (left)) + && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (left)), INT_MAX)) { - f->left_pos = - XINT (XCAR (XCDR (tem1))); + f->left_pos = - XINT (XCAR (XCDR (left))); window_prompting |= XNegative; } - else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus) - && CONSP (XCDR (tem1)) - && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (tem1)))) + else if (CONSP (left) && EQ (XCAR (left), Qplus) + && CONSP (XCDR (left)) + && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (left)))) { - f->left_pos = XINT (XCAR (XCDR (tem1))); + f->left_pos = XINT (XCAR (XCDR (left))); } - else if (EQ (tem1, Qunbound)) + else if (EQ (left, Qunbound)) f->left_pos = 0; else { - CHECK_TYPE_RANGED_INTEGER (int, tem1); - f->left_pos = XINT (tem1); + CHECK_TYPE_RANGED_INTEGER (int, left); + f->left_pos = XINT (left); if (f->left_pos < 0) window_prompting |= XNegative; } - if (!NILP (tem2) && ! EQ (tem2, Qunbound)) + if (!NILP (user_position) && ! EQ (user_position, Qunbound)) window_prompting |= USPosition; else window_prompting |= PPosition; @@ -4483,6 +4763,7 @@ syms_of_frame (void) { DEFSYM (Qframep, "framep"); DEFSYM (Qframe_live_p, "frame-live-p"); + DEFSYM (Qframe_windows_min_size, "frame-windows-min-size"); DEFSYM (Qexplicit_name, "explicit-name"); DEFSYM (Qheight, "height"); DEFSYM (Qicon, "icon"); @@ -4601,7 +4882,7 @@ Setting this variable does not affect existing frames, only new ones. */); Vdefault_frame_alist = Qnil; DEFVAR_LISP ("default-frame-scroll-bars", Vdefault_frame_scroll_bars, - doc: /* Default position of scroll bars on this window-system. */); + doc: /* Default position of vertical scroll bars on this window-system. */); #ifdef HAVE_WINDOW_SYSTEM #if defined (HAVE_NTGUI) || defined (NS_IMPL_COCOA) || (defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS)) /* MS-Windows, Mac OS X, and GTK have scroll bars on the right by @@ -4614,6 +4895,14 @@ Setting this variable does not affect existing frames, only new ones. */); Vdefault_frame_scroll_bars = Qnil; #endif + DEFVAR_LISP ("default-frame-horizontal-scroll-bars", Vdefault_frame_horizontal_scroll_bars, + doc: /* Default value for horizontal scroll bars on this window-system. */); +#ifdef HAVE_WINDOW_SYSTEM + Vdefault_frame_horizontal_scroll_bars = Qt; +#else + Vdefault_frame_horizontal_scroll_bars = Qnil; +#endif + DEFVAR_BOOL ("scroll-bar-adjust-thumb-portion", scroll_bar_adjust_thumb_portion_p, doc: /* Adjust thumb for overscrolling for Gtk+ and MOTIF. @@ -4690,6 +4979,10 @@ or call the function `tool-bar-mode'. */); Vtool_bar_mode = Qnil; #endif + DEFVAR_LISP ("frame-initial-frame-tool-bar-height", Vframe_initial_frame_tool_bar_height, + doc: /* Height of tool bar of initial frame. */); + Vframe_initial_frame_tool_bar_height = make_number (0); + DEFVAR_KBOARD ("default-minibuffer-frame", Vdefault_minibuffer_frame, doc: /* Minibufferless frames use this frame's minibuffer. Emacs cannot create minibufferless frames unless this is set to an @@ -4718,11 +5011,19 @@ current values of `frame-char-height' and `frame-char-width'. If this is non-nil, no rounding occurs, hence frame sizes can increase/decrease by one pixel. -With some window managers you have to set this to non-nil in order to -fully maximize frames. To resize your initial frame pixelwise, -set this option to a non-nil value in your init file. */); +With some window managers you may have to set this to non-nil in order +to fully maximize frames. To resize your initial frame pixelwise, set +this option to a non-nil value in your init file. */); frame_resize_pixelwise = 0; + DEFVAR_BOOL ("frame-inhibit-implied-resize", frame_inhibit_implied_resize, + doc: /* Non-nil means do not resize frame implicitly. +If this option is nil, setting default font, menubar mode, fringe width, +or scroll bar mode of a specific frame may resize the frame in order to +preserve the number of columns or lines it displays. If this option is +non-nil, no such resizing is done. */); + frame_inhibit_implied_resize = 0; + staticpro (&Vframe_list); defsubr (&Sframep); @@ -4765,9 +5066,11 @@ set this option to a non-nil value in your init file. */); defsubr (&Sframe_text_cols); defsubr (&Sframe_text_lines); defsubr (&Sframe_total_cols); + defsubr (&Sframe_total_lines); defsubr (&Sframe_text_width); defsubr (&Sframe_text_height); defsubr (&Sscroll_bar_width); + defsubr (&Sscroll_bar_height); defsubr (&Sfringe_width); defsubr (&Sborder_width); defsubr (&Sright_divider_width); diff --git a/src/frame.h b/src/frame.h index 999a29d56ae..fde815c3b84 100644 --- a/src/frame.h +++ b/src/frame.h @@ -313,7 +313,6 @@ struct frame ENUM_BF (output_method) output_method : 3; #ifdef HAVE_WINDOW_SYSTEM - /* See FULLSCREEN_ enum on top. */ ENUM_BF (fullscreen_type) want_fullscreen : 4; @@ -321,14 +320,26 @@ struct frame display the scroll bars of this type on this frame. */ ENUM_BF (vertical_scroll_bar_type) vertical_scroll_bar_type : 2; + /* Nonzero if we should actually display horizontal scroll bars on this frame. */ + bool_bf horizontal_scroll_bars : 1; #endif /* HAVE_WINDOW_SYSTEM */ + /* Whether new_height and new_width shall be interpreted + in pixels. */ + bool_bf new_pixelwise : 1; + + /* True if frame has been added to Vframe_list and is henceforth + considered official. For in-official frames we neither process + x_set_window_size requests nor do we allow running + window-configuration-change-hook when resizing windows. */ + bool_bf official : 1; + /* Bitfield area ends here. */ - /* Margin at the top of the frame. Used to display the tool-bar. */ + /* Number of lines (rounded up) of tool bar. REMOVE THIS */ int tool_bar_lines; - /* Pixel height of tool bar. */ + /* Height of frame internal tool bar in pixels. */ int tool_bar_height; int n_tool_bar_rows; @@ -347,18 +358,22 @@ struct frame /* Cost of deleting n lines on this frame. */ int *delete_n_lines_cost; - /* Text width of this frame (excluding fringes, scroll bars and - internal border width) and text height (excluding internal border - width) in units of canonical characters. */ + /* Text width of this frame (excluding fringes, vertical scroll bar + and internal border widths) and text height (excluding menu bar, + tool bar, horizontal scroll bar and internal border widths) in + units of canonical characters. */ int text_cols, text_lines; - /* Total width of this frame (including fringes and scroll bars) in + /* Total width of this frame (including fringes, vertical scroll bar + and internal border widths) and total height (including menu bar, + tool bar, horizontal scroll bar and internal border widths) in units of canonical characters. */ - int total_cols; + int total_cols, total_lines; - /* Text width of this frame (excluding fringes, scroll bars and - internal border width) and text height (excluding internal border - width) in pixels. */ + /* Text width of this frame (excluding fringes, vertical scroll bar + and internal border widths) and text height (excluding menu bar, + tool bar, horizontal scroll bar and internal border widths) in + pixels. */ int text_width, text_height; /* New text height and width for pending size change. 0 if no change @@ -367,14 +382,12 @@ struct frame text width/height of the frame. */ int new_width, new_height; - /* Whether new_height and new_width shall be interpreted - in pixels. */ - bool new_pixelwise; - /* Pixel position of the frame window (x and y offsets in root window). */ int left_pos, top_pos; - /* Size of the frame window (including internal border widths) in + /* Total width of this frame (including fringes, vertical scroll bar + and internal border widths) and total height (including menu bar, + tool bar, horizontal scroll bar and internal border widths) in pixels. */ int pixel_width, pixel_height; @@ -396,9 +409,21 @@ struct frame a highlighting is displayed inside the internal border. */ int internal_border_width; - /* Width of borders between this frame's windows. */ - int right_divider_width; - int bottom_divider_width; + /* Widths of dividers between this frame's windows in pixels. */ + int right_divider_width, bottom_divider_width; + + /* Widths of fringes in pixels. */ + int left_fringe_width, right_fringe_width; + + /* Total width of fringes reserved for drawing truncation bitmaps, + continuation bitmaps and alike - REMOVE THIS !!!!. */ + int fringe_cols; + + /* Number of lines of menu bar. */ + int menu_bar_lines; + + /* Pixel height of menubar. */ + int menu_bar_height; /* Canonical X unit. Width of default font, in pixels. */ int column_width; @@ -426,22 +451,6 @@ struct frame /* List of font-drivers available on the frame. */ struct font_driver_list *font_driver_list; - /* Total width of fringes reserved for drawing truncation bitmaps, - continuation bitmaps and alike. The width is in canonical char - units of the frame. This must currently be the case because window - sizes aren't pixel values. If it weren't the case, we wouldn't be - able to split windows horizontally nicely. */ - int fringe_cols; - - /* The extra width (in pixels) currently allotted for fringes. */ - int left_fringe_width, right_fringe_width; - - /* Number of lines of menu bar. */ - int menu_bar_lines; - - /* Pixel height of menubar. */ - int menu_bar_height; - #if defined (HAVE_X_WINDOWS) /* Used by x_wait_for_event when watching for an X event on this frame. */ int wait_event_type; @@ -469,6 +478,14 @@ struct frame int config_scroll_bar_width; int config_scroll_bar_cols; + /* Configured height of the scroll bar, in pixels and in characters. + config_scroll_bar_lines tracks config_scroll_bar_height if the + latter is positive; a zero value in config_scroll_bar_height means + to compute the actual width on the fly, using + config_scroll_bar_lines and the current font width. */ + int config_scroll_bar_height; + int config_scroll_bar_lines; + /* The baud rate that was used to calculate costs for this frame. */ int cost_calculation_baud_rate; @@ -716,8 +733,7 @@ default_pixels_per_inch_y (void) /* Pixel width of frame F. */ #define FRAME_PIXEL_WIDTH(f) ((f)->pixel_width) -/* Pixel height of frame F, including non-toolkit menu bar and - non-toolkit tool bar lines. */ +/* Pixel height of frame F. */ #define FRAME_PIXEL_HEIGHT(f) ((f)->pixel_height) /* Width of frame F, measured in canonical character columns, @@ -733,7 +749,7 @@ default_pixels_per_inch_y (void) #define FRAME_TEXT_WIDTH(f) (f)->text_width /* Height of frame F, measured in pixels not including the height - for internal borders. */ + for scroll bar and internal borders. */ #define FRAME_TEXT_HEIGHT(f) (f)->text_height /* Number of lines of frame F used for menu bar. @@ -782,6 +798,8 @@ default_pixels_per_inch_y (void) #else #define FRAME_EXTERNAL_MENU_BAR(f) false #endif + +/* True if frame F is currently visible. */ #define FRAME_VISIBLE_P(f) (f)->visible /* True if frame F is currently visible but hidden. */ @@ -828,12 +846,14 @@ default_pixels_per_inch_y (void) #define FRAME_FOCUS_FRAME(f) f->focus_frame #ifdef HAVE_WINDOW_SYSTEM - + /* This frame slot says whether scroll bars are currently enabled for frame F, and which side they are on. */ #define FRAME_VERTICAL_SCROLL_BAR_TYPE(f) ((f)->vertical_scroll_bar_type) #define FRAME_HAS_VERTICAL_SCROLL_BARS(f) \ ((f)->vertical_scroll_bar_type != vertical_scroll_bar_none) +#define FRAME_HAS_HORIZONTAL_SCROLL_BARS(f) \ + ((f)->horizontal_scroll_bars) #define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT(f) \ ((f)->vertical_scroll_bar_type == vertical_scroll_bar_left) #define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT(f) \ @@ -854,61 +874,85 @@ default_pixels_per_inch_y (void) If scroll bars are turned off, this is still nonzero. */ #define FRAME_CONFIG_SCROLL_BAR_WIDTH(f) ((f)->config_scroll_bar_width) +/* Height that a scroll bar in frame F should have, if there is one. + Measured in pixels. + If scroll bars are turned off, this is still nonzero. */ +#define FRAME_CONFIG_SCROLL_BAR_HEIGHT(f) ((f)->config_scroll_bar_height) + /* Width that a scroll bar in frame F should have, if there is one. Measured in columns (characters). If scroll bars are turned off, this is still nonzero. */ #define FRAME_CONFIG_SCROLL_BAR_COLS(f) ((f)->config_scroll_bar_cols) -/* Width of a scroll bar in frame F, measured in columns (characters), - but only if scroll bars are on the left. If scroll bars are on - the right in this frame, or there are no scroll bars, value is 0. */ - -#define FRAME_LEFT_SCROLL_BAR_COLS(f) \ - (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f) \ - ? FRAME_CONFIG_SCROLL_BAR_COLS (f) \ - : 0) +/* Height that a scroll bar in frame F should have, if there is one. + Measured in lines (characters). + If scroll bars are turned off, this is still nonzero. */ +#define FRAME_CONFIG_SCROLL_BAR_LINES(f) ((f)->config_scroll_bar_lines) /* Width of a left scroll bar in frame F, measured in pixels */ - #define FRAME_LEFT_SCROLL_BAR_AREA_WIDTH(f) \ (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f) \ ? FRAME_CONFIG_SCROLL_BAR_WIDTH (f) \ : 0) -/* Width of a scroll bar in frame F, measured in columns (characters), - but only if scroll bars are on the right. If scroll bars are on - the left in this frame, or there are no scroll bars, value is 0. */ - -#define FRAME_RIGHT_SCROLL_BAR_COLS(f) \ - (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f) \ - ? FRAME_CONFIG_SCROLL_BAR_COLS (f) \ - : 0) - /* Width of a right scroll bar area in frame F, measured in pixels */ - #define FRAME_RIGHT_SCROLL_BAR_AREA_WIDTH(f) \ (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f) \ ? FRAME_CONFIG_SCROLL_BAR_WIDTH (f) \ : 0) -/* Actual width of a scroll bar in frame F, measured in columns. */ +/* Width of a left scroll bar in frame F, measured in columns + (characters), but only if scroll bars are on the left. If scroll + bars are on the right in this frame, or there are no scroll bars, + value is 0. */ +#define FRAME_LEFT_SCROLL_BAR_COLS(f) \ + (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f) \ + ? FRAME_CONFIG_SCROLL_BAR_COLS (f) \ + : 0) -#define FRAME_SCROLL_BAR_COLS(f) \ - (FRAME_HAS_VERTICAL_SCROLL_BARS (f) \ +/* Width of a right scroll bar in frame F, measured in columns + (characters), but only if scroll bars are on the right. If scroll + bars are on the left in this frame, or there are no scroll bars, + value is 0. */ +#define FRAME_RIGHT_SCROLL_BAR_COLS(f) \ + (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f) \ ? FRAME_CONFIG_SCROLL_BAR_COLS (f) \ : 0) -/* Actual width of a scroll bar area in frame F, measured in pixels. */ +/* Width of a vertical scroll bar area in frame F, measured in + pixels. */ +#define FRAME_SCROLL_BAR_AREA_WIDTH(f) \ + (FRAME_HAS_VERTICAL_SCROLL_BARS (f) \ + ? FRAME_CONFIG_SCROLL_BAR_WIDTH (f) \ + : 0) -#define FRAME_SCROLL_BAR_AREA_WIDTH(f) \ - (FRAME_HAS_VERTICAL_SCROLL_BARS (f) \ - ? FRAME_CONFIG_SCROLL_BAR_WIDTH (f) \ +/* Height of horizontal scroll bar area in frame F, measured in + pixels. */ +#define FRAME_SCROLL_BAR_AREA_HEIGHT(f) \ + (FRAME_HAS_HORIZONTAL_SCROLL_BARS (f) \ + ? FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) \ + : 0) + +/* Width of vertical scroll bar in frame F, measured in columns. */ +#define FRAME_SCROLL_BAR_COLS(f) \ + (FRAME_HAS_VERTICAL_SCROLL_BARS (f) \ + ? FRAME_CONFIG_SCROLL_BAR_COLS (f) \ + : 0) + +/* Height of horizontal scroll bar in frame F, measured in lines. */ +#define FRAME_SCROLL_BAR_LINES(f) \ + (FRAME_HAS_HORIZONTAL_SCROLL_BARS (f) \ + ? FRAME_CONFIG_SCROLL_BAR_LINES (f) \ : 0) /* Total width of frame F, in columns (characters), including the width used by scroll bars if any. */ #define FRAME_TOTAL_COLS(f) ((f)->total_cols) +/* Total height of frame F, in lines (characters), + including the height used by scroll bars if any. */ +#define FRAME_TOTAL_LINES(f) ((f)->total_lines) + /* Set the character widths of frame F. WIDTH specifies a nominal character text width. */ #define SET_FRAME_COLS(f, width) \ @@ -917,8 +961,16 @@ default_pixels_per_inch_y (void) + FRAME_SCROLL_BAR_COLS (f) \ + FRAME_FRINGE_COLS (f))) -/* Set the pixel widths of frame F. WIDTH specifies a nominal pixel - text width. */ +/* Set the character heights of frame F. HEIGHT specifies a nominal + character text height. */ +#define SET_FRAME_LINES(f, height) \ + ((f)->text_lines = (height), \ + (f)->total_lines = ((height) \ + + FRAME_TOP_MARGIN (f) \ + + FRAME_SCROLL_BAR_LINES (f))) + +/* Set the widths of frame F. WIDTH specifies a nominal pixel text + width. */ #define SET_FRAME_WIDTH(f, width) \ ((f)->text_width = (width), \ (f)->pixel_width = ((width) \ @@ -926,21 +978,23 @@ default_pixels_per_inch_y (void) + FRAME_TOTAL_FRINGE_WIDTH (f) \ + 2 * FRAME_INTERNAL_BORDER_WIDTH (f))) -/* Set the pixel heights of frame F. HEIGHT specifies a nominal pixel - text width. */ +/* Set the heights of frame F. HEIGHT specifies a nominal pixel text + height. */ #define SET_FRAME_HEIGHT(f, height) \ ((f)->text_height = (height), \ (f)->pixel_height = ((height) \ - + 2 * FRAME_INTERNAL_BORDER_WIDTH (f))) + + FRAME_TOP_MARGIN_HEIGHT (f) \ + + FRAME_SCROLL_BAR_AREA_HEIGHT (f) \ + + 2 * FRAME_INTERNAL_BORDER_WIDTH (f))) /* Maximum + 1 legitimate value for FRAME_CURSOR_X. */ - #define FRAME_CURSOR_X_LIMIT(f) \ (FRAME_COLS (f) + FRAME_LEFT_SCROLL_BAR_COLS (f)) +/* Nonzero if frame F has scroll bars. */ #define FRAME_SCROLL_BARS(f) (f->scroll_bars) - #define FRAME_CONDEMNED_SCROLL_BARS(f) (f->condemned_scroll_bars) + #define FRAME_MENU_BAR_ITEMS(f) (f->menu_bar_items) #define FRAME_COST_BAUD_RATE(f) ((f)->cost_calculation_baud_rate) @@ -1053,6 +1107,7 @@ extern void check_window_system (struct frame *); extern void frame_make_pointer_invisible (struct frame *); extern void frame_make_pointer_visible (struct frame *); extern Lisp_Object delete_frame (Lisp_Object, Lisp_Object); +extern bool frame_inhibit_resize (struct frame *, bool); extern Lisp_Object Vframe_list; @@ -1073,12 +1128,10 @@ extern Lisp_Object Vframe_list; /* Canonical y-unit on frame F. This value currently equals the line height of the frame (which is the height of the default font of F). */ - #define FRAME_LINE_HEIGHT(F) ((F)->line_height) /* Canonical x-unit on frame F. This value currently equals the average width of the default font of F. */ - #define FRAME_COLUMN_WIDTH(F) ((F)->column_width) /* Pixel width of areas used to display truncation marks, continuation @@ -1091,7 +1144,6 @@ extern Lisp_Object Vframe_list; units of the frame. This must currently be the case because window sizes aren't pixel values. If it weren't the case, we wouldn't be able to split windows horizontally nicely. */ - #define FRAME_FRINGE_COLS(F) ((F)->fringe_cols) /* Pixel-width of the left and right fringe. */ @@ -1134,7 +1186,6 @@ extern Lisp_Object Vframe_list; /* Convert canonical value X to pixels. F is the frame whose canonical char width is to be used. X must be a Lisp integer or float. Value is a C integer. */ - #define FRAME_PIXEL_X_FROM_CANON_X(F, X) \ (INTEGERP (X) \ ? XINT (X) * FRAME_COLUMN_WIDTH (F) \ @@ -1143,7 +1194,6 @@ extern Lisp_Object Vframe_list; /* Convert canonical value Y to pixels. F is the frame whose canonical character height is to be used. X must be a Lisp integer or float. Value is a C integer. */ - #define FRAME_PIXEL_Y_FROM_CANON_Y(F, Y) \ (INTEGERP (Y) \ ? XINT (Y) * FRAME_LINE_HEIGHT (F) \ @@ -1153,7 +1203,6 @@ extern Lisp_Object Vframe_list; canonical character width is to be used. X is a C integer. Result is a Lisp float if X is not a multiple of the canon width, otherwise it's a Lisp integer. */ - #define FRAME_CANON_X_FROM_PIXEL_X(F, X) \ ((X) % FRAME_COLUMN_WIDTH (F) != 0 \ ? make_float ((double) (X) / FRAME_COLUMN_WIDTH (F)) \ @@ -1163,7 +1212,6 @@ extern Lisp_Object Vframe_list; canonical character height is to be used. Y is a C integer. Result is a Lisp float if Y is not a multiple of the canon width, otherwise it's a Lisp integer. */ - #define FRAME_CANON_Y_FROM_PIXEL_Y(F, Y) \ ((Y) % FRAME_LINE_HEIGHT (F) \ ? make_float ((double) (Y) / FRAME_LINE_HEIGHT (F)) \ @@ -1177,7 +1225,6 @@ extern Lisp_Object Vframe_list; Return the upper/left pixel position of the character cell on frame F at ROW/COL. */ - #define FRAME_LINE_TO_PIXEL_Y(f, row) \ (((row) < FRAME_TOP_MARGIN (f) ? 0 : FRAME_INTERNAL_BORDER_WIDTH (f)) \ + (row) * FRAME_LINE_HEIGHT (f)) @@ -1188,25 +1235,27 @@ extern Lisp_Object Vframe_list; /* Return the pixel width/height of frame F if it has COLS columns/LINES rows. */ - #define FRAME_TEXT_COLS_TO_PIXEL_WIDTH(f, cols) \ - (FRAME_COL_TO_PIXEL_X (f, cols) \ + ((cols) * FRAME_COLUMN_WIDTH (f) \ + FRAME_SCROLL_BAR_AREA_WIDTH (f) \ + FRAME_TOTAL_FRINGE_WIDTH (f) \ - + FRAME_INTERNAL_BORDER_WIDTH (f)) + + 2 * FRAME_INTERNAL_BORDER_WIDTH (f)) #define FRAME_TEXT_LINES_TO_PIXEL_HEIGHT(f, lines) \ ((lines) * FRAME_LINE_HEIGHT (f) \ + + FRAME_TOP_MARGIN_HEIGHT (f) \ + + FRAME_SCROLL_BAR_AREA_HEIGHT (f) \ + 2 * FRAME_INTERNAL_BORDER_WIDTH (f)) /* Return the row/column (zero-based) of the character cell containing the pixel on FRAME at Y/X. */ - #define FRAME_PIXEL_Y_TO_LINE(f, y) \ (((y) < FRAME_TOP_MARGIN_HEIGHT (f) \ ? (y) \ - : ((y) < FRAME_TOP_MARGIN_HEIGHT (f) + FRAME_INTERNAL_BORDER_WIDTH (f) \ - ? (y) - (FRAME_TOP_MARGIN_HEIGHT (f) + FRAME_INTERNAL_BORDER_WIDTH (f) \ + : ((y) < (FRAME_TOP_MARGIN_HEIGHT (f) \ + + FRAME_INTERNAL_BORDER_WIDTH (f)) \ + ? (y) - (FRAME_TOP_MARGIN_HEIGHT (f) \ + + FRAME_INTERNAL_BORDER_WIDTH (f) \ /* Arrange for the division to round down. */ \ + FRAME_LINE_HEIGHT (f) - 1) \ : (y) - FRAME_INTERNAL_BORDER_WIDTH (f))) \ @@ -1217,21 +1266,23 @@ extern Lisp_Object Vframe_list; / FRAME_COLUMN_WIDTH (f)) /* How many columns/rows of text can we fit in WIDTH/HEIGHT pixels on - frame F? */ - + frame F (so we round down)? */ #define FRAME_PIXEL_WIDTH_TO_TEXT_COLS(f, width) \ - (FRAME_PIXEL_X_TO_COL (f, ((width) \ - - FRAME_INTERNAL_BORDER_WIDTH (f) \ - - FRAME_TOTAL_FRINGE_WIDTH (f) \ - - FRAME_SCROLL_BAR_AREA_WIDTH (f)))) \ + (((width) \ + - FRAME_TOTAL_FRINGE_WIDTH (f) \ + - FRAME_SCROLL_BAR_AREA_WIDTH (f) \ + - 2 * FRAME_INTERNAL_BORDER_WIDTH (f)) \ + / FRAME_COLUMN_WIDTH (f)) \ #define FRAME_PIXEL_HEIGHT_TO_TEXT_LINES(f, height) \ - (FRAME_PIXEL_Y_TO_LINE (f, ((height) \ - - FRAME_INTERNAL_BORDER_WIDTH (f)))) + (((height) \ + - FRAME_TOP_MARGIN_HEIGHT (f) \ + - FRAME_SCROLL_BAR_AREA_HEIGHT (f) \ + - 2 * FRAME_INTERNAL_BORDER_WIDTH (f)) \ + / FRAME_LINE_HEIGHT (f)) /* Return the pixel width/height of frame F with a text size of - width/height. */ - + width/heigh. */ #define FRAME_TEXT_TO_PIXEL_WIDTH(f, width) \ ((width) \ + FRAME_SCROLL_BAR_AREA_WIDTH (f) \ @@ -1239,11 +1290,13 @@ extern Lisp_Object Vframe_list; + 2 * FRAME_INTERNAL_BORDER_WIDTH (f)) #define FRAME_TEXT_TO_PIXEL_HEIGHT(f, height) \ - ((height) + 2 * FRAME_INTERNAL_BORDER_WIDTH (f)) + ((height) \ + + FRAME_TOP_MARGIN_HEIGHT (f) \ + + FRAME_SCROLL_BAR_AREA_HEIGHT (f) \ + + 2 * FRAME_INTERNAL_BORDER_WIDTH (f)) /* Return the text width/height of frame F with a pixel size of width/height. */ - #define FRAME_PIXEL_TO_TEXT_WIDTH(f, width) \ ((width) \ - FRAME_SCROLL_BAR_AREA_WIDTH (f) \ @@ -1251,15 +1304,26 @@ extern Lisp_Object Vframe_list; - 2 * FRAME_INTERNAL_BORDER_WIDTH (f)) #define FRAME_PIXEL_TO_TEXT_HEIGHT(f, height) \ - ((height) - 2 * FRAME_INTERNAL_BORDER_WIDTH (f)) + ((height) \ + - FRAME_TOP_MARGIN_HEIGHT (f) \ + - FRAME_SCROLL_BAR_AREA_HEIGHT (f) \ + - 2 * FRAME_INTERNAL_BORDER_WIDTH (f)) + +/* Return the width/height reserved for the windows of frame F. */ +#define FRAME_WINDOWS_WIDTH(f) \ + (FRAME_PIXEL_WIDTH (f) \ + - 2 * FRAME_INTERNAL_BORDER_WIDTH (f)) -/* Value is the smallest width of any character in any font on frame F. */ +#define FRAME_WINDOWS_HEIGHT(f) \ + (FRAME_PIXEL_HEIGHT (f) \ + - FRAME_TOP_MARGIN_HEIGHT (f) \ + - 2 * FRAME_INTERNAL_BORDER_WIDTH (f)) +/* Value is the smallest width of any character in any font on frame F. */ #define FRAME_SMALLEST_CHAR_WIDTH(f) \ FRAME_DISPLAY_INFO (f)->smallest_char_width /* Value is the smallest height of any font on frame F. */ - #define FRAME_SMALLEST_FONT_HEIGHT(f) \ FRAME_DISPLAY_INFO (f)->smallest_font_height @@ -1282,6 +1346,7 @@ extern Lisp_Object Qname, Qtitle; extern Lisp_Object Qparent_id; extern Lisp_Object Qunsplittable, Qvisibility; extern Lisp_Object Qscroll_bar_width, Qvertical_scroll_bars; +extern Lisp_Object Qscroll_bar_height, Qhorizontal_scroll_bars; extern Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background; extern Lisp_Object Qscreen_gamma; extern Lisp_Object Qline_spacing; @@ -1311,25 +1376,24 @@ extern Lisp_Object Qrun_hook_with_args; /* The class of this X application. */ #define EMACS_CLASS "Emacs" -/* These are in xterm.c, w32term.c, etc. */ +/* If these are not in frame.c they are in xterm.c, w32term.c, etc. */ +extern void adjust_frame_size (struct frame *, int, int, int, bool); +extern int frame_windows_min_size (Lisp_Object, Lisp_Object, Lisp_Object); extern void x_set_scroll_bar_default_width (struct frame *); +extern void x_set_scroll_bar_default_height (struct frame *); extern void x_set_offset (struct frame *, int, int, int); extern void x_wm_set_size_hint (struct frame *f, long flags, bool user_position); - extern Lisp_Object x_new_font (struct frame *, Lisp_Object, int); - - extern Lisp_Object Qface_set_after_frame_default; - extern void x_set_frame_parameters (struct frame *, Lisp_Object); - extern void x_set_fullscreen (struct frame *, Lisp_Object, Lisp_Object); extern void x_set_line_spacing (struct frame *, Lisp_Object, Lisp_Object); extern void x_set_screen_gamma (struct frame *, Lisp_Object, Lisp_Object); extern void x_set_font (struct frame *, Lisp_Object, Lisp_Object); extern void x_set_font_backend (struct frame *, Lisp_Object, Lisp_Object); -extern void x_set_fringe_width (struct frame *, Lisp_Object, Lisp_Object); +extern void x_set_left_fringe (struct frame *, Lisp_Object, Lisp_Object); +extern void x_set_right_fringe (struct frame *, Lisp_Object, Lisp_Object); extern void x_set_border_width (struct frame *, Lisp_Object, Lisp_Object); extern void x_set_internal_border_width (struct frame *, Lisp_Object, Lisp_Object); @@ -1341,10 +1405,10 @@ extern void x_set_visibility (struct frame *, Lisp_Object, Lisp_Object); extern void x_set_autoraise (struct frame *, Lisp_Object, Lisp_Object); extern void x_set_autolower (struct frame *, Lisp_Object, Lisp_Object); extern void x_set_unsplittable (struct frame *, Lisp_Object, Lisp_Object); -extern void x_set_vertical_scroll_bars (struct frame *, Lisp_Object, - Lisp_Object); -extern void x_set_scroll_bar_width (struct frame *, Lisp_Object, - Lisp_Object); +extern void x_set_vertical_scroll_bars (struct frame *, Lisp_Object, Lisp_Object); +extern void x_set_horizontal_scroll_bars (struct frame *, Lisp_Object, Lisp_Object); +extern void x_set_scroll_bar_width (struct frame *, Lisp_Object, Lisp_Object); +extern void x_set_scroll_bar_height (struct frame *, Lisp_Object, Lisp_Object); extern long x_figure_window_size (struct frame *, Lisp_Object, bool); diff --git a/src/fringe.c b/src/fringe.c index 54f880dc624..3c0e883b2e9 100644 --- a/src/fringe.c +++ b/src/fringe.c @@ -1329,98 +1329,6 @@ update_window_fringes (struct window *w, bool keep_current_p) } -/* Compute actual fringe widths for frame F. - - If REDRAW is 1, redraw F if the fringe settings was actually - modified and F is visible. - - Since the combined left and right fringe must occupy an integral - number of columns, we may need to add some pixels to each fringe. - Typically, we add an equal amount (+/- 1 pixel) to each fringe, - but a negative width value is taken literally (after negating it). - - We never make the fringes narrower than specified. -*/ - -void -compute_fringe_widths (struct frame *f, bool redraw_p) -{ - int o_left = FRAME_LEFT_FRINGE_WIDTH (f); - int o_right = FRAME_RIGHT_FRINGE_WIDTH (f); - int o_cols = FRAME_FRINGE_COLS (f); - - Lisp_Object left_fringe = Fassq (Qleft_fringe, f->param_alist); - Lisp_Object right_fringe = Fassq (Qright_fringe, f->param_alist); - int left_fringe_width, right_fringe_width; - - if (!NILP (left_fringe)) - left_fringe = Fcdr (left_fringe); - if (!NILP (right_fringe)) - right_fringe = Fcdr (right_fringe); - - left_fringe_width = ((NILP (left_fringe) || !INTEGERP (left_fringe)) ? 8 : - XINT (left_fringe)); - right_fringe_width = ((NILP (right_fringe) || !INTEGERP (right_fringe)) ? 8 : - XINT (right_fringe)); - - if (left_fringe_width || right_fringe_width) - { - int left_wid = eabs (left_fringe_width); - int right_wid = eabs (right_fringe_width); - int conf_wid = left_wid + right_wid; - int font_wid = FRAME_COLUMN_WIDTH (f); - int cols = (left_wid + right_wid + font_wid-1) / font_wid; - int real_wid = cols * font_wid; - if (left_wid && right_wid) - { - if (left_fringe_width < 0) - { - /* Left fringe width is fixed, adjust right fringe if necessary */ - FRAME_LEFT_FRINGE_WIDTH (f) = left_wid; - FRAME_RIGHT_FRINGE_WIDTH (f) = real_wid - left_wid; - } - else if (right_fringe_width < 0) - { - /* Right fringe width is fixed, adjust left fringe if necessary */ - FRAME_LEFT_FRINGE_WIDTH (f) = real_wid - right_wid; - FRAME_RIGHT_FRINGE_WIDTH (f) = right_wid; - } - else - { - /* Adjust both fringes with an equal amount. - Note that we are doing integer arithmetic here, so don't - lose a pixel if the total width is an odd number. */ - int fill = real_wid - conf_wid; - FRAME_LEFT_FRINGE_WIDTH (f) = left_wid + fill/2; - FRAME_RIGHT_FRINGE_WIDTH (f) = right_wid + fill - fill/2; - } - } - else if (left_fringe_width) - { - FRAME_LEFT_FRINGE_WIDTH (f) = real_wid; - FRAME_RIGHT_FRINGE_WIDTH (f) = 0; - } - else - { - FRAME_LEFT_FRINGE_WIDTH (f) = 0; - FRAME_RIGHT_FRINGE_WIDTH (f) = real_wid; - } - FRAME_FRINGE_COLS (f) = cols; - } - else - { - FRAME_LEFT_FRINGE_WIDTH (f) = 0; - FRAME_RIGHT_FRINGE_WIDTH (f) = 0; - FRAME_FRINGE_COLS (f) = 0; - } - - if (redraw_p && FRAME_VISIBLE_P (f)) - if (o_left != FRAME_LEFT_FRINGE_WIDTH (f) || - o_right != FRAME_RIGHT_FRINGE_WIDTH (f) || - o_cols != FRAME_FRINGE_COLS (f)) - redraw_frame (f); -} - /* Free resources used by a user-defined bitmap. */ diff --git a/src/gtkutil.c b/src/gtkutil.c index afa41f3269a..b18e5f325e1 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -115,6 +115,7 @@ along with GNU Emacs. If not, see . */ #define XG_BIN_CHILD(x) gtk_bin_get_child (GTK_BIN (x)) static void update_theme_scrollbar_width (void); +static void update_theme_scrollbar_height (void); #define TB_INFO_KEY "xg_frame_tb_info" struct xg_frame_tb_info @@ -821,7 +822,7 @@ xg_set_geometry (struct frame *f) /* Clear under internal border if any. As we use a mix of Gtk+ and X calls and use a GtkFixed widget, this doesn't happen automatically. */ -static void +void xg_clear_under_internal_border (struct frame *f) { if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0) @@ -883,6 +884,8 @@ xg_frame_resized (struct frame *f, int pixelwidth, int pixelheight) change_frame_size (f, width, height, 0, 1, 0, 1); SET_FRAME_GARBAGED (f); cancel_mouse_face (f); + + do_pending_window_change (0); } } @@ -927,7 +930,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height) x_wait_for_event (f, ConfigureNotify); } else - change_frame_size (f, width, height, 0, 1, 0, 1); + adjust_frame_size (f, -1, -1, 5, 0); } /* Handle height/width changes (i.e. add/remove/move menu/toolbar). @@ -1017,6 +1020,7 @@ style_changed_cb (GObject *go, kbd_buffer_store_event (&event); update_theme_scrollbar_width (); + update_theme_scrollbar_height (); /* If scroll bar width changed, we need set the new size on all frames on this display. */ @@ -1031,6 +1035,7 @@ style_changed_cb (GObject *go, && FRAME_X_DISPLAY (f) == dpy) { x_set_scroll_bar_default_width (f); + x_set_scroll_bar_default_height (f); xg_frame_set_char_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f)); } } @@ -1314,7 +1319,6 @@ x_wm_set_size_hint (struct frame *f, long int flags, bool user_position) base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 1) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f); - check_frame_size (f, &min_cols, &min_rows, 0); if (min_cols > 0) --min_cols; /* We used one col in base_width = ... 1); */ if (min_rows > 0) --min_rows; /* We used one row in base_height = ... 1); */ @@ -3419,9 +3423,9 @@ xg_event_is_for_menubar (struct frame *f, const XEvent *event) bool xg_ignore_gtk_scrollbar; -/* The width of the scroll bar for the current theme. */ - +/* Width and height of scroll bars for the current theme. */ static int scroll_bar_width_for_theme; +static int scroll_bar_height_for_theme; /* Xlib's `Window' fits in 32 bits. But we want to store pointers, and they may be larger than 32 bits. Keep a mapping from integer index to widget @@ -3524,12 +3528,41 @@ update_theme_scrollbar_width (void) scroll_bar_width_for_theme = w; } +static void +update_theme_scrollbar_height (void) +{ +#ifdef HAVE_GTK3 + GtkAdjustment *hadj; +#else + GtkObject *hadj; +#endif + GtkWidget *wscroll; + int w = 0, b = 0; + + hadj = gtk_adjustment_new (YG_SB_MIN, YG_SB_MIN, YG_SB_MAX, 0.1, 0.1, 0.1); + wscroll = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT (hadj)); + g_object_ref_sink (G_OBJECT (wscroll)); + gtk_widget_style_get (wscroll, "slider-width", &w, "trough-border", &b, NULL); + gtk_widget_destroy (wscroll); + g_object_unref (G_OBJECT (wscroll)); + w += 2*b; + if (w < 12) w = 12; + scroll_bar_height_for_theme = w; +} + int xg_get_default_scrollbar_width (void) { return scroll_bar_width_for_theme; } +int +xg_get_default_scrollbar_height (void) +{ + /* Apparently there's no default height for themes. */ + return scroll_bar_width_for_theme; +} + /* Return the scrollbar id for X Window WID on display DPY. Return -1 if WID not in id_to_widget. */ @@ -3628,6 +3661,74 @@ xg_create_scroll_bar (struct frame *f, xg_set_cursor (webox, FRAME_DISPLAY_INFO (f)->xg_cursor); bar->x_window = scroll_id; + bar->horizontal = 0; +} + +/* Create a horizontal scroll bar widget for frame F. Store the scroll + bar in BAR. SCROLL_CALLBACK is the callback to invoke when the value + of the bar changes. END_CALLBACK is the callback to invoke when + scrolling ends. SCROLL_BAR_NAME is the name we use for the scroll + bar. Can be used to set resources for the widget. */ + +void +xg_create_horizontal_scroll_bar (struct frame *f, + struct scroll_bar *bar, + GCallback scroll_callback, + GCallback end_callback, + const char *scroll_bar_name) +{ + GtkWidget *wscroll; + GtkWidget *webox; + intptr_t scroll_id; +#ifdef HAVE_GTK3 + GtkAdjustment *hadj; +#else + GtkObject *hadj; +#endif + + /* Page, step increment values are not so important here, they + will be corrected in x_set_toolkit_scroll_bar_thumb. */ + hadj = gtk_adjustment_new (YG_SB_MIN, YG_SB_MIN, YG_SB_MAX, + 0.1, 0.1, 0.1); + + wscroll = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT (hadj)); + webox = gtk_event_box_new (); + gtk_widget_set_name (wscroll, scroll_bar_name); +#ifndef HAVE_GTK3 + gtk_range_set_update_policy (GTK_RANGE (wscroll), GTK_UPDATE_CONTINUOUS); +#endif + g_object_set_data (G_OBJECT (wscroll), XG_FRAME_DATA, (gpointer)f); + + scroll_id = xg_store_widget_in_map (wscroll); + + g_signal_connect (G_OBJECT (wscroll), + "destroy", + G_CALLBACK (xg_gtk_scroll_destroy), + (gpointer) scroll_id); + g_signal_connect (G_OBJECT (wscroll), + "change-value", + scroll_callback, + (gpointer) bar); + g_signal_connect (G_OBJECT (wscroll), + "button-release-event", + end_callback, + (gpointer) bar); + + /* The scroll bar widget does not draw on a window of its own. Instead + it draws on the parent window, in this case the edit widget. So + whenever the edit widget is cleared, the scroll bar needs to redraw + also, which causes flicker. Put an event box between the edit widget + and the scroll bar, so the scroll bar instead draws itself on the + event box window. */ + gtk_fixed_put (GTK_FIXED (f->output_data.x->edit_widget), webox, -1, -1); + gtk_container_add (GTK_CONTAINER (webox), wscroll); + + + /* Set the cursor to an arrow. */ + xg_set_cursor (webox, FRAME_DISPLAY_INFO (f)->xg_cursor); + + bar->x_window = scroll_id; + bar->horizontal = 1; } /* Remove the scroll bar represented by SCROLLBAR_ID from the frame F. */ @@ -3710,6 +3811,73 @@ xg_update_scrollbar_pos (struct frame *f, } } + +/* Update the position of the horizontal scroll bar represented by SCROLLBAR_ID + in frame F. + TOP/LEFT are the new pixel positions where the bar shall appear. + WIDTH, HEIGHT is the size in pixels the bar shall have. */ + +void +xg_update_horizontal_scrollbar_pos (struct frame *f, + ptrdiff_t scrollbar_id, + int top, + int left, + int width, + int height) +{ + + GtkWidget *wscroll = xg_get_widget_from_map (scrollbar_id); + + if (wscroll) + { + GtkWidget *wfixed = f->output_data.x->edit_widget; + GtkWidget *wparent = gtk_widget_get_parent (wscroll); + gint msl; + + /* Clear out old position. */ + int oldx = -1, oldy = -1, oldw, oldh; + if (gtk_widget_get_parent (wparent) == wfixed) + { + gtk_container_child_get (GTK_CONTAINER (wfixed), wparent, + "x", &oldx, "y", &oldy, NULL); + gtk_widget_get_size_request (wscroll, &oldw, &oldh); + } + + /* Move and resize to new values. */ + gtk_fixed_move (GTK_FIXED (wfixed), wparent, left, top); + gtk_widget_style_get (wscroll, "min-slider-length", &msl, NULL); + if (msl > width) + { + /* No room. Hide scroll bar as some themes output a warning if + the width is less than the min size. */ + gtk_widget_hide (wparent); + gtk_widget_hide (wscroll); + } + else + { + gtk_widget_show_all (wparent); + gtk_widget_set_size_request (wscroll, width, height); + } + gtk_widget_queue_draw (wfixed); + gdk_window_process_all_updates (); + if (oldx != -1 && oldw > 0 && oldh > 0) + /* Clear under old scroll bar position. This must be done after + the gtk_widget_queue_draw and gdk_window_process_all_updates + above. */ + x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + oldx, oldy, oldw, oldh); + + /* GTK does not redraw until the main loop is entered again, but + if there are no X events pending we will not enter it. So we sync + here to get some events. */ + + x_sync (f); + SET_FRAME_GARBAGED (f); + cancel_mouse_face (f); + } +} + + /* Get the current value of the range, truncated to an integer. */ static int @@ -3804,6 +3972,47 @@ xg_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, } } +/* Set the thumb size and position of horizontal scroll bar BAR. We are + currently displaying PORTION out of a whole WHOLE, and our position + POSITION. */ +void +xg_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar, + int portion, + int position, + int whole) +{ + GtkWidget *wscroll = xg_get_widget_from_map (bar->x_window); + + if (wscroll && bar->dragging == -1) + { + GtkAdjustment *adj; + int lower = 0; + int upper = max (whole - 1, 0); + int pagesize = min (upper, max (portion, 0)); + int value = max (0, min (position, upper - pagesize)); + /* These should be set to something more + related. */ + int page_increment = 4; + int step_increment = 1; + + block_input (); + adj = gtk_range_get_adjustment (GTK_RANGE (wscroll)); + + /* gtk_adjustment_set_lower (adj, (gdouble) lower); + gtk_adjustment_set_upper (adj, (gdouble) upper); + gtk_adjustment_set_page_size (adj, (gdouble) pagesize); + gtk_adjustment_set_value (adj, (gdouble) value); + gtk_adjustment_set_page_increment (adj, (gdouble) page_increment); + gtk_adjustment_set_step_increment (adj, (gdouble) + step_increment); */ + gtk_adjustment_configure (adj, (gdouble) value, (gdouble) lower, + (gdouble) upper, (gdouble) step_increment, + (gdouble) page_increment, (gdouble) pagesize); + gtk_adjustment_changed (adj); + unblock_input (); + } +} + /* Return true if EVENT is for a scroll bar in frame F. When the same X window is used for several Gtk+ widgets, we cannot say for sure based on the X window alone if an event is for the @@ -5010,6 +5219,7 @@ xg_initialize (void) gtk_binding_entry_add_signal (binding_set, GDK_KEY_g, GDK_CONTROL_MASK, "cancel", 0); update_theme_scrollbar_width (); + update_theme_scrollbar_height (); #ifdef HAVE_FREETYPE x_last_font_name = NULL; diff --git a/src/gtkutil.h b/src/gtkutil.h index a69932cc25c..5c7d8b03379 100644 --- a/src/gtkutil.h +++ b/src/gtkutil.h @@ -33,6 +33,9 @@ along with GNU Emacs. If not, see . */ #define XG_SB_MIN 1 #define XG_SB_MAX 10000000 #define XG_SB_RANGE (XG_SB_MAX-XG_SB_MIN) +#define YG_SB_MIN 1 +#define YG_SB_MAX 10000000 +#define YG_SB_RANGE (YG_SB_MAX-YG_SB_MIN) /* Key for data that is valid for menus and scroll bars in a frame */ #define XG_FRAME_DATA "emacs_frame" @@ -114,6 +117,11 @@ extern void xg_create_scroll_bar (struct frame *f, GCallback scroll_callback, GCallback end_callback, const char *scroll_bar_name); +extern void xg_create_horizontal_scroll_bar (struct frame *f, + struct scroll_bar *bar, + GCallback scroll_callback, + GCallback end_callback, + const char *scroll_bar_name); extern void xg_remove_scroll_bar (struct frame *f, ptrdiff_t scrollbar_id); extern void xg_update_scrollbar_pos (struct frame *f, @@ -122,18 +130,30 @@ extern void xg_update_scrollbar_pos (struct frame *f, int left, int width, int height); +extern void xg_update_horizontal_scrollbar_pos (struct frame *f, + ptrdiff_t scrollbar_id, + int top, + int left, + int width, + int height); extern void xg_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position, int whole); +extern void xg_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar, + int portion, + int position, + int whole); extern bool xg_event_is_for_scrollbar (struct frame *, const XEvent *); extern int xg_get_default_scrollbar_width (void); +extern int xg_get_default_scrollbar_height (void); extern void update_frame_tool_bar (struct frame *f); extern void free_frame_tool_bar (struct frame *f); extern void xg_change_toolbar_position (struct frame *f, Lisp_Object pos); +extern void xg_clear_under_internal_border (struct frame *f); extern void xg_frame_resized (struct frame *f, int pixelwidth, int pixelheight); @@ -162,7 +182,6 @@ extern bool xg_prepare_tooltip (struct frame *f, extern void xg_show_tooltip (struct frame *f, int root_x, int root_y); extern bool xg_hide_tooltip (struct frame *f); - /* Mark all callback data that are Lisp_object:s during GC. */ extern void xg_mark_data (void); diff --git a/src/insdel.c b/src/insdel.c index 876e2869978..463392dcada 100644 --- a/src/insdel.c +++ b/src/insdel.c @@ -203,6 +203,25 @@ gap_right (ptrdiff_t charpos, ptrdiff_t bytepos) QUIT; } +/* If the selected window's old pointm is adjacent or covered by the + region from FROM to TO, unsuspend auto hscroll in that window. */ + +static void +adjust_suspend_auto_hscroll (ptrdiff_t from, ptrdiff_t to) +{ + if (WINDOWP (selected_window)) + { + struct window *w = XWINDOW (selected_window); + + if (BUFFERP (w->contents) + && XBUFFER (w->contents) == current_buffer + && XMARKER (w->old_pointm)->charpos >= from + && XMARKER (w->old_pointm)->charpos <= to) + w->suspend_auto_hscroll = 0; + } +} + + /* Adjust all markers for a deletion whose range in bytes is FROM_BYTE to TO_BYTE. The range in charpos is FROM to TO. @@ -217,6 +236,7 @@ adjust_markers_for_delete (ptrdiff_t from, ptrdiff_t from_byte, struct Lisp_Marker *m; ptrdiff_t charpos; + adjust_suspend_auto_hscroll (from, to); for (m = BUF_MARKERS (current_buffer); m; m = m->next) { charpos = m->charpos; @@ -256,6 +276,7 @@ adjust_markers_for_insert (ptrdiff_t from, ptrdiff_t from_byte, ptrdiff_t nchars = to - from; ptrdiff_t nbytes = to_byte - from_byte; + adjust_suspend_auto_hscroll (from, to); for (m = BUF_MARKERS (current_buffer); m; m = m->next) { eassert (m->bytepos >= m->charpos @@ -321,6 +342,7 @@ adjust_markers_for_replace (ptrdiff_t from, ptrdiff_t from_byte, ptrdiff_t diff_chars = new_chars - old_chars; ptrdiff_t diff_bytes = new_bytes - old_bytes; + adjust_suspend_auto_hscroll (from, from + old_chars); for (m = BUF_MARKERS (current_buffer); m; m = m->next) { if (m->bytepos >= prev_to_byte) diff --git a/src/keyboard.c b/src/keyboard.c index 8fe6926a17c..a684f18c756 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -3464,7 +3464,8 @@ readable_events (int flags) event->kind == FOCUS_IN_EVENT) #ifdef USE_TOOLKIT_SCROLL_BARS && !((flags & READABLE_EVENTS_IGNORE_SQUEEZABLES) - && event->kind == SCROLL_BAR_CLICK_EVENT + && (event->kind == SCROLL_BAR_CLICK_EVENT + || event->kind == HORIZONTAL_SCROLL_BAR_CLICK_EVENT) && event->part == scroll_bar_handle && event->modifiers == 0) #endif @@ -3761,7 +3762,8 @@ discard_mouse_events (void) #ifdef HAVE_GPM || sp->kind == GPM_CLICK_EVENT #endif - || sp->kind == SCROLL_BAR_CLICK_EVENT) + || sp->kind == SCROLL_BAR_CLICK_EVENT + || sp->kind == HORIZONTAL_SCROLL_BAR_CLICK_EVENT) { sp->kind = NO_EVENT; } @@ -5160,15 +5162,18 @@ static const char *const lispy_drag_n_drop_names[] = /* Scroll bar parts. */ static Lisp_Object Qabove_handle, Qhandle, Qbelow_handle; -Lisp_Object Qup, Qdown, Qbottom; +static Lisp_Object Qbefore_handle, Qhorizontal_handle, Qafter_handle; +Lisp_Object Qup, Qdown, Qtop, Qbottom; +Lisp_Object Qleft, Qright, Qleftmost, Qrightmost; static Lisp_Object Qend_scroll; -Lisp_Object Qtop; static Lisp_Object Qratio; /* An array of scroll bar parts, indexed by an enum scroll_bar_part value. */ static Lisp_Object *const scroll_bar_parts[] = { &Qabove_handle, &Qhandle, &Qbelow_handle, - &Qup, &Qdown, &Qtop, &Qbottom, &Qend_scroll, &Qratio + &Qup, &Qdown, &Qtop, &Qbottom, &Qend_scroll, &Qratio, + &Qbefore_handle, &Qhorizontal_handle, &Qafter_handle, + &Qleft, &Qright, &Qleftmost, &Qrightmost, &Qend_scroll, &Qratio }; /* A vector, indexed by button number, giving the down-going location @@ -5546,6 +5551,7 @@ make_lispy_event (struct input_event *event) #endif #ifndef USE_TOOLKIT_SCROLL_BARS case SCROLL_BAR_CLICK_EVENT: + case HORIZONTAL_SCROLL_BAR_CLICK_EVENT: #endif { int button = event->code; @@ -5946,6 +5952,36 @@ make_lispy_event (struct input_event *event) return list2 (head, position); } + case HORIZONTAL_SCROLL_BAR_CLICK_EVENT: + { + Lisp_Object position, head, window, portion_whole, part; + + window = event->frame_or_window; + portion_whole = Fcons (event->x, event->y); + part = *scroll_bar_parts[(int) event->part]; + + position = list5 (window, Qhorizontal_scroll_bar, portion_whole, + make_number (event->timestamp), part); + + /* Always treat scroll bar events as clicks. */ + event->modifiers |= click_modifier; + event->modifiers &= ~up_modifier; + + if (event->code >= ASIZE (mouse_syms)) + mouse_syms = larger_vector (mouse_syms, + event->code - ASIZE (mouse_syms) + 1, + -1); + + /* Get the symbol we should use for the mouse click. */ + head = modify_event_symbol (event->code, + event->modifiers, + Qmouse_click, + Vlispy_mouse_stem, + NULL, &mouse_syms, + ASIZE (mouse_syms)); + return list2 (head, position); + } + #endif /* USE_TOOLKIT_SCROLL_BARS */ case DRAG_N_DROP_EVENT: @@ -10177,7 +10213,8 @@ On such systems, Emacs starts a subshell instead of suspending. */) with a window system; but suspend should be disabled in that case. */ get_tty_size (fileno (CURTTY ()->input), &width, &height); if (width != old_width || height != old_height) - change_frame_size (SELECTED_FRAME (), width, height, 0, 0, 0, 0); + change_frame_size (SELECTED_FRAME (), width, height + - FRAME_MENU_BAR_LINES (SELECTED_FRAME ()), 0, 0, 0, 0); /* Run suspend-resume-hook. */ hook = intern ("suspend-resume-hook"); @@ -11026,6 +11063,13 @@ syms_of_keyboard (void) DEFSYM (Qbottom, "bottom"); DEFSYM (Qend_scroll, "end-scroll"); DEFSYM (Qratio, "ratio"); + DEFSYM (Qbefore_handle, "before-handle"); + DEFSYM (Qhorizontal_handle, "horizontal-handle"); + DEFSYM (Qafter_handle, "after-handle"); + DEFSYM (Qleft, "left"); + DEFSYM (Qright, "right"); + DEFSYM (Qleftmost, "leftmost"); + DEFSYM (Qrightmost, "rightmost"); DEFSYM (Qevent_kind, "event-kind"); DEFSYM (Qevent_symbol_elements, "event-symbol-elements"); diff --git a/src/minibuf.c b/src/minibuf.c index b85d3f57df3..93e19d5c120 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -651,6 +651,7 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, set_window_buffer (minibuf_window, Fcurrent_buffer (), 0, 0); Fselect_window (minibuf_window, Qnil); XWINDOW (minibuf_window)->hscroll = 0; + XWINDOW (minibuf_window)->suspend_auto_hscroll = 0; Fmake_local_variable (Qprint_escape_newlines); print_escape_newlines = 1; diff --git a/src/nsfns.m b/src/nsfns.m index 8f1a45d03f1..8bce1da2e5d 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -76,10 +76,12 @@ extern Lisp_Object Qicon_top; extern Lisp_Object Qtop; extern Lisp_Object Qdisplay; extern Lisp_Object Qvertical_scroll_bars; +extern Lisp_Object Qhorizontal_scroll_bars; extern Lisp_Object Qauto_raise; extern Lisp_Object Qauto_lower; extern Lisp_Object Qbox; extern Lisp_Object Qscroll_bar_width; +extern Lisp_Object Qscroll_bar_height; extern Lisp_Object Qx_resource_name; extern Lisp_Object Qface_set_after_frame_default; extern Lisp_Object Qunderline, Qundefined; @@ -705,6 +707,26 @@ x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) } +void +x_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval) +{ + int old_width = FRAME_INTERNAL_BORDER_WIDTH (f); + + CHECK_TYPE_RANGED_INTEGER (int, arg); + FRAME_INTERNAL_BORDER_WIDTH (f) = XINT (arg); + if (FRAME_INTERNAL_BORDER_WIDTH (f) < 0) + FRAME_INTERNAL_BORDER_WIDTH (f) = 0; + + if (FRAME_INTERNAL_BORDER_WIDTH (f) == old_width) + return; + + if (FRAME_X_WINDOW (f) != 0) + adjust_frame_size (f, -1, -1, 3, 0); + + SET_FRAME_GARBAGED (f); +} + + static void ns_implicitly_set_icon_type (struct frame *f) { @@ -954,17 +976,19 @@ frame_parm_handler ns_frame_parm_handlers[] = x_set_mouse_color, x_explicitly_set_name, x_set_scroll_bar_width, /* generic OK */ + x_set_scroll_bar_height, /* generic OK */ x_set_title, x_set_unsplittable, /* generic OK */ x_set_vertical_scroll_bars, /* generic OK */ + x_set_horizontal_scroll_bars, /* generic OK */ x_set_visibility, /* generic OK */ x_set_tool_bar_lines, 0, /* x_set_scroll_bar_foreground, will ignore (not possible on NS) */ 0, /* x_set_scroll_bar_background, will ignore (not possible on NS) */ x_set_screen_gamma, /* generic OK */ x_set_line_spacing, /* generic OK, sets f->extra_line_spacing to int */ - x_set_fringe_width, /* generic OK */ - x_set_fringe_width, /* generic OK */ + x_set_left_fringe, /* generic OK */ + x_set_right_fringe, /* generic OK */ 0, /* x_set_wait_for_wm, will ignore */ x_set_fullscreen, /* generic OK */ x_set_font_backend, /* generic OK */ @@ -1208,7 +1232,7 @@ This function is an internal primitive--use `make-frame' instead. */) "internalBorderWidth", "InternalBorderWidth", RES_TYPE_NUMBER); - /* default scrollbars on right on Mac */ + /* default vertical scrollbars on right on Mac */ { Lisp_Object spos #ifdef NS_IMPL_GNUSTEP @@ -1220,6 +1244,9 @@ This function is an internal primitive--use `make-frame' instead. */) "verticalScrollBars", "VerticalScrollBars", RES_TYPE_SYMBOL); } + x_default_parameter (f, parms, Qhorizontal_scroll_bars, Qt, + "horizontalScrollBars", "HorizontalScrollBars", + RES_TYPE_SYMBOL); x_default_parameter (f, parms, Qforeground_color, build_string ("Black"), "foreground", "Foreground", RES_TYPE_STRING); x_default_parameter (f, parms, Qbackground_color, build_string ("White"), @@ -1280,6 +1307,8 @@ This function is an internal primitive--use `make-frame' instead. */) f->output_data.ns->vertical_drag_cursor = [NSCursor resizeUpDownCursor]; FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor = [NSCursor arrowCursor]; + FRAME_DISPLAY_INFO (f)->horizontal_scroll_bar_cursor + = [NSCursor arrowCursor]; f->output_data.ns->current_pointer = f->output_data.ns->text_cursor; [[EmacsView alloc] initFrameFromEmacs: f]; @@ -1305,6 +1334,9 @@ This function is an internal primitive--use `make-frame' instead. */) x_default_parameter (f, parms, Qscroll_bar_width, Qnil, "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER); + x_default_parameter (f, parms, Qscroll_bar_height, Qnil, + "scrollBarHeight", "ScrollBarHeight", + RES_TYPE_NUMBER); x_default_parameter (f, parms, Qalpha, Qnil, "alpha", "Alpha", RES_TYPE_NUMBER); x_default_parameter (f, parms, Qfullscreen, Qnil, @@ -2231,6 +2263,15 @@ x_set_scroll_bar_default_width (struct frame *f) wid - 1) / wid; } +void +x_set_scroll_bar_default_height (struct frame *f) +{ + int height = FRAME_LINE_HEIGHT (f); + FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = NS_SCROLL_BAR_WIDTH_DEFAULT; + FRAME_CONFIG_SCROLL_BAR_LINES (f) = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + + height - 1) / height; +} + /* terms impl this instead of x-get-resource directly */ char * x_get_string_resource (XrmDatabase rdb, const char *name, const char *class) diff --git a/src/nsterm.h b/src/nsterm.h index 7ed23f583f6..00a0b54add9 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -606,6 +606,9 @@ struct ns_display_info /* The cursor to use for vertical scroll bars. */ Cursor vertical_scroll_bar_cursor; + /* The cursor to use for horizontal scroll bars. */ + Cursor horizontal_scroll_bar_cursor; + /* Information about the range of text currently shown in mouse-face. */ Mouse_HLInfo mouse_highlight; @@ -746,12 +749,20 @@ struct x_output #endif /* Compute pixel size for vertical scroll bars */ -#define NS_SCROLL_BAR_WIDTH(f) \ -(FRAME_HAS_VERTICAL_SCROLL_BARS (f) \ - ? rint (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0 \ - ? FRAME_CONFIG_SCROLL_BAR_WIDTH (f) \ - : (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f))) \ - : 0) +#define NS_SCROLL_BAR_WIDTH(f) \ + (FRAME_HAS_VERTICAL_SCROLL_BARS (f) \ + ? rint (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0 \ + ? FRAME_CONFIG_SCROLL_BAR_WIDTH (f) \ + : (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f))) \ + : 0) + +/* Compute pixel size for horizontal scroll bars */ +#define NS_SCROLL_BAR_HEIGHT(f) \ + (FRAME_HAS_HORIZONTAL_SCROLL_BARS (f) \ + ? rint (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0 \ + ? FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) \ + : (FRAME_SCROLL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f))) \ + : 0) /* Difference btwn char-column-calculated and actual SB widths. This is only a concern for rendering when SB on left. */ @@ -760,6 +771,13 @@ struct x_output (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f) \ - NS_SCROLL_BAR_WIDTH (f)) : 0) +/* Difference btwn char-line-calculated and actual SB heights. + This is only a concern for rendering when SB on top. */ +#define NS_SCROLL_BAR_ADJUST_HORIZONTALLY(w, f) \ + (WINDOW_HAS_HORIZONTAL_SCROLL_BARS (w) ? \ + (FRAME_SCROLL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f) \ + - NS_SCROLL_BAR_HEIGHT (f)) : 0) + /* XXX: fix for GNUstep inconsistent accounting for titlebar */ #ifdef NS_IMPL_GNUSTEP #define NS_TOP_POS(f) ((f)->top_pos + 18) @@ -777,8 +795,8 @@ struct x_output /* First position where characters can be shown (instead of scrollbar, if it is on left. */ -#define FIRST_CHAR_POSITION(f) \ - (! (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)) ? 0 \ +#define FIRST_CHAR_POSITION(f) \ + (! (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)) ? 0 \ : FRAME_SCROLL_BAR_COLS (f)) extern struct ns_display_info *ns_term_init (Lisp_Object display_name); @@ -918,6 +936,7 @@ extern char gnustep_base_version[]; /* version tracking */ #define SCREENMAX 16000 #define NS_SCROLL_BAR_WIDTH_DEFAULT [EmacsScroller scrollerWidth] +#define NS_SCROLL_BAR_HEIGHT_DEFAULT [EmacsScroller scrollerHeight] /* This is to match emacs on other platforms, ugly though it is. */ #define NS_SELECTION_BG_COLOR_DEFAULT @"LightGoldenrod2"; #define NS_SELECTION_FG_COLOR_DEFAULT @"Black"; diff --git a/src/nsterm.m b/src/nsterm.m index 3b1c945c6bf..9c64ab5f93b 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1342,10 +1342,6 @@ x_set_window_size (struct frame *f, block_input (); - check_frame_size (f, &width, &height, pixelwise); - - compute_fringe_widths (f, 0); - if (pixelwise) { pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width); @@ -1417,6 +1413,8 @@ x_set_window_size (struct frame *f, cancel_mouse_face (f); unblock_input (); + + do_pending_window_change (0); } @@ -2315,52 +2313,6 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row, { int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny; - /* If the fringe is adjacent to the left (right) scroll bar of a - leftmost (rightmost, respectively) window, then extend its - background to the gap between the fringe and the bar. */ - if ((WINDOW_LEFTMOST_P (w) - && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)) - || (WINDOW_RIGHTMOST_P (w) - && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))) - { - int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w); - - if (sb_width > 0) - { - int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w); - int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w) - * FRAME_COLUMN_WIDTH (f)); - - if (bx < 0) - { - /* Bitmap fills the fringe. */ - if (bar_area_x + bar_area_width == p->x) - bx = bar_area_x + sb_width; - else if (p->x + p->wd == bar_area_x) - bx = bar_area_x; - if (bx >= 0) - { - int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w); - - nx = bar_area_width - sb_width; - by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, - row->y)); - ny = row->visible_height; - } - } - else - { - if (bar_area_x + bar_area_width == bx) - { - bx = bar_area_x + sb_width; - nx += bar_area_width - sb_width; - } - else if (bx + nx == bar_area_x) - nx += bar_area_width - sb_width; - } - } - } - if (bx >= 0 && nx > 0) { NSRect r = NSMakeRect (bx, by, nx, ny); @@ -3792,10 +3744,9 @@ ns_set_vertical_scroll_bar (struct window *window, NSRect r, v; struct frame *f = XFRAME (WINDOW_FRAME (window)); EmacsView *view = FRAME_NS_VIEW (f); - int window_y, window_height; - int top, left, height, width, sb_width, sb_left; EmacsScroller *bar; - BOOL fringe_extended_p; + int window_y, window_height; + int top, left, height, width; /* optimization; display engine sends WAY too many of these.. */ if (!NILP (window->vertical_scroll_bar)) @@ -3822,18 +3773,11 @@ ns_set_vertical_scroll_bar (struct window *window, width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f); left = WINDOW_SCROLL_BAR_AREA_X (window); - /* allow for displaying a skinnier scrollbar than char area allotted */ - sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ? - WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width; - sb_left = left; - - r = NSMakeRect (sb_left, top, sb_width, height); + r = NSMakeRect (left, top, width, height); /* the parent view is flipped, so we need to flip y value */ v = [view frame]; r.origin.y = (v.size.height - r.size.height - r.origin.y); - fringe_extended_p = WINDOW_FRINGE_EXTENDED_P (window); - XSETWINDOW (win, window); block_input (); @@ -3846,7 +3790,7 @@ ns_set_vertical_scroll_bar (struct window *window, [bar removeFromSuperview]; wset_vertical_scroll_bar (window, Qnil); } - ns_clear_frame_area (f, sb_left, top, width, height); + ns_clear_frame_area (f, left, top, width, height); unblock_input (); return; } @@ -3854,12 +3798,7 @@ ns_set_vertical_scroll_bar (struct window *window, if (NILP (window->vertical_scroll_bar)) { if (width > 0 && height > 0) - { - if (fringe_extended_p) - ns_clear_frame_area (f, sb_left, top, sb_width, height); - else - ns_clear_frame_area (f, left, top, width, height); - } + ns_clear_frame_area (f, left, top, width, height); bar = [[EmacsScroller alloc] initFrame: r window: win]; wset_vertical_scroll_bar (window, make_save_ptr (bar)); @@ -3873,7 +3812,97 @@ ns_set_vertical_scroll_bar (struct window *window, if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r)) { if (oldRect.origin.x != r.origin.x) - ns_clear_frame_area (f, sb_left, top, width, height); + ns_clear_frame_area (f, left, top, width, height); + [bar setFrame: r]; + } + } + + [bar setPosition: position portion: portion whole: whole]; + unblock_input (); +} + + +static void +ns_set_horizontal_scroll_bar (struct window *window, + int portion, int whole, int position) +/* -------------------------------------------------------------------------- + External (hook): Update or add scrollbar + -------------------------------------------------------------------------- */ +{ + Lisp_Object win; + NSRect r, v; + struct frame *f = XFRAME (WINDOW_FRAME (window)); + EmacsView *view = FRAME_NS_VIEW (f); + EmacsScroller *bar; + int top, height, left, width; + int window_x, window_width; + int pixel_width = WINDOW_PIXEL_WIDTH (window); + + /* optimization; display engine sends WAY too many of these.. */ + if (!NILP (window->horizontal_scroll_bar)) + { + bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar); + if ([bar checkSamePosition: position portion: portion whole: whole]) + { + if (view->scrollbarsNeedingUpdate == 0) + { + if (!windows_or_buffers_changed) + return; + } + else + view->scrollbarsNeedingUpdate--; + } + } + + NSTRACE (ns_set_horizontal_scroll_bar); + + /* Get dimensions. */ + window_box (window, ANY_AREA, 0, &window_x, &window_width, 0); + left = window_x; + width = window_width; + height = WINDOW_CONFIG_SCROLL_BAR_LINES (window) * FRAME_LINE_HEIGHT (f); + top = WINDOW_SCROLL_BAR_AREA_Y (window); + + r = NSMakeRect (left, top, width, height); + /* the parent view is flipped, so we need to flip y value */ + v = [view frame]; + /* ??????? PXW/scrollbars !!!!!!!!!!!!!!!!!!!! */ + r.origin.y = (v.size.height - r.size.height - r.origin.y); + + XSETWINDOW (win, window); + block_input (); + + if (WINDOW_TOTAL_COLS (window) < 5) + { + if (!NILP (window->horizontal_scroll_bar)) + { + bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar); + [bar removeFromSuperview]; + wset_horizontal_scroll_bar (window, Qnil); + } + ns_clear_frame_area (f, left, top, width, height); + unblock_input (); + return; + } + + if (NILP (window->horizontal_scroll_bar)) + { + if (width > 0 && height > 0) + ns_clear_frame_area (f, left, top, width, height); + + bar = [[EmacsScroller alloc] initFrame: r window: win]; + wset_horizontal_scroll_bar (window, make_save_ptr (bar)); + } + else + { + NSRect oldRect; + bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar); + oldRect = [bar frame]; + r.size.width = oldRect.size.width; + if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r)) + { + if (oldRect.origin.x != r.origin.x) + ns_clear_frame_area (f, left, top, width, height); [bar setFrame: r]; } } @@ -3919,6 +3948,12 @@ ns_redeem_scroll_bar (struct window *window) bar = XNS_SCROLL_BAR (window->vertical_scroll_bar); [bar reprieve]; } + + if (!NILP (window->horizontal_scroll_bar)) + { + bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar); + [bar reprieve]; + } } @@ -4483,7 +4518,7 @@ ns_term_shutdown (int sig) [self sendEvent:event]; [self updateWindows]; } while (shouldKeepRunning); - + [pool release]; } @@ -4652,30 +4687,9 @@ ns_term_shutdown (int sig) ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES; #endif [NSApp setServicesProvider: NSApp]; - - [self antialiasThresholdDidChange:nil]; -#ifdef NS_IMPL_COCOA -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(antialiasThresholdDidChange:) - name:NSAntialiasThresholdChangedNotification - object:nil]; -#endif -#endif - ns_send_appdefined (-2); } -- (void)antialiasThresholdDidChange:(NSNotification *)notification -{ -#ifdef NS_IMPL_COCOA -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - macfont_update_antialias_threshold (); -#endif -#endif -} - /* Termination sequences: C-x C-c: @@ -7021,7 +7035,7 @@ if (cols > 0 && rows > 0) if (nr_eff_screens == 1) return [super constrainFrameRect:frameRect toScreen:screen]; - + /* The default implementation does two things 1) ensure that the top of the rectangle is below the menu bar (or below the top of the screen) and 2) resizes windows larger than the screen. As we @@ -7506,8 +7520,6 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset) FRAME_COLUMN_WIDTH (f) = font->average_width; FRAME_LINE_HEIGHT (f) = font->height; - compute_fringe_widths (f, 1); - /* Compute the scroll bar width in character columns. */ if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0) { @@ -7521,6 +7533,19 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset) FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid; } + /* Compute the scroll bar height in character lines. */ + if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0) + { + int height = FRAME_LINE_HEIGHT (f); + FRAME_CONFIG_SCROLL_BAR_LINES (f) + = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height; + } + else + { + int height = FRAME_LINE_HEIGHT (f); + FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height; + } + /* Now make the frame display the given font. */ if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen]) x_set_window_size (f, 0, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), diff --git a/src/term.c b/src/term.c index 9081790745c..8c004ccbecb 100644 --- a/src/term.c +++ b/src/term.c @@ -2411,7 +2411,7 @@ frame's terminal). */) was suspended. */ get_tty_size (fileno (t->display_info.tty->input), &width, &height); if (width != old_width || height != old_height) - change_frame_size (f, width, height, 0, 0, 0, 0); + change_frame_size (f, width, height - FRAME_MENU_BAR_LINES (f), 0, 0, 0, 0); SET_FRAME_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1); } @@ -3904,6 +3904,7 @@ clear_tty_hooks (struct terminal *terminal) terminal->fullscreen_hook = 0; terminal->menu_show_hook = 0; terminal->set_vertical_scroll_bar_hook = 0; + terminal->set_horizontal_scroll_bar_hook = 0; terminal->condemn_scroll_bars_hook = 0; terminal->redeem_scroll_bar_hook = 0; terminal->judge_scroll_bars_hook = 0; @@ -4225,6 +4226,7 @@ use the Bourne shell command `TERM=... export TERM' (C-shell:\n\ tty->specified_window = height; FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none; + FRAME_HAS_HORIZONTAL_SCROLL_BARS (f) = 0; tty->char_ins_del_ok = 1; baud_rate = 19200; } diff --git a/src/termhooks.h b/src/termhooks.h index f9bf9d785b6..04104eb41e9 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -37,7 +37,14 @@ enum scroll_bar_part { scroll_bar_to_top, scroll_bar_to_bottom, scroll_bar_end_scroll, - scroll_bar_move_ratio + scroll_bar_move_ratio, + scroll_bar_before_handle, + scroll_bar_horizontal_handle, + scroll_bar_after_handle, + scroll_bar_left_arrow, + scroll_bar_right_arrow, + scroll_bar_to_leftmost, + scroll_bar_to_rightmost }; /* Output method of a terminal (and frames on this terminal, respectively). */ @@ -130,6 +137,19 @@ enum event_kind whose scroll bar was clicked in. .timestamp gives a timestamp (in milliseconds) for the click. */ + HORIZONTAL_SCROLL_BAR_CLICK_EVENT, /* .code gives the number of the mouse button + that was clicked. + .modifiers holds the state of the modifier + keys. + .part is a lisp symbol indicating which + part of the scroll bar got clicked. + .x gives the distance from the start of the + scroll bar of the click; .y gives the total + length of the scroll bar. + .frame_or_window gives the window + whose scroll bar was clicked in. + .timestamp gives a timestamp (in + milliseconds) for the click. */ SELECTION_REQUEST_EVENT, /* Another X client wants a selection from us. See `struct selection_input_event'. */ SELECTION_CLEAR_EVENT, /* Another X client cleared our selection. */ @@ -518,6 +538,16 @@ struct terminal int position); + /* Set the horizontal scroll bar for WINDOW to have its upper left + corner at (TOP, LEFT), and be LENGTH rows high. Set its handle to + indicate that we are displaying PORTION characters out of a total + of WHOLE characters, starting at POSITION. If WINDOW doesn't yet + have a scroll bar, create one for it. */ + void (*set_horizontal_scroll_bar_hook) (struct window *window, + int portion, int whole, + int position); + + /* The following three hooks are used when we're doing a thorough redisplay of the frame. We don't explicitly know which scroll bars are going to be deleted, because keeping track of when windows go diff --git a/src/w32console.c b/src/w32console.c index 2fbc190ee2d..98f68145191 100644 --- a/src/w32console.c +++ b/src/w32console.c @@ -657,6 +657,7 @@ initialize_w32_display (struct terminal *term, int *width, int *height) term->frame_rehighlight_hook = 0; term->frame_raise_lower_hook = 0; term->set_vertical_scroll_bar_hook = 0; + term->set_horizontal_scroll_bar_hook = 0; term->condemn_scroll_bars_hook = 0; term->redeem_scroll_bar_hook = 0; term->judge_scroll_bars_hook = 0; diff --git a/src/w32fns.c b/src/w32fns.c index 14d1cb4e771..ac0e693e1c0 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -328,8 +328,7 @@ void x_explicitly_set_name (struct frame *, Lisp_Object, Lisp_Object); void x_set_menu_bar_lines (struct frame *, Lisp_Object, Lisp_Object); void x_set_title (struct frame *, Lisp_Object, Lisp_Object); void x_set_tool_bar_lines (struct frame *, Lisp_Object, Lisp_Object); - - +void x_set_internal_border_width (struct frame *f, Lisp_Object, Lisp_Object); /* Store the screen positions of frame F into XPTR and YPTR. @@ -1361,23 +1360,23 @@ x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) { CHECK_NUMBER (Vx_window_horizontal_drag_shape); horizontal_drag_cursor - = XCreateFontCursor (FRAME_X_DISPLAY (f), + = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_window_horizontal_drag_shape)); } else horizontal_drag_cursor - = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow); + = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_sb_h_double_arrow); if (!NILP (Vx_window_vertical_drag_shape)) { CHECK_NUMBER (Vx_window_vertical_drag_shape); vertical_drag_cursor - = XCreateFontCursor (FRAME_X_DISPLAY (f), + = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_window_vertical_drag_shape)); } else vertical_drag_cursor - = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_v_double_arrow); + = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_sb_v_double_arrow); /* Check and report errors with the above calls. */ x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s"); @@ -1599,8 +1598,53 @@ x_set_icon_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval) unblock_input (); #endif } - +void +x_clear_under_internal_border (struct frame *f) +{ + int border = FRAME_INTERNAL_BORDER_WIDTH (f); + + /* Clear border if it's larger than before. */ + if (border != 0) + { + HDC hdc = get_frame_dc (f); + int width = FRAME_PIXEL_WIDTH (f); + int height = FRAME_PIXEL_HEIGHT (f); + + block_input (); + w32_clear_area (f, hdc, 0, FRAME_TOP_MARGIN_HEIGHT (f), width, border); + w32_clear_area (f, hdc, 0, 0, border, height); + w32_clear_area (f, hdc, width - border, 0, border, height); + w32_clear_area (f, hdc, 0, height - border, width, border); + release_frame_dc (f, hdc); + unblock_input (); + } +} + + +void +x_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval) +{ + int border; + + CHECK_TYPE_RANGED_INTEGER (int, arg); + border = max (XINT (arg), 0); + + if (border != FRAME_INTERNAL_BORDER_WIDTH (f)) + { + FRAME_INTERNAL_BORDER_WIDTH (f) = border; + + if (FRAME_X_WINDOW (f) != 0) + { + adjust_frame_size (f, -1, -1, 3, 0); + + if (FRAME_VISIBLE_P (f)) + x_clear_under_internal_border (f); + } + } +} + + void x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) { @@ -1621,7 +1665,10 @@ x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) FRAME_MENU_BAR_LINES (f) = 0; FRAME_MENU_BAR_HEIGHT (f) = 0; if (nlines) - FRAME_EXTERNAL_MENU_BAR (f) = 1; + { + FRAME_EXTERNAL_MENU_BAR (f) = 1; + windows_or_buffers_changed = 23; + } else { if (FRAME_EXTERNAL_MENU_BAR (f) == 1) @@ -1630,11 +1677,16 @@ x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) /* Adjust the frame size so that the client (text) dimensions remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being - set correctly. */ - x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 1); - do_pending_window_change (0); + set correctly. Note that we resize twice: The first time upon + a request from the window manager who wants to keep the height + of the outer rectangle (including decorations) unchanged, and a + second time because we want to keep the height of the inner + rectangle (without the decorations unchanged). */ + adjust_frame_size (f, -1, -1, 2, 1); + + /* Not sure whether this is needed. */ + x_clear_under_internal_border (f); } - adjust_frame_glyphs (f); } @@ -1648,8 +1700,7 @@ x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) void x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) { - int delta, nlines, root_height; - int unit = FRAME_LINE_HEIGHT (f); + int nlines; /* Treat tool bars like menu bars. */ if (FRAME_MINIBUF_ONLY_P (f)) @@ -1661,66 +1712,50 @@ x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) else nlines = 0; - /* Make sure we redisplay all windows in this frame. */ - windows_or_buffers_changed = 23; + x_change_tool_bar_height (f, nlines * FRAME_LINE_HEIGHT (f)); +} - /* DELTA is in pixels now. */ - delta = (nlines - FRAME_TOOL_BAR_LINES (f)) * unit; - /* Don't resize the tool-bar to more than we have room for. Note: The - calculations below and the subsequent call to resize_frame_windows - are inherently flawed because they can make the toolbar higher than - the containing frame. */ - if (delta > 0) - { - root_height = WINDOW_PIXEL_HEIGHT (XWINDOW (FRAME_ROOT_WINDOW (f))); - if (root_height - delta < unit) - { - delta = root_height - unit; - /* When creating a new frame and toolbar mode is enabled, we - need at least one toolbar line. */ - nlines = max (FRAME_TOOL_BAR_LINES (f) + delta / unit, 1); - } - } +/* Set the pixel height of the tool bar of frame F to HEIGHT. */ +void +x_change_tool_bar_height (struct frame *f, int height) +{ + Lisp_Object frame; + int unit = FRAME_LINE_HEIGHT (f); + int old_height = FRAME_TOOL_BAR_HEIGHT (f); + int lines = (height + unit - 1) / unit; + int old_text_height = FRAME_TEXT_HEIGHT (f); - FRAME_TOOL_BAR_LINES (f) = nlines; - FRAME_TOOL_BAR_HEIGHT (f) = nlines * FRAME_LINE_HEIGHT (f); - ++windows_or_buffers_changed; - resize_frame_windows (f, FRAME_TEXT_HEIGHT (f), 0, 1); - adjust_frame_glyphs (f); + /* Make sure we redisplay all windows in this frame. */ + windows_or_buffers_changed = 23; + + /* Recalculate tool bar and frame text sizes. */ + FRAME_TOOL_BAR_HEIGHT (f) = height; + FRAME_TOOL_BAR_LINES (f) = lines; + FRAME_TEXT_HEIGHT (f) + = FRAME_PIXEL_TO_TEXT_HEIGHT (f, FRAME_PIXEL_HEIGHT (f)); + FRAME_LINES (f) + = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, FRAME_PIXEL_HEIGHT (f)); + /* Store the `tool-bar-lines' and `height' frame parameters. */ + store_frame_param (f, Qtool_bar_lines, make_number (lines)); + store_frame_param (f, Qheight, make_number (FRAME_LINES (f))); - /* We also have to make sure that the internal border at the top of - the frame, below the menu bar or tool bar, is redrawn when the - tool bar disappears. This is so because the internal border is - below the tool bar if one is displayed, but is below the menu bar - if there isn't a tool bar. The tool bar draws into the area - below the menu bar. */ if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_HEIGHT (f) == 0) { clear_frame (f); clear_current_matrices (f); } - /* If the tool bar gets smaller, the internal border below it - has to be cleared. It was formerly part of the display - of the larger tool bar, and updating windows won't clear it. */ - if (FRAME_INTERNAL_BORDER_WIDTH (f) != 0 && FRAME_VISIBLE_P (f)) - { - int height = FRAME_INTERNAL_BORDER_WIDTH (f); - int width = FRAME_PIXEL_WIDTH (f); - int y = nlines * unit; - HDC hdc = get_frame_dc (f); + if ((height < old_height) && WINDOWP (f->tool_bar_window)) + clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix); - block_input (); - w32_clear_area (f, hdc, 0, y, width, height); - release_frame_dc (f, hdc); - unblock_input (); - } + /* Recalculate toolbar height. */ + f->n_tool_bar_rows = 0; - if (delta < 0 && WINDOWP (f->tool_bar_window)) - clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix); + adjust_frame_size (f, -1, -1, 4, 0); - run_window_configuration_change_hook (f); + if (FRAME_X_WINDOW (f)) + x_clear_under_internal_border (f); } @@ -1839,6 +1874,16 @@ x_set_scroll_bar_default_width (struct frame *f) = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit; } + +void +x_set_scroll_bar_default_height (struct frame *f) +{ + int unit = FRAME_LINE_HEIGHT (f); + + FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = GetSystemMetrics (SM_CXHSCROLL); + FRAME_CONFIG_SCROLL_BAR_LINES (f) + = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + unit - 1) / unit; +} /* Subroutines for creating a frame. */ @@ -1893,7 +1938,7 @@ w32_init_class (HINSTANCE hinst) } static HWND -w32_createscrollbar (struct frame *f, struct scroll_bar * bar) +w32_createvscrollbar (struct frame *f, struct scroll_bar * bar) { return CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE, /* Position and size of scroll bar. */ @@ -1901,6 +1946,15 @@ w32_createscrollbar (struct frame *f, struct scroll_bar * bar) FRAME_W32_WINDOW (f), NULL, hinst, NULL); } +static HWND +w32_createhscrollbar (struct frame *f, struct scroll_bar * bar) +{ + return CreateWindow ("SCROLLBAR", "", SBS_HORZ | WS_CHILD | WS_VISIBLE, + /* Position and size of scroll bar. */ + bar->left, bar->top, bar->width, bar->height, + FRAME_W32_WINDOW (f), NULL, hinst, NULL); +} + static void w32_createwindow (struct frame *f) { @@ -1952,7 +2006,8 @@ w32_createwindow (struct frame *f) SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FRAME_COLUMN_WIDTH (f)); SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, FRAME_LINE_HEIGHT (f)); SetWindowLong (hwnd, WND_BORDER_INDEX, FRAME_INTERNAL_BORDER_WIDTH (f)); - SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, FRAME_SCROLL_BAR_AREA_WIDTH (f)); + SetWindowLong (hwnd, WND_VSCROLLBAR_INDEX, FRAME_SCROLL_BAR_AREA_WIDTH (f)); + SetWindowLong (hwnd, WND_HSCROLLBAR_INDEX, FRAME_SCROLL_BAR_AREA_HEIGHT (f)); SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f)); /* Enable drag-n-drop. */ @@ -2367,7 +2422,8 @@ w32_name_of_message (UINT msg) M (WM_EMACS_KILL), M (WM_EMACS_CREATEWINDOW), M (WM_EMACS_DONE), - M (WM_EMACS_CREATESCROLLBAR), + M (WM_EMACS_CREATEVSCROLLBAR), + M (WM_EMACS_CREATEHSCROLLBAR), M (WM_EMACS_SHOWWINDOW), M (WM_EMACS_SETWINDOWPOS), M (WM_EMACS_DESTROYWINDOW), @@ -2384,6 +2440,7 @@ w32_name_of_message (UINT msg) M (WM_EMACS_SHOW_CARET), M (WM_EMACS_HIDE_CARET), M (WM_EMACS_SETCURSOR), + M (WM_EMACS_SHOWCURSOR), M (WM_EMACS_PAINT), M (WM_CHAR), #undef M @@ -3441,6 +3498,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) track_mouse_event_fn (&tme); track_mouse_window = hwnd; } + case WM_HSCROLL: case WM_VSCROLL: if (w32_mouse_move_interval <= 0 || (msg == WM_MOUSEMOVE && button_state == 0)) @@ -3779,10 +3837,14 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) return 0; case WM_WINDOWPOSCHANGING: - /* Don't restrict the sizing of tip frames. */ - if (frame_resize_pixelwise || hwnd == tip_window) - return 0; + /* Don't restrict the sizing of any kind of frames. If the window + manager doesn't, there's no reason to do it ourselves. */ +#if 0 + if (frame_resize_pixelwise || hwnd == tip_window) +#endif + return 0; +#if 0 /* Don't restrict the sizing of fullscreened frames, allowing them to be flush with the sides of the screen. */ f = x_window_to_frame (dpyinfo, hwnd); @@ -3805,7 +3867,8 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) DWORD font_width; DWORD line_height; DWORD internal_border; - DWORD scrollbar_extra; + DWORD vscrollbar_extra; + DWORD hscrollbar_extra; RECT wr; wp.length = sizeof (wp); @@ -3816,7 +3879,8 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX); line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX); internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX); - scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX); + vscrollbar_extra = GetWindowLong (hwnd, WND_VSCROLLBAR_INDEX); + hscrollbar_extra = GetWindowLong (hwnd, WND_HSCROLLBAR_INDEX); leave_crit (); @@ -3827,10 +3891,10 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) /* Force width and height of client area to be exact multiples of the character cell dimensions. */ wdiff = (lppos->cx - (rect.right - rect.left) - - 2 * internal_border - scrollbar_extra) + - 2 * internal_border - vscrollbar_extra) % font_width; hdiff = (lppos->cy - (rect.bottom - rect.top) - - 2 * internal_border) + - 2 * internal_border - hscrollbar_extra) % line_height; if (wdiff || hdiff) @@ -3865,6 +3929,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } goto dflt; +#endif case WM_GETMINMAXINFO: /* Hack to allow resizing the Emacs frame above the screen size. @@ -3899,9 +3964,20 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) return 0; } - case WM_EMACS_CREATESCROLLBAR: - return (LRESULT) w32_createscrollbar ((struct frame *) wParam, - (struct scroll_bar *) lParam); + case WM_EMACS_SHOWCURSOR: + { + ShowCursor ((BOOL) wParam); + + return 0; + } + + case WM_EMACS_CREATEVSCROLLBAR: + return (LRESULT) w32_createvscrollbar ((struct frame *) wParam, + (struct scroll_bar *) lParam); + + case WM_EMACS_CREATEHSCROLLBAR: + return (LRESULT) w32_createhscrollbar ((struct frame *) wParam, + (struct scroll_bar *) lParam); case WM_EMACS_SHOWWINDOW: return ShowWindow ((HWND) wParam, (WPARAM) lParam); @@ -4104,7 +4180,8 @@ my_create_tip_window (struct frame *f) SetWindowLong (tip_window, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f)); /* Tip frames have no scrollbars. */ - SetWindowLong (tip_window, WND_SCROLLBAR_INDEX, 0); + SetWindowLong (tip_window, WND_VSCROLLBAR_INDEX, 0); + SetWindowLong (tip_window, WND_HSCROLLBAR_INDEX, 0); /* Do this to discard the default setting specified by our parent. */ ShowWindow (tip_window, SW_HIDE); @@ -4336,7 +4413,6 @@ This function is an internal primitive--use `make-frame' instead. */) Lisp_Object name; int minibuffer_only = 0; long window_prompting = 0; - int width, height; ptrdiff_t count = SPECPDL_INDEX (); struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; Lisp_Object display; @@ -4404,8 +4480,9 @@ This function is an internal primitive--use `make-frame' instead. */) XSETFRAME (frame, f); - /* By default, make scrollbars the system standard width. */ - x_set_scroll_bar_default_width (f); + /* By default, make scrollbars the system standard width and height. */ + FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL); + FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = GetSystemMetrics (SM_CXHSCROLL); f->terminal = dpyinfo->terminal; @@ -4431,7 +4508,6 @@ This function is an internal primitive--use `make-frame' instead. */) #endif /* GLYPH_DEBUG */ /* Specify the parent under which to make this window. */ - if (!NILP (parent)) { f->output_data.w32->parent_desc = (Window) XFASTINT (parent); @@ -4454,7 +4530,7 @@ This function is an internal primitive--use `make-frame' instead. */) { fset_name (f, name); f->explicit_name = 1; - /* use the frame's title when getting resources for this frame. */ + /* Use the frame's title when getting resources for this frame. */ specbind (Qx_resource_name, name); } @@ -4464,9 +4540,11 @@ This function is an internal primitive--use `make-frame' instead. */) x_default_parameter (f, parameters, Qfont_backend, Qnil, "fontBackend", "FontBackend", RES_TYPE_STRING); + /* Extract the window parameters from the supplied values that are needed to determine window geometry. */ x_default_font_parameter (f, parameters); + x_default_parameter (f, parameters, Qborder_width, make_number (2), "borderWidth", "BorderWidth", RES_TYPE_NUMBER); @@ -4480,7 +4558,7 @@ This function is an internal primitive--use `make-frame' instead. */) "internalBorder", "InternalBorder", RES_TYPE_NUMBER); if (! EQ (value, Qunbound)) parameters = Fcons (Fcons (Qinternal_border_width, value), - parameters); + parameters); } /* Default internalBorderWidth to 0 on Windows to match other programs. */ x_default_parameter (f, parameters, Qinternal_border_width, make_number (0), @@ -4491,6 +4569,8 @@ This function is an internal primitive--use `make-frame' instead. */) NULL, NULL, RES_TYPE_NUMBER); x_default_parameter (f, parameters, Qvertical_scroll_bars, Qright, "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL); + x_default_parameter (f, parameters, Qhorizontal_scroll_bars, Qbottom, + "horizontalScrollBars", "ScrollBars", RES_TYPE_SYMBOL); /* Also do the stuff which must be set before the window exists. */ x_default_parameter (f, parameters, Qforeground_color, build_string ("black"), @@ -4511,57 +4591,42 @@ This function is an internal primitive--use `make-frame' instead. */) "rightFringe", "RightFringe", RES_TYPE_NUMBER); /* Process alpha here (Bug#16619). */ x_default_parameter (f, parameters, Qalpha, Qnil, - "alpha", "Alpha", RES_TYPE_NUMBER); + "alpha", "Alpha", RES_TYPE_NUMBER); - /* Init faces before x_default_parameter is called for scroll-bar - parameters because that function calls x_set_scroll_bar_width, - which calls change_frame_size, which calls Fset_window_buffer, - which runs hooks, which call Fvertical_motion. At the end, we - end up in init_iterator with a null face cache, which should not - happen. */ + /* Init faces first since we need the frame's column width/line + height in various occasions. */ init_frame_faces (f); - /* Avoid calling window-configuration-change-hook; otherwise we - could get an infloop in next_frame since the frame is not yet in - Vframe_list. */ - { - ptrdiff_t count2 = SPECPDL_INDEX (); - - record_unwind_protect (unwind_create_frame_1, inhibit_lisp_code); - inhibit_lisp_code = Qt; - - /* PXW: This is a duplicate from below. We have to do it here since - otherwise x_set_tool_bar_lines will work with the character sizes - installed by init_frame_faces while the frame's pixel size is still - calculated from a character size of 1 and we subsequently hit the - eassert (height >= 0) assertion in window_box_height. The - non-pixelwise code apparently worked around this because it had one - frame line vs one toolbar line which left us with a zero root - window height which was obviously wrong as well ... */ - change_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), - FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 1, 0, 0, 1); - - /* The X resources controlling the menu-bar and tool-bar are - processed specially at startup, and reflected in the mode - variables; ignore them here. */ - x_default_parameter (f, parameters, Qmenu_bar_lines, - NILP (Vmenu_bar_mode) - ? make_number (0) : make_number (1), - NULL, NULL, RES_TYPE_NUMBER); - x_default_parameter (f, parameters, Qtool_bar_lines, - NILP (Vtool_bar_mode) - ? make_number (0) : make_number (1), - NULL, NULL, RES_TYPE_NUMBER); - - unbind_to (count2, Qnil); - } + /* The following call of change_frame_size is needed since otherwise + x_set_tool_bar_lines will already work with the character sizes + installed by init_frame_faces while the frame's pixel size is + still calculated from a character size of 1 and we subsequently + hit the (height >= 0) assertion in window_box_height. + + The non-pixelwise code apparently worked around this because it + had one frame line vs one toolbar line which left us with a zero + root window height which was obviously wrong as well ... */ + adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), + FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, 1); + + /* The X resources controlling the menu-bar and tool-bar are + processed specially at startup, and reflected in the mode + variables; ignore them here. */ + x_default_parameter (f, parameters, Qmenu_bar_lines, + NILP (Vmenu_bar_mode) + ? make_number (0) : make_number (1), + NULL, NULL, RES_TYPE_NUMBER); + x_default_parameter (f, parameters, Qtool_bar_lines, + NILP (Vtool_bar_mode) + ? make_number (0) : make_number (1), + NULL, NULL, RES_TYPE_NUMBER); x_default_parameter (f, parameters, Qbuffer_predicate, Qnil, "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL); x_default_parameter (f, parameters, Qtitle, Qnil, "title", "Title", RES_TYPE_STRING); x_default_parameter (f, parameters, Qfullscreen, Qnil, - "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); + "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW; f->output_data.w32->parent_desc = FRAME_DISPLAY_INFO (f)->root_window; @@ -4604,15 +4669,13 @@ This function is an internal primitive--use `make-frame' instead. */) "cursorType", "CursorType", RES_TYPE_SYMBOL); x_default_parameter (f, parameters, Qscroll_bar_width, Qnil, "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER); + x_default_parameter (f, parameters, Qscroll_bar_height, Qnil, + "scrollBarHeight", "ScrollBarHeight", RES_TYPE_NUMBER); + + /* Consider frame official, now. */ + f->official = true; - /* Dimensions, especially FRAME_LINES (f), must be done via change_frame_size. - Change will not be effected unless different from the current - FRAME_LINES (f). */ - width = FRAME_TEXT_WIDTH (f); - height = FRAME_TEXT_HEIGHT (f); - FRAME_TEXT_HEIGHT (f) = 0; - SET_FRAME_WIDTH (f, 0); - change_frame_size (f, width, height, 1, 0, 0, 1); + adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 0, 1); /* Tell the server what size and position, etc, we want, and how badly we want them. This should be done after we have the menu @@ -5672,13 +5735,12 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, "cursorColor", "Foreground", RES_TYPE_STRING); x_default_parameter (f, parms, Qborder_color, build_string ("black"), "borderColor", "BorderColor", RES_TYPE_STRING); + x_default_parameter (f, parms, Qalpha, Qnil, + "alpha", "Alpha", RES_TYPE_NUMBER); - /* Init faces before x_default_parameter is called for scroll-bar - parameters because that function calls x_set_scroll_bar_width, - which calls change_frame_size, which calls Fset_window_buffer, - which runs hooks, which call Fvertical_motion. At the end, we - end up in init_iterator with a null face cache, which should not - happen. */ + /* Init faces before x_default_parameter is called for the + scroll-bar-width parameter because otherwise we end up in + init_iterator with a null face cache, which should not happen. */ init_frame_faces (f); f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED; @@ -5709,9 +5771,10 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, from the current FRAME_LINES (f). */ width = FRAME_COLS (f); height = FRAME_LINES (f); - FRAME_LINES (f) = 0; SET_FRAME_COLS (f, 0); - change_frame_size (f, width, height, 1, 0, 0, 0); + SET_FRAME_LINES (f, 0); + adjust_frame_size (f, width * FRAME_COLUMN_WIDTH (f), + height * FRAME_LINE_HEIGHT (f), 0, 1); /* Add `tooltip' frame parameter's default value. */ if (NILP (Fframe_parameter (frame, Qtooltip))) @@ -5756,6 +5819,7 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, below. And the frame needs to be on Vframe_list or making it visible won't work. */ Vframe_list = Fcons (frame, Vframe_list); + f->official = true; /* Setting attributes of faces of the tooltip frame from resources and similar will increment face_change_count, which leads to the @@ -7966,17 +8030,19 @@ frame_parm_handler w32_frame_parm_handlers[] = x_set_mouse_color, x_explicitly_set_name, x_set_scroll_bar_width, + x_set_scroll_bar_height, x_set_title, x_set_unsplittable, x_set_vertical_scroll_bars, + x_set_horizontal_scroll_bars, x_set_visibility, x_set_tool_bar_lines, 0, /* x_set_scroll_bar_foreground, */ 0, /* x_set_scroll_bar_background, */ x_set_screen_gamma, x_set_line_spacing, - x_set_fringe_width, - x_set_fringe_width, + x_set_left_fringe, + x_set_right_fringe, 0, /* x_set_wait_for_wm, */ x_set_fullscreen, x_set_font_backend, diff --git a/src/w32inevt.c b/src/w32inevt.c index 50538c5b4ba..ccb5a900a16 100644 --- a/src/w32inevt.c +++ b/src/w32inevt.c @@ -587,7 +587,8 @@ resize_event (WINDOW_BUFFER_SIZE_RECORD *event) { struct frame *f = get_frame (); - change_frame_size (f, event->dwSize.X, event->dwSize.Y, 0, 1, 0, 0); + change_frame_size (f, event->dwSize.X, event->dwSize.Y + - FRAME_MENU_BAR_LINES (f), 0, 1, 0, 0); SET_FRAME_GARBAGED (f); } @@ -603,8 +604,8 @@ maybe_generate_resize_event (void) if the size hasn't actually changed. */ change_frame_size (f, 1 + info.srWindow.Right - info.srWindow.Left, - 1 + info.srWindow.Bottom - info.srWindow.Top, - 0, 0, 0, 0); + 1 + info.srWindow.Bottom - info.srWindow.Top + - FRAME_MENU_BAR_LINES (f), 0, 0, 0, 0); } #if HAVE_W32NOTIFY diff --git a/src/w32menu.c b/src/w32menu.c index 6276c840fc6..9f777167bf0 100644 --- a/src/w32menu.c +++ b/src/w32menu.c @@ -503,7 +503,8 @@ set_frame_menubar (struct frame *f, bool first_time, bool deep_p) /* Force the window size to be recomputed so that the frame's text area remains the same, if menubar has just been created. */ if (old_widget == NULL) - x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 1); + adjust_frame_size (f, FRAME_TEXT_WIDTH (f), + FRAME_TEXT_HEIGHT (f), 2, 0); } unblock_input (); diff --git a/src/w32term.c b/src/w32term.c index fd902ee7cd5..dfda29fb903 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -158,8 +158,11 @@ DWORD dwMainThreadId = 0; HANDLE hMainThread = NULL; int vertical_scroll_bar_min_handle; +int horizontal_scroll_bar_min_handle; int vertical_scroll_bar_top_border; int vertical_scroll_bar_bottom_border; +int horizontal_scroll_bar_left_border; +int horizontal_scroll_bar_right_border; int last_scroll_bar_drag_pos; @@ -455,7 +458,7 @@ x_set_frame_alpha (struct frame *f) if (!pfnSetLayeredWindowAttributes) return; - if (dpyinfo->x_highlight_frame == f) + if (dpyinfo->w32_focus_frame == f) alpha = f->alpha[0]; else alpha = f->alpha[1]; @@ -3337,11 +3340,15 @@ note_mouse_movement (struct frame *frame, MSG *msg) Mouse Face ************************************************************************/ -static struct scroll_bar *x_window_to_scroll_bar (Window); +static struct scroll_bar *x_window_to_scroll_bar (Window, int); static void x_scroll_bar_report_motion (struct frame **, Lisp_Object *, enum scroll_bar_part *, Lisp_Object *, Lisp_Object *, unsigned long *); +static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object *, + enum scroll_bar_part *, + Lisp_Object *, Lisp_Object *, + unsigned long *); static void x_check_fullscreen (struct frame *); static void @@ -3349,6 +3356,7 @@ w32_define_cursor (Window window, Cursor cursor) { PostMessage (window, WM_EMACS_SETCURSOR, (WPARAM) cursor, 0); } + /* Return the current position of the mouse. *fp should be a frame which indicates which display to ask about. @@ -3380,7 +3388,14 @@ w32_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, block_input (); if (dpyinfo->last_mouse_scroll_bar && insist == 0) - x_scroll_bar_report_motion (fp, bar_window, part, x, y, time); + { + struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar; + + if (bar->horizontal) + x_horizontal_scroll_bar_report_motion (fp, bar_window, part, x, y, time); + else + x_scroll_bar_report_motion (fp, bar_window, part, x, y, time); + } else { POINT pt; @@ -3408,7 +3423,7 @@ w32_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, if (! f1) { struct scroll_bar *bar - = x_window_to_scroll_bar (WindowFromPoint (pt)); + = x_window_to_scroll_bar (WindowFromPoint (pt), 2); if (bar) f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); @@ -3475,12 +3490,12 @@ w32_handle_tool_bar_click (struct frame *f, struct input_event *button_event) /* Scroll bar support. */ -/* Given a window ID, find the struct scroll_bar which manages it. - This can be called in GC, so we have to make sure to strip off mark - bits. */ +/* Given a window ID, find the struct scroll_bar which manages it + vertically. This can be called in GC, so we have to make sure to + strip off mark bits. */ static struct scroll_bar * -x_window_to_scroll_bar (Window window_id) +x_window_to_scroll_bar (Window window_id, int type) { Lisp_Object tail, frame; @@ -3498,7 +3513,10 @@ x_window_to_scroll_bar (Window window_id) condemned = Qnil, ! NILP (bar)); bar = XSCROLL_BAR (bar)->next) - if (SCROLL_BAR_W32_WINDOW (XSCROLL_BAR (bar)) == window_id) + if (SCROLL_BAR_W32_WINDOW (XSCROLL_BAR (bar)) == window_id + && (type = 2 + || (type == 1 && XSCROLL_BAR (bar)->horizontal) + || (type == 0 && !XSCROLL_BAR (bar)->horizontal))) return XSCROLL_BAR (bar); } @@ -3507,7 +3525,7 @@ x_window_to_scroll_bar (Window window_id) -/* Set the thumb size and position of scroll bar BAR. We are currently +/* Set the thumb size and position of vertical scroll bar BAR. We are currently displaying PORTION out of a whole WHOLE, and our position POSITION. */ static void @@ -3581,16 +3599,49 @@ w32_set_scroll_bar_thumb (struct scroll_bar *bar, unblock_input (); } +/* Set the thumb size and position of horizontal scroll bar BAR. We are currently + displaying PORTION out of a whole WHOLE, and our position POSITION. */ + +static void +w32_set_horizontal_scroll_bar_thumb (struct scroll_bar *bar, + int portion, int position, int whole) +{ + Window w = SCROLL_BAR_W32_WINDOW (bar); + SCROLLINFO si; + + block_input (); + + si.cbSize = sizeof (si); + si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; + si.nMin = 0; + si.nMax = whole; + /* Allow nPage to be one larger than nPos so we don't allow to scroll + an already fully visible buffer. */ + si.nPage = min (portion, si.nMax) + 1; + si.nPos = min (position, si.nMax); + SetScrollInfo (w, SB_CTL, &si, TRUE); + + unblock_input (); +} + /************************************************************************ Scroll bars, general ************************************************************************/ static HWND -my_create_scrollbar (struct frame * f, struct scroll_bar * bar) +my_create_vscrollbar (struct frame * f, struct scroll_bar * bar) +{ + return (HWND) SendMessage (FRAME_W32_WINDOW (f), + WM_EMACS_CREATEVSCROLLBAR, (WPARAM) f, + (LPARAM) bar); +} + +static HWND +my_create_hscrollbar (struct frame * f, struct scroll_bar * bar) { return (HWND) SendMessage (FRAME_W32_WINDOW (f), - WM_EMACS_CREATESCROLLBAR, (WPARAM) f, + WM_EMACS_CREATEHSCROLLBAR, (WPARAM) f, (LPARAM) bar); } @@ -3660,7 +3711,7 @@ my_bring_window_to_top (HWND hwnd) scroll bar. */ static struct scroll_bar * -x_scroll_bar_create (struct window *w, int top, int left, int width, int height) +x_scroll_bar_create (struct window *w, int left, int top, int width, int height, bool horizontal) { struct frame *f = XFRAME (WINDOW_FRAME (w)); HWND hwnd; @@ -3679,16 +3730,24 @@ x_scroll_bar_create (struct window *w, int top, int left, int width, int height) bar->start = 0; bar->end = 0; bar->dragging = 0; + bar->horizontal = horizontal; /* Requires geometry to be set before call to create the real window */ - hwnd = my_create_scrollbar (f, bar); + if (horizontal) + hwnd = my_create_hscrollbar (f, bar); + else + hwnd = my_create_vscrollbar (f, bar); si.cbSize = sizeof (si); si.fMask = SIF_ALL; si.nMin = 0; - si.nMax = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height) - + VERTICAL_SCROLL_BAR_MIN_HANDLE; + if (horizontal) + si.nMax = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, width) + + HORIZONTAL_SCROLL_BAR_MIN_HANDLE; + else + si.nMax = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height) + + VERTICAL_SCROLL_BAR_MIN_HANDLE; si.nPage = si.nMax; si.nPos = 0; @@ -3724,15 +3783,18 @@ x_scroll_bar_remove (struct scroll_bar *bar) my_destroy_window (f, SCROLL_BAR_W32_WINDOW (bar)); /* Dissociate this scroll bar from its window. */ - wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil); + if (bar->horizontal) + wset_horizontal_scroll_bar (XWINDOW (bar->window), Qnil); + else + wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil); unblock_input (); } -/* Set the handle of the vertical scroll bar for WINDOW to indicate - that we are displaying PORTION characters out of a total of WHOLE - characters, starting at POSITION. If WINDOW has no scroll bar, - create one. */ +/* Set the handle of the vertical scroll bar for WINDOW to indicate that + we are displaying PORTION characters out of a total of WHOLE + characters, starting at POSITION. If WINDOW has no vertical scroll + bar, create one. */ static void w32_set_vertical_scroll_bar (struct window *w, int portion, int whole, int position) @@ -3765,7 +3827,7 @@ w32_set_vertical_scroll_bar (struct window *w, } unblock_input (); - bar = x_scroll_bar_create (w, top, left, width, height); + bar = x_scroll_bar_create (w, left, top, width, height, 0); } else { @@ -3829,6 +3891,106 @@ w32_set_vertical_scroll_bar (struct window *w, wset_vertical_scroll_bar (w, barobj); } +/* Set the handle of the horizontal scroll bar for WINDOW to indicate + that we are displaying PORTION characters out of a total of WHOLE + characters, starting at POSITION. If WINDOW has no horizontal scroll + bar, create one. */ +static void +w32_set_horizontal_scroll_bar (struct window *w, + int portion, int whole, int position) +{ + struct frame *f = XFRAME (w->frame); + Lisp_Object barobj; + struct scroll_bar *bar; + int top, height, left, width; + int window_x, window_width; + int clear_left = WINDOW_LEFT_EDGE_X (w); + int clear_width = WINDOW_PIXEL_WIDTH (w) - WINDOW_RIGHT_DIVIDER_WIDTH (w); + + /* Get window dimensions. */ + window_box (w, ANY_AREA, &window_x, 0, &window_width, 0); + left = window_x; + height = WINDOW_SCROLL_BAR_AREA_HEIGHT (w); + width = window_width; + top = WINDOW_SCROLL_BAR_AREA_Y (w); + + /* Does the scroll bar exist yet? */ + if (NILP (w->horizontal_scroll_bar)) + { + HDC hdc; + block_input (); + if (width > 0 && height > 0) + { + hdc = get_frame_dc (f); + w32_clear_area (f, hdc, clear_left, top, clear_width, height); + release_frame_dc (f, hdc); + } + unblock_input (); + + bar = x_scroll_bar_create (w, left, top, width, height, 1); + } + else + { + /* It may just need to be moved and resized. */ + HWND hwnd; + + bar = XSCROLL_BAR (w->horizontal_scroll_bar); + hwnd = SCROLL_BAR_W32_WINDOW (bar); + + /* If already correctly positioned, do nothing. */ + if (bar->left == left && bar->top == top + && bar->width == width && bar->height == height) + { + /* Redraw after clear_frame. */ + if (!my_show_window (f, hwnd, SW_NORMAL)) + InvalidateRect (hwnd, NULL, FALSE); + } + else + { + HDC hdc; + SCROLLINFO si; + + block_input (); + if (width && height) + { + hdc = get_frame_dc (f); + /* Since Windows scroll bars are smaller than the space reserved + for them on the frame, we have to clear "under" them. */ + w32_clear_area (f, hdc, clear_left, top, clear_width, height); + release_frame_dc (f, hdc); + } + /* Make sure scroll bar is "visible" before moving, to ensure the + area of the parent window now exposed will be refreshed. */ + my_show_window (f, hwnd, SW_HIDE); + MoveWindow (hwnd, left, top, width, max (height, 1), TRUE); + + /* +++ SetScrollInfo +++ */ + si.cbSize = sizeof (si); + si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; + si.nMin = 0; + si.nMax = whole; + si.nPage = min (portion, si.nMax) + 1; + si.nPos = min (position, si.nMax); + SetScrollInfo (hwnd, SB_CTL, &si, FALSE); + + my_show_window (f, hwnd, SW_NORMAL); + /* InvalidateRect (w, NULL, FALSE); */ + + /* Remember new settings. */ + bar->left = left; + bar->top = top; + bar->width = width; + bar->height = height; + + unblock_input (); + } + } + + w32_set_horizontal_scroll_bar_thumb (bar, portion, position, whole); + XSETVECTOR (barobj, bar); + wset_horizontal_scroll_bar (w, barobj); +} + /* The following three hooks are used when we're doing a thorough redisplay of the frame. We don't explicitly know which scroll bars @@ -3845,17 +4007,22 @@ w32_set_vertical_scroll_bar (struct window *w, static void w32_condemn_scroll_bars (struct frame *frame) { - /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */ - while (! NILP (FRAME_SCROLL_BARS (frame))) + if (!NILP (FRAME_SCROLL_BARS (frame))) { - Lisp_Object bar; - bar = FRAME_SCROLL_BARS (frame); - fset_scroll_bars (frame, XSCROLL_BAR (bar)->next); - XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame); - XSCROLL_BAR (bar)->prev = Qnil; - if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame))) - XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar; - fset_condemned_scroll_bars (frame, bar); + if (!NILP (FRAME_CONDEMNED_SCROLL_BARS (frame))) + { + /* Prepend scrollbars to already condemned ones. */ + Lisp_Object last = FRAME_SCROLL_BARS (frame); + + while (!NILP (XSCROLL_BAR (last)->next)) + last = XSCROLL_BAR (last)->next; + + XSCROLL_BAR (last)->next = FRAME_CONDEMNED_SCROLL_BARS (frame); + XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = last; + } + + fset_condemned_scroll_bars (frame, FRAME_SCROLL_BARS (frame)); + fset_scroll_bars (frame, Qnil); } } @@ -3864,47 +4031,84 @@ w32_condemn_scroll_bars (struct frame *frame) Note that WINDOW isn't necessarily condemned at all. */ static void -w32_redeem_scroll_bar (struct window *window) +w32_redeem_scroll_bar (struct window *w) { struct scroll_bar *bar; Lisp_Object barobj; struct frame *f; /* We can't redeem this window's scroll bar if it doesn't have one. */ - if (NILP (window->vertical_scroll_bar)) + if (NILP (w->vertical_scroll_bar) && NILP (w->horizontal_scroll_bar)) emacs_abort (); - bar = XSCROLL_BAR (window->vertical_scroll_bar); - - /* Unlink it from the condemned list. */ - f = XFRAME (WINDOW_FRAME (window)); - if (NILP (bar->prev)) + if (!NILP (w->vertical_scroll_bar) && WINDOW_HAS_VERTICAL_SCROLL_BAR (w)) { - /* If the prev pointer is nil, it must be the first in one of - the lists. */ - if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar)) - /* It's not condemned. Everything's fine. */ - return; - else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f), - window->vertical_scroll_bar)) - fset_condemned_scroll_bars (f, bar->next); + bar = XSCROLL_BAR (w->vertical_scroll_bar); + /* Unlink it from the condemned list. */ + f = XFRAME (WINDOW_FRAME (w)); + if (NILP (bar->prev)) + { + /* If the prev pointer is nil, it must be the first in one of + the lists. */ + if (EQ (FRAME_SCROLL_BARS (f), w->vertical_scroll_bar)) + /* It's not condemned. Everything's fine. */ + goto horizontal; + else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f), + w->vertical_scroll_bar)) + fset_condemned_scroll_bars (f, bar->next); + else + /* If its prev pointer is nil, it must be at the front of + one or the other! */ + emacs_abort (); + } else - /* If its prev pointer is nil, it must be at the front of - one or the other! */ - emacs_abort (); + XSCROLL_BAR (bar->prev)->next = bar->next; + + if (! NILP (bar->next)) + XSCROLL_BAR (bar->next)->prev = bar->prev; + + bar->next = FRAME_SCROLL_BARS (f); + bar->prev = Qnil; + XSETVECTOR (barobj, bar); + fset_scroll_bars (f, barobj); + if (! NILP (bar->next)) + XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar); } - else - XSCROLL_BAR (bar->prev)->next = bar->next; - if (! NILP (bar->next)) - XSCROLL_BAR (bar->next)->prev = bar->prev; + horizontal: + if (!NILP (w->horizontal_scroll_bar) && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w)) + { + bar = XSCROLL_BAR (w->horizontal_scroll_bar); + /* Unlink it from the condemned list. */ + f = XFRAME (WINDOW_FRAME (w)); + if (NILP (bar->prev)) + { + /* If the prev pointer is nil, it must be the first in one of + the lists. */ + if (EQ (FRAME_SCROLL_BARS (f), w->horizontal_scroll_bar)) + /* It's not condemned. Everything's fine. */ + return; + else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f), + w->horizontal_scroll_bar)) + fset_condemned_scroll_bars (f, bar->next); + else + /* If its prev pointer is nil, it must be at the front of + one or the other! */ + emacs_abort (); + } + else + XSCROLL_BAR (bar->prev)->next = bar->next; - bar->next = FRAME_SCROLL_BARS (f); - bar->prev = Qnil; - XSETVECTOR (barobj, bar); - fset_scroll_bars (f, barobj); - if (! NILP (bar->next)) - XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar); + if (! NILP (bar->next)) + XSCROLL_BAR (bar->next)->prev = bar->prev; + + bar->next = FRAME_SCROLL_BARS (f); + bar->prev = Qnil; + XSETVECTOR (barobj, bar); + fset_scroll_bars (f, barobj); + if (! NILP (bar->next)) + XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar); + } } /* Remove all scroll bars on FRAME that haven't been saved since the @@ -3935,8 +4139,9 @@ w32_judge_scroll_bars (struct frame *f) and they should get garbage-collected. */ } -/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind - is set to something other than NO_EVENT, it is enqueued. +/* Handle a mouse click on the vertical scroll bar BAR. If + *EMACS_EVENT's kind is set to something other than NO_EVENT, it is + enqueued. This may be called from a signal handler, so we have to ignore GC mark bits. */ @@ -4043,9 +4248,120 @@ w32_scroll_bar_handle_click (struct scroll_bar *bar, W32Msg *msg, } } -/* Return information to the user about the current position of the mouse - on the scroll bar. */ +/* Handle a mouse click on the horizontal scroll bar BAR. If + *EMACS_EVENT's kind is set to something other than NO_EVENT, it is + enqueued. + + This may be called from a signal handler, so we have to ignore GC + mark bits. */ +static int +w32_horizontal_scroll_bar_handle_click (struct scroll_bar *bar, W32Msg *msg, + struct input_event *emacs_event) +{ + if (! WINDOWP (bar->window)) + emacs_abort (); + + emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT; + emacs_event->code = 0; + /* not really meaningful to distinguish left/right */ + emacs_event->modifiers = msg->dwModifiers; + emacs_event->frame_or_window = bar->window; + emacs_event->arg = Qnil; + emacs_event->timestamp = msg->msg.time; + + { + int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width); + int x; + int dragging = bar->dragging; + SCROLLINFO si; + + si.cbSize = sizeof (si); + si.fMask = SIF_POS; + + GetScrollInfo ((HWND) msg->msg.lParam, SB_CTL, &si); + x = si.nPos; + + bar->dragging = 0; + FRAME_DISPLAY_INFO (f)->last_mouse_scroll_bar_pos = msg->msg.wParam; + + switch (LOWORD (msg->msg.wParam)) + { + case SB_LINELEFT: + emacs_event->part = scroll_bar_left_arrow; + break; + case SB_LINERIGHT: + emacs_event->part = scroll_bar_right_arrow; + break; + case SB_PAGELEFT: + emacs_event->part = scroll_bar_before_handle; + break; + case SB_PAGERIGHT: + emacs_event->part = scroll_bar_after_handle; + break; + case SB_LEFT: + emacs_event->part = scroll_bar_horizontal_handle; + x = 0; + break; + case SB_RIGHT: + emacs_event->part = scroll_bar_horizontal_handle; + x = left_range; + break; + case SB_THUMBTRACK: + case SB_THUMBPOSITION: + if (HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width) <= 0xffff) + x = HIWORD (msg->msg.wParam); + bar->dragging = 1; + emacs_event->part = scroll_bar_horizontal_handle; + + /* "Silently" update current position. */ + { + SCROLLINFO si; + + si.cbSize = sizeof (si); + si.fMask = SIF_POS; + si.nPos = min (x, XWINDOW (bar->window)->hscroll_whole - 1); + /* Remember apparent position (we actually lag behind the real + position, so don't set that directly). */ + last_scroll_bar_drag_pos = x; + + SetScrollInfo (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, &si, FALSE); + } + break; + case SB_ENDSCROLL: + /* If this is the end of a drag sequence, then reset the scroll + handle size to normal and do a final redraw. Otherwise do + nothing. */ + if (dragging) + { + SCROLLINFO si; + int start = bar->start; + int end = bar->end; + + si.cbSize = sizeof (si); +/** si.fMask = SIF_PAGE | SIF_POS; **/ + si.fMask = SIF_POS; +/** si.nPage = end - start + HORIZONTAL_SCROLL_BAR_MIN_HANDLE; **/ + si.nPos = min (last_scroll_bar_drag_pos, + XWINDOW (bar->window)->hscroll_whole - 1); +/** si.nPos = last_scroll_bar_drag_pos; **/ + SetScrollInfo (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, &si, TRUE); + } + /* fall through */ + default: + emacs_event->kind = NO_EVENT; + return FALSE; + } + + XSETINT (emacs_event->x, x); + XSETINT (emacs_event->y, left_range); + + return TRUE; + } +} + +/* Return information to the user about the current position of the mouse + on the vertical scroll bar. */ static void x_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window, enum scroll_bar_part *part, @@ -4100,6 +4416,62 @@ x_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window, unblock_input (); } +/* Return information to the user about the current position of the mouse + on the horizontal scroll bar. */ +static void +x_horizontal_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window, + enum scroll_bar_part *part, + Lisp_Object *x, Lisp_Object *y, + unsigned long *time) +{ + struct w32_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp); + struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar; + Window w = SCROLL_BAR_W32_WINDOW (bar); + struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); + int pos; + int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width); + SCROLLINFO si; + + block_input (); + + *fp = f; + *bar_window = bar->window; + + si.cbSize = sizeof (si); + si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE; + + GetScrollInfo (w, SB_CTL, &si); + pos = si.nPos; + left_range = si.nMax - si.nPage + 1; + + switch (LOWORD (dpyinfo->last_mouse_scroll_bar_pos)) + { + case SB_THUMBPOSITION: + case SB_THUMBTRACK: + *part = scroll_bar_handle; + if (HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width) <= 0xffff) + pos = HIWORD (dpyinfo->last_mouse_scroll_bar_pos); + break; + case SB_LINERIGHT: + *part = scroll_bar_handle; + pos++; + break; + default: + *part = scroll_bar_handle; + break; + } + + XSETINT (*y, pos); + XSETINT (*x, left_range); + + f->mouse_moved = 0; + dpyinfo->last_mouse_scroll_bar = NULL; + + *time = dpyinfo->last_mouse_movement_time; + + unblock_input (); +} + /* The screen has been cleared so we may have changed foreground or background colors, and the scroll bars may need to be redrawn. @@ -4114,7 +4486,8 @@ x_scroll_bar_clear (struct frame *f) /* We can have scroll bars even if this is 0, if we just turned off scroll bar mode. But in that case we should not clear them. */ - if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)) + if (FRAME_HAS_VERTICAL_SCROLL_BARS (f) + || FRAME_HAS_HORIZONTAL_SCROLL_BARS (f)) for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar); bar = XSCROLL_BAR (bar)->next) { @@ -4589,10 +4962,20 @@ w32_read_socket (struct terminal *terminal, construct_drag_n_drop (&inev, &msg, f); break; + case WM_HSCROLL: + { + struct scroll_bar *bar = + x_window_to_scroll_bar ((HWND)msg.msg.lParam, 1); + + if (bar) + w32_horizontal_scroll_bar_handle_click (bar, &msg, &inev); + break; + } + case WM_VSCROLL: { struct scroll_bar *bar = - x_window_to_scroll_bar ((HWND)msg.msg.lParam); + x_window_to_scroll_bar ((HWND)msg.msg.lParam, 0); if (bar) w32_scroll_bar_handle_click (bar, &msg, &inev); @@ -4787,10 +5170,6 @@ w32_read_socket (struct terminal *terminal, change_frame_size (f, text_width, text_height, 0, 1, 0, 1); SET_FRAME_GARBAGED (f); cancel_mouse_face (f); - /* Do we want to set these here ???? */ -/** FRAME_PIXEL_WIDTH (f) = width; **/ -/** FRAME_TEXT_WIDTH (f) = text_width; **/ -/** FRAME_PIXEL_HEIGHT (f) = height; **/ f->win_gravity = NorthWestGravity; } } @@ -5430,8 +5809,6 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset) FRAME_COLUMN_WIDTH (f) = unit = font->average_width; FRAME_LINE_HEIGHT (f) = font->height; - compute_fringe_widths (f, 1); - /* Compute number of scrollbar columns. */ unit = FRAME_COLUMN_WIDTH (f); if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0) @@ -5451,8 +5828,8 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset) doing it because it's done in Fx_show_tip, and it leads to problems because the tip frame has no widget. */ if (NILP (tip_frame) || XFRAME (tip_frame) != f) - x_set_window_size (f, 0, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), - FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 1); + adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), + FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3, 0); } /* X version sets font of input methods here also. */ @@ -5649,6 +6026,7 @@ w32fullscreen_hook (struct frame *f) HWND hwnd = FRAME_W32_WINDOW(f); DWORD dwStyle = GetWindowLong (hwnd, GWL_STYLE); RECT rect; + enum fullscreen_type prev_fsmode = FRAME_PREV_FSMODE (f); block_input(); f->want_fullscreen &= ~FULLSCREEN_WAIT; @@ -5670,7 +6048,14 @@ w32fullscreen_hook (struct frame *f) if (f->want_fullscreen == FULLSCREEN_NONE) ShowWindow (hwnd, SW_SHOWNORMAL); else if (f->want_fullscreen == FULLSCREEN_MAXIMIZED) - ShowWindow (hwnd, SW_MAXIMIZE); + { + if (prev_fsmode == FULLSCREEN_BOTH || prev_fsmode == FULLSCREEN_WIDTH + || prev_fsmode == FULLSCREEN_HEIGHT) + /* Make window normal since otherwise the subsequent + maximization might fail in some cases. */ + ShowWindow (hwnd, SW_SHOWNORMAL); + ShowWindow (hwnd, SW_MAXIMIZE); + } else if (f->want_fullscreen == FULLSCREEN_BOTH) { w32_fullscreen_rect (hwnd, f->want_fullscreen, @@ -5705,70 +6090,40 @@ void x_set_window_size (struct frame *f, int change_gravity, int width, int height, bool pixelwise) { int pixelwidth, pixelheight; + RECT rect; block_input (); - check_frame_size (f, &width, &height, pixelwise); - - compute_fringe_widths (f, 0); - - if (frame_resize_pixelwise) + if (pixelwise) { - if (pixelwise) - { - pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width); - pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height); - } - else - { - pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width); - pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height); - } + pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width); + pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height); } else { - /* If we don't resize frames pixelwise, round sizes to multiples - of character sizes here. Otherwise, when enforcing size hints - while processing WM_WINDOWPOSCHANGING in w32_wnd_proc, we might - clip our frame rectangle to a multiple of the frame's character - size and subsequently lose our mode line or scroll bar. - Bug#16923 could be one possible consequence of this. Carefully - reverse-engineer what WM_WINDOWPOSCHANGING does here since - otherwise we might make our frame too small, see Bug#17077. */ - int unit_width = FRAME_COLUMN_WIDTH (f); - int unit_height = FRAME_LINE_HEIGHT (f); - - pixelwidth = (((((pixelwise ? width : (width * FRAME_COLUMN_WIDTH (f))) - + FRAME_TOTAL_FRINGE_WIDTH (f)) - / unit_width) * unit_width) - + FRAME_SCROLL_BAR_AREA_WIDTH (f) - + 2 * FRAME_INTERNAL_BORDER_WIDTH (f)); - - pixelheight = ((((pixelwise ? height : (height * FRAME_LINE_HEIGHT (f))) - / unit_height) * unit_height) - + 2 * FRAME_INTERNAL_BORDER_WIDTH (f)); + pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width); + pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height); } f->win_gravity = NorthWestGravity; x_wm_set_size_hint (f, (long) 0, 0); - { - RECT rect; + f->want_fullscreen = FULLSCREEN_NONE; + w32fullscreen_hook (f); - rect.left = rect.top = 0; - rect.right = pixelwidth; - rect.bottom = pixelheight; + rect.left = rect.top = 0; + rect.right = pixelwidth; + rect.bottom = pixelheight; - AdjustWindowRect (&rect, f->output_data.w32->dwStyle, - FRAME_EXTERNAL_MENU_BAR (f)); + AdjustWindowRect (&rect, f->output_data.w32->dwStyle, + FRAME_EXTERNAL_MENU_BAR (f)); - my_set_window_pos (FRAME_W32_WINDOW (f), - NULL, - 0, 0, - rect.right - rect.left, - rect.bottom - rect.top, - SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); - } + my_set_window_pos (FRAME_W32_WINDOW (f), + NULL, + 0, 0, + rect.right - rect.left, + rect.bottom - rect.top, + SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); /* If w32_enable_frame_resize_hack is non-nil, immediately apply the new pixel sizes to the frame and its subwindows. @@ -5817,6 +6172,8 @@ x_set_window_size (struct frame *f, int change_gravity, int width, int height, b } unblock_input (); + + do_pending_window_change (0); } /* Mouse warping. */ @@ -6156,7 +6513,8 @@ x_wm_set_size_hint (struct frame *f, long flags, bool user_position) SetWindowLong (window, WND_FONTWIDTH_INDEX, FRAME_COLUMN_WIDTH (f)); SetWindowLong (window, WND_LINEHEIGHT_INDEX, FRAME_LINE_HEIGHT (f)); SetWindowLong (window, WND_BORDER_INDEX, FRAME_INTERNAL_BORDER_WIDTH (f)); - SetWindowLong (window, WND_SCROLLBAR_INDEX, FRAME_SCROLL_BAR_AREA_WIDTH (f)); + SetWindowLong (window, WND_VSCROLLBAR_INDEX, FRAME_SCROLL_BAR_AREA_WIDTH (f)); + SetWindowLong (window, WND_HSCROLLBAR_INDEX, FRAME_SCROLL_BAR_AREA_HEIGHT (f)); leave_crit (); } @@ -6243,6 +6601,7 @@ w32_initialize_display_info (Lisp_Object display_name) dpyinfo->smallest_font_height = 1; dpyinfo->smallest_char_width = 1; dpyinfo->vertical_scroll_bar_cursor = w32_load_cursor (IDC_ARROW); + dpyinfo->horizontal_scroll_bar_cursor = w32_load_cursor (IDC_ARROW); /* TODO: dpyinfo->gray */ reset_mouse_highlight (&dpyinfo->mouse_highlight); @@ -6363,6 +6722,7 @@ w32_create_terminal (struct w32_display_info *dpyinfo) terminal->menu_show_hook = w32_menu_show; terminal->popup_dialog_hook = w32_popup_dialog; terminal->set_vertical_scroll_bar_hook = w32_set_vertical_scroll_bar; + terminal->set_horizontal_scroll_bar_hook = w32_set_horizontal_scroll_bar; terminal->condemn_scroll_bars_hook = w32_condemn_scroll_bars; terminal->redeem_scroll_bar_hook = w32_redeem_scroll_bar; terminal->judge_scroll_bars_hook = w32_judge_scroll_bars; @@ -6595,13 +6955,16 @@ w32_initialize (void) #undef LOAD_PROC - /* Ensure scrollbar handle is at least 5 pixels. */ + /* Ensure scrollbar handles are at least 5 pixels. */ vertical_scroll_bar_min_handle = 5; + horizontal_scroll_bar_min_handle = 5; /* For either kind of scroll bar, take account of the arrows; these effectively form the border of the main scroll bar range. */ vertical_scroll_bar_top_border = vertical_scroll_bar_bottom_border = GetSystemMetrics (SM_CYVSCROLL); + horizontal_scroll_bar_left_border = horizontal_scroll_bar_right_border + = GetSystemMetrics (SM_CYHSCROLL); } } diff --git a/src/w32term.h b/src/w32term.h index ae666925833..0fabe12819c 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -99,6 +99,9 @@ struct w32_display_info /* The cursor to use for vertical scroll bars. */ Cursor vertical_scroll_bar_cursor; + /* The cursor to use for horizontal scroll bars. */ + Cursor horizontal_scroll_bar_cursor; + /* Resource data base */ XrmDatabase xrdb; @@ -194,6 +197,9 @@ struct w32_display_info /* Time of last mouse movement. */ Time last_mouse_movement_time; + + /* Value returned by last call of ShowCursor. */ + int cursor_display_counter; }; /* This is a chain of structures for all the displays currently in use. */ @@ -231,6 +237,9 @@ extern void x_set_menu_bar_lines (struct frame *, Lisp_Object, Lisp_Object); extern void x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval); +extern void x_set_internal_border_width (struct frame *f, + Lisp_Object value, + Lisp_Object oldval); extern void x_activate_menubar (struct frame *); extern int x_bitmap_icon (struct frame *, Lisp_Object); extern void initialize_frame_menubar (struct frame *); @@ -451,6 +460,9 @@ struct scroll_bar { place where the user grabbed it. If the handle isn't currently being dragged, this is Qnil. */ int dragging; + + /* true if the scroll bar is horizontal. */ + bool horizontal; }; /* Turning a lisp vector value into a pointer to a struct scroll_bar. */ @@ -484,9 +496,9 @@ struct scroll_bar { /* Return the inside width of a vertical scroll bar, given the outside width. */ -#define VERTICAL_SCROLL_BAR_INSIDE_WIDTH(f,width) \ - ((width) \ - - VERTICAL_SCROLL_BAR_LEFT_BORDER \ +#define VERTICAL_SCROLL_BAR_INSIDE_WIDTH(f,width) \ + ((width) \ + - VERTICAL_SCROLL_BAR_LEFT_BORDER \ - VERTICAL_SCROLL_BAR_RIGHT_BORDER) /* Return the length of the rectangle within which the top of the @@ -496,14 +508,36 @@ struct scroll_bar { This is the real range of motion for the scroll bar, so when we're scaling buffer positions to scroll bar positions, we use this, not VERTICAL_SCROLL_BAR_INSIDE_HEIGHT. */ -#define VERTICAL_SCROLL_BAR_TOP_RANGE(f,height) \ +#define VERTICAL_SCROLL_BAR_TOP_RANGE(f,height) \ (VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, height) - VERTICAL_SCROLL_BAR_MIN_HANDLE) /* Return the inside height of vertical scroll bar, given the outside height. See VERTICAL_SCROLL_BAR_TOP_RANGE too. */ -#define VERTICAL_SCROLL_BAR_INSIDE_HEIGHT(f,height) \ +#define VERTICAL_SCROLL_BAR_INSIDE_HEIGHT(f,height) \ ((height) - VERTICAL_SCROLL_BAR_TOP_BORDER - VERTICAL_SCROLL_BAR_BOTTOM_BORDER) +/* Return the inside height of a horizontal scroll bar, given the + outside height. */ +#define HORIZONTAL_SCROLL_BAR_INSIDE_HEIGHT(f,height) \ + ((height) \ + - HORIZONTAL_SCROLL_BAR_TOP_BORDER \ + - HORIZONTAL_SCROLL_BAR_BOTTOM_BORDER) + +/* Return the length of the rectangle within which the left of the + handle must stay. This isn't equivalent to the inside width, + because the scroll bar handle has a minimum width. + + This is the real range of motion for the scroll bar, so when we're + scaling buffer positions to scroll bar positions, we use this, not + HORIZONTAL_SCROLL_BAR_INSIDE_WIDTH. */ +#define HORIZONTAL_SCROLL_BAR_LEFT_RANGE(f,width) \ + (HORIZONTAL_SCROLL_BAR_INSIDE_WIDTH (f, width) - HORIZONTAL_SCROLL_BAR_MIN_HANDLE) + +/* Return the inside width of horizontal scroll bar, given the outside + width. See HORIZONTAL_SCROLL_BAR_LEFT_RANGE too. */ +#define HORIZONTAL_SCROLL_BAR_INSIDE_WIDTH(f,width) \ + ((width) - HORIZONTAL_SCROLL_BAR_LEFT_BORDER - HORIZONTAL_SCROLL_BAR_RIGHT_BORDER) + /* Border widths for scroll bars. @@ -521,8 +555,14 @@ struct scroll_bar { #define VERTICAL_SCROLL_BAR_TOP_BORDER (vertical_scroll_bar_top_border) #define VERTICAL_SCROLL_BAR_BOTTOM_BORDER (vertical_scroll_bar_bottom_border) +#define HORIZONTAL_SCROLL_BAR_LEFT_BORDER (horizontal_scroll_bar_left_border) +#define HORIZONTAL_SCROLL_BAR_RIGHT_BORDER (horizontal_scroll_bar_right_border) +#define HORIZONTAL_SCROLL_BAR_TOP_BORDER (0) +#define HORIZONTAL_SCROLL_BAR_BOTTOM_BORDER (0) + /* Minimum lengths for scroll bar handles, in pixels. */ #define VERTICAL_SCROLL_BAR_MIN_HANDLE (vertical_scroll_bar_min_handle) +#define HORIZONTAL_SCROLL_BAR_MIN_HANDLE (horizontal_scroll_bar_min_handle) struct frame; /* from frame.h */ @@ -584,35 +624,38 @@ do { \ #define WM_EMACS_KILL (WM_EMACS_START + 0) #define WM_EMACS_CREATEWINDOW (WM_EMACS_START + 1) #define WM_EMACS_DONE (WM_EMACS_START + 2) -#define WM_EMACS_CREATESCROLLBAR (WM_EMACS_START + 3) -#define WM_EMACS_SHOWWINDOW (WM_EMACS_START + 4) -#define WM_EMACS_SETWINDOWPOS (WM_EMACS_START + 5) -#define WM_EMACS_DESTROYWINDOW (WM_EMACS_START + 6) -#define WM_EMACS_TRACKPOPUPMENU (WM_EMACS_START + 7) -#define WM_EMACS_SETFOCUS (WM_EMACS_START + 8) -#define WM_EMACS_SETFOREGROUND (WM_EMACS_START + 9) -#define WM_EMACS_SETLOCALE (WM_EMACS_START + 10) -#define WM_EMACS_SETKEYBOARDLAYOUT (WM_EMACS_START + 11) -#define WM_EMACS_REGISTER_HOT_KEY (WM_EMACS_START + 12) -#define WM_EMACS_UNREGISTER_HOT_KEY (WM_EMACS_START + 13) -#define WM_EMACS_TOGGLE_LOCK_KEY (WM_EMACS_START + 14) -#define WM_EMACS_TRACK_CARET (WM_EMACS_START + 15) -#define WM_EMACS_DESTROY_CARET (WM_EMACS_START + 16) -#define WM_EMACS_SHOW_CARET (WM_EMACS_START + 17) -#define WM_EMACS_HIDE_CARET (WM_EMACS_START + 18) -#define WM_EMACS_SETCURSOR (WM_EMACS_START + 19) -#define WM_EMACS_PAINT (WM_EMACS_START + 20) -#define WM_EMACS_BRINGTOTOP (WM_EMACS_START + 21) -#define WM_EMACS_INPUT_READY (WM_EMACS_START + 22) -#define WM_EMACS_FILENOTIFY (WM_EMACS_START + 23) -#define WM_EMACS_END (WM_EMACS_START + 24) +#define WM_EMACS_CREATEVSCROLLBAR (WM_EMACS_START + 3) +#define WM_EMACS_CREATEHSCROLLBAR (WM_EMACS_START + 4) +#define WM_EMACS_SHOWWINDOW (WM_EMACS_START + 5) +#define WM_EMACS_SETWINDOWPOS (WM_EMACS_START + 6) +#define WM_EMACS_DESTROYWINDOW (WM_EMACS_START + 7) +#define WM_EMACS_TRACKPOPUPMENU (WM_EMACS_START + 8) +#define WM_EMACS_SETFOCUS (WM_EMACS_START + 9) +#define WM_EMACS_SETFOREGROUND (WM_EMACS_START + 10) +#define WM_EMACS_SETLOCALE (WM_EMACS_START + 11) +#define WM_EMACS_SETKEYBOARDLAYOUT (WM_EMACS_START + 12) +#define WM_EMACS_REGISTER_HOT_KEY (WM_EMACS_START + 13) +#define WM_EMACS_UNREGISTER_HOT_KEY (WM_EMACS_START + 14) +#define WM_EMACS_TOGGLE_LOCK_KEY (WM_EMACS_START + 15) +#define WM_EMACS_TRACK_CARET (WM_EMACS_START + 16) +#define WM_EMACS_DESTROY_CARET (WM_EMACS_START + 17) +#define WM_EMACS_SHOW_CARET (WM_EMACS_START + 18) +#define WM_EMACS_HIDE_CARET (WM_EMACS_START + 19) +#define WM_EMACS_SETCURSOR (WM_EMACS_START + 20) +#define WM_EMACS_SHOWCURSOR (WM_EMACS_START + 21) +#define WM_EMACS_PAINT (WM_EMACS_START + 22) +#define WM_EMACS_BRINGTOTOP (WM_EMACS_START + 23) +#define WM_EMACS_INPUT_READY (WM_EMACS_START + 24) +#define WM_EMACS_FILENOTIFY (WM_EMACS_START + 25) +#define WM_EMACS_END (WM_EMACS_START + 26) #define WND_FONTWIDTH_INDEX (0) #define WND_LINEHEIGHT_INDEX (4) #define WND_BORDER_INDEX (8) -#define WND_SCROLLBAR_INDEX (12) -#define WND_BACKGROUND_INDEX (16) -#define WND_LAST_INDEX (20) +#define WND_VSCROLLBAR_INDEX (12) +#define WND_HSCROLLBAR_INDEX (16) +#define WND_BACKGROUND_INDEX (20) +#define WND_LAST_INDEX (24) #define WND_EXTRA_BYTES (WND_LAST_INDEX) diff --git a/src/widget.c b/src/widget.c index bd0fe826e68..45118a88730 100644 --- a/src/widget.c +++ b/src/widget.c @@ -404,7 +404,6 @@ set_frame_size (EmacsFrame ew) } #endif /* 0 */ { - struct frame *f = ew->emacs_frame.frame; Dimension pixel_width, pixel_height; /* Take into account the size of the scrollbar. Always use the @@ -413,8 +412,6 @@ set_frame_size (EmacsFrame ew) frame's character width which is bad for vertically split windows. */ - compute_fringe_widths (f, 0); - #if 0 /* This can run Lisp code, and it is dangerous to give out the frame to Lisp code before it officially exists. This is handled in Fx_create_frame so not needed here. */ @@ -472,10 +469,6 @@ update_wm_hints (EmacsFrame ew) /* This happens when the frame is just created. */ if (! wmshell) return; -#if 0 - check_frame_size (ew->emacs_frame.frame, &min_cols, &min_rows, 0); -#endif - pixel_to_char_size (ew, ew->core.width, ew->core.height, &char_width, &char_height); char_to_pixel_size (ew, char_width, char_height, @@ -690,6 +683,15 @@ EmacsFrameResize (Widget widget) if (true || frame_resize_pixelwise) { int width, height; +/** int width = (ew->core.width **/ +/** - FRAME_SCROLL_BAR_AREA_WIDTH (f) **/ +/** - FRAME_TOTAL_FRINGE_WIDTH (f) **/ +/** - 2 * FRAME_INTERNAL_BORDER_WIDTH (f)); **/ + +/** int height = (ew->core.height **/ +/** - FRAME_TOOLBAR_HEIGHT (f) **/ +/** - FRAME_SCROLL_BAR_AREA_HEIGHT (f) **/ +/** - 2 * FRAME_INTERNAL_BORDER_WIDTH (f)); **/ pixel_to_text_size (ew, ew->core.width, ew->core.height, &width, &height); change_frame_size (f, width, height, 0, 1, 0, 1); @@ -829,7 +831,8 @@ EmacsFrameSetCharSize (Widget widget, int columns, int rows) EmacsFrame ew = (EmacsFrame) widget; struct frame *f = ew->emacs_frame.frame; - x_set_window_size (f, 0, columns, rows, 0); + if (!frame_inhibit_resize (f, 0) && !frame_inhibit_resize (f, 1)) + x_set_window_size (f, 0, columns, rows, 0); } diff --git a/src/window.c b/src/window.c index 6afe7454149..ae28b714720 100644 --- a/src/window.c +++ b/src/window.c @@ -52,6 +52,7 @@ static Lisp_Object Qrecord_window_buffer; static Lisp_Object Qwindow_deletable_p, Qdelete_window, Qdisplay_buffer; static Lisp_Object Qreplace_buffer_in_windows, Qget_mru_window; static Lisp_Object Qwindow_resize_root_window, Qwindow_resize_root_window_vertically; +static Lisp_Object Qwindow_sanitize_window_sizes; static Lisp_Object Qwindow_pixel_to_total; static Lisp_Object Qscroll_up, Qscroll_down, Qscroll_command; static Lisp_Object Qsafe, Qabove, Qbelow, Qwindow_size, Qclone_of; @@ -87,7 +88,7 @@ static struct window *set_window_fringes (struct window *, Lisp_Object, static struct window *set_window_margins (struct window *, Lisp_Object, Lisp_Object); static struct window *set_window_scroll_bars (struct window *, Lisp_Object, - Lisp_Object, Lisp_Object); + Lisp_Object, Lisp_Object, Lisp_Object); static void apply_window_adjustment (struct window *); /* This is the window in which the terminal's cursor should @@ -143,66 +144,85 @@ wset_combination_limit (struct window *w, Lisp_Object val) { w->combination_limit = val; } + static void wset_dedicated (struct window *w, Lisp_Object val) { w->dedicated = val; } + static void wset_display_table (struct window *w, Lisp_Object val) { w->display_table = val; } + static void wset_new_normal (struct window *w, Lisp_Object val) { w->new_normal = val; } + static void wset_new_total (struct window *w, Lisp_Object val) { w->new_total = val; } + static void wset_normal_cols (struct window *w, Lisp_Object val) { w->normal_cols = val; } + static void wset_normal_lines (struct window *w, Lisp_Object val) { w->normal_lines = val; } + static void wset_parent (struct window *w, Lisp_Object val) { w->parent = val; } + static void wset_pointm (struct window *w, Lisp_Object val) { w->pointm = val; } + +static void +wset_old_pointm (struct window *w, Lisp_Object val) +{ + w->old_pointm = val; +} + static void wset_start (struct window *w, Lisp_Object val) { w->start = val; } + static void wset_temslot (struct window *w, Lisp_Object val) { w->temslot = val; } + static void wset_vertical_scroll_bar_type (struct window *w, Lisp_Object val) { w->vertical_scroll_bar_type = val; } + static void wset_window_parameters (struct window *w, Lisp_Object val) { w->window_parameters = val; } + static void wset_combination (struct window *w, bool horflag, Lisp_Object val) { @@ -871,6 +891,9 @@ window_body_height (struct window *w, bool pixelwise) { int height = (w->pixel_height - WINDOW_HEADER_LINE_HEIGHT (w) + - (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w) + ? WINDOW_SCROLL_BAR_AREA_HEIGHT (w) + : 0) - WINDOW_MODE_LINE_HEIGHT (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w)); @@ -991,6 +1014,15 @@ WINDOW must be a live window and defaults to the selected one. */) return (make_number (WINDOW_SCROLL_BAR_AREA_WIDTH (decode_live_window (window)))); } +DEFUN ("window-scroll-bar-height", Fwindow_scroll_bar_height, + Swindow_scroll_bar_height, 0, 1, 0, + doc: /* Return the height in pixels of WINDOW's horizontal scrollbar. +WINDOW must be a live window and defaults to the selected one. */) + (Lisp_Object window) +{ + return (make_number (WINDOW_SCROLL_BAR_AREA_HEIGHT (decode_live_window (window)))); +} + DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0, doc: /* Return the number of columns by which WINDOW is scrolled from left margin. WINDOW must be a live window and defaults to the selected one. */) @@ -1018,6 +1050,8 @@ set_window_hscroll (struct window *w, EMACS_INT hscroll) XBUFFER (w->contents)->prevent_redisplay_optimizations_p = 1; w->hscroll = new_hscroll; + w->suspend_auto_hscroll = 1; + return make_number (new_hscroll); } @@ -1167,12 +1201,16 @@ display margins, fringes, header line, and/or mode line. */) return list4i ((WINDOW_BOX_LEFT_EDGE_COL (w) + WINDOW_LEFT_MARGIN_COLS (w) - + WINDOW_LEFT_FRINGE_COLS (w)), + + ((WINDOW_LEFT_FRINGE_WIDTH (w) + + WINDOW_FRAME_COLUMN_WIDTH (w) - 1) + / WINDOW_FRAME_COLUMN_WIDTH (w))), (WINDOW_TOP_EDGE_LINE (w) + WINDOW_HEADER_LINE_LINES (w)), (WINDOW_BOX_RIGHT_EDGE_COL (w) - WINDOW_RIGHT_MARGIN_COLS (w) - - WINDOW_RIGHT_FRINGE_COLS (w)), + - ((WINDOW_RIGHT_FRINGE_WIDTH (w) + + WINDOW_FRAME_COLUMN_WIDTH (w) - 1) + / WINDOW_FRAME_COLUMN_WIDTH (w))), (WINDOW_BOTTOM_EDGE_LINE (w) - WINDOW_MODE_LINE_LINES (w))); } @@ -1286,6 +1324,17 @@ coordinates_in_window (register struct window *w, int x, int y) && x >= right_x - WINDOW_RIGHT_DIVIDER_WIDTH (w) && x <= right_x) return ON_RIGHT_DIVIDER; + /* On the horizontal scroll bar? (Including the empty space at its + right!) */ + else if ((WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w) + && y >= (bottom_y + - WINDOW_SCROLL_BAR_AREA_HEIGHT (w) + - CURRENT_MODE_LINE_HEIGHT (w) + - WINDOW_BOTTOM_DIVIDER_WIDTH (w)) + && y <= (bottom_y + - CURRENT_MODE_LINE_HEIGHT (w) + - WINDOW_BOTTOM_DIVIDER_WIDTH (w)))) + return ON_HORIZONTAL_SCROLL_BAR; /* On the mode or header line? */ else if ((WINDOW_WANTS_MODELINE_P (w) && y >= (bottom_y @@ -1329,7 +1378,7 @@ coordinates_in_window (register struct window *w, int x, int y) /* Outside any interesting column? */ if (x < left_x || x > right_x) - return ON_SCROLL_BAR; + return ON_VERTICAL_SCROLL_BAR; lmargin_width = window_box_width (w, LEFT_MARGIN_AREA); rmargin_width = window_box_width (w, RIGHT_MARGIN_AREA); @@ -1493,10 +1542,13 @@ If they are in the windows's left or right marginal areas, `left-margin'\n\ case ON_RIGHT_MARGIN: return Qright_margin; - case ON_SCROLL_BAR: + case ON_VERTICAL_SCROLL_BAR: /* Historically we are supposed to return nil in this case. */ return Qnil; + case ON_HORIZONTAL_SCROLL_BAR: + return Qnil; + case ON_RIGHT_DIVIDER: return Qright_divider; @@ -1637,6 +1689,14 @@ correct to return the top-level value of `point', outside of any return Fmarker_position (w->pointm); } +DEFUN ("window-old-point", Fwindow_old_point, Swindow_old_point, 0, 1, 0, + doc: /* Return old value of point in WINDOW. +WINDOW must be a live window and defaults to the selected one. */) + (Lisp_Object window) +{ + return Fmarker_position (decode_live_window (window)->old_pointm); +} + DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0, doc: /* Return position at which display currently starts in WINDOW. WINDOW must be a live window and defaults to the selected one. @@ -2915,6 +2975,7 @@ selected frame and no others. */) return Qnil; } + static Lisp_Object resize_root_window (Lisp_Object window, Lisp_Object delta, Lisp_Object horizontal, Lisp_Object ignore, Lisp_Object pixelwise) { @@ -2922,10 +2983,17 @@ resize_root_window (Lisp_Object window, Lisp_Object delta, Lisp_Object horizonta } +Lisp_Object +sanitize_window_sizes (Lisp_Object frame, Lisp_Object horizontal) +{ + return call2 (Qwindow_sanitize_window_sizes, frame, horizontal); +} + + static Lisp_Object window_pixel_to_total (Lisp_Object frame, Lisp_Object horizontal) { - return call2(Qwindow_pixel_to_total, frame, horizontal); + return call2 (Qwindow_pixel_to_total, frame, horizontal); } @@ -3204,89 +3272,6 @@ replace_buffer_in_windows_safely (Lisp_Object buffer) window_loop (REPLACE_BUFFER_IN_WINDOWS_SAFELY, buffer, 1, frame); } } - -/* If *HEIGHT or *WIDTH are too small a size for FRAME, set them to the - minimum allowable size. PIXELWISE means interpret these as pixel - sizes. */ - -void -check_frame_size (struct frame *frame, int *width, int *height, bool pixelwise) -{ - /* For height, we have to see: - how many windows the frame has at minimum (one or two), - and whether it has a menu bar or other special stuff at the top. */ - if (pixelwise) - { - int min_height = MIN_SAFE_WINDOW_HEIGHT * FRAME_LINE_HEIGHT (frame); - int min_width = MIN_SAFE_WINDOW_WIDTH * FRAME_COLUMN_WIDTH (frame); - - if (!FRAME_MINIBUF_ONLY_P (frame) && FRAME_HAS_MINIBUF_P (frame)) - min_height = 2 * min_height; - - min_height += FRAME_TOP_MARGIN_HEIGHT (frame); - min_height += FRAME_INTERNAL_BORDER_WIDTH (frame); - - if (*height < min_height) - *height = min_height; - if (*width < min_width) - *width = min_width; - } - else - { - int min_height - = ((FRAME_MINIBUF_ONLY_P (frame) || ! FRAME_HAS_MINIBUF_P (frame)) - ? MIN_SAFE_WINDOW_HEIGHT - : 2 * MIN_SAFE_WINDOW_HEIGHT); - - if (FRAME_TOP_MARGIN (frame) > 0) - min_height += FRAME_TOP_MARGIN (frame); - - if (*height < min_height) - *height = min_height; - if (*width < MIN_SAFE_WINDOW_WIDTH) - *width = MIN_SAFE_WINDOW_WIDTH; - } -} - -/* Adjust the margins of window W if text area is too small. - Return 1 if window width is ok after adjustment; 0 if window - is still too narrow. */ - -static int -adjust_window_margins (struct window *w) -{ - int box_width = (WINDOW_PIXEL_WIDTH (w) - - WINDOW_FRINGES_WIDTH (w) - - WINDOW_SCROLL_BAR_AREA_WIDTH (w)); - int margin_width = WINDOW_MARGINS_WIDTH (w); - - if (box_width - margin_width >= MIN_SAFE_WINDOW_PIXEL_WIDTH (w)) - return 1; - - if (margin_width < 0 || box_width < MIN_SAFE_WINDOW_PIXEL_WIDTH (w)) - return 0; - else - /* Window's text area is too narrow, but reducing the window - margins will fix that. */ - { - int unit = WINDOW_FRAME_COLUMN_WIDTH (w); - - margin_width = box_width - MIN_SAFE_WINDOW_PIXEL_WIDTH (w); - - if (WINDOW_RIGHT_MARGIN_WIDTH (w) > 0) - { - if (WINDOW_LEFT_MARGIN_WIDTH (w) > 0) - w->left_margin_cols = w->right_margin_cols = - margin_width / (2 * unit); - else - w->right_margin_cols = margin_width / unit; - } - else - w->left_margin_cols = margin_width / unit; - - return 1; - } -} /* The following three routines are needed for running a window's configuration change hook. */ @@ -3320,7 +3305,7 @@ run_window_configuration_change_hook (struct frame *f) = Fdefault_value (Qwindow_configuration_change_hook); XSETFRAME (frame, f); - if (NILP (Vrun_hooks) || !NILP (inhibit_lisp_code)) + if (NILP (Vrun_hooks) || !(f->official)) return; /* Use the right buffer. Matters when running the local hooks. */ @@ -3415,17 +3400,21 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer, w->last_cursor_vpos = 0; if (!(keep_margins_p && samebuf)) - { /* If we're not actually changing the buffer, don't reset hscroll and - vscroll. This case happens for example when called from + { /* If we're not actually changing the buffer, don't reset hscroll + and vscroll. This case happens for example when called from change_frame_size_1, where we use a dummy call to - Fset_window_buffer on the frame's selected window (and no other) - just in order to run window-configuration-change-hook. - Resetting hscroll and vscroll here is problematic for things like - image-mode and doc-view-mode since it resets the image's position - whenever we resize the frame. */ - w->hscroll = w->min_hscroll = 0; + Fset_window_buffer on the frame's selected window (and no + other) just in order to run window-configuration-change-hook + (no longer true since change_frame_size_1 directly calls + run_window_configuration_change_hook). Resetting hscroll and + vscroll here is problematic for things like image-mode and + doc-view-mode since it resets the image's position whenever we + resize the frame. */ + w->hscroll = w->min_hscroll = w->hscroll_whole = 0; + w->suspend_auto_hscroll = 0; w->vscroll = 0; set_marker_both (w->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b)); + set_marker_both (w->old_pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b)); set_marker_restricted (w->start, make_number (b->last_window_start), buffer); @@ -3443,6 +3432,7 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer, Fset_buffer (buffer); XMARKER (w->pointm)->insertion_type = !NILP (Vwindow_point_insertion_type); + XMARKER (w->old_pointm)->insertion_type = !NILP (Vwindow_point_insertion_type); if (!keep_margins_p) { @@ -3451,7 +3441,9 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer, BVAR (b, right_fringe_width), BVAR (b, fringes_outside_margins)); set_window_scroll_bars (w, BVAR (b, scroll_bar_width), - BVAR (b, vertical_scroll_bar_type), Qnil); + BVAR (b, vertical_scroll_bar_type), + BVAR (b, scroll_bar_height), + BVAR (b, horizontal_scroll_bar_type)); set_window_margins (w, BVAR (b, left_margin_cols), BVAR (b, right_margin_cols)); apply_window_adjustment (w); @@ -3597,10 +3589,11 @@ temp_output_buffer_show (register Lisp_Object buf) Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window))); Vminibuf_scroll_window = window; w = XWINDOW (window); - w->hscroll = 0; - w->min_hscroll = 0; + w->hscroll = w->min_hscroll = w->hscroll_whole = 0; + w->suspend_auto_hscroll = 0; set_marker_restricted_both (w->start, buf, BEG, BEG); set_marker_restricted_both (w->pointm, buf, BEG, BEG); + set_marker_restricted_both (w->old_pointm, buf, BEG, BEG); /* Run temp-buffer-show-hook, with the chosen window selected and its buffer current. */ @@ -3652,6 +3645,7 @@ make_parent_window (Lisp_Object window, bool horflag) /* ...but now P becomes an internal window. */ wset_start (p, Qnil); wset_pointm (p, Qnil); + wset_old_pointm (p, Qnil); wset_buffer (p, Qnil); wset_combination (p, horflag, window); wset_combination_limit (p, Qnil); @@ -3675,7 +3669,9 @@ make_window (void) wset_new_pixel (w, make_number (0)); wset_start (w, Fmake_marker ()); wset_pointm (w, Fmake_marker ()); + wset_old_pointm (w, Fmake_marker ()); wset_vertical_scroll_bar_type (w, Qt); + wset_horizontal_scroll_bar_type (w, Qt); /* These Lisp fields are marked specially so they're not set to nil by allocate_window. */ wset_prev_buffers (w, Qnil); @@ -3692,8 +3688,8 @@ make_window (void) #endif w->sequence_number = ++sequence_number; w->scroll_bar_width = -1; + w->scroll_bar_height = -1; w->column_number_displayed = -1; - /* Reset window_list. */ Vwindow_list = Qnil; /* Return window. */ @@ -3943,11 +3939,8 @@ window_resize_apply (struct window *w, bool horflag) } } else - { - adjust_window_margins (w); - /* Bug#15957. */ - w->window_end_valid = 0; - } + /* Bug#15957. */ + w->window_end_valid = 0; } @@ -4107,6 +4100,7 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise) /* old_size is the old size of the frame's root window. */ int old_size = horflag ? r->total_cols : r->total_lines; int old_pixel_size = horflag ? r->pixel_width : r->pixel_height; + int old_pixel_top = r->pixel_top; /* new_size is the new size of the frame's root window. */ int new_size, new_pixel_size; int unit = horflag ? FRAME_COLUMN_WIDTH (f) : FRAME_LINE_HEIGHT (f); @@ -4121,7 +4115,7 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise) new_pixel_size = max (horflag ? size : (size - - FRAME_TOP_MARGIN_HEIGHT (f) +/** - FRAME_TOP_MARGIN_HEIGHT (f) **/ - ((FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f)) ? FRAME_LINE_HEIGHT (f) : 0)), @@ -4133,7 +4127,7 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise) new_size = max (horflag ? size : (size - - FRAME_TOP_MARGIN (f) +/** - FRAME_TOP_MARGIN (f) **/ - ((FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f)) ? 1 : 0)), @@ -4144,7 +4138,8 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise) r->top_line = FRAME_TOP_MARGIN (f); r->pixel_top = FRAME_TOP_MARGIN_HEIGHT (f); - if (new_pixel_size == old_pixel_size) + if (new_pixel_size == old_pixel_size + && r->pixel_top == old_pixel_top) ; else if (WINDOW_LEAF_P (r)) /* For a leaf root window just set the size. */ @@ -4186,6 +4181,7 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise) { window_resize_apply (r, horflag); window_pixel_to_total (r->frame, horflag ? Qt : Qnil); +#if 0 /* Let's try without safe sizes and/or killing other windows. */ } else { @@ -4198,7 +4194,6 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise) window_resize_apply (r, horflag); window_pixel_to_total (r->frame, horflag ? Qt : Qnil); } -#if 0 /* Let's try without killing other windows. */ else { /* We lost. Delete all windows but the frame's @@ -4402,7 +4397,9 @@ set correctly. See the code of `split-window' for how this is done. */) n->right_fringe_width = r->right_fringe_width; n->fringes_outside_margins = r->fringes_outside_margins; n->scroll_bar_width = r->scroll_bar_width; + n->scroll_bar_height = r->scroll_bar_height; wset_vertical_scroll_bar_type (n, r->vertical_scroll_bar_type); + wset_horizontal_scroll_bar_type (n, r->horizontal_scroll_bar_type); /* Directly assign orthogonal coordinates and sizes. */ if (horflag) @@ -4546,6 +4543,7 @@ Signal an error when WINDOW is the only window on its frame. */) { unshow_buffer (w); unchain_marker (XMARKER (w->pointm)); + unchain_marker (XMARKER (w->old_pointm)); unchain_marker (XMARKER (w->start)); wset_buffer (w, Qnil); } @@ -4807,6 +4805,7 @@ window_internal_height (struct window *w) return ht; } + /************************************************************************ Window Scrolling @@ -4857,6 +4856,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, int noerror) void *itdata = NULL; int window_total_lines; int frame_line_height = default_line_pixel_height (w); + bool adjust_old_pointm = !NILP (Fequal (Fwindow_point (window), + Fwindow_old_point (window))); SET_TEXT_POS_FROM_MARKER (start, w->start); /* Scrolling a minibuffer window via scroll bar when the echo area @@ -4985,6 +4986,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, int noerror) { ptrdiff_t start_pos = IT_CHARPOS (it); int dy = frame_line_height; + dy = max ((window_box_height (w) - next_screen_context_lines * dy), dy) * n; @@ -5228,6 +5230,13 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, int noerror) } } bidi_unshelve_cache (itdata, 0); + + if (adjust_old_pointm) + Fset_marker (w->old_pointm, + ((w == XWINDOW (selected_window)) + ? make_number (BUF_PT (XBUFFER (w->contents))) + : Fmarker_position (w->pointm)), + w->contents); } @@ -5252,6 +5261,8 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, int noerror) ptrdiff_t startpos = marker_position (w->start); ptrdiff_t startbyte = marker_byte_position (w->start); Lisp_Object original_pos = Qnil; + bool adjust_old_pointm = !NILP (Fequal (Fwindow_point (window), + Fwindow_old_point (window))); /* If scrolling screen-fulls, compute the number of lines to scroll from the window's height. */ @@ -5267,6 +5278,7 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, int noerror) struct position posit = *compute_motion (startpos, startbyte, 0, 0, 0, PT, ht, 0, -1, w->hscroll, 0, w); + window_scroll_preserve_vpos = posit.vpos; window_scroll_preserve_hpos = posit.hpos + w->hscroll; } @@ -5382,6 +5394,13 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, int noerror) else xsignal0 (Qend_of_buffer); } + + if (adjust_old_pointm) + Fset_marker (w->old_pointm, + ((w == XWINDOW (selected_window)) + ? make_number (BUF_PT (XBUFFER (w->contents))) + : Fmarker_position (w->pointm)), + w->contents); } @@ -5518,6 +5537,7 @@ specifies the window to scroll. This takes precedence over Fset_buffer (w->contents); SET_PT_BOTH (marker_position (w->pointm), marker_byte_position (w->pointm)); + SET_PT_BOTH (marker_position (w->old_pointm), marker_byte_position (w->old_pointm)); if (NILP (arg)) window_scroll (window, 1, 1, 1); @@ -5532,6 +5552,7 @@ specifies the window to scroll. This takes precedence over } set_marker_both (w->pointm, Qnil, PT, PT_BYTE); + set_marker_both (w->old_pointm, Qnil, PT, PT_BYTE); unbind_to (count, Qnil); return Qnil; @@ -5557,6 +5578,8 @@ by this function. This happens in an interactive call. */) if (!NILP (set_minimum)) w->min_hscroll = w->hscroll; + w->suspend_auto_hscroll = 1; + return result; } @@ -5580,6 +5603,8 @@ by this function. This happens in an interactive call. */) if (!NILP (set_minimum)) w->min_hscroll = w->hscroll; + w->suspend_auto_hscroll = 1; + return result; } @@ -5677,7 +5702,7 @@ and redisplay normally--don't erase and redraw the frame. */) if (buf != current_buffer) error ("`recenter'ing a window that does not display current-buffer."); - + /* If redisplay is suppressed due to an error, try again. */ buf->display_error_modiff = 0; @@ -5847,34 +5872,46 @@ and redisplay normally--don't erase and redraw the frame. */) } DEFUN ("window-text-width", Fwindow_text_width, Swindow_text_width, - 0, 1, 0, + 0, 2, 0, doc: /* Return the width in columns of the text display area of WINDOW. WINDOW must be a live window and defaults to the selected one. The returned width does not include dividers, scrollbars, margins, fringes, nor any partial-width columns at the right of the text -area. */) - (Lisp_Object window) +area. + +Optional argument PIXELWISE non-nil, means to return the width in +pixels. */) + (Lisp_Object window, Lisp_Object pixelwise) { struct window *w = decode_live_window (window); - return make_number (window_box_width (w, TEXT_AREA) - / FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w))); + if (NILP (pixelwise)) + return make_number (window_box_width (w, TEXT_AREA) + / FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w))); + else + return make_number (window_box_width (w, TEXT_AREA)); } DEFUN ("window-text-height", Fwindow_text_height, Swindow_text_height, - 0, 1, 0, + 0, 2, 0, doc: /* Return the height in lines of the text display area of WINDOW. WINDOW must be a live window and defaults to the selected one. The returned height does not include dividers, the mode line, any header -line, nor any partial-height lines at the bottom of the text area. */) - (Lisp_Object window) +line, nor any partial-height lines at the bottom of the text area. + +Optional argument PIXELWISE non-nil, means to return the height in +pixels. */) + (Lisp_Object window, Lisp_Object pixelwise) { struct window *w = decode_live_window (window); - return make_number (window_box_height (w) - / FRAME_LINE_HEIGHT (WINDOW_XFRAME (w))); + if (NILP (pixelwise)) + return make_number (window_box_height (w) + / FRAME_LINE_HEIGHT (WINDOW_XFRAME (w))); + else + return make_number (window_box_height (w)); } DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line, @@ -5984,17 +6021,18 @@ struct saved_window { struct vectorlike_header header; - Lisp_Object window, buffer, start, pointm; + Lisp_Object window, buffer, start, pointm, old_pointm; Lisp_Object pixel_left, pixel_top, pixel_height, pixel_width; Lisp_Object left_col, top_line, total_cols, total_lines; Lisp_Object normal_cols, normal_lines; - Lisp_Object hscroll, min_hscroll; + Lisp_Object hscroll, min_hscroll, hscroll_whole, suspend_auto_hscroll; Lisp_Object parent, prev; Lisp_Object start_at_line_beg; Lisp_Object display_table; Lisp_Object left_margin_cols, right_margin_cols; Lisp_Object left_fringe_width, right_fringe_width, fringes_outside_margins; Lisp_Object scroll_bar_width, vertical_scroll_bar_type, dedicated; + Lisp_Object scroll_bar_height, horizontal_scroll_bar_type; Lisp_Object combination_limit, window_parameters; }; @@ -6022,13 +6060,359 @@ DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_config return XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame; } -/* From Chong's unwind_create_frame_1. */ -static void -unwind_change_frame (Lisp_Object val) +DEFUN ("set-window-configuration", Fset_window_configuration, + Sset_window_configuration, 1, 1, 0, + doc: /* Set the configuration of windows and buffers as specified by CONFIGURATION. +CONFIGURATION must be a value previously returned +by `current-window-configuration' (which see). +If CONFIGURATION was made from a frame that is now deleted, +only frame-independent values can be restored. In this case, +the return value is nil. Otherwise the value is t. */) + (Lisp_Object configuration) { - inhibit_lisp_code = val; + register struct save_window_data *data; + struct Lisp_Vector *saved_windows; + Lisp_Object new_current_buffer; + Lisp_Object frame; + struct frame *f; + ptrdiff_t old_point = -1; + + CHECK_WINDOW_CONFIGURATION (configuration); + + data = (struct save_window_data *) XVECTOR (configuration); + saved_windows = XVECTOR (data->saved_windows); + + new_current_buffer = data->current_buffer; + if (!BUFFER_LIVE_P (XBUFFER (new_current_buffer))) + new_current_buffer = Qnil; + else + { + if (XBUFFER (new_current_buffer) == current_buffer) + /* The code further down "preserves point" by saving here PT in + old_point and then setting it later back into PT. When the + current-selected-window and the final-selected-window both show + the current buffer, this suffers from the problem that the + current PT is the window-point of the current-selected-window, + while the final PT is the point of the final-selected-window, so + this copy from one PT to the other would end up moving the + window-point of the final-selected-window to the window-point of + the current-selected-window. So we have to be careful which + point of the current-buffer we copy into old_point. */ + if (EQ (XWINDOW (data->current_window)->contents, new_current_buffer) + && WINDOWP (selected_window) + && EQ (XWINDOW (selected_window)->contents, new_current_buffer) + && !EQ (selected_window, data->current_window)) + old_point = marker_position (XWINDOW (data->current_window)->pointm); + else + old_point = PT; + else + /* BUF_PT (XBUFFER (new_current_buffer)) gives us the position of + point in new_current_buffer as of the last time this buffer was + used. This can be non-deterministic since it can be changed by + things like jit-lock by mere temporary selection of some random + window that happens to show this buffer. + So if possible we want this arbitrary choice of "which point" to + be the one from the to-be-selected-window so as to prevent this + window's cursor from being copied from another window. */ + if (EQ (XWINDOW (data->current_window)->contents, new_current_buffer) + /* If current_window = selected_window, its point is in BUF_PT. */ + && !EQ (selected_window, data->current_window)) + old_point = marker_position (XWINDOW (data->current_window)->pointm); + else + old_point = BUF_PT (XBUFFER (new_current_buffer)); + } + + frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame; + f = XFRAME (frame); + + /* If f is a dead frame, don't bother rebuilding its window tree. + However, there is other stuff we should still try to do below. */ + if (FRAME_LIVE_P (f)) + { + Lisp_Object window; + Lisp_Object dead_windows = Qnil; + register Lisp_Object tem, par, pers; + register struct window *w; + register struct saved_window *p; + struct window *root_window; + struct window **leaf_windows; + int n_leaf_windows; + ptrdiff_t k; + int i, n; + + /* Don't do this within the main loop below: This may call Lisp + code and is thus potentially unsafe while input is blocked. */ + for (k = 0; k < saved_windows->header.size; k++) + { + p = SAVED_WINDOW_N (saved_windows, k); + window = p->window; + w = XWINDOW (window); + if (BUFFERP (w->contents) + && !EQ (w->contents, p->buffer) + && BUFFER_LIVE_P (XBUFFER (p->buffer))) + /* If a window we restore gets another buffer, record the + window's old buffer. */ + call1 (Qrecord_window_buffer, window); + } + + /* Consider frame unofficial, temporarily. */ + f->official = false; + /* The mouse highlighting code could get screwed up + if it runs during this. */ + block_input (); + + /* "Swap out" point from the selected window's buffer + into the window itself. (Normally the pointm of the selected + window holds garbage.) We do this now, before + restoring the window contents, and prevent it from + being done later on when we select a new window. */ + if (! NILP (XWINDOW (selected_window)->contents)) + { + w = XWINDOW (selected_window); + set_marker_both (w->pointm, + w->contents, + BUF_PT (XBUFFER (w->contents)), + BUF_PT_BYTE (XBUFFER (w->contents))); + } + + fset_redisplay (f); + FRAME_WINDOW_SIZES_CHANGED (f) = 1; + + /* Problem: Freeing all matrices and later allocating them again + is a serious redisplay flickering problem. What we would + really like to do is to free only those matrices not reused + below. */ + root_window = XWINDOW (FRAME_ROOT_WINDOW (f)); + leaf_windows = alloca (count_windows (root_window) + * sizeof *leaf_windows); + n_leaf_windows = get_leaf_windows (root_window, leaf_windows, 0); + + /* Kludge Alert! + Mark all windows now on frame as "deleted". + Restoring the new configuration "undeletes" any that are in it. + + Save their current buffers in their height fields, since we may + need it later, if a buffer saved in the configuration is now + dead. */ + delete_all_child_windows (FRAME_ROOT_WINDOW (f)); + + for (k = 0; k < saved_windows->header.size; k++) + { + p = SAVED_WINDOW_N (saved_windows, k); + window = p->window; + w = XWINDOW (window); + wset_next (w, Qnil); + + if (!NILP (p->parent)) + wset_parent + (w, SAVED_WINDOW_N (saved_windows, XFASTINT (p->parent))->window); + else + wset_parent (w, Qnil); + + if (!NILP (p->prev)) + { + wset_prev + (w, SAVED_WINDOW_N (saved_windows, XFASTINT (p->prev))->window); + wset_next (XWINDOW (w->prev), p->window); + } + else + { + wset_prev (w, Qnil); + if (!NILP (w->parent)) + wset_combination (XWINDOW (w->parent), + (XINT (p->total_cols) + != XWINDOW (w->parent)->total_cols), + p->window); + } + + /* If we squirreled away the buffer, restore it now. */ + if (BUFFERP (w->combination_limit)) + wset_buffer (w, w->combination_limit); + w->pixel_left = XFASTINT (p->pixel_left); + w->pixel_top = XFASTINT (p->pixel_top); + w->pixel_width = XFASTINT (p->pixel_width); + w->pixel_height = XFASTINT (p->pixel_height); + w->left_col = XFASTINT (p->left_col); + w->top_line = XFASTINT (p->top_line); + w->total_cols = XFASTINT (p->total_cols); + w->total_lines = XFASTINT (p->total_lines); + wset_normal_cols (w, p->normal_cols); + wset_normal_lines (w, p->normal_lines); + w->hscroll = XFASTINT (p->hscroll); + w->suspend_auto_hscroll = !NILP (p->suspend_auto_hscroll); + w->min_hscroll = XFASTINT (p->min_hscroll); + w->hscroll_whole = XFASTINT (p->hscroll_whole); + wset_display_table (w, p->display_table); + w->left_margin_cols = XINT (p->left_margin_cols); + w->right_margin_cols = XINT (p->right_margin_cols); + w->left_fringe_width = XINT (p->left_fringe_width); + w->right_fringe_width = XINT (p->right_fringe_width); + w->fringes_outside_margins = !NILP (p->fringes_outside_margins); + w->scroll_bar_width = XINT (p->scroll_bar_width); + w->scroll_bar_height = XINT (p->scroll_bar_height); + wset_vertical_scroll_bar_type (w, p->vertical_scroll_bar_type); + wset_horizontal_scroll_bar_type (w, p->horizontal_scroll_bar_type); + wset_dedicated (w, p->dedicated); + wset_combination_limit (w, p->combination_limit); + /* Restore any window parameters that have been saved. + Parameters that have not been saved are left alone. */ + for (tem = p->window_parameters; CONSP (tem); tem = XCDR (tem)) + { + pers = XCAR (tem); + if (CONSP (pers)) + { + if (NILP (XCDR (pers))) + { + par = Fassq (XCAR (pers), w->window_parameters); + if (CONSP (par) && !NILP (XCDR (par))) + /* Reset a parameter to nil if and only if it + has a non-nil association. Don't make new + associations. */ + Fsetcdr (par, Qnil); + } + else + /* Always restore a non-nil value. */ + Fset_window_parameter (window, XCAR (pers), XCDR (pers)); + } + } + + if (BUFFERP (p->buffer) && BUFFER_LIVE_P (XBUFFER (p->buffer))) + /* If saved buffer is alive, install it. */ + { + wset_buffer (w, p->buffer); + w->start_at_line_beg = !NILP (p->start_at_line_beg); + set_marker_restricted (w->start, p->start, w->contents); + set_marker_restricted (w->pointm, p->pointm, w->contents); + set_marker_restricted (w->old_pointm, p->old_pointm, w->contents); + /* As documented in Fcurrent_window_configuration, don't + restore the location of point in the buffer which was + current when the window configuration was recorded. */ + if (!EQ (p->buffer, new_current_buffer) + && XBUFFER (p->buffer) == current_buffer) + Fgoto_char (w->pointm); + } + else if (BUFFERP (w->contents) && BUFFER_LIVE_P (XBUFFER (w->contents))) + /* Keep window's old buffer; make sure the markers are real. */ + { + /* Set window markers at start of visible range. */ + if (XMARKER (w->start)->buffer == 0) + set_marker_restricted_both (w->start, w->contents, 0, 0); + if (XMARKER (w->pointm)->buffer == 0) + set_marker_restricted_both + (w->pointm, w->contents, + BUF_PT (XBUFFER (w->contents)), + BUF_PT_BYTE (XBUFFER (w->contents))); + if (XMARKER (w->old_pointm)->buffer == 0) + set_marker_restricted_both + (w->old_pointm, w->contents, + BUF_PT (XBUFFER (w->contents)), + BUF_PT_BYTE (XBUFFER (w->contents))); + w->start_at_line_beg = 1; + } + else if (!NILP (w->start)) + /* Leaf window has no live buffer, get one. */ + { + /* Get the buffer via other_buffer_safely in order to + avoid showing an unimportant buffer and, if necessary, to + recreate *scratch* in the course (part of Juanma's bs-show + scenario from March 2011). */ + wset_buffer (w, other_buffer_safely (Fcurrent_buffer ())); + /* This will set the markers to beginning of visible + range. */ + set_marker_restricted_both (w->start, w->contents, 0, 0); + set_marker_restricted_both (w->pointm, w->contents, 0, 0); + set_marker_restricted_both (w->old_pointm, w->contents, 0, 0); + w->start_at_line_beg = 1; + if (!NILP (w->dedicated)) + /* Record this window as dead. */ + dead_windows = Fcons (window, dead_windows); + /* Make sure window is no more dedicated. */ + wset_dedicated (w, Qnil); + } + } + + fset_root_window (f, data->root_window); + /* Arrange *not* to restore point in the buffer that was + current when the window configuration was saved. */ + if (EQ (XWINDOW (data->current_window)->contents, new_current_buffer)) + set_marker_restricted (XWINDOW (data->current_window)->pointm, + make_number (old_point), + XWINDOW (data->current_window)->contents); + + /* In the following call to `select-window', prevent "swapping out + point" in the old selected window using the buffer that has + been restored into it. We already swapped out that point from + that window's old buffer. + + Do not record the buffer here. We do that in a separate call + to select_window below. See also Bug#16207. */ + select_window (data->current_window, Qt, 1); + BVAR (XBUFFER (XWINDOW (selected_window)->contents), + last_selected_window) + = selected_window; + + if (NILP (data->focus_frame) + || (FRAMEP (data->focus_frame) + && FRAME_LIVE_P (XFRAME (data->focus_frame)))) + Fredirect_frame_focus (frame, data->focus_frame); + + /* Now, free glyph matrices in windows that were not reused. */ + for (i = n = 0; i < n_leaf_windows; ++i) + { + if (NILP (leaf_windows[i]->contents)) + free_window_matrices (leaf_windows[i]); + else if (EQ (leaf_windows[i]->contents, new_current_buffer)) + ++n; + } + + /* Make frame official again and apply frame size changes if + needed. */ + f->official = true; + adjust_frame_size (f, -1, -1, 1, 0); + + adjust_frame_glyphs (f); + unblock_input (); + + /* Scan dead buffer windows. */ + for (; CONSP (dead_windows); dead_windows = XCDR (dead_windows)) + { + window = XCAR (dead_windows); + if (WINDOW_LIVE_P (window) && !EQ (window, FRAME_ROOT_WINDOW (f))) + delete_deletable_window (window); + } + + /* Record the selected window's buffer here. The window should + already be the selected one from the call above. */ + select_window (data->current_window, Qnil, 0); + + /* Fselect_window will have made f the selected frame, so we + reselect the proper frame here. Fhandle_switch_frame will change the + selected window too, but that doesn't make the call to + Fselect_window above totally superfluous; it still sets f's + selected window. */ + if (FRAME_LIVE_P (XFRAME (data->selected_frame))) + do_switch_frame (data->selected_frame, 0, 0, Qnil); + + run_window_configuration_change_hook (f); + } + + if (!NILP (new_current_buffer)) + { + Fset_buffer (new_current_buffer); + /* If the new current buffer doesn't appear in the selected + window, go to its old point (see bug#12208). */ + if (!EQ (XWINDOW (data->current_window)->contents, new_current_buffer)) + Fgoto_char (make_number (old_point)); + } + + Vminibuf_scroll_window = data->minibuf_scroll_window; + minibuf_selected_window = data->minibuf_selected_window; + + return (FRAME_LIVE_P (f) ? Qt : Qnil); } + +#if 0 DEFUN ("set-window-configuration", Fset_window_configuration, Sset_window_configuration, 1, 1, 0, doc: /* Set the configuration of windows and buffers as specified by CONFIGURATION. @@ -6137,18 +6521,18 @@ the return value is nil. Otherwise the value is t. */) call1 (Qrecord_window_buffer, window); } - /* Don't run lisp in the following segment since the frame is in a - completely inconsistent state. See Bug#16207. */ - record_unwind_protect (unwind_change_frame, inhibit_lisp_code); - inhibit_lisp_code = Qt; + /* Consider frame unofficial, temporarily. */ + f->official = false; /* The mouse highlighting code could get screwed up if it runs during this. */ block_input (); if (data->frame_text_width != previous_frame_text_width || data->frame_text_height != previous_frame_text_height) - change_frame_size (f, data->frame_text_width, - data->frame_text_height, 0, 0, 0, 1); + /* Make frame size fit the one in data, so window sizes restored + from data match those of the frame. */ + adjust_frame_size (f, data->frame_text_width, + data->frame_text_height, 5, 0); if (data->frame_menu_bar_lines != previous_frame_menu_bar_lines) { @@ -6245,7 +6629,9 @@ the return value is nil. Otherwise the value is t. */) wset_normal_cols (w, p->normal_cols); wset_normal_lines (w, p->normal_lines); w->hscroll = XFASTINT (p->hscroll); + w->suspend_auto_hscroll = !NILP (p->suspend_auto_hscroll); w->min_hscroll = XFASTINT (p->min_hscroll); + w->hscroll_whole = XFASTINT (p->hscroll_whole); wset_display_table (w, p->display_table); w->left_margin_cols = XINT (p->left_margin_cols); w->right_margin_cols = XINT (p->right_margin_cols); @@ -6253,7 +6639,9 @@ the return value is nil. Otherwise the value is t. */) w->right_fringe_width = XINT (p->right_fringe_width); w->fringes_outside_margins = !NILP (p->fringes_outside_margins); w->scroll_bar_width = XINT (p->scroll_bar_width); + w->scroll_bar_height = XINT (p->scroll_bar_height); wset_vertical_scroll_bar_type (w, p->vertical_scroll_bar_type); + wset_horizontal_scroll_bar_type (w, p->horizontal_scroll_bar_type); wset_dedicated (w, p->dedicated); wset_combination_limit (w, p->combination_limit); /* Restore any window parameters that have been saved. @@ -6284,16 +6672,15 @@ the return value is nil. Otherwise the value is t. */) wset_buffer (w, p->buffer); w->start_at_line_beg = !NILP (p->start_at_line_beg); set_marker_restricted (w->start, p->start, w->contents); - set_marker_restricted (w->pointm, p->pointm, - w->contents); - + set_marker_restricted (w->pointm, p->pointm, w->contents); + set_marker_restricted (w->old_pointm, p->old_pointm, w->contents); /* As documented in Fcurrent_window_configuration, don't restore the location of point in the buffer which was current when the window configuration was recorded. */ if (!EQ (p->buffer, new_current_buffer) && XBUFFER (p->buffer) == current_buffer) Fgoto_char (w->pointm); - } + } else if (BUFFERP (w->contents) && BUFFER_LIVE_P (XBUFFER (w->contents))) /* Keep window's old buffer; make sure the markers are real. */ { @@ -6305,20 +6692,26 @@ the return value is nil. Otherwise the value is t. */) (w->pointm, w->contents, BUF_PT (XBUFFER (w->contents)), BUF_PT_BYTE (XBUFFER (w->contents))); + if (XMARKER (w->old_pointm)->buffer == 0) + set_marker_restricted_both + (w->old_pointm, w->contents, + BUF_PT (XBUFFER (w->contents)), + BUF_PT_BYTE (XBUFFER (w->contents))); w->start_at_line_beg = 1; } else if (!NILP (w->start)) /* Leaf window has no live buffer, get one. */ { /* Get the buffer via other_buffer_safely in order to - avoid showing an unimportant buffer and, if necessary, to - recreate *scratch* in the course (part of Juanma's bs-show - scenario from March 2011). */ + avoid showing an unimportant buffer and, if necessary, to + recreate *scratch* in the course (part of Juanma's bs-show + scenario from March 2011). */ wset_buffer (w, other_buffer_safely (Fcurrent_buffer ())); /* This will set the markers to beginning of visible range. */ set_marker_restricted_both (w->start, w->contents, 0, 0); set_marker_restricted_both (w->pointm, w->contents, 0, 0); + set_marker_restricted_both (w->old_pointm, w->contents, 0, 0); w->start_at_line_beg = 1; if (!NILP (w->dedicated)) /* Record this window as dead. */ @@ -6356,8 +6749,8 @@ the return value is nil. Otherwise the value is t. */) /* Set the frame size to the value it had before this function. */ if (previous_frame_text_width != FRAME_TEXT_WIDTH (f) || previous_frame_text_height != FRAME_TEXT_HEIGHT (f)) - change_frame_size (f, previous_frame_text_width, - previous_frame_text_height, 0, 0, 0, 1); + adjust_frame_size (f, previous_frame_text_width, + previous_frame_text_height, 5, 0); if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f)) { @@ -6386,9 +6779,13 @@ the return value is nil. Otherwise the value is t. */) ++n; } + /* Make frame official again and apply frame size changes if + needed. */ + f->official = true; + adjust_frame_size (f, -1, -1, 1, 0); + adjust_frame_glyphs (f); unblock_input (); - unbind_to (count, Qnil); /* Scan dead buffer windows. */ for (; CONSP (dead_windows); dead_windows = XCDR (dead_windows)) @@ -6427,6 +6824,7 @@ the return value is nil. Otherwise the value is t. */) return (FRAME_LIVE_P (f) ? Qt : Qnil); } +#endif void restore_window_configuration (Lisp_Object configuration) @@ -6459,6 +6857,7 @@ delete_all_child_windows (Lisp_Object window) { unshow_buffer (w); unchain_marker (XMARKER (w->pointm)); + unchain_marker (XMARKER (w->old_pointm)); unchain_marker (XMARKER (w->start)); /* Since combination limit makes sense for an internal windows only, we use this slot to save the buffer for the sake of @@ -6565,7 +6964,9 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i) p->normal_cols = w->normal_cols; p->normal_lines = w->normal_lines; XSETFASTINT (p->hscroll, w->hscroll); + p->suspend_auto_hscroll = w->suspend_auto_hscroll ? Qt : Qnil; XSETFASTINT (p->min_hscroll, w->min_hscroll); + XSETFASTINT (p->hscroll_whole, w->hscroll_whole); p->display_table = w->display_table; p->left_margin_cols = make_number (w->left_margin_cols); p->right_margin_cols = make_number (w->right_margin_cols); @@ -6573,7 +6974,9 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i) p->right_fringe_width = make_number (w->right_fringe_width); p->fringes_outside_margins = w->fringes_outside_margins ? Qt : Qnil; p->scroll_bar_width = make_number (w->scroll_bar_width); + p->scroll_bar_height = make_number (w->scroll_bar_height); p->vertical_scroll_bar_type = w->vertical_scroll_bar_type; + p->horizontal_scroll_bar_type = w->horizontal_scroll_bar_type; p->dedicated = w->dedicated; p->combination_limit = w->combination_limit; p->window_parameters = Qnil; @@ -6635,9 +7038,13 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i) BUF_PT_BYTE (XBUFFER (w->contents))); else p->pointm = Fcopy_marker (w->pointm, Qnil); + p->old_pointm = Fcopy_marker (w->old_pointm, Qnil); XMARKER (p->pointm)->insertion_type = !NILP (buffer_local_value /* Don't signal error if void. */ (Qwindow_point_insertion_type, w->contents)); + XMARKER (p->old_pointm)->insertion_type + = !NILP (buffer_local_value /* Don't signal error if void. */ + (Qwindow_point_insertion_type, w->contents)); p->start = Fcopy_marker (w->start, Qnil); p->start_at_line_beg = w->start_at_line_beg ? Qt : Qnil; @@ -6645,6 +7052,7 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i) else { p->pointm = Qnil; + p->old_pointm = Qnil; p->start = Qnil; p->start_at_line_beg = Qnil; } @@ -6714,7 +7122,6 @@ static void apply_window_adjustment (struct window *w) { eassert (w); - adjust_window_margins (w); clear_glyph_matrix (w->current_matrix); w->window_end_valid = 0; windows_or_buffers_changed = 30; @@ -6732,8 +7139,8 @@ set_window_margins (struct window *w, Lisp_Object left_width, Lisp_Object right_width) { int left, right; + int unit = WINDOW_FRAME_COLUMN_WIDTH (w); - /* FIXME: what about margins that are too wide? */ left = (NILP (left_width) ? 0 : (CHECK_NATNUM (left_width), XINT (left_width))); right = (NILP (right_width) ? 0 @@ -6741,11 +7148,23 @@ set_window_margins (struct window *w, Lisp_Object left_width, if (w->left_margin_cols != left || w->right_margin_cols != right) { - w->left_margin_cols = left; - w->right_margin_cols = right; - return w; + /* Don't change anything if new margins won't fit. */ + if ((WINDOW_PIXEL_WIDTH (w) + - WINDOW_FRINGES_WIDTH (w) + - WINDOW_SCROLL_BAR_AREA_WIDTH (w) + - (left + right) * unit) + >= MIN_SAFE_WINDOW_PIXEL_WIDTH (w)) + { + w->left_margin_cols = left; + w->right_margin_cols = right; + + return w; + } + else + return NULL; } - return NULL; + else + return NULL; } DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins, @@ -6807,12 +7226,25 @@ set_window_fringes (struct window *w, Lisp_Object left_width, || w->right_fringe_width != right || w->fringes_outside_margins != outside)) { + if (left > 0 || right > 0) + { + /* Don't change anything if new fringes don't fit. */ + if ((WINDOW_PIXEL_WIDTH (w) + - WINDOW_MARGINS_WIDTH (w) + - WINDOW_SCROLL_BAR_AREA_WIDTH (w) + - max (left, 0) - max (right, 0)) + < MIN_SAFE_WINDOW_PIXEL_WIDTH (w)) + return NULL; + } + w->left_fringe_width = left; w->right_fringe_width = right; w->fringes_outside_margins = outside; + return w; } - return NULL; + else + return NULL; } DEFUN ("set-window-fringes", Fset_window_fringes, Sset_window_fringes, @@ -6863,9 +7295,12 @@ Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS). */) static struct window * set_window_scroll_bars (struct window *w, Lisp_Object width, - Lisp_Object vertical_type, Lisp_Object horizontal_type) + Lisp_Object vertical_type, Lisp_Object height, + Lisp_Object horizontal_type) { int iwidth = (NILP (width) ? -1 : (CHECK_NATNUM (width), XINT (width))); + int iheight = (NILP (height) ? -1 : (CHECK_NATNUM (height), XINT (height))); + bool changed = 0; if (iwidth == 0) vertical_type = Qnil; @@ -6879,32 +7314,69 @@ set_window_scroll_bars (struct window *w, Lisp_Object width, if (w->scroll_bar_width != iwidth || !EQ (w->vertical_scroll_bar_type, vertical_type)) { - w->scroll_bar_width = iwidth; - wset_vertical_scroll_bar_type (w, vertical_type); - return w; + /* Don't change anything if new scroll bar won't fit. */ + if ((WINDOW_PIXEL_WIDTH (w) + - WINDOW_MARGINS_WIDTH (w) + - WINDOW_FRINGES_WIDTH (w) + - max (iwidth, 0)) + >= MIN_SAFE_WINDOW_PIXEL_WIDTH (w)) + { + w->scroll_bar_width = iwidth; + wset_vertical_scroll_bar_type (w, vertical_type); + changed = 1; + } + } + + if (MINI_WINDOW_P (w) || iheight == 0) + horizontal_type = Qnil; + + if (!(NILP (horizontal_type) + || EQ (horizontal_type, Qbottom) + || EQ (horizontal_type, Qt))) + error ("Invalid type of horizontal scroll bar"); + + if (w->scroll_bar_height != iheight + || !EQ (w->horizontal_scroll_bar_type, horizontal_type)) + { + /* Don't change anything if new scroll bar won't fit. */ + if ((WINDOW_PIXEL_HEIGHT (w) + - WINDOW_HEADER_LINE_HEIGHT (w) + - WINDOW_MODE_LINE_HEIGHT (w) + - max (iheight, 0)) + >= MIN_SAFE_WINDOW_PIXEL_HEIGHT (w)) + { + w->scroll_bar_height = iheight; + wset_horizontal_scroll_bar_type (w, horizontal_type); + changed = 1; + } } - return NULL; + + return changed ? w : NULL; } DEFUN ("set-window-scroll-bars", Fset_window_scroll_bars, - Sset_window_scroll_bars, 2, 4, 0, + Sset_window_scroll_bars, 1, 5, 0, doc: /* Set width and type of scroll bars of window WINDOW. WINDOW must be a live window and defaults to the selected one. Second parameter WIDTH specifies the pixel width for the scroll bar. Third parameter VERTICAL-TYPE specifies the type of the vertical scroll -bar: left, right, or nil. -If WIDTH is nil, use the frame's scroll-bar width. -If VERTICAL-TYPE is t, use the frame's scroll-bar type. -Fourth parameter HORIZONTAL-TYPE is currently unused. +bar: left, right, or nil. If WIDTH is nil, use the frame's scroll-bar +width. If VERTICAL-TYPE is t, use the frame's scroll-bar type. + +Fourth parameter HEIGHT specifies the pixel height for the scroll bar. +Fifth parameter HORIZONTAL-TYPE specifies the type of the vertical +scroll bar: nil, bottom, or t. If HEIGHT is nil, use the frame's +scroll-bar height. If HORIZONTAL-TYPE is t, use the frame's scroll-bar +type. Return t if scroll bars were actually changed and nil otherwise. */) - (Lisp_Object window, Lisp_Object width, - Lisp_Object vertical_type, Lisp_Object horizontal_type) + (Lisp_Object window, Lisp_Object width, Lisp_Object vertical_type, + Lisp_Object height, Lisp_Object horizontal_type) { struct window *w = set_window_scroll_bars (decode_live_window (window), - width, vertical_type, horizontal_type); + width, vertical_type, height, horizontal_type); return w ? (apply_window_adjustment (w), Qt) : Qnil; } @@ -6914,19 +7386,20 @@ DEFUN ("window-scroll-bars", Fwindow_scroll_bars, Swindow_scroll_bars, doc: /* Get width and type of scroll bars of window WINDOW. WINDOW must be a live window and defaults to the selected one. -Value is a list of the form (WIDTH COLS VERTICAL-TYPE HORIZONTAL-TYPE). -If WIDTH is nil or TYPE is t, the window is using the frame's corresponding -value. */) +Value is a list of the form (WIDTH COLS VERTICAL-TYPE HEIGHT LINES +HORIZONTAL-TYPE). If WIDTH or HEIGHT is nil or TYPE is t, the window is +using the frame's corresponding value. */) (Lisp_Object window) { struct window *w = decode_live_window (window); - return list4 (make_number (WINDOW_SCROLL_BAR_AREA_WIDTH (w)), - make_number (WINDOW_SCROLL_BAR_COLS (w)), - w->vertical_scroll_bar_type, Qnil); + return Fcons (make_number (WINDOW_SCROLL_BAR_AREA_WIDTH (w)), + list5 (make_number (WINDOW_SCROLL_BAR_COLS (w)), + w->vertical_scroll_bar_type, + make_number (WINDOW_SCROLL_BAR_AREA_HEIGHT (w)), + make_number (WINDOW_SCROLL_BAR_LINES (w)), + w->horizontal_scroll_bar_type)); } - - /*********************************************************************** Smooth scrolling @@ -7116,7 +7589,9 @@ compare_window_configurations (Lisp_Object configuration1, || !EQ (sw1->right_fringe_width, sw2->right_fringe_width) || !EQ (sw1->fringes_outside_margins, sw2->fringes_outside_margins) || !EQ (sw1->scroll_bar_width, sw2->scroll_bar_width) - || !EQ (sw1->vertical_scroll_bar_type, sw2->vertical_scroll_bar_type)) + || !EQ (sw1->scroll_bar_height, sw2->scroll_bar_height) + || !EQ (sw1->vertical_scroll_bar_type, sw2->vertical_scroll_bar_type) + || !EQ (sw1->horizontal_scroll_bar_type, sw2->horizontal_scroll_bar_type)) return 0; } @@ -7170,6 +7645,7 @@ syms_of_window (void) DEFSYM (Qdelete_window, "delete-window"); DEFSYM (Qwindow_resize_root_window, "window--resize-root-window"); DEFSYM (Qwindow_resize_root_window_vertically, "window--resize-root-window-vertically"); + DEFSYM (Qwindow_sanitize_window_sizes, "window--sanitize-window-sizes"); DEFSYM (Qwindow_pixel_to_total, "window--pixel-to-total"); DEFSYM (Qsafe, "safe"); DEFSYM (Qdisplay_buffer, "display-buffer"); @@ -7396,12 +7872,14 @@ pixelwise even if this option is nil. */); defsubr (&Swindow_right_divider_width); defsubr (&Swindow_bottom_divider_width); defsubr (&Swindow_scroll_bar_width); + defsubr (&Swindow_scroll_bar_height); defsubr (&Swindow_inside_edges); defsubr (&Swindow_inside_pixel_edges); defsubr (&Swindow_inside_absolute_pixel_edges); defsubr (&Scoordinates_in_window_p); defsubr (&Swindow_at); defsubr (&Swindow_point); + defsubr (&Swindow_old_point); defsubr (&Swindow_start); defsubr (&Swindow_end); defsubr (&Sset_window_point); diff --git a/src/window.h b/src/window.h index b9c2b1f5ba8..cdf8da93138 100644 --- a/src/window.h +++ b/src/window.h @@ -128,21 +128,37 @@ struct window each one can have its own value of point. */ Lisp_Object pointm; + /* A marker pointing to where in the text point was in this window + at the time of last redisplay. The value is saved for the + selected window too. */ + Lisp_Object old_pointm; + /* No permanent meaning; used by save-window-excursion's bookkeeping. */ Lisp_Object temslot; - /* This window's vertical scroll bar. This field is only for use - by the window-system-dependent code which implements the - scroll bars; it can store anything it likes here. If this - window is newly created and we haven't displayed a scroll bar in - it yet, or if the frame doesn't have any scroll bars, this is nil. */ + /* This window's vertical scroll bar. This field is only for use by + the window-system-dependent code which implements the scroll + bars; it can store anything it likes here. If this window is + newly created and we haven't displayed a scroll bar in it yet, or + if the frame doesn't have any scroll bars, this is nil. */ Lisp_Object vertical_scroll_bar; /* Type of vertical scroll bar. A value of nil means no scroll bar. A value of t means use frame value. */ Lisp_Object vertical_scroll_bar_type; + /* This window's horizontal scroll bar. This field is only for use + by the window-system-dependent code which implements the scroll + bars; it can store anything it likes here. If this window is + newly created and we haven't displayed a scroll bar in it yet, or + if the frame doesn't have any scroll bars, this is nil. */ + Lisp_Object horizontal_scroll_bar; + + /* Type of horizontal scroll bar. A value of nil means + no scroll bar. A value of t means use frame value. */ + Lisp_Object horizontal_scroll_bar_type; + /* Display-table to use for displaying chars in this window. Nil means use the buffer's own display-table. */ Lisp_Object display_table; @@ -209,6 +225,10 @@ struct window the user has set, by set-window-hscroll for example. */ ptrdiff_t min_hscroll; + /* Maximum line length in pixels within window bound by size of + window (set up by set_horizontal_scroll_bar). */ + ptrdiff_t hscroll_whole; + /* Displayed buffer's text modification events counter as of last time display completed. */ EMACS_INT last_modified; @@ -282,6 +302,10 @@ struct window A value of -1 means use frame values. */ int scroll_bar_width; + /* Pixel height of scroll bars. + A value of -1 means use frame values. */ + int scroll_bar_height; + /* Effective height of the mode line, or -1 if not known. */ int mode_line_height; @@ -355,6 +379,10 @@ struct window /* True if it needs to be redisplayed. */ bool_bf redisplay : 1; + /* True if auto hscrolling is currently suspended in this + window. */ + bool_bf suspend_auto_hscroll : 1; + /* Amount by which lines of this window are scrolled in y-direction (smooth scrolling). */ int vscroll; @@ -402,6 +430,18 @@ wset_vertical_scroll_bar (struct window *w, Lisp_Object val) w->vertical_scroll_bar = val; } +INLINE void +wset_horizontal_scroll_bar (struct window *w, Lisp_Object val) +{ + w->horizontal_scroll_bar = val; +} + +INLINE void +wset_horizontal_scroll_bar_type (struct window *w, Lisp_Object val) +{ + w->horizontal_scroll_bar_type = val; +} + INLINE void wset_prev_buffers (struct window *w, Lisp_Object val) { @@ -415,8 +455,17 @@ wset_next_buffers (struct window *w, Lisp_Object val) } /* True if W is a minibuffer window. */ +#define MINI_WINDOW_P(W) ((W)->mini) -#define MINI_WINDOW_P(W) ((W)->mini) +/* 1 if W is a non-only minibuffer window. */ +/* The first check is redundant and the second overly complicated. */ +#define MINI_NON_ONLY_WINDOW_P(W) \ + (MINI_WINDOW_P (W) \ + && (EQ (W->prev, FRAME_ROOT_WINDOW (WINDOW_XFRAME (W))))) + +/* 1 if W is a minibuffer-only window. */ +#define MINI_ONLY_WINDOW_P(W) \ + (MINI_WINDOW_P (W) && NILP (W->prev)) /* General window layout: @@ -460,16 +509,17 @@ wset_next_buffers (struct window *w, Lisp_Object val) #define WINDOW_VERTICAL_COMBINATION_P(W) \ (WINDOWP ((W)->contents) && !(W)->horizontal) -#define WINDOW_XFRAME(W) \ - (XFRAME (WINDOW_FRAME ((W)))) +/* WINDOW's XFRAME. */ +#define WINDOW_XFRAME(W) (XFRAME (WINDOW_FRAME ((W)))) -/* Return the canonical column width of the frame of window W. */ +/* Whether WINDOW is a pseudo window. */ +#define WINDOW_PSEUDO_P(W) ((W)->pseudo_window_p) +/* Return the canonical column width of the frame of window W. */ #define WINDOW_FRAME_COLUMN_WIDTH(W) \ (FRAME_COLUMN_WIDTH (WINDOW_XFRAME ((W)))) /* Return the canonical column width of the frame of window W. */ - #define WINDOW_FRAME_LINE_HEIGHT(W) \ (FRAME_LINE_HEIGHT (WINDOW_XFRAME ((W)))) @@ -613,6 +663,10 @@ wset_next_buffers (struct window *w, Lisp_Object val) #define WINDOW_LEFTMOST_P(W) \ (WINDOW_LEFT_PIXEL_EDGE (W) == 0) +/* True if window W's has no other windows above in its frame. */ +#define WINDOW_TOPMOST_P(W) \ + (WINDOW_TOP_PIXEL_EDGE (W) == 0) + /* True if window W's has no other windows to its right in its frame. */ #define WINDOW_RIGHTMOST_P(W) \ (WINDOW_RIGHT_PIXEL_EDGE (W) \ @@ -629,7 +683,6 @@ wset_next_buffers (struct window *w, Lisp_Object val) /* Return the frame column at which the text (or left fringe) in window W starts. This is different from the `LEFT_EDGE' because it does not include a left-hand scroll bar if any. */ - #define WINDOW_BOX_LEFT_EDGE_COL(W) \ (WINDOW_LEFT_EDGE_COL (W) \ + WINDOW_LEFT_SCROLL_BAR_COLS (W)) @@ -644,7 +697,6 @@ wset_next_buffers (struct window *w, Lisp_Object val) /* Return the window column before which the text in window W ends. This is different from WINDOW_RIGHT_EDGE_COL because it does not include a scroll bar or window-separating line on the right edge. */ - #define WINDOW_BOX_RIGHT_EDGE_COL(W) \ (WINDOW_RIGHT_EDGE_COL (W) \ - WINDOW_RIGHT_SCROLL_BAR_COLS (W)) @@ -706,114 +758,108 @@ wset_next_buffers (struct window *w, Lisp_Object val) #define WINDOW_FRINGES_WIDTH(W) \ (WINDOW_LEFT_FRINGE_WIDTH (W) + WINDOW_RIGHT_FRINGE_WIDTH (W)) -/* Widths of fringes in columns. */ -#define WINDOW_FRINGE_COLS(W) \ - ((W->left_fringe_width >= 0 \ - && W->right_fringe_width >= 0) \ - ? ((WINDOW_FRINGES_WIDTH (W) \ - + WINDOW_FRAME_COLUMN_WIDTH (W) - 1) \ - / WINDOW_FRAME_COLUMN_WIDTH (W)) \ - : FRAME_FRINGE_COLS (WINDOW_XFRAME (W))) - -#define WINDOW_LEFT_FRINGE_COLS(W) \ - ((WINDOW_LEFT_FRINGE_WIDTH ((W)) \ - + WINDOW_FRAME_COLUMN_WIDTH (W) - 1) \ - / WINDOW_FRAME_COLUMN_WIDTH (W)) - -#define WINDOW_RIGHT_FRINGE_COLS(W) \ - ((WINDOW_RIGHT_FRINGE_WIDTH ((W)) \ - + WINDOW_FRAME_COLUMN_WIDTH (W) - 1) \ - / WINDOW_FRAME_COLUMN_WIDTH (W)) - /* Are fringes outside display margins in window W. */ #define WINDOW_HAS_FRINGES_OUTSIDE_MARGINS(W) \ ((W)->fringes_outside_margins) -/* Say whether scroll bars are currently enabled for window W, +/* Say whether vertical scroll bars are currently enabled for window W, and which side they are on. */ -#define WINDOW_VERTICAL_SCROLL_BAR_TYPE(w) \ - (EQ (w->vertical_scroll_bar_type, Qt) \ - ? FRAME_VERTICAL_SCROLL_BAR_TYPE (WINDOW_XFRAME (w)) \ - : EQ (w->vertical_scroll_bar_type, Qleft) \ +#define WINDOW_VERTICAL_SCROLL_BAR_TYPE(W) \ + (WINDOW_PSEUDO_P (W) \ + ? vertical_scroll_bar_none \ + : EQ (W->vertical_scroll_bar_type, Qt) \ + ? FRAME_VERTICAL_SCROLL_BAR_TYPE (WINDOW_XFRAME (W)) \ + : EQ (W->vertical_scroll_bar_type, Qleft) \ ? vertical_scroll_bar_left \ - : EQ (w->vertical_scroll_bar_type, Qright) \ + : EQ (W->vertical_scroll_bar_type, Qright) \ ? vertical_scroll_bar_right \ - : vertical_scroll_bar_none) \ - -#define WINDOW_HAS_VERTICAL_SCROLL_BAR(w) \ - (EQ (w->vertical_scroll_bar_type, Qt) \ - ? FRAME_HAS_VERTICAL_SCROLL_BARS (WINDOW_XFRAME (w)) \ - : !NILP (w->vertical_scroll_bar_type)) - -#define WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT(w) \ - (EQ (w->vertical_scroll_bar_type, Qt) \ - ? FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (WINDOW_XFRAME (w)) \ - : EQ (w->vertical_scroll_bar_type, Qleft)) - -#define WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT(w) \ - (EQ (w->vertical_scroll_bar_type, Qt) \ - ? FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (WINDOW_XFRAME (w)) \ - : EQ (w->vertical_scroll_bar_type, Qright)) + : vertical_scroll_bar_none) + +#define WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT(W) \ + (WINDOW_VERTICAL_SCROLL_BAR_TYPE (W) == vertical_scroll_bar_left) + +#define WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT(W) \ + (WINDOW_VERTICAL_SCROLL_BAR_TYPE (W) == vertical_scroll_bar_right) + +#define WINDOW_HAS_VERTICAL_SCROLL_BAR(W) \ + (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (W) \ + || WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (W)) + +/* Say whether horizontal scroll bars are currently enabled for window + W. Horizontal scrollbars exist for toolkit versions only. */ +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI) +#define WINDOW_HAS_HORIZONTAL_SCROLL_BAR(W) \ + ((WINDOW_PSEUDO_P (W) || MINI_NON_ONLY_WINDOW_P (W)) \ + ? false \ + : EQ (W->horizontal_scroll_bar_type, Qt) \ + ? FRAME_HAS_HORIZONTAL_SCROLL_BARS (WINDOW_XFRAME (W)) \ + : EQ (W->horizontal_scroll_bar_type, Qbottom) \ + ? true \ + : false) +#else +#define WINDOW_HAS_HORIZONTAL_SCROLL_BAR(W) false +#endif /* Width that a scroll bar in window W should have, if there is one. Measured in pixels. If scroll bars are turned off, this is still nonzero. */ -#define WINDOW_CONFIG_SCROLL_BAR_WIDTH(w) \ - (w->scroll_bar_width >= 0 \ - ? w->scroll_bar_width \ - : FRAME_CONFIG_SCROLL_BAR_WIDTH (WINDOW_XFRAME (w))) +#define WINDOW_CONFIG_SCROLL_BAR_WIDTH(W) \ + (W->scroll_bar_width >= 0 \ + ? W->scroll_bar_width \ + : FRAME_CONFIG_SCROLL_BAR_WIDTH (WINDOW_XFRAME (W))) /* Width that a scroll bar in window W should have, if there is one. Measured in columns (characters). If scroll bars are turned off, this is still nonzero. */ -#define WINDOW_CONFIG_SCROLL_BAR_COLS(w) \ - (w->scroll_bar_width >= 0 \ - ? ((w->scroll_bar_width \ - + WINDOW_FRAME_COLUMN_WIDTH (w) - 1) \ - / WINDOW_FRAME_COLUMN_WIDTH (w)) \ - : FRAME_CONFIG_SCROLL_BAR_COLS (WINDOW_XFRAME (w))) +#define WINDOW_CONFIG_SCROLL_BAR_COLS(W) \ + (W->scroll_bar_width >= 0 \ + ? ((W->scroll_bar_width \ + + WINDOW_FRAME_COLUMN_WIDTH (W) - 1) \ + / WINDOW_FRAME_COLUMN_WIDTH (W)) \ + : FRAME_CONFIG_SCROLL_BAR_COLS (WINDOW_XFRAME (W))) /* Width of left scroll bar in window W, measured in columns (characters). If scroll bars are on the right in this frame, or there are no scroll bars, value is 0. */ -#define WINDOW_LEFT_SCROLL_BAR_COLS(w) \ - (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w) \ - ? (WINDOW_CONFIG_SCROLL_BAR_COLS (w)) \ +#define WINDOW_LEFT_SCROLL_BAR_COLS(W) \ + (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (W) \ + ? (WINDOW_CONFIG_SCROLL_BAR_COLS (W)) \ : 0) /* Width of right scroll bar in window W, measured in columns (characters). If scroll bars are on the left in this frame, or there are no scroll bars, value is 0. */ -#define WINDOW_RIGHT_SCROLL_BAR_COLS(w) \ - (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w) \ - ? WINDOW_CONFIG_SCROLL_BAR_COLS (w) \ +#define WINDOW_RIGHT_SCROLL_BAR_COLS(W) \ + (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (W) \ + ? WINDOW_CONFIG_SCROLL_BAR_COLS (W) \ : 0) /* Width of a scroll bar in window W, measured in columns. */ -#define WINDOW_SCROLL_BAR_COLS(w) \ - (WINDOW_HAS_VERTICAL_SCROLL_BAR (w) \ - ? WINDOW_CONFIG_SCROLL_BAR_COLS (w) \ +#define WINDOW_SCROLL_BAR_COLS(W) \ + (WINDOW_HAS_VERTICAL_SCROLL_BAR (W) \ + ? WINDOW_CONFIG_SCROLL_BAR_COLS (W) \ : 0) /* Width of a left scroll bar area in window W, measured in pixels. */ -#define WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH(w) \ - (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w) \ - ? WINDOW_CONFIG_SCROLL_BAR_WIDTH (w) \ +#define WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH(W) \ + (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (W) \ + ? WINDOW_CONFIG_SCROLL_BAR_WIDTH (W) \ : 0) /* Width of a right scroll bar area in window W, measured in pixels. */ -#define WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH(w) \ - (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w) \ - ? WINDOW_CONFIG_SCROLL_BAR_WIDTH (w) \ +#define WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH(W) \ + (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (W) \ + ? WINDOW_CONFIG_SCROLL_BAR_WIDTH (W) \ : 0) /* Width of scroll bar area in window W, measured in pixels. */ -#define WINDOW_SCROLL_BAR_AREA_WIDTH(w) \ - (WINDOW_HAS_VERTICAL_SCROLL_BAR (w) \ - ? WINDOW_CONFIG_SCROLL_BAR_WIDTH (w) \ +#define WINDOW_SCROLL_BAR_AREA_WIDTH(W) \ + (WINDOW_HAS_VERTICAL_SCROLL_BAR (W) \ + ? WINDOW_CONFIG_SCROLL_BAR_WIDTH (W) \ : 0) -/* Return the frame position where the scroll bar of window W starts. */ +/* Return the frame position where the vertical scroll bar of window W + starts. */ #define WINDOW_SCROLL_BAR_AREA_X(W) \ (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (W) \ ? WINDOW_BOX_RIGHT_EDGE_X (W) \ @@ -829,6 +875,36 @@ wset_next_buffers (struct window *w, Lisp_Object val) ? 0 \ : FRAME_BOTTOM_DIVIDER_WIDTH (WINDOW_XFRAME (W))) +/* Height that a scroll bar in window W should have, if there is one. + Measured in pixels. If scroll bars are turned off, this is still + nonzero. */ +#define WINDOW_CONFIG_SCROLL_BAR_HEIGHT(W) \ + (W->scroll_bar_height >= 0 \ + ? W->scroll_bar_height \ + : FRAME_CONFIG_SCROLL_BAR_HEIGHT (WINDOW_XFRAME (W))) + +/* Height that a scroll bar in window W should have, if there is one. + Measured in lines (characters). If scroll bars are turned off, this + is still nonzero. */ +#define WINDOW_CONFIG_SCROLL_BAR_LINES(W) \ + (W->scroll_bar_height >= 0 \ + ? ((W->scroll_bar_height \ + + WINDOW_FRAME_LINE_HEIGHT (W) - 1) \ + / WINDOW_FRAME_LINE_HEIGHT (W)) \ + : FRAME_CONFIG_SCROLL_BAR_LINES (WINDOW_XFRAME (W))) + +/* Height of a scroll bar in window W, measured in columns. */ +#define WINDOW_SCROLL_BAR_LINES(W) \ + (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (W) \ + ? WINDOW_CONFIG_SCROLL_BAR_LINES (W) \ + : 0) + +/* Height of scroll bar area in window W, measured in pixels. */ +#define WINDOW_SCROLL_BAR_AREA_HEIGHT(W) \ + (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (W) \ + ? WINDOW_CONFIG_SCROLL_BAR_HEIGHT (W) \ + : 0) + /* Height in pixels, and in lines, of the mode line. May be zero if W doesn't have a mode line. */ #define WINDOW_MODE_LINE_HEIGHT(W) \ @@ -837,67 +913,63 @@ wset_next_buffers (struct window *w, Lisp_Object val) : 0) #define WINDOW_MODE_LINE_LINES(W) \ - (!! WINDOW_WANTS_MODELINE_P ((W))) + (!! WINDOW_WANTS_MODELINE_P (W)) /* Height in pixels, and in lines, of the header line. Zero if W doesn't have a header line. */ #define WINDOW_HEADER_LINE_HEIGHT(W) \ - (WINDOW_WANTS_HEADER_LINE_P ((W)) \ + (WINDOW_WANTS_HEADER_LINE_P (W) \ ? CURRENT_HEADER_LINE_HEIGHT (W) \ : 0) #define WINDOW_HEADER_LINE_LINES(W) \ - (!! WINDOW_WANTS_HEADER_LINE_P ((W))) + (!! WINDOW_WANTS_HEADER_LINE_P (W)) -/* Pixel height of window W without mode line and bottom divider. */ +/* Pixel height of window W without mode line, bottom scroll bar and + bottom divider. */ #define WINDOW_BOX_HEIGHT_NO_MODE_LINE(W) \ - (WINDOW_PIXEL_HEIGHT ((W)) \ + (WINDOW_PIXEL_HEIGHT (W) \ - WINDOW_BOTTOM_DIVIDER_WIDTH (W) \ - - WINDOW_MODE_LINE_HEIGHT ((W))) + - WINDOW_SCROLL_BAR_AREA_HEIGHT (W) \ + - WINDOW_MODE_LINE_HEIGHT (W)) /* Pixel height of window W without mode and header line and bottom divider. */ #define WINDOW_BOX_TEXT_HEIGHT(W) \ (WINDOW_PIXEL_HEIGHT ((W)) \ - WINDOW_BOTTOM_DIVIDER_WIDTH (W) \ - - WINDOW_MODE_LINE_HEIGHT ((W)) \ - - WINDOW_HEADER_LINE_HEIGHT ((W))) + - WINDOW_SCROLL_BAR_AREA_HEIGHT (W) \ + - WINDOW_MODE_LINE_HEIGHT (W) \ + - WINDOW_HEADER_LINE_HEIGHT (W)) + +/* Return the frame position where the horizontal scroll bar of window W + starts. */ +#define WINDOW_SCROLL_BAR_AREA_Y(W) \ + (WINDOW_TOP_EDGE_Y (W) \ + + (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (W) \ + ? WINDOW_BOX_HEIGHT_NO_MODE_LINE (W) : 0)) /* Convert window W relative pixel X to frame pixel coordinates. */ #define WINDOW_TO_FRAME_PIXEL_X(W, X) \ ((X) + WINDOW_BOX_LEFT_EDGE_X ((W))) /* Convert window W relative pixel Y to frame pixel coordinates. */ -#define WINDOW_TO_FRAME_PIXEL_Y(W, Y) \ - ((Y) + WINDOW_TOP_EDGE_Y ((W))) +#define WINDOW_TO_FRAME_PIXEL_Y(W, Y) \ + ((Y) + WINDOW_TOP_EDGE_Y (W)) /* Convert frame relative pixel X to window relative pixel X. */ -#define FRAME_TO_WINDOW_PIXEL_X(W, X) \ +#define FRAME_TO_WINDOW_PIXEL_X(W, X) \ ((X) - WINDOW_BOX_LEFT_EDGE_X ((W))) /* Convert frame relative pixel Y to window relative pixel Y. */ -#define FRAME_TO_WINDOW_PIXEL_Y(W, Y) \ - ((Y) - WINDOW_TOP_EDGE_Y ((W))) +#define FRAME_TO_WINDOW_PIXEL_Y(W, Y) \ + ((Y) - WINDOW_TOP_EDGE_Y (W)) /* Convert a text area relative x-position in window W to frame X pixel coordinates. */ #define WINDOW_TEXT_TO_FRAME_PIXEL_X(W, X) \ (window_box_left ((W), TEXT_AREA) + (X)) -/* True if the background of the window W's fringe that is adjacent to - a scroll bar is extended to the gap between the fringe and the bar. */ - -#define WINDOW_FRINGE_EXTENDED_P(w) \ - (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w) \ - ? (WINDOW_LEFTMOST_P (w) \ - && WINDOW_LEFT_FRINGE_WIDTH (w) \ - && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) \ - || WINDOW_LEFT_MARGIN_COLS (w) == 0)) \ - : (WINDOW_RIGHTMOST_P (w) \ - && WINDOW_RIGHT_FRINGE_WIDTH (w) \ - && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) \ - || WINDOW_RIGHT_MARGIN_COLS (w) == 0))) - /* This is the window in which the terminal's cursor should be left when nothing is being done with it. This must always be a leaf window, and its buffer is selected by the top level editing loop at the end of each command. @@ -981,11 +1053,6 @@ extern void bset_update_mode_line (struct buffer *b); above already does it, so it's only needed in unusual cases. */ extern void redisplay_other_windows (void); -/* If *ROWS or *COLS are too small a size for FRAME, set them to the - minimum allowable size. */ - -extern void check_frame_size (struct frame *frame, int *width, int *height, bool pixelwise); - /* Return a pointer to the glyph W's physical cursor is on. Value is null if W's current matrix is invalid, so that no meaningful glyph can be returned. */ @@ -1010,7 +1077,6 @@ struct glyph *get_phys_cursor_glyph (struct window *w); CHECK_TYPE (WINDOW_LIVE_P (WINDOW), Qwindow_live_p, WINDOW) /* These used to be in lisp.h. */ - extern Lisp_Object Qwindow_live_p; extern Lisp_Object Vwindow_list; @@ -1024,6 +1090,7 @@ extern int window_body_width (struct window *w, bool); extern void temp_output_buffer_show (Lisp_Object); extern void replace_buffer_in_windows (Lisp_Object); extern void replace_buffer_in_windows_safely (Lisp_Object); +extern Lisp_Object sanitize_window_sizes (Lisp_Object, Lisp_Object); /* This looks like a setter, but it is a bit special. */ extern void wset_buffer (struct window *, Lisp_Object); extern bool window_outdated (struct window *); diff --git a/src/xdisp.c b/src/xdisp.c index cf027a2b72e..bbe810d1a08 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -1024,6 +1024,8 @@ window_text_bottom_y (struct window *w) if (WINDOW_WANTS_MODELINE_P (w)) height -= CURRENT_MODE_LINE_HEIGHT (w); + height -= WINDOW_SCROLL_BAR_AREA_HEIGHT (w); + return height; } @@ -1068,6 +1070,7 @@ window_box_height (struct window *w) eassert (height >= 0); height -= WINDOW_BOTTOM_DIVIDER_WIDTH (w); + height -= WINDOW_SCROLL_BAR_AREA_HEIGHT (w); /* Note: the code below that determines the mode-line/header-line height is essentially the same as that contained in the macro @@ -1954,8 +1957,8 @@ pixel_to_glyph_coords (struct frame *f, register int pix_x, register int pix_y, if (pix_y < 0) pix_y = 0; - else if (pix_y > FRAME_LINES (f)) - pix_y = FRAME_LINES (f); + else if (pix_y > FRAME_TOTAL_LINES (f)) + pix_y = FRAME_TOTAL_LINES (f); } } #endif @@ -2498,7 +2501,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) gx = WINDOW_PIXEL_WIDTH (w) - width; goto row_glyph; - case ON_SCROLL_BAR: + case ON_VERTICAL_SCROLL_BAR: gx = (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w) ? 0 : (window_box_right_offset (w, RIGHT_MARGIN_AREA) @@ -10521,6 +10524,7 @@ with_echo_area_buffer (struct window *w, int which, { wset_buffer (w, buffer); set_marker_both (w->pointm, buffer, BEG, BEG_BYTE); + set_marker_both (w->old_pointm, buffer, BEG, BEG_BYTE); } bset_undo_list (current_buffer, Qt); @@ -10559,7 +10563,7 @@ with_echo_area_buffer_unwind_data (struct window *w) Vwith_echo_area_save_vector = Qnil; if (NILP (vector)) - vector = Fmake_vector (make_number (9), Qnil); + vector = Fmake_vector (make_number (11), Qnil); XSETBUFFER (tmp, current_buffer); ASET (vector, i, tmp); ++i; ASET (vector, i, Vdeactivate_mark); ++i; @@ -10571,12 +10575,14 @@ with_echo_area_buffer_unwind_data (struct window *w) ASET (vector, i, w->contents); ++i; ASET (vector, i, make_number (marker_position (w->pointm))); ++i; ASET (vector, i, make_number (marker_byte_position (w->pointm))); ++i; + ASET (vector, i, make_number (marker_position (w->old_pointm))); ++i; + ASET (vector, i, make_number (marker_byte_position (w->old_pointm))); ++i; ASET (vector, i, make_number (marker_position (w->start))); ++i; ASET (vector, i, make_number (marker_byte_position (w->start))); ++i; } else { - int end = i + 6; + int end = i + 8; for (; i < end; ++i) ASET (vector, i, Qnil); } @@ -10608,9 +10614,12 @@ unwind_with_echo_area_buffer (Lisp_Object vector) set_marker_both (w->pointm, buffer, XFASTINT (AREF (vector, 5)), XFASTINT (AREF (vector, 6))); - set_marker_both (w->start, buffer, + set_marker_both (w->old_pointm, buffer, XFASTINT (AREF (vector, 7)), XFASTINT (AREF (vector, 8))); + set_marker_both (w->start, buffer, + XFASTINT (AREF (vector, 9)), + XFASTINT (AREF (vector, 10))); } Vwith_echo_area_save_vector = vector; @@ -11885,7 +11894,7 @@ update_tool_bar (struct frame *f, int save_match_data) int do_update = FRAME_EXTERNAL_TOOL_BAR (f); #else int do_update = (WINDOWP (f->tool_bar_window) - && WINDOW_PIXEL_HEIGHT (XWINDOW (f->tool_bar_window)) > 0); + && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)) > 0); #endif if (do_update) @@ -12269,16 +12278,9 @@ display_tool_bar_line (struct it *it, int height) } -/* Max tool-bar height. Basically, this is what makes all other windows - disappear when the frame gets too small. Rethink this! */ - -#define MAX_FRAME_TOOL_BAR_HEIGHT(f) \ - ((FRAME_LINE_HEIGHT (f) * FRAME_LINES (f))) - /* Value is the number of pixels needed to make all tool-bar items of frame F visible. The actual number of glyph rows needed is returned in *N_ROWS if non-NULL. */ - static int tool_bar_height (struct frame *f, int *n_rows, bool pixelwise) { @@ -12347,7 +12349,6 @@ PIXELWISE non-nil means return the height of the tool bar in pixels. */) /* Display the tool-bar of frame F. Value is non-zero if tool-bar's height should be changed. */ - static int redisplay_tool_bar (struct frame *f) { @@ -12369,7 +12370,7 @@ redisplay_tool_bar (struct frame *f) can turn off tool-bars by specifying tool-bar-lines zero. */ if (!WINDOWP (f->tool_bar_window) || (w = XWINDOW (f->tool_bar_window), - WINDOW_PIXEL_HEIGHT (w) == 0)) + WINDOW_TOTAL_LINES (w) == 0)) return 0; /* Set up an iterator for the tool-bar window. */ @@ -12396,14 +12397,7 @@ redisplay_tool_bar (struct frame *f) if (new_height != WINDOW_PIXEL_HEIGHT (w)) { - Lisp_Object frame; - int new_lines = ((new_height + FRAME_LINE_HEIGHT (f) - 1) - / FRAME_LINE_HEIGHT (f)); - - XSETFRAME (frame, f); - Fmodify_frame_parameters (frame, - list1 (Fcons (Qtool_bar_lines, - make_number (new_lines)))); + x_change_tool_bar_height (f, new_height); /* Always do that now. */ clear_glyph_matrix (w->desired_matrix); f->fonts_changed = 1; @@ -12456,14 +12450,11 @@ redisplay_tool_bar (struct frame *f) if (!NILP (Vauto_resize_tool_bars)) { - /* Do we really allow the toolbar to occupy the whole frame? */ - int max_tool_bar_height = MAX_FRAME_TOOL_BAR_HEIGHT (f); int change_height_p = 0; /* If we couldn't display everything, change the tool-bar's height if there is room for more. */ - if (IT_STRING_CHARPOS (it) < it.end_charpos - && it.current_y < max_tool_bar_height) + if (IT_STRING_CHARPOS (it) < it.end_charpos) change_height_p = 1; /* We subtract 1 because display_tool_bar_line advances the @@ -12482,15 +12473,13 @@ redisplay_tool_bar (struct frame *f) /* If row displays tool-bar items, but is partially visible, change the tool-bar's height. */ if (MATRIX_ROW_DISPLAYS_TEXT_P (row) - && MATRIX_ROW_BOTTOM_Y (row) > it.last_visible_y - && MATRIX_ROW_BOTTOM_Y (row) < max_tool_bar_height) + && MATRIX_ROW_BOTTOM_Y (row) > it.last_visible_y) change_height_p = 1; /* Resize windows as needed by changing the `tool-bar-lines' frame parameter. */ if (change_height_p) { - Lisp_Object frame; int nrows; int new_height = tool_bar_height (f, &nrows, 1); @@ -12502,35 +12491,12 @@ redisplay_tool_bar (struct frame *f) if (change_height_p) { - /* Current size of the tool-bar window in canonical line - units. */ - int old_lines = WINDOW_TOTAL_LINES (w); - /* Required size of the tool-bar window in canonical - line units. */ - int new_lines = ((new_height + FRAME_LINE_HEIGHT (f) - 1) - / FRAME_LINE_HEIGHT (f)); - /* Maximum size of the tool-bar window in canonical line - units that this frame can allow. */ - int max_lines = - WINDOW_TOTAL_LINES (XWINDOW (FRAME_ROOT_WINDOW (f))) - 1; - - /* Don't try to change the tool-bar window size and set - the fonts_changed flag unless really necessary. That - flag causes redisplay to give up and retry - redisplaying the frame from scratch, so setting it - unnecessarily can lead to nasty redisplay loops. */ - if (new_lines <= max_lines - && eabs (new_lines - old_lines) >= 1) - { - XSETFRAME (frame, f); - Fmodify_frame_parameters (frame, - list1 (Fcons (Qtool_bar_lines, - make_number (new_lines)))); - clear_glyph_matrix (w->desired_matrix); - f->n_tool_bar_rows = nrows; - f->fonts_changed = 1; - return 1; - } + x_change_tool_bar_height (f, new_height); + clear_glyph_matrix (w->desired_matrix); + f->n_tool_bar_rows = nrows; + f->fonts_changed = 1; + + return 1; } } } @@ -12864,7 +12830,20 @@ hscroll_window_tree (Lisp_Object window) /* Scroll when cursor is inside this scroll margin. */ h_margin = hscroll_margin * WINDOW_FRAME_COLUMN_WIDTH (w); + /* If the position of this window's point has explicitly + changed, no more suspend auto hscrolling. */ + if (NILP (Fequal (Fwindow_point (window), Fwindow_old_point (window)))) + w->suspend_auto_hscroll = 0; + + /* Remember window point. */ + Fset_marker (w->old_pointm, + ((w == XWINDOW (selected_window)) + ? make_number (BUF_PT (XBUFFER (w->contents))) + : Fmarker_position (w->pointm)), + w->contents); + if (!NILP (Fbuffer_local_value (Qauto_hscroll_mode, w->contents)) + && w->suspend_auto_hscroll == 0 /* In some pathological cases, like restoring a window configuration into a frame that is much smaller than the one from which the configuration was saved, we @@ -12877,8 +12856,7 @@ hscroll_window_tree (Lisp_Object window) inside the left margin and the window is already hscrolled. */ && ((!row_r2l_p - && ((w->hscroll - && w->cursor.x <= h_margin) + && ((w->hscroll && w->cursor.x <= h_margin) || (cursor_row->enabled_p && cursor_row->truncated_on_right_p && (w->cursor.x >= text_area_width - h_margin)))) @@ -15759,6 +15737,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste return rc; } + void set_vertical_scroll_bar (struct window *w) { @@ -15797,6 +15776,60 @@ set_vertical_scroll_bar (struct window *w) } +void +set_horizontal_scroll_bar (struct window *w) +{ + int start, end, whole, box_width; + + if (!MINI_WINDOW_P (w) + || (w == XWINDOW (minibuf_window) + && NILP (echo_area_buffer[0]))) + { + struct buffer *b = XBUFFER (w->contents); + struct buffer *old_buffer = NULL; + struct it it; + struct text_pos startp; + + if (b != current_buffer) + { + old_buffer = current_buffer; + set_buffer_internal (b); + } + + SET_TEXT_POS_FROM_MARKER (startp, w->start); + start_display (&it, w, startp); + it.last_visible_x = INT_MAX; + whole = move_it_to (&it, -1, INT_MAX, window_box_height (w), -1, + MOVE_TO_X | MOVE_TO_Y); + /* whole = move_it_to (&it, w->window_end_pos, INT_MAX, + window_box_height (w), -1, + MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y); */ + + start = w->hscroll * FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w)); + box_width = window_box_width (w, TEXT_AREA); + end = start + box_width; + + /* The following is needed to ensure that if after maximizing a + window we get hscroll > 0, we can still drag the thumb to the + left. */ + whole = max (whole, w->hscroll + box_width); + whole = max (whole, end - start); + + if (old_buffer) + set_buffer_internal (old_buffer); + } + else + start = end = whole = 0; + + w->hscroll_whole = whole; + + /* Indicate what this scroll bar ought to be displaying now. */ + if (FRAME_TERMINAL (XFRAME (w->frame))->set_horizontal_scroll_bar_hook) + (*FRAME_TERMINAL (XFRAME (w->frame))->set_horizontal_scroll_bar_hook) + (w, end - start, whole, start); +} + + /* Redisplay leaf window WINDOW. JUST_THIS_ONE_P non-zero means only selected_window is redisplayed. @@ -16010,6 +16043,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) { ptrdiff_t new_pt = marker_position (w->pointm); ptrdiff_t new_pt_byte = marker_byte_position (w->pointm); + if (new_pt < BEGV) { new_pt = BEGV; @@ -16749,7 +16783,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) redisplay_tool_bar (f); #else if (WINDOWP (f->tool_bar_window) - && (FRAME_TOOL_BAR_HEIGHT (f) > 0 + && (FRAME_TOOL_BAR_LINES (f) > 0 || !NILP (Vauto_resize_tool_bars)) && redisplay_tool_bar (f)) ignore_mouse_drag_p = 1; @@ -16789,10 +16823,15 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) ; finish_scroll_bars: - if (WINDOW_HAS_VERTICAL_SCROLL_BAR (w)) + if (WINDOW_HAS_VERTICAL_SCROLL_BAR (w) || WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w)) { - /* Set the thumb's position and size. */ - set_vertical_scroll_bar (w); + if (WINDOW_HAS_VERTICAL_SCROLL_BAR (w)) + /* Set the thumb's position and size. */ + set_vertical_scroll_bar (w); + + if (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w)) + /* Set the thumb's position and size. */ + set_horizontal_scroll_bar (w); /* Note that we actually used the scroll bar attached to this window, so it shouldn't be deleted at the end of redisplay. */ @@ -28990,7 +29029,8 @@ note_mouse_highlight (struct frame *f, int x, int y) else cursor = FRAME_X_OUTPUT (f)->nontext_cursor; else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE - || part == ON_SCROLL_BAR) + || part == ON_VERTICAL_SCROLL_BAR + || part == ON_HORIZONTAL_SCROLL_BAR) cursor = FRAME_X_OUTPUT (f)->nontext_cursor; else cursor = FRAME_X_OUTPUT (f)->text_cursor; @@ -29911,8 +29951,10 @@ expose_frame (struct frame *f, int x, int y, int w, int h) if (w == 0 || h == 0) { r.x = r.y = 0; - r.width = FRAME_COLUMN_WIDTH (f) * FRAME_COLS (f); - r.height = FRAME_LINE_HEIGHT (f) * FRAME_LINES (f); + r.width = FRAME_TEXT_WIDTH (f); + r.height = FRAME_TEXT_HEIGHT (f); +/** r.width = FRAME_COLUMN_WIDTH (f) * FRAME_COLS (f); **/ +/** r.height = FRAME_LINE_HEIGHT (f) * FRAME_LINES (f); **/ } else { @@ -30198,8 +30240,9 @@ A value of nil means no special handling of these characters. */); DEFVAR_LISP ("void-text-area-pointer", Vvoid_text_area_pointer, doc: /* The pointer shape to show in void text areas. -A value of nil means to show the text pointer. Other options are `arrow', -`text', `hand', `vdrag', `hdrag', `modeline', and `hourglass'. */); +A value of nil means to show the text pointer. Other options are +`arrow', `text', `hand', `vdrag', `hdrag', `nhdrag', `modeline', and +`hourglass'. */); Vvoid_text_area_pointer = Qarrow; DEFVAR_LISP ("inhibit-redisplay", Vinhibit_redisplay, @@ -30694,10 +30737,10 @@ init_xdisp (void) r->pixel_top = r->top_line * FRAME_LINE_HEIGHT (f); r->total_cols = FRAME_COLS (f); r->pixel_width = r->total_cols * FRAME_COLUMN_WIDTH (f); - r->total_lines = FRAME_LINES (f) - 1 - FRAME_TOP_MARGIN (f); + r->total_lines = FRAME_TOTAL_LINES (f) - 1 - FRAME_TOP_MARGIN (f); r->pixel_height = r->total_lines * FRAME_LINE_HEIGHT (f); - m->top_line = FRAME_LINES (f) - 1; + m->top_line = FRAME_TOTAL_LINES (f) - 1; m->pixel_top = m->top_line * FRAME_LINE_HEIGHT (f); m->total_cols = FRAME_COLS (f); m->pixel_width = m->total_cols * FRAME_COLUMN_WIDTH (f); diff --git a/src/xfns.c b/src/xfns.c index 7d87ddbb2b4..1787d0297e6 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -1009,7 +1009,7 @@ x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) #else /* not USE_X_TOOLKIT && not USE_GTK */ FRAME_MENU_BAR_LINES (f) = nlines; FRAME_MENU_BAR_HEIGHT (f) = nlines * FRAME_LINE_HEIGHT (f); - resize_frame_windows (f, FRAME_TEXT_HEIGHT (f), 0, 1); + adjust_frame_size (f, -1, -1, 2, 1); if (FRAME_X_WINDOW (f)) x_clear_under_internal_border (f); @@ -1064,10 +1064,6 @@ void x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) { int nlines; -#if ! defined (USE_GTK) - int delta, root_height; - int unit = FRAME_LINE_HEIGHT (f); -#endif /* Treat tool bars like menu bars. */ if (FRAME_MINIBUF_ONLY_P (f)) @@ -1079,11 +1075,18 @@ x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) else nlines = 0; -#ifdef USE_GTK + x_change_tool_bar_height (f, nlines * FRAME_LINE_HEIGHT (f)); +} + +/* Set the pixel height of the tool bar of frame F to HEIGHT. */ +void +x_change_tool_bar_height (struct frame *f, int height) +{ +#ifdef USE_GTK FRAME_TOOL_BAR_LINES (f) = 0; FRAME_TOOL_BAR_HEIGHT (f) = 0; - if (nlines) + if (height) { FRAME_EXTERNAL_TOOL_BAR (f) = 1; if (FRAME_X_P (f) && f->output_data.x->toolbar_widget == 0) @@ -1097,39 +1100,25 @@ x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) free_frame_tool_bar (f); FRAME_EXTERNAL_TOOL_BAR (f) = 0; } - #else /* !USE_GTK */ + int unit = FRAME_LINE_HEIGHT (f); + int old_height = FRAME_TOOL_BAR_HEIGHT (f); + int lines = (height + unit - 1) / unit; /* Make sure we redisplay all windows in this frame. */ windows_or_buffers_changed = 60; - /* DELTA is in pixels now. */ - delta = (nlines - FRAME_TOOL_BAR_LINES (f)) * unit; - /* Don't resize the tool-bar to more than we have room for. Note: The - calculations below and the subsequent call to resize_frame_windows - are inherently flawed because they can make the toolbar higher than - the containing frame. */ - if (delta > 0) - { - root_height = WINDOW_PIXEL_HEIGHT (XWINDOW (FRAME_ROOT_WINDOW (f))); - if (root_height - delta < unit) - { - delta = root_height - unit; - /* When creating a new frame and toolbar mode is enabled, we - need at least one toolbar line. */ - nlines = max (FRAME_TOOL_BAR_LINES (f) + delta / unit, 1); - } - } - - FRAME_TOOL_BAR_LINES (f) = nlines; - FRAME_TOOL_BAR_HEIGHT (f) = nlines * FRAME_LINE_HEIGHT (f); - resize_frame_windows (f, FRAME_TEXT_HEIGHT (f), 0, 1); -#if !defined USE_X_TOOLKIT && !defined USE_GTK - if (FRAME_X_WINDOW (f)) - x_clear_under_internal_border (f); -#endif - adjust_frame_glyphs (f); + /* Recalculate tool bar and frame text sizes. */ + FRAME_TOOL_BAR_HEIGHT (f) = height; + FRAME_TOOL_BAR_LINES (f) = lines; + FRAME_TEXT_HEIGHT (f) + = FRAME_PIXEL_TO_TEXT_HEIGHT (f, FRAME_PIXEL_HEIGHT (f)); + FRAME_LINES (f) + = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, FRAME_PIXEL_HEIGHT (f)); + /* Store the `tool-bar-lines' and `height' frame parameters. */ + store_frame_param (f, Qtool_bar_lines, make_number (lines)); + store_frame_param (f, Qheight, make_number (FRAME_LINES (f))); /* We also have to make sure that the internal border at the top of the frame, below the menu bar or tool bar, is redrawn when the @@ -1143,30 +1132,52 @@ x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) clear_current_matrices (f); } - /* If the tool bar gets smaller, the internal border below it - has to be cleared. It was formerly part of the display - of the larger tool bar, and updating windows won't clear it. */ - if (delta < 0) + if ((height < old_height) && WINDOWP (f->tool_bar_window)) + clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix); + + /* Recalculate toolbar height. */ + f->n_tool_bar_rows = 0; + + adjust_frame_size (f, -1, -1, 4, 0); + +/** #if !defined USE_X_TOOLKIT **/ + if (FRAME_X_WINDOW (f)) + x_clear_under_internal_border (f); +/** #endif **/ + +#endif /* USE_GTK */ +} + + +void +x_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval) +{ + int border; + + CHECK_TYPE_RANGED_INTEGER (int, arg); + border = max (XINT (arg), 0); + + if (border != FRAME_INTERNAL_BORDER_WIDTH (f)) { - int height = FRAME_INTERNAL_BORDER_WIDTH (f); - int width = FRAME_PIXEL_WIDTH (f); - int y = nlines * unit; + FRAME_INTERNAL_BORDER_WIDTH (f) = border; - /* height can be zero here. */ - if (height > 0 && width > 0) +#ifdef USE_X_TOOLKIT + if (FRAME_X_OUTPUT (f)->edit_widget) + widget_store_internal_border (FRAME_X_OUTPUT (f)->edit_widget); +#endif + + if (FRAME_X_WINDOW (f) != 0) { - block_input (); - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - 0, y, width, height); - unblock_input (); - } + adjust_frame_size (f, -1, -1, 3, 0); - if (WINDOWP (f->tool_bar_window)) - clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix); +#ifdef USE_GTK + xg_clear_under_internal_border (f); +#else + x_clear_under_internal_border (f); +#endif + } } - run_window_configuration_change_hook (f); -#endif /* USE_GTK */ } @@ -1508,14 +1519,36 @@ x_set_scroll_bar_default_width (struct frame *f) FRAME_CONFIG_SCROLL_BAR_COLS (f) = (minw + unit - 1) / unit; FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = minw; #else - /* The width of a non-toolkit scrollbar is at least 14 pixels and a - multiple of the frame's character width. */ + /* The width of a non-toolkit scrollbar is 14 pixels. */ FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + unit - 1) / unit; FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = FRAME_CONFIG_SCROLL_BAR_COLS (f) * unit; #endif } +void +x_set_scroll_bar_default_height (struct frame *f) +{ + int height = FRAME_LINE_HEIGHT (f); +#ifdef USE_TOOLKIT_SCROLL_BARS +#ifdef USE_GTK + int min_height = xg_get_default_scrollbar_height (); +#else + int min_height = 16; +#endif + /* A minimum height of 14 doesn't look good for toolkit scroll bars. */ + FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = min_height; + FRAME_CONFIG_SCROLL_BAR_LINES (f) = (min_height + height - 1) / height; +#else + /* The height of a non-toolkit scrollbar is 14 pixels. */ + FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height; + + /* Use all of that space (aside from required margins) for the + scroll bar. */ + FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = 14; +#endif +} + /* Record in frame F the specified or default value according to ALIST of the parameter named PROP (a Lisp symbol). If no value is @@ -2755,12 +2788,6 @@ do_unwind_create_frame (Lisp_Object frame) unwind_create_frame (frame); } -static void -unwind_create_frame_1 (Lisp_Object val) -{ - inhibit_lisp_code = val; -} - static void x_default_font_parameter (struct frame *f, Lisp_Object parms) { @@ -2865,12 +2892,11 @@ set_machine_and_pid_properties (struct frame *f) DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame, 1, 1, 0, doc: /* Make a new X window, which is called a "frame" in Emacs terms. -Return an Emacs frame object. -PARMS is an alist of frame parameters. +Return an Emacs frame object. PARMS is an alist of frame parameters. If the parameters specify that the frame should not have a minibuffer, -and do not specify a specific minibuffer window to use, -then `default-minibuffer-frame' must be a frame whose minibuffer can -be shared by the new frame. +and do not specify a specific minibuffer window to use, then +`default-minibuffer-frame' must be a frame whose minibuffer can be +shared by the new frame. This function is an internal primitive--use `make-frame' instead. */) (Lisp_Object parms) @@ -2880,7 +2906,6 @@ This function is an internal primitive--use `make-frame' instead. */) Lisp_Object name; int minibuffer_only = 0; long window_prompting = 0; - int width, height; ptrdiff_t count = SPECPDL_INDEX (); struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; Lisp_Object display; @@ -3002,7 +3027,6 @@ This function is an internal primitive--use `make-frame' instead. */) } /* Specify the parent under which to make this X window. */ - if (!NILP (parent)) { f->output_data.x->parent_desc = (Window) XFASTINT (parent); @@ -3025,7 +3049,7 @@ This function is an internal primitive--use `make-frame' instead. */) { fset_name (f, name); f->explicit_name = 1; - /* use the frame's title when getting resources for this frame. */ + /* Use the frame's title when getting resources for this frame. */ specbind (Qx_resource_name, name); } @@ -3088,6 +3112,14 @@ This function is an internal primitive--use `make-frame' instead. */) #endif "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL); + x_default_parameter (f, parms, Qhorizontal_scroll_bars, +#if defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS) + Qt, +#else + Qnil, +#endif + "horizontalScrollBars", "ScrollBars", + RES_TYPE_SYMBOL); /* Also do the stuff which must be set before the window exists. */ x_default_parameter (f, parms, Qforeground_color, build_string ("black"), @@ -3120,49 +3152,36 @@ This function is an internal primitive--use `make-frame' instead. */) dpyinfo_refcount = dpyinfo->reference_count; #endif /* GLYPH_DEBUG */ - /* Init faces before x_default_parameter is called for scroll-bar - parameters because that function calls x_set_scroll_bar_width, - which calls change_frame_size, which calls Fset_window_buffer, - which runs hooks, which call Fvertical_motion. At the end, we - end up in init_iterator with a null face cache, which should not - happen. */ + /* Init faces before x_default_parameter is called for the + scroll-bar-width parameter because otherwise we end up in + init_iterator with a null face cache, which should not happen. */ init_frame_faces (f); - /* PXW: This is a duplicate from below. We have to do it here since - otherwise x_set_tool_bar_lines will work with the character sizes - installed by init_frame_faces while the frame's pixel size is still - calculated from a character size of 1 and we subsequently hit the - eassert (height >= 0) assertion in window_box_height. The - non-pixelwise code apparently worked around this because it had one - frame line vs one toolbar line which left us with a zero root - window height which was obviously wrong as well ... */ - change_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), - FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 1, 0, 0, 1); + /* The following call of change_frame_size is needed since otherwise + x_set_tool_bar_lines will already work with the character sizes + installed by init_frame_faces while the frame's pixel size is + still calculated from a character size of 1 and we subsequently + hit the (height >= 0) assertion in window_box_height. + + The non-pixelwise code apparently worked around this because it + had one frame line vs one toolbar line which left us with a zero + root window height which was obviously wrong as well ... */ + adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), + FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, 1); /* Set the menu-bar-lines and tool-bar-lines parameters. We don't look up the X resources controlling the menu-bar and tool-bar here; they are processed specially at startup, and reflected in - the values of the mode variables. + the values of the mode variables. */ - Avoid calling window-configuration-change-hook; otherwise we - could get an infloop in next_frame since the frame is not yet in - Vframe_list. */ - { - ptrdiff_t count2 = SPECPDL_INDEX (); - record_unwind_protect (unwind_create_frame_1, inhibit_lisp_code); - inhibit_lisp_code = Qt; - - x_default_parameter (f, parms, Qmenu_bar_lines, - NILP (Vmenu_bar_mode) - ? make_number (0) : make_number (1), - NULL, NULL, RES_TYPE_NUMBER); - x_default_parameter (f, parms, Qtool_bar_lines, - NILP (Vtool_bar_mode) - ? make_number (0) : make_number (1), - NULL, NULL, RES_TYPE_NUMBER); - - unbind_to (count2, Qnil); - } + x_default_parameter (f, parms, Qmenu_bar_lines, + NILP (Vmenu_bar_mode) + ? make_number (0) : make_number (1), + NULL, NULL, RES_TYPE_NUMBER); + x_default_parameter (f, parms, Qtool_bar_lines, + NILP (Vtool_bar_mode) + ? make_number (0) : make_number (1), + NULL, NULL, RES_TYPE_NUMBER); x_default_parameter (f, parms, Qbuffer_predicate, Qnil, "bufferPredicate", "BufferPredicate", @@ -3172,7 +3191,7 @@ This function is an internal primitive--use `make-frame' instead. */) x_default_parameter (f, parms, Qwait_for_wm, Qt, "waitForWM", "WaitForWM", RES_TYPE_BOOLEAN); x_default_parameter (f, parms, Qfullscreen, Qnil, - "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); + "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); x_default_parameter (f, parms, Qtool_bar_position, FRAME_TOOL_BAR_POSITION (f), 0, 0, RES_TYPE_SYMBOL); @@ -3213,17 +3232,16 @@ This function is an internal primitive--use `make-frame' instead. */) x_default_parameter (f, parms, Qscroll_bar_width, Qnil, "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER); + x_default_parameter (f, parms, Qscroll_bar_height, Qnil, + "scrollBarHeight", "ScrollBarHeight", + RES_TYPE_NUMBER); x_default_parameter (f, parms, Qalpha, Qnil, "alpha", "Alpha", RES_TYPE_NUMBER); - /* Dimensions, especially FRAME_LINES (f), must be done via change_frame_size. - Change will not be effected unless different from the current - FRAME_LINES (f). */ - width = FRAME_TEXT_WIDTH (f); - height = FRAME_TEXT_HEIGHT (f); - FRAME_TEXT_HEIGHT (f) = 0; - SET_FRAME_WIDTH (f, 0); - change_frame_size (f, width, height, 1, 0, 0, 1); + /* Consider frame official, now. */ + f->official = true; + + adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 0, 1); #if defined (USE_X_TOOLKIT) || defined (USE_GTK) /* Create the menu bar. */ @@ -4961,12 +4979,9 @@ x_create_tip_frame (struct x_display_info *dpyinfo, dpyinfo_refcount = dpyinfo->reference_count; #endif /* GLYPH_DEBUG */ - /* Init faces before x_default_parameter is called for scroll-bar - parameters because that function calls x_set_scroll_bar_width, - which calls change_frame_size, which calls Fset_window_buffer, - which runs hooks, which call Fvertical_motion. At the end, we - end up in init_iterator with a null face cache, which should not - happen. */ + /* Init faces before x_default_parameter is called for the + scroll-bar-width parameter because otherwise we end up in + init_iterator with a null face cache, which should not happen. */ init_frame_faces (f); f->output_data.x->parent_desc = FRAME_DISPLAY_INFO (f)->root_window; @@ -5023,7 +5038,7 @@ x_create_tip_frame (struct x_display_info *dpyinfo, width = FRAME_COLS (f); height = FRAME_LINES (f); SET_FRAME_COLS (f, 0); - FRAME_LINES (f) = 0; + SET_FRAME_LINES (f, 0); change_frame_size (f, width, height, 1, 0, 0, 0); /* Add `tooltip' frame parameter's default value. */ @@ -5081,7 +5096,7 @@ x_create_tip_frame (struct x_display_info *dpyinfo, below. And the frame needs to be on Vframe_list or making it visible won't work. */ Vframe_list = Fcons (frame, Vframe_list); - + f->official = true; /* Setting attributes of faces of the tooltip frame from resources and similar will increment face_change_count, which leads to the @@ -6011,17 +6026,19 @@ frame_parm_handler x_frame_parm_handlers[] = x_set_mouse_color, x_explicitly_set_name, x_set_scroll_bar_width, + x_set_scroll_bar_height, x_set_title, x_set_unsplittable, x_set_vertical_scroll_bars, + x_set_horizontal_scroll_bars, x_set_visibility, x_set_tool_bar_lines, x_set_scroll_bar_foreground, x_set_scroll_bar_background, x_set_screen_gamma, x_set_line_spacing, - x_set_fringe_width, - x_set_fringe_width, + x_set_left_fringe, + x_set_right_fringe, x_set_wait_for_wm, x_set_fullscreen, x_set_font_backend, diff --git a/src/xmenu.c b/src/xmenu.c index f4d0921762c..a7d47188ef5 100644 --- a/src/xmenu.c +++ b/src/xmenu.c @@ -627,7 +627,7 @@ update_frame_menubar (struct frame *f) xg_update_frame_menubar (f); #else struct x_output *x; - int columns, rows; +/** int columns, rows; **/ eassert (FRAME_X_P (f)); @@ -639,8 +639,8 @@ update_frame_menubar (struct frame *f) block_input (); /* Save the size of the frame because the pane widget doesn't accept to resize itself. So force it. */ - columns = FRAME_COLS (f); - rows = FRAME_LINES (f); +/** columns = FRAME_COLS (f); **/ +/** rows = FRAME_LINES (f); **/ /* Do the voodoo which means "I'm changing lots of things, don't try to refigure sizes until I'm done." */ @@ -662,7 +662,8 @@ update_frame_menubar (struct frame *f) lw_refigure_widget (x->column_widget, True); /* Force the pane widget to resize itself with the right values. */ - EmacsFrameSetCharSize (x->edit_widget, columns, rows); +/** EmacsFrameSetCharSize (x->edit_widget, columns, rows); **/ + adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 2, 0); unblock_input (); #endif } @@ -705,7 +706,7 @@ apply_systemfont_to_menu (struct frame *f, Widget w) void set_frame_menubar (struct frame *f, bool first_time, bool deep_p) { - xt_or_gtk_widget menubar_widget; + xt_or_gtk_widget menubar_widget, old_widget; #ifdef USE_X_TOOLKIT LWLIB_ID id; #endif @@ -718,7 +719,7 @@ set_frame_menubar (struct frame *f, bool first_time, bool deep_p) eassert (FRAME_X_P (f)); - menubar_widget = f->output_data.x->menubar_widget; + menubar_widget = old_widget = f->output_data.x->menubar_widget; XSETFRAME (Vmenu_updating_frame, f); @@ -1099,7 +1100,15 @@ free_frame_menubar (struct frame *f) if (x1 == 0 && y1 == 0) XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL); #endif - x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 1); + adjust_frame_size (f, FRAME_TEXT_WIDTH (f), + FRAME_TEXT_HEIGHT (f), 2, 0); + /* + if (frame_inhibit_resize (f, 0)) + change_frame_size (f, 0, 0, 0, 0, 0, 1); + else + x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f), + FRAME_TEXT_HEIGHT (f), 1); + */ } unblock_input (); } diff --git a/src/xterm.c b/src/xterm.c index 85835a2c7c5..b4eba7fcf82 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -246,11 +246,15 @@ static void x_clip_to_row (struct window *, struct glyph_row *, static void x_flush (struct frame *f); static void x_update_begin (struct frame *); static void x_update_window_begin (struct window *); -static struct scroll_bar *x_window_to_scroll_bar (Display *, Window); +static struct scroll_bar *x_window_to_scroll_bar (Display *, Window, int); static void x_scroll_bar_report_motion (struct frame **, Lisp_Object *, enum scroll_bar_part *, Lisp_Object *, Lisp_Object *, Time *); +static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object *, + enum scroll_bar_part *, + Lisp_Object *, Lisp_Object *, + Time *); static int x_handle_net_wm_state (struct frame *, const XPropertyEvent *); static void x_check_fullscreen (struct frame *); static void x_check_expected_move (struct frame *, int, int); @@ -268,6 +272,7 @@ static void x_wm_set_window_state (struct frame *, int); static void x_wm_set_icon_pixmap (struct frame *, ptrdiff_t); static void x_initialize (void); +static int get_current_wm_state (struct frame *, Window, int *, int *); /* Flush display of frame F. */ @@ -634,10 +639,8 @@ XTframe_up_to_date (struct frame *f) } -/* Clear under internal border if any for non-toolkit builds. */ - - -#if !defined USE_X_TOOLKIT && !defined USE_GTK +/* Clear under internal border if any (GTK has its own version). */ +#ifndef USE_GTK void x_clear_under_internal_border (struct frame *f) { @@ -3974,7 +3977,14 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, block_input (); if (dpyinfo->last_mouse_scroll_bar && insist == 0) - x_scroll_bar_report_motion (fp, bar_window, part, x, y, timestamp); + { + struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar; + + if (bar->horizontal) + x_horizontal_scroll_bar_report_motion (fp, bar_window, part, x, y, timestamp); + else + x_scroll_bar_report_motion (fp, bar_window, part, x, y, timestamp); + } else { Window root; @@ -4118,7 +4128,7 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, { struct scroll_bar *bar; - bar = x_window_to_scroll_bar (FRAME_X_DISPLAY (*fp), win); + bar = x_window_to_scroll_bar (FRAME_X_DISPLAY (*fp), win, 2); if (bar) { @@ -4173,7 +4183,7 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, bits. */ static struct scroll_bar * -x_window_to_scroll_bar (Display *display, Window window_id) +x_window_to_scroll_bar (Display *display, Window window_id, int type) { Lisp_Object tail, frame; @@ -4198,8 +4208,11 @@ x_window_to_scroll_bar (Display *display, Window window_id) condemned = Qnil, ! NILP (bar)); bar = XSCROLL_BAR (bar)->next) - if (XSCROLL_BAR (bar)->x_window == window_id && - FRAME_X_DISPLAY (XFRAME (frame)) == display) + if (XSCROLL_BAR (bar)->x_window == window_id + && FRAME_X_DISPLAY (XFRAME (frame)) == display + && (type = 2 + || (type == 1 && XSCROLL_BAR (bar)->horizontal) + || (type == 0 && !XSCROLL_BAR (bar)->horizontal))) return XSCROLL_BAR (bar); } @@ -4237,7 +4250,7 @@ x_window_to_menu_bar (Window window) #ifdef USE_TOOLKIT_SCROLL_BARS -static void x_send_scroll_bar_event (Lisp_Object, int, int, int); +static void x_send_scroll_bar_event (Lisp_Object, int, int, int, bool); /* Lisp window being scrolled. Set when starting to interact with a toolkit scroll bar, reset to nil when ending the interaction. */ @@ -4251,6 +4264,7 @@ static Lisp_Object window_being_scrolled; /* Id of action hook installed for scroll bars. */ static XtActionHookId action_hook_id; +static XtActionHookId horizontal_action_hook_id; static Boolean xaw3d_arrow_scroll; @@ -4288,7 +4302,7 @@ xt_action_hook (Widget widget, XtPointer client_data, String action_name, struct scroll_bar *bar; x_send_scroll_bar_event (window_being_scrolled, - scroll_bar_end_scroll, 0, 0); + scroll_bar_end_scroll, 0, 0, 0); w = XWINDOW (window_being_scrolled); bar = XSCROLL_BAR (w->vertical_scroll_bar); @@ -4306,6 +4320,49 @@ xt_action_hook (Widget widget, XtPointer client_data, String action_name, toolkit_scroll_bar_interaction = 0; } } + + +static void +xt_horizontal_action_hook (Widget widget, XtPointer client_data, String action_name, + XEvent *event, String *params, Cardinal *num_params) +{ + int scroll_bar_p; + const char *end_action; + +#ifdef USE_MOTIF + scroll_bar_p = XmIsScrollBar (widget); + end_action = "Release"; +#else /* !USE_MOTIF i.e. use Xaw */ + scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass); + end_action = "EndScroll"; +#endif /* USE_MOTIF */ + + if (scroll_bar_p + && strcmp (action_name, end_action) == 0 + && WINDOWP (window_being_scrolled)) + { + struct window *w; + struct scroll_bar *bar; + + x_send_scroll_bar_event (window_being_scrolled, + scroll_bar_end_scroll, 0, 0, 1); + w = XWINDOW (window_being_scrolled); + bar = XSCROLL_BAR (w->horizontal_scroll_bar); + + if (bar->dragging != -1) + { + bar->dragging = -1; + /* The thumb size is incorrect while dragging: fix it. */ + set_horizontal_scroll_bar (w); + } + window_being_scrolled = Qnil; +#if defined (USE_LUCID) + bar->last_seen_part = scroll_bar_nowhere; +#endif + /* Xt timeouts no longer needed. */ + toolkit_scroll_bar_interaction = 0; + } +} #endif /* not USE_GTK */ /* Send a client message with message type Xatom_Scrollbar for a @@ -4314,7 +4371,7 @@ xt_action_hook (Widget widget, XtPointer client_data, String action_name, amount to scroll of a whole of WHOLE. */ static void -x_send_scroll_bar_event (Lisp_Object window, int part, int portion, int whole) +x_send_scroll_bar_event (Lisp_Object window, int part, int portion, int whole, bool horizontal) { XEvent event; XClientMessageEvent *ev = &event.xclient; @@ -4329,7 +4386,9 @@ x_send_scroll_bar_event (Lisp_Object window, int part, int portion, int whole) /* Construct a ClientMessage event to send to the frame. */ ev->type = ClientMessage; - ev->message_type = FRAME_DISPLAY_INFO (f)->Xatom_Scrollbar; + ev->message_type = (horizontal + ? FRAME_DISPLAY_INFO (f)->Xatom_Horizontal_Scrollbar + : FRAME_DISPLAY_INFO (f)->Xatom_Scrollbar); ev->display = FRAME_X_DISPLAY (f); ev->window = FRAME_X_WINDOW (f); ev->format = 32; @@ -4394,6 +4453,41 @@ x_scroll_bar_to_input_event (const XEvent *event, ievent->modifiers = 0; } +/* Transform a horizontal scroll bar ClientMessage EVENT to an Emacs + input event in *IEVENT. */ + +static void +x_horizontal_scroll_bar_to_input_event (const XEvent *event, + struct input_event *ievent) +{ + const XClientMessageEvent *ev = &event->xclient; + Lisp_Object window; + struct window *w; + + /* See the comment in the function above. */ + intptr_t iw0 = ev->data.l[0]; + intptr_t iw1 = ev->data.l[1]; + intptr_t iw = (iw0 << 31 << 1) + (iw1 & 0xffffffffu); + w = (struct window *) iw; + + XSETWINDOW (window, w); + + ievent->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT; + ievent->frame_or_window = window; + ievent->arg = Qnil; +#ifdef USE_GTK + ievent->timestamp = CurrentTime; +#else + ievent->timestamp = + XtLastTimestampProcessed (FRAME_X_DISPLAY (XFRAME (w->frame))); +#endif + ievent->code = 0; + ievent->part = ev->data.l[2]; + ievent->x = make_number (ev->data.l[3]); + ievent->y = make_number (ev->data.l[4]); + ievent->modifiers = 0; +} + #ifdef USE_MOTIF @@ -4401,7 +4495,6 @@ x_scroll_bar_to_input_event (const XEvent *event, #define XM_SB_MAX 10000000 - /* Scroll bar callback for Motif scroll bars. WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the scroll_bar structure. CALL_DATA is a pointer to a XmScrollBarCallbackStruct. */ @@ -4412,51 +4505,65 @@ xm_scroll_callback (Widget widget, XtPointer client_data, XtPointer call_data) struct scroll_bar *bar = client_data; XmScrollBarCallbackStruct *cs = call_data; int part = -1, whole = 0, portion = 0; + int horizontal = bar->horizontal; switch (cs->reason) { case XmCR_DECREMENT: bar->dragging = -1; - part = scroll_bar_up_arrow; + part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break; case XmCR_INCREMENT: bar->dragging = -1; - part = scroll_bar_down_arrow; + part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break; case XmCR_PAGE_DECREMENT: bar->dragging = -1; - part = scroll_bar_above_handle; + part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break; case XmCR_PAGE_INCREMENT: bar->dragging = -1; - part = scroll_bar_below_handle; + part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break; case XmCR_TO_TOP: bar->dragging = -1; - part = scroll_bar_to_top; + part = horizontal ? scroll_bar_to_leftmost : scroll_bar_to_top; break; case XmCR_TO_BOTTOM: bar->dragging = -1; - part = scroll_bar_to_bottom; + part = horizontal ? scroll_bar_to_rightmost : scroll_bar_to_bottom; break; case XmCR_DRAG: { int slider_size; - /* Get the slider size. */ block_input (); XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL); unblock_input (); - whole = XM_SB_MAX - slider_size; - portion = min (cs->value, whole); - part = scroll_bar_handle; + if (horizontal) + { + whole = bar->whole; + portion = (((float) cs->value + / (XM_SB_MAX - slider_size)) + * (whole + - ((float) slider_size / XM_SB_MAX) * whole)); + portion = max (0, portion); + part = scroll_bar_horizontal_handle; + } + else + { + whole = XM_SB_MAX - slider_size; + portion = min (cs->value, whole); + part = scroll_bar_handle; + } + bar->dragging = cs->value; } break; @@ -4468,7 +4575,7 @@ xm_scroll_callback (Widget widget, XtPointer client_data, XtPointer call_data) if (part >= 0) { window_being_scrolled = bar->window; - x_send_scroll_bar_event (bar->window, part, portion, whole); + x_send_scroll_bar_event (bar->window, part, portion, whole, bar->horizontal); } } @@ -4497,27 +4604,42 @@ xg_scroll_callback (GtkRange *range, if (FRAME_DISPLAY_INFO (f)->grabbed != 0 && FRAME_DISPLAY_INFO (f)->grabbed < (1 << 4)) { - part = scroll_bar_handle; - whole = gtk_adjustment_get_upper (adj) - - gtk_adjustment_get_page_size (adj); - portion = min ((int)value, whole); - bar->dragging = portion; - } + if (bar->horizontal) + { + part = scroll_bar_horizontal_handle; + whole = (int)(gtk_adjustment_get_upper (adj) - + gtk_adjustment_get_page_size (adj)); + portion = min ((int)value, whole); + bar->dragging = portion; + } + else + { + part = scroll_bar_handle; + whole = gtk_adjustment_get_upper (adj) - + gtk_adjustment_get_page_size (adj); + portion = min ((int)value, whole); + bar->dragging = portion; + } + } break; case GTK_SCROLL_STEP_BACKWARD: - part = scroll_bar_up_arrow; + part = (bar->horizontal + ? scroll_bar_left_arrow : scroll_bar_up_arrow); bar->dragging = -1; break; case GTK_SCROLL_STEP_FORWARD: - part = scroll_bar_down_arrow; + part = (bar->horizontal + ? scroll_bar_right_arrow : scroll_bar_down_arrow); bar->dragging = -1; break; case GTK_SCROLL_PAGE_BACKWARD: - part = scroll_bar_above_handle; + part = (bar->horizontal + ? scroll_bar_before_handle : scroll_bar_above_handle); bar->dragging = -1; break; case GTK_SCROLL_PAGE_FORWARD: - part = scroll_bar_below_handle; + part = (bar->horizontal + ? scroll_bar_after_handle : scroll_bar_below_handle); bar->dragging = -1; break; } @@ -4525,7 +4647,7 @@ xg_scroll_callback (GtkRange *range, if (part >= 0) { window_being_scrolled = bar->window; - x_send_scroll_bar_event (bar->window, part, portion, whole); + x_send_scroll_bar_event (bar->window, part, portion, whole, bar->horizontal); } return FALSE; @@ -4543,7 +4665,7 @@ xg_end_scroll_callback (GtkWidget *widget, if (WINDOWP (window_being_scrolled)) { x_send_scroll_bar_event (window_being_scrolled, - scroll_bar_end_scroll, 0, 0); + scroll_bar_end_scroll, 0, 0, bar->horizontal); window_being_scrolled = Qnil; } @@ -4567,29 +4689,27 @@ xaw_jump_callback (Widget widget, XtPointer client_data, XtPointer call_data) float shown; int whole, portion, height; enum scroll_bar_part part; + int horizontal = bar->horizontal; /* Get the size of the thumb, a value between 0 and 1. */ block_input (); XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL); unblock_input (); - whole = 10000000; - portion = shown < 1 ? top * whole : 0; - - if (shown < 1 && (eabs (top + shown - 1) < 1.0f / height)) - /* Some derivatives of Xaw refuse to shrink the thumb when you reach - the bottom, so we force the scrolling whenever we see that we're - too close to the bottom (in x_set_toolkit_scroll_bar_thumb - we try to ensure that we always stay two pixels away from the - bottom). */ - part = scroll_bar_down_arrow; + if (horizontal) + { + whole = bar->whole; + portion = (top * (whole - (shown * whole))) / (1 - shown); + portion = max (0, portion); + part = scroll_bar_horizontal_handle; + } else part = scroll_bar_handle; window_being_scrolled = bar->window; bar->dragging = portion; bar->last_seen_part = part; - x_send_scroll_bar_event (bar->window, part, portion, whole); + x_send_scroll_bar_event (bar->window, part, portion, whole, bar->horizontal); } @@ -4628,12 +4748,13 @@ xaw_scroll_callback (Widget widget, XtPointer client_data, XtPointer call_data) window_being_scrolled = bar->window; bar->dragging = -1; bar->last_seen_part = part; - x_send_scroll_bar_event (bar->window, part, position, height); + x_send_scroll_bar_event (bar->window, part, position, height, bar->horizontal); } #endif /* not USE_GTK and not USE_MOTIF */ #define SCROLL_BAR_NAME "verticalScrollBar" +#define SCROLL_BAR_HORIZONTAL_NAME "horizontalScrollBar" /* Create the widget for scroll bar BAR on frame F. Record the widget and X window of the scroll bar in BAR. */ @@ -4651,6 +4772,18 @@ x_create_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar) unblock_input (); } +static void +x_create_horizontal_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar) +{ + const char *scroll_bar_name = SCROLL_BAR_HORIZONTAL_NAME; + + block_input (); + xg_create_horizontal_scroll_bar (f, bar, G_CALLBACK (xg_scroll_callback), + G_CALLBACK (xg_end_scroll_callback), + scroll_bar_name); + unblock_input (); +} + #else /* not USE_GTK */ static void @@ -4846,6 +4979,208 @@ x_create_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar) SET_SCROLL_BAR_X_WIDGET (bar, widget); xwindow = XtWindow (widget); bar->x_window = xwindow; + bar->whole = 1; + bar->horizontal = 0; + + unblock_input (); +} + +static void +x_create_horizontal_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar) +{ + Window xwindow; + Widget widget; + Arg av[20]; + int ac = 0; + const char *scroll_bar_name = SCROLL_BAR_HORIZONTAL_NAME; + unsigned long pixel; + + block_input (); + +#ifdef USE_MOTIF + /* Set resources. Create the widget. */ + XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac; + XtSetArg (av[ac], XmNminimum, 0); ++ac; + XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac; + XtSetArg (av[ac], XmNorientation, XmHORIZONTAL); ++ac; + XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_RIGHT), ++ac; + XtSetArg (av[ac], XmNincrement, 1); ++ac; + XtSetArg (av[ac], XmNpageIncrement, 1); ++ac; + + pixel = f->output_data.x->scroll_bar_foreground_pixel; + if (pixel != -1) + { + XtSetArg (av[ac], XmNforeground, pixel); + ++ac; + } + + pixel = f->output_data.x->scroll_bar_background_pixel; + if (pixel != -1) + { + XtSetArg (av[ac], XmNbackground, pixel); + ++ac; + } + + widget = XmCreateScrollBar (f->output_data.x->edit_widget, + (char *) scroll_bar_name, av, ac); + + /* Add one callback for everything that can happen. */ + XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback, + (XtPointer) bar); + XtAddCallback (widget, XmNdragCallback, xm_scroll_callback, + (XtPointer) bar); + XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback, + (XtPointer) bar); + XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback, + (XtPointer) bar); + XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback, + (XtPointer) bar); + XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback, + (XtPointer) bar); + XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback, + (XtPointer) bar); + + /* Realize the widget. Only after that is the X window created. */ + XtRealizeWidget (widget); + + /* Set the cursor to an arrow. I didn't find a resource to do that. + And I'm wondering why it hasn't an arrow cursor by default. */ + XDefineCursor (XtDisplay (widget), XtWindow (widget), + f->output_data.x->nontext_cursor); + +#else /* !USE_MOTIF i.e. use Xaw */ + + /* Set resources. Create the widget. The background of the + Xaw3d scroll bar widget is a little bit light for my taste. + We don't alter it here to let users change it according + to their taste with `emacs*verticalScrollBar.background: xxx'. */ + XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac; + XtSetArg (av[ac], XtNorientation, XtorientHorizontal); ++ac; + /* For smoother scrolling with Xaw3d -sm */ + /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */ + + pixel = f->output_data.x->scroll_bar_foreground_pixel; + if (pixel != -1) + { + XtSetArg (av[ac], XtNforeground, pixel); + ++ac; + } + + pixel = f->output_data.x->scroll_bar_background_pixel; + if (pixel != -1) + { + XtSetArg (av[ac], XtNbackground, pixel); + ++ac; + } + + /* Top/bottom shadow colors. */ + + /* Allocate them, if necessary. */ + if (f->output_data.x->scroll_bar_top_shadow_pixel == -1) + { + pixel = f->output_data.x->scroll_bar_background_pixel; + if (pixel != -1) + { + if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), + FRAME_X_COLORMAP (f), + &pixel, 1.2, 0x8000)) + pixel = -1; + f->output_data.x->scroll_bar_top_shadow_pixel = pixel; + } + } + if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1) + { + pixel = f->output_data.x->scroll_bar_background_pixel; + if (pixel != -1) + { + if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), + FRAME_X_COLORMAP (f), + &pixel, 0.6, 0x4000)) + pixel = -1; + f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel; + } + } + +#ifdef XtNbeNiceToColormap + /* Tell the toolkit about them. */ + if (f->output_data.x->scroll_bar_top_shadow_pixel == -1 + || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1) + /* We tried to allocate a color for the top/bottom shadow, and + failed, so tell Xaw3d to use dithering instead. */ + /* But only if we have a small colormap. Xaw3d can allocate nice + colors itself. */ + { + XtSetArg (av[ac], XtNbeNiceToColormap, + DefaultDepthOfScreen (FRAME_X_SCREEN (f)) < 16); + ++ac; + } + else + /* Tell what colors Xaw3d should use for the top/bottom shadow, to + be more consistent with other emacs 3d colors, and since Xaw3d is + not good at dealing with allocation failure. */ + { + /* This tells Xaw3d to use real colors instead of dithering for + the shadows. */ + XtSetArg (av[ac], XtNbeNiceToColormap, False); + ++ac; + + /* Specify the colors. */ + pixel = f->output_data.x->scroll_bar_top_shadow_pixel; + if (pixel != -1) + { + XtSetArg (av[ac], XtNtopShadowPixel, pixel); + ++ac; + } + pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel; + if (pixel != -1) + { + XtSetArg (av[ac], XtNbottomShadowPixel, pixel); + ++ac; + } + } +#endif + + widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass, + f->output_data.x->edit_widget, av, ac); + + { + char const *initial = ""; + char const *val = initial; + XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val, +#ifdef XtNarrowScrollbars + XtNarrowScrollbars, (XtPointer) &xaw3d_arrow_scroll, +#endif + XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL); + if (xaw3d_arrow_scroll || val == initial) + { /* ARROW_SCROLL */ + xaw3d_arrow_scroll = True; + /* Isn't that just a personal preference ? --Stef */ + XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL); + } + } + + /* Define callbacks. */ + XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar); + XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback, + (XtPointer) bar); + + /* Realize the widget. Only after that is the X window created. */ + XtRealizeWidget (widget); + +#endif /* !USE_MOTIF */ + + /* Install an action hook that lets us detect when the user + finishes interacting with a scroll bar. */ + if (horizontal_action_hook_id == 0) + horizontal_action_hook_id + = XtAppAddActionHook (Xt_app_con, xt_horizontal_action_hook, 0); + + /* Remember X window and widget in the scroll bar vector. */ + SET_SCROLL_BAR_X_WIDGET (bar, widget); + xwindow = XtWindow (widget); + bar->x_window = xwindow; + bar->whole = 1; + bar->horizontal = 1; unblock_input (); } @@ -4862,6 +5197,12 @@ x_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, int portion, int positio xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole); } +static void +x_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position, int whole) +{ + xg_set_toolkit_horizontal_scroll_bar_thumb (bar, portion, position, whole); +} + #else /* not USE_GTK */ static void x_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position, @@ -4974,6 +5315,89 @@ x_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, int portion, int positio unblock_input (); } + +static void +x_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position, + int whole) +{ + struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); + Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar); + float top, shown; + + block_input (); + +#ifdef USE_MOTIF + bar->whole = whole; + shown = (float) portion / whole; + top = (float) position / (whole - portion); + { + int size = clip_to_bounds (1, shown * XM_SB_MAX, XM_SB_MAX); + int value = clip_to_bounds (0, top * (XM_SB_MAX - size), XM_SB_MAX - size); + + XmScrollBarSetValues (widget, value, size, 0, 0, False); + } +#else /* !USE_MOTIF i.e. use Xaw */ + bar->whole = whole; + if (whole == 0) + top = 0, shown = 1; + else + { + top = (float) position / whole; + shown = (float) portion / whole; + } + + { + float old_top, old_shown; + Dimension height; + XtVaGetValues (widget, + XtNtopOfThumb, &old_top, + XtNshown, &old_shown, + XtNheight, &height, + NULL); + +#if 0 + /* Massage the top+shown values. */ + if (bar->dragging == -1 || bar->last_seen_part == scroll_bar_down_arrow) + top = max (0, min (1, top)); + else + top = old_top; +#if ! defined (HAVE_XAW3D) + /* With Xaw, 'top' values too closer to 1.0 may + cause the thumb to disappear. Fix that. */ + top = min (top, 0.99f); +#endif + /* Keep two pixels available for moving the thumb down. */ + shown = max (0, min (1 - top - (2.0f / height), shown)); +#if ! defined (HAVE_XAW3D) + /* Likewise with too small 'shown'. */ + shown = max (shown, 0.01f); +#endif +#endif + + /* If the call to XawScrollbarSetThumb below doesn't seem to + work, check that 'NARROWPROTO' is defined in src/config.h. + If this is not so, most likely you need to fix configure. */ + XawScrollbarSetThumb (widget, top, shown); +#if 0 + if (top != old_top || shown != old_shown) + { + if (bar->dragging == -1) + XawScrollbarSetThumb (widget, top, shown); + else + { + /* Try to make the scrolling a tad smoother. */ + if (!xaw3d_pick_top) + shown = min (shown, old_shown); + + XawScrollbarSetThumb (widget, top, shown); + } + } +#endif + } +#endif /* !USE_MOTIF */ + + unblock_input (); +} #endif /* not USE_GTK */ #endif /* USE_TOOLKIT_SCROLL_BARS */ @@ -4990,7 +5414,7 @@ x_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, int portion, int positio scroll bar. */ static struct scroll_bar * -x_scroll_bar_create (struct window *w, int top, int left, int width, int height) +x_scroll_bar_create (struct window *w, int top, int left, int width, int height, bool horizontal) { struct frame *f = XFRAME (w->frame); struct scroll_bar *bar @@ -5000,7 +5424,10 @@ x_scroll_bar_create (struct window *w, int top, int left, int width, int height) block_input (); #ifdef USE_TOOLKIT_SCROLL_BARS - x_create_toolkit_scroll_bar (f, bar); + if (horizontal) + x_create_horizontal_toolkit_scroll_bar (f, bar); + else + x_create_toolkit_scroll_bar (f, bar); #else /* not USE_TOOLKIT_SCROLL_BARS */ { XSetWindowAttributes a; @@ -5063,8 +5490,12 @@ x_scroll_bar_create (struct window *w, int top, int left, int width, int height) #ifdef USE_TOOLKIT_SCROLL_BARS { #ifdef USE_GTK - xg_update_scrollbar_pos (f, bar->x_window, top, - left,width, max (height, 1)); + if (horizontal) + xg_update_horizontal_scrollbar_pos (f, bar->x_window, top, + left, width, max (height, 1)); + else + xg_update_scrollbar_pos (f, bar->x_window, top, + left, width, max (height, 1)); #else /* not USE_GTK */ Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar); XtConfigureWidget (scroll_bar, left, top, width, max (height, 1), 0); @@ -5148,7 +5579,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end, int rebuild /* Draw the empty space above the handle. Note that we can't clear zero-height areas; that means "clear to end of window." */ - if (start > 0) + if ((inside_width > 0) && (start > 0)) x_clear_area (FRAME_X_DISPLAY (f), w, VERTICAL_SCROLL_BAR_LEFT_BORDER, VERTICAL_SCROLL_BAR_TOP_BORDER, @@ -5173,7 +5604,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end, int rebuild /* Draw the empty space below the handle. Note that we can't clear zero-height areas; that means "clear to end of window." */ - if (end < inside_height) + if ((inside_width > 0) && (end < inside_height)) x_clear_area (FRAME_X_DISPLAY (f), w, VERTICAL_SCROLL_BAR_LEFT_BORDER, VERTICAL_SCROLL_BAR_TOP_BORDER + end, @@ -5205,7 +5636,10 @@ x_scroll_bar_remove (struct scroll_bar *bar) #endif /* Dissociate this scroll bar from its window. */ - wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil); + if (bar->horizontal) + wset_horizontal_scroll_bar (XWINDOW (bar->window), Qnil); + else + wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil); unblock_input (); } @@ -5229,8 +5663,6 @@ XTset_vertical_scroll_bar (struct window *w, int portion, int whole, int positio window_box (w, ANY_AREA, 0, &window_y, 0, &window_height); top = window_y; height = window_height; - - /* Compute the left edge and the width of the scroll bar area. */ left = WINDOW_SCROLL_BAR_AREA_X (w); width = WINDOW_SCROLL_BAR_AREA_WIDTH (w); @@ -5245,7 +5677,7 @@ XTset_vertical_scroll_bar (struct window *w, int portion, int whole, int positio unblock_input (); } - bar = x_scroll_bar_create (w, top, left, width, max (height, 1)); + bar = x_scroll_bar_create (w, top, left, width, max (height, 1), 0); } else { @@ -5334,6 +5766,138 @@ XTset_vertical_scroll_bar (struct window *w, int portion, int whole, int positio } +static void +XTset_horizontal_scroll_bar (struct window *w, int portion, int whole, int position) +{ + struct frame *f = XFRAME (w->frame); + Lisp_Object barobj; + struct scroll_bar *bar; + int top, height, left, width; + int window_x, window_width; + int pixel_width = WINDOW_PIXEL_WIDTH (w); + + /* Get window dimensions. */ + window_box (w, ANY_AREA, &window_x, 0, &window_width, 0); + left = window_x; + width = window_width; + top = WINDOW_SCROLL_BAR_AREA_Y (w); + height = WINDOW_SCROLL_BAR_AREA_HEIGHT (w); + + /* Does the scroll bar exist yet? */ + if (NILP (w->horizontal_scroll_bar)) + { + if (width > 0 && height > 0) + { + block_input (); + + /* Clear also part between window_width and + WINDOW_PIXEL_WIDTH. */ + x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + left, top, pixel_width, height); + unblock_input (); + } + + bar = x_scroll_bar_create (w, top, left, width, height, 1); + } + else + { + /* It may just need to be moved and resized. */ + unsigned int mask = 0; + + bar = XSCROLL_BAR (w->horizontal_scroll_bar); + + block_input (); + + if (left != bar->left) + mask |= CWX; + if (top != bar->top) + mask |= CWY; + if (width != bar->width) + mask |= CWWidth; + if (height != bar->height) + mask |= CWHeight; + +#ifdef USE_TOOLKIT_SCROLL_BARS + /* Move/size the scroll bar widget. */ + if (mask) + { + /* Since toolkit scroll bars are smaller than the space reserved + for them on the frame, we have to clear "under" them. */ + if (width > 0 && height > 0) + x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + WINDOW_LEFT_EDGE_X (w), top, + pixel_width - WINDOW_RIGHT_DIVIDER_WIDTH (w), height); +#ifdef USE_GTK + xg_update_horizontal_scrollbar_pos (f, bar->x_window, top, left, + width, height); +#else /* not USE_GTK */ + XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar), + left, top, width, height, 0); +#endif /* not USE_GTK */ + } +#else /* not USE_TOOLKIT_SCROLL_BARS */ + + /* Clear areas not covered by the scroll bar because it's not as + wide as the area reserved for it. This makes sure a + previous mode line display is cleared after C-x 2 C-x 1, for + example. */ + { + int area_height = WINDOW_CONFIG_SCROLL_BAR_HEIGHT (w); + int rest = area_height - height; + if (rest > 0 && width > 0) + x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + left, top, width, rest); + } + + /* Move/size the scroll bar window. */ + if (mask) + { + XWindowChanges wc; + + wc.x = left; + wc.y = top; + wc.width = width; + wc.height = height; + XConfigureWindow (FRAME_X_DISPLAY (f), bar->x_window, + mask, &wc); + } + +#endif /* not USE_TOOLKIT_SCROLL_BARS */ + + /* Remember new settings. */ + bar->left = left; + bar->top = top; + bar->width = width; + bar->height = height; + + unblock_input (); + } + +#ifdef USE_TOOLKIT_SCROLL_BARS + x_set_toolkit_horizontal_scroll_bar_thumb (bar, portion, position, whole); +#else /* not USE_TOOLKIT_SCROLL_BARS */ + /* Set the scroll bar's current state, unless we're currently being + dragged. */ + if (bar->dragging == -1) + { + int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, width); + + if (whole == 0) + x_scroll_bar_set_handle (bar, 0, left_range, 0); + else + { + int start = ((double) position * left_range) / whole; + int end = ((double) (position + portion) * left_range) / whole; + x_scroll_bar_set_handle (bar, start, end, 0); + } + } +#endif /* not USE_TOOLKIT_SCROLL_BARS */ + + XSETVECTOR (barobj, bar); + wset_horizontal_scroll_bar (w, barobj); +} + + /* The following three hooks are used when we're doing a thorough redisplay of the frame. We don't explicitly know which scroll bars are going to be deleted, because keeping track of when windows go @@ -5349,17 +5913,22 @@ XTset_vertical_scroll_bar (struct window *w, int portion, int whole, int positio static void XTcondemn_scroll_bars (struct frame *frame) { - /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */ - while (! NILP (FRAME_SCROLL_BARS (frame))) + if (!NILP (FRAME_SCROLL_BARS (frame))) { - Lisp_Object bar; - bar = FRAME_SCROLL_BARS (frame); - fset_scroll_bars (frame, XSCROLL_BAR (bar)->next); - XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame); - XSCROLL_BAR (bar)->prev = Qnil; - if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame))) - XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar; - fset_condemned_scroll_bars (frame, bar); + if (!NILP (FRAME_CONDEMNED_SCROLL_BARS (frame))) + { + /* Prepend scrollbars to already condemned ones. */ + Lisp_Object last = FRAME_SCROLL_BARS (frame); + + while (!NILP (XSCROLL_BAR (last)->next)) + last = XSCROLL_BAR (last)->next; + + XSCROLL_BAR (last)->next = FRAME_CONDEMNED_SCROLL_BARS (frame); + XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = last; + } + + fset_condemned_scroll_bars (frame, FRAME_SCROLL_BARS (frame)); + fset_scroll_bars (frame, Qnil); } } @@ -5368,47 +5937,84 @@ XTcondemn_scroll_bars (struct frame *frame) Note that WINDOW isn't necessarily condemned at all. */ static void -XTredeem_scroll_bar (struct window *window) +XTredeem_scroll_bar (struct window *w) { struct scroll_bar *bar; - struct frame *f; Lisp_Object barobj; + struct frame *f; /* We can't redeem this window's scroll bar if it doesn't have one. */ - if (NILP (window->vertical_scroll_bar)) + if (NILP (w->vertical_scroll_bar) && NILP (w->horizontal_scroll_bar)) emacs_abort (); - bar = XSCROLL_BAR (window->vertical_scroll_bar); - - /* Unlink it from the condemned list. */ - f = XFRAME (WINDOW_FRAME (window)); - if (NILP (bar->prev)) + if (!NILP (w->vertical_scroll_bar) && WINDOW_HAS_VERTICAL_SCROLL_BAR (w)) { - /* If the prev pointer is nil, it must be the first in one of - the lists. */ - if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar)) - /* It's not condemned. Everything's fine. */ - return; - else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f), - window->vertical_scroll_bar)) - fset_condemned_scroll_bars (f, bar->next); + bar = XSCROLL_BAR (w->vertical_scroll_bar); + /* Unlink it from the condemned list. */ + f = XFRAME (WINDOW_FRAME (w)); + if (NILP (bar->prev)) + { + /* If the prev pointer is nil, it must be the first in one of + the lists. */ + if (EQ (FRAME_SCROLL_BARS (f), w->vertical_scroll_bar)) + /* It's not condemned. Everything's fine. */ + goto horizontal; + else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f), + w->vertical_scroll_bar)) + fset_condemned_scroll_bars (f, bar->next); + else + /* If its prev pointer is nil, it must be at the front of + one or the other! */ + emacs_abort (); + } else - /* If its prev pointer is nil, it must be at the front of - one or the other! */ - emacs_abort (); + XSCROLL_BAR (bar->prev)->next = bar->next; + + if (! NILP (bar->next)) + XSCROLL_BAR (bar->next)->prev = bar->prev; + + bar->next = FRAME_SCROLL_BARS (f); + bar->prev = Qnil; + XSETVECTOR (barobj, bar); + fset_scroll_bars (f, barobj); + if (! NILP (bar->next)) + XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar); } - else - XSCROLL_BAR (bar->prev)->next = bar->next; - if (! NILP (bar->next)) - XSCROLL_BAR (bar->next)->prev = bar->prev; + horizontal: + if (!NILP (w->horizontal_scroll_bar) && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w)) + { + bar = XSCROLL_BAR (w->horizontal_scroll_bar); + /* Unlink it from the condemned list. */ + f = XFRAME (WINDOW_FRAME (w)); + if (NILP (bar->prev)) + { + /* If the prev pointer is nil, it must be the first in one of + the lists. */ + if (EQ (FRAME_SCROLL_BARS (f), w->horizontal_scroll_bar)) + /* It's not condemned. Everything's fine. */ + return; + else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f), + w->horizontal_scroll_bar)) + fset_condemned_scroll_bars (f, bar->next); + else + /* If its prev pointer is nil, it must be at the front of + one or the other! */ + emacs_abort (); + } + else + XSCROLL_BAR (bar->prev)->next = bar->next; + + if (! NILP (bar->next)) + XSCROLL_BAR (bar->next)->prev = bar->prev; - bar->next = FRAME_SCROLL_BARS (f); - bar->prev = Qnil; - XSETVECTOR (barobj, bar); - fset_scroll_bars (f, barobj); - if (! NILP (bar->next)) - XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar); + bar->next = FRAME_SCROLL_BARS (f); + bar->prev = Qnil; + XSETVECTOR (barobj, bar); + fset_scroll_bars (f, barobj); + if (! NILP (bar->next)) + XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar); + } } /* Remove all scroll bars on FRAME that haven't been saved since the @@ -5493,7 +6099,9 @@ x_scroll_bar_handle_click (struct scroll_bar *bar, if (! WINDOWP (bar->window)) emacs_abort (); - emacs_event->kind = SCROLL_BAR_CLICK_EVENT; + emacs_event->kind = (bar->horizontal + ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT + : SCROLL_BAR_CLICK_EVENT); emacs_event->code = event->xbutton.button - Button1; emacs_event->modifiers = (x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO @@ -5505,36 +6113,68 @@ x_scroll_bar_handle_click (struct scroll_bar *bar, emacs_event->frame_or_window = bar->window; emacs_event->arg = Qnil; emacs_event->timestamp = event->xbutton.time; - { - int top_range - = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height); - int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER; + if (bar->horizontal) + { + int left_range + = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width); + int x = event->xbutton.x - HORIZONTAL_SCROLL_BAR_LEFT_BORDER; - if (y < 0) y = 0; - if (y > top_range) y = top_range; + if (x < 0) x = 0; + if (x > left_range) x = left_range; - if (y < bar->start) - emacs_event->part = scroll_bar_above_handle; - else if (y < bar->end + VERTICAL_SCROLL_BAR_MIN_HANDLE) - emacs_event->part = scroll_bar_handle; - else - emacs_event->part = scroll_bar_below_handle; + if (x < bar->start) + emacs_event->part = scroll_bar_before_handle; + else if (x < bar->end + HORIZONTAL_SCROLL_BAR_MIN_HANDLE) + emacs_event->part = scroll_bar_horizontal_handle; + else + emacs_event->part = scroll_bar_after_handle; #ifndef USE_TOOLKIT_SCROLL_BARS - /* If the user has released the handle, set it to its final position. */ - if (event->type == ButtonRelease && bar->dragging != -1) - { - int new_start = y - bar->dragging; - int new_end = new_start + bar->end - bar->start; + /* If the user has released the handle, set it to its final position. */ + if (event->type == ButtonRelease && bar->dragging != -1) + { + int new_start = - bar->dragging; + int new_end = new_start + bar->end - bar->start; - x_scroll_bar_set_handle (bar, new_start, new_end, 0); - bar->dragging = -1; - } + x_scroll_bar_set_handle (bar, new_start, new_end, 0); + bar->dragging = -1; + } #endif - XSETINT (emacs_event->x, y); - XSETINT (emacs_event->y, top_range); - } + XSETINT (emacs_event->x, left_range); + XSETINT (emacs_event->y, x); + } + else + { + int top_range + = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height); + int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER; + + if (y < 0) y = 0; + if (y > top_range) y = top_range; + + if (y < bar->start) + emacs_event->part = scroll_bar_above_handle; + else if (y < bar->end + VERTICAL_SCROLL_BAR_MIN_HANDLE) + emacs_event->part = scroll_bar_handle; + else + emacs_event->part = scroll_bar_below_handle; + +#ifndef USE_TOOLKIT_SCROLL_BARS + /* If the user has released the handle, set it to its final position. */ + if (event->type == ButtonRelease && bar->dragging != -1) + { + int new_start = y - bar->dragging; + int new_end = new_start + bar->end - bar->start; + + x_scroll_bar_set_handle (bar, new_start, new_end, 0); + bar->dragging = -1; + } +#endif + + XSETINT (emacs_event->x, y); + XSETINT (emacs_event->y, top_range); + } } #ifndef USE_TOOLKIT_SCROLL_BARS @@ -5641,6 +6281,75 @@ x_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window, } +/* Return information to the user about the current position of the mouse + on the scroll bar. */ + +static void +x_horizontal_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window, + enum scroll_bar_part *part, Lisp_Object *x, + Lisp_Object *y, Time *timestamp) +{ + struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp); + struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar; + Window w = bar->x_window; + struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); + int win_x, win_y; + Window dummy_window; + int dummy_coord; + unsigned int dummy_mask; + + block_input (); + + /* Get the mouse's position relative to the scroll bar window, and + report that. */ + if (XQueryPointer (FRAME_X_DISPLAY (f), w, + + /* Root, child, root x and root y. */ + &dummy_window, &dummy_window, + &dummy_coord, &dummy_coord, + + /* Position relative to scroll bar. */ + &win_x, &win_y, + + /* Mouse buttons and modifier keys. */ + &dummy_mask)) + { + int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width); + + win_x -= HORIZONTAL_SCROLL_BAR_LEFT_BORDER; + + if (bar->dragging != -1) + win_x -= bar->dragging; + + if (win_x < 0) + win_x = 0; + if (win_x > left_range) + win_x = left_range; + + *fp = f; + *bar_window = bar->window; + + if (bar->dragging != -1) + *part = scroll_bar_horizontal_handle; + else if (win_x < bar->start) + *part = scroll_bar_before_handle; + else if (win_x < bar->end + HORIZONTAL_SCROLL_BAR_MIN_HANDLE) + *part = scroll_bar_handle; + else + *part = scroll_bar_after_handle; + + XSETINT (*y, win_x); + XSETINT (*x, left_range); + + f->mouse_moved = 0; + dpyinfo->last_mouse_scroll_bar = NULL; + *timestamp = dpyinfo->last_mouse_movement_time; + } + + unblock_input (); +} + + /* The screen has been cleared so we may have changed foreground or background colors, and the scroll bars may need to be redrawn. Clear out the scroll bars, and ask for expose events, so we can @@ -5783,6 +6492,35 @@ static void xembed_send_message (struct frame *f, Time, enum xembed_message, long detail, long data1, long data2); +static void +x_net_wm_state (struct frame *f, Window window) +{ + int value = FULLSCREEN_NONE; + Lisp_Object lval = Qnil; + int sticky = 0; + + (void)get_current_wm_state (f, window, &value, &sticky); + + switch (value) + { + case FULLSCREEN_WIDTH: + lval = Qfullwidth; + break; + case FULLSCREEN_HEIGHT: + lval = Qfullheight; + break; + case FULLSCREEN_BOTH: + lval = Qfullboth; + break; + case FULLSCREEN_MAXIMIZED: + lval = Qmaximized; + break; + } + + store_frame_param (f, Qfullscreen, lval); +/** store_frame_param (f, Qsticky, sticky ? Qt : Qnil); **/ +} + /* Handles the XEvent EVENT on display DPYINFO. *FINISH is X_EVENT_GOTO_OUT if caller should stop reading events. @@ -5980,6 +6718,12 @@ handle_one_xevent (struct x_display_info *dpyinfo, *finish = X_EVENT_GOTO_OUT; goto done; } + else if (event->xclient.message_type == dpyinfo->Xatom_Horizontal_Scrollbar) + { + x_horizontal_scroll_bar_to_input_event (event, &inev.ie); + *finish = X_EVENT_GOTO_OUT; + goto done; + } #endif /* USE_TOOLKIT_SCROLL_BARS */ /* XEmbed messages from the embedder (if any). */ @@ -6131,7 +6875,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, goto OTHER; #else /* not USE_TOOLKIT_SCROLL_BARS */ bar = x_window_to_scroll_bar (event->xexpose.display, - event->xexpose.window); + event->xexpose.window, 2); if (bar) x_scroll_bar_expose (bar, event); @@ -6695,7 +7439,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, #ifndef USE_TOOLKIT_SCROLL_BARS struct scroll_bar *bar = x_window_to_scroll_bar (event->xmotion.display, - event->xmotion.window); + event->xmotion.window, 2); if (bar) x_scroll_bar_note_movement (bar, &event->xmotion); @@ -6728,6 +7472,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, #endif if (f) { + x_net_wm_state (f, event->xconfigure.window); + #ifndef USE_X_TOOLKIT #ifndef USE_GTK int width = FRAME_PIXEL_TO_TEXT_WIDTH (f, event->xconfigure.width); @@ -6838,7 +7584,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, { struct scroll_bar *bar = x_window_to_scroll_bar (event->xbutton.display, - event->xbutton.window); + event->xbutton.window, 2); #ifdef USE_TOOLKIT_SCROLL_BARS /* Make the "Ctrl-Mouse-2 splits window" work for toolkit @@ -7824,10 +8570,10 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset) FRAME_COLUMN_WIDTH (f) = font->average_width; FRAME_LINE_HEIGHT (f) = FONT_HEIGHT (font); - FRAME_TOOL_BAR_HEIGHT (f) = FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f); +#ifndef USE_X_TOOLKIT \ +/** FRAME_TOOL_BAR_HEIGHT (f) = FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f); **/ FRAME_MENU_BAR_HEIGHT (f) = FRAME_MENU_BAR_LINES (f) * FRAME_LINE_HEIGHT (f); - - compute_fringe_widths (f, 1); +#endif /* Compute character columns occupied by scrollbar. @@ -8658,7 +9404,7 @@ x_wait_for_event (struct frame *f, int eventtype) } -/* Change the size of frame F's X window to COLS/ROWS in the case F +/* Change the size of frame F's X window to WIDTH/HEIGHT in the case F doesn't have a widget. If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity for this size change and subsequent size changes. Otherwise we leave the window gravity unchanged. */ @@ -8668,23 +9414,39 @@ x_set_window_size_1 (struct frame *f, int change_gravity, int width, int height, { int pixelwidth, pixelheight; - check_frame_size (f, &width, &height, pixelwise); - - compute_fringe_widths (f, 0); - - pixelwidth = ((pixelwise - ? FRAME_TEXT_TO_PIXEL_WIDTH (f, width) - : FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width)) - + FRAME_TOOLBAR_WIDTH (f)); +/** if (pixelwise) **/ +/** { **/ +/** pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width); **/ +/** pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height); **/ +/** } **/ +/** else **/ +/** { **/ +/** pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width); **/ +/** pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height); **/ +/** } **/ + +/** FRAME_TOOL_BAR_HEIGHT (f) = FRAME_TOOLBAR_HEIGHT (f); **/ + pixelwidth = (pixelwise + ? FRAME_TEXT_TO_PIXEL_WIDTH (f, width) + : FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width)); pixelheight = ((pixelwise ? FRAME_TEXT_TO_PIXEL_HEIGHT (f, height) - : FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height)) - + FRAME_MENUBAR_HEIGHT (f) - + FRAME_TOOLBAR_HEIGHT (f)); + : FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height))); + +/** pixelwidth = ((pixelwise ? width : (width * FRAME_COLUMN_WIDTH (f))) **/ +/** + FRAME_SCROLL_BAR_AREA_WIDTH (f) **/ +/** + FRAME_TOTAL_FRINGE_WIDTH (f) **/ +/** + 2 * FRAME_INTERNAL_BORDER_WIDTH (f)); **/ + +/** pixelheight = ((pixelwise ? height : (height * FRAME_LINE_HEIGHT (f))) **/ +/** + FRAME_TOOLBAR_HEIGHT (f) **/ +/** + FRAME_SCROLL_BAR_AREA_HEIGHT (f) **/ +/** + 2 * FRAME_INTERNAL_BORDER_WIDTH (f)); **/ + if (change_gravity) f->win_gravity = NorthWestGravity; x_wm_set_size_hint (f, 0, 0); XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), - pixelwidth, pixelheight); + pixelwidth, pixelheight + FRAME_MENUBAR_HEIGHT (f)); /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to @@ -8714,7 +9476,7 @@ x_set_window_size_1 (struct frame *f, int change_gravity, int width, int height, x_wait_for_event (f, ConfigureNotify); else { - change_frame_size (f, width, height, 0, 1, 0, 1); + change_frame_size (f, pixelwidth, pixelheight, 0, 1, 0, 1); x_sync (f); } } @@ -8730,8 +9492,9 @@ x_set_window_size (struct frame *f, int change_gravity, int width, int height, b { block_input (); - check_frame_size (f, &width, &height, pixelwise); - + /* The following breaks our calculations. If it's really needed, + think of something else. */ +#if 0 if (NILP (tip_frame) || XFRAME (tip_frame) != f) { int text_width, text_height; @@ -8754,6 +9517,7 @@ x_set_window_size (struct frame *f, int change_gravity, int width, int height, b change_frame_size (f, text_width, text_height, 0, 1, 0, 1); } +#endif #ifdef USE_GTK if (FRAME_GTK_WIDGET (f)) @@ -8767,9 +9531,7 @@ x_set_window_size (struct frame *f, int change_gravity, int width, int height, b #else /* not USE_GTK */ x_set_window_size_1 (f, change_gravity, width, height, pixelwise); -#if !defined USE_X_TOOLKIT x_clear_under_internal_border (f); -#endif #endif /* not USE_GTK */ @@ -8783,6 +9545,8 @@ x_set_window_size (struct frame *f, int change_gravity, int width, int height, b cancel_mouse_face (f); unblock_input (); + + do_pending_window_change (0); } /* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */ @@ -9419,6 +10183,9 @@ x_wm_set_size_hint (struct frame *f, long flags, bool user_position) XSizeHints size_hints; Window window = FRAME_OUTER_WINDOW (f); + if (!window) + return; + #ifdef USE_X_TOOLKIT if (f->output_data.x->widget) { @@ -9452,8 +10219,6 @@ x_wm_set_size_hint (struct frame *f, long flags, bool user_position) base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0); base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0); - check_frame_size (f, &min_cols, &min_rows, 0); - if (frame_resize_pixelwise) /* Needed to prevent a bad protocol error crash when making the frame size very small. */ @@ -10079,6 +10844,9 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) dpyinfo->vertical_scroll_bar_cursor = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow); + dpyinfo->horizontal_scroll_bar_cursor + = XCreateFontCursor (dpyinfo->display, XC_sb_h_double_arrow); + xrdb = x_load_resources (dpyinfo->display, xrm_option, resource_name, EMACS_CLASS); #ifdef HAVE_XRMSETDATABASE @@ -10214,6 +10982,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) ATOM_REFS_INIT ("DONE", Xatom_DONE) ATOM_REFS_INIT ("PAGE", Xatom_PAGE) ATOM_REFS_INIT ("SCROLLBAR", Xatom_Scrollbar) + ATOM_REFS_INIT ("HORIZONTAL_SCROLLBAR", Xatom_Horizontal_Scrollbar) ATOM_REFS_INIT ("_XEMBED", Xatom_XEMBED) /* EWMH */ ATOM_REFS_INIT ("_NET_WM_STATE", Xatom_net_wm_state) @@ -10602,6 +11371,7 @@ x_create_terminal (struct x_display_info *dpyinfo) terminal->popup_dialog_hook = xw_popup_dialog; #endif terminal->set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar; + terminal->set_horizontal_scroll_bar_hook = XTset_horizontal_scroll_bar; terminal->condemn_scroll_bars_hook = XTcondemn_scroll_bars; terminal->redeem_scroll_bar_hook = XTredeem_scroll_bar; terminal->judge_scroll_bars_hook = XTjudge_scroll_bars; diff --git a/src/xterm.h b/src/xterm.h index 569433e4242..3e92ebd2317 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -175,6 +175,9 @@ struct x_display_info /* The cursor to use for vertical scroll bars. */ Cursor vertical_scroll_bar_cursor; + /* The cursor to use for horizontal scroll bars. */ + Cursor horizontal_scroll_bar_cursor; + /* The invisible cursor used for pointer blanking. Unused if this display supports Xfixes extension. */ Cursor invisible_cursor; @@ -279,8 +282,8 @@ struct x_display_info /* More atoms for Ghostscript support. */ Atom Xatom_DONE, Xatom_PAGE; - /* Atom used in toolkit scroll bar client messages. */ - Atom Xatom_Scrollbar; + /* Atoms used in toolkit scroll bar client messages. */ + Atom Xatom_Scrollbar, Xatom_Horizontal_Scrollbar; /* Atom used in XEmbed client messages. */ Atom Xatom_XEMBED, Xatom_XEMBED_INFO; @@ -822,6 +825,14 @@ struct scroll_bar /* Last scroll bar part seen in xaw_jump_callback and xaw_scroll_callback. */ enum scroll_bar_part last_seen_part; #endif + +#if defined (USE_TOOLKIT_SCROLL_BARS) && !defined (USE_GTK) + /* Last value of whole for horizontal scrollbars. */ + int whole; +#endif + + /* 1 if the scroll bar is horizontal. */ + bool horizontal; }; /* Turning a lisp vector value into a pointer to a struct scroll_bar. */ @@ -868,6 +879,28 @@ struct scroll_bar #define VERTICAL_SCROLL_BAR_INSIDE_HEIGHT(f, height) \ ((height) - VERTICAL_SCROLL_BAR_TOP_BORDER - VERTICAL_SCROLL_BAR_BOTTOM_BORDER) +/* Return the inside height of a horizontal scroll bar, given the outside + height. */ +#define HORIZONTAL_SCROLL_BAR_INSIDE_HEIGHT(f, height) \ + ((height) \ + - HORIZONTAL_SCROLL_BAR_TOP_BORDER \ + - HORIZONTAL_SCROLL_BAR_BOTTOM_BORDER) + +/* Return the length of the rectangle within which the left part of the + handle must stay. This isn't equivalent to the inside width, because + the scroll bar handle has a minimum width. + + This is the real range of motion for the scroll bar, so when we're + scaling buffer positions to scroll bar positions, we use this, not + HORIZONTAL_SCROLL_BAR_INSIDE_WIDTH. */ +#define HORIZONTAL_SCROLL_BAR_LEFT_RANGE(f, width) \ + (HORIZONTAL_SCROLL_BAR_INSIDE_WIDTH (f, width) - HORIZONTAL_SCROLL_BAR_MIN_HANDLE) + +/* Return the inside width of horizontal scroll bar, given the outside + width. See HORIZONTAL_SCROLL_BAR_LEFT_RANGE too. */ +#define HORIZONTAL_SCROLL_BAR_INSIDE_WIDTH(f, width) \ + ((width) - HORIZONTAL_SCROLL_BAR_LEFT_BORDER - HORIZONTAL_SCROLL_BAR_LEFT_BORDER) + /* Border widths for scroll bars. @@ -885,8 +918,14 @@ struct scroll_bar #define VERTICAL_SCROLL_BAR_TOP_BORDER (2) #define VERTICAL_SCROLL_BAR_BOTTOM_BORDER (2) +#define HORIZONTAL_SCROLL_BAR_LEFT_BORDER (2) +#define HORIZONTAL_SCROLL_BAR_RIGHT_BORDER (2) +#define HORIZONTAL_SCROLL_BAR_TOP_BORDER (2) +#define HORIZONTAL_SCROLL_BAR_BOTTOM_BORDER (2) + /* Minimum lengths for scroll bar handles, in pixels. */ #define VERTICAL_SCROLL_BAR_MIN_HANDLE (5) +#define HORIZONTAL_SCROLL_BAR_MIN_HANDLE (5) /* If a struct input_event has a kind which is SELECTION_REQUEST_EVENT or SELECTION_CLEAR_EVENT, then its contents are really described @@ -982,6 +1021,7 @@ x_display_pixel_width (struct x_display_info *dpyinfo) extern void x_set_sticky (struct frame *, Lisp_Object, Lisp_Object); extern void x_wait_for_event (struct frame *, int); +extern void x_clear_under_internal_border (struct frame *f); /* Defined in xselect.c. */ @@ -1063,10 +1103,6 @@ extern void x_session_close (void); extern Lisp_Object Qx_gtk_map_stock; -#if !defined USE_X_TOOLKIT && !defined USE_GTK -extern void x_clear_under_internal_border (struct frame *f); -#endif - /* Is the frame embedded into another application? */ #define FRAME_X_EMBEDDED_P(f) (FRAME_X_OUTPUT(f)->explicit_parent != 0) -- 2.39.2