From 1689117cf760311e14186a992a43943d3d55c3ba Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Wed, 25 Sep 2002 19:16:46 +0000 Subject: [PATCH] fix GtkWindowMnemonic to have a separate typedef 2002-09-24 Havoc Pennington * gtk/gtkwindow.c: fix GtkWindowMnemonic to have a separate typedef * gdk/x11/gdkevents-x11.c (gdk_check_wm_state_changed): monitor FULLSCREEN state * tests/testgtk.c (get_state_controls): add fullscreen/unfullscreen test * gdk/gdkdisplay.c (gdk_display_finalize): fix unused variable * gdk/x11/gdkscreen-x11.c (init_xinerama_support): fix unused variable * gdk/x11/gdkevents-x11.c (gdk_xsettings_watch_cb): mop up unused variable * gdk/x11/gdkscreen-x11.c (_gdk_x11_screen_window_manager_changed): emit window_manager_changed signal * gdk/x11/gdkscreen-x11.h (struct _GdkScreenX11Class): add window_manager_changed signal * gdk/x11/gdkevents-x11.c (gdk_x11_screen_get_window_manager_name): new function * gtk/gtkwindow.c (gtk_window_class_init): add type_hint, skip_taskbar_hint, skip_pager_hint properties (gtk_window_set_skip_taskbar_hint): (gtk_window_get_skip_taskbar_hint): (gtk_window_set_skip_pager_hint): (gtk_window_get_skip_pager_hint): (gtk_window_fullscreen): (gtk_window_unfullscreen): new functions * gdk/gdkevents.h (GdkWindowState): add FULLSCREEN state * gdk/gdkwindow.h (GdkWindowTypeHint): add missing type hint values * gdk/x11/gdkwindow-x11.c (gdk_window_set_skip_taskbar_hint): (gdk_window_set_skip_pager_hint): (gdk_window_fullscreen): (gdk_window_unfullscreen): new functions (set_initial_hints): set fullscreen here if appropriate --- ChangeLog | 49 +++++++ ChangeLog.pre-2-10 | 49 +++++++ ChangeLog.pre-2-2 | 49 +++++++ ChangeLog.pre-2-4 | 49 +++++++ ChangeLog.pre-2-6 | 49 +++++++ ChangeLog.pre-2-8 | 49 +++++++ gdk/gdkdisplay.c | 2 - gdk/gdkevents.h | 9 +- gdk/gdkwindow.h | 22 ++- gdk/x11/gdkevents-x11.c | 237 ++++++++++++++++++++++--------- gdk/x11/gdkscreen-x11.c | 35 ++++- gdk/x11/gdkscreen-x11.h | 15 ++ gdk/x11/gdkwindow-x11.c | 202 ++++++++++++++++++++++++-- gdk/x11/gdkwindow-x11.h | 4 + gdk/x11/gdkx.h | 3 + gtk/gtkwindow.c | 304 +++++++++++++++++++++++++++++++++++++++- gtk/gtkwindow.h | 8 ++ tests/testgtk.c | 32 ++++- 18 files changed, 1066 insertions(+), 101 deletions(-) diff --git a/ChangeLog b/ChangeLog index 404315a638..c54aa38b1f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,52 @@ +2002-09-24 Havoc Pennington + + * gtk/gtkwindow.c: fix GtkWindowMnemonic to have a separate + typedef + + * gdk/x11/gdkevents-x11.c (gdk_check_wm_state_changed): monitor + FULLSCREEN state + + * tests/testgtk.c (get_state_controls): add + fullscreen/unfullscreen test + + * gdk/gdkdisplay.c (gdk_display_finalize): fix unused variable + + * gdk/x11/gdkscreen-x11.c (init_xinerama_support): fix unused + variable + + * gdk/x11/gdkevents-x11.c (gdk_xsettings_watch_cb): mop up unused + variable + + * gdk/x11/gdkscreen-x11.c + (_gdk_x11_screen_window_manager_changed): emit + window_manager_changed signal + + * gdk/x11/gdkscreen-x11.h (struct _GdkScreenX11Class): add + window_manager_changed signal + + * gdk/x11/gdkevents-x11.c + (gdk_x11_screen_get_window_manager_name): new function + + * gtk/gtkwindow.c (gtk_window_class_init): add type_hint, + skip_taskbar_hint, skip_pager_hint properties + (gtk_window_set_skip_taskbar_hint): + (gtk_window_get_skip_taskbar_hint): + (gtk_window_set_skip_pager_hint): + (gtk_window_get_skip_pager_hint): + (gtk_window_fullscreen): + (gtk_window_unfullscreen): new functions + + * gdk/gdkevents.h (GdkWindowState): add FULLSCREEN state + + * gdk/gdkwindow.h (GdkWindowTypeHint): add missing type hint + values + + * gdk/x11/gdkwindow-x11.c (gdk_window_set_skip_taskbar_hint): + (gdk_window_set_skip_pager_hint): + (gdk_window_fullscreen): + (gdk_window_unfullscreen): new functions + (set_initial_hints): set fullscreen here if appropriate + Wed Sep 25 10:51:24 2002 Owen Taylor * gdk/gdkscreen.h gdk/{x11,win32,linux-fb}/gdkscreen-*.c: diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 404315a638..c54aa38b1f 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,52 @@ +2002-09-24 Havoc Pennington + + * gtk/gtkwindow.c: fix GtkWindowMnemonic to have a separate + typedef + + * gdk/x11/gdkevents-x11.c (gdk_check_wm_state_changed): monitor + FULLSCREEN state + + * tests/testgtk.c (get_state_controls): add + fullscreen/unfullscreen test + + * gdk/gdkdisplay.c (gdk_display_finalize): fix unused variable + + * gdk/x11/gdkscreen-x11.c (init_xinerama_support): fix unused + variable + + * gdk/x11/gdkevents-x11.c (gdk_xsettings_watch_cb): mop up unused + variable + + * gdk/x11/gdkscreen-x11.c + (_gdk_x11_screen_window_manager_changed): emit + window_manager_changed signal + + * gdk/x11/gdkscreen-x11.h (struct _GdkScreenX11Class): add + window_manager_changed signal + + * gdk/x11/gdkevents-x11.c + (gdk_x11_screen_get_window_manager_name): new function + + * gtk/gtkwindow.c (gtk_window_class_init): add type_hint, + skip_taskbar_hint, skip_pager_hint properties + (gtk_window_set_skip_taskbar_hint): + (gtk_window_get_skip_taskbar_hint): + (gtk_window_set_skip_pager_hint): + (gtk_window_get_skip_pager_hint): + (gtk_window_fullscreen): + (gtk_window_unfullscreen): new functions + + * gdk/gdkevents.h (GdkWindowState): add FULLSCREEN state + + * gdk/gdkwindow.h (GdkWindowTypeHint): add missing type hint + values + + * gdk/x11/gdkwindow-x11.c (gdk_window_set_skip_taskbar_hint): + (gdk_window_set_skip_pager_hint): + (gdk_window_fullscreen): + (gdk_window_unfullscreen): new functions + (set_initial_hints): set fullscreen here if appropriate + Wed Sep 25 10:51:24 2002 Owen Taylor * gdk/gdkscreen.h gdk/{x11,win32,linux-fb}/gdkscreen-*.c: diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 404315a638..c54aa38b1f 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,52 @@ +2002-09-24 Havoc Pennington + + * gtk/gtkwindow.c: fix GtkWindowMnemonic to have a separate + typedef + + * gdk/x11/gdkevents-x11.c (gdk_check_wm_state_changed): monitor + FULLSCREEN state + + * tests/testgtk.c (get_state_controls): add + fullscreen/unfullscreen test + + * gdk/gdkdisplay.c (gdk_display_finalize): fix unused variable + + * gdk/x11/gdkscreen-x11.c (init_xinerama_support): fix unused + variable + + * gdk/x11/gdkevents-x11.c (gdk_xsettings_watch_cb): mop up unused + variable + + * gdk/x11/gdkscreen-x11.c + (_gdk_x11_screen_window_manager_changed): emit + window_manager_changed signal + + * gdk/x11/gdkscreen-x11.h (struct _GdkScreenX11Class): add + window_manager_changed signal + + * gdk/x11/gdkevents-x11.c + (gdk_x11_screen_get_window_manager_name): new function + + * gtk/gtkwindow.c (gtk_window_class_init): add type_hint, + skip_taskbar_hint, skip_pager_hint properties + (gtk_window_set_skip_taskbar_hint): + (gtk_window_get_skip_taskbar_hint): + (gtk_window_set_skip_pager_hint): + (gtk_window_get_skip_pager_hint): + (gtk_window_fullscreen): + (gtk_window_unfullscreen): new functions + + * gdk/gdkevents.h (GdkWindowState): add FULLSCREEN state + + * gdk/gdkwindow.h (GdkWindowTypeHint): add missing type hint + values + + * gdk/x11/gdkwindow-x11.c (gdk_window_set_skip_taskbar_hint): + (gdk_window_set_skip_pager_hint): + (gdk_window_fullscreen): + (gdk_window_unfullscreen): new functions + (set_initial_hints): set fullscreen here if appropriate + Wed Sep 25 10:51:24 2002 Owen Taylor * gdk/gdkscreen.h gdk/{x11,win32,linux-fb}/gdkscreen-*.c: diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 404315a638..c54aa38b1f 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,52 @@ +2002-09-24 Havoc Pennington + + * gtk/gtkwindow.c: fix GtkWindowMnemonic to have a separate + typedef + + * gdk/x11/gdkevents-x11.c (gdk_check_wm_state_changed): monitor + FULLSCREEN state + + * tests/testgtk.c (get_state_controls): add + fullscreen/unfullscreen test + + * gdk/gdkdisplay.c (gdk_display_finalize): fix unused variable + + * gdk/x11/gdkscreen-x11.c (init_xinerama_support): fix unused + variable + + * gdk/x11/gdkevents-x11.c (gdk_xsettings_watch_cb): mop up unused + variable + + * gdk/x11/gdkscreen-x11.c + (_gdk_x11_screen_window_manager_changed): emit + window_manager_changed signal + + * gdk/x11/gdkscreen-x11.h (struct _GdkScreenX11Class): add + window_manager_changed signal + + * gdk/x11/gdkevents-x11.c + (gdk_x11_screen_get_window_manager_name): new function + + * gtk/gtkwindow.c (gtk_window_class_init): add type_hint, + skip_taskbar_hint, skip_pager_hint properties + (gtk_window_set_skip_taskbar_hint): + (gtk_window_get_skip_taskbar_hint): + (gtk_window_set_skip_pager_hint): + (gtk_window_get_skip_pager_hint): + (gtk_window_fullscreen): + (gtk_window_unfullscreen): new functions + + * gdk/gdkevents.h (GdkWindowState): add FULLSCREEN state + + * gdk/gdkwindow.h (GdkWindowTypeHint): add missing type hint + values + + * gdk/x11/gdkwindow-x11.c (gdk_window_set_skip_taskbar_hint): + (gdk_window_set_skip_pager_hint): + (gdk_window_fullscreen): + (gdk_window_unfullscreen): new functions + (set_initial_hints): set fullscreen here if appropriate + Wed Sep 25 10:51:24 2002 Owen Taylor * gdk/gdkscreen.h gdk/{x11,win32,linux-fb}/gdkscreen-*.c: diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 404315a638..c54aa38b1f 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,52 @@ +2002-09-24 Havoc Pennington + + * gtk/gtkwindow.c: fix GtkWindowMnemonic to have a separate + typedef + + * gdk/x11/gdkevents-x11.c (gdk_check_wm_state_changed): monitor + FULLSCREEN state + + * tests/testgtk.c (get_state_controls): add + fullscreen/unfullscreen test + + * gdk/gdkdisplay.c (gdk_display_finalize): fix unused variable + + * gdk/x11/gdkscreen-x11.c (init_xinerama_support): fix unused + variable + + * gdk/x11/gdkevents-x11.c (gdk_xsettings_watch_cb): mop up unused + variable + + * gdk/x11/gdkscreen-x11.c + (_gdk_x11_screen_window_manager_changed): emit + window_manager_changed signal + + * gdk/x11/gdkscreen-x11.h (struct _GdkScreenX11Class): add + window_manager_changed signal + + * gdk/x11/gdkevents-x11.c + (gdk_x11_screen_get_window_manager_name): new function + + * gtk/gtkwindow.c (gtk_window_class_init): add type_hint, + skip_taskbar_hint, skip_pager_hint properties + (gtk_window_set_skip_taskbar_hint): + (gtk_window_get_skip_taskbar_hint): + (gtk_window_set_skip_pager_hint): + (gtk_window_get_skip_pager_hint): + (gtk_window_fullscreen): + (gtk_window_unfullscreen): new functions + + * gdk/gdkevents.h (GdkWindowState): add FULLSCREEN state + + * gdk/gdkwindow.h (GdkWindowTypeHint): add missing type hint + values + + * gdk/x11/gdkwindow-x11.c (gdk_window_set_skip_taskbar_hint): + (gdk_window_set_skip_pager_hint): + (gdk_window_fullscreen): + (gdk_window_unfullscreen): new functions + (set_initial_hints): set fullscreen here if appropriate + Wed Sep 25 10:51:24 2002 Owen Taylor * gdk/gdkscreen.h gdk/{x11,win32,linux-fb}/gdkscreen-*.c: diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 404315a638..c54aa38b1f 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,52 @@ +2002-09-24 Havoc Pennington + + * gtk/gtkwindow.c: fix GtkWindowMnemonic to have a separate + typedef + + * gdk/x11/gdkevents-x11.c (gdk_check_wm_state_changed): monitor + FULLSCREEN state + + * tests/testgtk.c (get_state_controls): add + fullscreen/unfullscreen test + + * gdk/gdkdisplay.c (gdk_display_finalize): fix unused variable + + * gdk/x11/gdkscreen-x11.c (init_xinerama_support): fix unused + variable + + * gdk/x11/gdkevents-x11.c (gdk_xsettings_watch_cb): mop up unused + variable + + * gdk/x11/gdkscreen-x11.c + (_gdk_x11_screen_window_manager_changed): emit + window_manager_changed signal + + * gdk/x11/gdkscreen-x11.h (struct _GdkScreenX11Class): add + window_manager_changed signal + + * gdk/x11/gdkevents-x11.c + (gdk_x11_screen_get_window_manager_name): new function + + * gtk/gtkwindow.c (gtk_window_class_init): add type_hint, + skip_taskbar_hint, skip_pager_hint properties + (gtk_window_set_skip_taskbar_hint): + (gtk_window_get_skip_taskbar_hint): + (gtk_window_set_skip_pager_hint): + (gtk_window_get_skip_pager_hint): + (gtk_window_fullscreen): + (gtk_window_unfullscreen): new functions + + * gdk/gdkevents.h (GdkWindowState): add FULLSCREEN state + + * gdk/gdkwindow.h (GdkWindowTypeHint): add missing type hint + values + + * gdk/x11/gdkwindow-x11.c (gdk_window_set_skip_taskbar_hint): + (gdk_window_set_skip_pager_hint): + (gdk_window_fullscreen): + (gdk_window_unfullscreen): new functions + (set_initial_hints): set fullscreen here if appropriate + Wed Sep 25 10:51:24 2002 Owen Taylor * gdk/gdkscreen.h gdk/{x11,win32,linux-fb}/gdkscreen-*.c: diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c index 9ee37d0c2e..b783eb2ecc 100644 --- a/gdk/gdkdisplay.c +++ b/gdk/gdkdisplay.c @@ -121,8 +121,6 @@ gdk_display_dispose (GObject *object) static void gdk_display_finalize (GObject *object) { - GdkDisplay *display = GDK_DISPLAY_OBJECT (object); - parent_class->finalize (object); } diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h index 19990ce4d7..dbed63cb4d 100644 --- a/gdk/gdkevents.h +++ b/gdk/gdkevents.h @@ -201,10 +201,11 @@ typedef enum typedef enum { - GDK_WINDOW_STATE_WITHDRAWN = 1 << 0, - GDK_WINDOW_STATE_ICONIFIED = 1 << 1, - GDK_WINDOW_STATE_MAXIMIZED = 1 << 2, - GDK_WINDOW_STATE_STICKY = 1 << 3 + GDK_WINDOW_STATE_WITHDRAWN = 1 << 0, + GDK_WINDOW_STATE_ICONIFIED = 1 << 1, + GDK_WINDOW_STATE_MAXIMIZED = 1 << 2, + GDK_WINDOW_STATE_STICKY = 1 << 3, + GDK_WINDOW_STATE_FULLSCREEN = 1 << 4 } GdkWindowState; typedef enum diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h index 2495dc4104..008bac003e 100644 --- a/gdk/gdkwindow.h +++ b/gdk/gdkwindow.h @@ -104,7 +104,11 @@ typedef enum GDK_WINDOW_TYPE_HINT_NORMAL, GDK_WINDOW_TYPE_HINT_DIALOG, GDK_WINDOW_TYPE_HINT_MENU, - GDK_WINDOW_TYPE_HINT_TOOLBAR + GDK_WINDOW_TYPE_HINT_TOOLBAR, + GDK_WINDOW_TYPE_HINT_SPLASHSCREEN, + GDK_WINDOW_TYPE_HINT_UTILITY, + GDK_WINDOW_TYPE_HINT_DOCK, + GDK_WINDOW_TYPE_HINT_DESKTOP } GdkWindowTypeHint; @@ -396,10 +400,16 @@ void gdk_window_set_hints (GdkWindow *window, gint max_height, gint flags); #endif -void gdk_window_set_type_hint (GdkWindow *window, - GdkWindowTypeHint hint); -void gdk_window_set_modal_hint (GdkWindow *window, - gboolean modal); +void gdk_window_set_type_hint (GdkWindow *window, + GdkWindowTypeHint hint); +void gdk_window_set_modal_hint (GdkWindow *window, + gboolean modal); + +void gdk_window_set_skip_taskbar_hint (GdkWindow *window, + gboolean skips_taskbar); +void gdk_window_set_skip_pager_hint (GdkWindow *window, + gboolean skips_pager); + void gdk_window_set_geometry_hints (GdkWindow *window, GdkGeometry *geometry, GdkWindowHints geom_mask); @@ -490,6 +500,8 @@ void gdk_window_stick (GdkWindow *window); void gdk_window_unstick (GdkWindow *window); void gdk_window_maximize (GdkWindow *window); void gdk_window_unmaximize (GdkWindow *window); +void gdk_window_fullscreen (GdkWindow *window); +void gdk_window_unfullscreen (GdkWindow *window); void gdk_window_register_dnd (GdkWindow *window); diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c index 920d59d64b..5706a395d8 100644 --- a/gdk/x11/gdkevents-x11.c +++ b/gdk/x11/gdkevents-x11.c @@ -364,7 +364,7 @@ gdk_check_wm_state_changed (GdkWindow *window) gulong bytes_after; Atom *atoms = NULL; gulong i; - gboolean found_sticky, found_maxvert, found_maxhorz; + gboolean found_sticky, found_maxvert, found_maxhorz, found_fullscreen; GdkWindowState old_state; GdkDisplay *display = GDK_WINDOW_DISPLAY (window); @@ -375,6 +375,7 @@ gdk_check_wm_state_changed (GdkWindow *window) found_sticky = FALSE; found_maxvert = FALSE; found_maxhorz = FALSE; + found_fullscreen = FALSE; XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"), @@ -386,7 +387,8 @@ gdk_check_wm_state_changed (GdkWindow *window) Atom sticky_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_STICKY"); Atom maxvert_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_VERT"); Atom maxhorz_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_HORZ"); - + Atom fullscreen_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_FULLSCREEN"); + i = 0; while (i < nitems) { @@ -396,7 +398,9 @@ gdk_check_wm_state_changed (GdkWindow *window) found_maxvert = TRUE; else if (atoms[i] == maxhorz_atom) found_maxhorz = TRUE; - + else if (atoms[i] == fullscreen_atom) + found_fullscreen = TRUE; + ++i; } @@ -444,6 +448,21 @@ gdk_check_wm_state_changed (GdkWindow *window) GDK_WINDOW_STATE_STICKY); } + if (old_state & GDK_WINDOW_STATE_FULLSCREEN) + { + if (!found_fullscreen) + gdk_synthesize_window_state (window, + GDK_WINDOW_STATE_FULLSCREEN, + 0); + } + else + { + if (found_fullscreen) + gdk_synthesize_window_state (window, + 0, + GDK_WINDOW_STATE_FULLSCREEN); + } + /* Our "maximized" means both vertical and horizontal; if only one, * we don't expose that via GDK */ @@ -607,7 +626,14 @@ gdk_event_translate (GdkDisplay *display, xevent->xany.window == screen_x11->wmspec_check_window) { if (xevent->type == DestroyNotify) - screen_x11->wmspec_check_window = None; + { + screen_x11->wmspec_check_window = None; + g_free (screen_x11->window_manager_name); + screen_x11->window_manager_name = g_strdup ("unknown"); + + /* careful, reentrancy */ + _gdk_x11_screen_window_manager_changed (GDK_SCREEN (screen_x11)); + } /* Eat events on this window unless someone had wrapped * it as a foreign window @@ -2052,6 +2078,108 @@ gdk_x11_get_server_time (GdkWindow *window) return xevent.xproperty.time; } +static void +fetch_net_wm_check_window (GdkScreen *screen) +{ + GdkScreenX11 *screen_x11; + GdkDisplay *display; + Atom type; + gint format; + gulong n_items; + gulong bytes_after; + Window *xwindow; + + /* This function is very slow on every call if you are not running a + * spec-supporting WM. For now not optimized, because it isn't in + * any critical code paths, but if you used it somewhere that had to + * be fast you want to avoid "GTK is slow with old WMs" complaints. + * Probably at that point the function should be changed to query + * _NET_SUPPORTING_WM_CHECK only once every 10 seconds or something. + */ + + screen_x11 = GDK_SCREEN_X11 (screen); + display = screen_x11->display; + + if (screen_x11->wmspec_check_window != None) + return; /* already have it */ + + XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), screen_x11->xroot_window, + gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTING_WM_CHECK"), + 0, G_MAXLONG, False, XA_WINDOW, &type, &format, + &n_items, &bytes_after, (guchar **) & xwindow); + + if (type != XA_WINDOW) + return; + + gdk_error_trap_push (); + + /* Find out if this WM goes away, so we can reset everything. */ + XSelectInput (screen_x11->xdisplay, *xwindow, StructureNotifyMask); + + screen_x11->wmspec_check_window = *xwindow; + XFree (xwindow); + + screen_x11->need_refetch_net_supported = TRUE; + screen_x11->need_refetch_wm_name = TRUE; + + /* Careful, reentrancy */ + _gdk_x11_screen_window_manager_changed (GDK_SCREEN (screen_x11)); +} + +const char* +gdk_x11_screen_get_window_manager_name (GdkScreen *screen) +{ + GdkScreenX11 *screen_x11; + + screen_x11 = GDK_SCREEN_X11 (screen); + + fetch_net_wm_check_window (screen); + + if (screen_x11->need_refetch_wm_name) + { + /* Get the name of the window manager */ + screen_x11->need_refetch_wm_name = FALSE; + + g_free (screen_x11->window_manager_name); + screen_x11->window_manager_name = g_strdup ("unknown"); + + if (screen_x11->wmspec_check_window != None) + { + Atom type; + gint format; + gulong n_items; + gulong bytes_after; + guchar *name; + + name = NULL; + + XGetWindowProperty (GDK_DISPLAY_XDISPLAY (screen_x11->display), + screen_x11->wmspec_check_window, + gdk_x11_get_xatom_by_name_for_display (screen_x11->display, + "_NET_WM_NAME"), + 0, G_MAXLONG, False, + gdk_x11_get_xatom_by_name_for_display (screen_x11->display, + "UTF8_STRING"), + &type, &format, + &n_items, &bytes_after, + (guchar **)&name); + + gdk_display_sync (screen_x11->display); + + gdk_error_trap_pop (); + + if (name != NULL) + { + g_free (screen_x11->window_manager_name); + screen_x11->window_manager_name = g_strdup (name); + XFree (name); + } + } + } + + return GDK_SCREEN_X11 (screen)->window_manager_name; +} + typedef struct _NetWmSupportedAtoms NetWmSupportedAtoms; struct _NetWmSupportedAtoms @@ -2076,6 +2204,8 @@ struct _NetWmSupportedAtoms * is that your application can start up before the window manager * does when the user logs in, and before the window manager starts * gdk_x11_screen_supports_net_wm_hint() will return %FALSE for every property. + * You can monitor the window_manager_changed signal on #GdkScreen to detect + * a window manager change. * * Return value: %TRUE if the window manager supports @property **/ @@ -2083,11 +2213,6 @@ gboolean gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen, GdkAtom property) { - Atom type; - gint format; - gulong nitems; - gulong bytes_after; - Window *xwindow; gulong i; GdkScreenX11 *screen_x11; NetWmSupportedAtoms *supported_atoms; @@ -2105,72 +2230,51 @@ gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen, g_object_set_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms", supported_atoms); } - if (screen_x11->wmspec_check_window != None) + fetch_net_wm_check_window (screen); + + if (screen_x11->wmspec_check_window == None) + return FALSE; + + if (screen_x11->need_refetch_net_supported) { - if (supported_atoms->atoms == NULL) + /* WM has changed since we last got the supported list, + * refetch it. + */ + Atom type; + gint format; + gulong bytes_after; + + screen_x11->need_refetch_net_supported = FALSE; + + if (supported_atoms->atoms) + XFree (supported_atoms->atoms); + + supported_atoms->atoms = NULL; + supported_atoms->n_atoms = 0; + + XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), screen_x11->xroot_window, + gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTED"), + 0, G_MAXLONG, False, XA_ATOM, &type, &format, + &supported_atoms->n_atoms, &bytes_after, + (guchar **)&supported_atoms->atoms); + + if (type != XA_ATOM) return FALSE; - - i = 0; - while (i < supported_atoms->n_atoms) - { - if (supported_atoms->atoms[i] == gdk_x11_atom_to_xatom_for_display (display, property)) - return TRUE; - - ++i; - } - - return FALSE; } - - if (supported_atoms->atoms) - XFree (supported_atoms->atoms); - - supported_atoms->atoms = NULL; - supported_atoms->n_atoms = 0; - /* This function is very slow on every call if you are not running a - * spec-supporting WM. For now not optimized, because it isn't in - * any critical code paths, but if you used it somewhere that had to - * be fast you want to avoid "GTK is slow with old WMs" complaints. - * Probably at that point the function should be changed to query - * _NET_SUPPORTING_WM_CHECK only once every 10 seconds or something. - */ - - XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), screen_x11->xroot_window, - gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTING_WM_CHECK"), - 0, G_MAXLONG, False, XA_WINDOW, &type, &format, - &nitems, &bytes_after, (guchar **) & xwindow); - - if (type != XA_WINDOW) + if (supported_atoms->atoms == NULL) return FALSE; - - gdk_error_trap_push (); - - /* Find out if this WM goes away, so we can reset everything. */ - XSelectInput (screen_x11->xdisplay, *xwindow, StructureNotifyMask); - - gdk_display_sync (screen_x11->display); - if (gdk_error_trap_pop ()) + i = 0; + while (i < supported_atoms->n_atoms) { - XFree (xwindow); - return FALSE; + if (supported_atoms->atoms[i] == gdk_x11_atom_to_xatom_for_display (display, property)) + return TRUE; + + ++i; } - XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), screen_x11->xroot_window, - gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTED"), - 0, G_MAXLONG, False, XA_ATOM, &type, &format, - &supported_atoms->n_atoms, &bytes_after, - (guchar **)&supported_atoms->atoms); - - if (type != XA_ATOM) - return FALSE; - - screen_x11->wmspec_check_window = *xwindow; - XFree (xwindow); - - /* since wmspec_check_window != None this isn't infinite. ;-) */ - return gdk_x11_screen_supports_net_wm_hint (screen, property); + return FALSE; } /** @@ -2393,7 +2497,6 @@ gdk_xsettings_watch_cb (Window window, { GdkWindow *gdkwin; GdkScreen *screen = cb_data; - GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen); gdkwin = gdk_window_lookup_for_display (gdk_screen_get_display (screen), window); diff --git a/gdk/x11/gdkscreen-x11.c b/gdk/x11/gdkscreen-x11.c index 9cd565cad8..2f312f5771 100644 --- a/gdk/x11/gdkscreen-x11.c +++ b/gdk/x11/gdkscreen-x11.c @@ -46,8 +46,14 @@ static void gdk_screen_x11_dispose (GObject *object); static void gdk_screen_x11_finalize (GObject *object); static void init_xinerama_support (GdkScreen *screen); +enum +{ + WINDOW_MANAGER_CHANGED, + LAST_SIGNAL +}; static gpointer parent_class = NULL; +static guint signals[LAST_SIGNAL] = { 0 }; GType _gdk_screen_x11_get_type () @@ -84,6 +90,16 @@ gdk_screen_x11_class_init (GdkScreenX11Class *klass) object_class->finalize = gdk_screen_x11_finalize; parent_class = g_type_class_peek_parent (klass); + + signals[WINDOW_MANAGER_CHANGED] = + g_signal_new ("window_manager_changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdkScreenX11Class, window_manager_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); } /** @@ -247,7 +263,7 @@ gdk_screen_x11_dispose (GObject *object) screen_x11->screen_num = -1; screen_x11->xroot_window = None; screen_x11->wmspec_check_window = None; - + G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -264,10 +280,12 @@ gdk_screen_x11_finalize (GObject *object) g_object_unref (screen_x11->visuals[i]);*/ g_free (screen_x11->visuals); g_hash_table_destroy (screen_x11->visual_hash); + + g_free (screen_x11->window_manager_name); + g_hash_table_destroy (screen_x11->colormap_hash); /* X settings */ g_free (screen_x11->xsettings_client); - g_free (screen_x11->monitors); G_OBJECT_CLASS (parent_class)->finalize (object); @@ -360,7 +378,9 @@ _gdk_x11_screen_new (GdkDisplay *display, screen_x11->screen_num = screen_number; screen_x11->xroot_window = RootWindow (display_x11->xdisplay,screen_number); screen_x11->wmspec_check_window = None; - + /* we want this to be always non-null */ + screen_x11->window_manager_name = g_strdup ("unknown"); + init_xinerama_support (screen); _gdk_visual_init (screen); @@ -463,7 +483,6 @@ init_xinerama_support (GdkScreen * screen) #ifdef HAVE_XINERAMA int opcode, firstevent, firsterror; - gint result; if (XQueryExtension (GDK_SCREEN_XDISPLAY (screen), "XINERAMA", &opcode, &firstevent, &firsterror)) @@ -484,6 +503,13 @@ init_xinerama_support (GdkScreen * screen) screen_x11->monitors[0].height = HeightOfScreen (screen_x11->xscreen); } +void +_gdk_x11_screen_window_manager_changed (GdkScreen *screen) +{ + g_signal_emit (G_OBJECT (screen), + signals[WINDOW_MANAGER_CHANGED], 0); +} + /** * gdk_screen_make_display_name: * @screen: a #GdkScreen @@ -512,3 +538,4 @@ gdk_screen_make_display_name (GdkScreen *screen) return g_string_free (str, FALSE); } + diff --git a/gdk/x11/gdkscreen-x11.h b/gdk/x11/gdkscreen-x11.h index b6f2531418..6d3864671e 100644 --- a/gdk/x11/gdkscreen-x11.h +++ b/gdk/x11/gdkscreen-x11.h @@ -53,7 +53,18 @@ struct _GdkScreenX11 gint screen_num; Window xroot_window; GdkWindow *root_window; + + /* Window manager */ Window wmspec_check_window; + char *window_manager_name; + /* TRUE if wmspec_check_window has changed since last + * fetch of _NET_SUPPORTED + */ + guint need_refetch_net_supported : 1; + /* TRUE if wmspec_check_window has changed since last + * fetch of window manager name + */ + guint need_refetch_wm_name : 1; /* Visual Part */ GdkVisualPrivate *system_visual; @@ -82,12 +93,16 @@ struct _GdkScreenX11 struct _GdkScreenX11Class { GdkScreenClass parent_class; + + void (* window_manager_changed) (GdkScreenX11 *screen_x11); }; GType _gdk_screen_x11_get_type (void); GdkScreen * _gdk_x11_screen_new (GdkDisplay *display, gint screen_number); +void _gdk_x11_screen_window_manager_changed (GdkScreen *screen); + G_END_DECLS #endif /* __GDK_SCREEN_X11_H__ */ diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c index 1d9689c039..bbd689ebf4 100644 --- a/gdk/x11/gdkwindow-x11.c +++ b/gdk/x11/gdkwindow-x11.c @@ -133,7 +133,7 @@ _gdk_window_impl_get_type (void) static void gdk_window_impl_x11_init (GdkWindowImplX11 *impl) -{ +{ impl->width = 1; impl->height = 1; } @@ -900,7 +900,7 @@ static void set_initial_hints (GdkWindow *window) { GdkWindowObject *private; - Atom atoms[5]; + Atom atoms[6]; gint i; private = (GdkWindowObject*) window; @@ -946,6 +946,13 @@ set_initial_hints (GdkWindow *window) ++i; } + if (private->state & GDK_WINDOW_STATE_FULLSCREEN) + { + atoms[i] = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), + "_NET_WM_STATE_FULLSCREEN"); + ++i; + } + if (private->modal_hint) { atoms[i] = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), @@ -1610,6 +1617,18 @@ gdk_window_set_type_hint (GdkWindow *window, case GDK_WINDOW_TYPE_HINT_TOOLBAR: atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLBAR"); break; + case GDK_WINDOW_TYPE_HINT_UTILITY: + atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_UTILITY"); + break; + case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN: + atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_SPLASHSCREEN"); + break; + case GDK_WINDOW_TYPE_HINT_DOCK: + atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DOCK"); + break; + case GDK_WINDOW_TYPE_HINT_DESKTOP: + atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DESKTOP"); + break; default: g_warning ("Unknown hint %d passed to gdk_window_set_type_hint", hint); /* Fall thru */ @@ -1688,6 +1707,79 @@ gdk_window_set_modal_hint (GdkWindow *window, 0); } +/** + * gdk_window_set_skip_taskbar_hint: + * @window: a #GdkWindow + * @skips_taskbar: %TRUE to skip the taskbar + * + * Toggles whether a window should appear in a task list or window + * list. If a window's semantic type as specified with + * gdk_window_set_type_hint() already fully describes the window, this + * function should NOT be called in addition, instead you should allow + * the window to be treated according to standard policy for its + * semantic type. + **/ +void +gdk_window_set_skip_taskbar_hint (GdkWindow *window, + gboolean skips_taskbar) +{ + GdkWindowObject *private; + GdkWindowImplX11 *impl; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + private = (GdkWindowObject*) window; + impl = GDK_WINDOW_IMPL_X11 (private->impl); + + impl->skip_taskbar_hint = skips_taskbar; + + if (GDK_WINDOW_IS_MAPPED (window)) + gdk_wmspec_change_state (skips_taskbar, window, + gdk_atom_intern ("_NET_WM_STATE_SKIP_TASKBAR", FALSE), + 0); +} + +/** + * gdk_window_set_skip_pager_hint: + * @window: a #GdkWindow + * @skips_taskbar: %TRUE to skip the pager + * + * Toggles whether a window should appear in a pager (workspace + * switcher, or other desktop utility program that displays a small + * thumbnail representation of the windows on the desktop). If a + * window's semantic type as specified with gdk_window_set_type_hint() + * already fully describes the window, this function should NOT be + * called in addition, instead you should allow the window to be + * treated according to standard policy for its semantic type. + **/ +void +gdk_window_set_skip_pager_hint (GdkWindow *window, + gboolean skips_pager) +{ + GdkWindowObject *private; + GdkWindowImplX11 *impl; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + private = (GdkWindowObject*) window; + impl = GDK_WINDOW_IMPL_X11 (private->impl); + + impl->skip_pager_hint = skips_pager; + + if (GDK_WINDOW_IS_MAPPED (window)) + gdk_wmspec_change_state (skips_pager, window, + gdk_atom_intern ("_NET_WM_STATE_SKIP_PAGER", FALSE), + 0); +} + /** * gdk_window_set_geometry_hints: * @window: a #GdkWindow @@ -3297,13 +3389,17 @@ gdk_window_unstick (GdkWindow *window) * gdk_window_maximize: * @window: a #GdkWindow * - * Asks the window manager to maximize @window, if the window manager supports - * this operation. Not all window managers support this, and some deliberately - * ignore it or don't have a concept of "maximized"; so you can't rely on the - * maximization actually happening. But it will happen with most standard - * window managers, and GDK makes a best effort to get it to happen. + * Maximizes the window. If the window was already maximized, then + * this function does nothing. + * + * On X11, asks the window manager to maximize @window, if the window + * manager supports this operation. Not all window managers support + * this, and some deliberately ignore it or don't have a concept of + * "maximized"; so you can't rely on the maximization actually + * happening. But it will happen with most standard window managers, + * and GDK makes a best effort to get it to happen. * - * If the window was already maximized, then this function does nothing. + * On Windows, reliably maximizes the window. * **/ void @@ -3328,13 +3424,17 @@ gdk_window_maximize (GdkWindow *window) * gdk_window_unmaximize: * @window: a #GdkWindow * - * Asks the window manager to unmaximize @window, if the window manager supports - * this operation. Not all window managers support this, and some deliberately - * ignore it or don't have a concept of "maximized"; so you can't rely on the - * unmaximization actually happening. But it will happen with most standard - * window managers, and GDK makes a best effort to get it to happen. + * Unmaximizes the window. If the window wasn't maximized, then this + * function does nothing. + * + * On X11, asks the window manager to unmaximize @window, if the + * window manager supports this operation. Not all window managers + * support this, and some deliberately ignore it or don't have a + * concept of "maximized"; so you can't rely on the unmaximization + * actually happening. But it will happen with most standard window + * managers, and GDK makes a best effort to get it to happen. * - * If the window wasn't maximized, then this function does nothing. + * On Windows, reliably unmaximizes the window. * **/ void @@ -3355,6 +3455,80 @@ gdk_window_unmaximize (GdkWindow *window) 0); } +/** + * gdk_window_fullscreen: + * @window: a #GdkWindow + * + * Moves the window into fullscreen mode. This means the + * window covers the entire screen and is above any panels + * or task bars. + * + * If the window was already fullscreen, then this function does nothing. + * + * On X11, asks the window manager to put @window in a fullscreen + * state, if the window manager supports this operation. Not all + * window managers support this, and some deliberately ignore it or + * don't have a concept of "fullscreen"; so you can't rely on the + * fullscreenification actually happening. But it will happen with + * most standard window managers, and GDK makes a best effort to get + * it to happen. + * + **/ +void +gdk_window_fullscreen (GdkWindow *window) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + if (GDK_WINDOW_IS_MAPPED (window)) + gdk_wmspec_change_state (TRUE, window, + gdk_atom_intern ("_NET_WM_STATE_FULLSCREEN", FALSE), + GDK_NONE); + + else + gdk_synthesize_window_state (window, + 0, + GDK_WINDOW_STATE_FULLSCREEN); +} + +/** + * gdk_window_unfullscreen: + * @window: a #GdkWindow + * + * Moves the window out of fullscreen mode. If the window was not + * fullscreen, does nothing. + * + * On X11, asks the window manager to move @window out of the fullscreen + * state, if the window manager supports this operation. Not all + * window managers support this, and some deliberately ignore it or + * don't have a concept of "fullscreen"; so you can't rely on the + * unfullscreenification actually happening. But it will happen with + * most standard window managers, and GDK makes a best effort to get + * it to happen. + * + **/ +void +gdk_window_unfullscreen (GdkWindow *window) +{ + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + if (GDK_WINDOW_IS_MAPPED (window)) + gdk_wmspec_change_state (FALSE, window, + gdk_atom_intern ("_NET_WM_STATE_FULLSCREEN", FALSE), + GDK_NONE); + + else + gdk_synthesize_window_state (window, + GDK_WINDOW_STATE_FULLSCREEN, + 0); +} + + /** * gdk_window_set_group: * @window: a #GdkWindow diff --git a/gdk/x11/gdkwindow-x11.h b/gdk/x11/gdkwindow-x11.h index 0aaf0f93c2..75556e00cb 100644 --- a/gdk/x11/gdkwindow-x11.h +++ b/gdk/x11/gdkwindow-x11.h @@ -83,6 +83,10 @@ struct _GdkWindowImplX11 */ guint has_pointer_focus : 1; + /* Set if we are requesting these hints */ + guint skip_taskbar_hint : 1; + guint skip_pager_hint : 1; + /* We use an extra X window for toplevel windows that we XSetInputFocus() * to in order to avoid getting keyboard events redirected to subwindows * that might not even be part of this app diff --git a/gdk/x11/gdkx.h b/gdk/x11/gdkx.h index 83a4807f7c..1842b14721 100644 --- a/gdk/x11/gdkx.h +++ b/gdk/x11/gdkx.h @@ -53,6 +53,9 @@ Display *gdk_x11_gc_get_xdisplay (GdkGC *gc); GC gdk_x11_gc_get_xgc (GdkGC *gc); Screen * gdk_x11_screen_get_xscreen (GdkScreen *screen); int gdk_x11_screen_get_screen_number (GdkScreen *screen); + +const char* gdk_x11_screen_get_window_manager_name (GdkScreen *screen); + #ifndef GDK_MULTIHEAD_SAFE Window gdk_x11_get_default_root_xwindow (void); Display *gdk_x11_get_default_xdisplay (void); diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 8113bbc29e..dce5ea7761 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -70,7 +70,10 @@ enum { PROP_DESTROY_WITH_PARENT, PROP_ICON, PROP_SCREEN, - + PROP_TYPE_HINT, + PROP_SKIP_TASKBAR_HINT, + PROP_SKIP_PAGER_HINT, + /* Readonly properties */ PROP_IS_ACTIVE, PROP_HAS_TOPLEVEL_FOCUS, @@ -134,19 +137,30 @@ struct _GtkWindowGeometryInfo GtkWindowLastGeometryInfo last; }; -typedef struct { +typedef struct _GtkWindowMnemonic GtkWindowMnemonic; + +struct _GtkWindowMnemonic { GtkWindow *window; guint keyval; GSList *targets; -} GtkWindowMnemonic; +}; +typedef struct _GtkWindowPrivate GtkWindowPrivate; + +struct _GtkWindowPrivate +{ + guint fullscreen_initially : 1; + guint skips_taskbar : 1; + guint skips_pager : 1; +}; static void gtk_window_class_init (GtkWindowClass *klass); static void gtk_window_init (GtkWindow *window); static void gtk_window_dispose (GObject *object); static void gtk_window_destroy (GtkObject *object); static void gtk_window_finalize (GObject *object); +static void gtk_window_private_finalize (GtkWindowPrivate *priv); static void gtk_window_show (GtkWidget *widget); static void gtk_window_hide (GtkWidget *widget); static void gtk_window_map (GtkWidget *widget); @@ -288,6 +302,33 @@ mnemonic_equal (gconstpointer a, gconstpointer b) (ka->keyval == kb->keyval); } +GtkWindowPrivate* +gtk_window_get_private (GtkWindow *window) +{ + GtkWindowPrivate *private; + static GQuark private_quark = 0; + + if (!private_quark) + private_quark = g_quark_from_static_string ("gtk-window-private"); + + private = g_object_get_qdata (G_OBJECT (window), private_quark); + + if (!private) + { + private = g_new0 (GtkWindowPrivate, 1); + + private->fullscreen_initially = FALSE; + private->skips_pager = FALSE; + private->skips_taskbar = FALSE; + + g_object_set_qdata_full (G_OBJECT (window), private_quark, + private, + (GDestroyNotify) gtk_window_private_finalize); + } + + return private; +} + GtkType gtk_window_get_type (void) { @@ -523,7 +564,32 @@ gtk_window_class_init (GtkWindowClass *klass) _("Whether the input focus is within this GtkWindow"), FALSE, G_PARAM_READABLE)); - + + g_object_class_install_property (gobject_class, + PROP_TYPE_HINT, + g_param_spec_enum ("type_hint", + _("Type hint"), + _("Hint to help the desktop environment understand what kind of window this is and how to treat it."), + GDK_TYPE_WINDOW_TYPE_HINT, + GDK_WINDOW_TYPE_HINT_NORMAL, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_SKIP_TASKBAR_HINT, + g_param_spec_boolean ("skip_taskbar_hint", + _("Skip taskbar"), + _("TRUE if the window should not be in the task bar."), + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_SKIP_PAGER_HINT, + g_param_spec_boolean ("skip_pager_hint", + _("Skip pager"), + _("TRUE if the window should not be in the pager."), + FALSE, + G_PARAM_READWRITE)); + window_signals[SET_FOCUS] = g_signal_new ("set_focus", G_TYPE_FROM_CLASS (object_class), @@ -728,6 +794,19 @@ gtk_window_set_property (GObject *object, case PROP_SCREEN: gtk_window_set_screen (window, g_value_get_object (value)); break; + case PROP_TYPE_HINT: + gtk_window_set_type_hint (window, + g_value_get_enum (value)); + break; + case PROP_SKIP_TASKBAR_HINT: + gtk_window_set_skip_taskbar_hint (window, + g_value_get_boolean (value)); + break; + case PROP_SKIP_PAGER_HINT: + gtk_window_set_skip_pager_hint (window, + g_value_get_boolean (value)); + break; + default: break; } @@ -796,6 +875,18 @@ gtk_window_get_property (GObject *object, case PROP_HAS_TOPLEVEL_FOCUS: g_value_set_boolean (value, window->has_toplevel_focus); break; + case PROP_TYPE_HINT: + g_value_set_enum (value, + window->type_hint); + break; + case PROP_SKIP_TASKBAR_HINT: + g_value_set_boolean (value, + gtk_window_get_skip_taskbar_hint (window)); + break; + case PROP_SKIP_PAGER_HINT: + g_value_set_boolean (value, + gtk_window_get_skip_pager_hint (window)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1776,6 +1867,111 @@ gtk_window_get_type_hint (GtkWindow *window) return window->type_hint; } +/** + * gtk_window_set_skip_taskbar_hint: + * @window: a #GtkWindow + * @setting: %TRUE to keep this window from appearing in the task bar + * + * Windows may set a hint asking the desktop environment not to display + * the window in the task bar. This function toggles this hint. + * + **/ +void +gtk_window_set_skip_taskbar_hint (GtkWindow *window, + gboolean setting) +{ + GtkWindowPrivate *priv; + + g_return_if_fail (GTK_IS_WINDOW (window)); + + priv = gtk_window_get_private (window); + + setting = setting != FALSE; + + if (priv->skips_taskbar != setting) + { + priv->skips_taskbar = setting; + if (GTK_WIDGET_REALIZED (window)) + gdk_window_set_skip_taskbar_hint (GTK_WIDGET (window)->window, + priv->skips_taskbar); + g_object_notify (G_OBJECT (window), "skip_taskbar_hint"); + } +} + +/** + * gtk_window_get_skip_taskbar_hint: + * @window: a #GtkWindow + * + * Gets the value set by gtk_window_set_skip_taskbar_hint() + * + * Return value: %TRUE if window shouldn't be in taskbar + **/ +gboolean +gtk_window_get_skip_taskbar_hint (GtkWindow *window) +{ + GtkWindowPrivate *priv; + + g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); + + priv = gtk_window_get_private (window); + + return priv->skips_taskbar; +} + +/** + * gtk_window_set_skip_pager_hint: + * @window: a #GtkWindow + * @setting: %TRUE to keep this window from appearing in the pager + * + * Windows may set a hint asking the desktop environment not to display + * the window in the pager. This function toggles this hint. + * (A "pager" is any desktop navigation tool such as a workspace + * switcher that displays a thumbnail representation of the windows + * on the screen.) + * + **/ +void +gtk_window_set_skip_pager_hint (GtkWindow *window, + gboolean setting) +{ + GtkWindowPrivate *priv; + + g_return_if_fail (GTK_IS_WINDOW (window)); + + priv = gtk_window_get_private (window); + + setting = setting != FALSE; + + if (priv->skips_pager != setting) + { + priv->skips_pager = setting; + if (GTK_WIDGET_REALIZED (window)) + gdk_window_set_skip_pager_hint (GTK_WIDGET (window)->window, + priv->skips_pager); + g_object_notify (G_OBJECT (window), "skip_pager_hint"); + } +} + +/** + * gtk_window_get_skip_pager_hint: + * @window: a #GtkWindow + * + * Gets the value set by gtk_window_set_skip_pager_hint(). + * + * Return value: %TRUE if window shouldn't be in pager + **/ +gboolean +gtk_window_get_skip_pager_hint (GtkWindow *window) +{ + GtkWindowPrivate *priv; + + g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); + + priv = gtk_window_get_private (window); + + return priv->skips_pager; +} + /** * gtk_window_set_destroy_with_parent: * @window: a #GtkWindow @@ -3057,6 +3253,13 @@ gtk_window_mnemonic_hash_remove (gpointer key, return FALSE; } +static void +gtk_window_private_finalize (GtkWindowPrivate *priv) +{ + + g_free (priv); +} + static void gtk_window_finalize (GObject *object) { @@ -3192,6 +3395,9 @@ gtk_window_map (GtkWidget *widget) { GtkWindow *window = GTK_WINDOW (widget); GdkWindow *toplevel; + GtkWindowPrivate *priv; + + priv = gtk_window_get_private (window); GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); @@ -3220,6 +3426,11 @@ gtk_window_map (GtkWidget *widget) else gdk_window_deiconify (toplevel); + if (priv->fullscreen_initially) + gdk_window_fullscreen (toplevel); + else + gdk_window_unfullscreen (toplevel); + /* No longer use the default settings */ window->need_default_size = FALSE; window->need_default_position = FALSE; @@ -3396,6 +3607,12 @@ gtk_window_realize (GtkWidget *widget) gdk_window_set_type_hint (widget->window, window->type_hint); + if (gtk_window_get_skip_pager_hint (window)) + gdk_window_set_skip_pager_hint (widget->window, TRUE); + + if (gtk_window_get_skip_taskbar_hint (window)) + gdk_window_set_skip_taskbar_hint (widget->window, TRUE); + /* transient_for must be set to allow the modal hint */ if (window->transient_parent && window->modal) gdk_window_set_modal_hint (widget->window, TRUE); @@ -5240,6 +5457,85 @@ gtk_window_unmaximize (GtkWindow *window) gdk_window_unmaximize (toplevel); } +/** + * gtk_window_fullscreen: + * @window: a #GtkWindow + * + * Asks to place @window in the fullscreen state. Note that you + * shouldn't assume the window is definitely full screen afterward, + * because other entities (e.g. the user or window manager) could unfullscreen it + * again, and not all window managers honor requests to fullscreen + * windows. But normally the window will end up fullscreen. Just + * don't write code that crashes if not. + * + * You can track the fullscreen state via the "window_state_event" signal + * on #GtkWidget. + * + **/ +void +gtk_window_fullscreen (GtkWindow *window) +{ + GtkWidget *widget; + GdkWindow *toplevel; + GtkWindowPrivate *priv; + + g_return_if_fail (GTK_IS_WINDOW (window)); + + widget = GTK_WIDGET (window); + priv = gtk_window_get_private (window); + + priv->fullscreen_initially = TRUE; + + if (window->frame) + toplevel = window->frame; + else + toplevel = widget->window; + + if (toplevel != NULL) + gdk_window_fullscreen (toplevel); +} + +/** + * gtk_window_unfullscreen: + * @window: a #GtkWindow + * + * Asks to toggle off the fullscreen state for @window. Note that you + * shouldn't assume the window is definitely not full screen + * afterward, because other entities (e.g. the user or window manager) could fullscreen it + * again, and not all window managers honor requests to unfullscreen + * windows. But normally the window will end up restored to its normal + * state. Just don't write code that crashes if not. + * + * You can track the fullscreen state via the "window_state_event" signal + * on #GtkWidget. + * + **/ +void +gtk_window_unfullscreen (GtkWindow *window) +{ + GtkWidget *widget; + GdkWindow *toplevel; + GtkWindowPrivate *priv; + + g_return_if_fail (GTK_IS_WINDOW (window)); + + widget = GTK_WIDGET (window); + priv = gtk_window_get_private (window); + + priv->fullscreen_initially = FALSE; + + if (window->frame) + toplevel = window->frame; + else + toplevel = widget->window; + + if (toplevel != NULL) + gdk_window_unfullscreen (toplevel); +} + + /** * gtk_window_set_resizable: * @window: a #GtkWindow diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h index 9dff5d7205..d760933b78 100644 --- a/gtk/gtkwindow.h +++ b/gtk/gtkwindow.h @@ -195,6 +195,12 @@ GtkWindow *gtk_window_get_transient_for (GtkWindow *window); void gtk_window_set_type_hint (GtkWindow *window, GdkWindowTypeHint hint); GdkWindowTypeHint gtk_window_get_type_hint (GtkWindow *window); +void gtk_window_set_skip_taskbar_hint (GtkWindow *window, + gboolean setting); +gboolean gtk_window_get_skip_taskbar_hint (GtkWindow *window); +void gtk_window_set_skip_pager_hint (GtkWindow *window, + gboolean setting); +gboolean gtk_window_get_skip_pager_hint (GtkWindow *window); void gtk_window_set_destroy_with_parent (GtkWindow *window, gboolean setting); gboolean gtk_window_get_destroy_with_parent (GtkWindow *window); @@ -270,6 +276,8 @@ void gtk_window_stick (GtkWindow *window); void gtk_window_unstick (GtkWindow *window); void gtk_window_maximize (GtkWindow *window); void gtk_window_unmaximize (GtkWindow *window); +void gtk_window_fullscreen (GtkWindow *window); +void gtk_window_unfullscreen (GtkWindow *window); void gtk_window_begin_resize_drag (GtkWindow *window, GdkWindowEdge edge, diff --git a/tests/testgtk.c b/tests/testgtk.c index afb4675099..9f412a72bd 100644 --- a/tests/testgtk.c +++ b/tests/testgtk.c @@ -9215,7 +9215,9 @@ window_state_callback (GtkWidget *widget, (event->new_window_state & GDK_WINDOW_STATE_STICKY) ? "sticky" : "not sticky", ", ", (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) ? - "maximized" : "not maximized", + "maximized" : "not maximized", ", ", + (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) ? + "fullscreen" : "not fullscreen", NULL); gtk_label_set_text (GTK_LABEL (label), msg); @@ -9261,6 +9263,20 @@ tracking_label (GtkWidget *window) GTK_SIGNAL_FUNC (gtk_window_iconify), GTK_OBJECT (window)); gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Fullscreen"); + gtk_signal_connect_object (GTK_OBJECT (button), + "clicked", + GTK_SIGNAL_FUNC (gtk_window_fullscreen), + GTK_OBJECT (window)); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Unfullscreen"); + gtk_signal_connect_object (GTK_OBJECT (button), + "clicked", + GTK_SIGNAL_FUNC (gtk_window_unfullscreen), + GTK_OBJECT (window)); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); button = gtk_button_new_with_label ("Present"); gtk_signal_connect_object (GTK_OBJECT (button), @@ -9324,6 +9340,20 @@ get_state_controls (GtkWidget *window) GTK_OBJECT (window)); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + button = gtk_button_new_with_label ("Fullscreen"); + gtk_signal_connect_object (GTK_OBJECT (button), + "clicked", + GTK_SIGNAL_FUNC (gtk_window_fullscreen), + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Unfullscreen"); + gtk_signal_connect_object (GTK_OBJECT (button), + "clicked", + GTK_SIGNAL_FUNC (gtk_window_unfullscreen), + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + button = gtk_button_new_with_label ("Hide (withdraw)"); gtk_signal_connect_object (GTK_OBJECT (button), "clicked",