~ubuntu-branches/ubuntu/trusty/unity-greeter/trusty

« back to all changes in this revision

Viewing changes to .pc/do-not-read-password.patch/src/menubar.vala

  • Committer: Package Import Robot
  • Author(s): Michael Terry
  • Date: 2013-03-15 14:04:08 UTC
  • mfrom: (1.1.22)
  • Revision ID: package-import@ubuntu.com-20130315140408-m2kwmrmxtyn0j9hk
Tags: 13.04.2-0ubuntu1
* New upstream release.
  - Fix duplicate entries showing for multiple users on the same remote
    login service.
  - Add custom indicator support for system administrators (LP: #1155157)
* debian/control:
  - Switch Vcs-Bzr to point at Unity Greeter trunk, since we are inlining
    the packaging
  - Use debhelper 9
* debian/rules:
  - Use upstream ./autogen.sh for autoreconf
* debian/patches/do-not-read-password.patch,
  debian/patches/move-nm-applet.patch,
  debian/patches/spawn-gsd-directly.patch:
  - Drop, included upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: Vala; indent-tabs-mode: nil; tab-width: 4 -*-
2
 
 *
3
 
 * Copyright (C) 2011,2012 Canonical Ltd
4
 
 *
5
 
 * This program is free software: you can redistribute it and/or modify
6
 
 * it under the terms of the GNU General Public License version 3 as
7
 
 * published by the Free Software Foundation.
8
 
 *
9
 
 * This program 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
12
 
 * GNU General Public License for more details.
13
 
 *
14
 
 * You should have received a copy of the GNU General Public License
15
 
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 
 *
17
 
 * Authors: Robert Ancell <robert.ancell@canonical.com>
18
 
 *          Michael Terry <michael.terry@canonical.com>
19
 
 */
20
 
 
21
 
private class IndicatorMenuItem : Gtk.MenuItem
22
 
{
23
 
    public unowned Indicator.ObjectEntry entry;
24
 
    private Gtk.Box hbox;
25
 
 
26
 
    public IndicatorMenuItem (Indicator.ObjectEntry entry)
27
 
    {
28
 
        this.entry = entry;
29
 
        this.hbox = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 3);
30
 
        this.add (this.hbox);
31
 
        this.hbox.show ();
32
 
 
33
 
        if (entry.label != null)
34
 
        {
35
 
            entry.label.show.connect (this.visibility_changed_cb);
36
 
            entry.label.hide.connect (this.visibility_changed_cb);
37
 
            hbox.pack_start (entry.label, false, false, 0);
38
 
        }
39
 
        if (entry.image != null)
40
 
        {
41
 
            entry.image.show.connect (visibility_changed_cb);
42
 
            entry.image.hide.connect (visibility_changed_cb);
43
 
            hbox.pack_start (entry.image, false, false, 0);
44
 
        }
45
 
        if (entry.accessible_desc != null)
46
 
            get_accessible ().set_name (entry.accessible_desc);
47
 
        if (entry.menu != null)
48
 
            set_submenu (entry.menu as Gtk.Widget);
49
 
 
50
 
        if (has_visible_child ())
51
 
            show ();
52
 
    }
53
 
 
54
 
    public bool has_visible_child ()
55
 
    {
56
 
        return (entry.image != null && entry.image.get_visible ()) ||
57
 
               (entry.label != null && entry.label.get_visible ());
58
 
    }
59
 
 
60
 
    public void visibility_changed_cb (Gtk.Widget widget)
61
 
    {
62
 
        visible = has_visible_child ();
63
 
    }
64
 
}
65
 
 
66
 
public class MenuBar : Gtk.MenuBar
67
 
