1 // Copyright (c) 2012 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.
5 #include "chrome/browser/ui/gtk/global_menu_bar.h"
9 #include "base/command_line.h"
10 #include "base/prefs/pref_service.h"
11 #include "chrome/app/chrome_command_ids.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/browser_commands.h"
16 #include "chrome/browser/ui/gtk/accelerators_gtk.h"
17 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
18 #include "chrome/browser/ui/gtk/gtk_util.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chrome/common/pref_names.h"
21 #include "content/public/browser/notification_details.h"
22 #include "content/public/browser/notification_source.h"
23 #include "grit/generated_resources.h"
24 #include "ui/base/accelerators/menu_label_accelerator_util_linux.h"
25 #include "ui/base/accelerators/platform_accelerator_gtk.h"
26 #include "ui/base/l10n/l10n_util.h"
28 struct GlobalMenuBarCommand
{
36 const int MENU_SEPARATOR
=-1;
37 const int MENU_END
= -2;
38 const int MENU_DISABLED_LABEL
= -3;
40 GlobalMenuBarCommand file_menu
[] = {
41 { IDS_NEW_TAB
, IDC_NEW_TAB
},
42 { IDS_NEW_WINDOW
, IDC_NEW_WINDOW
},
43 { IDS_NEW_INCOGNITO_WINDOW
, IDC_NEW_INCOGNITO_WINDOW
},
44 { IDS_REOPEN_CLOSED_TABS_LINUX
, IDC_RESTORE_TAB
},
45 { IDS_OPEN_FILE_LINUX
, IDC_OPEN_FILE
},
46 { IDS_OPEN_LOCATION_LINUX
, IDC_FOCUS_LOCATION
},
48 { MENU_SEPARATOR
, MENU_SEPARATOR
},
50 { IDS_CREATE_SHORTCUTS
, IDC_CREATE_SHORTCUTS
},
52 { MENU_SEPARATOR
, MENU_SEPARATOR
},
54 { IDS_CLOSE_WINDOW_LINUX
, IDC_CLOSE_WINDOW
},
55 { IDS_CLOSE_TAB_LINUX
, IDC_CLOSE_TAB
},
56 { IDS_SAVE_PAGE
, IDC_SAVE_PAGE
},
58 { MENU_SEPARATOR
, MENU_SEPARATOR
},
60 { IDS_PRINT
, IDC_PRINT
},
62 { MENU_END
, MENU_END
}
65 GlobalMenuBarCommand edit_menu
[] = {
67 { IDS_COPY
, IDC_COPY
},
68 { IDS_PASTE
, IDC_PASTE
},
70 { MENU_SEPARATOR
, MENU_SEPARATOR
},
72 { IDS_FIND
, IDC_FIND
},
74 { MENU_SEPARATOR
, MENU_SEPARATOR
},
76 { IDS_PREFERENCES
, IDC_OPTIONS
},
78 { MENU_END
, MENU_END
}
81 GlobalMenuBarCommand view_menu
[] = {
82 { IDS_SHOW_BOOKMARK_BAR
, IDC_SHOW_BOOKMARK_BAR
},
84 { MENU_SEPARATOR
, MENU_SEPARATOR
},
86 { IDS_STOP_MENU_LINUX
, IDC_STOP
},
87 { IDS_RELOAD_MENU_LINUX
, IDC_RELOAD
},
89 { MENU_SEPARATOR
, MENU_SEPARATOR
},
91 { IDS_FULLSCREEN
, IDC_FULLSCREEN
},
92 { IDS_TEXT_DEFAULT_LINUX
, IDC_ZOOM_NORMAL
},
93 { IDS_TEXT_BIGGER_LINUX
, IDC_ZOOM_PLUS
},
94 { IDS_TEXT_SMALLER_LINUX
, IDC_ZOOM_MINUS
},
96 { MENU_END
, MENU_END
}
99 GlobalMenuBarCommand history_menu
[] = {
100 { IDS_HISTORY_HOME_LINUX
, IDC_HOME
},
101 { IDS_HISTORY_BACK_LINUX
, IDC_BACK
},
102 { IDS_HISTORY_FORWARD_LINUX
, IDC_FORWARD
},
104 { MENU_SEPARATOR
, MENU_SEPARATOR
},
106 { IDS_HISTORY_VISITED_LINUX
, MENU_DISABLED_LABEL
,
107 GlobalMenuBar::TAG_MOST_VISITED_HEADER
},
109 { MENU_SEPARATOR
, MENU_SEPARATOR
},
111 { IDS_HISTORY_CLOSED_LINUX
, MENU_DISABLED_LABEL
,
112 GlobalMenuBar::TAG_RECENTLY_CLOSED_HEADER
},
114 { MENU_SEPARATOR
, MENU_SEPARATOR
},
116 { IDS_SHOWFULLHISTORY_LINK
, IDC_SHOW_HISTORY
},
118 { MENU_END
, MENU_END
}
121 GlobalMenuBarCommand tools_menu
[] = {
122 { IDS_SHOW_DOWNLOADS
, IDC_SHOW_DOWNLOADS
},
123 { IDS_SHOW_HISTORY
, IDC_SHOW_HISTORY
},
124 { IDS_SHOW_EXTENSIONS
, IDC_MANAGE_EXTENSIONS
},
126 { MENU_SEPARATOR
, MENU_SEPARATOR
},
128 { IDS_TASK_MANAGER
, IDC_TASK_MANAGER
},
129 { IDS_CLEAR_BROWSING_DATA
, IDC_CLEAR_BROWSING_DATA
},
131 { MENU_SEPARATOR
, MENU_SEPARATOR
},
133 { IDS_VIEW_SOURCE
, IDC_VIEW_SOURCE
},
134 { IDS_DEV_TOOLS
, IDC_DEV_TOOLS
},
135 { IDS_DEV_TOOLS_CONSOLE
, IDC_DEV_TOOLS_CONSOLE
},
136 { IDS_DEV_TOOLS_DEVICES
, IDC_DEV_TOOLS_DEVICES
},
138 { MENU_END
, MENU_END
}
141 GlobalMenuBarCommand help_menu
[] = {
142 #if defined(GOOGLE_CHROME_BUILD)
143 { IDS_FEEDBACK
, IDC_FEEDBACK
},
145 { IDS_HELP_PAGE
, IDC_HELP_PAGE_VIA_MENU
},
146 { MENU_END
, MENU_END
}
151 GlobalMenuBar::GlobalMenuBar(Browser
* browser
)
153 menu_bar_(gtk_menu_bar_new()),
154 history_menu_(browser_
),
155 dummy_accel_group_(gtk_accel_group_new()),
156 block_activation_(false) {
157 // The global menu bar should never actually be shown in the app; it should
158 // instead remain in our widget hierarchy simply to be noticed by third party
160 g_object_ref_sink(menu_bar_
);
161 gtk_widget_set_no_show_all(menu_bar_
, TRUE
);
163 // Set a nice name so it shows up in gtkparasite and others.
164 gtk_widget_set_name(menu_bar_
, "chrome-hidden-global-menubar");
166 BuildGtkMenuFrom(IDS_FILE_MENU_LINUX
, &id_to_menu_item_
, file_menu
, NULL
);
167 BuildGtkMenuFrom(IDS_EDIT_MENU_LINUX
, &id_to_menu_item_
, edit_menu
, NULL
);
168 BuildGtkMenuFrom(IDS_VIEW_MENU_LINUX
, &id_to_menu_item_
, view_menu
, NULL
);
169 BuildGtkMenuFrom(IDS_HISTORY_MENU_LINUX
, &id_to_menu_item_
,
170 history_menu
, &history_menu_
);
172 BuildGtkMenuFrom(IDS_TOOLS_MENU_LINUX
, &id_to_menu_item_
, tools_menu
, NULL
);
173 BuildGtkMenuFrom(IDS_HELP_MENU_LINUX
, &id_to_menu_item_
, help_menu
, NULL
);
175 for (CommandIDMenuItemMap::const_iterator it
= id_to_menu_item_
.begin();
176 it
!= id_to_menu_item_
.end(); ++it
) {
177 // Get the starting enabled state.
178 gtk_widget_set_sensitive(it
->second
,
179 chrome::IsCommandEnabled(browser_
, it
->first
));
181 // Set the accelerator for each menu item.
182 AcceleratorsGtk
* accelerators
= AcceleratorsGtk::GetInstance();
183 const ui::Accelerator
* accelerator
=
184 accelerators
->GetPrimaryAcceleratorForCommand(it
->first
);
186 gtk_widget_add_accelerator(it
->second
,
189 ui::GetGdkKeyCodeForAccelerator(*accelerator
),
190 ui::GetGdkModifierForAccelerator(*accelerator
),
194 chrome::AddCommandObserver(browser_
, it
->first
, this);
197 pref_change_registrar_
.Init(browser_
->profile()->GetPrefs());
198 pref_change_registrar_
.Add(
199 prefs::kShowBookmarkBar
,
200 base::Bind(&GlobalMenuBar::OnBookmarkBarVisibilityChanged
,
201 base::Unretained(this)));
202 OnBookmarkBarVisibilityChanged();
205 GlobalMenuBar::~GlobalMenuBar() {
207 g_object_unref(dummy_accel_group_
);
208 gtk_widget_destroy(menu_bar_
);
209 g_object_unref(menu_bar_
);
212 void GlobalMenuBar::Disable() {
213 for (CommandIDMenuItemMap::const_iterator it
= id_to_menu_item_
.begin();
214 it
!= id_to_menu_item_
.end(); ++it
) {
215 chrome::RemoveCommandObserver(browser_
, it
->first
, this);
217 id_to_menu_item_
.clear();
219 pref_change_registrar_
.RemoveAll();
222 void GlobalMenuBar::BuildGtkMenuFrom(
224 std::map
<int, GtkWidget
*>* id_to_menu_item
,
225 GlobalMenuBarCommand
* commands
,
226 GlobalMenuOwner
* owner
) {
227 GtkWidget
* menu
= gtk_menu_new();
228 for (int i
= 0; commands
[i
].str_id
!= MENU_END
; ++i
) {
229 GtkWidget
* menu_item
= BuildMenuItem(
230 commands
[i
].str_id
, commands
[i
].command
, commands
[i
].tag
,
231 id_to_menu_item
, menu
);
232 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), menu_item
);
235 gtk_widget_show(menu
);
237 GtkWidget
* menu_item
= gtk_menu_item_new_with_mnemonic(
238 ui::RemoveWindowsStyleAccelerators(
239 l10n_util::GetStringUTF8(menu_str_id
)).c_str());
241 // Give the owner a chance to sink the reference before we add it to the menu
244 owner
->Init(menu
, menu_item
);
246 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item
), menu
);
247 gtk_widget_show(menu_item
);
248 gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar_
), menu_item
);
251 GtkWidget
* GlobalMenuBar::BuildMenuItem(
255 std::map
<int, GtkWidget
*>* id_to_menu_item
,
256 GtkWidget
* menu_to_add_to
) {
257 GtkWidget
* menu_item
= NULL
;
258 if (string_id
== MENU_SEPARATOR
) {
259 menu_item
= gtk_separator_menu_item_new();
261 std::string label
= ui::ConvertAcceleratorsFromWindowsStyle(
262 l10n_util::GetStringUTF8(string_id
));
264 if (command_id
== IDC_SHOW_BOOKMARK_BAR
)
265 menu_item
= gtk_check_menu_item_new_with_mnemonic(label
.c_str());
267 menu_item
= gtk_menu_item_new_with_mnemonic(label
.c_str());
270 g_object_set_data(G_OBJECT(menu_item
), "type-tag",
271 GINT_TO_POINTER(tag_id
));
274 if (command_id
== MENU_DISABLED_LABEL
) {
275 gtk_widget_set_sensitive(menu_item
, FALSE
);
277 id_to_menu_item
->insert(std::make_pair(command_id
, menu_item
));
278 g_object_set_data(G_OBJECT(menu_item
), "command-id",
279 GINT_TO_POINTER(command_id
));
280 g_signal_connect(menu_item
, "activate",
281 G_CALLBACK(OnItemActivatedThunk
), this);
284 gtk_widget_show(menu_item
);
288 void GlobalMenuBar::EnabledStateChangedForCommand(int id
, bool enabled
) {
289 CommandIDMenuItemMap::iterator it
= id_to_menu_item_
.find(id
);
290 if (it
!= id_to_menu_item_
.end())
291 gtk_widget_set_sensitive(it
->second
, enabled
);
294 void GlobalMenuBar::OnBookmarkBarVisibilityChanged() {
295 CommandIDMenuItemMap::iterator it
=
296 id_to_menu_item_
.find(IDC_SHOW_BOOKMARK_BAR
);
297 if (it
!= id_to_menu_item_
.end()) {
298 PrefService
* prefs
= browser_
->profile()->GetPrefs();
299 block_activation_
= true;
300 gtk_check_menu_item_set_active(
301 GTK_CHECK_MENU_ITEM(it
->second
),
302 prefs
->GetBoolean(prefs::kShowBookmarkBar
));
303 block_activation_
= false;
307 void GlobalMenuBar::OnItemActivated(GtkWidget
* sender
) {
308 if (block_activation_
)
311 int id
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(sender
), "command-id"));
312 chrome::ExecuteCommand(browser_
, id
);