~indicator-applet-developers/indicator-appmenu/trunk.13.04

« back to all changes in this revision

Viewing changes to src/window-menu-model.c

  • Committer: Ted Gould
  • Date: 2012-03-21 14:46:04 UTC
  • mfrom: (166.3.59 gmenumodel-menus)
  • Revision ID: ted@gould.cx-20120321144604-r4limdyast215291
Adding GMenuModel support for menus

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2012 Canonical Limited
 
3
 *
 
4
 * This library is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU Lesser General Public
 
6
 * License as published by the Free Software Foundation; either
 
7
 * version 2 of the licence, or (at your option) any later version.
 
8
 *
 
9
 * This library is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * Lesser General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU Lesser General Public
 
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 
16
 *
 
17
 * Author: Ted Gould <ted.gould@canonical.com>
 
18
 */
 
19
 
 
20
#ifdef HAVE_CONFIG_H
 
21
#include "config.h"
 
22
#endif
 
23
 
 
24
#include <libbamf/libbamf.h>
 
25
#include <gio/gio.h>
 
26
#include <gtk/gtk.h>
 
27
#include <glib/gi18n.h>
 
28
#include <gio/gdesktopappinfo.h>
 
29
 
 
30
#include "window-menu-model.h"
 
31
#include "gactionmuxer.h"
 
32
#include "gtkmodelmenu.h"
 
33
 
 
34
struct _WindowMenuModelPrivate {
 
35
        guint xid;
 
36
 
 
37
        /* All the actions */
 
38
        GActionMuxer * action_mux;
 
39
        GtkAccelGroup * accel_group;
 
40
 
 
41
        /* Application Menu */
 
42
        GDBusMenuModel * app_menu_model;
 
43
        IndicatorObjectEntry application_menu;
 
44
        gboolean has_application_menu;
 
45
 
 
46
        /* Window Menus */
 
47
        GDBusMenuModel * win_menu_model;
 
48
        GtkMenu * win_menu;
 
49
        gulong win_menu_insert;
 
50
        gulong win_menu_remove;
 
51
};
 
52
 
 
53
#define WINDOW_MENU_MODEL_GET_PRIVATE(o) \
 
54
(G_TYPE_INSTANCE_GET_PRIVATE ((o), WINDOW_MENU_MODEL_TYPE, WindowMenuModelPrivate))
 
55
 
 
56
/* Base class stuff */
 
57
static void                window_menu_model_class_init (WindowMenuModelClass *klass);
 
58
static void                window_menu_model_init       (WindowMenuModel *self);
 
59
static void                window_menu_model_dispose    (GObject *object);
 
60
static void                window_menu_model_finalize   (GObject *object);
 
61
 
 
62
/* Window Menu subclassin' */
 
63
static GList *             get_entries                  (WindowMenu * wm);
 
64
static guint               get_location                 (WindowMenu * wm,
 
65
                                                         IndicatorObjectEntry * entry);
 
66
static WindowMenuStatus    get_status                   (WindowMenu * wm);
 
67
static gboolean            get_error_state              (WindowMenu * wm);
 
68
static guint               get_xid                      (WindowMenu * wm);
 
69
 
 
70
/* GLib boilerplate */
 
71
G_DEFINE_TYPE (WindowMenuModel, window_menu_model, WINDOW_MENU_TYPE);
 
72
 
 
73
/* Prefixes to the action muxer */
 
74
#define ACTION_MUX_PREFIX_WIN  "win"
 
75
#define ACTION_MUX_PREFIX_APP  "app"
 
76
 
 
77
/* Entry data on the menuitem */
 
78
#define ENTRY_DATA  "window-menu-model-menuitem-entry"
 
79
 
 
80
static void
 
81
window_menu_model_class_init (WindowMenuModelClass *klass)
 
