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 ([email protected]) + * Owen Taylor ([email protected]) + * + * 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) {
_______________________________________________ Mailing list: https://launchpad.net/~ayatana-commits Post to : [email protected] Unsubscribe : https://launchpad.net/~ayatana-commits More help : https://help.launchpad.net/ListHelp

