~ubuntu-branches/ubuntu/natty/thunderbird/natty-security

« back to all changes in this revision

Viewing changes to debian/globalmenu/src/uGlobalMenuBar.cpp

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2012-06-15 01:54:24 UTC
  • mfrom: (1.10.3)
  • Revision ID: package-import@ubuntu.com-20120615015424-eii885av2qzwmz5h
Tags: 13.0.1+build1-0ubuntu0.11.04.1
* New upstream stable release (THUNDERBIRD_13_0_1_BUILD1)
  - see LP: #1007556 for USN information

* Update globalmenu-extension to v3.2.3
  - Reduce our memory footprint a bit, which wasn't really a lot anyway
  - Avoid the use of the component manager for accessing commonly used
    services, where "commonly used" means "accessed when building every
    menu item". This should save some CPU cycles when building or
    refreshing menus
  - Try to recycle menuitems when they are removed from a menu by
    adding contiguous blocks of removed items to a "free list" which
    is emptied asynchronously, and reusing the items in this list when
    new items are added in place of the removed items. This means that
    menus which fully refresh on opening no longer alter the menu
    structure, but instead just update properties on existing nodes.
    This has a few benefits:
    + With no layout changes, unity-panel-service doesn't request
      the entire menu structure, which significantly reduces dbus traffic
      and makes it much faster to refresh the menu contents
    + The size of the menu doesn't change when it is refreshed, which
      eliminates the flicker that used to occur when opening some menus
  - Remove all use of the global observer service for sending our own
    internal notifications around
  - Get rid of a static initializer
  - Don't support older than Thunderbird 11
  - Fix some GError leaks
  - Hide the internal menu when creating a native menu, rather than
    waiting for confirmation that the native menu is registered
    successfully. We don't try to create a native menu if we don't
    find a menu service to register the menu with anyway
  - Keep menu contents updated whilst the menu is open, rather than
    just whilst it is opening
  - Fix LP: #915888 - Formatting toolbar menu entry is inverted
* Refresh build-depends:
  - Bump minimum GTK version to 2.14 as we build with GIO support
  - Add minimum requirement for glib (2.18)
  - Drop libidl-dev, this doesn't appear to be needed now
  - Bump minimum NSPR version to 4.9.0 for --enable-system-nspr builds
  - Bump minimum sqlite version to 3.7.10 for --enable-system-sqlite
    builds
  - Bump minimum NSS version to 3.13.2 for --enable-system-nss builds
* Clean up the file exclude list and add comments for excluded files
  - update debian/build/create-tarball.py
* Make it easy to run Thunderbird in valgrind for builds that are compiled
  with explicit valgrind support
  - update debian/thunderbird.sh.in
* Refresh patches:
  - update debian/patches/revert-bmo621446-investigation.patch
  - update debian/patches/dont-include-hyphenation-patterns.patch
* Drop patches fixed upstream:
  - remove debian/patches/use-menubar-text-colour-on-tabbar.patch
  - remove debian/patches/no-sps-profiler-on-unsupported-archs.patch
  - remove debian/patches/distro-locale-searchplugins.patch
  - remove debian/patches/avoid-dbus-roundtrip-for-httpchannel.patch
  - update debian/patches/series
* Bump debhelper compat to 7
  - update debian/apport/blacklist.in
  - update debian/appoty/source_thunderbird.py.in
  - update debian/compat
  - update debian/config/mozconfig.in
  - update debian/control.in
  - update debian/rules
  - update debian/thunderbird-dev.install.in
  - update debian/thunderbird-dev.links.in
  - update debian/thunderbird-globalmenu.dirs.in
  - update debian/thunderbird-gnome-support.install.in
  - update debian/thunderbird.dirs.in
  - update debian/thunderbird.install.in
  - update debian/thunderbird.links.in
  - update debian/thunderbird.lintian-overrides.in
  - update debian/thunderbird.sh.in
* Use "general.useragent.locale" to select the searchengine locale
  - update debian/patches/distro-locale-searchplugins.patch
  - add debian/patches/dont-override-general-useragent-locale.patch
  - update debian/patches/series
* Drop no-dynamic-nss-softokn.patch. This patch has no documentation and
  it doesn't look like it's actually useful for anything
