aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--libowl/owlwindowmenu.c53
2 files changed, 50 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index 802714d..846a814 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
2007-04-20 Ross Burton <ross@openedhand.com>
+ * libowl/owlwindowmenu.c:
+ Comments, sanity checks.
+
+2007-04-20 Ross Burton <ross@openedhand.com>
+
* libowl/Makefile.am:
* libowl/owlwindowmenu.[ch]:
Add function so that if you send the CUSTOM message (by clicking
diff --git a/libowl/owlwindowmenu.c b/libowl/owlwindowmenu.c
index 7be5f0f..4f6b2d7 100644
--- a/libowl/owlwindowmenu.c
+++ b/libowl/owlwindowmenu.c
@@ -28,13 +28,17 @@
static Atom atom_custom, atom_protocol;
+/*
+ * Ensures that the atoms we need are defined.
+ */
static void
ensure_atoms (GdkDrawable *drawable)
{
static gboolean done = FALSE;
+
if (G_UNLIKELY (!done)) {
GdkDisplay *display = gdk_drawable_get_display (drawable);
-
+
atom_custom = gdk_x11_get_xatom_by_name_for_display
(display, "_NET_WM_CONTEXT_CUSTOM");
atom_protocol = gdk_x11_get_xatom_by_name_for_display
@@ -42,10 +46,14 @@ ensure_atoms (GdkDrawable *drawable)
g_assert (atom_custom);
g_assert (atom_protocol);
+
done = TRUE;
}
}
+/*
+ * Menu positioning function, called by gtk_menu_popup.
+ */
static void
position_func (GtkMenu *menu,
gint *x,
@@ -55,37 +63,59 @@ position_func (GtkMenu *menu,
{
GtkWidget *window = user_data;
- /* Set the position of the menu to the origin of the window. This means that
- the menu is in the top left of the application window. */
+ /*
+ * Set the position of the menu to the origin of the window. This means that
+ * the menu is in the top left of the application window. It might be
+ * interesting to see if the theme could specify an offset, so that the menu
+ * aligns itself with the decorations.
+ */
gdk_window_get_origin (window->window, x, y);
}
+/*
+ * Gdk event filter. This should be as fast as possible for non-client messages
+ * as it gets called *frequently*.
+ */
static GdkFilterReturn
filter_func (GdkXEvent *xevent, GdkEvent *event, gpointer data)
{
- if (((XEvent*)xevent)->type == ClientMessage) {
+ if (G_UNLIKELY (((XEvent*)xevent)->type == ClientMessage)) {
XClientMessageEvent *xev = xevent;
+
if (xev->message_type == atom_protocol) {
Atom protocol = xev->data.l[0];
+
if (protocol == atom_custom) {
GtkMenu *menu;
-
+
+ /* Sanity check the user data is the window */
g_return_val_if_fail (GTK_IS_WINDOW (data), GDK_FILTER_CONTINUE);
menu = g_object_get_data (G_OBJECT (data), MENU_PROP);
- /* I wonder if this offset from the window should be specified by the theme */
- gtk_menu_popup (menu, NULL, NULL,
- position_func, data,
+ if (menu) {
+ gtk_menu_popup (menu, NULL, NULL,
+ position_func, data,
0, gtk_get_current_event_time());
+ }
return GDK_FILTER_REMOVE;
}
}
}
+
return GDK_FILTER_CONTINUE;
}
+/**
+ * owl_set_window_menu:
+ * @window: a top-level #GtkWindow
+ * @menu: a #GtkMenu
+ *
+ * Make @menu pop up when the CUSTOM protocol is sent to @window. This means
+ * that when the user clicks on the title bar with a suitable window manager,
+ * the menu appears.
+ */
void
owl_set_window_menu (GtkWindow *window, GtkMenu *menu)
{
@@ -96,15 +126,18 @@ owl_set_window_menu (GtkWindow *window, GtkMenu *menu)
int count = 0;
g_return_if_fail (GTK_IS_WINDOW (window));
+ /* TODO: allow NULL menu to unset? */
g_return_if_fail (GTK_IS_MENU (menu));
w = GTK_WIDGET (window)->window;
+ /* Make sure the atoms we need are defined */
ensure_atoms (w);
/* We only need to setup if the property isn't already set */
done_setup = g_object_get_data (G_OBJECT (window), MENU_PROP) != NULL;
+ /* Set the menu. If there is a menu already defined, it will be unreffed */
g_object_set_data_full (G_OBJECT (window), MENU_PROP, g_object_ref (menu), g_object_unref);
/* It's possible that we are replacing the menu with another menu, so the
@@ -112,21 +145,25 @@ owl_set_window_menu (GtkWindow *window, GtkMenu *menu)
if (done_setup)
return;
+ /* Get the protocols supported by this window */
status = XGetWMProtocols(GDK_WINDOW_XDISPLAY (w), GDK_WINDOW_XID (w),
&old_atoms, &count);
/* TODO: check error */
/* TODO: check if old_atoms already contains custom */
+ /* Add _NEW_WM_CONTEXT_CUSTOM to the list */
atoms = g_new0 (Atom, count+1);
memcpy (atoms, old_atoms, count * sizeof (Atom));
atoms[count] = atom_custom;
+ /* And set the list */
XSetWMProtocols (GDK_WINDOW_XDISPLAY (w), GDK_WINDOW_XID (w), atoms, count+1);
/* TODO: check error */
XFree (old_atoms);
g_free (atoms);
+ /* Add a filter so that we can catch the CUSTOM event and display the menu. */
gdk_window_add_filter (w, filter_func, window);
}