small wm spec API additions



Hi,

This adds support for the remaining window type hints, the fullscreen
state, skip taskbar/pager, and adds a signal to GdkScreenX11 for
window_manager_changed (since it's otherwise a bit complicated for
apps to detect this, and anyone using gdk_net_wm_supports() really
needs to monitor it).

The skip taskbar/pager hint and the window_manager_changed signal need
test code in tests/, I haven't tested them. I'll add that and clean up
the patch if people like the API additions conceptually.

Havoc

Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gtk+/ChangeLog,v
retrieving revision 1.3417
diff -u -p -u -r1.3417 ChangeLog
--- ChangeLog	10 May 2002 21:59:18 -0000	1.3417
+++ ChangeLog	13 May 2002 03:45:24 -0000
@@ -1,3 +1,36 @@
+2002-05-12  Havoc Pennington  <hp pobox com>
+
+	* 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
+
+	* gdk/gdkscreen.c: add missing includes to avoid warnings
+
 2002-05-10  Daniel Elstner  <daniel elstner gmx net>
 
 	[ merge from stable ]
Index: gdk/gdkevents.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkevents.h,v
retrieving revision 1.16
diff -u -p -u -r1.16 gdkevents.h
--- gdk/gdkevents.h	25 Apr 2002 22:29:09 -0000	1.16
+++ gdk/gdkevents.h	13 May 2002 03:45:24 -0000
@@ -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
Index: gdk/gdkscreen.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkscreen.c,v
retrieving revision 1.6
diff -u -p -u -r1.6 gdkscreen.c
--- gdk/gdkscreen.c	2 May 2002 22:28:42 -0000	1.6
+++ gdk/gdkscreen.c	13 May 2002 03:45:24 -0000
@@ -23,6 +23,8 @@
 
 #include "gdkscreen.h"
 #include "gdkcolor.h"
+#include "gdkwindow.h"
+#include "gdk.h"
 
 GType
 gdk_screen_get_type (void)
Index: gdk/gdkwindow.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkwindow.h,v
retrieving revision 1.41
diff -u -p -u -r1.41 gdkwindow.h
--- gdk/gdkwindow.h	25 Apr 2002 22:29:10 -0000	1.41
+++ gdk/gdkwindow.h	13 May 2002 03:45:24 -0000
@@ -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	 (GdkWin
 					  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          
 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);
 
Index: gdk/x11/gdkevents-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkevents-x11.c,v
retrieving revision 1.77
diff -u -p -u -r1.77 gdkevents-x11.c
--- gdk/x11/gdkevents-x11.c	6 May 2002 22:05:17 -0000	1.77
+++ gdk/x11/gdkevents-x11.c	13 May 2002 03:45:24 -0000
@@ -610,7 +610,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");
+
+          /* This sure is a sucky place to emit a signal */
+          _gdk_x11_screen_window_manager_changed (GDK_SCREEN (screen_x11));
+        }
       
       /* Eat events on this window unless someone had wrapped
        * it as a foreign window
@@ -2079,6 +2086,84 @@ gdk_x11_get_server_time (GdkWindow *wind
   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;
+  guchar *name;
+  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);
+
+  /* Get the name of the window manager */
+  name = NULL;
+  XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), screen_x11->xroot_window,
+		      gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_NAME"),
+		      0, G_MAXLONG, False,
+                      gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"),
+                      &type, &format, 
+		      &n_items, &bytes_after,
+		      (guchar **)&name);
+  
+  gdk_display_sync (screen_x11->display);
+  
+  if (gdk_error_trap_pop () || name == NULL)
+    {
+      XFree (xwindow);
+      if (name)
+        XFree (name);
+      return;
+    }  
+
+  g_free (screen_x11->window_manager_name);
+  screen_x11->window_manager_name = g_strdup (name);
+  XFree (name);
+  
+  screen_x11->wmspec_check_window = *xwindow;
+  XFree (xwindow);
+
+  /* This sure is a sucky place to emit a signal */
+  _gdk_x11_screen_window_manager_changed (GDK_SCREEN (screen_x11));
+}
+
+const char*
+gdk_x11_screen_get_window_manager_name (GdkScreen *screen)
+{
+  fetch_net_wm_check_window (screen);
+  
+  return GDK_SCREEN_X11 (screen)->window_manager_name;
+}
+
 typedef struct _NetWmSupportedAtoms NetWmSupportedAtoms;
 
 struct _NetWmSupportedAtoms
@@ -2110,15 +2195,11 @@ 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;
   GdkDisplay *display;
+  Window old_wmcheck_window;
 
   g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
   
