diff options
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | libowl/Makefile.am | 6 | ||||
-rw-r--r-- | libowl/owlwindowmenu.c | 132 | ||||
-rw-r--r-- | libowl/owlwindowmenu.h | 32 | ||||
-rw-r--r-- | tests/Makefile.am | 3 | ||||
-rw-r--r-- | tests/test-menu.c | 25 |
6 files changed, 206 insertions, 3 deletions
@@ -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; +} |