82
{
 
83
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
84
 
 
85
        g_type_class_add_private (klass, sizeof (WindowMenuModelPrivate));
 
86
 
 
87
        object_class->dispose = window_menu_model_dispose;
 
88
        object_class->finalize = window_menu_model_finalize;
 
89
 
 
90
        WindowMenuClass * wm_class = WINDOW_MENU_CLASS(klass);
 
91
 
 
92
        wm_class->get_entries = get_entries;
 
93
        wm_class->get_location = get_location;
 
94
        wm_class->get_status = get_status;
 
95
        wm_class->get_error_state = get_error_state;
 
96
        wm_class->get_xid = get_xid;
 
97
 
 
98
        return;
 
99
}
 
100
 
 
101
static void
 
102
window_menu_model_init (WindowMenuModel *self)
 
103
{
 
104
        self->priv = WINDOW_MENU_MODEL_GET_PRIVATE(self);
 
105
 
 
106
        self->priv->action_mux = g_action_muxer_new();
 
107
        self->priv->accel_group = gtk_accel_group_new();
 
108
 
 
109
        return;
 
110
}
 
111
 
 
112
static void
 
113
window_menu_model_dispose (GObject *object)
 
114
{
 
115
        WindowMenuModel * menu = WINDOW_MENU_MODEL(object);
 
116
 
 
117
        g_clear_object(&menu->priv->action_mux);
 
118
        g_clear_object(&menu->priv->accel_group);
 
119
 
 
120
        /* Application Menu */
 
121
        g_clear_object(&menu->priv->app_menu_model);
 
122
        g_clear_object(&menu->priv->application_menu.label);
 
123
        g_clear_object(&menu->priv->application_menu.menu);
 
124
 
 
125
        /* Window Menus */
 
126
        if (menu->priv->win_menu_insert != 0) {
 
127
                g_signal_handler_disconnect(menu->priv->win_menu, menu->priv->win_menu_insert);
 
128
                menu->priv->win_menu_insert = 0;
 
129
        }
 
130
 
 
131
        if (menu->priv->win_menu_remove != 0) {
 
132
                g_signal_handler_disconnect(menu->priv->win_menu, menu->priv->win_menu_remove);
 
133
                menu->priv->win_menu_remove = 0;
 
134
        }
 
135
 
 
136
        g_clear_object(&menu->priv->win_menu_model);
 
137
        g_clear_object(&menu->priv->win_menu);
 
138
 
 
139
        G_OBJECT_CLASS (window_menu_model_parent_class)->dispose (object);
 
140
        return;
 
141
}
 
142
 
 
143
static void
 
144
window_menu_model_finalize (GObject *object)
 
145
{
 
146
 
 
147
        G_OBJECT_CLASS (window_menu_model_parent_class)->finalize (object);
 
148
        return;
 
149
}
 
150
 
 
151
/* Adds the application menu and turns the whole thing into an object
 
152
   entry that can be used elsewhere */
 
153
static void
 
154
add_application_menu (WindowMenuModel * menu, const gchar * appname, GMenuModel * model)
 
155
{
 
156
        g_return_if_fail(G_IS_MENU_MODEL(model));
 
157
 
 
158
        menu->priv->app_menu_model = g_object_ref(model);
 
159
 
 
160
        if (appname != NULL) {
 
161
                menu->priv->application_menu.label = GTK_LABEL(gtk_label_new(appname));
 
162
        } else {
 
163
                menu->priv->application_menu.label = GTK_LABEL(gtk_label_new(_("Unknown Application Name")));
 
164
        }
 
165
        g_object_ref_sink(menu->priv->application_menu.label);
 
166
        gtk_widget_show(GTK_WIDGET(menu->priv->application_menu.label));
 
167
 
 
168
        menu->priv->application_menu.menu = GTK_MENU(gtk_model_menu_create_menu(model, G_ACTION_OBSERVABLE(menu->priv->action_mux), menu->priv->accel_group));
 
169
 
 
170
        gtk_widget_show(GTK_WIDGET(menu->priv->application_menu.menu));
 
171
        g_object_ref_sink(menu->priv->application_menu.menu);
 
172
 
 
173
        menu->priv->has_application_menu = TRUE;
 
174
 
 
175
        return;
 
176
}
 
177
 
 
178
/* Find the label in a GTK MenuItem */
 
179
GtkLabel *
 
180
mi_find_label (GtkWidget * mi)
 
