Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(321)

Side by Side Diff: chrome/browser/ui/views/frame/global_menu_bar_x11.cc

Issue 21187006: linux_aura: Implement the static part of the dbus menu for Unity. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/views/frame/global_menu_bar_x11.h"
6
7 #include <dlfcn.h>
8 #include <glib-object.h>
9
10 #include "base/logging.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/stringprintf.h"
13 #include "chrome/app/chrome_command_ids.h"
14 #include "chrome/browser/ui/browser_commands.h"
15 #include "chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.h"
16 #include "chrome/browser/ui/views/frame/browser_view.h"
17 #include "chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h"
18 #include "chrome/common/pref_names.h"
19 #include "grit/generated_resources.h"
20 #include "ui/base/accelerators/menu_label_accelerator_util_linux.h"
21 #include "ui/base/keycodes/keyboard_code_conversion_x.h"
22 #include "ui/base/l10n/l10n_util.h"
23
24 // libdbusmenu-glib types
25 typedef struct _DbusmenuMenuitem DbusmenuMenuitem;
26 typedef DbusmenuMenuitem* (*dbusmenu_menuitem_new_func)();
27 typedef DbusmenuMenuitem* (*dbusmenu_menuitem_new_with_id_func)(int id);
28
29 typedef int (*dbusmenu_menuitem_get_id_func)(DbusmenuMenuitem* item);
30 typedef DbusmenuMenuitem* (*dbusmenu_menuitem_child_append_func)(
31 DbusmenuMenuitem* parent,
32 DbusmenuMenuitem* child);
33 typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_func)(
34 DbusmenuMenuitem* item,
35 const char* property,
36 const char* value);
37 typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_variant_func)(
38 DbusmenuMenuitem* item,
39 const char* property,
40 GVariant* value);
41 typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_bool_func)(
42 DbusmenuMenuitem* item,
43 const char* property,
44 bool value);
45 typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_int_func)(
46 DbusmenuMenuitem* item,
47 const char* property,
48 int value);
49
50 typedef struct _DbusmenuServer DbusmenuServer;
51 typedef DbusmenuServer* (*dbusmenu_server_new_func)(const char* object);
52 typedef void (*dbusmenu_server_set_root_func)(DbusmenuServer* self,
53 DbusmenuMenuitem* root);
54
55 // A line in the static menu definitions.
56 struct GlobalMenuBarCommand {
57 int str_id;
58 int command;
59 int tag;
60 };
61
62 namespace {
63
64 bool attempted_load = false;
65
66 // Retrieved functions from libdbusmenu-glib.
67
68 // DbusmenuMenuItem methods:
69 dbusmenu_menuitem_new_func menuitem_new = NULL;
70 dbusmenu_menuitem_new_with_id_func menuitem_new_with_id = NULL;
71 dbusmenu_menuitem_get_id_func menuitem_get_id = NULL;
72 dbusmenu_menuitem_child_append_func menuitem_child_append = NULL;
73 dbusmenu_menuitem_property_set_func menuitem_property_set = NULL;
74 dbusmenu_menuitem_property_set_variant_func menuitem_property_set_variant =
75 NULL;
76 dbusmenu_menuitem_property_set_bool_func menuitem_property_set_bool = NULL;
77 dbusmenu_menuitem_property_set_int_func menuitem_property_set_int = NULL;
78
79 // DbusmenuServer methods:
80 dbusmenu_server_new_func server_new = NULL;
81 dbusmenu_server_set_root_func server_set_root = NULL;
82
83 // Properties that we set on menu items:
84 const char kPropertyEnabled[] = "enabled";
85 const char kPropertyLabel[] = "label";
86 const char kPropertyShortcut[] = "shortcut";
87 const char kPropertyType[] = "type";
88 const char kPropertyToggleType[] = "toggle-type";
89 const char kPropertyToggleState[] = "toggle-state";
90 const char kPropertyVisible[] = "visible";
91
92 const char kTypeCheckmark[] = "checkmark";
93 const char kTypeSeparator[] = "separator";
94
95 // Constants used in menu definitions
96 const int MENU_SEPARATOR =-1;
97 const int MENU_END = -2;
98 const int MENU_DISABLED_LABEL = -3;
99
100 GlobalMenuBarCommand file_menu[] = {
101 { IDS_NEW_TAB, IDC_NEW_TAB },
102 { IDS_NEW_WINDOW, IDC_NEW_WINDOW },
103 { IDS_NEW_INCOGNITO_WINDOW, IDC_NEW_INCOGNITO_WINDOW },
104 { IDS_REOPEN_CLOSED_TABS_LINUX, IDC_RESTORE_TAB },
105 { IDS_OPEN_FILE_LINUX, IDC_OPEN_FILE },
106 { IDS_OPEN_LOCATION_LINUX, IDC_FOCUS_LOCATION },
107
108 { MENU_SEPARATOR, MENU_SEPARATOR },
109
110 { IDS_CREATE_SHORTCUTS, IDC_CREATE_SHORTCUTS },
111
112 { MENU_SEPARATOR, MENU_SEPARATOR },
113
114 { IDS_CLOSE_WINDOW_LINUX, IDC_CLOSE_WINDOW },
115 { IDS_CLOSE_TAB_LINUX, IDC_CLOSE_TAB },
116 { IDS_SAVE_PAGE, IDC_SAVE_PAGE },
117
118 { MENU_SEPARATOR, MENU_SEPARATOR },
119
120 { IDS_PRINT, IDC_PRINT },
121
122 { MENU_END, MENU_END }
123 };
124
125 GlobalMenuBarCommand edit_menu[] = {
126 { IDS_CUT, IDC_CUT },
127 { IDS_COPY, IDC_COPY },
128 { IDS_PASTE, IDC_PASTE },
129
130 { MENU_SEPARATOR, MENU_SEPARATOR },
131
132 { IDS_FIND, IDC_FIND },
133
134 { MENU_SEPARATOR, MENU_SEPARATOR },
135
136 { IDS_PREFERENCES, IDC_OPTIONS },
137
138 { MENU_END, MENU_END }
139 };
140
141
142 GlobalMenuBarCommand view_menu[] = {
143 { IDS_SHOW_BOOKMARK_BAR, IDC_SHOW_BOOKMARK_BAR },
144
145 { MENU_SEPARATOR, MENU_SEPARATOR },
146
147 { IDS_STOP_MENU_LINUX, IDC_STOP },
148 { IDS_RELOAD_MENU_LINUX, IDC_RELOAD },
149
150 { MENU_SEPARATOR, MENU_SEPARATOR },
151
152 { IDS_FULLSCREEN, IDC_FULLSCREEN },
153 { IDS_TEXT_DEFAULT_LINUX, IDC_ZOOM_NORMAL },
154 { IDS_TEXT_BIGGER_LINUX, IDC_ZOOM_PLUS },
155 { IDS_TEXT_SMALLER_LINUX, IDC_ZOOM_MINUS },
156
157 { MENU_END, MENU_END }
158 };
159
160 // TODO(erg): History menu.
161
162 GlobalMenuBarCommand tools_menu[] = {
163 { IDS_SHOW_DOWNLOADS, IDC_SHOW_DOWNLOADS },
164 { IDS_SHOW_HISTORY, IDC_SHOW_HISTORY },
165 { IDS_SHOW_EXTENSIONS, IDC_MANAGE_EXTENSIONS },
166
167 { MENU_SEPARATOR, MENU_SEPARATOR },
168
169 { IDS_TASK_MANAGER, IDC_TASK_MANAGER },
170 { IDS_CLEAR_BROWSING_DATA, IDC_CLEAR_BROWSING_DATA },
171
172 { MENU_SEPARATOR, MENU_SEPARATOR },
173
174 { IDS_VIEW_SOURCE, IDC_VIEW_SOURCE },
175 { IDS_DEV_TOOLS, IDC_DEV_TOOLS },
176 { IDS_DEV_TOOLS_CONSOLE, IDC_DEV_TOOLS_CONSOLE },
177
178 { MENU_END, MENU_END }
179 };
180
181 GlobalMenuBarCommand help_menu[] = {
182 { IDS_FEEDBACK, IDC_FEEDBACK },
183 { IDS_HELP_PAGE , IDC_HELP_PAGE_VIA_MENU },
184 { MENU_END, MENU_END }
185 };
186
187
188 void EnsureMethodsLoaded() {
189 if (attempted_load)
sadrul 2013/08/01 20:57:45 attempted_load could be a static bool inside this
190 return;
191 attempted_load = true;
192
193 void* dbusmenu_lib = dlopen("libdbusmenu-glib.so", RTLD_LAZY);
194 if (!dbusmenu_lib)
195 return;
196
197 // DbusmenuMenuItem methods.
198 menuitem_new = reinterpret_cast<dbusmenu_menuitem_new_func>(
199 dlsym(dbusmenu_lib, "dbusmenu_menuitem_new"));
200 menuitem_new_with_id = reinterpret_cast<dbusmenu_menuitem_new_with_id_func>(
201 dlsym(dbusmenu_lib, "dbusmenu_menuitem_new_with_id"));
202 menuitem_get_id = reinterpret_cast<dbusmenu_menuitem_get_id_func>(
203 dlsym(dbusmenu_lib, "dbusmenu_menuitem_get_id"));
204 menuitem_child_append = reinterpret_cast<dbusmenu_menuitem_child_append_func>(
205 dlsym(dbusmenu_lib, "dbusmenu_menuitem_child_append"));
206 menuitem_property_set = reinterpret_cast<dbusmenu_menuitem_property_set_func>(
207 dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set"));
208 menuitem_property_set_variant =
209 reinterpret_cast<dbusmenu_menuitem_property_set_variant_func>(
210 dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_variant"));
211 menuitem_property_set_bool =
212 reinterpret_cast<dbusmenu_menuitem_property_set_bool_func>(
213 dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_bool"));
214 menuitem_property_set_int =
215 reinterpret_cast<dbusmenu_menuitem_property_set_int_func>(
216 dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_int"));
217
218 // DbusmenuServer methods.
219 server_new = reinterpret_cast<dbusmenu_server_new_func>(
220 dlsym(dbusmenu_lib, "dbusmenu_server_new"));
221 server_set_root = reinterpret_cast<dbusmenu_server_set_root_func>(
222 dlsym(dbusmenu_lib, "dbusmenu_server_set_root"));
223 }
224
225 } // namespace
226
227 GlobalMenuBarX11::GlobalMenuBarX11(BrowserView* browser_view,
228 BrowserDesktopRootWindowHostX11* host)
229 : browser_(browser_view->browser()),
230 browser_view_(browser_view),
231 host_(host),
232 server_(NULL) {
233 EnsureMethodsLoaded();
sadrul 2013/08/01 20:57:45 Should this happen in InitServer() instead?
Elliot Glaysher 2013/08/01 21:27:18 No. We will only get InitServer() in response to a
234
235 if (server_new)
236 host_->AddObserver(this);
237 }
238
239 GlobalMenuBarX11::~GlobalMenuBarX11() {
240 if (server_) {
241 Disable();
242 g_object_unref(server_);
243 host_->RemoveObserver(this);
244 }
245 }
246
247 // static
248 std::string GlobalMenuBarX11::GetPathForWindow(unsigned long xid) {
249 return base::StringPrintf("/com/canonical/menu/%lX", xid);
250 }
251
252 void GlobalMenuBarX11::InitServer(unsigned long xid) {
253 std::string path = GetPathForWindow(xid);
254 server_ = server_new(path.c_str());
255
256 root_item_ = menuitem_new();
257 menuitem_property_set(root_item_, kPropertyLabel, "Root");
258 menuitem_property_set_bool(root_item_, kPropertyVisible, true);
259
260 BuildMenuFrom(root_item_, IDS_FILE_MENU_LINUX, &id_to_menu_item_, file_menu);
261 BuildMenuFrom(root_item_, IDS_EDIT_MENU_LINUX, &id_to_menu_item_, edit_menu);
262 BuildMenuFrom(root_item_, IDS_VIEW_MENU_LINUX, &id_to_menu_item_, view_menu);
263 // TODO(erg): History menu.
264 BuildMenuFrom(root_item_, IDS_TOOLS_MENU_LINUX, &id_to_menu_item_,
265 tools_menu);
266 BuildMenuFrom(root_item_, IDS_HELP_MENU_LINUX, &id_to_menu_item_, help_menu);
267
268 for (CommandIDMenuItemMap::const_iterator it = id_to_menu_item_.begin();
269 it != id_to_menu_item_.end(); ++it) {
270 menuitem_property_set_bool(it->second, kPropertyEnabled,
271 chrome::IsCommandEnabled(browser_, it->first));
272
273 ui::Accelerator accelerator;
274 if (browser_view_->GetAccelerator(it->first, &accelerator))
275 RegisterAccelerator(it->second, accelerator);
276
277 chrome::AddCommandObserver(browser_, it->first, this);
278 }
279
280 pref_change_registrar_.Init(browser_->profile()->GetPrefs());
281 pref_change_registrar_.Add(
282 prefs::kShowBookmarkBar,
283 base::Bind(&GlobalMenuBarX11::OnBookmarkBarVisibilityChanged,
284 base::Unretained(this)));
285 OnBookmarkBarVisibilityChanged();
286
287 server_set_root(server_, root_item_);
288 }
289
290 void GlobalMenuBarX11::Disable() {
291 for (CommandIDMenuItemMap::const_iterator it = id_to_menu_item_.begin();
292 it != id_to_menu_item_.end(); ++it) {
293 chrome::RemoveCommandObserver(browser_, it->first, this);
294 }
295 id_to_menu_item_.clear();
296
297 pref_change_registrar_.RemoveAll();
298 }
299
300 void GlobalMenuBarX11::BuildMenuFrom(
301 DbusmenuMenuitem* parent,
302 int menu_str_id,
303 std::map<int, DbusmenuMenuitem*>* id_to_menu_item,
304 GlobalMenuBarCommand* commands) {
305 DbusmenuMenuitem* top = menuitem_new();
306 menuitem_property_set(
307 top, kPropertyLabel,
308 ui::RemoveWindowsStyleAccelerators(
309 l10n_util::GetStringUTF8(menu_str_id)).c_str());
310 menuitem_property_set_bool(top, kPropertyVisible, true);
311
312 for (int i = 0; commands[i].str_id != MENU_END; ++i) {
313 DbusmenuMenuitem* menu_item = BuildMenuItem(
314 commands[i].str_id, commands[i].command, commands[i].tag,
315 id_to_menu_item);
316 menuitem_child_append(top, menu_item);
317 }
318
319 menuitem_child_append(parent, top);
320 }
321
322 DbusmenuMenuitem* GlobalMenuBarX11::BuildMenuItem(
323 int string_id,
324 int command_id,
325 int tag_id,
326 std::map<int, DbusmenuMenuitem*>* id_to_menu_item) {
327 DbusmenuMenuitem* item = menuitem_new();
328
329 if (string_id == MENU_SEPARATOR) {
330 menuitem_property_set(item, kPropertyType, kTypeSeparator);
331 } else {
332 std::string label = ui::ConvertAcceleratorsFromWindowsStyle(
333 l10n_util::GetStringUTF8(string_id));
334 menuitem_property_set(item, kPropertyLabel, label.c_str());
335
336 if (command_id == IDC_SHOW_BOOKMARK_BAR)
337 menuitem_property_set(item, kPropertyToggleType, kTypeCheckmark);
338
339 if (tag_id)
340 g_object_set_data(G_OBJECT(item), "type-tag", GINT_TO_POINTER(tag_id));
341
342 if (command_id == MENU_DISABLED_LABEL) {
sadrul 2013/08/01 20:57:45 The menus are disabled afterwards in InitServer ap
Elliot Glaysher 2013/08/01 21:27:18 The set of items disabled here and the set of item
343 menuitem_property_set_bool(item, kPropertyEnabled, false);
344 } else {
345 id_to_menu_item->insert(std::make_pair(command_id, item));
346 g_object_set_data(G_OBJECT(item), "command-id",
347 GINT_TO_POINTER(command_id));
348 g_signal_connect(item, "item-activated",
349 G_CALLBACK(OnItemActivatedThunk), this);
350 }
351 }
352
353 menuitem_property_set_bool(item, kPropertyVisible, true);
354 return item;
355 }
356
357 void GlobalMenuBarX11::RegisterAccelerator(DbusmenuMenuitem* item,
358 const ui::Accelerator& accelerator) {
359 // A translation of libdbusmenu-gtk's menuitem_property_set_shortcut()
360 // translated from GDK types to ui::Accelerator types.
361 GVariantBuilder builder;
362 g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
363
364 if (accelerator.IsCtrlDown())
365 g_variant_builder_add(&builder, "s", "Control");
366 if (accelerator.IsAltDown())
367 g_variant_builder_add(&builder, "s", "Alt");
368 if (accelerator.IsShiftDown())
369 g_variant_builder_add(&builder, "s", "Shift");
370
371 char* name = XKeysymToString(XKeysymForWindowsKeyCode(
372 accelerator.key_code(), false));
373 if (!name) {
374 NOTIMPLEMENTED();
375 return;
376 }
377 g_variant_builder_add(&builder, "s", name);
378
379 GVariant* inside_array = g_variant_builder_end(&builder);
380 g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
381 g_variant_builder_add_value(&builder, inside_array);
382 GVariant* outside_array = g_variant_builder_end(&builder);
383
384 menuitem_property_set_variant(item, kPropertyShortcut, outside_array);
385 }
386
387 void GlobalMenuBarX11::OnBookmarkBarVisibilityChanged() {
388 CommandIDMenuItemMap::iterator it =
389 id_to_menu_item_.find(IDC_SHOW_BOOKMARK_BAR);
390 if (it != id_to_menu_item_.end()) {
391 PrefService* prefs = browser_->profile()->GetPrefs();
392 // Note: Unlike the GTK version, we don't appear to need to do tricks where
393 // we block activation while setting the toggle.
394 menuitem_property_set_int(it->second, kPropertyToggleState,
395 prefs->GetBoolean(prefs::kShowBookmarkBar));
396 }
397 }
398
399 void GlobalMenuBarX11::EnabledStateChangedForCommand(int id, bool enabled) {
400 CommandIDMenuItemMap::iterator it = id_to_menu_item_.find(id);
401 if (it != id_to_menu_item_.end())
402 menuitem_property_set_bool(it->second, kPropertyEnabled, enabled);
403 }
404
405 void GlobalMenuBarX11::OnWindowMapped(unsigned long xid) {
406 if (!server_)
407 InitServer(xid);
408
409 GlobalMenuBarRegistrarX11::GetInstance()->OnWindowMapped(xid);
410 }
411
412 void GlobalMenuBarX11::OnWindowUnmapped(unsigned long xid) {
413 GlobalMenuBarRegistrarX11::GetInstance()->OnWindowUnmapped(xid);
414 }
415
416 void GlobalMenuBarX11::OnItemActivated(DbusmenuMenuitem* item,
417 unsigned int timestamp) {
418 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item), "command-id"));
419 chrome::ExecuteCommand(browser_, id);
420 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698