* Apport hook improvements:
  - Add support for reporting preference defaults that are set by extensions
  - When reporting preferences, record the source of each preference
  - Report plugin packages for plugins that are installed with the
    package manager
  - Add some addon manager related prefs to the whitelist
  - Display additional metadata in the extensions report
  - Take "default-to-compatible" in to account when determining whether
    the user is running incompatible addons
  - Attach submitted crash ID's to bug reports
  - Report if files in the profile folder have broken permissions
* Update compare-locales to 0.9.5
* Fix for NSS libs not being signed, breaking FIPS
  - update debian/rules
* Update StartupWMClass to the correct name
  - update debian/thunderbird.desktop.in
  - update debian/rules

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
/* ***** BEGIN LICENSE BLOCK *****
 
3
 *       Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
4
 *
 
5
 * The contents of this file are subject to the Mozilla Public License Version
 
6
 * 1.1 (the "License"); you may not use this file except in compliance with
 
7
 * the License. You may obtain a copy of the License at
 
8
 * http://www.mozilla.org/MPL/
 
9
 * 
 
10
 * Software distributed under the License is distributed on an "AS IS" basis,
 
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
12
 * for the specific language governing rights and limitations under the
 
13
 * License.
 
14
 *
 
15
 * The Original Code is globalmenu-extension.
 
16
 *
 
17
 * The Initial Developer of the Original Code is
 
18
 * Canonical Ltd.
 
19
 * Portions created by the Initial Developer are Copyright (C) 2010
 
20
 * the Initial Developer. All Rights Reserved.
 
21
 *
 
22
 * Contributor(s):
 
23
 * Chris Coulson <chris.coulson@canonical.com>
 
24
 *
 
25
 * Alternatively, the contents of this file may be used under the terms of
 
26
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
27
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
28
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
29
 * of those above. If you wish to allow use of your version of this file only
 
30
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
31
 * use your version of this file under the terms of the MPL, indicate your
 
32
 * decision by deleting the provisions above and replace them with the notice
 
33
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
34
 * the provisions above, a recipient may use your version of this file under
 
35
 * the terms of any one of the MPL, the GPL or the LGPL.
 
36
 * 
 
37
 * ***** END LICENSE BLOCK ***** */
 
38
 
 
39
#include <nsDebug.h>
 
40
#include <nsIObserver.h>
 
41
#include <nsIWidget.h>
 
42
#include <nsIDOMWindow.h>
 
43
#include <nsIXULWindow.h>
 
44
#include <nsIInterfaceRequestorUtils.h>
 
45
#include <nsIDocShell.h>
 
46
#if 1
 
47
# include <nsIDOMNSEvent.h>
 
48
#endif
 
49
#include <nsIPrefBranch.h>
 
50
#include <nsIDOMKeyEvent.h>
 
51
#include <nsIDOMEventListener.h>
 
52
#include <nsICaseConversion.h>
 
53
 
 
54
#include <glib-object.h>
 
55
#include <gdk/gdk.h>
 
56
#include <gdk/gdkx.h>
 
57
 
 
58
#include "uGlobalMenuBar.h"
 
59
#include "uGlobalMenu.h"
 
60
#include "uGlobalMenuUtils.h"
 
61
#include "uGlobalMenuService.h"
 
62
#include "uWidgetAtoms.h"
 
63
 
 
64
#include "uDebug.h"
 
65
 
 
66
#define MODIFIER_SHIFT    1
 
67
#define MODIFIER_CONTROL  2
 
68
#define MODIFIER_ALT      4
 
69
#define MODIFIER_META     8
 
70
 
 
71
NS_IMPL_ISUPPORTS1(uGlobalMenuBarListener, nsIDOMEventListener)
 
72
 
 
73
NS_IMETHODIMP
 
74
uGlobalMenuBarListener::HandleEvent(nsIDOMEvent *aEvent)
 
