From 21d3d60f4810fccde29ecc6029fcfbc28d457500 Mon Sep 17 00:00:00 2001 From: Cody Russell Date: Thu, 18 Oct 2007 00:31:22 +0000 Subject: [PATCH] gdk/win32/gdkevents-win32.c Force non-modal transient dialogs to iconify 2007-10-17 Cody Russell * gdk/win32/gdkevents-win32.c * gdk/win32/gdkwindow-win32.[ch]: Force non-modal transient dialogs to iconify with their parents on Win32. Maintain a list of transient children, and whenever a window is hidden or restored we now do the same thing to all connected transient windows above and below the current window in the chain. See comment under WM_ACTIVATE for the reasons why. (#164537, #371036, #405178) svn path=/trunk/; revision=18929 --- ChangeLog | 10 ++++ gdk/win32/gdkevents-win32.c | 92 +++++++++++++++++++++++++++++++++---- gdk/win32/gdkwindow-win32.c | 53 +++++++++++++++++++-- gdk/win32/gdkwindow-win32.h | 3 ++ 4 files changed, 147 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3fe5e9767e..3f81f71d43 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2007-10-17 Cody Russell + + * gdk/win32/gdkevents-win32.c + * gdk/win32/gdkwindow-win32.[ch]: Force non-modal transient dialogs + to iconify with their parents on Win32. Maintain a list of transient + children, and whenever a window is hidden or restored we now do the + same thing to all connected transient windows above and below the + current window in the chain. See comment under WM_ACTIVATE for the + reasons why. (#164537, #371036, #405178) + 2007-10-17 Owen Taylor * gtk/Makefile.am (libgtk_win32_2_0_la_LDFLAGS): Move -Wl,-luuid diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c index 1115513932..a03833bda2 100644 --- a/gdk/win32/gdkevents-win32.c +++ b/gdk/win32/gdkevents-win32.c @@ -1266,6 +1266,37 @@ apply_filters (GdkWindow *window, return result; } +static void +show_window_recurse (GdkWindow *window, gboolean hide_window) +{ + GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl); + GSList *children = impl->transient_children; + GdkWindow *child = NULL; + + if (!impl->changing_state) + { + impl->changing_state = TRUE; + + if (children != NULL) + { + while (children != NULL) + { + child = children->data; + show_window_recurse (child, hide_window); + + children = g_slist_next (children); + } + } + + if (!hide_window) + ShowWindow (GDK_WINDOW_HWND (window), SW_RESTORE); + else + ShowWindow (GDK_WINDOW_HWND (window), SW_MINIMIZE); + + impl->changing_state = FALSE; + } +} + static gboolean gdk_window_is_ancestor (GdkWindow *ancestor, GdkWindow *window) @@ -2826,16 +2857,18 @@ gdk_event_translate (MSG *msg, { SetForegroundWindow (GDK_WINDOW_HWND (impl->transient_owner)); } + + if (p_grab_window == window) + { + gdk_pointer_ungrab (msg->time); + } + + if (k_grab_window == window) + { + gdk_keyboard_ungrab (msg->time); + } } - if (event->any.type == GDK_UNMAP && - p_grab_window == window) - gdk_pointer_ungrab (msg->time); - - if (event->any.type == GDK_UNMAP && - k_grab_window == window) - gdk_keyboard_ungrab (msg->time); - return_val = TRUE; break; @@ -3331,6 +3364,49 @@ gdk_event_translate (MSG *msg, break; case WM_ACTIVATE: + ; + + /* + * On Windows, transient windows will not have their own taskbar entries. + * Because of this, we must hide and restore groups of transients in both + * directions. That is, all transient children must be hidden or restored + * with this window, but if this window's transient owner also has a + * transient owner then this window's transient owner must be hidden/restored + * with this one. And etc, up the chain until we hit an ancestor that has no + * transient owner. + * + * It would be a good idea if applications don't chain transient windows + * together. There's a limit to how much evil GTK can try to shield you + * from. + */ + GdkWindow *tmp_window = NULL; + GdkWindowImplWin32 *tmp_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl); + + while (tmp_impl->transient_owner != NULL) + { + tmp_window = tmp_impl->transient_owner; + tmp_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (tmp_window)->impl); + } + + if (tmp_window == NULL) + tmp_window = window; + + if (LOWORD (msg->wParam) == WA_INACTIVE && HIWORD (msg->wParam)) + { + if (!tmp_impl->changing_state) + { + show_window_recurse (tmp_window, TRUE); + } + } + else if (LOWORD (msg->wParam) == WA_ACTIVE && HIWORD (msg->wParam)) + { + if (!tmp_impl->changing_state) + { + show_window_recurse (tmp_window, FALSE); + } + } + + /* Bring any tablet contexts to the top of the overlap order when * one of our windows is activated. * NOTE: It doesn't seem to work well if it is done in WM_ACTIVATEAPP diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c index d0e2ee6cba..51db1c1669 100644 --- a/gdk/win32/gdkwindow-win32.c +++ b/gdk/win32/gdkwindow-win32.c @@ -107,6 +107,9 @@ gdk_window_impl_win32_init (GdkWindowImplWin32 *impl) impl->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL; impl->extension_events_selected = FALSE; impl->transient_owner = NULL; + impl->transient_children = NULL; + impl->num_transients = 0; + impl->changing_state = FALSE; } static void @@ -831,6 +834,7 @@ _gdk_windowing_window_destroy (GdkWindow *window, { GdkWindowObject *private = (GdkWindowObject *)window; GdkWindowImplWin32 *window_impl = GDK_WINDOW_IMPL_WIN32 (private->impl); + GSList *tmp; g_return_if_fail (GDK_IS_WINDOW (window)); @@ -840,6 +844,19 @@ _gdk_windowing_window_destroy (GdkWindow *window, if (private->extension_events != 0) _gdk_input_window_destroy (window); + /* Remove all our transient children */ + tmp = window_impl->transient_children; + while (tmp != NULL) + { + GdkWindow *child = tmp->data; + GdkWindowImplWin32 *child_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (child)->impl); + + child_impl->transient_owner = NULL; + tmp = g_slist_next (tmp); + } + g_slist_free (window_impl->transient_children); + window_impl->transient_children = NULL; + /* Remove ourself from our transient owner */ if (window_impl->transient_owner != NULL) { @@ -1929,6 +1946,8 @@ gdk_window_set_transient_for (GdkWindow *window, { HWND window_id, parent_id; GdkWindowImplWin32 *window_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl); + GdkWindowImplWin32 *parent_impl = NULL; + GSList *item; g_return_if_fail (GDK_IS_WINDOW (window)); @@ -1951,7 +1970,32 @@ gdk_window_set_transient_for (GdkWindow *window, return; } - window_impl->transient_owner = parent; + if (parent == NULL) + { + GdkWindowImplWin32 *trans_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window_impl->transient_owner)->impl); + if (trans_impl->transient_children != NULL) + { + item = g_slist_find (trans_impl->transient_children, window); + item->data = NULL; + trans_impl->transient_children = g_slist_delete_link (trans_impl->transient_children, item); + trans_impl->num_transients--; + + if (!trans_impl->num_transients) + { + trans_impl->transient_children = NULL; + } + } + + window_impl->transient_owner = NULL; + } + else + { + parent_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (parent)->impl); + + parent_impl->transient_children = g_slist_append (parent_impl->transient_children, window); + parent_impl->num_transients++; + window_impl->transient_owner = parent; + } /* This changes the *owner* of the window, despite the misleading * name. (Owner and parent are unrelated concepts.) At least that's @@ -2923,7 +2967,7 @@ QueryTree (HWND hwnd, gint *nchildren) { guint i, n; - HWND child; + HWND child = NULL; n = 0; do { @@ -3407,7 +3451,7 @@ gdk_window_set_modal_hint (GdkWindow *window, private->modal_hint = modal; -#if 0 +#if 1 /* Not sure about this one.. -- Cody */ if (GDK_WINDOW_IS_MAPPED (window)) API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), @@ -3426,6 +3470,9 @@ gdk_window_set_skip_taskbar_hint (GdkWindow *window, g_return_if_fail (GDK_IS_WINDOW (window)); + // ### TODO: Need to figure out what to do here. + return; + GDK_NOTE (MISC, g_print ("gdk_window_set_skip_taskbar_hint: %p: %s\n", GDK_WINDOW_HWND (window), skips_taskbar ? "TRUE" : "FALSE")); diff --git a/gdk/win32/gdkwindow-win32.h b/gdk/win32/gdkwindow-win32.h index 8a697565a4..8583ab35f3 100644 --- a/gdk/win32/gdkwindow-win32.h +++ b/gdk/win32/gdkwindow-win32.h @@ -88,6 +88,9 @@ struct _GdkWindowImplWin32 gboolean extension_events_selected; GdkWindow *transient_owner; + GSList *transient_children; + gint num_transients; + gboolean changing_state; }; struct _GdkWindowImplWin32Class