181
{
 
182
        if (GTK_IS_LABEL(mi)) {
 
183
                return GTK_LABEL(mi);
 
184
        }
 
185
 
 
186
        GtkLabel * retval = NULL;
 
187
 
 
188
        if (GTK_IS_CONTAINER(mi)) {
 
189
                GList * children = gtk_container_get_children(GTK_CONTAINER(mi));
 
190
                GList * child = children;
 
191
 
 
192
                while (child != NULL && retval == NULL) {
 
193
                        if (GTK_IS_WIDGET(child->data)) {
 
194
                                retval = mi_find_label(GTK_WIDGET(child->data));
 
195
                        }
 
196
                        child = g_list_next(child);
 
197
                }
 
198
 
 
199
                g_list_free(children);
 
200
        }
 
201
 
 
202
        return retval;
 
203
}
 
204
 
 
205
/* Find the icon in a GTK MenuItem */
 
206
GtkImage *
 
207
mi_find_icon (GtkWidget * mi)
 
208
{
 
209
        if (GTK_IS_IMAGE(mi)) {
 
210
                return GTK_IMAGE(mi);
 
211
        }
 
212
 
 
213
        GtkImage * retval = NULL;
 
214
 
 
215
        if (GTK_IS_CONTAINER(mi)) {
 
216
                GList * children = gtk_container_get_children(GTK_CONTAINER(mi));
 
217
                GList * child = children;
 
218
 
 
219
                while (child != NULL && retval == NULL) {
 
220
                        if (GTK_IS_WIDGET(child->data)) {
 
221
                                retval = mi_find_icon(GTK_WIDGET(child->data));
 
222
                        }
 
223
                        child = g_list_next(child);
 
224
                }
 
225
 
 
226
                g_list_free(children);
 
227
        }
 
228
 
 
229
        return retval;
 
230
}
 
231
 
 
232
/* Check the menu and make sure we return it if it's a menu
 
233
   all proper like that */
 
234
GtkMenu *
 
235
mi_find_menu (GtkMenuItem * mi)
 
236
{
 
237
        GtkWidget * retval = gtk_menu_item_get_submenu(mi);
 
238
        if (GTK_IS_MENU(retval)) {
 
239
                return GTK_MENU(retval);
 
240
        } else {
 
241
                return NULL;
 
242
        }
 
243
}
 
244
 
 
245
typedef struct _WindowMenuEntry WindowMenuEntry;
 
246
struct _WindowMenuEntry {
 
247
        IndicatorObjectEntry entry;
 
248
 
 
249
        GtkMenuItem * gmi;
 
250
 
 
251
        gulong label_sig;
 
252
        gulong sensitive_sig;
 
253
        gulong visible_sig;
 
254
};
 
255
 
 
256
/* Destroy and unref the items of the object entry */
 
257
static void
 
258
entry_object_free (gpointer inentry)
 
259
{
 
260
        WindowMenuEntry * entry = (WindowMenuEntry *)inentry;
 
261
 
 
262
        if (entry->label_sig != 0) {
 
263
                g_signal_handler_disconnect(entry->gmi, entry->label_sig);
 
264
        }
 
265
 
 
266
        if (entry->sensitive_sig != 0) {
 
267
                g_signal_handler_disconnect(entry->gmi, entry->sensitive_sig);
 
268
        }
 
269
 
 
270
        if (entry->visible_sig != 0) {
 
271
                g_signal_handler_disconnect(entry->gmi, entry->visible_sig);
 
272
        }
 
273
 
 
274
        g_clear_object(&entry->entry.label);
 
275
        g_clear_object(&entry->entry.image);
 
276
        g_clear_object(&entry->entry.menu);
 
277
 
 
278
        g_free(entry);
 
279
        return;
 
280
}
 
281
 
 
282
/* Sync the menu label changing to the label object */
 
283
static void
 
284
entry_label_notify (GObject * obj, GParamSpec * pspec, gpointer user_data)
 