75
{
 
76
  nsAutoString type;
 
77
  nsresult rv = aEvent->GetType(type);
 
78
  if (NS_FAILED(rv)) {
 
79
    NS_WARNING("Failed to determine type of event");
 
80
    return rv;
 
81
  }
 
82
 
 
83
  if (type.EqualsLiteral("focus")) {
 
84
    mMenuBar->Focus();
 
85
  } else if (type.EqualsLiteral("blur")) {
 
86
    mMenuBar->Blur();
 
87
  } else if (type.EqualsLiteral("keypress")) {
 
88
    rv = mMenuBar->KeyPress(aEvent);
 
89
  } else if (type.EqualsLiteral("keydown")) {
 
90
    rv = mMenuBar->KeyDown(aEvent);
 
91
  } else if (type.EqualsLiteral("keyup")) {
 
92
    rv = mMenuBar->KeyUp(aEvent);
 
93
  }
 
94
 
 
95
  return rv;
 
96
}
 
97
 
 
98
GtkWidget*
 
99
uGlobalMenuBar::WidgetToGTKWindow(nsIWidget *aWidget)
 
100
{
 
101
  // Get the main GDK drawing window from our nsIWidget
 
102
  GdkWindow *window = static_cast<GdkWindow *>(aWidget->GetNativeData(NS_NATIVE_WINDOW));
 
103
  if (!window)
 
104
    return nsnull;
 
105
 
 
106
  // Get the widget for the main drawing window, which should be a MozContainer
 
107
  gpointer user_data = nsnull;
 
108
  gdk_window_get_user_data(window, &user_data);
 
109
  if (!user_data || !GTK_IS_CONTAINER(user_data))
 
110
    return nsnull;
 
111
 
 
112
  return gtk_widget_get_toplevel(GTK_WIDGET(user_data));
 
113
}
 
114
 
 
115
bool
 
116
uGlobalMenuBar::AppendMenuObject(uGlobalMenuObject *menu)
 
117
{
 
118
  gboolean res = dbusmenu_menuitem_child_append(mDbusMenuItem,
 
119
                                                menu->GetDbusMenuItem());
 
120
  return res && mMenuObjects.AppendElement(menu);
 
121
}
 
122
 
 
123
bool
 
124
uGlobalMenuBar::InsertMenuObjectAt(uGlobalMenuObject *menu,
 
125
                                   PRUint32 index)
 
126
{
 
127
  gboolean res = dbusmenu_menuitem_child_add_position(mDbusMenuItem,
 
128
                                                      menu->GetDbusMenuItem(),
 
129
                                                      index);
 
130
  return res && mMenuObjects.InsertElementAt(index, menu);
 
131
}
 
132
 
 
133
bool
 
134
uGlobalMenuBar::RemoveMenuObjectAt(PRUint32 index)
 
135
{
 
136
  NS_ASSERTION(index < mMenuObjects.Length(), "Invalid index");
 
137
  if (index >= mMenuObjects.Length()) {
 
138
    return false;
 
139
  }
 
140
 
 
141
  gboolean res = dbusmenu_menuitem_child_delete(mDbusMenuItem,
 
142
                                       mMenuObjects[index]->GetDbusMenuItem());
 
143
  mMenuObjects.RemoveElementAt(index);
 
144
 
 
145
  return !!res;
 
146
}
 
147
 
 
148
nsresult
 
149
uGlobalMenuBar::Build()
 
150
{
 
151
  PRUint32 count = mContent->GetChildCount();
 
152
 
 
153
  for (PRUint32 i = 0; i < count; i++) {
 
154
    nsIContent *menuContent = mContent->GetChildAt(i);
 
155
    uGlobalMenuObject *newItem =
 
156
      NewGlobalMenuItem(static_cast<uGlobalMenuObject *>(this),
 
157
                        mListener, menuContent, this);
 
158
    bool res = false;
 
159
    if (newItem) {
 
160
      res = AppendMenuObject(newItem);
 
161
    }
 
162
    NS_ASSERTION(res, "Failed to append menuitem. Our menu representation is out-of-sync with reality");
 
163
    if (!res) {
 
164
      // XXX: Is there anything else we should do here?
 
165
      return NS_ERROR_FAILURE;
 
166
    }
 
167
  }
 
168
 
 
169
  return NS_OK;
 
170
}
 
171
 
 
172
void
 
173
uGlobalMenuBar::InitializeDbusMenuItem()
 
174
{
 
175
  if (!mDbusMenuItem) {
 
176
    mDbusMenuItem = dbusmenu_menuitem_new();
 
177
  }
 
178
}
 
179
 
 
180
nsresult
 
