summaryrefslogtreecommitdiff
path: root/gdk
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2001-02-27 20:40:15 +0000
committerHavoc Pennington <hp@src.gnome.org>2001-02-27 20:40:15 +0000
commit75d79abf9801195a0241b02ed7974fafa8278f5c (patch)
tree750b8f34aca36f06e24ff6ec060353d3e785289f /gdk
parentaf03d3855dc4f6eefe713c69dce355de6f26d4ab (diff)
downloadgtk+-75d79abf9801195a0241b02ed7974fafa8278f5c.tar.gz
test the window state stuff
2001-02-26 Havoc Pennington <hp@redhat.com> * gtk/testgtk.c: test the window state stuff * gtk/gtkwindow.c (gtk_window_present): new function, makes a window come to the user's attention as if it were just created (gtk_window_iconify): new function (gtk_window_deiconify): new function (gtk_window_stick): new function (gtk_window_unstick): new function (gtk_window_maximize): new function (gtk_window_unmaximize): new function * gtk/gtkwidget.h, gtk/gtkwidget.c: add window_state_event signal * gtk/gtkmain.c (gtk_main_do_event): handle GDK_WINDOW_STATE * gdk/x11/gdkevents-x11.c: create window state events when appropriate (gdk_wmspec_supported): new function * gdk/x11/gdkwindow-x11.c (gdk_window_iconify): handle iconification before showing the window (gdk_window_deiconify): new function (gdk_window_stick): new function (gdk_window_unstick): new function (gdk_window_maximize): new function (gdk_window_unmaximize): new function * gdk/gdkwindow.c: store the window state in the window; change to using the GDK_WINDOW_STATE_WITHDRAWN flag instead of window->mapped. (gdk_window_get_state): return the current window state * gdk/gdkevents.c (gdk_event_get_time): handle GDK_WINDOW_STATE (gdk_event_get_state): handle GDK_WINDOW_STATE (gdk_synthesize_window_state): function to create the window state events * gdk/gdkevents.h (struct _GdkEventWindowState): new type of event, for changes to "window state" such as maximized, sticky, etc. * 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
Diffstat (limited to 'gdk')
-rw-r--r--gdk/gdkevents.c55
-rw-r--r--gdk/gdkevents.h24
-rw-r--r--gdk/gdkinternals.h5
-rw-r--r--gdk/gdkwindow.c34
-rw-r--r--gdk/gdkwindow.h14
-rw-r--r--gdk/x11/gdkevents-x11.c263
-rw-r--r--gdk/x11/gdkgeometry-x11.c7
-rw-r--r--gdk/x11/gdkmain-x11.c1
-rw-r--r--gdk/x11/gdkwindow-x11.c413
-rw-r--r--gdk/x11/gdkx.h3
10 files changed, 792 insertions, 27 deletions
diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c
index 8308bbeccd..203f7f4e24 100644
--- a/gdk/gdkevents.c
+++ b/gdk/gdkevents.c
@@ -454,6 +454,7 @@ gdk_event_get_time (GdkEvent *event)
case GDK_EXPOSE:
case GDK_MAP:
case GDK_UNMAP:
+ case GDK_WINDOW_STATE:
/* return current time */
break;
}
@@ -529,6 +530,7 @@ gdk_event_get_state (GdkEvent *event,
case GDK_EXPOSE:
case GDK_MAP:
case GDK_UNMAP:
+ case GDK_WINDOW_STATE:
/* no state field */
break;
}
@@ -803,3 +805,56 @@ gdk_event_button_generate (GdkEvent *event)
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_mask = (unset_flags | set_flags) ^ old;
+ temp_event.new_window_state = old;
+ temp_event.new_window_state |= set_flags;
+ temp_event.new_window_state &= ~unset_flags;
+
+ if (temp_event.new_window_state == 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 to the user.
+ */
+
+ ((GdkWindowObject*) window)->state = temp_event.new_window_state;
+
+ /* 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;
+ }
+}
+
diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h
index f49b156ecd..ea2c25b3ab 100644
--- a/gdk/gdkevents.h
+++ b/gdk/gdkevents.h
@@ -28,8 +28,8 @@ typedef struct _GdkEventProperty GdkEventProperty;
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 @@ typedef enum
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 @@ typedef enum
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 @@ struct _GdkEventClient
} data;
};
+
+struct _GdkEventWindowState
+{
+ GdkEventType type;
+ GdkWindow *window;
+ gint8 send_event;
+ GdkWindowState changed_mask;
+ GdkWindowState new_window_state;
+};
+
/* Event types for DND */
struct _GdkEventDND {
@@ -397,6 +416,7 @@ union _GdkEvent
GdkEventProximity proximity;
GdkEventClient client;
GdkEventDND dnd;
+ GdkEventWindowState window_state;
};
gboolean gdk_events_pending (void);
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index 2987f81863..5f96ffd7ed 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -117,6 +117,9 @@ void gdk_event_queue_remove_link (GList *node);
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 *
@@ -163,6 +166,8 @@ void _gdk_windowing_window_clear_area_e (GdkWindow *window,
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
* exposes. The return value indicates whether the function has a saved
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index 6cd615333b..acead1b234 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -188,6 +188,8 @@ gdk_window_init (GdkWindowObject *window)
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 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
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 @@ gdk_window_get_toplevels (void)
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 @@ gdk_window_is_viewable (GdkWindow *window)
(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_is_viewable (GdkWindow *window)
}
/**
+ * 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 @@ gdk_window_invalidate_rect (GdkWindow *window,
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 @@ gdk_window_invalidate_region (GdkWindow *window,
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);
diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h
index 435e5868dc..9976265edc 100644
--- a/gdk/gdkwindow.h
+++ b/gdk/gdkwindow.h
@@ -199,7 +199,9 @@ struct _GdkWindowObject
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 @@ void gdk_window_clear_area_e (GdkWindow *window,
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 @@ void gdk_window_merge_child_shapes (GdkWindow *window);
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 @@ gboolean gdk_window_get_decorations (GdkWindow *window,
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);
diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c
index a005e5a148..7056d9bc75 100644
--- a/gdk/x11/gdkevents-x11.c
+++ b/gdk/x11/gdkevents-x11.c
@@ -44,6 +44,8 @@
#include <X11/XKBlib.h>
#endif
+#include <X11/Xatom.h>
+
typedef struct _GdkIOClosure GdkIOClosure;
typedef struct _GdkEventPrivate GdkEventPrivate;
@@ -119,7 +121,9 @@ static GSourceFuncs event_funcs = {
NULL
};
-GPollFD event_poll_fd;
+static GPollFD event_poll_fd;
+
+static Window wmspec_check_window = None;
/*********************************************
* Functions for maintaining the event queue *
@@ -260,6 +264,128 @@ gdk_add_client_message_filter (GdkAtom message_type,
client_filters = g_list_prepend (client_filters, filter);
}
+static GdkAtom wm_state_atom = 0;
+static GdkAtom wm_desktop_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);
+
+ if (wm_desktop_atom == 0)
+ wm_desktop_atom = gdk_atom_intern ("_NET_WM_DESKTOP", 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)
+ {
+
+ 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);
+ }
+ else
+ {
+ found_sticky = FALSE;
+ found_maxvert = FALSE;
+ found_maxhorz = FALSE;
+ }
+
+ /* For found_sticky to remain TRUE, we have to also be on desktop
+ * 0xFFFFFFFF
+ */
+
+ if (found_sticky)
+ {
+ gulong *desktop;
+
+ XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
+ wm_desktop_atom, 0, G_MAXLONG,
+ False, XA_CARDINAL, &type, &format, &nitems,
+ &bytes_after, (guchar **)&desktop);
+
+ if (type != None)
+ {
+ if (*desktop != 0xFFFFFFFF)
+ found_sticky = FALSE;
+ XFree (desktop);
+ }
+ }
+
+ 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 +432,19 @@ gdk_event_translate (GdkEvent *event,
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 +1087,17 @@ gdk_event_translate (GdkEvent *event,
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 +1111,12 @@ gdk_event_translate (GdkEvent *event,
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 +1219,19 @@ gdk_event_translate (GdkEvent *event,
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 (wm_desktop_atom == 0)
+ wm_desktop_atom = gdk_atom_intern ("_NET_WM_DESKTOP", FALSE);
+
+ if (event->property.atom == wm_state_atom ||
+ event->property.atom == wm_desktop_atom)
+ {
+ /* If window state changed, then synthesize those events. */
+ gdk_check_wm_state_changed (event->property.window);
+ }
break;
@@ -1586,3 +1754,94 @@ gdk_x11_get_server_time (GdkWindow *window)
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.
+ * Probably at that point the function should be changed to query
+ * _NET_SUPPORTING_WM_CHECK only once every 10 seconds or something.
+ */
+
+ 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 != XA_WINDOW)
+ return FALSE;
+
+ gdk_error_trap_push ();
+
+ /* Find out if this WM goes away, so we can reset everything. */
+ XSelectInput (gdk_display, *xwindow,
+ StructureNotifyMask);
+
+ gdk_flush ();
+
+ if (gdk_error_trap_pop ())
+ {
+ XFree (xwindow);
+ return FALSE;
+ }
+
+ XGetWindowProperty (gdk_display, gdk_root_window,
+ wmspec_supported_atom, 0, G_MAXLONG,
+ False, XA_ATOM, &type, &format, &n_atoms,
+ &bytes_after, (guchar **)&atoms);
+
+ if (type != XA_ATOM)
+ return FALSE;
+
+ wmspec_check_window = *xwindow;
+ XFree (xwindow);
+
+ /* since wmspec_check_window != None this isn't infinite. ;-) */
+ return gdk_wmspec_supported (property);
+}
+
+
+
diff --git a/gdk/x11/gdkgeometry-x11.c b/gdk/x11/gdkgeometry-x11.c
index 6102dc1ce5..17b6f8b9d5 100644
--- a/gdk/x11/gdkgeometry-x11.c
+++ b/gdk/x11/gdkgeometry-x11.c
@@ -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 @@ _gdk_window_move_resize_child (GdkWindow *window,
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 @@ _gdk_window_move_resize_child (GdkWindow *window,
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 @@ gdk_window_postmove (GdkWindow *window,
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)
diff --git a/gdk/x11/gdkmain-x11.c b/gdk/x11/gdkmain-x11.c
index 1f0097b944..1f395e390d 100644
--- a/gdk/x11/gdkmain-x11.c
+++ b/gdk/x11/gdkmain-x11.c
@@ -737,4 +737,3 @@ gdk_send_xevent (Window window, gboolean propagate, glong event_mask,
return result && !gdk_error_code;
}
-
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index a68b2be56a..548bb587c4 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -635,7 +635,12 @@ gdk_window_foreign_new (GdkNativeWindow anid)
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,73 @@ gdk_window_destroy_notify (GdkWindow *window)
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);
+ }
+
+ if (private->state & GDK_WINDOW_STATE_STICKY)
+ {
+ atoms[0] = 0xFFFFFFFF;
+ XChangeProperty (GDK_WINDOW_XDISPLAY (window),
+ GDK_WINDOW_XID (window),
+ gdk_atom_intern ("_NET_WM_DESKTOP", FALSE),
+ XA_CARDINAL, 32, PropModeReplace,
+ (guchar*) atoms, 1);
+ }
+}
+
void
gdk_window_show (GdkWindow *window)
{
@@ -719,13 +791,23 @@ gdk_window_show (GdkWindow *window)
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 +819,36 @@ gdk_window_hide (GdkWindow *window)
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 +861,17 @@ gdk_window_withdraw (GdkWindow *window)
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 +1058,41 @@ gdk_window_lower (GdkWindow *window)
}
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 +1955,43 @@ gdk_window_set_icon_name (GdkWindow *window,
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));
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return;
+
+ display = GDK_WINDOW_XDISPLAY (window);
+
+ 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));
@@ -1821,7 +2000,221 @@ gdk_window_iconify (GdkWindow *window)
return;
display = GDK_WINDOW_XDISPLAY (window);
- XIconifyWindow (display, GDK_WINDOW_XWINDOW (window), DefaultScreen (display));
+
+ 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))
+ {
+ /* "stick" means stick to all desktops _and_ do not scroll with the
+ * viewport. i.e. glue to the monitor glass in all cases.
+ */
+
+ XEvent xev;
+
+ /* Request stick during viewport scroll */
+ 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);
+
+ /* Request desktop 0xFFFFFFFF */
+ 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_DESKTOP", FALSE);
+ xev.xclient.format = 32;
+
+ xev.xclient.data.l[0] = 0xFFFFFFFF;
+
+ XSendEvent (gdk_display, gdk_root_window, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+ }
+ 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))
+ {
+ XEvent xev;
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+ gulong *current_desktop;
+
+ /* Request unstick from viewport */
+ 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);
+
+ /* Get current desktop, then set it; this is a race, but not
+ * one that matters much in practice.
+ */
+ XGetWindowProperty (gdk_display, gdk_root_window,
+ gdk_atom_intern ("_NET_CURRENT_DESKTOP", FALSE),
+ 0, G_MAXLONG,
+ False, XA_CARDINAL, &type, &format, &nitems,
+ &bytes_after, (guchar **)&current_desktop);
+
+ if (type == XA_CARDINAL)
+ {
+ 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_DESKTOP", FALSE);
+ xev.xclient.format = 32;
+
+ xev.xclient.data.l[0] = *current_desktop;
+
+ XSendEvent (gdk_display, gdk_root_window, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+
+ XFree (current_desktop);
+ }
+ }
+ 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))
+ {
+ 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
+ {
+ 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))
+ {
+ 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
+ {
+ gdk_synthesize_window_state (window,
+ GDK_WINDOW_STATE_MAXIMIZED,
+ 0);
+ }
}
void
diff --git a/gdk/x11/gdkx.h b/gdk/x11/gdkx.h
index 336bd35f31..628d32206f 100644
--- a/gdk/x11/gdkx.h
+++ b/gdk/x11/gdkx.h
@@ -185,6 +185,9 @@ gpointer gdk_xid_table_lookup (XID xid);
guint32 gdk_x11_get_server_time (GdkWindow *window);
+/* returns TRUE if we support the given WM spec feature */
+gboolean gdk_wmspec_supported (GdkAtom property);
+
#define gdk_window_lookup(xid) ((GdkWindow*) gdk_xid_table_lookup (xid))
#define gdk_pixmap_lookup(xid) ((GdkPixmap*) gdk_xid_table_lookup (xid))
#define gdk_font_lookup(xid) ((GdkFont*) gdk_xid_table_lookup (xid))