From cfd5e825ae51150889b3a5d1b46d617cdab85b23 Mon Sep 17 00:00:00 2001 From: Martin Rudalics Date: Fri, 14 Mar 2014 11:38:46 +0100 Subject: [PATCH] Document pixelwise frame resizing and fix related bug on Windows. * w32term.c (x_set_window_size): When frame-resize-pixelwise is nil, always resize character wise to avoid potential loss of the mode line (Bug#16923 related). * display.texi (Temporary Displays): Say that with-temp-buffer-window makes its buffer current. * frames.texi (Size and Position): Describe new option `frame-resize-pixelwise'. Rewrite descriptions of `set-frame-size', `set-frame-height' and `set-frame-width'. --- doc/lispref/ChangeLog | 8 +++++ doc/lispref/display.texi | 11 +++--- doc/lispref/frames.texi | 55 +++++++++++++++++++++++----- src/ChangeLog | 6 ++++ src/w32term.c | 77 +++++++++++++++++++++++++++------------- 5 files changed, 117 insertions(+), 40 deletions(-) diff --git a/doc/lispref/ChangeLog b/doc/lispref/ChangeLog index 274d9fa4fea..047a7c6f3b7 100644 --- a/doc/lispref/ChangeLog +++ b/doc/lispref/ChangeLog @@ -1,3 +1,11 @@ +2014-03-14 Martin Rudalics + + * display.texi (Temporary Displays): Say that + with-temp-buffer-window makes its buffer current. + * frames.texi (Size and Position): Describe new option + `frame-resize-pixelwise'. Rewrite descriptions of + `set-frame-size', `set-frame-height' and `set-frame-width'. + 2014-03-09 Martin Rudalics * elisp.texi (Top): Rename section "Width" to "Size of Displayed diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index bffb840bfeb..5037f0c9032 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -1175,12 +1175,11 @@ is current, and the window it was displayed in is selected. @end defvar @defmac with-temp-buffer-window buffer-or-name action quit-function forms@dots{} -This macro is similar to @code{with-output-to-temp-buffer}. -Like that construct, it executes @var{forms} while arranging to insert -any output they print into the buffer named @var{buffer-or-name}. -Finally, the buffer is displayed in some window, but not selected. -Unlike @code{with-output-to-temp-buffer}, this does not switch to Help -mode. +This macro is similar to @code{with-output-to-temp-buffer}. Like that +construct, it executes @var{forms} while arranging to insert any output +they print into the buffer named @var{buffer-or-name} and displays the +buffer in some window. Unlike @code{with-output-to-temp-buffer}, +however, this makes the buffer current and does not switch to Help mode. The argument @var{buffer-or-name} specifies the temporary buffer. It can be either a buffer, which must already exist, or a string, diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi index 206f14e751e..59881afb903 100644 --- a/doc/lispref/frames.texi +++ b/doc/lispref/frames.texi @@ -1147,21 +1147,46 @@ font. If you don't supply @var{frame}, these functions use the selected frame. @end defun -@defun set-frame-size frame cols rows +@defopt frame-resize-pixelwise +If this option is @code{nil}, a frame's size is usually rounded to a +multiple of the current values of that frame's @code{frame-char-height} +and @code{frame-char-width}. If this is non-@code{nil}, no rounding +occurs, hence frame sizes can increase/decrease by one pixel. + +Setting this causes the next resize operation to pass the corresponding +size hints to the window manager. This means that this variable should +be set only in a user's initial file; applications should never bind it +temporarily. + +The precise semantics of a value of @code{nil} for this option depends +on the toolkit used: Dragging the frame border with the mouse is usually +always done character-wise. Calling @code{set-frame-size} (see below) +with arguments that do not specify the frame size as an integer multiple +of its character size may be, however, either ignored or cause a +rounding (GTK+, Windows) or get accepted (Lucid, Motif). This also +means that with some toolkits and a display whose size is not an +integral multiple of your default font, you may have to set this to +non-@code{nil} in order to fully maximize a frame. +@end defopt + +@defun set-frame-size frame width height pixelwise This function sets the size of @var{frame}, measured in characters; -@var{cols} and @var{rows} specify the new width and height. +@var{width} and @var{height} specify the new width in columns and the +new height in lines. -To set the size based on values measured in pixels, use -@code{frame-char-height} and @code{frame-char-width} to convert -them to units of characters. +The optional argument @var{pixelwise} non-@code{nil} means to measure +the new width and height in units of pixels instead. Note that if +@code{frame-resize-pixelwise} is @code{nil}, some toolkits may refuse to +fully honor the request if it does not increase/decrease the frame size +to a multiple of its character size. @end defun -@defun set-frame-height frame lines &optional pretend -This function resizes @var{frame} to a height of @var{lines} lines. The +@defun set-frame-height frame height &optional pretend pixelwise +This function resizes @var{frame} to a height of @var{height} lines. The sizes of existing windows in @var{frame} are altered proportionally to fit. -If @var{pretend} is non-@code{nil}, then Emacs displays @var{lines} +If @var{pretend} is non-@code{nil}, then Emacs displays @var{height} lines of output in @var{frame}, but does not change its value for the actual height of the frame. This is only useful on text terminals. Using a smaller height than the terminal actually implements may be @@ -1170,12 +1195,24 @@ terminal malfunctions when using its whole screen. Setting the frame height ``for real'' does not always work, because knowing the correct actual size may be necessary for correct cursor positioning on text terminals. + +The optional fourth argument @var{pixelwise} non-@code{nil} means that +@var{frame} should be @var{height} pixels high. Note that if +@code{frame-resize-pixelwise} is @code{nil}, some toolkits may refuse to +fully honor the request if it does not increase/decrease the frame +height to a multiple of its character height. @end defun -@defun set-frame-width frame width &optional pretend +@defun set-frame-width frame width &optional pretend pixelwise This function sets the width of @var{frame}, measured in characters. The argument @var{pretend} has the same meaning as in @code{set-frame-height}. + +The optional fourth argument @var{pixelwise} non-@code{nil} means that +@var{frame} should be @var{width} pixels wide. Note that if +@code{frame-resize-pixelwise} is @code{nil}, some toolkits may refuse to +fully honor the request if it does not increase/decrease the frame width +to a multiple of its character width. @end defun @c FIXME? Belongs more in Emacs manual than here? diff --git a/src/ChangeLog b/src/ChangeLog index 013409ff406..0512b0d9b68 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2014-03-14 Martin Rudalics + + * w32term.c (x_set_window_size): When frame-resize-pixelwise is + nil, always resize character wise to avoid potential loss of the + mode line (Bug#16923 related). + 2014-03-12 Martin Rudalics * frame.c (x_set_frame_parameters): Always calculate new sizes diff --git a/src/w32term.c b/src/w32term.c index 5c93103f2c5..2981320e136 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -5648,6 +5648,31 @@ x_set_window_size (struct frame *f, int change_gravity, int width, int height, b pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height); } + if (!frame_resize_pixelwise) + { + /* If we don't resize frames pixelwise, round sizes to multiples + of character sizes. Otherwise, Windows may clip our frame + rectangle at a character size boundary and we risk losing our + mode line. Bug#16923 might be a consequence of this. + + So far, this is a Windows specific problem; other toolkits may + prefer to not resize the frame if the delta is not large enough + (GTK) or resize the frame pixelwise as requested (Lucid, + Motif). Windows just doesn't call us back (probably because of + the size hint settings which it apparently interprets strictly) + neither when the user tries to mouse-drag a frame border by, + nor when calling `set-frame-size' with a delta of less than the + canonical character size. If w32_enable_frame_resize_hack is + enabled (which it now is by default) we'd then below resize the + frame's root window in preparation of a WM_SIZE message to come + which, however, is not going to happen. */ + int unit_width = FRAME_COLUMN_WIDTH (f); + int unit_height = FRAME_LINE_HEIGHT (f); + + pixelwidth = (pixelwidth / unit_width) * unit_width; + pixelheight = (pixelheight / unit_height) * unit_height; + } + f->win_gravity = NorthWestGravity; x_wm_set_size_hint (f, (long) 0, 0); @@ -5670,39 +5695,40 @@ x_set_window_size (struct frame *f, int change_gravity, int width, int height, b } /* If w32_enable_frame_resize_hack is non-nil, immediately apply the - new pixel sizes to the frame and its subwindows. See discussion - of Bug#16028 for why we need this. */ + new pixel sizes to the frame and its subwindows. This approach is + fragile because Windows might not honor the resize request issued + by my_set_window_pos with a WM_SIZE message (see previous comment). - if (w32_enable_frame_resize_hack) - /* The following mirrors what is done in xterm.c. It appears to be - for informing lisp of the new size immediately, while the actual - resize will happen asynchronously. But on Windows, the menu bar - automatically wraps when the frame is too narrow to contain it, - and that causes any calculations made here to come out wrong. The - end is some nasty buggy behavior, including the potential loss - of the minibuffer. + Jason Rumney earlier refused to call change_frame_size right here + with the following argument: + + The following mirrors what is done in xterm.c. It appears to be for + informing lisp of the new size immediately, while the actual resize + will happen asynchronously. But on Windows, the menu bar + automatically wraps when the frame is too narrow to contain it, and + that causes any calculations made here to come out wrong. The end + is some nasty buggy behavior, including the potential loss of the + minibuffer. Disabling this code is either not sufficient to fix the problems completely, or it causes fresh problems, but at least it removes the most problematic symptom of the minibuffer becoming unusable. - ----------------------------------------------------------------- - - Now, strictly speaking, we can't be sure that this is accurate, - but the window manager will get around to dealing with the size - change request eventually, and we'll hear how it went when the - ConfigureNotify event gets here. + However, as the discussion about how to handle frame size + parameters on Windows (Bug#1348, Bug#16028) shows, that cure seems + worse than the disease. In particular, menu bar wrapping looks + like a non-issue - maybe so because Windows eventually gets back to + us with the correct client rectangle anyway. But we have to avoid + calling change_frame_size with a delta of less than one canoncial + character size when frame_resize_pixelwise is nil, as explained in + the comment above. */ - We could just not bother storing any of this information here, - and let the ConfigureNotify event set everything up, but that - might be kind of confusing to the Lisp code, since size changes - wouldn't be reported in the frame parameters until some random - point in the future when the ConfigureNotify event arrives. + if (w32_enable_frame_resize_hack) - We pass 1 for DELAY since we can't run Lisp code inside of - a BLOCK_INPUT. */ { - change_frame_size (f, width, height, 0, 1, 0, pixelwise); + change_frame_size (f, FRAME_PIXEL_TO_TEXT_WIDTH (f, pixelwidth), + FRAME_PIXEL_TO_TEXT_HEIGHT (f, pixelheight), + 0, 1, 0, 1); SET_FRAME_GARBAGED (f); /* If cursor was outside the new size, mark it as off. */ @@ -5711,7 +5737,8 @@ x_set_window_size (struct frame *f, int change_gravity, int width, int height, b /* Clear out any recollection of where the mouse highlighting was, since it might be in a place that's outside the new frame size. Actually checking whether it is outside is a pain in the neck, - so don't try--just let the highlighting be done afresh with new size. */ + so don't try--just let the highlighting be done afresh with new + size. */ cancel_mouse_face (f); } -- 2.39.2