181
uGlobalMenuBar::Init(nsIWidget *aWindow,
 
182
                     nsIContent *aMenuBar)
 
183
{
 
184
  NS_ENSURE_ARG(aWindow);
 
185
  NS_ENSURE_ARG(aMenuBar);
 
186
 
 
187
  // We create this early so that IsRegistered() works
 
188
  mCancellable = uGlobalMenuRequestAutoCanceller::Create();
 
189
 
 
190
  mContent = aMenuBar;
 
191
 
 
192
  mTopLevel = WidgetToGTKWindow(aWindow);
 
193
  if (!GTK_IS_WINDOW(mTopLevel)) {
 
194
    return NS_ERROR_FAILURE;
 
195
  }
 
196
 
 
197
  g_object_ref(mTopLevel);
 
198
 
 
199
  nsCAutoString path = NS_LITERAL_CSTRING("/com/canonical/menu/");
 
200
  char xid[10];
 
201
  sprintf(xid, "%X", (PRUint32) GDK_WINDOW_XID(gtk_widget_get_window(mTopLevel)));
 
202
  path.Append(xid);
 
203
 
 
204
  mServer = dbusmenu_server_new(path.get());
 
205
  if (!mServer) {
 
206
    NS_WARNING("Failed to create DbusmenuServer");
 
207
    return NS_ERROR_OUT_OF_MEMORY;
 
208
  }
 
209
 
 
210
  InitializeDbusMenuItem();
 
211
 
 
212
  if (!mDbusMenuItem) {
 
213
    NS_WARNING("Failed to create DbusmenuMenuitem");
 
214
    return NS_ERROR_OUT_OF_MEMORY;
 
215
  }
 
216
 
 
217
  dbusmenu_server_set_root(mServer, mDbusMenuItem);
 
218
 
 
219
  mListener = new uGlobalMenuDocListener();
 
220
 
 
221
  nsresult rv = mListener->Init(mContent);
 
222
  if (NS_FAILED(rv)) {
 
223
    NS_WARNING("Failed to initialize doc listener");
 
224
    return rv;
 
225
  }
 
226
 
 
227
  rv = Build();
 
228
  if (NS_FAILED(rv)) {
 
229
    NS_WARNING("Failed to build menubar");
 
230
    return rv;
 
231
  }
 
232
 
 
233
  mEventListener = new uGlobalMenuBarListener(this);
 
234
 
 
235
  mDocTarget = do_QueryInterface(mContent->GetCurrentDoc());
 
236
 
 
237
  mDocTarget->AddEventListener(NS_LITERAL_STRING("focus"),
 
238
                               mEventListener,
 
239
                               true);
 
240
  mDocTarget->AddEventListener(NS_LITERAL_STRING("blur"),
 
241
                               mEventListener,
 
242
                               true);
 
243
  mDocTarget->AddEventListener(NS_LITERAL_STRING("keypress"),
 
244
                               mEventListener,
 
245
                               false);
 
246
  mDocTarget->AddEventListener(NS_LITERAL_STRING("keydown"),
 
247
                               mEventListener,
 
248
                               false);
 
249
  mDocTarget->AddEventListener(NS_LITERAL_STRING("keyup"),
 
250
                               mEventListener,
 
251
                               false);
 
252
 
 
253
  nsIPrefBranch *prefs = uGlobalMenuService::GetPrefService();
 
254
  if (!prefs) {
 
255
    return NS_ERROR_FAILURE;
 
256
  }
 
257
 
 
258
  prefs->GetIntPref("ui.key.menuAccessKey", &mAccessKey);
 
259
  if (mAccessKey == nsIDOMKeyEvent::DOM_VK_SHIFT) {
 
260
    mAccessKeyMask = MODIFIER_SHIFT;
 
261
  } else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_CONTROL) {
 
262
    mAccessKeyMask = MODIFIER_CONTROL;
 
263
  } else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_ALT) {
 
264
    mAccessKeyMask = MODIFIER_ALT;
 
265
  } else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_META) {
 
266
    mAccessKeyMask = MODIFIER_META;
 
267
  } else {
 
268
    mAccessKeyMask = MODIFIER_ALT;
 
269
  }
 
270
 
 
271
  rv = mListener->RegisterFallbackListener(this);
 