285
{
 
286
        g_return_if_fail(GTK_IS_MENU_ITEM(obj));
 
287
 
 
288
        GtkMenuItem * gmi = GTK_MENU_ITEM(obj);
 
289
        WindowMenuEntry * entry = (WindowMenuEntry *)user_data;
 
290
 
 
291
        if (entry->entry.label != NULL) {
 
292
                const gchar * label = gtk_menu_item_get_label(gmi);
 
293
                gtk_label_set_label(entry->entry.label, label);
 
294
        }
 
295
 
 
296
        return;
 
297
}
 
298
 
 
299
/* Watch for visible changes and ensure they can be picked up by the
 
300
   indicator object host */
 
301
static void
 
302
entry_visible_notify (GObject * obj, GParamSpec * pspec, gpointer user_data)
 
303
{
 
304
        g_return_if_fail(GTK_IS_WIDGET(obj));
 
305
        GtkWidget * widget = GTK_WIDGET(obj);
 
306
        WindowMenuEntry * entry = (WindowMenuEntry *)user_data;
 
307
        gboolean visible = gtk_widget_get_visible(widget);
 
308
 
 
309
        if (entry->entry.label != NULL) {
 
310
                gtk_widget_set_visible(GTK_WIDGET(entry->entry.label), visible);
 
311
        }
 
312
 
 
313
        if (entry->entry.image != NULL) {
 
314
                gtk_widget_set_visible(GTK_WIDGET(entry->entry.image), visible);
 
315
        }
 
316
 
 
317
        return;
 
318
}
 
319
 
 
320
/* Watch for sensitive changes and ensure they can be picked up by the
 
321
   indicator object host */
 
322
static void
 
323
entry_sensitive_notify (GObject * obj, GParamSpec * pspec, gpointer user_data)
 
324
{
 
325
        g_return_if_fail(GTK_IS_WIDGET(obj));
 
326
        GtkWidget * widget = GTK_WIDGET(obj);
 
327
        WindowMenuEntry * entry = (WindowMenuEntry *)user_data;
 
328
        gboolean sensitive = gtk_widget_get_sensitive(widget);
 
329
 
 
330
        if (entry->entry.label != NULL) {
 
331
                gtk_widget_set_sensitive(GTK_WIDGET(entry->entry.label), sensitive);
 
332
        }
 
333
 
 
334
        if (entry->entry.image != NULL) {
 
335
                gtk_widget_set_sensitive(GTK_WIDGET(entry->entry.image), sensitive);
 
336
        }
 
337
 
 
338
        return;
 
339
}
 
340
 
 
341
/* Put an entry on a menu item */
 
342
static void
 
343
entry_on_menuitem (WindowMenuModel * menu, GtkMenuItem * gmi)
 
344
{
 
345
        WindowMenuEntry * entry = g_new0(WindowMenuEntry, 1);
 
346
 
 
347
        entry->gmi = gmi;
 
348
 
 
349
        entry->entry.label = mi_find_label(GTK_WIDGET(gmi));
 
350
        entry->entry.image = mi_find_icon(GTK_WIDGET(gmi));
 
351
        entry->entry.menu = mi_find_menu(gmi);
 
352
 
 
353
        if (entry->entry.label == NULL && entry->entry.image == NULL) {
 
354
                const gchar * label = gtk_menu_item_get_label(gmi);
 
355
                if (label == NULL) {
 
356
                        g_warning("Item doesn't have a label or an image, aborting");
 
357
                        return;
 
358
                }
 
359
 
 
360
                entry->entry.label = GTK_LABEL(gtk_label_new(label));
 
361
                gtk_widget_show(GTK_WIDGET(entry->entry.label));
 
362
                entry->label_sig = g_signal_connect(G_OBJECT(gmi), "notify::label", G_CALLBACK(entry_label_notify), entry->entry.label);
 
363
        }
 
364
 
 
365
        if (entry->entry.label != NULL) {
 
366
                g_object_ref_sink(entry->entry.label);
 
367
        }
 
368
 
 
369
        if (entry->entry.image != NULL) {
 
370
                g_object_ref_sink(entry->entry.image);
 
371
        }
 
372
 
 
373
        if (entry->entry.menu != NULL) {
 
374
                g_object_ref_sink(entry->entry.menu);
 
375
        }
 
376
 
 
377
        entry->sensitive_sig = g_signal_connect(G_OBJECT(gmi), "notify::sensitive", G_CALLBACK(entry_sensitive_notify), entry);
 
378
        entry->visible_sig = g_signal_connect(G_OBJECT(gmi), "notify::visible", G_CALLBACK(entry_visible_notify), entry);
 
379
 
 
380
        g_object_set_data_full(G_OBJECT(gmi), ENTRY_DATA, entry, entry_object_free);
 
381
 
 
382
        return;
 
383
}
 
