gdk/win32/gdkevents-win32.c Force non-modal transient dialogs to iconify

2007-10-17  Cody Russell  <cody@jhu.edu>

        * 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
This commit is contained in:
Cody Russell 2007-10-18 00:31:22 +00:00 committed by Cody Russell
parent e6572dfb95
commit 21d3d60f48
4 changed files with 147 additions and 11 deletions

View File

@ -1,3 +1,13 @@
2007-10-17 Cody Russell <cody@jhu.edu>
* 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 <otaylor@redhat.com>
* gtk/Makefile.am (libgtk_win32_2_0_la_LDFLAGS): Move -Wl,-luuid

View File

@ -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

View File

@ -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"));

View File

@ -88,6 +88,9 @@ struct _GdkWindowImplWin32
gboolean extension_events_selected;
GdkWindow *transient_owner;
GSList *transient_children;
gint num_transients;
gboolean changing_state;
};
struct _GdkWindowImplWin32Class