272
  if (NS_FAILED(rv)) {
 
273
    return rv;
 
274
  }
 
275
 
 
276
  PRUint32 xidn = (PRUint32) GDK_WINDOW_XID(gtk_widget_get_window(mTopLevel));
 
277
  uGlobalMenuService::RegisterGlobalMenuBar(this, mCancellable, xidn, path);
 
278
  HideXULMenuBar();
 
279
 
 
280
  return NS_OK;
 
281
}
 
282
 
 
283
bool
 
284
uGlobalMenuBar::ShouldParentStayVisible(nsIContent *aContent)
 
285
{
 
286
  static nsIAtom *blacklist[] =
 
287
    { uWidgetAtoms::toolbarspring, nsnull };
 
288
 
 
289
  nsIContent *parent = aContent->GetParent();
 
290
  if (!parent) {
 
291
    return true;
 
292
  }
 
293
 
 
294
  PRUint32 count = parent->GetChildCount();
 
295
 
 
296
  if (count <= 1) {
 
297
    // It's just us
 
298
    return false;
 
299
  }
 
300
 
 
301
  for (PRUint32 i = 0 ; i < count ; i++) {
 
302
    nsIContent *child = parent->GetChildAt(i);
 
303
    if (child == aContent) {
 
304
      continue;
 
305
    }
 
306
 
 
307
    bool found = false;
 
308
    for (PRUint32 j = 0 ; blacklist[j] != nsnull ; j++) {
 
309
      if (child->Tag() == blacklist[j]) {
 
310
        found = true;
 
311
        break;
 
312
      }
 
313
    }
 
314
 
 
315
    if (!found) {
 
316
      return true;
 
317
    }
 
318
  }
 
319
 
 
320
  return false;
 
321
}
 
322
 
 
323
PRUint32
 
324
uGlobalMenuBar::GetModifiersFromEvent(nsIDOMKeyEvent *aKeyEvent)
 
325
{
 
326
  PRUint32 modifiers = 0;
 
327
  bool modifier;
 
328
 
 
329
  aKeyEvent->GetAltKey(&modifier);
 
330
  if (modifier) {
 
331
    modifiers |= MODIFIER_ALT;
 
332
  }
 
333
 
 
334
  aKeyEvent->GetShiftKey(&modifier);
 
335
  if (modifier) {
 
336
    modifiers |= MODIFIER_SHIFT;
 
337
  }
 
338
 
 
339
  aKeyEvent->GetCtrlKey(&modifier);
 
340
  if (modifier) {
 
341
    modifiers |= MODIFIER_CONTROL;
 
342
  }
 
343
 
 
344
  aKeyEvent->GetMetaKey(&modifier);
 
345
  if (modifier) {
 
346
    modifiers |= MODIFIER_META;
 
347
  }
 
348
 
 
349
  return modifiers;
 
350
}
 
351
 
 
352
bool
 
353
uGlobalMenuBar::IsParentOfMenuBar(nsIContent *aContent)
 
354
{
 
355
  nsIContent *tmp = mContent->GetParent();
 
356
 
 
357
  while (tmp) {
 
358
    if (tmp == aContent) {
 
359
      return true;
 
360
    }
 
361
 
 
362
    tmp = tmp->GetParent();
 
363
  }
 
364
 
 
365
  return false;
 
366
}
 
367
 
 
368
void
 
369
uGlobalMenuBar::HideXULMenuBar()
 
370
{
 
371
  if (mHiddenElement) {
 
372
    mHiddenElement->SetAttr(kNameSpaceID_None, uWidgetAtoms::hidden,
 
373
                            mRestoreHidden ? NS_LITERAL_STRING("true") :
 
374
                            NS_LITERAL_STRING("false"), true);
 
375
  }
 
376
 
 
377
  nsIContent *tmp = mContent;
 
378
 
 
379
  // Walk up the DOM tree until we find a node with siblings
 
380
  while (tmp) {
 
381
    if (ShouldParentStayVisible(tmp)) {
 
382
      break;
 
383
    }
 
384
 
 
385
    tmp = tmp->GetParent();
 
386
  }
 
387
 
 
388
  mHiddenElement = tmp;
 
389
  mRestoreHidden = mHiddenElement->AttrValueIs(kNameSpaceID_None,
 
390
                                               uWidgetAtoms::hidden,
 
391
                                               uWidgetAtoms::_true,
 
392
                                               eCaseMatters);
 
393
 
 
394
  mHiddenElement->SetAttr(kNameSpaceID_None, uWidgetAtoms::hidden,
 
395
                          NS_LITERAL_STRING("true"), true);
 
396
}
 