{
68
 
    public Background? background { get; construct; default = null; }
69
 
    public bool high_contrast { get; private set; default = false; }
70
 
    public Gtk.Window? keyboard_window { get; private set; default = null; }
71
 
    public Gtk.AccelGroup? accel_group { get; construct; }
72
 
 
73
 
    private static const int HEIGHT = 24;
74
 
 
75
 
    public MenuBar (Background bg, Gtk.AccelGroup ag)
76
 
    {
77
 
        Object (background: bg, accel_group: ag);
78
 
    }
79
 
 
80
 
    public void set_layouts (List <LightDM.Layout> layouts)
81
 
    {
82
 
        if (layouts == null)
83
 
            layouts.append (LightDM.get_layout ()); /* default layout */
84
 
 
85
 
        var default_item = recreate_menu (layouts);
86
 
 
87
 
        /* Activate first item */
88
 
        if (default_item != null)
89
 
        {
90
 
            if (default_item.active) /* Started active, have to manually trigger callback */
91
 
                layout_toggled_cb (default_item);
92
 
            else
93
 
                default_item.active = true; /* will trigger callback to do rest of work */
94
 
        }
95
 
    }
96
 
 
97
 
    public override bool draw (Cairo.Context c)
98
 
    {
99
 
        if (background != null)
100
 
        {
101
 
            int x, y;
102
 
            background.translate_coordinates (this, 0, 0, out x, out y);
103
 
            c.save ();
104
 
            c.translate (x, y);
105
 
            background.draw_full (c, Background.DrawFlags.NONE);
106
 
            c.restore ();
107
 
        }
108
 
 
109
 
        c.set_source_rgb (0.1, 0.1, 0.1);
110
 
        c.paint_with_alpha (0.4);
111
 
 
112
 
        foreach (var child in get_children ())
113
 
        {
114
 
            propagate_draw (child, c);
115
 
        }
116
 
 
117
 
        return false;
118
 
    }
119
 
 
120
 
    /* Due to LP #973922 the keyboard has to be loaded after the main window
121
 
     * is shown and given focus. Therefore we don't enable the active state
122
 
     * until now.
123
 
     */
124
 
    public void set_keyboard_state ()
125
 
    {
126
 
        onscreen_keyboard_item.set_active (UGSettings.get_boolean (UGSettings.KEY_ONSCREEN_KEYBOARD));
127
 
    }
128
 
 
129
 
    private string default_theme_name;
130
 
    private List<Indicator.Object> indicator_objects;
131
 
    private Gtk.MenuItem keyboard_item;
132
 
    private Gtk.CheckMenuItem high_contrast_item;
133
 
    private Gtk.Label keyboard_label = null;
134
 
    private Pid keyboard_pid = 0;
135
 
    private Pid reader_pid = 0;
136
 
    private Gtk.CheckMenuItem onscreen_keyboard_item;
137
 
 
138
 
    construct
139
 
    {
140
 
        Gtk.Settings.get_default ().get ("gtk-theme-name", out default_theme_name);
141
 
 
142
 
        pack_direction = Gtk.PackDirection.RTL;
143
 
 
144
 
        var label = new Gtk.Label (Posix.utsname ().nodename);
145
 
        label.show ();
146
 
        var hostname_item = new Gtk.MenuItem ();
147
 
        hostname_item.add (label);
148
 
        hostname_item.sensitive = false;
149
 
        hostname_item.right_justified = true;
150
 
        hostname_item.show ();
151
 
        append (hostname_item);
152
 
 
153
 
        /* Hack to get a label showing on the menubar */
154
 
        label.ensure_style ();
155
 
        var fg = label.get_style_context ().get_color (Gtk.StateFlags.NORMAL);
156
 
        label.override_color (Gtk.StateFlags.INSENSITIVE, fg);
157
 
 
158
 
        /* Prevent dragging the window by the menubar */
159
 
        try
160
 
        {
161
 
            var style = new Gtk.CssProvider ();
162
 
            style.load_from_data ("* {-GtkWidget-window-dragging: false;}", -1);
163
 
            get_style_context ().add_provider (style, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
164
 
        }
165
 
        catch (Error e)
166
 
        {
167
 
            debug ("Internal error loading menubar style: %s", e.message);
168
 
        }
169
 
 
170
 
        setup_indicators ();
171
 
 
172
 
        UnityGreeter.singleton.starting_session.connect (cleanup);
173
 
    }
174
 
 
175
 
    private void close_pid (ref Pid pid)
176
 
    {
177
 
        if (pid != 0)
178
 
        {
179
 
            Posix.kill (pid, Posix.SIGTERM);
180
 
            int status;
181
 
            Posix.waitpid (pid, out status, 0);
182
 
            pid = 0;
183
 
        }
184
 
    }
185
 
 
186
 
    public void cleanup ()
187
 
    {
188
 
        close_pid (ref keyboard_pid);
189
 
        close_pid (ref reader_pid);
190
 
    }
191
 
 
192
 
    public override void get_preferred_height (out int min, out int nat)
193
 
    {
194
 
        min = HEIGHT;
195
 
        nat = HEIGHT;
196
 
    }
197
 
 
198
 
    private void greeter_set_env (string key, string val)
199
 
    {
200
 
        GLib.Environment.set_variable (key, val, true);
201
 
 
202
 
        /* And also set it in the DBus activation environment so that any
203
 
         * indicator services pick it up. */
204
 
        try
205
 
        {
206
 
            var proxy = new GLib.DBusProxy.for_bus_sync (GLib.BusType.SESSION,
207
 
                                                         GLib.DBusProxyFlags.NONE, null,
208
 
                                                         "org.freedesktop.DBus",
209
 
                                                         "/org/freedesktop/DBus",
210
 
                                                         "org.freedesktop.DBus",
211
 
                                                         null);
212
 
 
213
 
            var builder = new GLib.VariantBuilder (GLib.VariantType.ARRAY);
214
 
            builder.add ("{ss}", key, val);
215
 
 
216
 
            proxy.call_sync ("UpdateActivationEnvironment", new GLib.Variant ("(a{ss})", builder), GLib.DBusCallFlags.NONE, -1, null);
217
 
        }
218
 
        catch (Error e)
219
 
        {
220
 
            warning ("Could not get set environment for indicators: %s", e.message);
221
 
            return;
222
 
        }
223
 
    }
224
 
 
225
 
    private Gtk.Widget make_a11y_indicator ()
226
 
    {
227
 
        var a11y_item = new Gtk.MenuItem ();
228
 
        var hbox = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 3);
229
 
        hbox.show ();
230
 
        a11y_item.add (hbox);
231
 
        var image = new Gtk.Image.from_file (Path.build_filename (Config.PKGDATADIR, "a11y.svg"));
232
 
        image.show ();
233
 
        hbox.add (image);
234
 
        a11y_item.show ();
235
 
        a11y_item.set_submenu (new Gtk.Menu () as Gtk.Widget);
236
 
        onscreen_keyboard_item = new Gtk.CheckMenuItem.with_label (_("Onscreen keyboard"));
237
 
        onscreen_keyboard_item.toggled.connect (keyboard_toggled_cb);
238
 
        onscreen_keyboard_item.show ();
239
 
        unowned Gtk.Menu submenu = a11y_item.submenu;
240
 
        submenu.append (onscreen_keyboard_item);
241
 
        high_contrast_item = new Gtk.CheckMenuItem.with_label (_("High Contrast"));
242
 
        high_contrast_item.toggled.connect (high_contrast_toggled_cb);
243
 
        high_contrast_item.add_accelerator ("activate", accel_group, Gdk.KEY_h, Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE);
244
 
        high_contrast_item.show ();
245
 
        submenu.append (high_contrast_item);
246
 
        high_contrast_item.set_active (UGSettings.get_boolean (UGSettings.KEY_HIGH_CONTRAST));
247
 
        var item = new Gtk.CheckMenuItem.with_label (_("Screen Reader"));
248
 
        item.toggled.connect (screen_reader_toggled_cb);
249
 
        item.add_accelerator ("activate", accel_group, Gdk.KEY_s, Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE);
250
 
        item.show ();
251
 
        submenu.append (item);
252
 
        item.set_active (UGSettings.get_boolean (UGSettings.KEY_SCREEN_READER));
253
 
        return a11y_item;
254
 
    }
255
 
 
256
 
    private void layout_toggled_cb (Gtk.CheckMenuItem item)
257
 
    {
258
 
        if (!item.active)
259
 
            return;
260
 
 
261
 
        var layout = item.get_data<LightDM.Layout> ("unity-greeter-layout");
262
 
        if (layout == null)
263
 
            return;
264
 
 
265
 
        var desc = layout.short_description;
266
 
        if (desc == null || desc == "")
267
 
        {
268
 
            var parts = layout.name.split ("\t", 2);
269
 
            if (parts[0] == layout.name)
270
 
                desc = layout.name;
271
 
            else
272
 
            {
273
 
                /* Lookup parent layout, get its short_description */
274
 
                var parent_layout = UnityGreeter.get_layout_by_name (parts[0]);
275
 
                if (parent_layout.short_description == null ||
276
 
                    parent_layout.short_description == "")
277
 
                    desc = parts[0];
278
 
                else
279
 
                    desc = parent_layout.short_description;
280
 
            }
281
 
        }
282
 
        keyboard_label.label = desc;
283
 
 
284
 
        if (UnityGreeter.singleton.test_mode)
285
 
            debug ("Setting layout to %s", layout.name);
286
 
        else
287
 
            LightDM.set_layout (layout);
288
 
    }
289
 
 
290
 
    private static int cmp_layout (LightDM.Layout? a, LightDM.Layout? b)
291
 
    {
292
 
        if (a == null && b == null)
293
 
            return 0;
294
 
        else if (a == null)
295
 
            return 1;
296
 
        else if (b == null)
297
 
            return -1;
298
 
        else
299
 
        {
300
 
            /* Use a dumb, ascii comparison for now.  If it turns out that some
301
 
               descriptions can be in unicode, we'll have to use libicu's collation
302
 
               algorithms. */
303
 
            return strcmp (a.description, b.description);
304
 
        }
305
 
    }
306
 
 
307
 
    private Gtk.Widget make_keyboard_indicator ()
308
 
    {
309
 
        keyboard_item = new Gtk.MenuItem ();
310
 
        var hbox = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 3);
311
 
        hbox.show ();
312
 
        keyboard_item.add (hbox);
313
 
        var image = new Gtk.Image.from_icon_name ("keyboard", Gtk.IconSize.LARGE_TOOLBAR);
314
 
        image.show ();
315
 
        hbox.add (image);
316
 
        keyboard_label = new Gtk.Label ("");
317
 
        keyboard_label.width_chars = 2;
318
 
        keyboard_label.show ();
319
 
        hbox.add (keyboard_label);
320
 
        keyboard_item.show ();
321
 
 
322
 
        return keyboard_item;
323
 
    }
