ayatana-commits team mailing list archive
-
ayatana-commits team
-
Mailing list archive
-
Message #02212
[Merge] lp:~ted/indicator-appmenu/working-close-menu-item into lp:indicator-appmenu
Ted Gould has proposed merging lp:~ted/indicator-appmenu/working-close-menu-item into lp:indicator-appmenu with lp:~ted/indicator-appmenu/desktop-menu-handling as a prerequisite.
Requested reviews:
Indicator Applet Developers (indicator-applet-developers)
Have the close menu work for windows.
--
https://code.launchpad.net/~ted/indicator-appmenu/working-close-menu-item/+merge/34554
Your team ayatana-commits is subscribed to branch lp:indicator-appmenu.
=== modified file '.bzrignore'
--- .bzrignore 2010-06-29 15:04:15 +0000
+++ .bzrignore 2010-09-03 16:54:43 +0000
@@ -17,6 +17,7 @@
src/application-menu-debug-client.h
src/application-menu-debug-server.h
tools/current-menu-dump
+src/libappmenu_la-gdk-get-func.lo
tools/mock-json-app
tools/.deps
tools/.libs
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2010-07-22 13:06:09 +0000
+++ src/Makefile.am 2010-09-03 16:54:43 +0000
@@ -14,12 +14,15 @@
libappmenu_la_SOURCES = \
application-menu-registrar-server.h \
dbus-shared.h \
+ gdk-get-func.h \
+ gdk-get-func.c \
+ MwmUtil.h \
indicator-appmenu.c \
indicator-appmenu-marshal.c \
window-menus.c \
window-menus.h
libappmenu_la_CFLAGS = $(INDICATOR_CFLAGS) -Wall -Wl,-Bsymbolic-functions -Wl,-z,defs -Wl,--as-needed -Werror
-libappmenu_la_LIBADD = $(INDICATOR_LIBS)
+libappmenu_la_LIBADD = $(INDICATOR_LIBS) -lX11
libappmenu_la_LDFLAGS = -module -avoid-version
######################################
=== added file 'src/MwmUtil.h'
--- src/MwmUtil.h 1970-01-01 00:00:00 +0000
+++ src/MwmUtil.h 2010-09-03 16:54:43 +0000
@@ -0,0 +1,136 @@
+/**
+ *
+ * $Id$
+ *
+ * Copyright (C) 1995 Free Software Foundation, Inc.
+ *
+ * This file is part of the GNU LessTif Library.
+ *
+ * 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.
+ *
+ *
+ * * Feb 21 1999 - George Lebl (jirka@xxxxxx)
+ * Owen Taylor (otaylor@xxxxxxxxxx)
+ *
+ * Modified so that the MotifWmHints structure defined here
+ * is suitable for client side use on 64-bit architectures.
+ * X expects fields with a format of 32 to be longs, even
+ * when sizeof(long) == 8.
+ **/
+
+#ifndef MWMUTIL_H_INCLUDED
+#define MWMUTIL_H_INCLUDED
+
+#include <X11/Xmd.h>
+
+G_BEGIN_DECLS
+
+typedef struct {
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+ long input_mode;
+ unsigned long status;
+} MotifWmHints, MwmHints;
+
+#define MWM_HINTS_FUNCTIONS (1L << 0)
+#define MWM_HINTS_DECORATIONS (1L << 1)
+#define MWM_HINTS_INPUT_MODE (1L << 2)
+#define MWM_HINTS_STATUS (1L << 3)
+
+#define MWM_FUNC_ALL (1L << 0)
+#define MWM_FUNC_RESIZE (1L << 1)
+#define MWM_FUNC_MOVE (1L << 2)
+#define MWM_FUNC_MINIMIZE (1L << 3)
+#define MWM_FUNC_MAXIMIZE (1L << 4)
+#define MWM_FUNC_CLOSE (1L << 5)
+
+#define MWM_DECOR_ALL (1L << 0)
+#define MWM_DECOR_BORDER (1L << 1)
+#define MWM_DECOR_RESIZEH (1L << 2)
+#define MWM_DECOR_TITLE (1L << 3)
+#define MWM_DECOR_MENU (1L << 4)
+#define MWM_DECOR_MINIMIZE (1L << 5)
+#define MWM_DECOR_MAXIMIZE (1L << 6)
+
+#define MWM_INPUT_MODELESS 0
+#define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1
+#define MWM_INPUT_SYSTEM_MODAL 2
+#define MWM_INPUT_FULL_APPLICATION_MODAL 3
+#define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL
+
+#define MWM_TEAROFF_WINDOW (1L<<0)
+
+/*
+ * atoms
+ */
+#define _XA_MOTIF_BINDINGS "_MOTIF_BINDINGS"
+#define _XA_MOTIF_WM_HINTS "_MOTIF_WM_HINTS"
+#define _XA_MOTIF_WM_MESSAGES "_MOTIF_WM_MESSAGES"
+#define _XA_MOTIF_WM_OFFSET "_MOTIF_WM_OFFSET"
+#define _XA_MOTIF_WM_MENU "_MOTIF_WM_MENU"
+#define _XA_MOTIF_WM_INFO "_MOTIF_WM_INFO"
+#define _XA_MWM_HINTS _XA_MOTIF_WM_HINTS
+#define _XA_MWM_MESSAGES _XA_MOTIF_WM_MESSAGES
+#define _XA_MWM_MENU _XA_MOTIF_WM_MENU
+#define _XA_MWM_INFO _XA_MOTIF_WM_INFO
+
+
+/*
+ * _MWM_INFO property
+ */
+typedef struct {
+ long flags;
+ Window wm_window;
+} MotifWmInfo;
+
+typedef MotifWmInfo MwmInfo;
+
+#define MWM_INFO_STARTUP_STANDARD (1L<<0)
+#define MWM_INFO_STARTUP_CUSTOM (1L<<1)
+
+/*
+ * _MWM_HINTS property
+ */
+typedef struct {
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+ long inputMode;
+ unsigned long status;
+} PropMotifWmHints;
+
+typedef PropMotifWmHints PropMwmHints;
+
+#define PROP_MOTIF_WM_HINTS_ELEMENTS 5
+#define PROP_MWM_HINTS_ELEMENTS PROP_MOTIF_WM_HINTS_ELEMENTS
+
+/*
+ * _MWM_INFO property, slight return
+ */
+typedef struct {
+ unsigned long flags;
+ unsigned long wmWindow;
+} PropMotifWmInfo;
+
+typedef PropMotifWmInfo PropMwmInfo;
+
+#define PROP_MOTIF_WM_INFO_ELEMENTS 2
+#define PROP_MWM_INFO_ELEMENTS PROP_MOTIF_WM_INFO_ELEMENTS
+
+G_END_DECLS
+
+#endif /* MWMUTIL_H_INCLUDED */
=== added file 'src/gdk-get-func.c'
--- src/gdk-get-func.c 1970-01-01 00:00:00 +0000
+++ src/gdk-get-func.c 2010-09-03 16:54:43 +0000
@@ -0,0 +1,145 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-2007 Peter Mattis, Spencer Kimball,
+ * Josh MacDonald, Ryan Lortie
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+/*
+#ifdef HAVE_XKB
+#include <X11/XKBlib.h>
+#endif
+
+#include <netinet/in.h>
+#include <unistd.h>
+*/
+#include <gdk/gdk.h>
+#include <gdk/gdkprivate.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkwindow.h>
+
+#include "MwmUtil.h"
+/*
+#include "gdkwindowimpl.h"
+#include "gdkasync.h"
+#include "gdkinputprivate.h"
+#include "gdkdisplay-x11.h"
+#include "gdkprivate-x11.h"
+#include "gdkregion.h"
+#include "gdkinternals.h"
+#include "gdkwindow-x11.h"
+#include "gdkalias.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+
+#include <X11/extensions/shape.h>
+
+#ifdef HAVE_XCOMPOSITE
+#include <X11/extensions/Xcomposite.h>
+#endif
+
+#ifdef HAVE_XFIXES
+#include <X11/extensions/Xfixes.h>
+#endif
+
+#ifdef HAVE_XDAMAGE
+#include <X11/extensions/Xdamage.h>
+#endif
+*/
+
+#define WINDOW_IS_TOPLEVEL_OR_FOREIGN(window) \
+ (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \
+ GDK_WINDOW_TYPE (window) != GDK_WINDOW_OFFSCREEN)
+
+static MotifWmHints *
+gdk_window_get_mwm_hints (GdkWindow *window)
+{
+ GdkDisplay *display;
+ Atom hints_atom = None;
+ guchar *data;
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return NULL;
+
+ display = gdk_drawable_get_display (window);
+
+ hints_atom = gdk_x11_get_xatom_by_name_for_display (display, _XA_MOTIF_WM_HINTS);
+
+ XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+ hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
+ False, AnyPropertyType, &type, &format, &nitems,
+ &bytes_after, &data);
+
+ if (type == None)
+ return NULL;
+
+ return (MotifWmHints *)data;
+}
+
+/**
+ * gdk_window_get_functions:
+ * @window: The toplevel #GdkWindow to get the functions from
+ * @functions: The window functions will be written here
+ *
+ * Returns the functions set on the GdkWindow with #gdk_window_set_functions
+ * Returns: TRUE if the window has functions set, FALSE otherwise.
+ **/
+gboolean
+egg_window_get_functions(GdkWindow *window,
+ GdkWMFunction *functions)
+{
+ MotifWmHints *hints;
+ gboolean result = FALSE;
+
+ if (GDK_WINDOW_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return FALSE;
+
+ hints = gdk_window_get_mwm_hints (window);
+
+ if (hints)
+ {
+ if (hints->flags & MWM_HINTS_FUNCTIONS)
+ {
+ if (functions)
+ *functions = hints->functions;
+ result = TRUE;
+ }
+
+ XFree (hints);
+ }
+
+ return result;
+}
=== added file 'src/gdk-get-func.h'
--- src/gdk-get-func.h 1970-01-01 00:00:00 +0000
+++ src/gdk-get-func.h 2010-09-03 16:54:43 +0000
@@ -0,0 +1,3 @@
+
+gboolean egg_window_get_functions(GdkWindow *window, GdkWMFunction *functions);
+
=== modified file 'src/indicator-appmenu.c'
--- src/indicator-appmenu.c 2010-09-03 16:54:43 +0000
+++ src/indicator-appmenu.c 2010-09-03 16:54:43 +0000
@@ -23,6 +23,9 @@
#include "config.h"
#endif
+#include <X11/Xlib.h>
+#include <gdk/gdkx.h>
+
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-bindings.h>
#include <dbus/dbus-glib-lowlevel.h>
@@ -39,6 +42,7 @@
#include "indicator-appmenu-marshal.h"
#include "window-menus.h"
#include "dbus-shared.h"
+#include "gdk-get-func.h"
/**********************
Indicator Object
@@ -79,6 +83,8 @@
gulong sig_entry_added;
gulong sig_entry_removed;
+ GtkMenuItem * close_item;
+
GArray * window_menus;
GHashTable * desktop_windows;
@@ -244,6 +250,7 @@
self->apps = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref);
self->matcher = NULL;
self->active_window = NULL;
+ self->close_item = NULL;
/* Setup the entries for the fallbacks */
self->window_menus = g_array_sized_new(FALSE, FALSE, sizeof(IndicatorObjectEntry), 2);
@@ -381,6 +388,46 @@
return;
}
+/* Close the current application using magic */
+static void
+close_current (GtkMenuItem * mi, gpointer user_data)
+{
+ IndicatorAppmenu * iapp = INDICATOR_APPMENU(user_data);
+
+ if (iapp->active_window == NULL) {
+ g_warning("Can't close a window we don't have. NULL not cool.");
+ return;
+ }
+
+ guint xid = bamf_window_get_xid(iapp->active_window);
+ guint timestamp = gdk_event_get_time(NULL);
+
+ XEvent xev;
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.display = gdk_x11_get_default_xdisplay ();
+ xev.xclient.window = xid;
+ xev.xclient.message_type = gdk_x11_atom_to_xatom (gdk_atom_intern ("_NET_CLOSE_WINDOW", TRUE));
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = timestamp;
+ xev.xclient.data.l[1] = 2; /* Client type pager, so it listens to us */
+ xev.xclient.data.l[2] = 0;
+ xev.xclient.data.l[3] = 0;
+ xev.xclient.data.l[4] = 0;
+
+ gdk_error_trap_push ();
+ XSendEvent (gdk_x11_get_default_xdisplay (),
+ gdk_x11_get_default_root_xwindow (),
+ False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+ gdk_error_trap_pop ();
+
+ return;
+}
+
/* Create the default window menus */
static void
build_window_menus (IndicatorAppmenu * iapp)
@@ -404,8 +451,10 @@
mi = GTK_MENU_ITEM(gtk_image_menu_item_new_from_stock(GTK_STOCK_CLOSE, agroup));
gtk_widget_set_sensitive(GTK_WIDGET(mi), FALSE);
+ g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(close_current), iapp);
gtk_widget_show(GTK_WIDGET(mi));
gtk_menu_append(entries[0].menu, GTK_WIDGET(mi));
+ iapp->close_item = mi;
gtk_widget_show(GTK_WIDGET(entries[0].menu));
@@ -620,6 +669,50 @@
return count;
}
+/* A helper for switch_default_app that takes care of the
+ switching of the active window variable */
+static void
+switch_active_window (IndicatorAppmenu * iapp, BamfWindow * active_window)
+{
+ if (iapp->active_window == active_window) {
+ return;
+ }
+
+ iapp->active_window = active_window;
+
+ if (iapp->close_item == NULL) {
+ g_warning("No close item!?!?!");
+ return;
+ }
+
+ gtk_widget_set_sensitive(GTK_WIDGET(iapp->close_item), FALSE);
+
+ guint xid = bamf_window_get_xid(iapp->active_window);
+ if (xid == 0) {
+ return;
+ }
+
+ GdkWindow * window = gdk_window_foreign_new(xid);
+ if (window == NULL) {
+ g_warning("Unable to get foreign window for: %d", xid);
+ return;
+ }
+
+ GdkWMFunction functions;
+ if (!egg_window_get_functions(window, &functions)) {
+ g_debug("Unable to get MWM functions for: %d", xid);
+ functions = GDK_FUNC_ALL;
+ }
+
+ if (functions & GDK_FUNC_ALL || functions & GDK_FUNC_CLOSE) {
+ gtk_widget_set_sensitive(GTK_WIDGET(iapp->close_item), TRUE);
+ }
+
+ g_object_unref(window);
+
+ return;
+}
+
/* Switch applications, remove all the entires for the previous
one and add them for the new application */
static void
@@ -632,7 +725,7 @@
/* Keep active window up-to-date, though we're probably not
using it much. */
- iapp->active_window = active_window;
+ switch_active_window(iapp, active_window);
return;
}
if (iapp->default_app == NULL && iapp->active_window == active_window && newdef == NULL) {
@@ -673,7 +766,7 @@
iapp->default_app = NULL;
/* Update the active window pointer -- may be NULL */
- iapp->active_window = active_window;
+ switch_active_window(iapp, active_window);
/* If we're putting up a new window, let's do that now. */
if (newdef != NULL) {
Follow ups