From c42c7be0501b33730adb107727f6a31c931df6a5 Mon Sep 17 00:00:00 2001 From: Richard Hult Date: Tue, 23 Oct 2007 13:06:31 +0000 Subject: [PATCH] Maintain a list for the stacking order of windows. Implement lower and 2007-10-23 Richard Hult * gdk/quartz/gdkwindow-quartz.c: (gdk_window_raise, gdk_window_lower, gdk_window_new, _gdk_windowing_window_destroy): Maintain a list for the stacking order of windows. Implement lower and raise for child windows. The list for toplevels is created on demand, and cleared when a window gets or resigns main status and when new windows are created. (find_child_window_helper): Use the sorted list to go through windows from top to bottom. Take any titlebar in consideration for toplevels, to stop events from sometimes punching through (bugs #473813 and #489370). svn path=/trunk/; revision=18940 --- ChangeLog | 13 +++ gdk/quartz/gdkwindow-quartz.c | 172 +++++++++++++++++++++++++++++++--- gdk/quartz/gdkwindow-quartz.h | 3 + 3 files changed, 174 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index 994f62a711..4aee52dd91 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2007-10-23 Richard Hult + + * gdk/quartz/gdkwindow-quartz.c: + (gdk_window_raise, gdk_window_lower, gdk_window_new, + _gdk_windowing_window_destroy): Maintain a list for the stacking + order of windows. Implement lower and raise for child windows. The + list for toplevels is created on demand, and cleared when a window + gets or resigns main status and when new windows are created. + (find_child_window_helper): Use the sorted list to go through + windows from top to bottom. Take any titlebar in consideration for + toplevels, to stop events from sometimes punching through (bugs + #473813 and #489370). + 2007-10-22 Johan Dahlin * gtk/gtkbuilder.c: Use gtk_ascii_tolower/toupper instead of the C diff --git a/gdk/quartz/gdkwindow-quartz.c b/gdk/quartz/gdkwindow-quartz.c index cfb831b27f..e63491827e 100644 --- a/gdk/quartz/gdkwindow-quartz.c +++ b/gdk/quartz/gdkwindow-quartz.c @@ -32,6 +32,9 @@ static guint update_idle; static GSList *main_window_stack; +static void update_toplevel_order (void); +static void clear_toplevel_order (void); + #define WINDOW_IS_TOPLEVEL(window) \ (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \ GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN) @@ -467,23 +470,59 @@ find_child_window_helper (GdkWindow *window, gint x_offset, gint y_offset) { + GdkWindowImplQuartz *impl; GList *l; - for (l = GDK_WINDOW_OBJECT (window)->children; l; l = l->next) + impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl); + + if (window == _gdk_root) + update_toplevel_order (); + + for (l = impl->sorted_children; l; l = l->next) { - GdkWindowObject *private = l->data; - GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); + GdkWindowObject *child_private = l->data; + GdkWindowImplQuartz *child_impl = GDK_WINDOW_IMPL_QUARTZ (child_private->impl); int temp_x, temp_y; - if (!GDK_WINDOW_IS_MAPPED (private)) + if (!GDK_WINDOW_IS_MAPPED (child_private)) continue; - temp_x = x_offset + private->x; - temp_y = y_offset + private->y; - - /* FIXME: Are there off by one errors here? */ + temp_x = x_offset + child_private->x; + temp_y = y_offset + child_private->y; + + /* Special-case the root window. We have to include the title + * bar in the checks, otherwise the window below the title bar + * will be found i.e. events punch through. (If we can find a + * better way to deal with the events in gdkevents-quartz, this + * might not be needed.) + */ + if (window == _gdk_root) + { + NSRect frame = NSMakeRect (0, 0, 100, 100); + NSRect content; + int mask; + int titlebar_height; + + mask = [child_impl->toplevel styleMask]; + + /* Get the title bar height. */ + content = [NSWindow contentRectForFrameRect:frame + styleMask:mask]; + titlebar_height = frame.size.height - content.size.height; + + if (titlebar_height > 0 && + x >= temp_x && y >= temp_y - titlebar_height && + x < temp_x + child_impl->width && y < temp_y) + { + /* The root means "unknown" i.e. a window not managed by + * GDK. + */ + return (GdkWindow *)_gdk_root; + } + } + if (x >= temp_x && y >= temp_y && - x < temp_x + impl->width && y < temp_y + impl->height) + x < temp_x + child_impl->width && y < temp_y + child_impl->height) { /* Look for child windows. */ return find_child_window_helper (l->data, @@ -520,6 +559,8 @@ _gdk_quartz_window_did_become_main (GdkWindow *window) if (GDK_WINDOW_OBJECT (window)->window_type != GDK_WINDOW_TEMP) main_window_stack = g_slist_prepend (main_window_stack, window); + + clear_toplevel_order (); } void @@ -549,6 +590,8 @@ _gdk_quartz_window_did_resign_main (GdkWindow *window) [impl->toplevel makeKeyAndOrderFront:impl->toplevel]; } + + clear_toplevel_order (); } GdkWindow * @@ -561,6 +604,7 @@ gdk_window_new (GdkWindow *parent, GdkWindowImplQuartz *impl; GdkDrawableImplQuartz *draw_impl; GdkVisual *visual; + GdkWindowImplQuartz *parent_impl; if (parent && GDK_WINDOW_DESTROYED (parent)) return NULL; @@ -577,6 +621,7 @@ gdk_window_new (GdkWindow *parent, draw_impl->wrapper = GDK_DRAWABLE (window); private->parent = (GdkWindowObject *)parent; + parent_impl = GDK_WINDOW_IMPL_QUARTZ (private->parent->impl); private->accept_focus = TRUE; private->focus_on_map = TRUE; @@ -675,8 +720,13 @@ gdk_window_new (GdkWindow *parent, g_object_ref (draw_impl->colormap); } - if (private->parent) - private->parent->children = g_list_prepend (private->parent->children, window); + private->parent->children = g_list_prepend (private->parent->children, window); + + /* Maintain the z-ordered list of children. */ + if (parent != _gdk_root) + parent_impl->sorted_children = g_list_prepend (parent_impl->sorted_children, window); + else + clear_toplevel_order (); gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ? (attributes->cursor) : @@ -796,9 +846,27 @@ _gdk_windowing_window_destroy (GdkWindow *window, gboolean recursing, gboolean foreign_destroy) { + GdkWindowObject *private; + GdkWindowImplQuartz *impl; + GdkWindowObject *parent; + + private = GDK_WINDOW_OBJECT (window); + impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); + update_windows = g_slist_remove (update_windows, window); main_window_stack = g_slist_remove (main_window_stack, window); + g_list_free (impl->sorted_children); + impl->sorted_children = NULL; + + parent = private->parent; + if (parent) + { + GdkWindowImplQuartz *parent_impl = GDK_WINDOW_IMPL_QUARTZ (parent->impl); + + parent_impl->sorted_children = g_list_remove (parent_impl->sorted_children, window); + } + /* If the destroyed window was targeted for a pointer or keyboard * grab, release the grab. */ @@ -1284,6 +1352,53 @@ _gdk_windowing_window_clear_area_e (GdkWindow *window, /* FIXME: Implement */ } +/* Get the toplevel ordering from NSApp and update our own list. We do + * this on demand since the NSApp's list is not up to date directly + * after we get windowDidBecomeMain. + */ +static void +update_toplevel_order (void) +{ + GdkWindowObject *root; + GdkWindowImplQuartz *root_impl; + NSEnumerator *enumerator; + id nswindow; + GList *toplevels = NULL; + + root = GDK_WINDOW_OBJECT (_gdk_root); + root_impl = GDK_WINDOW_IMPL_QUARTZ (root->impl); + + if (root_impl->sorted_children) + return; + + enumerator = [[NSApp orderedWindows] objectEnumerator]; + while ((nswindow = [enumerator nextObject])) + { + GdkWindow *window; + + if (![[nswindow contentView] isKindOfClass:[GdkQuartzView class]]) + continue; + + window = [(GdkQuartzView *)[nswindow contentView] gdkWindow]; + toplevels = g_list_prepend (toplevels, window); + } + + root_impl->sorted_children = g_list_reverse (toplevels); +} + +static void +clear_toplevel_order (void) +{ + GdkWindowObject *root; + GdkWindowImplQuartz *root_impl; + + root = GDK_WINDOW_OBJECT (_gdk_root); + root_impl = GDK_WINDOW_IMPL_QUARTZ (root->impl); + + g_list_free (root_impl->sorted_children); + root_impl->sorted_children = NULL; +} + void gdk_window_raise (GdkWindow *window) { @@ -1292,13 +1407,28 @@ gdk_window_raise (GdkWindow *window) if (GDK_WINDOW_DESTROYED (window)) return; - /* FIXME: Only supported for toplevels currently. */ if (WINDOW_IS_TOPLEVEL (window)) { GdkWindowImplQuartz *impl; impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl); [impl->toplevel orderFront:impl->toplevel]; + + clear_toplevel_order (); + } + else + { + GdkWindowObject *parent = GDK_WINDOW_OBJECT (window)->parent; + + if (parent) + { + GdkWindowImplQuartz *impl; + + impl = (GdkWindowImplQuartz *)parent->impl; + + impl->sorted_children = g_list_remove (impl->sorted_children, window); + impl->sorted_children = g_list_prepend (impl->sorted_children, window); + } } } @@ -1310,13 +1440,28 @@ gdk_window_lower (GdkWindow *window) if (GDK_WINDOW_DESTROYED (window)) return; - /* FIXME: Only supported for toplevels currently. */ if (WINDOW_IS_TOPLEVEL (window)) { GdkWindowImplQuartz *impl; impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl); [impl->toplevel orderBack:impl->toplevel]; + + clear_toplevel_order (); + } + else + { + GdkWindowObject *parent = GDK_WINDOW_OBJECT (window)->parent; + + if (parent) + { + GdkWindowImplQuartz *impl; + + impl = (GdkWindowImplQuartz *)parent->impl; + + impl->sorted_children = g_list_remove (impl->sorted_children, window); + impl->sorted_children = g_list_append (impl->sorted_children, window); + } } } @@ -2572,7 +2717,6 @@ gdk_window_unfullscreen (GdkWindow *window) if (geometry) { - ShowMenuBar (); move_resize_window_internal (window, diff --git a/gdk/quartz/gdkwindow-quartz.h b/gdk/quartz/gdkwindow-quartz.h index ce5e0ba520..090c0cca0f 100644 --- a/gdk/quartz/gdkwindow-quartz.h +++ b/gdk/quartz/gdkwindow-quartz.h @@ -66,6 +66,9 @@ struct _GdkWindowImplQuartz gint in_paint_rect_count; GdkWindow *transient_for; + + /* Sorted by z-order */ + GList *sorted_children; }; struct _GdkWindowImplQuartzClass