324
 
 
325
 
    private void setup_indicators ()
326
 
    {
327
 
        /* Set indicators to run with reduced functionality */
328
 
        greeter_set_env ("INDICATOR_GREETER_MODE", "1");
329
 
 
330
 
        /* Don't allow virtual file systems? */
331
 
        greeter_set_env ("GIO_USE_VFS", "local");
332
 
        greeter_set_env ("GVFS_DISABLE_FUSE", "1");
333
 
 
334
 
        /* Hint to have gnome-settings-daemon run in greeter mode */
335
 
        greeter_set_env ("RUNNING_UNDER_GDM", "1");
336
 
 
337
 
        var keyboard_item = make_keyboard_indicator ();
338
 
        insert (keyboard_item, (int) get_children ().length () - 1);
339
 
 
340
 
        var a11y_item = make_a11y_indicator ();
341
 
        insert (a11y_item, (int) get_children ().length () - 1);
342
 
 
343
 
        debug ("LANG=%s LANGUAGE=%s", Environment.get_variable ("LANG"), Environment.get_variable ("LANGUAGE"));
344
 
        string[] filenames = { Path.build_filename (Config.INDICATORDIR, "libsession.so"),
345
 
                               Path.build_filename (Config.INDICATORDIR, "libdatetime.so"),
346
 
                               Path.build_filename (Config.INDICATORDIR, "libpower.so"),
347
 
                               Path.build_filename (Config.INDICATORDIR, "libsoundmenu.so"),
348
 
                               Path.build_filename (Config.INDICATORDIR, "libapplication.so") };
349
 
        foreach (var filename in filenames)
350
 
        {
351
 
            var io = new Indicator.Object.from_file (filename);
352
 
            if (io == null)
353
 
                continue;
354
 
 
355
 
            indicator_objects.append (io);
356
 
            io.entry_added.connect (indicator_added_cb);
357
 
            io.entry_removed.connect (indicator_removed_cb);
358
 
            foreach (var entry in io.get_entries ())
359
 
                indicator_added_cb (io, entry);
360
 
        }
361
 
        debug ("LANG=%s LANGUAGE=%s", Environment.get_variable ("LANG"), Environment.get_variable ("LANGUAGE"));
362
 
    }