384
 
 
385
/* A child item was added to a menu we're watching.  Let's try to integrate it. */
 
386
static void
 
387
item_inserted_cb (GtkContainer *menu,
 
388
                  GtkWidget    *widget,
 
389
#ifdef HAVE_GTK3
 
390
                  gint          position,
 
391
#endif
 
392
                  gpointer      data)
 
393
{
 
394
        if (g_object_get_data(G_OBJECT(widget), ENTRY_DATA) == NULL) {
 
395
                entry_on_menuitem(WINDOW_MENU_MODEL(data), GTK_MENU_ITEM(widget));
 
396
        }
 
397
 
 
398
        if (g_object_get_data(G_OBJECT(widget), ENTRY_DATA) != NULL) {
 
399
                g_signal_emit_by_name(data, WINDOW_MENU_SIGNAL_ENTRY_ADDED, g_object_get_data(G_OBJECT(widget), ENTRY_DATA));
 
400
        }
 
401
 
 
402
        return;
 
403
}
 
404
 
 
405
/* A child item was removed from a menu we're watching. */
 
406
static void
 
407
item_removed_cb (GtkContainer *menu, GtkWidget *widget, gpointer data)
 
408
{
 
409
        g_signal_emit_by_name(data, WINDOW_MENU_SIGNAL_ENTRY_REMOVED, g_object_get_data(G_OBJECT(widget), ENTRY_DATA));
 
410
        return;
 
411
}
 
412
 
 
413
/* Adds the window menu and turns it into a set of IndicatorObjectEntries
 
414
   that can be used elsewhere */
 
415
static void
 
416
add_window_menu (WindowMenuModel * menu, GMenuModel * model)
 
417
{
 
418
        menu->priv->win_menu_model = g_object_ref(model);
 
419
 
 
420
        menu->priv->win_menu = GTK_MENU(gtk_model_menu_create_menu(model, G_ACTION_OBSERVABLE(menu->priv->action_mux), menu->priv->accel_group));
 
421
        g_assert(menu->priv->win_menu != NULL);
 
422
        g_object_ref_sink(menu->priv->win_menu);
 
423
 
 
424
        menu->priv->win_menu_insert = g_signal_connect(G_OBJECT (menu->priv->win_menu),
 
425
#ifdef HAVE_GTK3
 
426
                "insert",
 
427
#else
 
428
                "child-added",
 
429
#endif
 
430
                G_CALLBACK (item_inserted_cb),
 
431
                menu);
 
432
        menu->priv->win_menu_remove = g_signal_connect (G_OBJECT (menu->priv->win_menu),
 
433
                "remove",
 
434
                G_CALLBACK (item_removed_cb),
 
435
                menu);
 
436
 
 
437
        GList * children = gtk_container_get_children(GTK_CONTAINER(menu->priv->win_menu));
 
438
        GList * child;
 
439
        for (child = children; child != NULL; child = g_list_next(child)) {
 
440
                GtkMenuItem * gmi = GTK_MENU_ITEM(child->data);
 
441
 
 
442
                if (gmi == NULL) {
 
443
                        continue;
 
444
                }
 
445
 
 
446
                entry_on_menuitem(menu, gmi);
 
447
        }
 
448
        g_list_free(children);
 
449
 
 
450
        return;
 
451
}
 
452
 
 
453
/* Builds the menu model from the window for the application */
 
454
WindowMenuModel *
 
455
window_menu_model_new (BamfApplication * app, BamfWindow * window)
 