@@ -2132,72 +2213,51 @@ gdk_x11_screen_supports_net_wm_hint (Gdk
       g_object_set_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms", supported_atoms);
     }
 
-  if (screen_x11->wmspec_check_window != None)
-    {
-      if (supported_atoms->atoms == NULL)
-        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.
-   */
+  old_wmcheck_window = screen_x11->wmspec_check_window;
   
-  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)
-    return FALSE;
+  fetch_net_wm_check_window (screen);
 
-  gdk_error_trap_push ();
-
-  /* Find out if this WM goes away, so we can reset everything. */
-  XSelectInput (screen_x11->xdisplay, *xwindow, StructureNotifyMask);
+  if (screen_x11->wmspec_check_window == None)
+    return FALSE;
 
-  gdk_display_sync (screen_x11->display);
-  
-  if (gdk_error_trap_pop ())
+  if (old_wmcheck_window != screen_x11->wmspec_check_window)
     {
-      XFree (xwindow);
-      return FALSE;
+      /* WM has changed since we last got the supported list,
+       * refetch it.
+       */
+      Atom type;
+      gint format;
+      gulong bytes_after;
+      
+      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;
     }
   
-  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)
+  if (supported_atoms->atoms == NULL)
     return FALSE;
   
-  screen_x11->wmspec_check_window = *xwindow;
-  XFree (xwindow);
+  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;
+    }
   
-  /* since wmspec_check_window != None this isn't infinite. ;-) */
-  return gdk_x11_screen_supports_net_wm_hint (screen, property);
+  return FALSE;
 }
 
 /**
Index: gdk/x11/gdkscreen-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkscreen-x11.c,v
retrieving revision 1.7
diff -u -p -u -r1.7 gdkscreen-x11.c
--- gdk/x11/gdkscreen-x11.c	3 May 2002 19:03:03 -0000	1.7
+++ gdk/x11/gdkscreen-x11.c	13 May 2002 03:45:24 -0000
@@ -59,8 +59,15 @@ static void          gdk_screen_x11_get_
 static void	     init_xinerama_support		  (GdkScreen * screen);
 
 
+enum
+{
+  WINDOW_MANAGER_CHANGED,
+  LAST_SIGNAL
+};
+
 GType gdk_screen_x11_get_type ();
 static gpointer parent_class = NULL;
+static guint signals[LAST_SIGNAL] = { 0 };
 
 GType
 gdk_screen_x11_get_type ()
@@ -92,6 +99,7 @@ void
 gdk_screen_x11_class_init (GdkScreenX11Class * klass)
 {
   GdkScreenClass *screen_class = GDK_SCREEN_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
   
   screen_class->get_display = gdk_screen_x11_get_display;
   screen_class->get_width = gdk_screen_x11_get_width;
@@ -109,6 +117,16 @@ gdk_screen_x11_class_init (GdkScreenX11C
   
   G_OBJECT_CLASS (klass)->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);
 }
 
 static GdkDisplay *
@@ -243,6 +261,7 @@ gdk_screen_x11_finalize (GObject *object
   g_hash_table_destroy (screen_x11->visual_hash);
   /* X settings */
   g_free (screen_x11->xsettings_client);
+  g_free (screen_x11->window_manager_name);
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -309,7 +328,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);
@@ -433,3 +454,9 @@ init_xinerama_support (GdkScreen * scree
   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);
+}
Index: gdk/x11/gdkscreen-x11.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkscreen-x11.h,v
retrieving revision 1.4
diff -u -p -u -r1.4 gdkscreen-x11.h
--- gdk/x11/gdkscreen-x11.h	3 May 2002 19:03:03 -0000	1.4
+++ gdk/x11/gdkscreen-x11.h	13 May 2002 03:45:24 -0000
@@ -53,7 +53,10 @@ struct _GdkScreenX11
   gint screen_num;
   Window xroot_window;
   GdkWindow *root_window;
+
+  /* Window manager */
   Window wmspec_check_window;
+  char *window_manager_name;
   
   /* Visual Part */
   GdkVisualPrivate *system_visual;
@@ -80,11 +83,16 @@ struct _GdkScreenX11
 struct _GdkScreenX11Class
 {
   GdkScreenClass parent_class;
+
+  void (* window_manager_changed) (GdkScreenX11 *screen_x11);
 };
 
 GType gdk_screen_x11_get_type ();
 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__ */