363
 
 
364
 
    private void keyboard_toggled_cb (Gtk.CheckMenuItem item)
365
 
    {
366
 
        /* FIXME: The below would be sufficient if gnome-session were running
367
 
         * to notice and run a screen keyboard in /etc/xdg/autostart...  But
368
 
         * since we're not running gnome-session, we hardcode onboard here. */
369
 
        /* var settings = new Settings ("org.gnome.desktop.a11y.applications");*/
370
 
        /*settings.set_boolean ("screen-keyboard-enabled", item.active);*/
371
 
 
372
 
        UGSettings.set_boolean (UGSettings.KEY_ONSCREEN_KEYBOARD, item.active);
373
 
 
374
 
        if (keyboard_window == null)
375
 
        {
376
 
            int id = 0;
377
 
 
378
 
            try
379
 
            {
380
 
                string[] argv;
381
 
                int onboard_stdout_fd;
382
 
 
383
 
                Shell.parse_argv ("onboard --xid", out argv);
384
 
                Process.spawn_async_with_pipes (null,
385
 
                                                argv,
386
 
                                                null,
387
 
                                                SpawnFlags.SEARCH_PATH,
388
 
                                                null,
389
 
                                                out keyboard_pid,
390
 
                                                null,
391
 
                                                out onboard_stdout_fd,
392
 
                                                null);
393
 
                var f = FileStream.fdopen (onboard_stdout_fd, "r");
394
 
                var stdout_text = new char[1024];
395
 
                if (f.gets (stdout_text) != null)
396
 
                    id = int.parse ((string) stdout_text);
397
 
 
398
 
            }
399
 
            catch (Error e)
400
 
            {
401
 
                warning ("Error setting up keyboard: %s", e.message);
402
 
                return;
403
 
            }
404
 
 
405
 
            var keyboard_socket = new Gtk.Socket ();
406
 
            keyboard_socket.show ();
407
 
            keyboard_window = new Gtk.Window ();
408
 
            keyboard_window.accept_focus = false;
409
 
            keyboard_window.focus_on_map = false;
410
 
            keyboard_window.add (keyboard_socket);
411
 
            Gtk.socket_add_id (keyboard_socket, id);
412
 
 
413
 
            /* Put keyboard at the bottom of the screen */
414
 
            var screen = get_screen ();
415
 
            var monitor = screen.get_monitor_at_window (get_window ());
416
 
            Gdk.Rectangle geom;
417
 
            screen.get_monitor_geometry (monitor, out geom);
418
 
            keyboard_window.move (geom.x, geom.y + geom.height - 200);
419
 
            keyboard_window.resize (geom.width, 200);
420
 
        }
421
 
 
422
 
        keyboard_window.visible = item.active;
423
 
    }
