aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--libowl/Makefile.am6
-rw-r--r--libowl/owlwindowmenu.c132
-rw-r--r--libowl/owlwindowmenu.h32
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/test-menu.c25
6 files changed, 206 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index f91a82d..802714d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+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
+ on the titlebar in MB), a menu is displayed.
+
+ * tests/Makefile.am:
+ * tests/test-menu.c:
+ Add test.
+
2007-04-11 Rob Bradford <rob@openedhand.com>
* libowl/owlcolourselectordialog.c:
diff --git a/libowl/Makefile.am b/libowl/Makefile.am
index 7cc1bcc..04372d3 100644
--- a/libowl/Makefile.am
+++ b/libowl/Makefile.am
@@ -4,7 +4,8 @@ libowlinclude_HEADERS = \
owlcolourswatch.h \
owlcolourpalette.h \
owlcolourselectordialog.h \
- owlcolourbutton.h
+ owlcolourbutton.h \
+ owlwindowmenu.h
libowlincludedir = $(includedir)/libowl/
@@ -17,7 +18,8 @@ libowl_la_SOURCES = \
owlcolourswatch.c \
owlcolourpalette.c \
owlcolourselectordialog.c \
- owlcolourbutton.c
+ owlcolourbutton.c \
+ owlwindowmenu.c
libowl_la_CPPFLAGS = $(GTK_CFLAGS) -Wall
libowl_la_LIBADD = $(GTK_LIBS)
diff --git a/libowl/owlwindowmenu.c b/libowl/owlwindowmenu.c
new file mode 100644
index 0000000..7be5f0f
--- /dev/null
+++ b/libowl/owlwindowmenu.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2007 Ross Burton <ross@openedhand.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include "owlwindowmenu.h"
+
+#define MENU_PROP "owl::windowmenu"
+
+static Atom atom_custom, atom_protocol;
+
+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
+ (display, "WM_PROTOCOLS");
+
+ g_assert (atom_custom);
+ g_assert (atom_protocol);
+ done = TRUE;
+ }
+}
+
+static void
+position_func (GtkMenu *menu,
+ gint *x,
+ gint *y,
+ gboolean *push_in,
+ gpointer user_data)
+{
+ 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. */
+
+ gdk_window_get_origin (window->window, x, y);
+}
+
+static GdkFilterReturn
+filter_func (GdkXEvent *xevent, GdkEvent *event, gpointer data)
+{
+ if (((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;
+
+ 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,
+ 0, gtk_get_current_event_time());
+
+ return GDK_FILTER_REMOVE;
+ }
+ }
+ }
+ return GDK_FILTER_CONTINUE;
+}
+
+void
+owl_set_window_menu (GtkWindow *window, GtkMenu *menu)
+{
+ gboolean done_setup;
+ GdkWindow *w;
+ Status status;
+ Atom *old_atoms = NULL, *atoms;
+ int count = 0;
+
+ g_return_if_fail (GTK_IS_WINDOW (window));
+ g_return_if_fail (GTK_IS_MENU (menu));
+
+ w = GTK_WIDGET (window)->window;
+
+ 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;
+
+ 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
+ filters and so on are already registered. */
+ if (done_setup)
+ return;
+
+ status = XGetWMProtocols(GDK_WINDOW_XDISPLAY (w), GDK_WINDOW_XID (w),
+ &old_atoms, &count);
+ /* TODO: check error */
+
+ /* TODO: check if old_atoms already contains custom */
+
+ atoms = g_new0 (Atom, count+1);
+ memcpy (atoms, old_atoms, count * sizeof (Atom));
+ atoms[count] = atom_custom;
+
+ XSetWMProtocols (GDK_WINDOW_XDISPLAY (w), GDK_WINDOW_XID (w), atoms, count+1);
+ /* TODO: check error */
+
+ XFree (old_atoms);
+ g_free (atoms);
+
+ gdk_window_add_filter (w, filter_func, window);
+}
diff --git a/libowl/owlwindowmenu.h b/libowl/owlwindowmenu.h
new file mode 100644
index 0000000..1acab60
--- /dev/null
+++ b/libowl/owlwindowmenu.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2007 Ross Burton <ross@openedhand.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __OWL_WINDOW_MENU_H__
+#define __OWL_WINDOW_MENU_H__
+
+#include <gtk/gtkwindow.h>
+#include <gtk/gtkmenu.h>
+
+G_BEGIN_DECLS
+
+void owl_set_window_menu (GtkWindow *window, GtkMenu *menu);
+
+G_END_DECLS
+
+#endif
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 5c6592f..c94c935 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,4 +1,4 @@
-noinst_PROGRAMS = test-paned test-slice test-colourpalette test-colourselectordialog test-colourbutton test-colourswatch
+noinst_PROGRAMS = test-paned test-slice test-colourpalette test-colourselectordialog test-colourbutton test-colourswatch test-menu
INCLUDES = -I$(top_srcdir)/libowl $(GTK_CFLAGS) -Wall
LDADD = -L../libowl -lowl $(GTK_LIBS)
@@ -9,3 +9,4 @@ test_colourswatch_SOURCES = test-colourswatch.c
test_colourpalette_SOURCES = test-colourpalette.c
test_colourselectordialog_SOURCES = test-colourselectordialog.c
test_colourbutton_SOURCES = test-colourbutton.c
+test_menu_SOURCES = test-menu.c
diff --git a/tests/test-menu.c b/tests/test-menu.c
new file mode 100644
index 0000000..6b479e7
--- /dev/null
+++ b/tests/test-menu.c
@@ -0,0 +1,25 @@
+#include <gtk/gtk.h>
+#include "owlwindowmenu.h"
+
+int
+main (int argc, char **argv)
+{
+ GtkWidget *window, *menu;
+
+ gtk_init (&argc, &argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ g_signal_connect (window, "delete-event", G_CALLBACK (gtk_main_quit), NULL);
+
+ menu = gtk_menu_new ();
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), gtk_menu_item_new_with_label ("Foo"));
+ gtk_widget_show_all (menu);
+
+ /* TODO: Annoying */
+ gtk_widget_realize (window);
+ owl_set_window_menu (GTK_WINDOW (window), GTK_MENU (menu));
+
+ gtk_widget_show_all (window);
+ gtk_main ();
+ return 0;
+}