Adjustments to double buffering on MS Windows
* src/w32fns.c (w32_set_inhibit_double_buffering): Add comment describing double buffering. (w32_wnd_proc): Respect `w32-disable-double-buffering'. (globals_of_w32fns): New variable `w32-disable-double-buffering'. * src/w32term.c (w32_show_back_buffer): Return immediately if double buffering is disabled on the frame. (w32_scroll_run): Use old scrolling code if `w32-disable-double-buffering' is enabled. (w32_scroll_bar_clear): Document why we don't clear scroll bars when double buffering is enabled. (w32_read_socket): Respect `w32-disable-double-buffering' and clean up some code. * src/w32xfns.c (get_frame_dc): Respect `w32-disable-double-buffering'.
This commit is contained in:
parent
1648791e7c
commit
1321b5989c
3 changed files with 87 additions and 15 deletions
16
src/w32fns.c
16
src/w32fns.c
|
@ -1802,9 +1802,16 @@ w32_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
|
|||
w32_change_tool_bar_height (f, nlines * FRAME_LINE_HEIGHT (f));
|
||||
}
|
||||
|
||||
/* Enable or disable double buffering on F.
|
||||
|
||||
When double buffering is enabled, all drawing happens on a back
|
||||
buffer (a bitmap), which is then displayed as a single operation
|
||||
after redisplay is complete. This avoids flicker caused by the
|
||||
results of an incomplete redisplay becoming visible. */
|
||||
static void
|
||||
w32_set_inhibit_double_buffering (struct frame *f,
|
||||
Lisp_Object new_value,
|
||||
/* This parameter is unused. */
|
||||
Lisp_Object old_value)
|
||||
{
|
||||
block_input ();
|
||||
|
@ -4114,7 +4121,8 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
f = w32_window_to_frame (dpyinfo, hwnd);
|
||||
|
||||
enter_crit ();
|
||||
if (f && !FRAME_OUTPUT_DATA (f)->paint_buffer)
|
||||
if (f && (w32_disable_double_buffering
|
||||
|| !FRAME_OUTPUT_DATA (f)->paint_buffer))
|
||||
{
|
||||
HDC hdc = get_frame_dc (f);
|
||||
GetUpdateRect (hwnd, &wmsg.rect, FALSE);
|
||||
|
@ -11236,6 +11244,12 @@ see `w32-ansi-code-page'. */);
|
|||
w32_multibyte_code_page = _getmbcp ();
|
||||
#endif
|
||||
|
||||
DEFVAR_BOOL ("w32-disable-double-buffering", w32_disable_double_buffering,
|
||||
doc: /* Completely disable double buffering.
|
||||
This variable is used for debugging, and takes precedence over any
|
||||
value of the `inhibit-double-buffering' frame parameter. */);
|
||||
w32_disable_double_buffering = false;
|
||||
|
||||
if (os_subtype == OS_SUBTYPE_NT)
|
||||
w32_unicode_gui = 1;
|
||||
else
|
||||
|
|
|
@ -283,6 +283,9 @@ w32_show_back_buffer (struct frame *f)
|
|||
|
||||
output = FRAME_OUTPUT_DATA (f);
|
||||
|
||||
if (!output->want_paint_buffer || w32_disable_double_buffering)
|
||||
return;
|
||||
|
||||
enter_crit ();
|
||||
|
||||
if (output->paint_buffer)
|
||||
|
@ -2935,6 +2938,8 @@ w32_scroll_run (struct window *w, struct run *run)
|
|||
struct frame *f = XFRAME (w->frame);
|
||||
int x, y, width, height, from_y, to_y, bottom_y;
|
||||
HDC hdc;
|
||||
HWND hwnd = FRAME_W32_WINDOW (f);
|
||||
HRGN expect_dirty = NULL;
|
||||
|
||||
/* Get frame-relative bounding box of the text display area of W,
|
||||
without mode lines. Include in this box the left and right
|
||||
|
@ -2953,6 +2958,9 @@ w32_scroll_run (struct window *w, struct run *run)
|
|||
height = bottom_y - from_y;
|
||||
else
|
||||
height = run->height;
|
||||
|
||||
if (w32_disable_double_buffering)
|
||||
expect_dirty = CreateRectRgn (x, y + height, x + width, bottom_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2962,15 +2970,55 @@ w32_scroll_run (struct window *w, struct run *run)
|
|||
height = bottom_y - to_y;
|
||||
else
|
||||
height = run->height;
|
||||
|
||||
if (w32_disable_double_buffering)
|
||||
expect_dirty = CreateRectRgn (x, y, x + width, to_y);
|
||||
}
|
||||
|
||||
block_input ();
|
||||
|
||||
/* Cursor off. Will be switched on again in gui_update_window_end. */
|
||||
gui_clear_cursor (w);
|
||||
hdc = get_frame_dc (f);
|
||||
BitBlt (hdc, x, to_y, width, height, hdc, x, from_y, SRCCOPY);
|
||||
release_frame_dc (f, hdc);
|
||||
if (!w32_disable_double_buffering)
|
||||
{
|
||||
hdc = get_frame_dc (f);
|
||||
BitBlt (hdc, x, to_y, width, height, hdc, x, from_y, SRCCOPY);
|
||||
release_frame_dc (f, hdc);
|
||||
}
|
||||
else
|
||||
{
|
||||
RECT from;
|
||||
RECT to;
|
||||
HRGN dirty = CreateRectRgn (0, 0, 0, 0);
|
||||
HRGN combined = CreateRectRgn (0, 0, 0, 0);
|
||||
|
||||
from.left = to.left = x;
|
||||
from.right = to.right = x + width;
|
||||
from.top = from_y;
|
||||
from.bottom = from_y + height;
|
||||
to.top = y;
|
||||
to.bottom = bottom_y;
|
||||
|
||||
ScrollWindowEx (hwnd, 0, to_y - from_y, &from, &to, dirty,
|
||||
NULL, SW_INVALIDATE);
|
||||
|
||||
/* Combine this with what we expect to be dirty. This covers the
|
||||
case where not all of the region we expect is actually dirty. */
|
||||
CombineRgn (combined, dirty, expect_dirty, RGN_OR);
|
||||
|
||||
/* If the dirty region is not what we expected, redraw the entire frame. */
|
||||
if (!EqualRgn (combined, expect_dirty))
|
||||
SET_FRAME_GARBAGED (f);
|
||||
|
||||
DeleteObject (dirty);
|
||||
DeleteObject (combined);
|
||||
}
|
||||
|
||||
unblock_input ();
|
||||
|
||||
if (w32_disable_double_buffering
|
||||
&& expect_dirty)
|
||||
DeleteObject (expect_dirty);
|
||||
}
|
||||
|
||||
|
||||
|
@ -4840,7 +4888,12 @@ w32_scroll_bar_clear (struct frame *f)
|
|||
{
|
||||
Lisp_Object bar;
|
||||
|
||||
if (FRAME_OUTPUT_DATA (f)->paint_buffer)
|
||||
/* Return if double buffering is enabled, since clearing a frame
|
||||
actually clears just the back buffer, so avoid clearing all of
|
||||
the scroll bars, since that causes the scroll bars to
|
||||
flicker. */
|
||||
if (!w32_disable_double_buffering
|
||||
&& FRAME_OUTPUT_DATA (f)->want_paint_buffer)
|
||||
return;
|
||||
|
||||
/* We can have scroll bars even if this is 0,
|
||||
|
@ -4958,6 +5011,11 @@ w32_read_socket (struct terminal *terminal,
|
|||
struct input_event inev;
|
||||
int do_help = 0;
|
||||
|
||||
/* WM_WINDOWPOSCHANGED makes the buffer dirty, but there's no
|
||||
reason to flush the back buffer after receiving such an
|
||||
event, and that also causes flicker. */
|
||||
bool ignore_dirty_back_buffer = false;
|
||||
|
||||
/* DebPrint (("w32_read_socket: %s time:%u\n", */
|
||||
/* w32_name_of_message (msg.msg.message), */
|
||||
/* msg.msg.time)); */
|
||||
|
@ -5005,8 +5063,8 @@ w32_read_socket (struct terminal *terminal,
|
|||
}
|
||||
else
|
||||
{
|
||||
enter_crit ();
|
||||
if (!FRAME_OUTPUT_DATA (f)->paint_buffer)
|
||||
if (w32_disable_double_buffering
|
||||
|| !FRAME_OUTPUT_DATA (f)->paint_buffer)
|
||||
{
|
||||
/* Erase background again for safety. But don't do
|
||||
that if the frame's 'garbaged' flag is set, since
|
||||
|
@ -5031,7 +5089,6 @@ w32_read_socket (struct terminal *terminal,
|
|||
}
|
||||
else
|
||||
w32_show_back_buffer (f);
|
||||
leave_crit ();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -5484,6 +5541,7 @@ w32_read_socket (struct terminal *terminal,
|
|||
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
f = w32_window_to_frame (dpyinfo, msg.msg.hwnd);
|
||||
ignore_dirty_back_buffer = true;
|
||||
|
||||
if (f)
|
||||
{
|
||||
|
@ -5894,11 +5952,9 @@ w32_read_socket (struct terminal *terminal,
|
|||
that is the case, flush any changes that have been made to
|
||||
the front buffer. */
|
||||
|
||||
if (f && FRAME_OUTPUT_DATA (f)->paint_buffer_dirty
|
||||
/* WM_WINDOWPOSCHANGED makes the buffer dirty, but there's
|
||||
no reason to flush it here, and that also causes
|
||||
flicker. */
|
||||
&& !f->garbaged && msg.msg.message != WM_WINDOWPOSCHANGED)
|
||||
if (f && !w32_disable_double_buffering
|
||||
&& FRAME_OUTPUT_DATA (f)->paint_buffer_dirty
|
||||
&& !f->garbaged && ignore_dirty_back_buffer)
|
||||
w32_show_back_buffer (f);
|
||||
}
|
||||
|
||||
|
|
|
@ -171,7 +171,8 @@ get_frame_dc (struct frame *f)
|
|||
if (output->paint_dc)
|
||||
{
|
||||
if (output->paint_buffer_width != FRAME_PIXEL_WIDTH (f)
|
||||
|| output->paint_buffer_height != FRAME_PIXEL_HEIGHT (f))
|
||||
|| output->paint_buffer_height != FRAME_PIXEL_HEIGHT (f)
|
||||
|| w32_disable_double_buffering)
|
||||
w32_release_paint_buffer (f);
|
||||
else
|
||||
{
|
||||
|
@ -188,7 +189,8 @@ get_frame_dc (struct frame *f)
|
|||
{
|
||||
select_palette (f, hdc);
|
||||
|
||||
if (FRAME_OUTPUT_DATA (f)->want_paint_buffer)
|
||||
if (!w32_disable_double_buffering
|
||||
&& FRAME_OUTPUT_DATA (f)->want_paint_buffer)
|
||||
{
|
||||
back_buffer
|
||||
= CreateCompatibleBitmap (hdc, FRAME_PIXEL_WIDTH (f),
|
||||
|
|
Loading…
Add table
Reference in a new issue