424
 
 
425
 
    /* Returns menuitem for first layout in list */
426
 
    private Gtk.RadioMenuItem recreate_menu (List <LightDM.Layout> layouts_in)
427
 
    {
428
 
        var submenu = new Gtk.Menu ();
429
 
        keyboard_item.set_submenu (submenu as Gtk.Widget);
430
 
 
431
 
        var layouts = layouts_in.copy ();
432
 
        layouts.sort (cmp_layout);
433
 
 
434
 
        Gtk.RadioMenuItem? default_item = null;
435
 
        Gtk.RadioMenuItem? last_item = null;
436
 
        foreach (var layout in layouts)
437
 
        {
438
 
            var item = new Gtk.RadioMenuItem.with_label (last_item == null ? null : last_item.get_group (), layout.description);
439
 
            last_item = item;
440
 
 
441
 
            item.show ();
442
 
 
443
 
            if (layouts_in.data == layout)
444
 
                default_item = item;
445
 
 
446
 
            /* LightDM does not change its layout list during its lifetime, so this is safe */
447
 
            item.set_data ("unity-greeter-layout", layout);
448
 
 
449
 
            item.toggled.connect (layout_toggled_cb);
450
 
 
451
 
            submenu.append (item);
452
 
        }
453
 
 
454
 
        return default_item;
455
 
    }
