From 764ec9e5f0adaff96b52252eea71eb30ef7cefa1 Mon Sep 17 00:00:00 2001 From: Martin Rudalics Date: Tue, 4 Feb 2014 08:36:58 +0100 Subject: [PATCH] Improve window dividers code. * faces.el (window-divider): New default value. Rewrite doc-string. (window-divider-first-pixel, window-divider-last-pixel): New faces. * dispextern.h (face_id): Add WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID and WINDOW_DIVIDER_LAST_PIXEL_FACE_ID. * w32term.c (w32_draw_window_divider): Handle first and last pixels specially. * w32term.h (w32_fill_area_abs): New function. * xdisp.c (x_draw_right_divider): Don't draw over bottom divider. * xfaces.c (realize_basic_faces): Handle new face ids. * xfns.c (Fx_create_frame): Call x_default_parameter for right and bottom divider width. * xterm.c (x_draw_window_divider): Handle first and last pixels specially. --- etc/NEWS | 12 +++++++++++ lisp/ChangeLog | 7 +++++++ lisp/faces.el | 33 ++++++++++++++++++++++++++++++ src/ChangeLog | 15 ++++++++++++++ src/dispextern.h | 2 ++ src/w32term.c | 42 ++++++++++++++++++++++++-------------- src/w32term.h | 10 ++++++++++ src/xdisp.c | 3 ++- src/xfaces.c | 8 ++++++++ src/xfns.c | 4 ++++ src/xterm.c | 52 ++++++++++++++++++++++++++++++++++++++++-------- 11 files changed, 164 insertions(+), 24 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index cfcb74cf782..11cb240890a 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -196,6 +196,18 @@ command `frame-configuration-to-register' still exists, but is unbound. *** New hooks `focus-in-hook', `focus-out-hook'. These are normal hooks run when an Emacs frame gains or loses input focus. +--- +*** Emacs can now draw dividers between adjacent windows. To put +dividers between side-by-side windows customize the frame parameter +right-divider-width to some positive integer. To put dividers between +vertically stacked windows set the frame parameter bottom-divider-width +to some positive integer. Dividers can be dragged with the mouse and +show a corresponding cursor when the mouse hovers over them. The +appearance of dividers can be changed by customizing the basic faces +window-divider, window-divider-first-pixel and window-divider-last-pixel +where the latter two are useful to provide a 3D effect or to better set +dividers apart from surrounding display objects. + --- *** `split-window' is now a non-interactive function, not a command. As a command, it was a special case of `C-x 2' (`split-window-below'), diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 7c204726568..a97860c8aa6 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,10 @@ +2014-02-03 Martin Rudalics + + * faces.el (window-divider): New default value. Rewrite + doc-string. + (window-divider-first-pixel, window-divider-last-pixel): New + faces. + 2014-02-03 Dmitry Gutov * progmodes/ruby-mode.el (ruby-font-lock-keywords): `private', diff --git a/lisp/faces.el b/lisp/faces.el index aa9d25c31d7..460fddf9ccd 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -2425,6 +2425,39 @@ Use the face `mode-line-highlight' for features that can be selected." :version "22.1" :group 'basic-faces) +(defface window-divider '((t :foreground "gray60")) + "Basic face for window dividers. +When a divider is less than 3 pixels wide, it is drawn solidly +with the foreground of this face. For larger dividers this face +is used for the inner part while the first pixel line/column is +drawn with the `window-divider-first-pixel' face and the last +pixel line/column with the `window-divider-last-pixel' face." + :version "24.4" + :group 'frames + :group 'basic-faces) + +(defface window-divider-first-pixel + '((t :foreground "gray80")) + "Basic face for first pixel line/column of window dividers. +When a divider is at least 3 pixels wide, its first pixel +line/column is drawn with the foreground of this face. If you do +not want to accentuate the first pixel line/column, set this to +the same as `window-divider' face." + :version "24.4" + :group 'frames + :group 'basic-faces) + +(defface window-divider-last-pixel + '((t :foreground "gray40")) + "Basic face for last pixel line/column of window dividers. +When a divider is at least 3 pixels wide, its last pixel +line/column is drawn with the foreground of this face. If you do +not want to accentuate the last pixel line/column, set this to +the same as `window-divider' face." + :version "24.4" + :group 'frames + :group 'basic-faces) + (defface minibuffer-prompt '((((background dark)) :foreground "cyan") ;; Don't use blue because many users of the MS-DOS port customize diff --git a/src/ChangeLog b/src/ChangeLog index ac41dabafcd..ec003cd59b2 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,18 @@ +2014-02-03 Martin Rudalics + + * dispextern.h (face_id): Add WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID + and WINDOW_DIVIDER_LAST_PIXEL_FACE_ID. + * w32term.c (w32_draw_window_divider): Handle first and last + pixels specially. + * w32term.h (w32_fill_area_abs): New function. + * xdisp.c (x_draw_right_divider): Don't draw over bottom + divider. + * xfaces.c (realize_basic_faces): Handle new face ids. + * xfns.c (Fx_create_frame): Call x_default_parameter for right + and bottom divider width. + * xterm.c (x_draw_window_divider): Handle first and last pixels + specially. + 2014-02-03 Dmitry Antipov * print.c (Fexternal_debugging_output): Add cast to pacify diff --git a/src/dispextern.h b/src/dispextern.h index a5dd054c123..9ecd4ecdf7e 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -1765,6 +1765,8 @@ enum face_id MENU_FACE_ID, VERTICAL_BORDER_FACE_ID, WINDOW_DIVIDER_FACE_ID, + WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID, + WINDOW_DIVIDER_LAST_PIXEL_FACE_ID, BASIC_FACE_ID_SENTINEL }; diff --git a/src/w32term.c b/src/w32term.c index 03d5a0047bc..b77d01796d7 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -628,26 +628,38 @@ static void w32_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1) { struct frame *f = XFRAME (WINDOW_FRAME (w)); - RECT r; - HDC hdc; - struct face *face; - - r.left = x0; - r.right = x1; - r.top = y0; - r.bottom = y1; - - hdc = get_frame_dc (f); - face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID); - if (face) - w32_fill_rect (f, hdc, face->foreground, &r); + HDC hdc = get_frame_dc (f); + struct face *face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID); + struct face *face_first = FACE_FROM_ID (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID); + struct face *face_last = FACE_FROM_ID (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID); + unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f); + unsigned long color_first = (face_first + ? face_first->foreground + : FRAME_FOREGROUND_PIXEL (f)); + unsigned long color_last = (face_last + ? face_last->foreground + : FRAME_FOREGROUND_PIXEL (f)); + + if (y1 - y0 > x1 - x0 && x1 - x0 > 2) + /* Vertical. */ + { + w32_fill_area_abs (f, hdc, color_first, x0, y0, x0 + 1, y1); + w32_fill_area_abs (f, hdc, color, x0 + 1, y0, x1 - 1, y1); + w32_fill_area_abs (f, hdc, color_last, x1 - 1, y0, x1, y1); + } + else if (x1 - x0 > y1 - y0 && y1 - y0 > 3) + /* Horizontal. */ + { + w32_fill_area_abs (f, hdc, color_first, x0, y0, x1, y0 + 1); + w32_fill_area_abs (f, hdc, color, x0, y0 + 1, x1, y1 - 1); + w32_fill_area_abs (f, hdc, color_last, x0, y1 - 1, x1, y1); + } else - w32_fill_rect (f, hdc, FRAME_FOREGROUND_PIXEL (f), &r); + w32_fill_area_abs (f, hdc, color, x0, y0, x1, y1); release_frame_dc (f, hdc); } - /* End update of window W. Draw vertical borders between horizontally adjacent windows, and diff --git a/src/w32term.h b/src/w32term.h index 5a1ae283137..f85e6bced8b 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -537,6 +537,16 @@ do { \ w32_fill_rect (f,hdc,pix,&rect); \ } while (0) +#define w32_fill_area_abs(f,hdc,pix,x0,y0,x1,y1) \ +do { \ + RECT rect; \ + rect.left = x0; \ + rect.top = y0; \ + rect.right = x1; \ + rect.bottom = y1; \ + w32_fill_rect (f,hdc,pix,&rect); \ +} while (0) + #define w32_clear_rect(f,hdc,lprect) \ w32_fill_rect (f, hdc, FRAME_BACKGROUND_PIXEL (f), lprect) diff --git a/src/xdisp.c b/src/xdisp.c index b5dec35568a..0ca877d997f 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -29277,7 +29277,8 @@ x_draw_right_divider (struct window *w) int x0 = WINDOW_RIGHT_EDGE_X (w) - WINDOW_RIGHT_DIVIDER_WIDTH (w); int x1 = WINDOW_RIGHT_EDGE_X (w); int y0 = WINDOW_TOP_EDGE_Y (w); - int y1 = WINDOW_BOTTOM_EDGE_Y (w); + /* The bottom divider prevails. */ + int y1 = WINDOW_BOTTOM_EDGE_Y (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w); FRAME_RIF (f)->draw_window_divider (w, x0, x1, y0, y1); } diff --git a/src/xfaces.c b/src/xfaces.c index f2d777a12b1..4271e47c36f 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -324,6 +324,8 @@ static Lisp_Object Qborder, Qmouse, Qmenu; Lisp_Object Qmode_line_inactive; static Lisp_Object Qvertical_border; static Lisp_Object Qwindow_divider; +static Lisp_Object Qwindow_divider_first_pixel; +static Lisp_Object Qwindow_divider_last_pixel; /* The symbol `face-alias'. A symbols having that property is an alias for another face. Value of the property is the name of @@ -5249,6 +5251,10 @@ realize_basic_faces (struct frame *f) realize_named_face (f, Qmenu, MENU_FACE_ID); realize_named_face (f, Qvertical_border, VERTICAL_BORDER_FACE_ID); realize_named_face (f, Qwindow_divider, WINDOW_DIVIDER_FACE_ID); + realize_named_face (f, Qwindow_divider_first_pixel, + WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID); + realize_named_face (f, Qwindow_divider_last_pixel, + WINDOW_DIVIDER_LAST_PIXEL_FACE_ID); /* Reflect changes in the `menu' face in menu bars. */ if (FRAME_FACE_CACHE (f)->menu_face_changed_p) @@ -6452,6 +6458,8 @@ syms_of_xfaces (void) DEFSYM (Qmode_line_inactive, "mode-line-inactive"); DEFSYM (Qvertical_border, "vertical-border"); DEFSYM (Qwindow_divider, "window-divider"); + DEFSYM (Qwindow_divider_first_pixel, "window-divider-first-pixel"); + DEFSYM (Qwindow_divider_last_pixel, "window-divider-last-pixel"); DEFSYM (Qtty_color_desc, "tty-color-desc"); DEFSYM (Qtty_color_standard_values, "tty-color-standard-values"); DEFSYM (Qtty_color_by_index, "tty-color-by-index"); diff --git a/src/xfns.c b/src/xfns.c index debc707dba2..ff492dcf126 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -3033,6 +3033,10 @@ This function is an internal primitive--use `make-frame' instead. */) #endif "internalBorderWidth", "internalBorderWidth", RES_TYPE_NUMBER); + x_default_parameter (f, parms, Qright_divider_width, make_number (0), + NULL, NULL, RES_TYPE_NUMBER); + x_default_parameter (f, parms, Qbottom_divider_width, make_number (0), + NULL, NULL, RES_TYPE_NUMBER); x_default_parameter (f, parms, Qvertical_scroll_bars, #if defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS) Qright, diff --git a/src/xterm.c b/src/xterm.c index 685fdf40a70..e1873127276 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -510,15 +510,51 @@ static void x_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1) { struct frame *f = XFRAME (WINDOW_FRAME (w)); - struct face *face; - - face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID); - if (face) - XSetForeground (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc, - face->foreground); + struct face *face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID); + struct face *face_first = FACE_FROM_ID (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID); + struct face *face_last = FACE_FROM_ID (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID); + unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f); + unsigned long color_first = (face_first + ? face_first->foreground + : FRAME_FOREGROUND_PIXEL (f)); + unsigned long color_last = (face_last + ? face_last->foreground + : FRAME_FOREGROUND_PIXEL (f)); + Display *display = FRAME_X_DISPLAY (f); + Window window = FRAME_X_WINDOW (f); - XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - f->output_data.x->normal_gc, x0, y0, x1 - x0, y1 - y0); + if (y1 - y0 > x1 - x0 && x1 - x0 > 2) + /* Vertical. */ + { + XSetForeground (display, f->output_data.x->normal_gc, color_first); + XFillRectangle (display, window, f->output_data.x->normal_gc, + x0, y0, 1, y1 - y0); + XSetForeground (display, f->output_data.x->normal_gc, color); + XFillRectangle (display, window, f->output_data.x->normal_gc, + x0 + 1, y0, x1 - x0 - 2, y1 - y0); + XSetForeground (display, f->output_data.x->normal_gc, color_last); + XFillRectangle (display, window, f->output_data.x->normal_gc, + x1 - 1, y0, 1, y1 - y0); + } + else if (x1 - x0 > y1 - y0 && y1 - y0 > 3) + /* Horizontal. */ + { + XSetForeground (display, f->output_data.x->normal_gc, color_first); + XFillRectangle (display, window, f->output_data.x->normal_gc, + x0, y0, x1 - x0, 1); + XSetForeground (display, f->output_data.x->normal_gc, color); + XFillRectangle (display, window, f->output_data.x->normal_gc, + x0, y0 + 1, x1 - x0, y1 - y0 - 2); + XSetForeground (display, f->output_data.x->normal_gc, color_last); + XFillRectangle (display, window, f->output_data.x->normal_gc, + x0, y1 - 1, x1 - x0, 1); + } + else + { + XSetForeground (display, f->output_data.x->normal_gc, color); + XFillRectangle (display, window, f->output_data.x->normal_gc, + x0, y0, x1 - x0, y1 - y0); + } } /* End update of window W. -- 2.39.2