456
{
 
457
        g_return_val_if_fail(BAMF_IS_APPLICATION(app), NULL);
 
458
        g_return_val_if_fail(BAMF_IS_WINDOW(window), NULL);
 
459
 
 
460
        WindowMenuModel * menu = g_object_new(WINDOW_MENU_MODEL_TYPE, NULL);
 
461
 
 
462
        menu->priv->xid = bamf_window_get_xid(window);
 
463
 
 
464
        gchar *unique_bus_name;
 
465
        gchar *app_menu_object_path;
 
466
        gchar *menubar_object_path;
 
467
        gchar *application_object_path;
 
468
        gchar *window_object_path;
 
469
        GDBusConnection *session;
 
470
 
 
471
        unique_bus_name = bamf_window_get_utf8_prop (window, "_GTK_UNIQUE_BUS_NAME");
 
472
 
 
473
        if (unique_bus_name == NULL) {
 
474
                /* If this isn't set, we won't get very far... */
 
475
                return NULL;
 
476
        }
 
477
 
 
478
        app_menu_object_path = bamf_window_get_utf8_prop (window, "_GTK_APP_MENU_OBJECT_PATH");
 
479
        menubar_object_path = bamf_window_get_utf8_prop (window, "_GTK_MENUBAR_OBJECT_PATH");
 
480
        application_object_path = bamf_window_get_utf8_prop (window, "_GTK_APPLICATION_OBJECT_PATH");
 
481
        window_object_path = bamf_window_get_utf8_prop (window, "_GTK_WINDOW_OBJECT_PATH");
 
482
 
 
483
        session = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
 
484
 
 
485
        /* Setup actions */
 
486
        if (application_object_path != NULL) {
 
487
                g_action_muxer_insert(menu->priv->action_mux, ACTION_MUX_PREFIX_APP, G_ACTION_GROUP(g_dbus_action_group_get (session, unique_bus_name, application_object_path)));
 
488
        }
 
489
 
 
490
        if (window_object_path != NULL) {
 
491
                g_action_muxer_insert(menu->priv->action_mux, ACTION_MUX_PREFIX_WIN, G_ACTION_GROUP(g_dbus_action_group_get (session, unique_bus_name, window_object_path)));
 
492
        }
 
493
 
 
494
        /* Build us some menus */
 
495
        if (app_menu_object_path != NULL) {
 
496
                const gchar * desktop_path = bamf_application_get_desktop_file(app);
 
497
                gchar * app_name = NULL;
 
498
 
 
499
                if (desktop_path != NULL) {
 
500
                        GDesktopAppInfo * desktop = g_desktop_app_info_new_from_filename(desktop_path);
 
501
 
 
502
                        if (desktop != NULL) {
 
503
                                app_name = g_strdup(g_app_info_get_name(G_APP_INFO(desktop)));
 
504
 
 
505
                                g_object_unref(desktop);
 
506
                        }
 
507
                }
 
508
 
 
509
                GMenuModel * model = G_MENU_MODEL(g_dbus_menu_model_get (session, unique_bus_name, app_menu_object_path));
 
510
 
 
511
                add_application_menu(menu, app_name, model);
 
512
 
 
513
                g_object_unref(model);
 
514
                g_free(app_name);
 
515
        }
 
516
 
 
517
        if (menubar_object_path != NULL) {
 
518
                GMenuModel * model = G_MENU_MODEL(g_dbus_menu_model_get (session, unique_bus_name, menubar_object_path));
 
519
 
 
520
                add_window_menu(menu, model);
 
521
 
 
522
                g_object_unref(model);
 
523
        }
 
524
 
 
525
        /* when the action groups change, we could end up having items
 
526
         * enabled/disabled.  how to deal with that?
 
527
         */
 
528
 
 
529
        g_free (unique_bus_name);
 
530
        g_free (app_menu_object_path);
 
531
        g_free (menubar_object_path);
 
532
        g_free (application_object_path);
 
533
        g_free (window_object_path);
 
534
 
 
535
        g_object_unref (session);
 
536
 
 
537
        return menu;
 
538
}
 
539
 
 
540
/* Get the list of entries */
 
541
static GList *
 
542
get_entries (WindowMenu * wm)
 