397
 
 
398
void
 
399
uGlobalMenuBar::ShowXULMenuBar()
 
400
{
 
401
  if (mHiddenElement) {
 
402
    mHiddenElement->SetAttr(kNameSpaceID_None, uWidgetAtoms::hidden,
 
403
                            mRestoreHidden ? NS_LITERAL_STRING("true") :
 
404
                            NS_LITERAL_STRING("false"), true);
 
405
    mHiddenElement = nsnull;
 
406
  }
 
407
}
 
408
 
 
409
uGlobalMenuBar::uGlobalMenuBar():
 
410
  uGlobalMenuObject(eMenuBar), mServer(nsnull), mTopLevel(nsnull),
 
411
  mOpenedByKeyboard(false)
 
412
{
 
413
  MOZ_COUNT_CTOR(uGlobalMenuBar);
 
414
}
 
415
 
 
416
uGlobalMenuBar::~uGlobalMenuBar()
 
417
{
 
418
  ShowXULMenuBar();
 
419
 
 
420
  if (mDocTarget) {
 
421
    mDocTarget->RemoveEventListener(NS_LITERAL_STRING("focus"),
 
422
                                    mEventListener,
 
423
                                    true);
 
424
    mDocTarget->RemoveEventListener(NS_LITERAL_STRING("blur"),
 
425
                                    mEventListener,
 
426
                                    true);
 
427
    mDocTarget->RemoveEventListener(NS_LITERAL_STRING("keypress"),
 
428
                                    mEventListener,
 
429
                                    false);
 
430
    mDocTarget->RemoveEventListener(NS_LITERAL_STRING("keydown"),
 
431
                                    mEventListener,
 
432
                                    false);
 
433
    mDocTarget->RemoveEventListener(NS_LITERAL_STRING("keyup"),
 
434
                                    mEventListener,
 
435
                                    false);
 
436
  }
 
437
 
 
438
  if (mListener) {
 
439
    mListener->UnregisterFallbackListener(this);
 
440
    mListener->Destroy();
 
441
  }
 
442
 
 
443
  if (mTopLevel)
 
444
    g_object_unref(mTopLevel);
 
445
 
 
446
  if (mDbusMenuItem)
 
447
    g_object_unref(mDbusMenuItem);
 
448
 
 
449
  if (mServer)
 
450
    g_object_unref(mServer);
 
451
 
 
452
  MOZ_COUNT_DTOR(uGlobalMenuBar);
 
453
}
 
454
 
 
455
/*static*/ uGlobalMenuBar*
 
456
uGlobalMenuBar::Create(nsIWidget *aWindow,
 
457
                       nsIContent *aMenuBar)
 
458
{
 
459
  uGlobalMenuBar *menubar = new uGlobalMenuBar();
 
460
  if (!menubar) {
 
461
    return nsnull;
 
462
  }
 
463
 
 
464
  if (NS_FAILED(menubar->Init(aWindow, aMenuBar))) {
 
465
    delete menubar;
 
466
    return nsnull;
 
467
  }
 
468
 
 
469
  return menubar;
 
470
}
 
471
 
 
472
void
 
473
uGlobalMenuBar::Blur()
 
474
{
 
475
  dbusmenu_server_set_status(mServer, DBUSMENU_STATUS_NORMAL);
 
476
}
 
477
 
 
478
void
 
479
uGlobalMenuBar::Focus()
 
480
{
 
481
  mOpenedByKeyboard = false;
 
482
}
 
483
 
 
484
bool
 
485
uGlobalMenuBar::ShouldHandleKeyEvent(nsIDOMEvent *aKeyEvent)
 