456
 
 
457
 
    private void high_contrast_toggled_cb (Gtk.CheckMenuItem item)
458
 
    {
459
 
        var settings = Gtk.Settings.get_default ();
460
 
        if (item.active)
461
 
            settings.set ("gtk-theme-name", "HighContrastInverse");
462
 
        else
463
 
            settings.set ("gtk-theme-name", default_theme_name);
464
 
        high_contrast = item.active;
465
 
        UGSettings.set_boolean (UGSettings.KEY_HIGH_CONTRAST, high_contrast);
466
 
    }
467
 
 
468
 
    private void screen_reader_toggled_cb (Gtk.CheckMenuItem item)
469
 
    {
470
 
        /* FIXME: The below would be sufficient if gnome-session were running
471
 
         * to notice and run a screen reader in /etc/xdg/autostart...  But
472
 
         * since we're not running gnome-session, we hardcode orca here.
473
 
        /*var settings = new Settings ("org.gnome.desktop.a11y.applications");*/
474
 
        /*settings.set_boolean ("screen-reader-enabled", item.active);*/
475
 
 
476
 
        UGSettings.set_boolean (UGSettings.KEY_SCREEN_READER, item.active);
477
 
 
478
 
        /* Hardcoded orca: */
479
 
        if (item.active)
480
 
        {
481
 
            try
482
 
            {
483
 
                string[] argv;
484
 
                Shell.parse_argv ("orca --replace --no-setup --disable splash-window,", out argv);
485
 
                Process.spawn_async (null,
486
 
                                     argv,
487
 
                                     null,
488
 
                                     SpawnFlags.SEARCH_PATH,
489
 
                                     null,
490
 
                                     out reader_pid);
491
 
            }
492
 
            catch (Error e)
493
 
            {
494
 
                warning ("Failed to run Orca: %s", e.message);
495
 
            }
496
 
        }
497
 
        else
498
 
            close_pid (ref reader_pid);
499
 
    }
500
 
 
501
 
    private uint get_indicator_index (Indicator.Object object)
502
 
    {
503
 
        uint index = 0;
504
 
 
505
 
        foreach (var io in indicator_objects)
506
 
        {
507
 
            if (io == object)
508
 
                return index;
509
 
            index++;
510
 
        }
511
 
 
512
 
        return index;
513
 
    }
514
 
 
515
 
    private Indicator.Object? get_indicator_object_from_entry (Indicator.ObjectEntry entry)
516
 
    {
517
 
        foreach (var io in indicator_objects)
518
 
        {
519
 
            foreach (var e in io.get_entries ())
520
 
            {
521
 
                if (e == entry)
522
 
                    return io;
523
 
            }
524
 
        }
525
 
 
526
 
        return null;
527
 
    }
528
 
 
529
 
    private void indicator_added_cb (Indicator.Object object, Indicator.ObjectEntry entry)
530
 
    {
531
 
        var index = get_indicator_index (object);
532
 
        var pos = 0;
533
 
        foreach (var child in get_children ())
534
 
        {
535
 
            if (!(child is IndicatorMenuItem))
536
 
                break;
537
 
 
538
 
            var menuitem = (IndicatorMenuItem) child;
539
 
            var child_object = get_indicator_object_from_entry (menuitem.entry);
540
 
            var child_index = get_indicator_index (child_object);
541
 
            if (child_index > index)
542
 
                break;
543
 
            pos++;
544
 
        }
545
 
 
546
 
        debug ("Adding indicator object %p at position %d", entry, pos);
547
 
 
548
 
        var menuitem = new IndicatorMenuItem (entry);
549
 
        insert (menuitem, pos);
550
 
    }
551
 
 
552
 
    private void indicator_removed_cb (Indicator.Object object, Indicator.ObjectEntry entry)
553
 
    {
554
 
        debug ("Removing indicator object %p", entry);
555
 
 
556
 
        foreach (var child in get_children ())
557
 
        {
558
 
            var menuitem = (IndicatorMenuItem) child;
559
 
            if (menuitem.entry == entry)
560
 
            {
561
 
                remove (child);
562
 
                return;
563
 
            }
564
 
        }
565
 
 
566
 
        warning ("Indicator object %p not in menubar", entry);
567
 
    }
568
 
}