543
{
 
544
        g_return_val_if_fail(IS_WINDOW_MENU_MODEL(wm), NULL);
 
545
        WindowMenuModel * menu = WINDOW_MENU_MODEL(wm);
 
546
 
 
547
        GList * ret = NULL;
 
548
 
 
549
        if (menu->priv->has_application_menu) {
 
550
                ret = g_list_append(ret, &menu->priv->application_menu);
 
551
        }
 
552
 
 
553
        if (menu->priv->win_menu != NULL) {
 
554
                GList * children = gtk_container_get_children(GTK_CONTAINER(menu->priv->win_menu));
 
555
                GList * child;
 
556
                for (child = children; child != NULL; child = g_list_next(child)) {
 
557
                        gpointer entry = g_object_get_data(child->data, ENTRY_DATA);
 
558
 
 
559
                        if (entry == NULL) {
 
560
                                /* Try to build the entry, it is possible (but unlikely) that
 
561
                                   we could beat the signal that this isn't created.  So we'll
 
562
                                   just handle that race here */
 
563
                                entry_on_menuitem(menu, GTK_MENU_ITEM(child->data));
 
564
                                entry = g_object_get_data(child->data, ENTRY_DATA);
 
565
                        }
 
566
 
 
567
                        if (entry != NULL) {
 
568
                                ret = g_list_append(ret, entry);
 
569
                        }
 
570
                }
 
571
 
 
572
                g_list_free(children);
 
573
        }
 
574
 
 
575
        return ret;
 
576
}
 
577
 
 
578
/* Find the location of an entry */
 
579
static guint
 
580
get_location (WindowMenu * wm, IndicatorObjectEntry * entry)
 
581
{
 
582
        g_return_val_if_fail(IS_WINDOW_MENU_MODEL(wm), 0);
 
583
        WindowMenuModel * menu = WINDOW_MENU_MODEL(wm);
 
584
 
 
585
        gboolean found = FALSE;
 
586
        guint pos = 0;
 
587
 
 
588
        if (menu->priv->has_application_menu) {
 
589
                if (entry == &menu->priv->application_menu) {
 
590
                        pos = 0;
 
591
                        found = TRUE;
 
592
                } else {
 
593
                        /* We need to put a shift in if there is an application
 
594
                           menu and we're not looking for that one */
 
595
                        pos = 1;
 
596
                }
 
597
        }
 
598
 
 
599
        if (menu->priv->win_menu != NULL) {
 
600
                GList * children = gtk_container_get_children(GTK_CONTAINER(menu->priv->win_menu));
 
601
                GList * child;
 
602
                for (child = children; child != NULL; child = g_list_next(child), pos++) {
 
603
                        gpointer lentry = g_object_get_data(child->data, ENTRY_DATA);
 
604
 
 
605
                        if (entry == lentry) {
 
606
                                found = TRUE;
 
607
                                break;
 
608
                        }
 
609
                }
 
610
 
 
611
                g_list_free(children);
 
612
        }
 
613
 
 
614
        if (!found) {
 
615
                /* NOTE: Not printing any of the values here because there's
 
616
                   a pretty good chance that they're not valid.  Let's not crash
 
617
                   things here. */
 
618
                g_warning("Unable to find entry: %p", entry);
 
619
        }
 
620
 
 
621
        return pos;
 
622
}
 
623
 
 
624
/* Get's the status of the application to whether underlines should be
 
625
   shown to the application.  GMenuModel doesn't give us this info. */
 
626
static WindowMenuStatus
 
627
get_status (WindowMenu * wm)
 
628
{
 
629
        return WINDOW_MENU_STATUS_NORMAL;
 
630
}
 
631
 
 
632
/* Says whether the application is in error, GMenuModel doesn't give us this
 
633
   information on the app */
 
634
static gboolean
 
635
get_error_state (WindowMenu * wm)
 
636
{
 
637
        return FALSE;
 
638
}
 
639
 
 
640
/* Get the XID of this guy */
 
641
static guint
 
642
get_xid (WindowMenu * wm)
 
643
{
 
644
        g_return_val_if_fail(IS_WINDOW_MENU_MODEL(wm), 0);
 
645
        return WINDOW_MENU_MODEL(wm)->priv->xid;
 
646
}