w32_change_tool_bar_height (f, nlines * FRAME_LINE_HEIGHT (f));
}
+static void
+w32_set_inhibit_double_buffering (struct frame *f,
+ Lisp_Object new_value,
+ Lisp_Object old_value)
+{
+ block_input ();
+
+ if (NILP (new_value))
+ FRAME_OUTPUT_DATA (f)->want_paint_buffer = 1;
+ else
+ {
+ FRAME_OUTPUT_DATA (f)->want_paint_buffer = 0;
+ w32_release_paint_buffer (f);
+
+ SET_FRAME_GARBAGED (f);
+ }
+
+ unblock_input ();
+}
/* Set the pixel height of the tool bar of frame F to HEIGHT. */
void
{
case WM_ERASEBKGND:
f = w32_window_to_frame (dpyinfo, hwnd);
- if (f)
+
+ enter_crit ();
+ if (f && !FRAME_OUTPUT_DATA (f)->paint_buffer)
{
HDC hdc = get_frame_dc (f);
GetUpdateRect (hwnd, &wmsg.rect, FALSE);
wmsg.rect.right, wmsg.rect.bottom));
#endif /* W32_DEBUG_DISPLAY */
}
+ leave_crit ();
return 1;
case WM_PALETTECHANGED:
/* ignore our own changes */
? make_fixnum (0) : make_fixnum (1),
NULL, NULL, RES_TYPE_NUMBER);
+ gui_default_parameter (f, parameters, Qinhibit_double_buffering, Qnil,
+ "inhibitDoubleBuffering", "InhibitDoubleBuffering",
+ RES_TYPE_BOOLEAN);
+
gui_default_parameter (f, parameters, Qbuffer_predicate, Qnil,
"bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
gui_default_parameter (f, parameters, Qtitle, Qnil,
"alpha", "Alpha", RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qalpha_background, Qnil,
"alphaBackground", "AlphaBackground", RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qinhibit_double_buffering, Qnil,
+ "inhibitDoubleBuffering", "InhibitDoubleBuffering",
+ RES_TYPE_BOOLEAN);
/* Add `tooltip' frame parameter's default value. */
if (NILP (Fframe_parameter (frame, Qtooltip)))
gui_set_alpha,
0, /* x_set_sticky */
0, /* x_set_tool_bar_position */
- 0, /* x_set_inhibit_double_buffering */
+ w32_set_inhibit_double_buffering,
w32_set_undecorated,
w32_set_parent_frame,
w32_set_skip_taskbar,
}
#endif
+static void
+w32_show_back_buffer (struct frame *f)
+{
+ struct w32_output *output;
+ HDC raw_dc;
+
+ output = FRAME_OUTPUT_DATA (f);
+
+ enter_crit ();
+
+ if (output->paint_buffer)
+ {
+ raw_dc = GetDC (output->window_desc);
+
+ if (!raw_dc)
+ emacs_abort ();
+
+ BitBlt (raw_dc, 0, 0, FRAME_PIXEL_WIDTH (f),
+ FRAME_PIXEL_HEIGHT (f),
+ output->paint_dc, 0, 0, SRCCOPY);
+ ReleaseDC (output->window_desc, raw_dc);
+
+ output->paint_buffer_dirty = 0;
+ }
+
+ leave_crit ();
+}
+
+void
+w32_release_paint_buffer (struct frame *f)
+{
+ /* Delete the back buffer so it gets created
+ again the next time we ask for the DC. */
+
+ enter_crit ();
+ if (FRAME_OUTPUT_DATA (f)->paint_buffer)
+ {
+ SelectObject (FRAME_OUTPUT_DATA (f)->paint_dc,
+ FRAME_OUTPUT_DATA (f)->paint_dc_object);
+ ReleaseDC (FRAME_OUTPUT_DATA (f)->window_desc,
+ FRAME_OUTPUT_DATA (f)->paint_buffer_handle);
+ DeleteDC (FRAME_OUTPUT_DATA (f)->paint_dc);
+ DeleteObject (FRAME_OUTPUT_DATA (f)->paint_buffer);
+
+ FRAME_OUTPUT_DATA (f)->paint_buffer = NULL;
+ FRAME_OUTPUT_DATA (f)->paint_dc = NULL;
+ FRAME_OUTPUT_DATA (f)->paint_buffer_handle = NULL;
+ }
+ leave_crit ();
+}
+
static void
w32_get_mouse_wheel_vertical_delta (void)
{
static void
w32_frame_up_to_date (struct frame *f)
{
- if (FRAME_W32_P (f))
- FRAME_MOUSE_UPDATE (f);
+ FRAME_MOUSE_UPDATE (f);
+
+ if (!buffer_flipping_blocked_p ()
+ && FRAME_OUTPUT_DATA (f)->paint_buffer_dirty)
+ w32_show_back_buffer (f);
}
+static void
+w32_buffer_flipping_unblocked_hook (struct frame *f)
+{
+ if (FRAME_OUTPUT_DATA (f)->paint_buffer_dirty)
+ w32_show_back_buffer (f);
+}
/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
arrow bitmaps, or clear the fringes if no bitmaps are required
{
struct frame *f = XFRAME (w->frame);
int x, y, width, height, from_y, to_y, bottom_y;
- HWND hwnd = FRAME_W32_WINDOW (f);
- HRGN expect_dirty;
+ HDC hdc;
/* Get frame-relative bounding box of the text display area of W,
without mode lines. Include in this box the left and right
height = bottom_y - from_y;
else
height = run->height;
- expect_dirty = CreateRectRgn (x, y + height, x + width, bottom_y);
}
else
{
height = bottom_y - to_y;
else
height = run->height;
- 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);
-
- {
- 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);
- }
-
+ hdc = get_frame_dc (f);
+ BitBlt (hdc, x, to_y, width, height, hdc, x, from_y, SRCCOPY);
+ release_frame_dc (f, hdc);
unblock_input ();
- DeleteObject (expect_dirty);
}
{
Lisp_Object bar;
+ if (FRAME_OUTPUT_DATA (f)->paint_buffer)
+ return;
+
/* 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. */
/* w32_name_of_message (msg.msg.message), */
/* msg.msg.time)); */
+ f = NULL;
+
EVENT_INIT (inev);
inev.kind = NO_EVENT;
inev.arg = Qnil;
}
else
{
- /* Erase background again for safety. But don't do
- that if the frame's 'garbaged' flag is set, since
- in that case expose_frame will do nothing, and if
- the various redisplay flags happen to be unset,
- we are left with a blank frame. */
- if (!FRAME_GARBAGED_P (f) || FRAME_PARENT_FRAME (f))
+ enter_crit ();
+ if (!FRAME_OUTPUT_DATA (f)->paint_buffer)
{
- HDC hdc = get_frame_dc (f);
-
- w32_clear_rect (f, hdc, &msg.rect);
- release_frame_dc (f, hdc);
+ /* Erase background again for safety. But don't do
+ that if the frame's 'garbaged' flag is set, since
+ in that case expose_frame will do nothing, and if
+ the various redisplay flags happen to be unset,
+ we are left with a blank frame. */
+
+ if (!FRAME_GARBAGED_P (f) || FRAME_PARENT_FRAME (f))
+ {
+ HDC hdc = get_frame_dc (f);
+
+ w32_clear_rect (f, hdc, &msg.rect);
+ release_frame_dc (f, hdc);
+ }
+
+ expose_frame (f,
+ msg.rect.left,
+ msg.rect.top,
+ msg.rect.right - msg.rect.left,
+ msg.rect.bottom - msg.rect.top);
+ w32_clear_under_internal_border (f);
}
- expose_frame (f,
- msg.rect.left,
- msg.rect.top,
- msg.rect.right - msg.rect.left,
- msg.rect.bottom - msg.rect.top);
- w32_clear_under_internal_border (f);
+ else
+ w32_show_back_buffer (f);
+ leave_crit ();
}
}
break;
if (width != FRAME_PIXEL_WIDTH (f)
|| height != FRAME_PIXEL_HEIGHT (f))
{
+ w32_release_paint_buffer (f);
+
change_frame_size
(f, width, height, false, true, false);
SET_FRAME_GARBAGED (f);
}
count++;
}
+
+ /* Event processing might have drawn to F outside redisplay. If
+ 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)
+ w32_show_back_buffer (f);
}
/* If the focus was just given to an autoraising frame,
face. */
free_frame_faces (f);
+ /* Now release the back buffer if any exists. */
+ w32_release_paint_buffer (f);
+
if (FRAME_W32_WINDOW (f))
my_destroy_window (f, FRAME_W32_WINDOW (f));
terminal->update_end_hook = w32_update_end;
terminal->read_socket_hook = w32_read_socket;
terminal->frame_up_to_date_hook = w32_frame_up_to_date;
+ terminal->buffer_flipping_unblocked_hook = w32_buffer_flipping_unblocked_hook;
terminal->defined_color_hook = w32_defined_color;
terminal->query_frame_background_color = w32_query_frame_background_color;
terminal->query_colors = w32_query_colors;
if (dpyinfo->palette)
DeleteObject (dpyinfo->palette);
}
+
w32_reset_fringes ();
}
f->output_data.w32->old_palette = NULL;
if (RealizePalette (hdc) != GDI_ERROR)
- {
- Lisp_Object frame, framelist;
- FOR_EACH_FRAME (framelist, frame)
{
- SET_FRAME_GARBAGED (XFRAME (frame));
+ Lisp_Object frame, framelist;
+ FOR_EACH_FRAME (framelist, frame)
+ {
+ SET_FRAME_GARBAGED (XFRAME (frame));
+ }
}
- }
}
void
HDC
get_frame_dc (struct frame *f)
{
- HDC hdc;
+ HDC hdc, paint_dc;
+ HBITMAP back_buffer;
+ HGDIOBJ obj;
+ struct w32_output *output;
if (f->output_method != output_w32)
emacs_abort ();
enter_crit ();
+ output = FRAME_OUTPUT_DATA (f);
+
+ if (output->paint_dc)
+ {
+ if (output->paint_buffer_width != FRAME_PIXEL_WIDTH (f)
+ || output->paint_buffer_height != FRAME_PIXEL_HEIGHT (f))
+ w32_release_paint_buffer (f);
+ else
+ {
+ output->paint_buffer_dirty = 1;
+ return output->paint_dc;
+ }
+ }
- hdc = GetDC (f->output_data.w32->window_desc);
+ hdc = GetDC (output->window_desc);
/* If this gets called during startup before the frame is valid,
there is a chance of corrupting random data or crashing. */
if (hdc)
- select_palette (f, hdc);
+ {
+ select_palette (f, hdc);
+
+ if (FRAME_OUTPUT_DATA (f)->want_paint_buffer)
+ {
+ back_buffer
+ = CreateCompatibleBitmap (hdc, FRAME_PIXEL_WIDTH (f),
+ FRAME_PIXEL_HEIGHT (f));
+
+ if (back_buffer)
+ {
+ paint_dc = CreateCompatibleDC (hdc);
+
+ if (!paint_dc)
+ DeleteObject (back_buffer);
+ else
+ {
+ obj = SelectObject (paint_dc, back_buffer);
+
+ output->paint_dc_object = obj;
+ output->paint_dc = paint_dc;
+ output->paint_buffer_handle = hdc;
+ output->paint_buffer = back_buffer;
+ output->paint_buffer_width = FRAME_PIXEL_WIDTH (f);
+ output->paint_buffer_height = FRAME_PIXEL_HEIGHT (f);
+ output->paint_buffer_dirty = 1;
+
+ SET_FRAME_GARBAGED (f);
+
+ return paint_dc;
+ }
+ }
+ }
+ }
return hdc;
}
{
int ret;
- deselect_palette (f, hdc);
- ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
+ /* Avoid releasing the double-buffered DC here, since it'll be
+ released upon the next buffer flip instead. */
+ if (hdc != FRAME_OUTPUT_DATA (f)->paint_dc)
+ {
+ deselect_palette (f, hdc);
+ ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
+ }
+ else
+ ret = 0;
leave_crit ();