PROP_CURSOR
};
+typedef enum {
+ CLEAR_BG_NONE,
+ CLEAR_BG_WINCLEARED, /* Clear backgrounds except those that the window system clears */
+ CLEAR_BG_ALL
+} ClearBg;
+
struct _GdkWindowPaint
{
GdkRegion *region;
gint y_offset;
cairo_surface_t *surface;
guint uses_implicit : 1;
+ guint flushed : 1;
guint32 region_tag;
};
gboolean recalculate_siblings,
gboolean recalculate_children);
static void gdk_window_flush_outstanding_moves (GdkWindow *window);
-static void gdk_window_flush (GdkWindow *window);
static void gdk_window_flush_recursive (GdkWindowObject *window);
static void do_move_region_bits_on_impl (GdkWindowObject *private,
GdkRegion *region, /* In impl window coords */
int dx, int dy);
static void gdk_window_invalidate_in_parent (GdkWindowObject *private);
-static void move_native_children (GdkWindowObject *private);
-static void update_cursor (GdkDisplay *display);
+static void move_native_children (GdkWindowObject *private);
+static void update_cursor (GdkDisplay *display);
+static void impl_window_add_update_area (GdkWindowObject *impl_window,
+ GdkRegion *region);
static void gdk_window_region_move_free (GdkWindowRegionMove *move);
+static void gdk_window_invalidate_region_full (GdkWindow *window,
+ const GdkRegion *region,
+ gboolean invalidate_children,
+ ClearBg clear_bg);
+static void gdk_window_invalidate_rect_full (GdkWindow *window,
+ const GdkRectangle *rect,
+ gboolean invalidate_children,
+ ClearBg clear_bg);
static guint signals[LAST_SIGNAL] = { 0 };
/* Properties */
g_object_class_install_property (object_class,
PROP_CURSOR,
- g_param_spec_pointer ("cursor",
- P_("Cursor"),
- P_("Cursor"),
- G_PARAM_READWRITE));
+ g_param_spec_boxed ("cursor",
+ P_("Cursor"),
+ P_("Cursor"),
+ GDK_TYPE_CURSOR,
+ G_PARAM_READWRITE));
/**
* GdkWindow::pick-embedded-child:
switch (prop_id)
{
case PROP_CURSOR:
- gdk_window_set_cursor (window, g_value_get_pointer (value));
+ gdk_window_set_cursor (window, g_value_get_boxed (value));
break;
default:
switch (prop_id)
{
case PROP_CURSOR:
- g_value_set_pointer (value, gdk_window_get_cursor (window));
+ g_value_set_boxed (value, gdk_window_get_cursor (window));
break;
default:
return private->event_mask;
else
{
- return
- /* We need thse for all native window so we can emulate
- events on children: */
+ GdkEventMask mask;
+
+ /* Do whatever the app asks to, since the app
+ * may be asking for weird things for native windows,
+ * but don't use motion hints as that may affect non-native
+ * child windows that don't want it. Also, we need to
+ * set all the app-specified masks since they will be picked
+ * up by any implicit grabs (i.e. if they were not set as
+ * native we would not get the events we need). */
+ mask = private->event_mask & ~GDK_POINTER_MOTION_HINT_MASK;
+
+ /* We need thse for all native windows so we can
+ emulate events on children: */
+ mask |=
GDK_EXPOSURE_MASK |
GDK_VISIBILITY_NOTIFY_MASK |
- GDK_POINTER_MOTION_MASK |
- GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
- GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
- GDK_SCROLL_MASK |
- /* Then do whatever the app asks to, since the app
- * may be asking for weird things for native windows,
- * but filter out things that override the above
- * requests somehow. */
- (private->event_mask &
- ~(GDK_POINTER_MOTION_HINT_MASK |
- GDK_BUTTON_MOTION_MASK |
- GDK_BUTTON1_MOTION_MASK |
- GDK_BUTTON2_MOTION_MASK |
- GDK_BUTTON3_MOTION_MASK));
+ GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK;
+
+ /* Additionally we select for pointer and button events
+ * for toplevels as we need to get these to emulate
+ * them for non-native subwindows. Even though we don't
+ * select on them for all native windows we will get them
+ * as the events are propagated out to the first window
+ * that select for them.
+ * Not selecting for button press on all windows is an
+ * important thing, because in X only one client can do
+ * so, and we don't want to unexpectedly prevent another
+ * client from doing it.
+ */
+ if (gdk_window_is_toplevel (private))
+ mask |=
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_SCROLL_MASK;
+
+ return mask;
}
}
+static GdkEventMask
+get_native_grab_event_mask (GdkEventMask grab_mask)
+{
+ /* Similar to the above but for pointer events only */
+ return
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
+ GDK_SCROLL_MASK |
+ (grab_mask &
+ ~GDK_POINTER_MOTION_HINT_MASK);
+}
+
/* Puts the native window in the right order wrt the other native windows
* in the hierarchy, given the position it has in the client side data.
* This is useful if some operation changed the stacking order.
/**
* gdk_window_new:
- * @parent: a #GdkWindow, or %NULL to create the window as a child of
+ * @parent: (allow-none): a #GdkWindow, or %NULL to create the window as a child of
* the default root window for the default display.
* @attributes: attributes of the new window
* @attributes_mask: mask indicating which fields in @attributes are valid
* more details. Note: to use this on displays other than the default
* display, @parent must be specified.
*
- * Return value: the new #GdkWindow
+ * Return value: (transfer none): the new #GdkWindow
**/
GdkWindow*
gdk_window_new (GdkWindow *parent,
_gdk_synthesize_crossing_events_for_geometry_change (window);
}
+static gboolean
+temporary_disable_extension_events (GdkWindowObject *window)
+{
+ GdkWindowObject *child;
+ GList *l;
+ gboolean res;
+
+ if (window->extension_events != 0)
+ {
+ g_object_set_data (G_OBJECT (window),
+ "gdk-window-extension-events",
+ GINT_TO_POINTER (window->extension_events));
+ gdk_input_set_extension_events ((GdkWindow *)window, 0,
+ GDK_EXTENSION_EVENTS_NONE);
+ }
+ else
+ res = FALSE;
+
+ for (l = window->children; l != NULL; l = l->next)
+ {
+ child = l->data;
+
+ if (window->impl_window == child->impl_window)
+ res |= temporary_disable_extension_events (window);
+ }
+
+ return res;
+}
+
+static void
+reenable_extension_events (GdkWindowObject *window)
+{
+ GdkWindowObject *child;
+ GList *l;
+ int mask;
+
+ mask = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window),
+ "gdk-window-extension-events"));
+
+ if (mask != 0)
+ {
+ /* We don't have the mode here, so we pass in cursor.
+ This works with the current code since mode is not
+ stored except as part of the mask, and cursor doesn't
+ change the mask. */
+ gdk_input_set_extension_events ((GdkWindow *)window, mask,
+ GDK_EXTENSION_EVENTS_CURSOR);
+ g_object_set_data (G_OBJECT (window),
+ "gdk-window-extension-events",
+ NULL);
+ }
+
+ for (l = window->children; l != NULL; l = l->next)
+ {
+ child = l->data;
+
+ if (window->impl_window == child->impl_window)
+ reenable_extension_events (window);
+ }
+}
+
/**
* gdk_window_ensure_native:
* @window: a #GdkWindow
GdkWindowObject *above;
GList listhead;
GdkWindowImplIface *impl_iface;
+ gboolean disabled_extension_events;
g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
/* Need to create a native window */
+ /* First we disable any extension events on the window or its
+ descendants to handle the native input window moving */
+ disabled_extension_events = FALSE;
+ if (impl_window->input_window)
+ disabled_extension_events = temporary_disable_extension_events (private);
+
screen = gdk_drawable_get_screen (window);
visual = gdk_drawable_get_visual (window);
if (gdk_window_is_viewable (window))
impl_iface->show (window, FALSE);
+ if (disabled_extension_events)
+ reenable_extension_events (private);
+
return TRUE;
}
return GDK_WINDOW_TYPE (window);
}
+/**
+ * gdk_window_is_destroyed:
+ * @window: a #GdkWindow
+ *
+ * Check to see if a window is destroyed..
+ *
+ * Return value: %TRUE if the window is destroyed
+ **/
+gboolean
+gdk_window_is_destroyed (GdkWindow *window)
+{
+ return GDK_WINDOW_DESTROYED (window);
+}
+
/**
* gdk_window_get_position:
* @window: a #GdkWindow
private->implicit_paint != NULL)
return FALSE; /* Don't stack implicit paints */
+ /* Never do implicit paints for foreign windows, they don't need
+ * double buffer combination since they have no client side children,
+ * and creating pixmaps for them is risky since they could disappear
+ * at any time
+ */
+ if (private->window_type == GDK_WINDOW_FOREIGN)
+ return FALSE;
+
paint = g_new (GdkWindowPaint, 1);
paint->region = gdk_region_new (); /* Empty */
paint->x_offset = rect->x;
paint->y_offset = rect->y;
paint->uses_implicit = FALSE;
+ paint->flushed = FALSE;
paint->surface = NULL;
paint->pixmap =
gdk_pixmap_new (window,
return;
paint = impl_window->implicit_paint;
+ paint->flushed = TRUE;
region = gdk_region_copy (private->clip_region_with_children);
/* Don't flush active double buffers, as that may show partially done
if (!gdk_region_empty (region))
{
+ /* Remove flushed region from the implicit paint */
+ gdk_region_subtract (paint->region, region);
+
/* Some regions are valid, push these to window now */
tmp_gc = _gdk_drawable_get_scratch_gc ((GdkDrawable *)window, FALSE);
_gdk_gc_set_clip_region_internal (tmp_gc, region, TRUE);
0, 0, paint->x_offset, paint->y_offset, -1, -1);
/* Reset clip region of the cached GdkGC */
gdk_gc_set_clip_region (tmp_gc, NULL);
-
- /* Remove flushed region from the implicit paint */
- gdk_region_subtract (paint->region, region);
}
else
gdk_region_destroy (region);
/* Reset clip region of the cached GdkGC */
gdk_gc_set_clip_region (tmp_gc, NULL);
}
+ else
+ gdk_region_destroy (paint->region);
g_object_unref (paint->pixmap);
g_free (paint);
/* Moves bits and update area by dx/dy in impl window.
Takes ownership of region to avoid copy (because we may change it) */
static void
-move_region_on_impl (GdkWindowObject *private,
+move_region_on_impl (GdkWindowObject *impl_window,
GdkRegion *region, /* In impl window coords */
int dx, int dy)
{
- GdkWindowObject *impl_window;
-
if ((dx == 0 && dy == 0) ||
gdk_region_empty (region))
{
return;
}
- impl_window = gdk_window_get_impl_window (private);
+ g_assert (impl_window == gdk_window_get_impl_window (impl_window));
/* Move any old invalid regions in the copy source area by dx/dy */
if (impl_window->update_area)
{
GdkRegion *update_area;
+
update_area = gdk_region_copy (region);
/* Convert from target to source */
gdk_region_destroy (update_area);
}
+ /* If we're currently exposing this window, don't copy to this
+ destination, as it will be overdrawn when the expose is done,
+ instead invalidate it and repaint later. */
+ if (impl_window->implicit_paint)
+ {
+ GdkWindowPaint *implicit_paint = impl_window->implicit_paint;
+ GdkRegion *exposing;
+
+ exposing = gdk_region_copy (implicit_paint->region);
+ gdk_region_intersect (exposing, region);
+ gdk_region_subtract (region, exposing);
+
+ impl_window_add_update_area (impl_window, exposing);
+ gdk_region_destroy (exposing);
+ }
+
if (1) /* Enable flicker free handling of moves. */
append_move_region (impl_window, region, dx, dy);
else
impl_window->outstanding_moves = NULL;
}
-static void
+/**
+ * gdk_window_flush:
+ * @window: a #GdkWindow
+ *
+ * Flush all outstanding cached operations on a window, leaving the
+ * window in a state which reflects all that has been drawn before.
+ *
+ * Gdk uses multiple kinds of caching to get better performance and
+ * nicer drawing. For instance, during exposes all paints to a window
+ * using double buffered rendering are keep on a pixmap until the last
+ * window has been exposed. It also delays window moves/scrolls until
+ * as long as possible until next update to avoid tearing when moving
+ * windows.
+ *
+ * Normally this should be completely invisible to applications, as
+ * we automatically flush the windows when required, but this might
+ * be needed if you for instance mix direct native drawing with
+ * gdk drawing. For Gtk widgets that don't use double buffering this
+ * will be called automatically before sending the expose event.
+ *
+ * Since: 2.18
+ **/
+void
gdk_window_flush (GdkWindow *window)
{
gdk_window_flush_outstanding_moves (window);
gdk_window_flush_implicit_paint (window);
}
+/* If we're about to move/resize or otherwise change the
+ * hierarchy of a client side window in an impl and we're
+ * called from an expose event handler then we need to
+ * flush any already painted parts of the implicit paint
+ * that are not part of the current paint, as these may
+ * be used when scrolling or may overdraw the changes
+ * caused by the hierarchy change.
+ */
+static void
+gdk_window_flush_if_exposing (GdkWindow *window)
+{
+ GdkWindowObject *private;
+ GdkWindowObject *impl_window;
+
+ private = (GdkWindowObject *) window;
+ impl_window = gdk_window_get_impl_window (private);
+
+ /* If we're in an implicit paint (i.e. in an expose handler, flush
+ all the already finished exposes to get things to an uptodate state. */
+ if (impl_window->implicit_paint)
+ gdk_window_flush (window);
+}
+
+
static void
gdk_window_flush_recursive_helper (GdkWindowObject *window,
GdkWindow *impl)
/**
* gdk_window_get_internal_paint_info:
* @window: a #GdkWindow
- * @real_drawable: location to store the drawable to which drawing should be
+ * @real_drawable: (out): location to store the drawable to which drawing should be
* done.
- * @x_offset: location to store the X offset between coordinates in @window,
+ * @x_offset: (out): location to store the X offset between coordinates in @window,
* and the underlying window system primitive coordinates for
* *@real_drawable.
- * @y_offset: location to store the Y offset between coordinates in @window,
+ * @y_offset: (out): location to store the Y offset between coordinates in @window,
* and the underlying window system primitive coordinates for
* *@real_drawable.
*
clip = private->clip_region;
gdk_region_intersect (exposure_region, clip);
+ _gdk_gc_remove_drawable_clip (gc);
clip = _gdk_gc_get_clip_region (gc);
if (clip)
{
gdk_region_subtract (exposure_region, clip);
gdk_region_destroy (clip);
- gdk_window_invalidate_region (GDK_WINDOW (private),
- exposure_region,
- _gdk_gc_get_subwindow (gc) == GDK_INCLUDE_INFERIORS);
+ gdk_window_invalidate_region_full (GDK_WINDOW (private),
+ exposure_region,
+ _gdk_gc_get_subwindow (gc) == GDK_INCLUDE_INFERIORS,
+ CLEAR_BG_ALL);
gdk_region_destroy (exposure_region);
}
width, height);
}
+/* TRUE if the window clears to the same pixels as a native
+ window clear. This means you can use the native window
+ clearing operation, and additionally it means any clearing
+ done by the native window system for you will already be right */
static gboolean
-clears_on_native (GdkWindowObject *private)
+clears_as_native (GdkWindowObject *private)
{
GdkWindowObject *next;
impl_iface = GDK_WINDOW_IMPL_GET_IFACE (private->impl);
- if (impl_iface->clear_region && clears_on_native (private))
+ if (impl_iface->clear_region && clears_as_native (private))
{
GdkRegion *copy;
copy = gdk_region_copy (region);
gdk_region_intersect (copy,
private->clip_region_with_children);
+
+ /* Drawing directly to the window, flush anything outstanding to
+ guarantee ordering. */
+ gdk_window_flush (window);
impl_iface->clear_region (window, copy, send_expose);
gdk_region_destroy (copy);
gint height,
gboolean send_expose)
{
- GdkWindowObject *private = (GdkWindowObject *)window;
GdkRectangle rect;
GdkRegion *region;
if (GDK_WINDOW_DESTROYED (window))
return;
- /* This is what XClearArea does, and e.g. GtkCList uses it,
- so we need to duplicate that */
- if (width == 0)
- width = private->width - x;
- if (height == 0)
- height = private->height - y;
+ /* Terminate early to avoid weird interpretation of
+ zero width/height by XClearArea */
+ if (width == 0 || height == 0)
+ return;
rect.x = x;
rect.y = y;
return;
if (!update_idle)
- {
- update_idle = gdk_threads_add_idle_full (GDK_PRIORITY_REDRAW,
- gdk_window_update_idle, NULL, NULL);
- }
+ update_idle =
+ gdk_threads_add_idle_full (GDK_PRIORITY_REDRAW,
+ gdk_window_update_idle,
+ NULL, NULL);
}
void
g_object_unref (window);
}
- else if (private->bg_pixmap != GDK_NO_BG)
+ else if (private->bg_pixmap != GDK_NO_BG &&
+ private->window_type != GDK_WINDOW_FOREIGN)
{
/* No exposure mask set, so nothing will be drawn, the
* app relies on the background being what it specified
* for the window. So, we need to clear this manually.
*
+ * For foreign windows if expose is not set that generally
+ * means some other client paints them, so don't clear
+ * there.
+ *
* We use begin/end_paint around the clear so that we can
* piggyback on the implicit paint */
GdkRegion *update_area = private->update_area;
private->update_area = NULL;
- if (_gdk_event_func && gdk_window_is_viewable (window) &&
- private->window_type != GDK_WINDOW_FOREIGN)
+ if (_gdk_event_func && gdk_window_is_viewable (window))
{
GdkRegion *expose_region;
gboolean end_implicit;
* be to late to anti-expose now. Since this is merely an
* optimization we just avoid doing it at all in that case.
*/
- if (private->implicit_paint != NULL) /* didn't flush implicit paint */
+ if (private->implicit_paint != NULL &&
+ !private->implicit_paint->flushed)
{
impl_iface = GDK_WINDOW_IMPL_GET_IFACE (private->impl);
save_region = impl_iface->queue_antiexpose (window, update_area);
GSList *old_update_windows = update_windows;
GSList *tmp_list = update_windows;
static gboolean in_process_all_updates = FALSE;
+ static gboolean got_recursive_update = FALSE;
if (in_process_all_updates)
- return;
+ {
+ /* We can't do this now since that would recurse, so
+ delay it until after the recursion is done. */
+ got_recursive_update = TRUE;
+ update_idle = 0;
+ return;
+ }
in_process_all_updates = TRUE;
+ got_recursive_update = FALSE;
if (update_idle)
g_source_remove (update_idle);
_gdk_windowing_after_process_all_updates ();
in_process_all_updates = FALSE;
+
+ /* If we ignored a recursive call, schedule a
+ redraw now so that it eventually happens,
+ otherwise we could miss an update if nothing
+ else schedules an update. */
+ if (got_recursive_update && !update_idle)
+ update_idle =
+ gdk_threads_add_idle_full (GDK_PRIORITY_REDRAW,
+ gdk_window_update_idle,
+ NULL, NULL);
}
/**
if ((impl_window->update_area ||
impl_window->outstanding_moves) &&
!impl_window->update_freeze_count &&
- !gdk_window_is_toplevel_frozen (window))
+ !gdk_window_is_toplevel_frozen (window) &&
+
+ /* Don't recurse into process_updates_internal, we'll
+ * do the update later when idle instead. */
+ impl_window->implicit_paint == NULL)
{
gdk_window_process_updates_internal ((GdkWindow *)impl_window);
gdk_window_remove_update_window ((GdkWindow *)impl_window);
g_object_unref (window);
}
-/**
- * gdk_window_invalidate_rect:
- * @window: a #GdkWindow
- * @rect: rectangle to invalidate or %NULL to invalidate the whole
- * window
- * @invalidate_children: whether to also invalidate child windows
- *
- * A convenience wrapper around gdk_window_invalidate_region() which
- * invalidates a rectangular region. See
- * gdk_window_invalidate_region() for details.
- **/
-void
-gdk_window_invalidate_rect (GdkWindow *window,
- const GdkRectangle *rect,
- gboolean invalidate_children)
+static void
+gdk_window_invalidate_rect_full (GdkWindow *window,
+ const GdkRectangle *rect,
+ gboolean invalidate_children,
+ ClearBg clear_bg)
{
GdkRectangle window_rect;
GdkRegion *region;
}
region = gdk_region_rectangle (rect);
- gdk_window_invalidate_region (window, region, invalidate_children);
+ gdk_window_invalidate_region_full (window, region, invalidate_children, clear_bg);
gdk_region_destroy (region);
}
+/**
+ * gdk_window_invalidate_rect:
+ * @window: a #GdkWindow
+ * @rect: rectangle to invalidate or %NULL to invalidate the whole
+ * window
+ * @invalidate_children: whether to also invalidate child windows
+ *
+ * A convenience wrapper around gdk_window_invalidate_region() which
+ * invalidates a rectangular region. See
+ * gdk_window_invalidate_region() for details.
+ **/
+void
+gdk_window_invalidate_rect (GdkWindow *window,
+ const GdkRectangle *rect,
+ gboolean invalidate_children)
+{
+ gdk_window_invalidate_rect_full (window, rect, invalidate_children, CLEAR_BG_NONE);
+}
+
static void
draw_ugly_color (GdkWindow *window,
const GdkRegion *region)
g_object_unref (ugly_gc);
}
-/**
- * gdk_window_invalidate_maybe_recurse:
- * @window: a #GdkWindow
- * @region: a #GdkRegion
- * @child_func: function to use to decide if to recurse to a child,
- * %NULL means never recurse.
- * @user_data: data passed to @child_func
- *
- * Adds @region to the update area for @window. The update area is the
- * region that needs to be redrawn, or "dirty region." The call
- * gdk_window_process_updates() sends one or more expose events to the
- * window, which together cover the entire update area. An
- * application would normally redraw the contents of @window in
- * response to those expose events.
- *
- * GDK will call gdk_window_process_all_updates() on your behalf
- * whenever your program returns to the main loop and becomes idle, so
- * normally there's no need to do that manually, you just need to
- * invalidate regions that you know should be redrawn.
- *
- * The @child_func parameter controls whether the region of
- * each child window that intersects @region will also be invalidated.
- * Only children for which @child_func returns TRUE will have the area
- * invalidated.
- **/
-void
-gdk_window_invalidate_maybe_recurse (GdkWindow *window,
- const GdkRegion *region,
- gboolean (*child_func) (GdkWindow *,
- gpointer),
- gpointer user_data)
+static void
+impl_window_add_update_area (GdkWindowObject *impl_window,
+ GdkRegion *region)
+{
+ if (impl_window->update_area)
+ gdk_region_union (impl_window->update_area, region);
+ else
+ {
+ gdk_window_add_update_window ((GdkWindow *)impl_window);
+ impl_window->update_area = gdk_region_copy (region);
+ gdk_window_schedule_update ((GdkWindow *)impl_window);
+ }
+}
+
+/* clear_bg controls if the region will be cleared to
+ * the background color/pixmap if the exposure mask is not
+ * set for the window, whereas this might not otherwise be
+ * done (unless necessary to emulate background settings).
+ * Set this to CLEAR_BG_WINCLEARED or CLEAR_BG_ALL if you
+ * need to clear the background, such as when exposing the area beneath a
+ * hidden or moved window, but not when an app requests repaint or when the
+ * windowing system exposes a newly visible area (because then the windowing
+ * system has already cleared the area).
+ */
+static void
+gdk_window_invalidate_maybe_recurse_full (GdkWindow *window,
+ const GdkRegion *region,
+ ClearBg clear_bg,
+ gboolean (*child_func) (GdkWindow *,
+ gpointer),
+ gpointer user_data)
{
GdkWindowObject *private = (GdkWindowObject *)window;
GdkWindowObject *impl_window;
gdk_region_offset (child_region, - child_rect.x, - child_rect.y);
gdk_region_intersect (child_region, tmp);
- gdk_window_invalidate_maybe_recurse ((GdkWindow *)child,
- child_region, child_func, user_data);
+ gdk_window_invalidate_maybe_recurse_full ((GdkWindow *)child,
+ child_region, clear_bg, child_func, user_data);
gdk_region_destroy (tmp);
}
/* Convert to impl coords */
gdk_region_offset (visible_region, private->abs_x, private->abs_y);
- if (impl_window->update_area)
- {
- gdk_region_union (impl_window->update_area, visible_region);
- }
- else
- {
- gdk_window_add_update_window ((GdkWindow *)impl_window);
- impl_window->update_area = gdk_region_copy (visible_region);
- gdk_window_schedule_update ((GdkWindow *)impl_window);
- }
+ /* Only invalidate area if app requested expose events or if
+ we need to clear the area (by request or to emulate background
+ clearing for non-native windows or native windows with no support
+ for window backgrounds */
+ if (private->event_mask & GDK_EXPOSURE_MASK ||
+ clear_bg == CLEAR_BG_ALL ||
+ (clear_bg == CLEAR_BG_WINCLEARED &&
+ (!clears_as_native (private) ||
+ !GDK_WINDOW_IMPL_GET_IFACE (private->impl)->supports_native_bg)))
+ impl_window_add_update_area (impl_window, visible_region);
}
gdk_region_destroy (visible_region);
}
+/**
+ * gdk_window_invalidate_maybe_recurse:
+ * @window: a #GdkWindow
+ * @region: a #GdkRegion
+ * @child_func: function to use to decide if to recurse to a child,
+ * %NULL means never recurse.
+ * @user_data: data passed to @child_func
+ *
+ * Adds @region to the update area for @window. The update area is the
+ * region that needs to be redrawn, or "dirty region." The call
+ * gdk_window_process_updates() sends one or more expose events to the
+ * window, which together cover the entire update area. An
+ * application would normally redraw the contents of @window in
+ * response to those expose events.
+ *
+ * GDK will call gdk_window_process_all_updates() on your behalf
+ * whenever your program returns to the main loop and becomes idle, so
+ * normally there's no need to do that manually, you just need to
+ * invalidate regions that you know should be redrawn.
+ *
+ * The @child_func parameter controls whether the region of
+ * each child window that intersects @region will also be invalidated.
+ * Only children for which @child_func returns TRUE will have the area
+ * invalidated.
+ **/
+void
+gdk_window_invalidate_maybe_recurse (GdkWindow *window,
+ const GdkRegion *region,
+ gboolean (*child_func) (GdkWindow *,
+ gpointer),
+ gpointer user_data)
+{
+ gdk_window_invalidate_maybe_recurse_full (window, region, CLEAR_BG_NONE,
+ child_func, user_data);
+}
+
static gboolean
true_predicate (GdkWindow *window,
gpointer user_data)
return TRUE;
}
+static void
+gdk_window_invalidate_region_full (GdkWindow *window,
+ const GdkRegion *region,
+ gboolean invalidate_children,
+ ClearBg clear_bg)
+{
+ gdk_window_invalidate_maybe_recurse_full (window, region, clear_bg,
+ invalidate_children ?
+ true_predicate : (gboolean (*) (GdkWindow *, gpointer))NULL,
+ NULL);
+}
+
/**
* gdk_window_invalidate_region:
* @window: a #GdkWindow
gdk_region_destroy (move_region);
}
- gdk_window_invalidate_maybe_recurse (window, region,
- (gboolean (*) (GdkWindow *, gpointer))gdk_window_has_no_impl,
- NULL);
+ gdk_window_invalidate_maybe_recurse_full (window, region, CLEAR_BG_WINCLEARED,
+ (gboolean (*) (GdkWindow *, gpointer))gdk_window_has_no_impl,
+ NULL);
}
/**
* gdk_window_get_pointer:
* @window: a #GdkWindow
- * @x: return location for X coordinate of pointer or %NULL to not
+ * @x: (out) (allow-none): return location for X coordinate of pointer or %NULL to not
* return the X coordinate
- * @y: return location for Y coordinate of pointer or %NULL to not
+ * @y: (out) (allow-none): return location for Y coordinate of pointer or %NULL to not
* return the Y coordinate
- * @mask: return location for modifier mask or %NULL to not return the
+ * @mask: (out) (allow-none): return location for modifier mask or %NULL to not return the
* modifier mask
*
* Obtains the current pointer position and modifier state.
* The position is given in coordinates relative to the upper left
* corner of @window.
*
- * Return value: the window containing the pointer (as with
+ * Return value: (transfer none): the window containing the pointer (as with
* gdk_window_at_pointer()), or %NULL if the window containing the
* pointer isn't known to GDK
**/
/**
* gdk_window_at_pointer:
- * @win_x: return location for origin of the window under the pointer
- * @win_y: return location for origin of the window under the pointer
+ * @win_x: (out) (allow-none): return location for origin of the window under the pointer
+ * @win_y: (out) (allow-none): return location for origin of the window under the pointer
*
* Obtains the window underneath the mouse pointer, returning the
* location of that window in @win_x, @win_y. Returns %NULL if the
* NOTE: For multihead-aware widgets or applications use
* gdk_display_get_window_at_pointer() instead.
*
- * Return value: window under the mouse pointer
+ * Return value: (transfer none): window under the mouse pointer
**/
GdkWindow*
gdk_window_at_pointer (gint *win_x,
if (gdk_window_is_viewable (window))
{
_gdk_synthesize_crossing_events_for_geometry_change (window);
- gdk_window_invalidate_rect (window, NULL, TRUE);
+ gdk_window_invalidate_rect_full (window, NULL, TRUE, CLEAR_BG_ALL);
}
}
}
if (private->destroyed)
return;
+ gdk_window_flush_if_exposing (window);
+
old_region = NULL;
if (gdk_window_is_viewable (window) &&
!private->input_only)
new_region = gdk_region_copy (private->clip_region);
gdk_region_subtract (new_region, old_region);
- gdk_window_invalidate_region (window, new_region, TRUE);
+ gdk_window_invalidate_region_full (window, new_region, TRUE, CLEAR_BG_ALL);
gdk_region_destroy (old_region);
gdk_region_destroy (new_region);
child.height = private->height;
gdk_rectangle_intersect (&r, &child, &r);
- gdk_window_invalidate_rect (GDK_WINDOW (private->parent), &r, TRUE);
+ gdk_window_invalidate_rect_full (GDK_WINDOW (private->parent), &r, TRUE, CLEAR_BG_ALL);
}
if (private->destroyed)
return;
+ gdk_window_flush_if_exposing (window);
+
/* Keep children in (reverse) stacking order */
gdk_window_lower_internal (window);
gdk_window_invalidate_in_parent (private);
}
+/**
+ * gdk_window_restack:
+ * @window: a #GdkWindow
+ * @sibling: a #GdkWindow that is a sibling of @window, or %NULL
+ * @above: a boolean
+ *
+ * Changes the position of @window in the Z-order (stacking order), so that
+ * it is above @sibling (if @above is %TRUE) or below @sibling (if @above is
+ * %FALSE).
+ *
+ * If @sibling is %NULL, then this either raises (if @above is %TRUE) or
+ * lowers the window.
+ *
+ * If @window is a toplevel, the window manager may choose to deny the
+ * request to move the window in the Z-order, gdk_window_restack() only
+ * requests the restack, does not guarantee it.
+ *
+ * Since: 2.18
+ */
+void
+gdk_window_restack (GdkWindow *window,
+ GdkWindow *sibling,
+ gboolean above)
+{
+ GdkWindowObject *private;
+ GdkWindowImplIface *impl_iface;
+ GdkWindowObject *parent;
+ GdkWindowObject *above_native;
+ GList *sibling_link;
+ GList *native_children;
+ GList *l, listhead;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+ g_return_if_fail (sibling == NULL || GDK_IS_WINDOW (sibling));
+
+ private = (GdkWindowObject *) window;
+ if (private->destroyed)
+ return;
+
+ if (sibling == NULL)
+ {
+ if (above)
+ gdk_window_raise (window);
+ else
+ gdk_window_lower (window);
+ return;
+ }
+
+ gdk_window_flush_if_exposing (window);
+
+ if (gdk_window_is_toplevel (private))
+ {
+ g_return_if_fail (gdk_window_is_toplevel (GDK_WINDOW_OBJECT (sibling)));
+ impl_iface = GDK_WINDOW_IMPL_GET_IFACE (private->impl);
+ impl_iface->restack_toplevel (window, sibling, above);
+ return;
+ }
+
+ parent = private->parent;
+ if (parent)
+ {
+ sibling_link = g_list_find (parent->children, sibling);
+ g_return_if_fail (sibling_link != NULL);
+ if (sibling_link == NULL)
+ return;
+
+ parent->children = g_list_remove (parent->children, window);
+ if (above)
+ parent->children = g_list_insert_before (parent->children,
+ sibling_link,
+ window);
+ else
+ parent->children = g_list_insert_before (parent->children,
+ sibling_link->next,
+ window);
+
+ impl_iface = GDK_WINDOW_IMPL_GET_IFACE (private->impl);
+ if (gdk_window_has_impl (private))
+ {
+ above_native = find_native_sibling_above (parent, private);
+ if (above_native)
+ {
+ listhead.data = window;
+ listhead.next = NULL;
+ listhead.prev = NULL;
+ impl_iface->restack_under ((GdkWindow *)above_native, &listhead);
+ }
+ else
+ impl_iface->raise (window);
+ }
+ else
+ {
+ native_children = NULL;
+ get_all_native_children (private, &native_children);
+ if (native_children != NULL)
+ {
+ above_native = find_native_sibling_above (parent, private);
+ if (above_native)
+ impl_iface->restack_under ((GdkWindow *)above_native,
+ native_children);
+ else
+ {
+ /* Right order, since native_children is bottom-topmost first */
+ for (l = native_children; l != NULL; l = l->next)
+ impl_iface->raise (l->data);
+ }
+
+ g_list_free (native_children);
+ }
+ }
+ }
+
+ recompute_visible_regions (private, TRUE, FALSE);
+
+ _gdk_synthesize_crossing_events_for_geometry_change (window);
+ gdk_window_invalidate_in_parent (private);
+}
+
+
/**
* gdk_window_show:
* @window: a #GdkWindow
}
/* Invalidate the rect */
- gdk_window_invalidate_in_parent (private);
+ if (was_mapped)
+ gdk_window_invalidate_in_parent (private);
}
/**
* roundtrip
*/
gdk_region_subtract (new_region, old_region);
- gdk_window_invalidate_region (window, new_region, TRUE);
+ gdk_window_invalidate_region_full (window, new_region, TRUE, CLEAR_BG_WINCLEARED);
gdk_region_destroy (old_region);
gdk_region_destroy (new_region);
return;
}
+ /* Bail early if no change */
+ if (private->width == width &&
+ private->height == height &&
+ (!with_move ||
+ (private->x == x &&
+ private->y == y)))
+ return;
+
+ gdk_window_flush_if_exposing (window);
+
/* Handle child windows */
expose = FALSE;
native windows, as we can't read that data */
gdk_region_offset (new_native_child_region, dx, dy);
gdk_region_subtract (copy_area, new_native_child_region);
+ gdk_region_offset (new_native_child_region, -dx, -dy);
}
gdk_region_subtract (new_region, copy_area);
* We also invalidate any children in that area, which could include
* this window if it still overlaps that area.
*/
- gdk_window_invalidate_region (GDK_WINDOW (private->parent), new_region, TRUE);
+ if (old_native_child_region)
+ {
+ /* No need to expose the region that the native window move copies */
+ gdk_region_offset (old_native_child_region, dx, dy);
+ gdk_region_intersect (old_native_child_region, new_native_child_region);
+ gdk_region_subtract (new_region, old_native_child_region);
+ }
+ gdk_window_invalidate_region_full (GDK_WINDOW (private->parent), new_region, TRUE, CLEAR_BG_ALL);
gdk_region_destroy (old_region);
gdk_region_destroy (new_region);
if (private->destroyed)
return;
+ gdk_window_flush_if_exposing (window);
+
old_native_child_region = collect_native_child_region (private, FALSE);
if (old_native_child_region)
{
move_region_on_impl (impl_window, copy_area, dx, dy); /* takes ownership of copy_area */
/* Invalidate not copied regions */
- gdk_window_invalidate_region (window, noncopy_area, TRUE);
+ if (old_native_child_region)
+ {
+ /* No need to expose the region that the native window move copies */
+ gdk_region_offset (old_native_child_region, dx, dy);
+ gdk_region_intersect (old_native_child_region, new_native_child_region);
+ gdk_region_subtract (noncopy_area, old_native_child_region);
+ }
+ gdk_window_invalidate_region_full (window, noncopy_area, TRUE, CLEAR_BG_ALL);
gdk_region_destroy (noncopy_area);
gdk_region_offset (copy_area, private->abs_x, private->abs_y);
move_region_on_impl (impl_window, copy_area, dx, dy); /* Takes ownership of copy_area */
- gdk_window_invalidate_region (window, nocopy_area, FALSE);
+ gdk_window_invalidate_region_full (window, nocopy_area, FALSE, CLEAR_BG_ALL);
gdk_region_destroy (nocopy_area);
}
diff = gdk_region_copy (new_region);
gdk_region_subtract (diff, old_region);
- gdk_window_invalidate_region (window, diff, TRUE);
+ gdk_window_invalidate_region_full (window, diff, TRUE, CLEAR_BG_ALL);
gdk_region_destroy (diff);
/* Adjust region to parent window coords */
gdk_region_offset (diff, private->x, private->y);
- gdk_window_invalidate_region (GDK_WINDOW (private->parent), diff, TRUE);
+ gdk_window_invalidate_region_full (GDK_WINDOW (private->parent), diff, TRUE, CLEAR_BG_ALL);
gdk_region_destroy (diff);
}
{
GList *cur;
GdkRectangle real_clip_rect;
- gboolean is_offscreen;
if (parentwin != private)
{
y_offset += GDK_WINDOW_OBJECT (lastwin)->y;
}
- is_offscreen = gdk_window_is_offscreen (parentwin);
-
/* children is ordered in reverse stack order */
for (cur = parentwin->children;
cur && cur->data != lastwin;
static void
update_cursor (GdkDisplay *display)
{
- GdkWindowObject *pointer_window, *cursor_window, *parent, *toplevel;
+ GdkWindowObject *cursor_window, *parent, *toplevel;
+ GdkWindow *pointer_window;
GdkWindowImplIface *impl_iface;
GdkPointerGrabInfo *grab;
- pointer_window = (GdkWindowObject *)display->pointer_info.window_under_pointer;
-
- cursor_window = pointer_window;
- while (cursor_window->cursor == NULL &&
- (parent = get_event_parent (cursor_window)) != NULL &&
- parent->window_type != GDK_WINDOW_ROOT)
- cursor_window = parent;
+ pointer_window = display->pointer_info.window_under_pointer;
/* We ignore the serials here and just pick the last grab
we've sent, as that would shortly be used anyway. */
grab = _gdk_display_get_last_pointer_grab (display);
- if (grab != NULL &&
- !_gdk_window_event_parent_of (grab->window, (GdkWindow *)cursor_window))
+ if (/* have grab */
+ grab != NULL &&
+ /* the pointer is not in a descendant of the grab window */
+ !_gdk_window_event_parent_of (grab->window, pointer_window))
+ /* use the cursor from the grab window */
cursor_window = (GdkWindowObject *)grab->window;
+ else
+ /* otherwise use the cursor from the pointer window */
+ cursor_window = (GdkWindowObject *)pointer_window;
+
+ /* Find the first window with the cursor actually set, as
+ the cursor is inherited from the parent */
+ while (cursor_window->cursor == NULL &&
+ (parent = get_event_parent (cursor_window)) != NULL &&
+ parent->window_type != GDK_WINDOW_ROOT)
+ cursor_window = parent;
/* Set all cursors on toplevel, otherwise its tricky to keep track of
* which native window has what cursor set. */
- toplevel = (GdkWindowObject *)get_event_toplevel ((GdkWindow *)pointer_window);
+ toplevel = (GdkWindowObject *)get_event_toplevel (pointer_window);
impl_iface = GDK_WINDOW_IMPL_GET_IFACE (toplevel->impl);
impl_iface->set_cursor ((GdkWindow *)toplevel, cursor_window->cursor);
}
gulong serial)
{
GdkEvent *event;
- guint32 event_mask;
+ guint32 window_event_mask, type_event_mask;
GdkPointerGrabInfo *grab;
GdkWindowImplIface *impl_iface;
grab = _gdk_display_has_pointer_grab (display, serial);
if (grab != NULL &&
- !grab->owner_events &&
- (GdkWindow *)window != grab->window)
- return;
+ !grab->owner_events)
+ {
+ /* !owner_event => only report events wrt grab window, ignore rest */
+ if ((GdkWindow *)window != grab->window)
+ return;
+ window_event_mask = grab->event_mask;
+ }
+ else
+ window_event_mask = window->event_mask;
if (type == GDK_LEAVE_NOTIFY)
- event_mask = GDK_LEAVE_NOTIFY_MASK;
+ type_event_mask = GDK_LEAVE_NOTIFY_MASK;
else
- event_mask = GDK_ENTER_NOTIFY_MASK;
+ type_event_mask = GDK_ENTER_NOTIFY_MASK;
if (window->extension_events != 0)
{
type == GDK_ENTER_NOTIFY);
}
- if (window->event_mask & event_mask)
+ if (window_event_mask & type_event_mask)
{
event = _gdk_make_event ((GdkWindow *)window, type, event_in_queue, TRUE);
event->crossing.time = time_;
_gdk_display_set_window_under_pointer (GdkDisplay *display,
GdkWindow *window)
{
- GdkWindowObject *private;
-
/* We don't track this if all native, and it can cause issues
with the update_cursor call below */
if (_gdk_native_windows)
return;
- private = (GdkWindowObject *)window;
-
if (display->pointer_info.window_under_pointer)
g_object_unref (display->pointer_info.window_under_pointer);
display->pointer_info.window_under_pointer = window;
res = _gdk_windowing_pointer_grab (window,
native,
owner_events,
- event_mask,
+ get_native_grab_event_mask (event_mask),
confine_to,
cursor,
time);
&toplevel_x, &toplevel_y);
if (type == GDK_BUTTON_PRESS &&
+ !source_event->any.send_event &&
_gdk_display_has_pointer_grab (display, serial) == NULL)
{
pointer_window =
if (_gdk_native_windows)
{
if (event->type == GDK_BUTTON_PRESS &&
+ !event->any.send_event &&
_gdk_display_has_pointer_grab (display, serial) == NULL)
{
_gdk_display_add_pointer_grab (display,
_gdk_display_pointer_grab_update (display,
serial);
}
- if (event->type == GDK_BUTTON_RELEASE)
+ if (event->type == GDK_BUTTON_RELEASE &&
+ !event->any.send_event)
{
button_release_grab =
_gdk_display_has_pointer_grab (display, serial);
(event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
{
button_release_grab->serial_end = serial;
- button_release_grab->implicit_ungrab = TRUE;
+ button_release_grab->implicit_ungrab = FALSE;
_gdk_display_pointer_grab_update (display, serial);
}
}
unlink_event = proxy_button_event (event,
serial);
- if (event->type == GDK_BUTTON_RELEASE)
+ if (event->type == GDK_BUTTON_RELEASE &&
+ !event->any.send_event)
{
button_release_grab =
_gdk_display_has_pointer_grab (display, serial);
(event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
{
button_release_grab->serial_end = serial;
- button_release_grab->implicit_ungrab = TRUE;
+ button_release_grab->implicit_ungrab = FALSE;
_gdk_display_pointer_grab_update (display, serial);
}
}