1 /*
   2 An implementation of indicator object showing menus from applications.
   3 
   4 Copyright 2010 Canonical Ltd.
   5 
   6 Authors:
   7     Ted Gould <ted@canonical.com>
   8 
   9 This program is free software: you can redistribute it and/or modify it 
  10 under the terms of the GNU General Public License version 3, as published 
  11 by the Free Software Foundation.
  12 
  13 This program is distributed in the hope that it will be useful, but 
  14 WITHOUT ANY WARRANTY; without even the implied warranties of 
  15 MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR 
  16 PURPOSE.  See the GNU General Public License for more details.
  17 
  18 You should have received a copy of the GNU General Public License along 
  19 with this program.  If not, see <http://www.gnu.org/licenses/>.
  20 */
  21 
  22 #ifdef HAVE_CONFIG_H
  23 #include "config.h"
  24 #endif
  25 
  26 #include <X11/Xlib.h>
  27 #include <gdk/gdkx.h>
  28 #include <gio/gio.h>
  29 
  30 #include <libindicator/indicator.h>
  31 #include <libindicator/indicator-object.h>
  32 
  33 #include <libdbusmenu-glib/menuitem.h>
  34 #include <libdbusmenu-glib/client.h>
  35 
  36 #include <libbamf/bamf-matcher.h>
  37 
  38 #include "gen-application-menu-registrar.xml.h"
  39 #include "gen-application-menu-renderer.xml.h"
  40 #include "indicator-appmenu-marshal.h"
  41 #include "window-menus.h"
  42 #include "dbus-shared.h"
  43 #include "gdk-get-func.h"
  44 
  45 /**********************
  46   Indicator Object
  47  **********************/
  48 #define INDICATOR_APPMENU_TYPE            (indicator_appmenu_get_type ())
  49 #define INDICATOR_APPMENU(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_APPMENU_TYPE, IndicatorAppmenu))
  50 #define INDICATOR_APPMENU_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_APPMENU_TYPE, IndicatorAppmenuClass))
  51 #define IS_INDICATOR_APPMENU(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_APPMENU_TYPE))
  52 #define IS_INDICATOR_APPMENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_APPMENU_TYPE))
  53 #define INDICATOR_APPMENU_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_APPMENU_TYPE, IndicatorAppmenuClass))
  54 
  55 GType indicator_appmenu_get_type (void);
  56 
  57 INDICATOR_SET_VERSION
  58 INDICATOR_SET_TYPE(INDICATOR_APPMENU_TYPE)
  59 
  60 typedef struct _IndicatorAppmenu      IndicatorAppmenu;
  61 typedef struct _IndicatorAppmenuClass IndicatorAppmenuClass;
  62 typedef struct _IndicatorAppmenuDebug      IndicatorAppmenuDebug;
  63 typedef struct _IndicatorAppmenuDebugClass IndicatorAppmenuDebugClass;
  64 
  65 typedef enum _ActiveStubsState ActiveStubsState;
  66 enum _ActiveStubsState {
  67 	STUBS_UNKNOWN,
  68 	STUBS_SHOW,
  69 	STUBS_HIDE
  70 };
  71 
  72 struct _IndicatorAppmenuClass {
  73 	IndicatorObjectClass parent_class;
  74 
  75 	void (*window_registered) (IndicatorAppmenu * iapp, guint wid, gchar * address, gpointer path, gpointer user_data);
  76 	void (*window_unregistered) (IndicatorAppmenu * iapp, guint wid, gpointer user_data);
  77 };
  78 
  79 struct _IndicatorAppmenu {
  80 	IndicatorObject parent;
  81 
  82 	gulong retry_registration;
  83 
  84 	WindowMenus * default_app;
  85 	GHashTable * apps;
  86 
  87 	BamfMatcher * matcher;
  88 	BamfWindow * active_window;
  89 	ActiveStubsState active_stubs;
  90 
  91 	gulong sig_entry_added;
  92 	gulong sig_entry_removed;
  93 	gulong sig_status_changed;
  94 	gulong sig_show_menu;
  95 	gulong sig_a11y_update;
  96 
  97 	GtkMenuItem * close_item;
  98 
  99 	GArray * window_menus;
 100 
 101 	GHashTable * desktop_windows;
 102 	WindowMenus * desktop_menu;
 103 
 104 	GDBusConnection * bus;
 105 	guint owner_id;
 106 	guint dbus_registration;
 107 
 108 	GHashTable * destruction_timers;
 109 };
 110 
 111 
 112 /**********************
 113   Debug Proxy
 114  **********************/
 115 #define INDICATOR_APPMENU_DEBUG_TYPE            (indicator_appmenu_debug_get_type ())
 116 #define INDICATOR_APPMENU_DEBUG(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_APPMENU_DEBUG_TYPE, IndicatorAppmenuDebug))
 117 #define INDICATOR_APPMENU_DEBUG_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_APPMENU_DEBUG_TYPE, IndicatorAppmenuDebugClass))
 118 #define IS_INDICATOR_APPMENU_DEBUG(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_APPMENU_DEBUG_TYPE))
 119 #define IS_INDICATOR_APPMENU_DEBUG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_APPMENU_DEBUG_TYPE))
 120 #define INDICATOR_APPMENU_DEBUG_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_APPMENU_DEBUG_TYPE, IndicatorAppmenuDebugClass))
 121 
 122 GType indicator_appmenu_debug_get_type (void);
 123 
 124 struct _IndicatorAppmenuDebugClass {
 125 	GObjectClass parent_class;
 126 };
 127 
 128 struct _IndicatorAppmenuDebug {
 129 	GObject parent;
 130 	IndicatorAppmenu * appmenu;
 131 	GCancellable * bus_cancel;
 132 	GDBusConnection * bus;
 133 	guint dbus_registration;
 134 };
 135 
 136 
 137 /**********************
 138   Prototypes
 139  **********************/
 140 static void indicator_appmenu_dispose                                (GObject *object);
 141 static void indicator_appmenu_finalize                               (GObject *object);
 142 static void build_window_menus                                       (IndicatorAppmenu * iapp);
 143 static GList * get_entries                                           (IndicatorObject * io);
 144 static guint get_location                                            (IndicatorObject * io,
 145                                                                       IndicatorObjectEntry * entry);
 146 static void entry_activate                                           (IndicatorObject * io,
 147                                                                       IndicatorObjectEntry * entry,
 148                                                                       guint timestamp);
 149 static void entry_activate_window                                    (IndicatorObject * io,
 150                                                                       IndicatorObjectEntry * entry,
 151                                                                       guint windowid,
 152                                                                       guint timestamp);
 153 static void switch_default_app                                       (IndicatorAppmenu * iapp,
 154                                                                       WindowMenus * newdef,
 155                                                                       BamfWindow * active_window);
 156 static void find_desktop_windows                                     (IndicatorAppmenu * iapp);
 157 static void new_window                                               (BamfMatcher * matcher,
 158                                                                       BamfView * view,
 159                                                                       gpointer user_data);
 160 static void old_window                                               (BamfMatcher * matcher,
 161                                                                       BamfView * view,
 162                                                                       gpointer user_data);
 163 static void window_entry_added                                       (WindowMenus * mw,
 164                                                                       IndicatorObjectEntry * entry,
 165                                                                       gpointer user_data);
 166 static void window_entry_removed                                     (WindowMenus * mw,
 167                                                                       IndicatorObjectEntry * entry,
 168                                                                       gpointer user_data);
 169 static void window_status_changed                                    (WindowMenus * mw,
 170                                                                       DbusmenuStatus status,
 171                                                                       IndicatorAppmenu * iapp);
 172 static void window_show_menu                                         (WindowMenus * mw,
 173                                                                       IndicatorObjectEntry * entry,
 174                                                                       guint timestamp,
 175                                                                       gpointer user_data);
 176 static void window_a11y_update                                       (WindowMenus * mw,
 177                                                                       IndicatorObjectEntry * entry,
 178                                                                       gpointer user_data);
 179 static void active_window_changed                                    (BamfMatcher * matcher,
 180                                                                       BamfView * oldview,
 181                                                                       BamfView * newview,
 182                                                                       gpointer user_data);
 183 static GQuark error_quark                                            (void);
 184 static gboolean retry_registration                                   (gpointer user_data);
 185 static void bus_method_call                                          (GDBusConnection * connection,
 186                                                                       const gchar * sender,
 187                                                                       const gchar * path,
 188                                                                       const gchar * interface,
 189                                                                       const gchar * method,
 190                                                                       GVariant * params,
 191                                                                       GDBusMethodInvocation * invocation,
 192                                                                       gpointer user_data);
 193 static void on_bus_acquired                                          (GDBusConnection * connection,
 194                                                                       const gchar * name,
 195                                                                       gpointer user_data);
 196 static void on_name_acquired                                         (GDBusConnection * connection,
 197                                                                       const gchar * name,
 198                                                                       gpointer user_data);
 199 static void on_name_lost                                             (GDBusConnection * connection,
 200                                                                       const gchar * name,
 201                                                                       gpointer user_data);
 202 static void menus_destroyed                                          (GObject * menus,
 203                                                                       gpointer user_data);
 204 static void source_unregister                                        (gpointer user_data);
 205 static GVariant * unregister_window                                  (IndicatorAppmenu * iapp,
 206                                                                       guint windowid);
 207 
 208 /* Unique error codes for debug interface */
 209 enum {
 210 	ERROR_NO_APPLICATIONS,
 211 	ERROR_NO_DEFAULT_APP,
 212 	ERROR_WINDOW_NOT_FOUND
 213 };
 214 
 215 /**********************
 216   DBus Interfaces
 217  **********************/
 218 static GDBusNodeInfo *      node_info = NULL;
 219 static GDBusInterfaceInfo * interface_info = NULL;
 220 static GDBusInterfaceVTable interface_table = {
 221        method_call:    bus_method_call,
 222        get_property:   NULL, /* No properties */
 223        set_property:   NULL  /* No properties */
 224 };
 225 
 226 G_DEFINE_TYPE (IndicatorAppmenu, indicator_appmenu, INDICATOR_OBJECT_TYPE);
 227 
 228 /* One time init */
 229 static void
 230 indicator_appmenu_class_init (IndicatorAppmenuClass *klass)
 231 {
 232 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 233 
 234 	object_class->dispose = indicator_appmenu_dispose;
 235 	object_class->finalize = indicator_appmenu_finalize;
 236 
 237 	IndicatorObjectClass * ioclass = INDICATOR_OBJECT_CLASS(klass);
 238 
 239 	ioclass->get_entries = get_entries;
 240 	ioclass->get_location = get_location;
 241 	ioclass->entry_activate = entry_activate;
 242 	ioclass->entry_activate_window = entry_activate_window;
 243 
 244 	/* Setting up the DBus interfaces */
 245 	if (node_info == NULL) {
 246 		GError * error = NULL;
 247 
 248 		node_info = g_dbus_node_info_new_for_xml(_application_menu_registrar, &error);
 249 		if (error != NULL) {
 250 			g_critical("Unable to parse Application Menu Interface description: %s", error->message);
 251 			g_error_free(error);
 252 		}
 253 	}
 254 
 255 	if (interface_info == NULL) {
 256 		interface_info = g_dbus_node_info_lookup_interface(node_info, REG_IFACE);
 257 
 258 		if (interface_info == NULL) {
 259 			g_critical("Unable to find interface '" REG_IFACE "'");
 260 		}
 261 	}
 262 
 263 	return;
 264 }
 265 
 266 /* Per instance Init */
 267 static void
 268 indicator_appmenu_init (IndicatorAppmenu *self)
 269 {
 270 	self->default_app = NULL;
 271 	self->apps = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref);
 272 	self->matcher = NULL;
 273 	self->active_window = NULL;
 274 	self->active_stubs = STUBS_UNKNOWN;
 275 	self->close_item = NULL;
 276 	self->retry_registration = 0;
 277 	self->bus = NULL;
 278 	self->owner_id = 0;
 279 	self->dbus_registration = 0;
 280 
 281 	/* Setup the entries for the fallbacks */
 282 	self->window_menus = g_array_sized_new(FALSE, FALSE, sizeof(IndicatorObjectEntry), 2);
 283 
 284 	/* Setup the cache of windows with possible desktop entries */
 285 	self->desktop_windows = g_hash_table_new(g_direct_hash, g_direct_equal);
 286 	self->desktop_menu = NULL; /* Starts NULL until found */
 287 
 288 	/* Set up the hashtable of destruction timers */
 289 	self->destruction_timers = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, source_unregister);
 290 
 291 	build_window_menus(self);
 292 
 293 	/* Get the default BAMF matcher */
 294 	self->matcher = bamf_matcher_get_default();
 295 	if (self->matcher == NULL) {
 296 		/* we don't want to exit out of Unity -- but this
 297 		   should really never happen */
 298 		g_warning("Unable to get BAMF matcher, can not watch applications switch!");
 299 	} else {
 300 		g_signal_connect(G_OBJECT(self->matcher), "active-window-changed", G_CALLBACK(active_window_changed), self);
 301 
 302 		/* Desktop window tracking */
 303 		g_signal_connect(G_OBJECT(self->matcher), "view-opened", G_CALLBACK(new_window), self);
 304 		g_signal_connect(G_OBJECT(self->matcher), "view-closed", G_CALLBACK(old_window), self);
 305 	}
 306 
 307 	find_desktop_windows(self);
 308 
 309 	/* Request a name so others can find us */
 310 	retry_registration(self);
 311 
 312 	return;
 313 }
 314 
 315 /* If we weren't able to register on the bus, then we need
 316    to try it all again. */
 317 static gboolean
 318 retry_registration (gpointer user_data)
 319 {
 320 	g_return_val_if_fail(IS_INDICATOR_APPMENU(user_data), FALSE);
 321 	IndicatorAppmenu * iapp = INDICATOR_APPMENU(user_data);
 322 
 323 	iapp->owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
 324 	                                 DBUS_NAME,
 325 	                                 G_BUS_NAME_OWNER_FLAGS_NONE,
 326 	                                 iapp->dbus_registration == 0 ? on_bus_acquired : NULL,
 327 	                                 on_name_acquired,
 328 	                                 on_name_lost,
 329 	                                 g_object_ref(iapp),
 330 	                                 g_object_unref);
 331 
 332 	return TRUE;
 333 }
 334 
 335 static void
 336 on_bus_acquired (GDBusConnection * connection, const gchar * name,
 337                  gpointer user_data)
 338 {
 339 	IndicatorAppmenu * iapp = INDICATOR_APPMENU(user_data);
 340 	GError * error = NULL;
 341 
 342 	iapp->bus = connection;
 343 
 344 	/* Now register our object on our new connection */
 345 	iapp->dbus_registration = g_dbus_connection_register_object(connection,
 346 	                                                            REG_OBJECT,
 347 	                                                            interface_info,
 348 	                                                            &interface_table,
 349 	                                                            user_data,
 350 	                                                            NULL,
 351 	                                                            &error);
 352 
 353 	if (error != NULL) {
 354 		g_critical("Unable to register the object to DBus: %s", error->message);
 355 		g_error_free(error);
 356 		g_bus_unown_name(iapp->owner_id);
 357 		iapp->owner_id = 0;
 358 		iapp->retry_registration = g_timeout_add_seconds(1, retry_registration, iapp);
 359 		return;
 360 	}
 361 
 362 	return;	
 363 }
 364 
 365 static void
 366 on_name_acquired (GDBusConnection * connection, const gchar * name,
 367                   gpointer user_data)
 368 {
 369 }
 370 
 371 static void
 372 on_name_lost (GDBusConnection * connection, const gchar * name,
 373               gpointer user_data)
 374 {
 375 	IndicatorAppmenu * iapp = INDICATOR_APPMENU(user_data);
 376 
 377 	if (connection == NULL) {
 378 		g_critical("OMG! Unable to get a connection to DBus");
 379 	}
 380 	else {
 381 		g_critical("Unable to claim the name %s", DBUS_NAME);
 382 	}
 383 
 384 	/* We can rest assured no one will register with us, but let's
 385 	   just ensure we're not showing anything. */
 386 	switch_default_app(iapp, NULL, NULL);
 387 
 388 	iapp->owner_id = 0;
 389 }
 390 
 391 /* Object refs decrement */
 392 static void
 393 indicator_appmenu_dispose (GObject *object)
 394 {
 395 	IndicatorAppmenu * iapp = INDICATOR_APPMENU(object);
 396 
 397 	/* Don't register if we're dying! */
 398 	if (iapp->retry_registration != 0) {
 399 		g_source_remove(iapp->retry_registration);
 400 		iapp->retry_registration = 0;
 401 	}
 402 
 403 	if (iapp->dbus_registration != 0) {
 404 		g_dbus_connection_unregister_object(iapp->bus, iapp->dbus_registration);
 405 		/* Don't care if it fails, there's nothing we can do */
 406 		iapp->dbus_registration = 0;
 407 	}
 408 
 409 	if (iapp->destruction_timers != NULL) {
 410 		/* These are in dispose and not finalize becuase the dereference
 411 		   function removes timers that could need the object to be in
 412 		   a valid state, so it's better to have them in dispose */
 413 		g_hash_table_destroy(iapp->destruction_timers);
 414 		iapp->destruction_timers = NULL;
 415 	}
 416 
 417 	if (iapp->bus != NULL) {
 418 		g_object_unref(iapp->bus);
 419 		iapp->bus = NULL;
 420 	}
 421 
 422 	if (iapp->owner_id != 0) {
 423 		g_bus_unown_name(iapp->owner_id);
 424 		iapp->owner_id = 0;
 425 	}
 426 
 427 	/* bring down the matcher before resetting to no menu so we don't
 428 	   get match signals */
 429 	if (iapp->matcher != NULL) {
 430 		g_object_unref(iapp->matcher);
 431 		iapp->matcher = NULL;
 432 	}
 433 
 434 	/* No specific ref */
 435 	switch_default_app (iapp, NULL, NULL);
 436 
 437 	if (iapp->apps != NULL) {
 438 		g_hash_table_destroy(iapp->apps);
 439 		iapp->apps = NULL;
 440 	}
 441 
 442 	if (iapp->desktop_windows != NULL) {
 443 		g_hash_table_destroy(iapp->desktop_windows);
 444 		iapp->desktop_windows = NULL;
 445 	}
 446 
 447 	if (iapp->desktop_menu != NULL) {
 448 		/* Wait, nothing here?  Yup.  We're not referencing the
 449 		   menus here they're already attached to the window ID.
 450 		   We're just keeping an efficient pointer to them. */
 451 		iapp->desktop_menu = NULL;
 452 	}
 453 
 454 	G_OBJECT_CLASS (indicator_appmenu_parent_class)->dispose (object);
 455 	return;
 456 }
 457 
 458 /* Free memory */
 459 static void
 460 indicator_appmenu_finalize (GObject *object)
 461 {
 462 	IndicatorAppmenu * iapp = INDICATOR_APPMENU(object);
 463 
 464 	if (iapp->window_menus != NULL) {
 465 		if (iapp->window_menus->len != 0) {
 466 			g_warning("Window menus weren't free'd in dispose!");
 467 		}
 468 		g_array_free(iapp->window_menus, TRUE);
 469 		iapp->window_menus = NULL;
 470 	}
 471 
 472 	G_OBJECT_CLASS (indicator_appmenu_parent_class)->finalize (object);
 473 	return;
 474 }
 475 
 476 static void
 477 emit_signal (IndicatorAppmenu * iapp, const gchar * name, GVariant * variant)
 478 {
 479 	GError * error = NULL;
 480 
 481 	g_dbus_connection_emit_signal (iapp->bus,
 482 		                       NULL,
 483 		                       REG_OBJECT,
 484 		                       REG_IFACE,
 485 		                       name,
 486 		                       variant,
 487 		                       &error);
 488 
 489 	if (error != NULL) {
 490 		g_critical("Unable to send %s signal: %s", name, error->message);
 491 		g_error_free(error);
 492 		return;
 493 	}
 494 
 495 	return;
 496 }
 497 
 498 /* Close the current application using magic */
 499 static void
 500 close_current (GtkMenuItem * mi, gpointer user_data)
 501 {
 502 	IndicatorAppmenu * iapp = INDICATOR_APPMENU(user_data);
 503 
 504 	if (!BAMF_IS_WINDOW (iapp->active_window) || bamf_view_is_closed (BAMF_VIEW (iapp->active_window))) {
 505 		g_warning("Can't close a window we don't have. Window is either non-existent or recently closed.");
 506 		return;
 507 	}
 508 
 509 	guint32 xid = bamf_window_get_xid(iapp->active_window);
 510 	guint timestamp = gdk_event_get_time(NULL);
 511 
 512 	XEvent xev;
 513 
 514 	xev.xclient.type = ClientMessage;
 515 	xev.xclient.serial = 0;
 516 	xev.xclient.send_event = True;
 517 	xev.xclient.display = gdk_x11_get_default_xdisplay ();
 518 	xev.xclient.window = xid;
 519 	xev.xclient.message_type = gdk_x11_atom_to_xatom (gdk_atom_intern ("_NET_CLOSE_WINDOW", TRUE));
 520 	xev.xclient.format = 32;
 521 	xev.xclient.data.l[0] = timestamp;
 522 	xev.xclient.data.l[1] = 2; /* Client type pager, so it listens to us */
 523 	xev.xclient.data.l[2] = 0;
 524 	xev.xclient.data.l[3] = 0;
 525 	xev.xclient.data.l[4] = 0;
 526 
 527 	gdk_error_trap_push ();
 528 	XSendEvent (gdk_x11_get_default_xdisplay (),
 529 	            gdk_x11_get_default_root_xwindow (),
 530 	            False,
 531 	            SubstructureRedirectMask | SubstructureNotifyMask,
 532 	            &xev);
 533   gdk_flush ();
 534 #if GTK_CHECK_VERSION(3, 0, 0)
 535 	gdk_error_trap_pop_ignored ();
 536 #else
 537 	gdk_error_trap_pop ();
 538 #endif
 539 
 540 	return;
 541 }
 542 
 543 /* Create the default window menus */
 544 static void
 545 build_window_menus (IndicatorAppmenu * iapp)
 546 {
 547 	IndicatorObjectEntry entries[1] = {{0}};
 548 	GtkAccelGroup * agroup = gtk_accel_group_new();
 549 	GtkMenuItem * mi = NULL;
 550 	GtkStockItem stockitem;
 551 
 552 	/* File Menu */
 553 	if (!gtk_stock_lookup(GTK_STOCK_FILE, &stockitem)) {
 554 		g_warning("Unable to find the file menu stock item");
 555 		stockitem.label = "_File";
 556 	}
 557 	entries[0].label = GTK_LABEL(gtk_label_new_with_mnemonic(stockitem.label));
 558 	g_object_ref(G_OBJECT(entries[0].label));
 559 	gtk_widget_show(GTK_WIDGET(entries[0].label));
 560 
 561 	entries[0].menu = GTK_MENU(gtk_menu_new());
 562 	g_object_ref(G_OBJECT(entries[0].menu));
 563 
 564 	mi = GTK_MENU_ITEM(gtk_image_menu_item_new_from_stock(GTK_STOCK_CLOSE, agroup));
 565 	gtk_widget_set_sensitive(GTK_WIDGET(mi), FALSE);
 566 	g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(close_current), iapp);
 567 	gtk_widget_show(GTK_WIDGET(mi));
 568 	gtk_menu_shell_append(GTK_MENU_SHELL(entries[0].menu), GTK_WIDGET(mi));
 569 	iapp->close_item = mi;
 570 
 571 	gtk_widget_show(GTK_WIDGET(entries[0].menu));
 572 
 573 	/* Copy the entries on the stack into the array */
 574 	g_array_insert_vals(iapp->window_menus, 0, entries, 1);
 575 
 576 	return;
 577 }
 578 
 579 /* Determine which windows should be used as the desktop
 580    menus. */
 581 static void
 582 determine_new_desktop (IndicatorAppmenu * iapp)
 583 {
 584 	GList * keys = g_hash_table_get_keys(iapp->desktop_windows);
 585 	GList * key;
 586 
 587 	for (key = keys; key != NULL; key = g_list_next(key)) {
 588 		guint xid = GPOINTER_TO_UINT(key->data);
 589 		gpointer pwm = g_hash_table_lookup(iapp->apps, GUINT_TO_POINTER(xid));
 590 		if (pwm != NULL) {
 591 			g_debug("Setting Desktop Menus to: %X", xid);
 592 			iapp->desktop_menu = WINDOW_MENUS(pwm);
 593 		}
 594 	}
 595 
 596 	g_list_free(keys);
 597 
 598 	return;
 599 }
 600 
 601 /* Puts all the desktop windows into the hash table so that we
 602    can have a nice list of them. */
 603 static void
 604 find_desktop_windows (IndicatorAppmenu * iapp)
 605 {
 606 	GList * windows = bamf_matcher_get_windows(iapp->matcher);
 607 	GList * lwindow;
 608 
 609 	for (lwindow = windows; lwindow != NULL; lwindow = g_list_next(lwindow)) {
 610 		BamfView * view = BAMF_VIEW(lwindow->data);
 611 		new_window(iapp->matcher, view, iapp);
 612 	}
 613 
 614 	g_list_free(windows);
 615 
 616 	return;
 617 }
 618 
 619 /* When new windows are born, we check to see if they're desktop
 620    windows. */
 621 static void
 622 new_window (BamfMatcher * matcher, BamfView * view, gpointer user_data)
 623 {
 624 	if (view == NULL || !BAMF_IS_WINDOW(view)) {
 625 		return;
 626 	}
 627 
 628 	BamfWindow * window = BAMF_WINDOW(view);
 629 	IndicatorAppmenu * iapp = INDICATOR_APPMENU(user_data);
 630 	guint32 xid = bamf_window_get_xid(window);
 631 
 632 	/* Make sure we don't destroy it later */
 633 	g_hash_table_remove(iapp->destruction_timers, GUINT_TO_POINTER(xid));
 634 
 635 	if (bamf_window_get_window_type(window) != BAMF_WINDOW_DESKTOP) {
 636 		return;
 637 	}
 638 
 639 	g_hash_table_insert(iapp->desktop_windows, GUINT_TO_POINTER(xid), GINT_TO_POINTER(TRUE));
 640 
 641 	g_debug("New Desktop Window: %X", xid);
 642 
 643 	gpointer pwm = g_hash_table_lookup(iapp->apps, GUINT_TO_POINTER(xid));
 644 	if (pwm != NULL) {
 645 		WindowMenus * wm = WINDOW_MENUS(pwm);
 646 		iapp->desktop_menu = wm;
 647 		g_debug("Setting Desktop Menus to: %X", xid);
 648 		if (iapp->active_window == NULL && iapp->default_app == NULL) {
 649 			switch_default_app(iapp, NULL, NULL);
 650 		}
 651 	}
 652 
 653 	return;
 654 }
 655 
 656 typedef struct _destroy_data_t destroy_data_t;
 657 struct _destroy_data_t {
 658 	IndicatorAppmenu * iapp;
 659 	guint32 xid;
 660 };
 661 
 662 /* Timeout to finally cleanup the window.  Causes is to ignore glitches that
 663    come from BAMF/WNCK. */
 664 static gboolean
 665 destroy_window_timeout (gpointer user_data)
 666 {
 667 	destroy_data_t * destroy_data = (destroy_data_t *)user_data;
 668 	g_hash_table_steal(destroy_data->iapp->destruction_timers, GUINT_TO_POINTER(destroy_data->xid));
 669 	unregister_window(destroy_data->iapp, destroy_data->xid);
 670 	return FALSE; /* free's data through source deregistration */
 671 }
 672 
 673 /* Unregisters the source in the hash table when it gets removed.  This ensure
 674    we don't leave any timeouts around */
 675 static void
 676 source_unregister (gpointer user_data)
 677 {
 678 	g_source_remove(GPOINTER_TO_UINT(user_data));
 679 	return;
 680 }
 681 
 682 /* When windows leave us, this function gets called */
 683 static void
 684 old_window (BamfMatcher * matcher, BamfView * view, gpointer user_data)
 685 {
 686 	if (view == NULL || !BAMF_IS_WINDOW(view)) {
 687 		return;
 688 	}
 689 
 690 	IndicatorAppmenu * iapp = INDICATOR_APPMENU(user_data);
 691 	BamfWindow * window = BAMF_WINDOW(view);
 692 	guint32 xid = bamf_window_get_xid(window);
 693 
 694 	destroy_data_t * destroy_data = g_new0(destroy_data_t, 1);
 695 	destroy_data->iapp = iapp;
 696 	destroy_data->xid = xid;
 697 
 698 	guint source_id = g_timeout_add_seconds_full(G_PRIORITY_LOW, 5, destroy_window_timeout, destroy_data, g_free);
 699 	g_hash_table_replace(iapp->destruction_timers, GUINT_TO_POINTER(xid), GUINT_TO_POINTER(source_id));
 700 
 701 	return;
 702 }
 703 
 704 /* List of desktop files that shouldn't have menu stubs. */
 705 const static gchar * stubs_blacklist[] = {
 706 	/* Firefox */
 707 	"/usr/share/applications/firefox.desktop",
 708 	/* Thunderbird */
 709 	"/usr/share/applications/thunderbird.desktop",
 710 	/* Open Office */
 711 	"/usr/share/applications/openoffice.org-base.desktop",
 712 	"/usr/share/applications/openoffice.org-impress.desktop",
 713 	"/usr/share/applications/openoffice.org-calc.desktop",
 714 	"/usr/share/applications/openoffice.org-math.desktop",
 715 	"/usr/share/applications/openoffice.org-draw.desktop",
 716 	"/usr/share/applications/openoffice.org-writer.desktop",
 717 	/* Blender */
 718 	"/usr/share/applications/blender-fullscreen.desktop",
 719 	"/usr/share/applications/blender-windowed.desktop",
 720 	/* Eclipse */
 721 	"/usr/share/applications/eclipse.desktop",
 722 
 723 	NULL
 724 };
 725 
 726 /* Check with BAMF, and then check the blacklist of desktop files
 727    to see if any are there.  Otherwise, show the stubs. */
 728 gboolean
 729 show_menu_stubs (BamfApplication * app)
 730 {
 731 	if (bamf_application_get_show_menu_stubs(app) == FALSE) {
 732 		return FALSE;
 733 	}
 734 
 735 	const gchar * desktop_file = bamf_application_get_desktop_file(app);
 736 	if (desktop_file == NULL || desktop_file[0] == '\0') {
 737 		return TRUE;
 738 	}
 739 
 740 	int i;
 741 	for (i = 0; stubs_blacklist[i] != NULL; i++) {
 742 		if (g_strcmp0(stubs_blacklist[i], desktop_file) == 0) {
 743 			return FALSE;
 744 		}
 745 	}
 746 
 747 	return TRUE;
 748 }
 749 
 750 /* Get the current set of entries */
 751 static GList *
 752 get_entries (IndicatorObject * io)
 753 {
 754 	g_return_val_if_fail(IS_INDICATOR_APPMENU(io), NULL);
 755 	IndicatorAppmenu * iapp = INDICATOR_APPMENU(io);
 756 
 757 	/* If we have a focused app with menus, use it's windows */
 758 	if (iapp->default_app != NULL) {
 759 		return window_menus_get_entries(iapp->default_app);
 760 	}
 761 
 762 	/* Else, let's go with desktop windows if there isn't a focused window */
 763 	if (iapp->active_window == NULL) {
 764 		if (iapp->desktop_menu == NULL) {
 765 			return NULL;
 766 		} else {
 767 			return window_menus_get_entries(iapp->desktop_menu);
 768 		}
 769 	}
 770 
 771 	/* Oh, now we're looking at stubs. */
 772 
 773 	if (iapp->active_stubs == STUBS_UNKNOWN) {
 774 		iapp->active_stubs = STUBS_SHOW;
 775 
 776 		BamfApplication * app = bamf_matcher_get_application_for_window(iapp->matcher, iapp->active_window);
 777 		if (app != NULL) {
 778 			/* First check to see if we can find an app, then if we can
 779 			   check to see if it has an opinion on whether we should
 780 			   show the stubs or not. */
 781 			if (show_menu_stubs(app) == FALSE) {
 782 				/* If it blocks them, fall out. */
 783 				iapp->active_stubs = STUBS_HIDE;
 784 			}
 785 		}
 786 	}
 787 
 788 	if (iapp->active_stubs == STUBS_HIDE) {
 789 		return NULL;
 790 	}
 791 
 792 	if (indicator_object_check_environment(INDICATOR_OBJECT(iapp), "unity")) {
 793 		return NULL;
 794 	}
 795 
 796 	GList * output = NULL;
 797 	int i;
 798 
 799 	/* There is only one item in window_menus now, but there
 800 	   was more, and there is likely to be more in the future
 801 	   so we're leaving this here to avoid a possible bug. */
 802 	for (i = 0; i < iapp->window_menus->len; i++) {
 803 		output = g_list_append(output, &g_array_index(iapp->window_menus, IndicatorObjectEntry, i));
 804 	}
 805 
 806 	return output;
 807 }
 808 
 809 /* Grabs the location of the entry */
 810 static guint
 811 get_location (IndicatorObject * io, IndicatorObjectEntry * entry)
 812 {
 813 	guint count = 0;
 814 	IndicatorAppmenu * iapp = INDICATOR_APPMENU(io);
 815 	if (iapp->default_app != NULL) {
 816 		/* Find the location in the app */
 817 		count = window_menus_get_location(iapp->default_app, entry);
 818 	} else if (iapp->active_window != NULL) {
 819 		/* Find the location in the window menus */
 820 		for (count = 0; count < iapp->window_menus->len; count++) {
 821 			if (entry == &g_array_index(iapp->window_menus, IndicatorObjectEntry, count)) {
 822 				break;
 823 			}
 824 		}
 825 		if (count == iapp->window_menus->len) {
 826 			g_warning("Unable to find entry in default window menus");
 827 			count = 0;
 828 		}
 829 	} else {
 830 		/* Find the location in the desktop menu */
 831 		if (iapp->desktop_menu != NULL) {
 832 			count = window_menus_get_location(iapp->desktop_menu, entry);
 833 		}
 834 	}
 835 	return count;
 836 }
 837 
 838 /* Responds to a menuitem being activated on the panel. */
 839 static void
 840 entry_activate (IndicatorObject * io, IndicatorObjectEntry * entry, guint timestamp)
 841 {
 842 	return entry_activate_window(io, entry, 0, timestamp);
 843 }
 844 
 845 /* Responds to a menuitem being activated on the panel. */
 846 static void
 847 entry_activate_window (IndicatorObject * io, IndicatorObjectEntry * entry, guint windowid, guint timestamp)
 848 {
 849 	IndicatorAppmenu * iapp = INDICATOR_APPMENU(io);
 850 
 851 	/* We need to force a focus change in this case as we probably
 852 	   just haven't gotten the signal from BAMF yet */
 853 	if (windowid != 0) {
 854 		GList * windows = bamf_matcher_get_windows(iapp->matcher);
 855 		GList * window;
 856 		BamfView * newwindow = NULL;
 857 
 858 		for (window = windows; window != NULL; window = g_list_next(window)) {
 859 			if (!BAMF_IS_WINDOW(window->data)) {
 860 				continue;
 861 			}
 862 
 863 			BamfWindow * testwindow = BAMF_WINDOW(window->data);
 864 
 865 			if (windowid == bamf_window_get_xid(testwindow)) {
 866 				newwindow = BAMF_VIEW(testwindow);
 867 				break;
 868 			}
 869 		}
 870 		g_list_free(windows);
 871 
 872 		if (newwindow != NULL) {
 873 			active_window_changed(iapp->matcher, BAMF_VIEW(iapp->active_window), newwindow, iapp);
 874 		}
 875 	}
 876 
 877 	if (iapp->default_app != NULL) {
 878 		window_menus_entry_activate(iapp->default_app, entry, timestamp);
 879 		return;
 880 	}
 881 
 882 	if (iapp->active_window == NULL) {
 883 		if (iapp->desktop_menu != NULL) {
 884 			window_menus_entry_activate(iapp->desktop_menu, entry, timestamp);
 885 		}
 886 		return;
 887 	}
 888 
 889 	/* Else we've got stubs, and the stubs don't care. */
 890 
 891 	return;
 892 }
 893 
 894 /* Checks to see we cared about a window that's going
 895    away, so that we can deal with that */
 896 static void
 897 window_finalized_is_active (gpointer user_data, GObject * old_window)
 898 {
 899 	g_return_if_fail(IS_INDICATOR_APPMENU(user_data));
 900 	IndicatorAppmenu * iapp = INDICATOR_APPMENU(user_data);
 901 
 902 	/* Pointer comparison as we can't really trust any of the
 903 	   pointers to do any dereferencing */
 904 	if ((gpointer)iapp->active_window != (gpointer)old_window) {
 905 		/* Ah, no issue, we weren't caring about this one
 906 		   anyway. */
 907 		return;
 908 	}
 909 
 910 	/* We're going to a state where we don't know what the active
 911 	   window is, hopefully BAMF will save us */
 912 	active_window_changed (iapp->matcher, NULL, NULL, iapp);
 913 
 914 	return;
 915 }
 916 
 917 /* A helper for switch_default_app that takes care of the
 918    switching of the active window variable */
 919 static void
 920 switch_active_window (IndicatorAppmenu * iapp, BamfWindow * active_window)
 921 {
 922 	if (iapp->active_window == active_window) {
 923 		return;
 924 	}
 925 
 926 	if (iapp->active_window != NULL) {
 927 		g_object_weak_unref(G_OBJECT(iapp->active_window), window_finalized_is_active, iapp);
 928 	}
 929 
 930 	iapp->active_window = active_window;
 931 	iapp->active_stubs = STUBS_UNKNOWN;
 932 
 933 	/* Close any existing open menu by showing a null entry */
 934 	window_show_menu(iapp->default_app, NULL, gtk_get_current_event_time(), iapp);
 935 
 936 	if (active_window != NULL) {
 937 		g_object_weak_ref(G_OBJECT(active_window), window_finalized_is_active, iapp);
 938 	}
 939 
 940 	if (iapp->close_item == NULL) {
 941 		g_warning("No close item!?!?!");
 942 		return;
 943 	}
 944 
 945 	gtk_widget_set_sensitive(GTK_WIDGET(iapp->close_item), FALSE);
 946 
 947 	if (iapp->active_window == NULL) {
 948 		return;
 949 	}
 950 
 951 	guint32 xid = bamf_window_get_xid(iapp->active_window);
 952 	if (xid == 0 || bamf_view_is_closed (BAMF_VIEW (iapp->active_window))) {
 953 		return;
 954 	}
 955  
 956 	GdkWMFunction functions;
 957 	if (!egg_xid_get_functions(xid, &functions)) {
 958 		g_debug("Unable to get MWM functions for: %d", xid);
 959 		functions = GDK_FUNC_ALL;
 960 	}
 961 
 962 	if (functions & GDK_FUNC_ALL || functions & GDK_FUNC_CLOSE) {
 963 		gtk_widget_set_sensitive(GTK_WIDGET(iapp->close_item), TRUE);
 964 	}
 965 
 966 	return;
 967 }
 968 
 969 /* Switch applications, remove all the entires for the previous
 970    one and add them for the new application */
 971 static void
 972 switch_default_app (IndicatorAppmenu * iapp, WindowMenus * newdef, BamfWindow * active_window)
 973 {
 974 	if (iapp->default_app == newdef && iapp->default_app != NULL) {
 975 		/* We've got an app with menus and it hasn't changed. */
 976 
 977 		/* Keep active window up-to-date, though we're probably not
 978 		   using it much. */
 979 		switch_active_window(iapp, active_window);
 980 		return;
 981 	}
 982 
 983 	if (iapp->default_app == NULL && iapp->active_window == active_window && newdef == NULL) {
 984 		/* There's no application menus, but the active window hasn't
 985 		   changed.  So there's no change. */
 986 		return;
 987 	}
 988 
 989 	/* hide the entries that we're swapping out */
 990 	indicator_object_set_visible (INDICATOR_OBJECT(iapp), FALSE);
 991 	
 992 	/* Disconnect signals */
 993 	if (iapp->sig_entry_added != 0) {
 994 		g_signal_handler_disconnect(G_OBJECT(iapp->default_app), iapp->sig_entry_added);
 995 		iapp->sig_entry_added = 0;
 996 	}
 997 	if (iapp->sig_entry_removed != 0) {
 998 		g_signal_handler_disconnect(G_OBJECT(iapp->default_app), iapp->sig_entry_removed);
 999 		iapp->sig_entry_removed = 0;
1000 	}
1001 	if (iapp->sig_status_changed != 0) {
1002 		g_signal_handler_disconnect(G_OBJECT(iapp->default_app), iapp->sig_status_changed);
1003 		iapp->sig_status_changed = 0;
1004 	}
1005 	if (iapp->sig_show_menu != 0) {
1006 		g_signal_handler_disconnect(G_OBJECT(iapp->default_app), iapp->sig_show_menu);
1007 		iapp->sig_show_menu = 0;
1008 	}
1009 	if (iapp->sig_a11y_update != 0) {
1010 		g_signal_handler_disconnect(G_OBJECT(iapp->default_app), iapp->sig_a11y_update);
1011 		iapp->sig_a11y_update = 0;
1012 	}
1013 
1014 	/* Default App is NULL, let's see if it needs replacement */
1015 	iapp->default_app = NULL;
1016 
1017 	/* Update the active window pointer -- may be NULL */
1018 	switch_active_window(iapp, active_window);
1019 
1020 	/* If we're putting up a new window, let's do that now. */
1021 	if (newdef != NULL) {
1022 		/* Switch */
1023 		iapp->default_app = newdef;
1024 
1025 		/* Connect signals */
1026 		iapp->sig_entry_added =   g_signal_connect(G_OBJECT(iapp->default_app),
1027 		                                           WINDOW_MENUS_SIGNAL_ENTRY_ADDED,
1028 		                                           G_CALLBACK(window_entry_added),
1029 		                                           iapp);
1030 		iapp->sig_entry_removed = g_signal_connect(G_OBJECT(iapp->default_app),
1031 		                                           WINDOW_MENUS_SIGNAL_ENTRY_REMOVED,
1032 		                                           G_CALLBACK(window_entry_removed),
1033 		                                           iapp);
1034 		iapp->sig_status_changed = g_signal_connect(G_OBJECT(iapp->default_app),
1035 		                                           WINDOW_MENUS_SIGNAL_STATUS_CHANGED,
1036 		                                           G_CALLBACK(window_status_changed),
1037 		                                           iapp);
1038 		iapp->sig_show_menu     = g_signal_connect(G_OBJECT(iapp->default_app),
1039 		                                           WINDOW_MENUS_SIGNAL_SHOW_MENU,
1040 		                                           G_CALLBACK(window_show_menu),
1041 		                                           iapp);
1042 		iapp->sig_a11y_update   = g_signal_connect(G_OBJECT(iapp->default_app),
1043 		                                           WINDOW_MENUS_SIGNAL_A11Y_UPDATE,
1044 		                                           G_CALLBACK(window_a11y_update),
1045 		                                           iapp);
1046 	}
1047 
1048 	/* show the entries that we're swapping in */
1049 	indicator_object_set_visible (INDICATOR_OBJECT(iapp), TRUE);
1050 
1051 		/* Set up initial state for new entries if needed */
1052 	if (iapp->default_app != NULL &&
1053             window_menus_get_status (iapp->default_app) != DBUSMENU_STATUS_NORMAL) {
1054 		window_status_changed (iapp->default_app,
1055 		                       window_menus_get_status (iapp->default_app),
1056 		                       iapp);
1057 	}
1058 
1059 	return;
1060 }
1061 
1062 /* Recieve the signal that the window being shown
1063    has now changed. */
1064 static void
1065 active_window_changed (BamfMatcher * matcher, BamfView * oldview, BamfView * newview, gpointer user_data)
1066 {
1067 	BamfWindow * window = NULL;
1068 
1069 	if (newview != NULL) {
1070 		window = BAMF_WINDOW(newview);
1071 		if (window == NULL) {
1072 			g_warning("Active window changed to View thats not a window.");
1073 		}
1074 	} else {
1075 		g_debug("Active window is: NULL");
1076 	}
1077 
1078 	IndicatorAppmenu * appmenu = INDICATOR_APPMENU(user_data);
1079 
1080 	if (window != NULL && bamf_window_get_window_type(window) == BAMF_WINDOW_DESKTOP) {
1081 		g_debug("Switching to menus from desktop");
1082 		switch_default_app(appmenu, NULL, NULL);
1083 		return;
1084 	}
1085 
1086 	WindowMenus * menus = NULL;
1087 	guint32 xid = 0;
1088 
1089 	while (window != NULL && menus == NULL) {
1090 		xid = bamf_window_get_xid(window);
1091 	
1092 		menus = g_hash_table_lookup(appmenu->apps, GUINT_TO_POINTER(xid));
1093 
1094 		if (menus == NULL) {
1095 			g_debug("Looking for parent window on XID %d", xid);
1096 			window = bamf_window_get_transient(window);
1097 		}
1098 	}
1099 
1100 	/* Note: We're not using window here, but re-casting the
1101 	   newwindow variable.  Which means we stay where we were
1102 	   but get the menus from parents. */
1103 	g_debug("Switching to menus from XID %d", xid);
1104 	if (newview != NULL) {
1105 		switch_default_app(appmenu, menus, BAMF_WINDOW(newview));
1106 	} else {
1107 		switch_default_app(appmenu, menus, NULL);
1108 	}
1109 
1110 	return;
1111 }
1112 
1113 /* Respond to the menus being destroyed.  We need to deregister
1114    and make sure we weren't being shown.  */
1115 static void
1116 menus_destroyed (GObject * menus, gpointer user_data)
1117 {
1118 	gboolean reload_menus = FALSE;
1119 	WindowMenus * wm = WINDOW_MENUS(menus);
1120 	IndicatorAppmenu * iapp = INDICATOR_APPMENU(user_data);
1121 
1122 	guint32 xid = window_menus_get_xid(wm);
1123 	g_return_if_fail(xid != 0);
1124 
1125 	g_hash_table_steal(iapp->apps, GUINT_TO_POINTER(xid));
1126 
1127 	g_debug("Removing menus for %d", xid);
1128 
1129 	if (iapp->desktop_menu == wm) {
1130 		iapp->desktop_menu = NULL;
1131 		determine_new_desktop(iapp);
1132 		if (iapp->default_app == NULL && iapp->active_window == NULL) {
1133 			reload_menus = TRUE;
1134 		}
1135 	}
1136 
1137 	/* If we're it, let's remove ourselves and BAMF will probably
1138 	   give us a new entry in a bit. */
1139 	if (iapp->default_app == wm) {
1140 		reload_menus = TRUE;
1141 	}
1142 
1143 	if (reload_menus) {
1144 		switch_default_app(iapp, NULL, NULL);
1145 	}
1146 
1147 	return;
1148 }
1149 
1150 /* A new window wishes to register it's windows with us */
1151 static GVariant *
1152 register_window (IndicatorAppmenu * iapp, guint windowid, const gchar * objectpath,
1153                  const gchar * sender)
1154 {
1155 	g_debug("Registering window ID %d with path %s from %s", windowid, objectpath, sender);
1156 
1157 	/* Shouldn't do anything, but let's be sure */
1158 	g_hash_table_remove(iapp->destruction_timers, GUINT_TO_POINTER(windowid));
1159 
1160 	if (g_hash_table_lookup(iapp->apps, GUINT_TO_POINTER(windowid)) == NULL && windowid != 0) {
1161 		WindowMenus * wm = window_menus_new(windowid, sender, objectpath);
1162 		g_return_val_if_fail(wm != NULL, FALSE);
1163 
1164 		g_hash_table_insert(iapp->apps, GUINT_TO_POINTER(windowid), wm);
1165 
1166 		emit_signal(iapp, "WindowRegistered",
1167 		            g_variant_new("(uso)", windowid, sender, objectpath));
1168 
1169 		gpointer pdesktop = g_hash_table_lookup(iapp->desktop_windows, GUINT_TO_POINTER(windowid));
1170 		if (pdesktop != NULL) {
1171 			determine_new_desktop(iapp);
1172 		}
1173 
1174 		/* Note: Does not cause ref */
1175 		BamfWindow * win = bamf_matcher_get_active_window(iapp->matcher);
1176 
1177 		active_window_changed(iapp->matcher, NULL, BAMF_VIEW(win), iapp);
1178 	} else {
1179 		if (windowid == 0) {
1180 			g_warning("Can't build windows for a NULL window ID %d with path %s from %s", windowid, objectpath, sender);
1181 		} else {
1182 			g_warning("Already have a menu for window ID %d with path %s from %s, unregistering that one", windowid, objectpath, sender);
1183 			unregister_window(iapp, windowid);
1184 
1185 			/* NOTE: So we're doing a lookup here.  That seems pretty useless
1186 			   now doesn't it.  It's for a good reason.  We're going recursive
1187 			   with a pretty complex set of functions we want to ensure that
1188 			   we're not going to end up infinitely recursive otherwise things
1189 			   could go really bad. */
1190 			if (g_hash_table_lookup(iapp->apps, GUINT_TO_POINTER(windowid)) == NULL) {
1191 				return register_window(iapp, windowid, objectpath, sender);
1192 			}
1193 
1194 			g_warning("Unable to unregister window!");
1195 		}
1196 	}
1197 
1198 	return g_variant_new("()");
1199 }
1200 
1201 /* Kindly remove an entry from our DB */
1202 static GVariant *
1203 unregister_window (IndicatorAppmenu * iapp, guint windowid)
1204 {
1205 	g_debug("Unregistering: %d", windowid);
1206 	g_return_val_if_fail(IS_INDICATOR_APPMENU(iapp), NULL);
1207 	g_return_val_if_fail(iapp->matcher != NULL, NULL);
1208 
1209 	/* Make sure we don't destroy it later */
1210 	g_hash_table_remove(iapp->destruction_timers, GUINT_TO_POINTER(windowid));
1211 
1212 	/* If it's a desktop window remove it from that table as well */
1213 	g_hash_table_remove(iapp->desktop_windows, GUINT_TO_POINTER(windowid));
1214 
1215 	/* Now let's see if we've got a WM object for it then
1216 	   we need to mark it as destroyed and unreference to
1217 	   actually destroy it. */
1218 	gpointer wm = g_hash_table_lookup(iapp->apps, GUINT_TO_POINTER(windowid));
1219 	if (wm != NULL) {
1220 		GObject * wmo = G_OBJECT(wm);
1221 
1222 		/* Using destroyed so that if the menus are shown
1223 		   they'll be switch and the current window gets
1224 		   updated as well. */
1225 		menus_destroyed(wmo, iapp);
1226 		g_object_unref(wmo);
1227 	}
1228 
1229 	return NULL;
1230 }
1231 
1232 /* Grab the menu information for a specific window */
1233 static GVariant *
1234 get_menu_for_window (IndicatorAppmenu * iapp, guint windowid, GError ** error)
1235 {
1236 	WindowMenus * wm = NULL;
1237 
1238 	if (windowid == 0) {
1239 		wm = iapp->default_app;
1240 	} else {
1241 		wm = WINDOW_MENUS(g_hash_table_lookup(iapp->apps, GUINT_TO_POINTER(windowid)));
1242 	}
1243 
1244 	if (wm == NULL) {
1245 		g_set_error_literal(error, error_quark(), ERROR_WINDOW_NOT_FOUND, "Window not found");
1246 		return NULL;
1247 	}
1248 
1249 	return g_variant_new("(so)", window_menus_get_address(wm),
1250 	                     window_menus_get_path(wm));
1251 }
1252 
1253 /* Get all the menus we have */
1254 static GVariant *
1255 get_menus (IndicatorAppmenu * iapp, GError ** error)
1256 {
1257 	if (iapp->apps == NULL) {
1258 		g_set_error_literal(error, error_quark(), ERROR_NO_APPLICATIONS, "No applications are registered");
1259 		return NULL;
1260 	}
1261 
1262 	GVariantBuilder builder;
1263 	GHashTableIter hash_iter;
1264 	gpointer value;
1265 
1266 	g_variant_builder_init (&builder, G_VARIANT_TYPE("a(uso)"));
1267 	g_hash_table_iter_init (&hash_iter, iapp->apps);
1268 	while (g_hash_table_iter_next (&hash_iter, NULL, &value)) {
1269 		if (value != NULL) {
1270 			WindowMenus * wm = WINDOW_MENUS(value);
1271 			g_variant_builder_add (&builder, "(uso)",
1272 			                       window_menus_get_xid(wm),
1273 			                       window_menus_get_address(wm),
1274 			                       window_menus_get_path(wm));
1275 		}
1276 	}
1277 
1278 	return g_variant_new ("(a(uso))", &builder);
1279 }
1280 
1281 /* A method has been called from our dbus inteface.  Figure out what it
1282    is and dispatch it. */
1283 static void
1284 bus_method_call (GDBusConnection * connection, const gchar * sender,
1285                  const gchar * path, const gchar * interface,
1286                  const gchar * method, GVariant * params,
1287                  GDBusMethodInvocation * invocation, gpointer user_data)
1288 {
1289 	IndicatorAppmenu * iapp = INDICATOR_APPMENU(user_data);
1290 	GVariant * retval = NULL;
1291 	GError * error = NULL;
1292 
1293 	if (g_strcmp0(method, "RegisterWindow") == 0) {
1294 		guint32 xid;
CID 10732 - PW.PARAMETER_HIDDEN
declaration hides parameter "path" (declared at line 1285)
1295 		const gchar * path;
1296 		g_variant_get(params, "(u&o)", &xid, &path);
1297 		retval = register_window(iapp, xid, path, sender);
1298 	} else if (g_strcmp0(method, "UnregisterWindow") == 0) {
1299 		guint32 xid;
1300 		g_variant_get(params, "(u)", &xid);
1301 		retval = unregister_window(iapp, xid);
1302 	} else if (g_strcmp0(method, "GetMenuForWindow") == 0) {
1303 		guint32 xid;
1304 		g_variant_get(params, "(u)", &xid);
1305 		retval = get_menu_for_window(iapp, xid, &error);
1306 	} else if (g_strcmp0(method, "GetMenus") == 0) {
1307 		retval = get_menus(iapp, &error);
1308 	} else {
1309 		g_warning("Calling method '%s' on the indicator service and it's unknown", method);
1310 	}
1311 
1312 	if (error != NULL) {
1313 		g_dbus_method_invocation_return_dbus_error(invocation,
1314 		                                           "com.canonical.AppMenu.Error",
1315 		                                           error->message);
1316 		g_error_free(error);
1317 	} else {
1318 		g_dbus_method_invocation_return_value(invocation, retval);
1319 	}
1320 	return;
1321 }
1322 
1323 /* Pass up the entry added event */
1324 static void
1325 window_entry_added (WindowMenus * mw, IndicatorObjectEntry * entry, gpointer user_data)
1326 {
1327 	g_signal_emit_by_name(G_OBJECT(user_data), INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED, entry);
1328 	return;
1329 }
1330 
1331 /* Pass up the entry removed event */
1332 static void
1333 window_entry_removed (WindowMenus * mw, IndicatorObjectEntry * entry, gpointer user_data)
1334 {
1335 	g_signal_emit_by_name(G_OBJECT(user_data), INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED, entry);
1336 	return;
1337 }
1338 
1339 /* Pass up the status changed event */
1340 static void
1341 window_status_changed (WindowMenus * mw, DbusmenuStatus status, IndicatorAppmenu * iapp)
1342 {
1343 	gboolean show_now = (status == DBUSMENU_STATUS_NOTICE);
1344 	GList * entry_head, * entries;
1345 
1346 	entry_head = indicator_object_get_entries(INDICATOR_OBJECT(iapp));
1347 
1348 	for (entries = entry_head; entries != NULL; entries = g_list_next(entries)) {
1349 		IndicatorObjectEntry * entry = (IndicatorObjectEntry *)entries->data;
1350 		g_signal_emit(G_OBJECT(iapp), INDICATOR_OBJECT_SIGNAL_SHOW_NOW_CHANGED_ID, 0, entry, show_now);
1351 	}
1352 
1353 	return;
1354 }
1355 
1356 /* Pass up the show menu event */
1357 static void
1358 window_show_menu (WindowMenus * mw, IndicatorObjectEntry * entry, guint timestamp, gpointer user_data)
1359 {
1360 	g_signal_emit_by_name(G_OBJECT(user_data), INDICATOR_OBJECT_SIGNAL_MENU_SHOW, entry, timestamp);
1361 	return;
1362 }
1363 
1364 /* Pass up the accessible string update */
1365 static void
1366 window_a11y_update (WindowMenus * mw, IndicatorObjectEntry * entry, gpointer user_data)
1367 {
1368 	g_signal_emit_by_name(G_OBJECT(user_data), INDICATOR_OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE, entry);
1369 	return;
1370 }
1371 
1372 /**********************
1373   DEBUG INTERFACE
1374  **********************/
1375 
1376 /* Builds the error quark if we need it, otherwise just
1377    returns the same value */
1378 static GQuark
1379 error_quark (void)
1380 {
1381 	static GQuark error_quark = 0;
1382 
1383 	if (error_quark == 0) {
1384 		error_quark = g_quark_from_static_string("indicator-appmenu");
1385 	}
1386 
1387 	return error_quark;
1388 }