486
{
 
487
#if 0
 
488
# define nsEvent aKeyEvent
 
489
#else
 
490
  nsCOMPtr<nsIDOMNSEvent> nsEvent = do_QueryInterface(aKeyEvent);
 
491
  if (!nsEvent) {
 
492
    return false;
 
493
  }
 
494
#endif
 
495
 
 
496
  bool handled, trusted;
 
497
  nsEvent->GetPreventDefault(&handled);
 
498
  nsEvent->GetIsTrusted(&trusted);
 
499
 
 
500
#if 0
 
501
# undef nsEvent
 
502
#endif
 
503
 
 
504
  if (handled || !trusted) {
 
505
    return false;
 
506
  }
 
507
 
 
508
  return true;
 
509
}
 
510
 
 
511
nsresult
 
512
uGlobalMenuBar::KeyDown(nsIDOMEvent *aKeyEvent)
 
513
{
 
514
  if (!ShouldHandleKeyEvent(aKeyEvent)) {
 
515
    return NS_OK;
 
516
  }
 
517
 
 
518
  nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
 
519
  if (keyEvent) {
 
520
    PRUint32 keyCode;
 
521
    keyEvent->GetKeyCode(&keyCode);
 
522
    PRUint32 modifiers = GetModifiersFromEvent(keyEvent);
 
523
    if ((keyCode == static_cast<PRUint32>(mAccessKey)) &&
 
524
        ((modifiers & ~mAccessKeyMask) == 0)) {
 
525
      dbusmenu_server_set_status(mServer, DBUSMENU_STATUS_NOTICE);
 
526
    }
 
527
  }
 
528
 
 
529
  return NS_OK;
 
530
}
 
531
 
 
532
nsresult
 
533
uGlobalMenuBar::KeyUp(nsIDOMEvent *aKeyEvent)
 
534
{
 
535
  if (!ShouldHandleKeyEvent(aKeyEvent)) {
 
536
    return NS_OK;
 
537
  }
 
538
 
 
539
  nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
 
540
  if (keyEvent) {
 
541
    PRUint32 keyCode;
 
542
    keyEvent->GetKeyCode(&keyCode);
 
543
    if (keyCode == static_cast<PRUint32>(mAccessKey)) {
 
544
      dbusmenu_server_set_status(mServer, DBUSMENU_STATUS_NORMAL);
 
545
    }
 
546
  }
 
547
 
 
548
  return NS_OK;
 
549
}
 
550
 
 
551
nsresult
 
552
uGlobalMenuBar::KeyPress(nsIDOMEvent *aKeyEvent)
 
553
{
 
554
  if (!ShouldHandleKeyEvent(aKeyEvent)) {
 
555
    return NS_OK;
 
556
  }
 
557
 
 
558
  nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
 
559
  uGlobalMenuObject *found = nsnull;
 
560
  PRUint32 keyCode = nsnull;
 
561
 
 
562
  if (keyEvent) {
 
563
    keyEvent->GetKeyCode(&keyCode);
 
564
    PRUint32 count = mMenuObjects.Length();
 
565
    PRUint32 modifiers = GetModifiersFromEvent(keyEvent);
 
566
    if ((modifiers & mAccessKeyMask) && ((modifiers & ~mAccessKeyMask) == 0)) {
 
567
      // The menu access modifier is pressed
 
568
      PRUint32 charCode;
 
569
      keyEvent->GetCharCode(&charCode);
 
570
      if (charCode != 0) {
 
571
        PRUnichar ch = PRUnichar(charCode);
 
572
 
 
573
        nsICaseConversion *converter= uGlobalMenuService::GetCaseConverter();
 
574
 
 
575
        PRUnichar chu;
 
576
        PRUnichar chl;
 
577
        if (converter) {
 
578
          converter->ToUpper(ch, &chu);
 
579
          converter->ToLower(ch, &chl);
 
580
        } else {
 
581
          NS_WARNING("No case converter");
 
582
          chu = ch;
 
583
          chl = ch;
 
584
        }
 
585
 
 
586
        for (PRUint32 i = 0; i < count; i++) {
 
587
          nsIContent *content = mMenuObjects[i]->GetContent();
 
588
          if (content) {
 
589
            nsAutoString accessKey;
 
590
            content->GetAttr(kNameSpaceID_None, uWidgetAtoms::accesskey,
 
591
                             accessKey);
 
592
            const PRUnichar *key = accessKey.BeginReading();
 
593
            if (*key == chl || *key == chu) {
 
594
              found = mMenuObjects[i];
 
595
              break;
 
596
            }
 
597
          }
 
598
        }
 
599
      }
 
600
    } else if (keyCode == nsIDOMKeyEvent::DOM_VK_F10) {
 
601
      // Go through each mMenuObject, and find the first one
 
602
      // that is both visible and sensitive, and mark it found
 
603
      // for opening.
 
604
      for (PRUint32 i = 0; i < count; i++) {
 
605
        uGlobalMenu *menu = static_cast<uGlobalMenu *>((uGlobalMenuObject *)mMenuObjects[i]);
 
606
        if (menu->CanOpen()) {
 
607
          found = mMenuObjects[i];
 
608
          break;
 
609
        }
 
610
      }
 
611
    }
 
612
  }
 
613
 
 
614
  if (found) {
 
615
    mOpenedByKeyboard = true;
 
616
    uGlobalMenu *menu = static_cast<uGlobalMenu *>(found);
 
617
    menu->OpenMenu();
 
618
    aKeyEvent->StopPropagation();
 
619
    aKeyEvent->PreventDefault();
 
620
  }
 
621
 
 
622
  return NS_OK;
 
623
}
 
