window state stuff
- From: Havoc Pennington <hp redhat com>
- To: gtk-devel-list gnome org
- Cc: jsh eazel com
- Subject: window state stuff
- Date: 23 Feb 2001 19:51:39 -0500
Hi,
Appended patch adds support for:
void gtk_window_present (GtkWindow *window);
void gtk_window_iconify (GtkWindow *window);
void gtk_window_deiconify (GtkWindow *window);
void gtk_window_stick (GtkWindow *window);
void gtk_window_unstick (GtkWindow *window);
void gtk_window_maximize (GtkWindow *window);
void gtk_window_unmaximize (GtkWindow *window);
and has GDK functions to support that. Also:
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
} GdkWindowState;
struct _GdkEventWindowState
{
GdkEventType type;
GdkWindow *window;
gint8 send_event;
GdkWindowState changed;
GdkWindowState current;
};
Which gives you notification of (de)iconify, (un)stick, (un)maximize,
plus also (un)withdraw (map_event/unmap_event occur on
withdraw/unwithdraw, but also on iconification).
Iconification includes window shading and flipping to another desktop,
at least for Sawfish. So there's no separate states for shading, and
people might be a bit surprised when they get iconify notifications on
desktop flips.
gtk_window_present() is pretty much exactly the same as the Nautilus
version, except that it uses the WM spec focus stuff if available.
The ChangeLog is incomplete, I know.
Havoc
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gtk+/ChangeLog,v
retrieving revision 1.1751
diff -u -u -r1.1751 ChangeLog
--- ChangeLog 2001/02/23 23:00:49 1.1751
+++ ChangeLog 2001/02/24 00:43:42
@@ -1,3 +1,11 @@
+2001-02-21 Havoc Pennington <hp redhat com>
+
+ * gdk/x11/gdkwindow-x11.c (gdk_window_focus): new function,
+ focuses a window
+
+ * gdk/x11/gdkmain-x11.c (_gdk_wmspec_supported): new function,
+ finds out if we support a given WM spec hint
+
Fri Feb 23 17:50:13 2001 Jonathan Blandford <jrb redhat com>
* gtk/gtktreeview.c (gtk_tree_view_bin_expose): Only draw the
Index: gdk/gdkevents.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkevents.c,v
retrieving revision 1.33
diff -u -u -r1.33 gdkevents.c
--- gdk/gdkevents.c 2000/12/18 19:12:34 1.33
+++ gdk/gdkevents.c 2001/02/24 00:43:43
@@ -454,6 +454,7 @@
case GDK_EXPOSE:
case GDK_MAP:
case GDK_UNMAP:
+ case GDK_WINDOW_STATE:
/* return current time */
break;
}
@@ -529,6 +530,7 @@
case GDK_EXPOSE:
case GDK_MAP:
case GDK_UNMAP:
+ case GDK_WINDOW_STATE:
/* no state field */
break;
}
@@ -803,3 +805,56 @@
button_number[0] = event->button.button;
}
}
+
+
+void
+gdk_synthesize_window_state (GdkWindow *window,
+ GdkWindowState unset_flags,
+ GdkWindowState set_flags)
+{
+ GdkEventWindowState temp_event;
+ GdkWindowState old;
+
+ g_return_if_fail (window != NULL);
+
+ temp_event.window = window;
+ temp_event.type = GDK_WINDOW_STATE;
+ temp_event.send_event = FALSE;
+
+ old = ((GdkWindowObject*)temp_event.window)->state;
+
+ temp_event.changed = (unset_flags | set_flags) ^ old;
+ temp_event.current = old;
+ temp_event.current |= set_flags;
+ temp_event.current &= ~unset_flags;
+
+ if (temp_event.current == old)
+ return; /* No actual work to do, nothing changed. */
+
+ /* Actually update the field in GdkWindow, this is sort of an odd
+ * place to do it, but seems like the safest since it ensures we expose no
+ * inconsistent state.
+ */
+
+ ((GdkWindowObject*)window)->state = temp_event.current;
+
+ /* We only really send the event to toplevels, since
+ * all the window states don't apply to non-toplevels.
+ * Non-toplevels do use the GDK_WINDOW_STATE_WITHDRAWN flag
+ * internally so we needed to update window->state.
+ */
+ switch (((GdkWindowObject*)window)->window_type)
+ {
+ case GDK_WINDOW_TOPLEVEL:
+ case GDK_WINDOW_DIALOG:
+ case GDK_WINDOW_TEMP: /* ? */
+ gdk_event_put ((GdkEvent*)&temp_event);
+ break;
+
+ case GDK_WINDOW_FOREIGN:
+ case GDK_WINDOW_ROOT:
+ case GDK_WINDOW_CHILD:
+ break;
+ }
+}
+
Index: gdk/gdkevents.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkevents.h,v
retrieving revision 1.11
diff -u -u -r1.11 gdkevents.h
--- gdk/gdkevents.h 2000/12/17 23:49:58 1.11
+++ gdk/gdkevents.h 2001/02/24 00:43:43
@@ -28,8 +28,8 @@
typedef struct _GdkEventSelection GdkEventSelection;
typedef struct _GdkEventProximity GdkEventProximity;
typedef struct _GdkEventClient GdkEventClient;
-
typedef struct _GdkEventDND GdkEventDND;
+typedef struct _GdkEventWindowState GdkEventWindowState;
typedef union _GdkEvent GdkEvent;
@@ -110,7 +110,8 @@
GDK_CLIENT_EVENT = 28,
GDK_VISIBILITY_NOTIFY = 29,
GDK_NO_EXPOSE = 30,
- GDK_SCROLL = 31
+ GDK_SCROLL = 31,
+ GDK_WINDOW_STATE = 32
} GdkEventType;
/* Event masks. (Used to select what types of events a window
@@ -193,6 +194,14 @@
GDK_PROPERTY_DELETE
} GdkPropertyState;
+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
+} GdkWindowState;
+
struct _GdkEventAny
{
GdkEventType type;
@@ -366,6 +375,16 @@
} data;
};
+
+struct _GdkEventWindowState
+{
+ GdkEventType type;
+ GdkWindow *window;
+ gint8 send_event;
+ GdkWindowState changed;
+ GdkWindowState current;
+};
+
/* Event types for DND */
struct _GdkEventDND {
@@ -397,6 +416,7 @@
GdkEventProximity proximity;
GdkEventClient client;
GdkEventDND dnd;
+ GdkEventWindowState window_state;
};
gboolean gdk_events_pending (void);
Index: gdk/gdkinternals.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkinternals.h,v
retrieving revision 1.6
diff -u -u -r1.6 gdkinternals.h
--- gdk/gdkinternals.h 2000/08/30 00:33:35 1.6
+++ gdk/gdkinternals.h 2001/02/24 00:43:43
@@ -117,6 +117,9 @@
void gdk_event_queue_append (GdkEvent *event);
void gdk_event_button_generate (GdkEvent *event);
+void gdk_synthesize_window_state (GdkWindow *window,
+ GdkWindowState unset_flags,
+ GdkWindowState set_flags);
/*************************************
* Interfaces used by windowing code *
@@ -162,6 +165,8 @@
gint y,
gint width,
gint height);
+
+#define GDK_WINDOW_IS_MAPPED(window) ((((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_WITHDRAWN) == 0)
/* Called before processing updates for a window. This gives the windowing
* layer a chance to save the region for later use in avoiding duplicate
Index: gdk/gdkwindow.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkwindow.c,v
retrieving revision 1.108
diff -u -u -r1.108 gdkwindow.c
--- gdk/gdkwindow.c 2001/02/20 05:21:44 1.108
+++ gdk/gdkwindow.c 2001/02/24 00:43:43
@@ -188,6 +188,8 @@
window->window_type = GDK_WINDOW_CHILD;
+ window->state = GDK_WINDOW_STATE_WITHDRAWN;
+
window->impl = g_object_new (_gdk_window_impl_get_type (), NULL);
}
@@ -290,7 +292,7 @@
case GDK_WINDOW_FOREIGN:
if (!GDK_WINDOW_DESTROYED (window))
{
- private->mapped = FALSE;
+ private->state |= GDK_WINDOW_STATE_WITHDRAWN;
private->destroyed = TRUE;
_gdk_windowing_window_destroy (window, recursing, foreign_destroy);
@@ -573,12 +575,9 @@
gboolean
gdk_window_is_visible (GdkWindow *window)
{
- GdkWindowObject *private = (GdkWindowObject *)window;
-
- g_return_val_if_fail (window != NULL, FALSE);
g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
- return private->mapped;
+ return GDK_WINDOW_IS_MAPPED (window);
}
/*************************************************************
@@ -605,7 +604,7 @@
(private != (GdkWindowObject *)gdk_parent_root) &&
(GDK_WINDOW_TYPE (private) != GDK_WINDOW_FOREIGN))
{
- if (!private->mapped)
+ if (!GDK_WINDOW_IS_MAPPED (window))
return FALSE;
private = (GdkWindowObject *)private->parent;
@@ -615,6 +614,25 @@
}
/**
+ * gdk_window_get_state:
+ * @window: a #GdkWindow
+ *
+ * Gets the bitwise OR of the currently active window state flags,
+ * from the #GdkWindowState enumeration.
+ *
+ * Return value: window state bitfield
+ **/
+GdkWindowState
+gdk_window_get_state (GdkWindow *window)
+{
+ GdkWindowObject *private = (GdkWindowObject *)window;
+
+ g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
+
+ return private->state;
+}
+
+/**
* gdk_window_begin_paint_rect:
* @window: a #GdkWindow
* @rectangle: rectangle you intend to draw to
@@ -1871,7 +1889,7 @@
if (GDK_WINDOW_DESTROYED (window))
return;
- if (private->input_only || !private->mapped)
+ if (private->input_only || !GDK_WINDOW_IS_MAPPED (window))
return;
if (!rect)
@@ -1927,7 +1945,7 @@
if (GDK_WINDOW_DESTROYED (window))
return;
- if (private->input_only || !private->mapped)
+ if (private->input_only || !GDK_WINDOW_IS_MAPPED (window))
return;
visible_region = gdk_drawable_get_visible_region (window);
Index: gdk/gdkwindow.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkwindow.h,v
retrieving revision 1.15
diff -u -u -r1.15 gdkwindow.h
--- gdk/gdkwindow.h 2001/01/26 21:11:57 1.15
+++ gdk/gdkwindow.h 2001/02/24 00:43:43
@@ -199,7 +199,9 @@
guint8 window_type;
guint8 depth;
guint8 resize_count;
- guint mapped : 1;
+
+ GdkWindowState state;
+
guint guffaw_gravity : 1;
guint input_only : 1;
@@ -254,6 +256,8 @@
gint height);
void gdk_window_raise (GdkWindow *window);
void gdk_window_lower (GdkWindow *window);
+void gdk_window_focus (GdkWindow *window,
+ guint32 timestamp);
void gdk_window_set_user_data (GdkWindow *window,
gpointer user_data);
void gdk_window_set_override_redirect (GdkWindow *window,
@@ -305,6 +309,8 @@
gboolean gdk_window_is_visible (GdkWindow *window);
gboolean gdk_window_is_viewable (GdkWindow *window);
+GdkWindowState gdk_window_get_state (GdkWindow *window);
+
/* Set static bit gravity on the parent, and static
* window gravity on all children.
*/
@@ -393,7 +399,13 @@
void gdk_window_set_functions (GdkWindow *window,
GdkWMFunction functions);
GList * gdk_window_get_toplevels (void);
+
void gdk_window_iconify (GdkWindow *window);
+void gdk_window_deiconify (GdkWindow *window);
+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_register_dnd (GdkWindow *window);
Index: gdk/x11/gdkevents-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkevents-x11.c,v
retrieving revision 1.37
diff -u -u -r1.37 gdkevents-x11.c
--- gdk/x11/gdkevents-x11.c 2001/02/02 17:52:07 1.37
+++ gdk/x11/gdkevents-x11.c 2001/02/24 00:43:43
@@ -44,6 +44,8 @@
#include <X11/XKBlib.h>
#endif
+#include <X11/Xatom.h>
+
typedef struct _GdkIOClosure GdkIOClosure;
typedef struct _GdkEventPrivate GdkEventPrivate;
@@ -118,8 +120,10 @@
gdk_event_dispatch,
NULL
};
+
+static GPollFD event_poll_fd;
-GPollFD event_poll_fd;
+static Window wmspec_check_window = None;
/*********************************************
* Functions for maintaining the event queue *
@@ -260,6 +264,96 @@
client_filters = g_list_prepend (client_filters, filter);
}
+static GdkAtom wm_state_atom = 0;
+
+static void
+gdk_check_wm_state_changed (GdkWindow *window)
+{
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+ GdkAtom *atoms = NULL;
+ gulong i;
+ GdkAtom sticky_atom;
+ GdkAtom maxvert_atom;
+ GdkAtom maxhorz_atom;
+ gboolean found_sticky, found_maxvert, found_maxhorz;
+ GdkWindowState old_state;
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return;
+
+ if (wm_state_atom == 0)
+ wm_state_atom = gdk_atom_intern ("_NET_WM_STATE", FALSE);
+
+ XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
+ wm_state_atom, 0, G_MAXLONG,
+ False, XA_ATOM, &type, &format, &nitems,
+ &bytes_after, (guchar **)&atoms);
+
+ if (type == None)
+ return;
+
+ sticky_atom = gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE);
+ maxvert_atom = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE);
+ maxhorz_atom = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE);
+
+ found_sticky = FALSE;
+ found_maxvert = FALSE;
+ found_maxhorz = FALSE;
+
+ i = 0;
+ while (i < nitems)
+ {
+ if (atoms[i] == sticky_atom)
+ found_sticky = TRUE;
+ else if (atoms[i] == maxvert_atom)
+ found_maxvert = TRUE;
+ else if (atoms[i] == maxhorz_atom)
+ found_maxhorz = TRUE;
+
+ ++i;
+ }
+
+ XFree (atoms);
+
+ old_state = gdk_window_get_state (window);
+
+ if (old_state & GDK_WINDOW_STATE_STICKY)
+ {
+ if (!found_sticky)
+ gdk_synthesize_window_state (window,
+ GDK_WINDOW_STATE_STICKY,
+ 0);
+ }
+ else
+ {
+ if (found_sticky)
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_WINDOW_STATE_STICKY);
+ }
+
+ /* Our "maximized" means both vertical and horizontal; if only one,
+ * we don't expose that via GDK
+ */
+ if (old_state & GDK_WINDOW_STATE_MAXIMIZED)
+ {
+ if (!(found_maxvert && found_maxhorz))
+ gdk_synthesize_window_state (window,
+ GDK_WINDOW_STATE_MAXIMIZED,
+ 0);
+ }
+ else
+ {
+ if (found_maxvert && found_maxhorz)
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_WINDOW_STATE_MAXIMIZED);
+ }
+}
+
static gint
gdk_event_translate (GdkEvent *event,
XEvent *xevent,
@@ -306,6 +400,19 @@
if (window != NULL)
gdk_window_ref (window);
+
+ if (wmspec_check_window != None &&
+ xevent->xany.window == wmspec_check_window)
+ {
+ if (xevent->type == DestroyNotify)
+ wmspec_check_window = None;
+
+ /* Eat events on this window unless someone had wrapped
+ * it as a foreign window
+ */
+ if (window == NULL)
+ return FALSE;
+ }
event->any.window = window;
event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
@@ -948,7 +1055,17 @@
xevent->xmap.window));
event->any.type = GDK_UNMAP;
- event->any.window = window;
+ event->any.window = window;
+
+ /* If we are shown (not withdrawn) and get an unmap, it means we
+ * were iconified in the X sense. If we are withdrawn, and get
+ * an unmap, it means we hid the window ourselves, so we
+ * will have already flipped the iconified bit off.
+ */
+ if (GDK_WINDOW_IS_MAPPED (window))
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_WINDOW_STATE_ICONIFIED);
if (gdk_xgrab_window == window_private)
gdk_xgrab_window = NULL;
@@ -962,6 +1079,12 @@
event->any.type = GDK_MAP;
event->any.window = window;
+
+ /* Unset iconified if it was set */
+ if (((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_ICONIFIED)
+ gdk_synthesize_window_state (window,
+ GDK_WINDOW_STATE_ICONIFIED,
+ 0);
break;
@@ -1064,6 +1187,15 @@
event->property.atom = xevent->xproperty.atom;
event->property.time = xevent->xproperty.time;
event->property.state = xevent->xproperty.state;
+
+ if (wm_state_atom == 0)
+ wm_state_atom = gdk_atom_intern ("_NET_WM_STATE", FALSE);
+
+ if (event->property.atom == wm_state_atom)
+ {
+ /* If window state changed, then synthesize those events. */
+ gdk_check_wm_state_changed (event->property.window);
+ }
break;
@@ -1585,4 +1717,89 @@
return xevent.xproperty.time;
}
+
+
+gboolean
+_gdk_wmspec_supported (GdkAtom property)
+{
+ static GdkAtom wmspec_check_atom = 0;
+ static GdkAtom wmspec_supported_atom = 0;
+ static GdkAtom *atoms = NULL;
+ static gulong n_atoms = 0;
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+ Window xwindow;
+ gulong i;
+
+ if (wmspec_check_window != None)
+ {
+ if (atoms == NULL)
+ return FALSE;
+
+ i = 0;
+ while (i < n_atoms)
+ {
+ if (atoms[i] == property)
+ return TRUE;
+
+ ++i;
+ }
+
+ return FALSE;
+ }
+
+ if (atoms)
+ XFree (atoms);
+
+ atoms = NULL;
+ 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.
+ */
+
+ if (wmspec_check_atom == 0)
+ wmspec_check_atom = gdk_atom_intern ("_NET_SUPPORTING_WM_CHECK", FALSE);
+
+ if (wmspec_supported_atom == 0)
+ wmspec_supported_atom = gdk_atom_intern ("_NET_SUPPORTED", FALSE);
+
+ XGetWindowProperty (gdk_display, gdk_root_window,
+ wmspec_check_atom, 0, G_MAXLONG,
+ False, XA_WINDOW, &type, &format, &nitems,
+ &bytes_after, (guchar **)&xwindow);
+
+ if (type == None)
+ return FALSE;
+
+ gdk_error_trap_push ();
+
+ /* Find out if this WM goes away, so we can reset everything. */
+ XSelectInput (gdk_display, xwindow,
+ StructureNotifyMask);
+
+ if (gdk_error_trap_pop ())
+ return FALSE;
+
+ gdk_error_trap_push ();
+
+ XGetWindowProperty (gdk_display, xwindow,
+ wmspec_check_atom, 0, G_MAXLONG,
+ False, XA_ATOM, &type, &format, &n_atoms,
+ &bytes_after, (guchar **)&atoms);
+
+ if (gdk_error_trap_pop ())
+ return FALSE;
+
+ wmspec_check_window = xwindow;
+
+ /* since wmspec_check_window != None this isn't infinite. ;-) */
+ return _gdk_wmspec_supported (property);
+}
+
+
Index: gdk/x11/gdkgeometry-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkgeometry-x11.c,v
retrieving revision 1.7
diff -u -u -r1.7 gdkgeometry-x11.c
--- gdk/x11/gdkgeometry-x11.c 2001/01/12 23:23:39 1.7
+++ gdk/x11/gdkgeometry-x11.c 2001/02/24 00:43:43
@@ -28,6 +28,7 @@
#include "gdkprivate-x11.h"
#include "gdkx.h"
#include "gdkregion.h"
+#include "gdkinternals.h"
typedef struct _GdkWindowQueueItem GdkWindowQueueItem;
typedef struct _GdkWindowParentPos GdkWindowParentPos;
@@ -332,7 +333,7 @@
if (impl->position_info.no_bg)
gdk_window_tmp_reset_bg (window);
- if (!impl->position_info.mapped && new_info.mapped && obj->mapped)
+ if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj))
XMapWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
impl->position_info = new_info;
@@ -378,7 +379,7 @@
if (impl->position_info.no_bg)
gdk_window_tmp_reset_bg (window);
- if (!impl->position_info.mapped && new_info.mapped && obj->mapped)
+ if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj))
XMapWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
impl->position_info = new_info;
@@ -651,7 +652,7 @@
new_info.x, new_info.y, new_info.width, new_info.height);
}
- if (!impl->position_info.mapped && new_info.mapped && obj->mapped)
+ if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj))
XMapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
if (impl->position_info.no_bg)
Index: gdk/x11/gdkmain-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkmain-x11.c,v
retrieving revision 1.124
diff -u -u -r1.124 gdkmain-x11.c
--- gdk/x11/gdkmain-x11.c 2001/02/19 20:38:15 1.124
+++ gdk/x11/gdkmain-x11.c 2001/02/24 00:43:43
@@ -737,4 +737,3 @@
return result && !gdk_error_code;
}
-
Index: gdk/x11/gdkprivate-x11.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkprivate-x11.h,v
retrieving revision 1.8
diff -u -u -r1.8 gdkprivate-x11.h
--- gdk/x11/gdkprivate-x11.h 2000/12/15 01:46:40 1.8
+++ gdk/x11/gdkprivate-x11.h 2001/02/24 00:43:43
@@ -86,6 +86,8 @@
void _gdk_selection_window_destroyed (GdkWindow *window);
gboolean _gdk_selection_filter_clear_event (XSelectionClearEvent *event);
+gboolean _gdk_wmspec_supported (GdkAtom property);
+
extern GdkDrawableClass _gdk_x11_drawable_class;
extern gboolean gdk_use_xshm;
extern Atom gdk_wm_delete_window;
Index: gdk/x11/gdkwindow-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkwindow-x11.c,v
retrieving revision 1.105
diff -u -u -r1.105 gdkwindow-x11.c
--- gdk/x11/gdkwindow-x11.c 2001/02/03 16:31:35 1.105
+++ gdk/x11/gdkwindow-x11.c 2001/02/24 00:43:43
@@ -635,7 +635,12 @@
impl->height = attrs.height;
private->window_type = GDK_WINDOW_FOREIGN;
private->destroyed = FALSE;
- private->mapped = (attrs.map_state != IsUnmapped);
+
+ if (attrs.map_state == IsUnmapped)
+ private->state = GDK_WINDOW_STATE_WITHDRAWN;
+ else
+ private->state = 0;
+
private->depth = attrs.depth;
gdk_drawable_ref (window);
@@ -709,6 +714,63 @@
gdk_drawable_unref (window);
}
+static void
+set_initial_hints (GdkWindow *window)
+{
+ GdkWindowObject *private;
+ GdkAtom atoms[5];
+ gint i;
+
+ private = (GdkWindowObject*) window;
+
+ if (private->state & GDK_WINDOW_STATE_ICONIFIED)
+ {
+ XWMHints *wm_hints;
+
+ wm_hints = XGetWMHints (GDK_WINDOW_XDISPLAY (window),
+ GDK_WINDOW_XID (window));
+ if (!wm_hints)
+ wm_hints = XAllocWMHints ();
+
+ wm_hints->flags |= StateHint;
+ wm_hints->initial_state = IconicState;
+
+ XSetWMHints (GDK_WINDOW_XDISPLAY (window),
+ GDK_WINDOW_XID (window), wm_hints);
+ XFree (wm_hints);
+ }
+
+ /* We set the spec hints regardless of whether the spec is supported,
+ * since it can't hurt and it's kind of expensive to check whether
+ * it's supported.
+ */
+
+ i = 0;
+
+ if (private->state & GDK_WINDOW_STATE_MAXIMIZED)
+ {
+ atoms[i] = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE);
+ ++i;
+ atoms[i] = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE);
+ ++i;
+ }
+
+ if (private->state & GDK_WINDOW_STATE_STICKY)
+ {
+ atoms[i] = gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE);
+ ++i;
+ }
+
+ if (i > 0)
+ {
+ XChangeProperty (GDK_WINDOW_XDISPLAY (window),
+ GDK_WINDOW_XID (window),
+ gdk_atom_intern ("_NET_WM_STATE", FALSE),
+ XA_ATOM, 32, PropModeReplace,
+ (guchar*) atoms, i);
+ }
+}
+
void
gdk_window_show (GdkWindow *window)
{
@@ -719,13 +781,23 @@
private = (GdkWindowObject*) window;
if (!private->destroyed)
{
- private->mapped = TRUE;
XRaiseWindow (GDK_WINDOW_XDISPLAY (window),
GDK_WINDOW_XID (window));
+
+ if (!GDK_WINDOW_IS_MAPPED (window))
+ {
+ set_initial_hints (window);
+
+ gdk_synthesize_window_state (window,
+ GDK_WINDOW_STATE_WITHDRAWN,
+ 0);
+ }
+ g_assert (GDK_WINDOW_IS_MAPPED (window));
+
if (GDK_WINDOW_IMPL_X11 (private->impl)->position_info.mapped)
- XMapWindow (GDK_WINDOW_XDISPLAY (window),
- GDK_WINDOW_XID (window));
+ XMapWindow (GDK_WINDOW_XDISPLAY (window),
+ GDK_WINDOW_XID (window));
}
}
@@ -737,14 +809,36 @@
g_return_if_fail (window != NULL);
private = (GdkWindowObject*) window;
+
+ /* You can't simply unmap toplevel windows. */
+ switch (private->window_type)
+ {
+ case GDK_WINDOW_TOPLEVEL:
+ case GDK_WINDOW_DIALOG:
+ case GDK_WINDOW_TEMP: /* ? */
+ gdk_window_withdraw (window);
+ return;
+ break;
+
+ case GDK_WINDOW_FOREIGN:
+ case GDK_WINDOW_ROOT:
+ case GDK_WINDOW_CHILD:
+ break;
+ }
+
if (!private->destroyed)
{
- private->mapped = FALSE;
+ if (GDK_WINDOW_IS_MAPPED (window))
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_WINDOW_STATE_WITHDRAWN);
+ g_assert (!GDK_WINDOW_IS_MAPPED (window));
+
_gdk_window_clear_update_area (window);
XUnmapWindow (GDK_WINDOW_XDISPLAY (window),
- GDK_WINDOW_XID (window));
+ GDK_WINDOW_XID (window));
}
}
@@ -757,8 +851,17 @@
private = (GdkWindowObject*) window;
if (!private->destroyed)
- XWithdrawWindow (GDK_WINDOW_XDISPLAY (window),
- GDK_WINDOW_XID (window), 0);
+ {
+ if (GDK_WINDOW_IS_MAPPED (window))
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_WINDOW_STATE_WITHDRAWN);
+
+ g_assert (!GDK_WINDOW_IS_MAPPED (window));
+
+ XWithdrawWindow (GDK_WINDOW_XDISPLAY (window),
+ GDK_WINDOW_XID (window), 0);
+ }
}
void
@@ -945,6 +1048,41 @@
}
void
+gdk_window_focus (GdkWindow *window,
+ guint32 timestamp)
+{
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return;
+
+ if (_gdk_wmspec_supported (gdk_atom_intern ("_NET_ACTIVE_WINDOW", FALSE)))
+ {
+ XEvent xev;
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.window = GDK_WINDOW_XWINDOW (window);
+ xev.xclient.display = gdk_display;
+ xev.xclient.message_type = gdk_atom_intern ("_NET_ACTIVE_WINDOW", FALSE);
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = 0;
+
+ XSendEvent (gdk_display, gdk_root_window, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+ }
+ else
+ {
+ XSetInputFocus (GDK_DISPLAY (),
+ GDK_WINDOW_XWINDOW (window),
+ RevertToNone,
+ timestamp);
+ }
+}
+
+void
gdk_window_set_hints (GdkWindow *window,
gint x,
gint y,
@@ -1807,12 +1945,13 @@
GUINT_TO_POINTER (TRUE));
set_text_property (window, gdk_atom_intern ("WM_ICON_NAME", FALSE), name);
-}
+}
void
gdk_window_iconify (GdkWindow *window)
{
Display *display;
+ GdkWindowObject *private;
g_return_if_fail (window != NULL);
g_return_if_fail (GDK_IS_WINDOW (window));
@@ -1821,7 +1960,229 @@
return;
display = GDK_WINDOW_XDISPLAY (window);
- XIconifyWindow (display, GDK_WINDOW_XWINDOW (window), DefaultScreen (display));
+
+ private = (GdkWindowObject*) window;
+
+ if (GDK_WINDOW_IS_MAPPED (window))
+ {
+ XIconifyWindow (display, GDK_WINDOW_XWINDOW (window), DefaultScreen (display));
+
+ }
+ else
+ {
+ /* Flip our client side flag, the real work happens on map. */
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_WINDOW_STATE_ICONIFIED);
+ }
+}
+
+void
+gdk_window_deiconify (GdkWindow *window)
+{
+ Display *display;
+ GdkWindowObject *private;
+
+ g_return_if_fail (window != NULL);
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return;
+
+ display = GDK_WINDOW_XDISPLAY (window);
+
+ private = (GdkWindowObject*) window;
+
+ if (GDK_WINDOW_IS_MAPPED (window))
+ {
+ gdk_window_show (window);
+ }
+ else
+ {
+ /* Flip our client side flag, the real work happens on map. */
+ gdk_synthesize_window_state (window,
+ GDK_WINDOW_STATE_ICONIFIED,
+ 0);
+ }
+}
+
+void
+gdk_window_stick (GdkWindow *window)
+{
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return;
+
+ if (GDK_WINDOW_IS_MAPPED (window))
+ {
+ if (_gdk_wmspec_supported (gdk_atom_intern ("_NET_WM_STATE", FALSE)))
+ {
+ XEvent xev;
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.window = GDK_WINDOW_XWINDOW (window);
+ xev.xclient.display = gdk_display;
+ xev.xclient.message_type = gdk_atom_intern ("_NET_WM_STATE", FALSE);
+ xev.xclient.format = 32;
+
+ xev.xclient.data.l[0] = gdk_atom_intern ("_NET_WM_STATE_ADD", FALSE);
+ xev.xclient.data.l[1] = gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE);
+ xev.xclient.data.l[2] = 0;
+
+ XSendEvent (gdk_display, gdk_root_window, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+ }
+ else
+ {
+ /* Nothing we can do to emulate this without the WM spec,
+ * I don't think.
+ */
+ }
+ }
+ else
+ {
+ /* Flip our client side flag, the real work happens on map. */
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_WINDOW_STATE_STICKY);
+ }
+}
+
+void
+gdk_window_unstick (GdkWindow *window)
+{
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return;
+
+ if (GDK_WINDOW_IS_MAPPED (window))
+ {
+ if (_gdk_wmspec_supported (gdk_atom_intern ("_NET_WM_STATE", FALSE)))
+ {
+ XEvent xev;
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.window = GDK_WINDOW_XWINDOW (window);
+ xev.xclient.display = gdk_display;
+ xev.xclient.message_type = gdk_atom_intern ("_NET_WM_STATE", FALSE);
+ xev.xclient.format = 32;
+
+ xev.xclient.data.l[0] = gdk_atom_intern ("_NET_WM_STATE_REMOVE", FALSE);
+ xev.xclient.data.l[1] = gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE);
+ xev.xclient.data.l[2] = 0;
+
+ XSendEvent (gdk_display, gdk_root_window, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+ }
+ else
+ {
+ /* Nothing we can do to emulate this without the WM spec,
+ * I don't think.
+ */
+ }
+ }
+ else
+ {
+ /* Flip our client side flag, the real work happens on map. */
+ gdk_synthesize_window_state (window,
+ GDK_WINDOW_STATE_STICKY,
+ 0);
+
+ }
+}
+
+void
+gdk_window_maximize (GdkWindow *window)
+{
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return;
+
+ if (GDK_WINDOW_IS_MAPPED (window))
+ {
+ if (_gdk_wmspec_supported (gdk_atom_intern ("_NET_WM_STATE", FALSE)))
+ {
+ XEvent xev;
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.window = GDK_WINDOW_XWINDOW (window);
+ xev.xclient.display = gdk_display;
+ xev.xclient.message_type = gdk_atom_intern ("_NET_WM_STATE", FALSE);
+ xev.xclient.format = 32;
+
+ xev.xclient.data.l[0] = gdk_atom_intern ("_NET_WM_STATE_ADD", FALSE);
+ xev.xclient.data.l[1] = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE);
+ xev.xclient.data.l[2] = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE);
+
+ XSendEvent (gdk_display, gdk_root_window, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+ }
+ else
+ {
+ /* FIXME try to emulate maximization somehow? */
+ }
+ }
+ else
+ {
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_WINDOW_STATE_MAXIMIZED);
+ }
+}
+
+void
+gdk_window_unmaximize (GdkWindow *window)
+{
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return;
+
+ if (GDK_WINDOW_IS_MAPPED (window))
+ {
+ if (_gdk_wmspec_supported (gdk_atom_intern ("_NET_WM_STATE", FALSE)))
+ {
+ XEvent xev;
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.window = GDK_WINDOW_XWINDOW (window);
+ xev.xclient.display = gdk_display;
+ xev.xclient.message_type = gdk_atom_intern ("_NET_WM_STATE", FALSE);
+ xev.xclient.format = 32;
+
+ xev.xclient.data.l[0] = gdk_atom_intern ("_NET_WM_STATE_REMOVE", FALSE);
+ xev.xclient.data.l[1] = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE);
+ xev.xclient.data.l[2] = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE);
+
+ XSendEvent (gdk_display, gdk_root_window, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+ }
+ else
+ {
+ /* FIXME try to emulate maximization somehow? */
+ }
+ }
+ else
+ {
+ gdk_synthesize_window_state (window,
+ GDK_WINDOW_STATE_MAXIMIZED,
+ 0);
+ }
}
void
Index: gtk/gtkmain.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmain.c,v
retrieving revision 1.150
diff -u -u -r1.150 gtkmain.c
--- gtk/gtkmain.c 2001/02/19 21:54:03 1.150
+++ gtk/gtkmain.c 2001/02/24 00:43:43
@@ -888,6 +888,7 @@
case GDK_SELECTION_NOTIFY:
case GDK_CLIENT_EVENT:
case GDK_VISIBILITY_NOTIFY:
+ case GDK_WINDOW_STATE:
gtk_widget_event (event_widget, event);
break;
Index: gtk/gtkwidget.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.c,v
retrieving revision 1.185
diff -u -u -r1.185 gtkwidget.c
--- gtk/gtkwidget.c 2001/02/03 01:09:40 1.185
+++ gtk/gtkwidget.c 2001/02/24 00:43:43
@@ -99,6 +99,7 @@
CLIENT_EVENT,
NO_EXPOSE_EVENT,
VISIBILITY_NOTIFY_EVENT,
+ WINDOW_STATE_EVENT,
DEBUG_MSG,
LAST_SIGNAL
};
@@ -314,6 +315,7 @@
klass->focus_out_event = NULL;
klass->map_event = NULL;
klass->unmap_event = NULL;
+ klass->window_state_event = NULL;
klass->property_notify_event = gtk_selection_property_notify;
klass->selection_clear_event = gtk_selection_clear;
klass->selection_request_event = gtk_selection_request;
@@ -775,6 +777,14 @@
gtk_marshal_BOOLEAN__POINTER,
GTK_TYPE_BOOL, 1,
GTK_TYPE_GDK_EVENT);
+ widget_signals[WINDOW_STATE_EVENT] =
+ gtk_signal_new ("window_state_event",
+ GTK_RUN_LAST,
+ GTK_CLASS_TYPE (object_class),
+ GTK_SIGNAL_OFFSET (GtkWidgetClass, no_expose_event),
+ gtk_marshal_BOOLEAN__POINTER,
+ GTK_TYPE_BOOL, 1,
+ GTK_TYPE_GDK_EVENT);
widget_signals[DEBUG_MSG] =
gtk_signal_new ("debug_msg",
GTK_RUN_LAST | GTK_RUN_ACTION,
@@ -2336,6 +2346,9 @@
break;
case GDK_UNMAP:
signal_num = UNMAP_EVENT;
+ break;
+ case GDK_WINDOW_STATE:
+ signal_num = WINDOW_STATE_EVENT;
break;
case GDK_PROPERTY_NOTIFY:
signal_num = PROPERTY_NOTIFY_EVENT;
Index: gtk/gtkwidget.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.h,v
retrieving revision 1.89
diff -u -u -r1.89 gtkwidget.h
--- gtk/gtkwidget.h 2001/02/03 01:09:40 1.89
+++ gtk/gtkwidget.h 2001/02/24 00:43:43
@@ -325,7 +325,9 @@
GdkEventClient *event);
gint (* no_expose_event) (GtkWidget *widget,
GdkEventAny *event);
-
+ gint (* window_state_event) (GtkWidget *widget,
+ GdkEventWindowState *event);
+
/* selection */
void (* selection_get) (GtkWidget *widget,
GtkSelectionData *selection_data,
Index: gtk/gtkwindow.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.c,v
retrieving revision 1.97
diff -u -u -r1.97 gtkwindow.c
--- gtk/gtkwindow.c 2001/02/03 01:09:40 1.97
+++ gtk/gtkwindow.c 2001/02/24 00:43:43
@@ -1247,7 +1247,8 @@
gtk_window_map (GtkWidget *widget)
{
GtkWindow *window;
-
+ GdkWindow *toplevel;
+
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_WINDOW (widget));
@@ -1260,7 +1261,28 @@
!GTK_WIDGET_MAPPED (window->bin.child))
gtk_widget_map (window->bin.child);
+ if (window->frame)
+ toplevel = window->frame;
+ else
+ toplevel = widget->window;
+
+ if (window->maximize_initially)
+ gdk_window_maximize (toplevel);
+ else
+ gdk_window_unmaximize (toplevel);
+
+ if (window->stick_initially)
+ gdk_window_stick (toplevel);
+ else
+ gdk_window_unstick (toplevel);
+
+ if (window->iconify_initially)
+ gdk_window_iconify (toplevel);
+ else
+ gdk_window_deiconify (toplevel);
+
gdk_window_show (widget->window);
+
if (window->frame)
gdk_window_show (window->frame);
}
@@ -1398,7 +1420,8 @@
gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
if (window->frame)
gtk_style_set_background (widget->style, window->frame, GTK_STATE_NORMAL);
-
+
+ /* This is a bad hack to set the window background. */
gtk_window_paint (widget, NULL);
if (window->transient_parent &&
@@ -1407,7 +1430,6 @@
GTK_WIDGET (window->transient_parent)->window);
}
-
static void
gtk_window_unrealize (GtkWidget *widget)
{
@@ -2786,3 +2808,267 @@
}
+
+/**
+ * gtk_window_present:
+ * @window: a #GtkWindow
+ *
+ * Presents a window to the user. This may mean raising the window
+ * in the stacking order, deiconifying it, moving it to the current
+ * desktop, and/or giving it the keyboard focus, possibly dependent
+ * on the user's platform, window manager, and preferences.
+ *
+ * If @window is hidden, this function calls gtk_widget_show()
+ * as well.
+ *
+ * This function should be used when the user tries to open a window
+ * that's already open. Say for example the preferences dialog is
+ * currently open, and the user chooses Preferences from the menu
+ * a second time; use gtk_window_present() to move the already-open dialog
+ * where the user can see it.
+ *
+ **/
+void
+gtk_window_present (GtkWindow *window)
+{
+ GtkWidget *widget;
+
+ g_return_if_fail (GTK_IS_WINDOW (window));
+
+ widget = GTK_WIDGET (window);
+
+ if (widget->window != NULL)
+ {
+ gdk_window_show (widget->window);
+ gdk_window_focus (widget->window,
+ gtk_get_current_event_time ());
+
+
+ /* FIXME add desktop-moving stuff from WM spec */
+ }
+
+ gtk_widget_show (widget);
+}
+
+/**
+ * gtk_window_iconify:
+ * @window: a #GtkWindow
+ *
+ * Asks to iconify @window. Note that you shouldn't assume the window
+ * is definitely iconified afterward, because other entities (e.g. the
+ * user or window manager) could deiconify it again, or there may not
+ * be a window manager in which case iconification isn't possible,
+ * etc. But normally the window will end up iconified. Just don't write
+ * code that crashes if not.
+ *
+ * It's permitted to call this function before showing a window,
+ * in which case the window will be iconified before it ever appears
+ * onscreen.
+ *
+ * You can track iconification via the "window_state_event" signal
+ * on #GtkWidget.
+ *
+ **/
+void
+gtk_window_iconify (GtkWindow *window)
+{
+ GtkWidget *widget;
+ GdkWindow *toplevel;
+
+ g_return_if_fail (GTK_IS_WINDOW (window));
+
+ widget = GTK_WIDGET (window);
+
+ window->iconify_initially = TRUE;
+
+ if (window->frame)
+ toplevel = window->frame;
+ else
+ toplevel = widget->window;
+
+ if (toplevel != NULL)
+ gdk_window_iconify (toplevel);
+}
+
+/**
+ * gtk_window_deiconify:
+ * @window: a #GtkWindow
+ *
+ * Asks to deiconify @window. Note that you shouldn't assume the
+ * window is definitely deiconified afterward, because other entities
+ * (e.g. the user or window manager) could iconify it again before
+ * your code which assumes deiconification gets to run.
+ *
+ * You can track iconification via the "window_state_event" signal
+ * on #GtkWidget.
+ **/
+void
+gtk_window_deiconify (GtkWindow *window)
+{
+ GtkWidget *widget;
+ GdkWindow *toplevel;
+
+ g_return_if_fail (GTK_IS_WINDOW (window));
+
+ widget = GTK_WIDGET (window);
+
+ window->iconify_initially = FALSE;
+
+ if (window->frame)
+ toplevel = window->frame;
+ else
+ toplevel = widget->window;
+
+ if (toplevel != NULL)
+ gdk_window_deiconify (toplevel);
+}
+
+/**
+ * gtk_window_stick:
+ * @window: a #GtkWindow
+ *
+ * Asks to stick @window, which means that it will appear on all user
+ * desktops. Note that you shouldn't assume the window is definitely
+ * stuck afterward, because other entities (e.g. the user or window
+ * manager) could unstick it again, and some window managers do not
+ * support sticking windows. But normally the window will end up
+ * stuck. Just don't write code that crashes if not.
+ *
+ * It's permitted to call this function before showing a window.
+ *
+ * You can track stickiness via the "window_state_event" signal
+ * on #GtkWidget.
+ *
+ **/
+void
+gtk_window_stick (GtkWindow *window)
+{
+ GtkWidget *widget;
+ GdkWindow *toplevel;
+
+ g_return_if_fail (GTK_IS_WINDOW (window));
+
+ widget = GTK_WIDGET (window);
+
+ window->stick_initially = TRUE;
+
+ if (window->frame)
+ toplevel = window->frame;
+ else
+ toplevel = widget->window;
+
+ if (toplevel != NULL)
+ gdk_window_stick (toplevel);
+}
+
+/**
+ * gtk_window_unstick:
+ * @window: a #GtkWindow
+ *
+ * Asks to unstick @window, which means that it will appear on only
+ * one of the user's desktops. Note that you shouldn't assume the
+ * window is definitely unstuck afterward, because other entities
+ * (e.g. the user or window manager) could stick it again. But
+ * normally the window will end up stuck. Just don't write code that
+ * crashes if not.
+ *
+ * You can track stickiness via the "window_state_event" signal
+ * on #GtkWidget.
+ *
+ **/
+void
+gtk_window_unstick (GtkWindow *window)
+{
+ GtkWidget *widget;
+ GdkWindow *toplevel;
+
+ g_return_if_fail (GTK_IS_WINDOW (window));
+
+ widget = GTK_WIDGET (window);
+
+ window->stick_initially = FALSE;
+
+ if (window->frame)
+ toplevel = window->frame;
+ else
+ toplevel = widget->window;
+
+ if (toplevel != NULL)
+ gdk_window_unstick (toplevel);
+}
+
+/**
+ * gtk_window_maximize:
+ * @window: a #GtkWindow
+ *
+ * Asks to maximize @window, so that it becomes full-screen. Note that
+ * you shouldn't assume the window is definitely maximized afterward,
+ * because other entities (e.g. the user or window manager) could
+ * unmaximize it again, and not all window managers support
+ * maximization. But normally the window will end up maximized. Just
+ * don't write code that crashes if not.
+ *
+ * It's permitted to call this function before showing a window,
+ * in which case the window will be maximized when it appears onscreen
+ * initially.
+ *
+ * You can track maximization via the "window_state_event" signal
+ * on #GtkWidget.
+ *
+ **/
+void
+gtk_window_maximize (GtkWindow *window)
+{
+ GtkWidget *widget;
+ GdkWindow *toplevel;
+
+ g_return_if_fail (GTK_IS_WINDOW (window));
+
+ widget = GTK_WIDGET (window);
+
+ window->maximize_initially = TRUE;
+
+ if (window->frame)
+ toplevel = window->frame;
+ else
+ toplevel = widget->window;
+
+ if (toplevel != NULL)
+ gdk_window_maximize (toplevel);
+}
+
+/**
+ * gtk_window_unmaximize:
+ * @window: a #GtkWindow
+ *
+ * Asks to unmaximize @window, so that it becomes full-screen. Note
+ * that you shouldn't assume the window is definitely unmaximized
+ * afterward, because other entities (e.g. the user or window manager)
+ * could maximize it again, and not all window managers honor requests
+ * to unmaximize. But normally the window will end up unmaximized. Just
+ * don't write code that crashes if not.
+ *
+ * You can track maximization via the "window_state_event" signal
+ * on #GtkWidget.
+ *
+ **/
+void
+gtk_window_unmaximize (GtkWindow *window)
+{
+ GtkWidget *widget;
+ GdkWindow *toplevel;
+
+ g_return_if_fail (GTK_IS_WINDOW (window));
+
+ widget = GTK_WIDGET (window);
+
+ window->maximize_initially = FALSE;
+
+ if (window->frame)
+ toplevel = window->frame;
+ else
+ toplevel = widget->window;
+
+ if (toplevel != NULL)
+ gdk_window_unmaximize (toplevel);
+}
Index: gtk/gtkwindow.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.h,v
retrieving revision 1.25
diff -u -u -r1.25 gtkwindow.h
--- gtk/gtkwindow.h 2001/01/08 17:04:17 1.25
+++ gtk/gtkwindow.h 2001/02/24 00:43:43
@@ -85,6 +85,11 @@
guint has_frame : 1;
+ /* gtk_window_iconify() called before realization */
+ guint iconify_initially : 1;
+ guint stick_initially : 1;
+ guint maximize_initially : 1;
+
guint frame_left;
guint frame_top;
guint frame_right;
@@ -152,6 +157,14 @@
/* Get the "built-in" accel group (convenience thing) */
GtkAccelGroup* gtk_window_get_default_accel_group (GtkWindow *window);
+
+void gtk_window_present (GtkWindow *window);
+void gtk_window_iconify (GtkWindow *window);
+void gtk_window_deiconify (GtkWindow *window);
+void gtk_window_stick (GtkWindow *window);
+void gtk_window_unstick (GtkWindow *window);
+void gtk_window_maximize (GtkWindow *window);
+void gtk_window_unmaximize (GtkWindow *window);
/* --- internal functions --- */
Index: gtk/testgtk.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/testgtk.c,v
retrieving revision 1.220
diff -u -u -r1.220 testgtk.c
--- gtk/testgtk.c 2001/02/21 19:59:22 1.220
+++ gtk/testgtk.c 2001/02/24 00:43:43
@@ -7663,6 +7663,199 @@
gtk_widget_destroy (window);
}
+
+/*
+ * Window state tracking
+ */
+
+static gint
+window_state_callback (GtkWidget *widget,
+ GdkEventWindowState *event,
+ gpointer data)
+{
+ GtkWidget *label = data;
+ gchar *msg;
+
+ msg = g_strconcat (GTK_WINDOW (widget)->title, ": ",
+ (event->current & GDK_WINDOW_STATE_WITHDRAWN) ?
+ "withdrawn" : "not withdrawn", ", ",
+ (event->current & GDK_WINDOW_STATE_ICONIFIED) ?
+ "iconified" : "not iconified", ", ",
+ (event->current & GDK_WINDOW_STATE_STICKY) ?
+ "sticky" : "not sticky", ", ",
+ (event->current & GDK_WINDOW_STATE_MAXIMIZED) ?
+ "maximized" : "not maximized",
+ NULL);
+
+ gtk_label_set_text (GTK_LABEL (label), msg);
+
+ g_free (msg);
+
+ return FALSE;
+}
+
+static GtkWidget*
+tracking_label (GtkWidget *window)
+{
+ GtkWidget *label;
+ GtkWidget *hbox;
+ GtkWidget *button;
+
+ hbox = gtk_hbox_new (FALSE, 5);
+
+ gtk_signal_connect_object (GTK_OBJECT (hbox),
+ "destroy",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy),
+ GTK_OBJECT (window));
+
+ label = gtk_label_new ("<no window state events received>");
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ gtk_signal_connect (GTK_OBJECT (window),
+ "window_state_event",
+ GTK_SIGNAL_FUNC (window_state_callback),
+ label);
+
+ button = gtk_button_new_with_label ("Deiconify");
+ gtk_signal_connect_object (GTK_WIDGET (button),
+ "clicked",
+ GTK_SIGNAL_FUNC (gtk_window_deiconify),
+ GTK_OBJECT (window));
+ gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+
+ button = gtk_button_new_with_label ("Iconify");
+ gtk_signal_connect_object (GTK_WIDGET (button),
+ "clicked",
+ 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 ("Present");
+ gtk_signal_connect_object (GTK_WIDGET (button),
+ "clicked",
+ GTK_SIGNAL_FUNC (gtk_window_present),
+ GTK_OBJECT (window));
+ gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+
+ button = gtk_button_new_with_label ("Show");
+ gtk_signal_connect_object (GTK_WIDGET (button),
+ "clicked",
+ GTK_SIGNAL_FUNC (gtk_widget_show),
+ GTK_OBJECT (window));
+ gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+
+ gtk_widget_show_all (hbox);
+
+ return hbox;
+}
+
+static GtkWidget*
+get_state_controls (GtkWidget *window)
+{
+ GtkWidget *vbox;
+ GtkWidget *button;
+
+ vbox = gtk_vbox_new (FALSE, 0);
+
+ button = gtk_button_new_with_label ("Stick");
+ gtk_signal_connect_object (GTK_WIDGET (button),
+ "clicked",
+ GTK_SIGNAL_FUNC (gtk_window_stick),
+ GTK_OBJECT (window));
+ gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+
+ button = gtk_button_new_with_label ("Unstick");
+ gtk_signal_connect_object (GTK_WIDGET (button),
+ "clicked",
+ GTK_SIGNAL_FUNC (gtk_window_unstick),
+ GTK_OBJECT (window));
+ gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+
+ button = gtk_button_new_with_label ("Maximize");
+ gtk_signal_connect_object (GTK_WIDGET (button),
+ "clicked",
+ GTK_SIGNAL_FUNC (gtk_window_maximize),
+ GTK_OBJECT (window));
+ gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+
+ button = gtk_button_new_with_label ("Unmaximize");
+ gtk_signal_connect_object (GTK_WIDGET (button),
+ "clicked",
+ GTK_SIGNAL_FUNC (gtk_window_unmaximize),
+ GTK_OBJECT (window));
+ gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+
+ button = gtk_button_new_with_label ("Iconify");
+ gtk_signal_connect_object (GTK_WIDGET (button),
+ "clicked",
+ GTK_SIGNAL_FUNC (gtk_window_iconify),
+ 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_WIDGET (button),
+ "clicked",
+ GTK_SIGNAL_FUNC (gtk_widget_hide),
+ GTK_OBJECT (window));
+ gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+
+ gtk_widget_show_all (vbox);
+
+ return vbox;
+}
+
+void
+create_window_states (void)
+{
+ static GtkWidget *window = NULL;
+ GtkWidget *label;
+ GtkWidget *box1;
+ GtkWidget *iconified;
+ GtkWidget *normal;
+ GtkWidget *controls;
+
+ if (!window)
+ {
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+ &window);
+
+ gtk_window_set_title (GTK_WINDOW (window), "Window states");
+
+ box1 = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (window), box1);
+
+ iconified = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_iconify (iconified);
+ gtk_window_set_title (GTK_WINDOW (iconified), "Iconified initially");
+ controls = get_state_controls (iconified);
+ gtk_container_add (GTK_CONTAINER (iconified), controls);
+
+ normal = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (normal), "Deiconified initially");
+ controls = get_state_controls (normal);
+ gtk_container_add (GTK_CONTAINER (normal), controls);
+
+ label = tracking_label (iconified);
+ gtk_container_add (GTK_CONTAINER (box1), label);
+
+ label = tracking_label (normal);
+ gtk_container_add (GTK_CONTAINER (box1), label);
+
+ gtk_widget_show_all (iconified);
+ gtk_widget_show_all (normal);
+ gtk_widget_show_all (box1);
+ }
+
+ if (!GTK_WIDGET_VISIBLE (window))
+ gtk_widget_show (window);
+ else
+ gtk_widget_destroy (window);
+}
+
/*
* GtkProgressBar
*/
@@ -9361,6 +9554,7 @@
{ "tooltips", create_tooltips },
{ "tree", create_tree_mode_window},
{ "WM hints", create_wmhints },
+ { "window states", create_window_states }
};
int nbuttons = sizeof (buttons) / sizeof (buttons[0]);
GtkWidget *window;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]