Index: gdk/x11/gdkwindow-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkwindow-x11.c,v
retrieving revision 1.151
diff -u -p -u -r1.151 gdkwindow-x11.c
--- gdk/x11/gdkwindow-x11.c	6 May 2002 22:05:17 -0000	1.151
+++ gdk/x11/gdkwindow-x11.c	13 May 2002 03:45:25 -0000
@@ -76,6 +76,15 @@ const int _gdk_event_mask_table[21] =
 };
 const int _gdk_nenvent_masks = sizeof (_gdk_event_mask_table) / sizeof (int);
 
+typedef struct
+{
+  guint skip_taskbar_hint : 1;
+  guint skip_pager_hint : 1;
+
+} GdkWindowImplX11Private;
+
+#define GDK_WINDOW_IMPL_X11_PRIVATE(x) (g_object_get_data (G_OBJECT (x), "gdk-window-impl-x11-private"))
+
 /* Forward declarations */
 static gboolean gdk_window_gravity_works          (GdkWindow  *window);
 static void     gdk_window_set_static_win_gravity (GdkWindow  *window,
@@ -93,6 +102,7 @@ static GdkRegion*  gdk_window_impl_x11_g
 static void gdk_window_impl_x11_init       (GdkWindowImplX11      *window);
 static void gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass);
 static void gdk_window_impl_x11_finalize   (GObject            *object);
+static void gdk_window_impl_x11_private_finalize (GdkWindowImplX11Private *priv);
 
 static gpointer parent_class = NULL;
 
@@ -133,8 +143,16 @@ _gdk_window_impl_get_type (void)
 static void
 gdk_window_impl_x11_init (GdkWindowImplX11 *impl)
 {
+  GdkWindowImplX11Private *priv;
+  
   impl->width = 1;
   impl->height = 1;
+
+  priv = g_new0 (GdkWindowImplX11Private, 1);
+  g_object_set_data_full (G_OBJECT (impl),
+                          "gdk-window-impl-x11-private",
+                          priv,
+                          (GDestroyNotify) gdk_window_impl_x11_private_finalize);
 }
 
 static void
@@ -157,6 +175,12 @@ gdk_window_impl_x11_class_init (GdkWindo
 }
 
 static void
+gdk_window_impl_x11_private_finalize (GdkWindowImplX11Private *priv)
+{
+  g_free (priv);
+}
+
+static void
 gdk_window_impl_x11_finalize (GObject *object)
 {
   GdkWindowObject *wrapper;
@@ -1619,6 +1643,18 @@ gdk_window_set_type_hint (GdkWindow     
     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 */
@@ -1698,6 +1734,79 @@ gdk_window_set_modal_hint (GdkWindow *wi
 }
 
 /**
+ * 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;
+  GdkWindowImplX11Private *impl_private;
+  
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
+
+  private = (GdkWindowObject*) window;
+  impl_private = GDK_WINDOW_IMPL_X11_PRIVATE (private->impl);
+
+  impl_private->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;
+  GdkWindowImplX11Private *impl_private;
+  
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
+
+  private = (GdkWindowObject*) window;
+  impl_private = GDK_WINDOW_IMPL_X11_PRIVATE (private->impl);
+
+  impl_private->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
  * @geometry: geometry hints
@@ -3278,11 +3387,14 @@ 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.
+ * 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.
+ *
+ * On Windows, reliably maximizes the window.
  *
  * If the window was already maximized, then this function does nothing.
  * 
@@ -3309,12 +3421,15 @@ 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.
+ * 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.
  *
+ * On Windows, reliably unmaximizes the window.
+ * 
  * If the window wasn't maximized, then this function does nothing.
  * 
  **/
@@ -3335,6 +3450,79 @@ gdk_window_unmaximize (GdkWindow *window
 				 GDK_WINDOW_STATE_MAXIMIZED,
 				 0);
 }
+
+/**
+ * gdk_window_fullscreen:
+ * @window: a #GdkWindow
+ *
+ * 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.
+ *
+ * On Windows, this function is not yet documented. FIXME.
+ *
+ * If the window was already fullscreen, then this function does nothing.
+ * 
+ **/
+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
+ *
+ * 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.
+ *
+ * On Windows, this function is not yet documented. FIXME.
+ *
+ * If the window was not fullscreen, then this function does nothing.
+ * 
+ **/
+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:
Index: gdk/x11/gdkx.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkx.h,v
retrieving revision 1.30
diff -u -p -u -r1.30 gdkx.h
--- gdk/x11/gdkx.h	30 Apr 2002 16:29:49 -0000	1.30
+++ gdk/x11/gdkx.h	13 May 2002 03:45:26 -0000
@@ -53,6 +53,9 @@ Display *gdk_x11_gc_get_xdisplay        
 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);