624
 
 
625
void
 
626
uGlobalMenuBar::NotifyMenuBarRegistered()
 
627
{
 
628
  if (mCancellable) {
 
629
    mCancellable->Destroy();
 
630
    mCancellable = nsnull;
 
631
  }
 
632
 
 
633
  SetFlags(UNITY_MENUBAR_IS_REGISTERED);
 
634
}
 
635
 
 
636
bool
 
637
uGlobalMenuBar::WidgetHasSameToplevelWindow(nsIWidget *aWidget)
 
638
{
 
639
  GtkWidget *topLevel = WidgetToGTKWindow(aWidget);
 
640
  return GDK_WINDOW_XID(gtk_widget_get_window(mTopLevel)) == GDK_WINDOW_XID(gtk_widget_get_window(topLevel));
 
641
}
 
642
 
 
643
void
 
644
uGlobalMenuBar::ObserveAttributeChanged(nsIDocument *aDocument,
 
645
                                        nsIContent *aContent,
 
646
                                        nsIAtom *aAttribute)
 
647
{
 
648
 
 
649
}
 
650
 
 
651
void
 
652
uGlobalMenuBar::ObserveContentRemoved(nsIDocument *aDocument,
 
653
                                      nsIContent *aContainer,
 
654
                                      nsIContent *aChild,
 
655
                                      PRInt32 aIndexInContainer)
 
656
{
 
657
  if (IsParentOfMenuBar(aContainer)) {
 
658
    HideXULMenuBar();
 
659
    return;
 
660
  }
 
661
 
 
662
  if (aContainer != mContent) {
 
663
    return;
 
664
  }
 
665
 
 
666
  bool res = RemoveMenuObjectAt(aIndexInContainer);
 
667
  NS_ASSERTION(res, "Failed to remove menuitem. Our menu representation is out-of-sync with reality");
 
668
  // XXX: Is there anything else we can do if removal fails?
 
669
}
 
670
 
 
671
void
 
672
uGlobalMenuBar::ObserveContentInserted(nsIDocument *aDocument,
 
673
                                       nsIContent *aContainer,
 
674
                                       nsIContent *aChild,
 
675
                                       PRInt32 aIndexInContainer)
 
676
{
 
677
  if (IsParentOfMenuBar(aContainer)) {
 
678
    HideXULMenuBar();
 
679
    return;
 
680
  }
 
681
 
 
682
  if (aContainer != mContent) {
 
683
    return;
 
684
  }
 
685
 
 
686
  uGlobalMenuObject *newItem =
 
687
    NewGlobalMenuItem(static_cast<uGlobalMenuObject *>(this),
 
688
                      mListener, aChild, this);
 
689
  bool res = false;
 
690
  if (newItem) {
 
691
    res = InsertMenuObjectAt(newItem, aIndexInContainer);
 
692
  }
 
693
  NS_ASSERTION(res, "Failed to insert menuitem. Our menu representation is out-of-sync with reality");
 
694
  // XXX: Is there anything else we can do if insertion fails?
 
695
}