Index: gtk/gtkwindow.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.c,v
retrieving revision 1.204
diff -u -p -u -r1.204 gtkwindow.c
--- gtk/gtkwindow.c	1 May 2002 17:22:53 -0000	1.204
+++ gtk/gtkwindow.c	13 May 2002 03:45:27 -0000
@@ -69,6 +69,9 @@ enum {
   PROP_DESTROY_WITH_PARENT,
   PROP_ICON,
   PROP_SCREEN,
+  PROP_TYPE_HINT,
+  PROP_SKIP_TASKBAR_HINT,
+  PROP_SKIP_PAGER_HINT,
   
   LAST_ARG
 };
@@ -136,12 +139,21 @@ typedef struct {
   GSList *targets;
 } GtkWindowMnemonic;
 
+typedef struct
+{
+  guint fullscreen_initially : 1;
+  guint skips_taskbar : 1;
+  guint skips_pager : 1;
+} GtkWindowPrivate;
+
+#define GTK_WINDOW_PRIVATE(x)  (g_object_get_data (G_OBJECT (x), "gtk-window-private"))
 
 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);
@@ -503,6 +515,31 @@ gtk_window_class_init (GtkWindowClass *k
 							GDK_TYPE_SCREEN,
  							G_PARAM_READWRITE));
 
+  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),
@@ -596,6 +633,7 @@ static void
 gtk_window_init (GtkWindow *window)
 {
   GdkColormap *colormap;
+  GtkWindowPrivate *priv;
   
   GTK_WIDGET_UNSET_FLAGS (window, GTK_NO_WINDOW);
   GTK_WIDGET_SET_FLAGS (window, GTK_TOPLEVEL);
@@ -631,6 +669,15 @@ gtk_window_init (GtkWindow *window)
   window->decorated = TRUE;
   window->mnemonic_modifier = GDK_MOD1_MASK;
   window->screen = gdk_get_default_screen ();
+
+  priv = g_new0 (GtkWindowPrivate, 1);
+  g_object_set_data_full (G_OBJECT (window),
+                          "gtk-window-private",
+                          priv,
+                          (GDestroyNotify) gtk_window_private_finalize);
+  priv->fullscreen_initially = FALSE;
+  priv->skips_pager = FALSE;
+  priv->skips_taskbar = FALSE;
   
   colormap = _gtk_widget_peek_colormap ();
   if (colormap)
@@ -707,6 +754,19 @@ gtk_window_set_property (GObject      *o
     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;
     }
@@ -769,6 +829,18 @@ gtk_window_get_property (GObject      *o
     case PROP_SCREEN:
       g_value_set_object (value, window->screen);
       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;
@@ -1750,6 +1822,111 @@ gtk_window_get_type_hint (GtkWindow *win
 }
 
 /**
+ * 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_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_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_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_PRIVATE (window);
+
+  return priv->skips_pager;
+}
+
+/**
  * gtk_window_set_destroy_with_parent:
  * @window: a #GtkWindow
  * @setting: whether to destroy @window with its transient parent
@@ -3031,6 +3208,13 @@ gtk_window_mnemonic_hash_remove (gpointe
 }
 
 static void
+gtk_window_private_finalize (GtkWindowPrivate  *priv)
+{
+  
+  g_free (priv);
+}
+
+static void
 gtk_window_finalize (GObject *object)
 {
   GtkWindow *window = GTK_WINDOW (object);
@@ -3161,6 +3345,9 @@ gtk_window_map (GtkWidget *widget)
 {
   GtkWindow *window = GTK_WINDOW (widget);
   GdkWindow *toplevel;
+  GtkWindowPrivate *priv;
+
+  priv = GTK_WINDOW_PRIVATE (widget);
   
   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
 
@@ -3189,6 +3376,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;
@@ -3359,6 +3551,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);
@@ -5174,6 +5372,85 @@ gtk_window_unmaximize (GtkWindow *window
   if (toplevel != NULL)
     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 <link
+ * linkend="gtk-X11-arch">window manager</link>) 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_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 <link
+ * linkend="gtk-X11-arch">window manager</link>) 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_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:
Index: gtk/gtkwindow.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.h,v
retrieving revision 1.62
diff -u -p -u -r1.62 gtkwindow.h
--- gtk/gtkwindow.h	29 Apr 2002 22:53:45 -0000	1.62
+++ gtk/gtkwindow.h	13 May 2002 03:45:27 -0000
@@ -192,6 +192,12 @@ GtkWindow *gtk_window_get_transient_for 
 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);
@@ -267,6 +273,8 @@ void     gtk_window_stick         (GtkWi
 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,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]