Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / gtk / browser_window_gtk.cc
blobc038e11eec3ffac823ac159ed50f8c7da3581b37
1 // Copyright 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/browser_window_gtk.h"
7 #include <gdk/gdkkeysyms.h>
9 #include <algorithm>
10 #include <string>
12 #include "base/base_paths.h"
13 #include "base/bind.h"
14 #include "base/command_line.h"
15 #include "base/debug/trace_event.h"
16 #include "base/environment.h"
17 #include "base/i18n/file_util_icu.h"
18 #include "base/logging.h"
19 #include "base/memory/scoped_ptr.h"
20 #include "base/memory/singleton.h"
21 #include "base/message_loop/message_loop.h"
22 #include "base/nix/xdg_util.h"
23 #include "base/path_service.h"
24 #include "base/prefs/pref_service.h"
25 #include "base/prefs/scoped_user_pref_update.h"
26 #include "base/strings/string_util.h"
27 #include "base/strings/utf_string_conversions.h"
28 #include "base/time/time.h"
29 #include "chrome/app/chrome_command_ids.h"
30 #include "chrome/browser/app_mode/app_mode_utils.h"
31 #include "chrome/browser/browser_process.h"
32 #include "chrome/browser/chrome_notification_types.h"
33 #include "chrome/browser/download/download_item_model.h"
34 #include "chrome/browser/extensions/tab_helper.h"
35 #include "chrome/browser/infobars/infobar_service.h"
36 #include "chrome/browser/profiles/profile.h"
37 #include "chrome/browser/themes/theme_properties.h"
38 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
39 #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
40 #include "chrome/browser/ui/browser.h"
41 #include "chrome/browser/ui/browser_command_controller.h"
42 #include "chrome/browser/ui/browser_commands.h"
43 #include "chrome/browser/ui/browser_dialogs.h"
44 #include "chrome/browser/ui/browser_list.h"
45 #include "chrome/browser/ui/browser_window_state.h"
46 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
47 #include "chrome/browser/ui/find_bar/find_tab_helper.h"
48 #include "chrome/browser/ui/gtk/accelerators_gtk.h"
49 #include "chrome/browser/ui/gtk/avatar_menu_bubble_gtk.h"
50 #include "chrome/browser/ui/gtk/avatar_menu_button_gtk.h"
51 #include "chrome/browser/ui/gtk/bookmarks/bookmark_bar_gtk.h"
52 #include "chrome/browser/ui/gtk/browser_titlebar.h"
53 #include "chrome/browser/ui/gtk/browser_toolbar_gtk.h"
54 #include "chrome/browser/ui/gtk/create_application_shortcuts_dialog_gtk.h"
55 #include "chrome/browser/ui/gtk/download/download_in_progress_dialog_gtk.h"
56 #include "chrome/browser/ui/gtk/download/download_shelf_gtk.h"
57 #include "chrome/browser/ui/gtk/edit_search_engine_dialog.h"
58 #include "chrome/browser/ui/gtk/extensions/extension_keybinding_registry_gtk.h"
59 #include "chrome/browser/ui/gtk/find_bar_gtk.h"
60 #include "chrome/browser/ui/gtk/fullscreen_exit_bubble_gtk.h"
61 #include "chrome/browser/ui/gtk/global_menu_bar.h"
62 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
63 #include "chrome/browser/ui/gtk/gtk_util.h"
64 #include "chrome/browser/ui/gtk/gtk_window_util.h"
65 #include "chrome/browser/ui/gtk/infobars/infobar_container_gtk.h"
66 #include "chrome/browser/ui/gtk/infobars/infobar_gtk.h"
67 #include "chrome/browser/ui/gtk/location_bar_view_gtk.h"
68 #include "chrome/browser/ui/gtk/nine_box.h"
69 #include "chrome/browser/ui/gtk/one_click_signin_bubble_gtk.h"
70 #include "chrome/browser/ui/gtk/password_generation_bubble_gtk.h"
71 #include "chrome/browser/ui/gtk/reload_button_gtk.h"
72 #include "chrome/browser/ui/gtk/status_bubble_gtk.h"
73 #include "chrome/browser/ui/gtk/tab_contents_container_gtk.h"
74 #include "chrome/browser/ui/gtk/tabs/tab_strip_gtk.h"
75 #include "chrome/browser/ui/gtk/task_manager_gtk.h"
76 #include "chrome/browser/ui/gtk/update_recommended_dialog.h"
77 #include "chrome/browser/ui/gtk/website_settings/website_settings_popup_gtk.h"
78 #include "chrome/browser/ui/omnibox/location_bar.h"
79 #include "chrome/browser/ui/omnibox/omnibox_view.h"
80 #include "chrome/browser/ui/tabs/tab_strip_model.h"
81 #include "chrome/browser/web_applications/web_app.h"
82 #include "chrome/common/chrome_switches.h"
83 #include "chrome/common/pref_names.h"
84 #include "components/user_prefs/pref_registry_syncable.h"
85 #include "content/public/browser/download_manager.h"
86 #include "content/public/browser/native_web_keyboard_event.h"
87 #include "content/public/browser/notification_service.h"
88 #include "content/public/browser/render_view_host.h"
89 #include "content/public/browser/render_widget_host_view.h"
90 #include "content/public/browser/web_contents.h"
91 #include "content/public/browser/web_contents_view.h"
92 #include "grit/chromium_strings.h"
93 #include "grit/generated_resources.h"
94 #include "grit/theme_resources.h"
95 #include "grit/ui_resources.h"
96 #include "ui/base/accelerators/platform_accelerator_gtk.h"
97 #include "ui/base/gtk/gtk_floating_container.h"
98 #include "ui/base/gtk/gtk_hig_constants.h"
99 #include "ui/base/gtk/gtk_screen_util.h"
100 #include "ui/base/l10n/l10n_util.h"
101 #include "ui/base/resource/resource_bundle.h"
102 #include "ui/base/x/active_window_watcher_x.h"
103 #include "ui/events/keycodes/keyboard_codes.h"
104 #include "ui/gfx/gtk_util.h"
105 #include "ui/gfx/image/cairo_cached_surface.h"
106 #include "ui/gfx/image/image.h"
107 #include "ui/gfx/rect.h"
108 #include "ui/gfx/screen.h"
109 #include "ui/gfx/skia_utils_gtk.h"
111 using content::NativeWebKeyboardEvent;
112 using content::SSLStatus;
113 using content::WebContents;
114 using web_modal::WebContentsModalDialogHost;
116 namespace {
118 // The number of milliseconds between loading animation frames.
119 const int kLoadingAnimationFrameTimeMs = 30;
121 const char* kBrowserWindowKey = "__BROWSER_WINDOW_GTK__";
123 // While resize areas on Windows are normally the same size as the window
124 // borders, our top area is shrunk by 1 px to make it easier to move the window
125 // around with our thinner top grabbable strip. (Incidentally, our side and
126 // bottom resize areas don't match the frame border thickness either -- they
127 // span the whole nonclient area, so there's no "dead zone" for the mouse.)
128 const int kTopResizeAdjust = 1;
129 // The thickness of the shadow around the toolbar+web content area. There are
130 // actually a couple pixels more that should overlap the toolbar and web
131 // content area, but we don't use those pixels.
132 const int kContentShadowThickness = 2;
133 // The offset to the background when the custom frame is off. We want the
134 // window background to line up with the tab background regardless of whether
135 // we're in custom frame mode or not. Since themes are designed with the
136 // custom frame in mind, we need to offset the background when the custom frame
137 // is off.
138 const int kCustomFrameBackgroundVerticalOffset = 15;
140 // The timeout in milliseconds before we'll get the true window position with
141 // gtk_window_get_position() after the last GTK configure-event signal.
142 const int kDebounceTimeoutMilliseconds = 100;
144 // Using gtk_window_get_position/size creates a race condition, so only use
145 // this to get the initial bounds. After window creation, we pick up the
146 // normal bounds by connecting to the configure-event signal.
147 gfx::Rect GetInitialWindowBounds(GtkWindow* window) {
148 gint x, y, width, height;
149 gtk_window_get_position(window, &x, &y);
150 gtk_window_get_size(window, &width, &height);
151 return gfx::Rect(x, y, width, height);
154 // Get the command ids of the key combinations that are not valid gtk
155 // accelerators.
156 int GetCustomCommandId(GdkEventKey* event) {
157 // Filter modifier to only include accelerator modifiers.
158 guint modifier = event->state & gtk_accelerator_get_default_mod_mask();
159 switch (event->keyval) {
160 // Gtk doesn't allow GDK_Tab or GDK_ISO_Left_Tab to be an accelerator (see
161 // gtk_accelerator_valid), so we need to handle these accelerators
162 // manually.
163 // Some X clients (e.g. cygwin, NX client, etc.) also send GDK_KP_Tab when
164 // typing a tab key. We should also handle GDK_KP_Tab for such X clients as
165 // Firefox does.
166 case GDK_Tab:
167 case GDK_ISO_Left_Tab:
168 case GDK_KP_Tab:
169 if (GDK_CONTROL_MASK == modifier) {
170 return IDC_SELECT_NEXT_TAB;
171 } else if ((GDK_CONTROL_MASK | GDK_SHIFT_MASK) == modifier) {
172 return IDC_SELECT_PREVIOUS_TAB;
174 break;
176 default:
177 break;
179 return -1;
182 // Get the command ids of the accelerators that we don't want the native widget
183 // to be able to override.
184 int GetPreHandleCommandId(GdkEventKey* event) {
185 // Filter modifier to only include accelerator modifiers.
186 guint modifier = event->state & gtk_accelerator_get_default_mod_mask();
187 switch (event->keyval) {
188 case GDK_Page_Down:
189 if (GDK_CONTROL_MASK == modifier) {
190 return IDC_SELECT_NEXT_TAB;
191 } else if ((GDK_CONTROL_MASK | GDK_SHIFT_MASK) == modifier) {
192 return IDC_MOVE_TAB_NEXT;
194 break;
196 case GDK_Page_Up:
197 if (GDK_CONTROL_MASK == modifier) {
198 return IDC_SELECT_PREVIOUS_TAB;
199 } else if ((GDK_CONTROL_MASK | GDK_SHIFT_MASK) == modifier) {
200 return IDC_MOVE_TAB_PREVIOUS;
202 break;
204 default:
205 break;
207 return -1;
210 GQuark GetBrowserWindowQuarkKey() {
211 static GQuark quark = g_quark_from_static_string(kBrowserWindowKey);
212 return quark;
215 } // namespace
217 BrowserWindowGtk::BrowserWindowGtk(Browser* browser)
218 : window_(NULL),
219 window_has_shown_(false),
220 window_container_(NULL),
221 window_vbox_(NULL),
222 render_area_vbox_(NULL),
223 render_area_floating_container_(NULL),
224 render_area_event_box_(NULL),
225 toolbar_border_(NULL),
226 browser_(browser),
227 state_(GDK_WINDOW_STATE_WITHDRAWN),
228 devtools_window_(NULL),
229 devtools_floating_container_(NULL),
230 frame_cursor_(NULL),
231 is_active_(false),
232 show_state_after_show_(ui::SHOW_STATE_DEFAULT),
233 suppress_window_raise_(false),
234 accel_group_(NULL),
235 is_fullscreen_(false) {
238 BrowserWindowGtk::~BrowserWindowGtk() {
239 ui::ActiveWindowWatcherX::RemoveObserver(this);
241 browser_->tab_strip_model()->RemoveObserver(this);
244 void BrowserWindowGtk::Init() {
245 // We register first so that other views like the toolbar can use the
246 // is_active() function in their ActiveWindowChanged() handlers.
247 ui::ActiveWindowWatcherX::AddObserver(this);
249 use_custom_frame_pref_.Init(
250 prefs::kUseCustomChromeFrame,
251 browser_->profile()->GetPrefs(),
252 base::Bind(&BrowserWindowGtk::OnUseCustomChromeFrameChanged,
253 base::Unretained(this)));
255 // Register to be notified of changes to the profile's avatar icon.
256 if (!browser_->profile()->IsOffTheRecord()) {
257 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
258 content::NotificationService::AllSources());
261 // In some (older) versions of compiz, raising top-level windows when they
262 // are partially off-screen causes them to get snapped back on screen, not
263 // always even on the current virtual desktop. If we are running under
264 // compiz, suppress such raises, as they are not necessary in compiz anyway.
265 if (ui::GuessWindowManager() == ui::WM_COMPIZ)
266 suppress_window_raise_ = true;
268 window_ = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
269 g_object_set_qdata(G_OBJECT(window_), GetBrowserWindowQuarkKey(), this);
270 gtk_widget_add_events(GTK_WIDGET(window_), GDK_BUTTON_PRESS_MASK |
271 GDK_POINTER_MOTION_MASK);
273 // Disable the resize gripper on Ubuntu.
274 gtk_window_util::DisableResizeGrip(window_);
276 // Add this window to its own unique window group to allow for
277 // window-to-parent modality.
278 gtk_window_group_add_window(gtk_window_group_new(), window_);
279 g_object_unref(gtk_window_get_group(window_));
281 // Set up a custom WM_CLASS for some sorts of window types. This allows
282 // task switchers to distinguish between main browser windows and e.g
283 // app windows.
284 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
285 if (browser_->is_app()) {
286 std::string app_name = browser_->app_name();
287 if (app_name != DevToolsWindow::kDevToolsApp) {
288 gtk_window_util::SetWindowCustomClass(window_,
289 web_app::GetWMClassFromAppName(app_name));
291 } else if (command_line.HasSwitch(switches::kUserDataDir)) {
292 // Set the class name to e.g. "Chrome (/tmp/my-user-data)". The
293 // class name will show up in the alt-tab list in gnome-shell if
294 // you're running a binary that doesn't have a matching .desktop
295 // file.
296 const std::string user_data_dir =
297 command_line.GetSwitchValueNative(switches::kUserDataDir);
298 gtk_window_util::SetWindowCustomClass(window_,
299 std::string(gdk_get_program_class()) + " (" + user_data_dir + ")");
302 // For popups, we initialize widgets then set the window geometry, because
303 // popups need the widgets inited before they can set the window size
304 // properly. For other windows, we set the geometry first to prevent resize
305 // flicker.
306 if (browser_->is_type_popup()) {
307 gtk_window_set_role(window_, "pop-up");
308 InitWidgets();
309 SetGeometryHints();
310 } else {
311 gtk_window_set_role(window_, "browser");
312 SetGeometryHints();
313 InitWidgets();
316 ConnectAccelerators();
318 // Set the initial background color of widgets.
319 SetBackgroundColor();
320 HideUnsupportedWindowFeatures();
322 if (UseCustomFrame()) {
323 // Setting _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED tells gnome-shell to not force
324 // fullscreen on the window when it matches the desktop size.
325 ui::SetHideTitlebarWhenMaximizedProperty(
326 ui::GetX11WindowFromGtkWidget(GTK_WIDGET(window_)),
327 ui::HIDE_TITLEBAR_WHEN_MAXIMIZED);
331 gboolean BrowserWindowGtk::OnCustomFrameExpose(GtkWidget* widget,
332 GdkEventExpose* event) {
333 TRACE_EVENT0("ui::gtk", "BrowserWindowGtk::OnCustomFrameExpose");
335 // Draw the default background.
336 cairo_t* cr = gdk_cairo_create(gtk_widget_get_window(widget));
337 gdk_cairo_rectangle(cr, &event->area);
338 cairo_clip(cr);
340 if (UsingCustomPopupFrame()) {
341 DrawPopupFrame(cr, widget, event);
342 } else {
343 DrawCustomFrame(cr, widget, event);
346 DrawContentShadow(cr);
348 cairo_destroy(cr);
350 if (UseCustomFrame() && !IsMaximized())
351 DrawCustomFrameBorder(widget);
353 return FALSE; // Allow subwidgets to paint.
356 void BrowserWindowGtk::DrawCustomFrameBorder(GtkWidget* widget) {
357 static NineBox* custom_frame_border = NULL;
358 if (!custom_frame_border) {
359 custom_frame_border = new NineBox(IDR_WINDOW_TOP_LEFT_CORNER,
360 IDR_WINDOW_TOP_CENTER,
361 IDR_WINDOW_TOP_RIGHT_CORNER,
362 IDR_WINDOW_LEFT_SIDE,
364 IDR_WINDOW_RIGHT_SIDE,
365 IDR_WINDOW_BOTTOM_LEFT_CORNER,
366 IDR_WINDOW_BOTTOM_CENTER,
367 IDR_WINDOW_BOTTOM_RIGHT_CORNER);
369 custom_frame_border->RenderToWidget(widget);
372 void BrowserWindowGtk::DrawContentShadow(cairo_t* cr) {
373 // Draw the shadow above the toolbar. Tabs on the tabstrip will draw over us.
374 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
375 int left_x, top_y;
376 gtk_widget_translate_coordinates(toolbar_->widget(),
377 GTK_WIDGET(window_), 0, 0, &left_x,
378 &top_y);
380 GtkAllocation window_vbox_allocation;
381 gtk_widget_get_allocation(window_vbox_, &window_vbox_allocation);
382 int center_width = window_vbox_allocation.width;
384 gfx::CairoCachedSurface* top_center =
385 rb.GetNativeImageNamed(IDR_CONTENT_TOP_CENTER).ToCairo();
386 gfx::CairoCachedSurface* top_right =
387 rb.GetNativeImageNamed(IDR_CONTENT_TOP_RIGHT_CORNER).ToCairo();
388 gfx::CairoCachedSurface* top_left =
389 rb.GetNativeImageNamed(IDR_CONTENT_TOP_LEFT_CORNER).ToCairo();
391 int center_left_x = left_x;
392 if (ShouldDrawContentDropShadow()) {
393 // Don't draw over the corners.
394 center_left_x += top_left->Width() - kContentShadowThickness;
395 center_width -= (top_left->Width() + top_right->Width());
396 center_width += 2 * kContentShadowThickness;
399 top_center->SetSource(cr, GTK_WIDGET(window_),
400 center_left_x, top_y - kContentShadowThickness);
401 cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
402 cairo_rectangle(cr, center_left_x, top_y - kContentShadowThickness,
403 center_width, top_center->Height());
404 cairo_fill(cr);
406 // Only draw the rest of the shadow if the user has the custom frame enabled
407 // and the browser is not maximized.
408 if (!ShouldDrawContentDropShadow())
409 return;
411 // The top left corner has a width of 3 pixels. On Windows, the last column
412 // of pixels overlap the toolbar. We just crop it off on Linux. The top
413 // corners extend to the base of the toolbar (one pixel above the dividing
414 // line).
415 int right_x = center_left_x + center_width;
416 top_left->SetSource(cr, GTK_WIDGET(window_),
417 left_x - kContentShadowThickness, top_y - kContentShadowThickness);
418 // The toolbar is shorter in location bar only mode so clip the image to the
419 // height of the toolbar + the amount of shadow above the toolbar.
420 cairo_rectangle(cr,
421 left_x - kContentShadowThickness,
422 top_y - kContentShadowThickness,
423 top_left->Width(),
424 top_left->Height());
425 cairo_fill(cr);
427 // Likewise, we crop off the left column of pixels for the top right corner.
428 top_right->SetSource(cr, GTK_WIDGET(window_),
429 right_x, top_y - kContentShadowThickness);
430 cairo_rectangle(cr,
431 right_x,
432 top_y - kContentShadowThickness,
433 top_right->Width(),
434 top_right->Height());
435 cairo_fill(cr);
437 // Fill in the sides. As above, we only draw 2 of the 3 columns on Linux.
438 int bottom_y;
439 gtk_widget_translate_coordinates(window_vbox_,
440 GTK_WIDGET(window_),
441 0, window_vbox_allocation.height,
442 NULL, &bottom_y);
443 // |side_y| is where to start drawing the side shadows. The top corners draw
444 // the sides down to the bottom of the toolbar.
445 int side_y = top_y - kContentShadowThickness + top_right->Height();
446 // |side_height| is how many pixels to draw for the side borders. We do one
447 // pixel before the bottom of the web contents because that extra pixel is
448 // drawn by the bottom corners.
449 int side_height = bottom_y - side_y - 1;
450 if (side_height > 0) {
451 gfx::CairoCachedSurface* left =
452 rb.GetNativeImageNamed(IDR_CONTENT_LEFT_SIDE).ToCairo();
453 left->SetSource(cr, GTK_WIDGET(window_),
454 left_x - kContentShadowThickness, side_y);
455 cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
456 cairo_rectangle(cr,
457 left_x - kContentShadowThickness,
458 side_y,
459 kContentShadowThickness,
460 side_height);
461 cairo_fill(cr);
463 gfx::CairoCachedSurface* right =
464 rb.GetNativeImageNamed(IDR_CONTENT_RIGHT_SIDE).ToCairo();
465 int right_side_x =
466 right_x + top_right->Width() - kContentShadowThickness - 1;
467 right->SetSource(cr, GTK_WIDGET(window_), right_side_x, side_y);
468 cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
469 cairo_rectangle(cr,
470 right_side_x,
471 side_y,
472 kContentShadowThickness,
473 side_height);
474 cairo_fill(cr);
477 // Draw the bottom corners. The bottom corners also draw the bottom row of
478 // pixels of the side shadows.
479 gfx::CairoCachedSurface* bottom_left =
480 rb.GetNativeImageNamed(IDR_CONTENT_BOTTOM_LEFT_CORNER).ToCairo();
481 bottom_left->SetSource(cr, GTK_WIDGET(window_),
482 left_x - kContentShadowThickness, bottom_y - 1);
483 cairo_paint(cr);
485 gfx::CairoCachedSurface* bottom_right =
486 rb.GetNativeImageNamed(IDR_CONTENT_BOTTOM_RIGHT_CORNER).ToCairo();
487 bottom_right->SetSource(cr, GTK_WIDGET(window_), right_x - 1, bottom_y - 1);
488 cairo_paint(cr);
490 // Finally, draw the bottom row. Since we don't overlap the contents, we clip
491 // the top row of pixels.
492 gfx::CairoCachedSurface* bottom =
493 rb.GetNativeImageNamed(IDR_CONTENT_BOTTOM_CENTER).ToCairo();
494 bottom->SetSource(cr, GTK_WIDGET(window_), left_x + 1, bottom_y - 1);
495 cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
496 cairo_rectangle(cr,
497 left_x + 1,
498 bottom_y,
499 window_vbox_allocation.width - 2,
500 kContentShadowThickness);
501 cairo_fill(cr);
504 void BrowserWindowGtk::DrawPopupFrame(cairo_t* cr,
505 GtkWidget* widget,
506 GdkEventExpose* event) {
507 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
509 // Like DrawCustomFrame(), except that we use the unthemed resources to draw
510 // the background. We do this because we can't rely on sane images in the
511 // theme that we can draw text on. (We tried using the tab background, but
512 // that has inverse saturation from what the user usually expects).
513 int image_name = GetThemeFrameResource();
514 gfx::CairoCachedSurface* surface =
515 rb.GetNativeImageNamed(image_name).ToCairo();
516 surface->SetSource(cr, widget, 0, GetVerticalOffset());
517 cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REFLECT);
518 cairo_rectangle(cr, event->area.x, event->area.y,
519 event->area.width, event->area.height);
520 cairo_fill(cr);
523 void BrowserWindowGtk::DrawCustomFrame(cairo_t* cr,
524 GtkWidget* widget,
525 GdkEventExpose* event) {
526 GtkThemeService* theme_provider = GtkThemeService::GetFrom(
527 browser()->profile());
529 int image_name = GetThemeFrameResource();
531 gfx::CairoCachedSurface* surface = theme_provider->GetImageNamed(
532 image_name).ToCairo();
533 if (event->area.y < surface->Height()) {
534 surface->SetSource(cr, widget, 0, GetVerticalOffset());
536 // The frame background isn't tiled vertically.
537 cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
538 cairo_rectangle(cr, event->area.x, event->area.y,
539 event->area.width, surface->Height() - event->area.y);
540 cairo_fill(cr);
543 if (theme_provider->HasCustomImage(IDR_THEME_FRAME_OVERLAY) &&
544 !browser()->profile()->IsOffTheRecord()) {
545 gfx::CairoCachedSurface* theme_overlay = theme_provider->GetImageNamed(
546 DrawFrameAsActive() ? IDR_THEME_FRAME_OVERLAY
547 : IDR_THEME_FRAME_OVERLAY_INACTIVE).ToCairo();
548 theme_overlay->SetSource(cr, widget, 0, GetVerticalOffset());
549 cairo_paint(cr);
553 int BrowserWindowGtk::GetVerticalOffset() {
554 return (IsMaximized() || (!UseCustomFrame())) ?
555 -kCustomFrameBackgroundVerticalOffset : 0;
558 int BrowserWindowGtk::GetThemeFrameResource() {
559 bool incognito = browser()->profile()->IsOffTheRecord();
560 int image_name;
561 if (DrawFrameAsActive()) {
562 image_name = incognito ? IDR_THEME_FRAME_INCOGNITO : IDR_THEME_FRAME;
563 } else {
564 image_name = incognito ? IDR_THEME_FRAME_INCOGNITO_INACTIVE :
565 IDR_THEME_FRAME_INACTIVE;
568 return image_name;
571 void BrowserWindowGtk::Show() {
572 // The Browser associated with this browser window must become the active
573 // browser at the time Show() is called. This is the natural behaviour under
574 // Windows, but gtk_widget_show won't show the widget (and therefore won't
575 // call OnFocusIn()) until we return to the runloop. Therefore any calls to
576 // chrome::FindLastActiveWithHostDesktopType will return the previous
577 // browser instead if we don't explicitly set it here.
578 BrowserList::SetLastActive(browser());
580 gtk_window_present(window_);
581 if (show_state_after_show_ == ui::SHOW_STATE_MAXIMIZED) {
582 gtk_window_maximize(window_);
583 show_state_after_show_ = ui::SHOW_STATE_NORMAL;
584 } else if (show_state_after_show_ == ui::SHOW_STATE_MINIMIZED) {
585 gtk_window_iconify(window_);
586 show_state_after_show_ = ui::SHOW_STATE_NORMAL;
589 // If we have sized the window by setting a size request for the render
590 // area, then undo it so that the render view can later adjust its own
591 // size.
592 gtk_widget_set_size_request(devtools_floating_container_, -1, -1);
594 window_has_shown_ = true;
595 browser()->OnWindowDidShow();
598 void BrowserWindowGtk::ShowInactive() {
599 gtk_window_set_focus_on_map(window_, false);
600 gtk_widget_show(GTK_WIDGET(window_));
603 void BrowserWindowGtk::Hide() {
604 // Not implemented.
607 void BrowserWindowGtk::SetBoundsImpl(const gfx::Rect& bounds,
608 bool exterior,
609 bool move) {
610 gint x = static_cast<gint>(bounds.x());
611 gint y = static_cast<gint>(bounds.y());
612 gint width = static_cast<gint>(bounds.width());
613 gint height = static_cast<gint>(bounds.height());
615 if (move)
616 gtk_window_move(window_, x, y);
618 if (exterior) {
619 gtk_window_util::SetWindowSize(window_, gfx::Size(width, height));
620 } else {
621 gtk_widget_set_size_request(devtools_floating_container_,
622 width, height);
626 void BrowserWindowGtk::SetBounds(const gfx::Rect& bounds) {
627 if (IsFullscreen())
628 ExitFullscreen();
629 SetBoundsImpl(bounds, true, true);
632 void BrowserWindowGtk::Close() {
633 // We're already closing. Do nothing.
634 if (!window_)
635 return;
637 if (!CanClose())
638 return;
640 // We're going to destroy the window, make sure the tab strip isn't running
641 // any animations which may still reference GtkWidgets.
642 tabstrip_->StopAnimation();
644 SaveWindowPosition();
646 if (accel_group_) {
647 // Disconnecting the keys we connected to our accelerator group frees the
648 // closures allocated in ConnectAccelerators.
649 AcceleratorsGtk* accelerators = AcceleratorsGtk::GetInstance();
650 for (AcceleratorsGtk::const_iterator iter = accelerators->begin();
651 iter != accelerators->end(); ++iter) {
652 gtk_accel_group_disconnect_key(accel_group_,
653 ui::GetGdkKeyCodeForAccelerator(iter->second),
654 ui::GetGdkModifierForAccelerator(iter->second));
656 gtk_window_remove_accel_group(window_, accel_group_);
657 g_object_unref(accel_group_);
658 accel_group_ = NULL;
661 // Cancel any pending callback from the window configure debounce timer.
662 window_configure_debounce_timer_.Stop();
664 // Likewise for the loading animation.
665 loading_animation_timer_.Stop();
667 GtkWidget* window = GTK_WIDGET(window_);
668 // To help catch bugs in any event handlers that might get fired during the
669 // destruction, set window_ to NULL before any handlers will run.
670 window_ = NULL;
671 // Avoid use-after-free in any code that runs after Close() and forgets to
672 // check window_.
673 window_container_ = NULL;
674 window_vbox_ = NULL;
675 render_area_vbox_ = NULL;
676 render_area_floating_container_ = NULL;
677 render_area_event_box_ = NULL;
678 toolbar_border_ = NULL;
679 devtools_floating_container_ = NULL;
681 window_has_shown_ = false;
682 titlebar_->set_window(NULL);
684 // We don't want GlobalMenuBar handling any notifications or commands after
685 // the window is destroyed.
686 global_menu_bar_->Disable();
687 gtk_widget_destroy(window);
690 void BrowserWindowGtk::Activate() {
691 gtk_window_present(window_);
694 void BrowserWindowGtk::Deactivate() {
695 gdk_window_lower(gtk_widget_get_window(GTK_WIDGET(window_)));
698 bool BrowserWindowGtk::IsActive() const {
699 if (ui::ActiveWindowWatcherX::WMSupportsActivation())
700 return is_active_;
702 // This still works even though we don't get the activation notification.
703 return window_ && gtk_window_is_active(window_);
706 void BrowserWindowGtk::FlashFrame(bool flash) {
707 // May not be respected by all window managers.
708 gtk_window_set_urgency_hint(window_, flash);
711 bool BrowserWindowGtk::IsAlwaysOnTop() const {
712 return false;
715 void BrowserWindowGtk::SetAlwaysOnTop(bool always_on_top) {
716 // Not implemented for browser windows.
717 NOTIMPLEMENTED();
720 gfx::NativeWindow BrowserWindowGtk::GetNativeWindow() {
721 return window_;
724 BrowserWindowTesting* BrowserWindowGtk::GetBrowserWindowTesting() {
725 NOTIMPLEMENTED();
726 return NULL;
729 StatusBubble* BrowserWindowGtk::GetStatusBubble() {
730 return status_bubble_.get();
733 void BrowserWindowGtk::UpdateTitleBar() {
734 TRACE_EVENT0("ui::gtk", "BrowserWindowGtk::UpdateTitleBar");
735 base::string16 title = browser_->GetWindowTitleForCurrentTab();
736 gtk_window_set_title(window_, base::UTF16ToUTF8(title).c_str());
737 if (ShouldShowWindowIcon())
738 titlebar_->UpdateTitleAndIcon();
741 void BrowserWindowGtk::BookmarkBarStateChanged(
742 BookmarkBar::AnimateChangeType change_type) {
743 MaybeShowBookmarkBar(change_type == BookmarkBar::ANIMATE_STATE_CHANGE);
746 void BrowserWindowGtk::UpdateDevTools() {
747 UpdateDevToolsForContents(
748 browser_->tab_strip_model()->GetActiveWebContents());
751 void BrowserWindowGtk::UpdateLoadingAnimations(bool should_animate) {
752 if (should_animate) {
753 if (!loading_animation_timer_.IsRunning()) {
754 // Loads are happening, and the timer isn't running, so start it.
755 loading_animation_timer_.Start(FROM_HERE,
756 base::TimeDelta::FromMilliseconds(kLoadingAnimationFrameTimeMs), this,
757 &BrowserWindowGtk::LoadingAnimationCallback);
759 } else {
760 if (loading_animation_timer_.IsRunning()) {
761 loading_animation_timer_.Stop();
762 // Loads are now complete, update the state if a task was scheduled.
763 LoadingAnimationCallback();
768 void BrowserWindowGtk::LoadingAnimationCallback() {
769 if (browser_->is_type_tabbed()) {
770 // Loading animations are shown in the tab for tabbed windows. We check the
771 // browser type instead of calling IsTabStripVisible() because the latter
772 // will return false for fullscreen windows, but we still need to update
773 // their animations (so that when they come out of fullscreen mode they'll
774 // be correct).
775 tabstrip_->UpdateLoadingAnimations();
776 } else if (ShouldShowWindowIcon()) {
777 // ... or in the window icon area for popups and app windows.
778 WebContents* web_contents =
779 browser_->tab_strip_model()->GetActiveWebContents();
780 // GetSelectedTabContents can return NULL for example under Purify when
781 // the animations are running slowly and this function is called on
782 // a timer through LoadingAnimationCallback.
783 titlebar_->UpdateThrobber(web_contents);
787 void BrowserWindowGtk::SetStarredState(bool is_starred) {
788 toolbar_->GetLocationBarView()->SetStarred(is_starred);
791 void BrowserWindowGtk::SetTranslateIconToggled(bool is_lit) {
792 NOTIMPLEMENTED();
795 void BrowserWindowGtk::OnActiveTabChanged(WebContents* old_contents,
796 WebContents* new_contents,
797 int index,
798 int reason) {
799 TRACE_EVENT0("ui::gtk", "BrowserWindowGtk::ActiveTabChanged");
800 if (old_contents && !old_contents->IsBeingDestroyed())
801 old_contents->GetView()->StoreFocus();
803 // Update various elements that are interested in knowing the current
804 // WebContents.
805 infobar_container_->ChangeInfoBarService(
806 InfoBarService::FromWebContents(new_contents));
807 contents_container_->SetTab(new_contents);
808 UpdateDevToolsForContents(new_contents);
810 // TODO(estade): after we manage browser activation, add a check to make sure
811 // we are the active browser before calling RestoreFocus().
812 if (!browser_->tab_strip_model()->closing_all()) {
813 new_contents->GetView()->RestoreFocus();
814 FindTabHelper* find_tab_helper =
815 FindTabHelper::FromWebContents(new_contents);
816 if (find_tab_helper->find_ui_active())
817 browser_->GetFindBarController()->find_bar()->SetFocusAndSelection();
820 // Update all the UI bits.
821 UpdateTitleBar();
822 MaybeShowBookmarkBar(false);
824 void BrowserWindowGtk::ZoomChangedForActiveTab(bool can_show_bubble) {
825 toolbar_->GetLocationBarView()->ZoomChangedForActiveTab(
826 can_show_bubble && !toolbar_->IsWrenchMenuShowing());
829 gfx::Rect BrowserWindowGtk::GetRestoredBounds() const {
830 return restored_bounds_;
833 ui::WindowShowState BrowserWindowGtk::GetRestoredState() const {
834 if (IsMaximized())
835 return ui::SHOW_STATE_MAXIMIZED;
836 if (IsMinimized())
837 return ui::SHOW_STATE_MINIMIZED;
838 return ui::SHOW_STATE_NORMAL;
841 gfx::Rect BrowserWindowGtk::GetBounds() const {
842 return bounds_;
845 bool BrowserWindowGtk::IsMaximized() const {
846 return (state_ & GDK_WINDOW_STATE_MAXIMIZED);
849 bool BrowserWindowGtk::IsMinimized() const {
850 return (state_ & GDK_WINDOW_STATE_ICONIFIED);
853 void BrowserWindowGtk::Maximize() {
854 gtk_window_maximize(window_);
857 void BrowserWindowGtk::Minimize() {
858 gtk_window_iconify(window_);
861 void BrowserWindowGtk::Restore() {
862 if (IsMaximized())
863 UnMaximize();
864 else if (IsMinimized())
865 gtk_window_deiconify(window_);
868 bool BrowserWindowGtk::ShouldDrawContentDropShadow() const {
869 return !IsMaximized() && UseCustomFrame();
872 void BrowserWindowGtk::EnterFullscreen(
873 const GURL& url, FullscreenExitBubbleType type) {
874 if (IsFullscreen())
875 return; // Nothing to do.
876 is_fullscreen_ = true;
878 // gtk_window_(un)fullscreen asks the window manager to toggle the EWMH
879 // for fullscreen windows. Not all window managers support this.
880 gtk_window_fullscreen(window_);
882 browser_->WindowFullscreenStateChanged();
883 UpdateCustomFrame();
884 toolbar_->Hide();
885 tabstrip_->Hide();
886 if (bookmark_bar_.get())
887 gtk_widget_hide(bookmark_bar_->widget());
888 if (!chrome::IsRunningInAppMode()) {
889 UpdateFullscreenExitBubbleContent(url, type);
891 gtk_widget_hide(titlebar_widget());
892 gtk_widget_hide(toolbar_border_);
895 void BrowserWindowGtk::UpdateFullscreenExitBubbleContent(
896 const GURL& url, FullscreenExitBubbleType bubble_type) {
897 if (!window_) {
898 // Don't create a fullscreen bubble for a closing window.
899 return;
900 } else if (bubble_type == FEB_TYPE_NONE) {
901 fullscreen_exit_bubble_.reset();
902 } else if (fullscreen_exit_bubble_.get()) {
903 fullscreen_exit_bubble_->UpdateContent(url, bubble_type);
904 } else {
905 fullscreen_exit_bubble_.reset(new FullscreenExitBubbleGtk(
906 GTK_FLOATING_CONTAINER(render_area_floating_container_),
907 browser(),
908 url,
909 bubble_type));
913 void BrowserWindowGtk::ExitFullscreen() {
914 if (!IsFullscreen())
915 return; // Nothing to do.
916 is_fullscreen_ = false;
918 // Work around a bug where if we try to unfullscreen, metacity immediately
919 // fullscreens us again. This is a little flickery and not necessary if
920 // there's a gnome-panel, but it's not easy to detect whether there's a
921 // panel or not.
922 bool unmaximize_before_unfullscreen = IsMaximized() &&
923 ui::GuessWindowManager() == ui::WM_METACITY;
924 if (unmaximize_before_unfullscreen)
925 UnMaximize();
927 gtk_window_unfullscreen(window_);
929 if (unmaximize_before_unfullscreen)
930 gtk_window_maximize(window_);
932 browser_->WindowFullscreenStateChanged();
933 gtk_widget_show(titlebar_widget());
934 UpdateFullscreenExitBubbleContent(GURL(), FEB_TYPE_NONE);
935 UpdateCustomFrame();
936 ShowSupportedWindowFeatures();
939 bool BrowserWindowGtk::ShouldHideUIForFullscreen() const {
940 return IsFullscreen();
943 bool BrowserWindowGtk::IsFullscreen() const {
944 return is_fullscreen_;
947 bool BrowserWindowGtk::IsFullscreenBubbleVisible() const {
948 return fullscreen_exit_bubble_ != NULL;
951 LocationBar* BrowserWindowGtk::GetLocationBar() const {
952 return toolbar_->GetLocationBar();
955 void BrowserWindowGtk::SetFocusToLocationBar(bool select_all) {
956 if (!IsFullscreen())
957 GetLocationBar()->FocusLocation(select_all);
960 void BrowserWindowGtk::UpdateReloadStopState(bool is_loading, bool force) {
961 toolbar_->GetReloadButton()->ChangeMode(
962 is_loading ? ReloadButtonGtk::MODE_STOP : ReloadButtonGtk::MODE_RELOAD,
963 force);
966 void BrowserWindowGtk::UpdateToolbar(content::WebContents* contents) {
967 TRACE_EVENT0("ui::gtk", "BrowserWindowGtk::UpdateToolbar");
968 toolbar_->UpdateWebContents(contents);
971 void BrowserWindowGtk::FocusToolbar() {
972 NOTIMPLEMENTED();
975 void BrowserWindowGtk::FocusAppMenu() {
976 NOTIMPLEMENTED();
979 void BrowserWindowGtk::FocusBookmarksToolbar() {
980 NOTIMPLEMENTED();
983 void BrowserWindowGtk::FocusInfobars() {
984 NOTIMPLEMENTED();
987 void BrowserWindowGtk::RotatePaneFocus(bool forwards) {
988 NOTIMPLEMENTED();
991 bool BrowserWindowGtk::IsBookmarkBarVisible() const {
992 return browser_->SupportsWindowFeature(Browser::FEATURE_BOOKMARKBAR) &&
993 bookmark_bar_.get() &&
994 browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
997 bool BrowserWindowGtk::IsBookmarkBarAnimating() const {
998 if (IsBookmarkBarSupported() && bookmark_bar_->IsAnimating())
999 return true;
1000 return false;
1003 bool BrowserWindowGtk::IsTabStripEditable() const {
1004 return !tabstrip()->IsDragSessionActive() &&
1005 !tabstrip()->IsActiveDropTarget();
1008 bool BrowserWindowGtk::IsToolbarVisible() const {
1009 return IsToolbarSupported();
1012 gfx::Rect BrowserWindowGtk::GetRootWindowResizerRect() const {
1013 return gfx::Rect();
1016 void BrowserWindowGtk::ConfirmAddSearchProvider(TemplateURL* template_url,
1017 Profile* profile) {
1018 new EditSearchEngineDialog(window_, template_url, NULL, profile);
1021 void BrowserWindowGtk::ShowUpdateChromeDialog() {
1022 UpdateRecommendedDialog::Show(window_);
1025 void BrowserWindowGtk::ShowBookmarkBubble(const GURL& url,
1026 bool already_bookmarked) {
1027 toolbar_->GetLocationBarView()->ShowStarBubble(url, !already_bookmarked);
1030 void BrowserWindowGtk::ShowTranslateBubble(
1031 content::WebContents* contents,
1032 TranslateBubbleModel::ViewState view_state,
1033 TranslateErrors::Type error_type) {
1034 NOTIMPLEMENTED();
1037 #if defined(ENABLE_ONE_CLICK_SIGNIN)
1038 void BrowserWindowGtk::ShowOneClickSigninBubble(
1039 OneClickSigninBubbleType type,
1040 const base::string16& email,
1041 const base::string16& error_message,
1042 const StartSyncCallback& start_sync_callback) {
1044 new OneClickSigninBubbleGtk(this, type, email,
1045 error_message, start_sync_callback);
1047 #endif
1049 bool BrowserWindowGtk::IsDownloadShelfVisible() const {
1050 return download_shelf_.get() && download_shelf_->IsShowing();
1053 DownloadShelf* BrowserWindowGtk::GetDownloadShelf() {
1054 if (!download_shelf_.get())
1055 download_shelf_.reset(new DownloadShelfGtk(browser_.get(),
1056 render_area_vbox_));
1057 return download_shelf_.get();
1060 void BrowserWindowGtk::UserChangedTheme() {
1061 SetBackgroundColor();
1062 InvalidateWindow();
1063 UpdateWindowShape(bounds_.width(), bounds_.height());
1066 int BrowserWindowGtk::GetExtraRenderViewHeight() const {
1067 int sum = infobar_container_->TotalHeightOfAnimatingBars();
1068 if (IsBookmarkBarSupported() && bookmark_bar_->IsAnimating())
1069 sum += bookmark_bar_->GetHeight();
1070 if (download_shelf_.get() && download_shelf_->IsClosing())
1071 sum += download_shelf_->GetHeight();
1072 return sum;
1075 void BrowserWindowGtk::WebContentsFocused(WebContents* contents) {
1076 NOTIMPLEMENTED();
1079 void BrowserWindowGtk::ShowWebsiteSettings(
1080 Profile* profile,
1081 content::WebContents* web_contents,
1082 const GURL& url,
1083 const content::SSLStatus& ssl) {
1084 WebsiteSettingsPopupGtk::Show(GetNativeWindow(), profile, web_contents, url,
1085 ssl);
1088 void BrowserWindowGtk::ShowAppMenu() {
1089 toolbar_->ShowAppMenu();
1092 bool BrowserWindowGtk::PreHandleKeyboardEvent(
1093 const NativeWebKeyboardEvent& event, bool* is_keyboard_shortcut) {
1094 GdkEventKey* os_event = &event.os_event->key;
1096 if (!os_event || event.type != blink::WebInputEvent::RawKeyDown)
1097 return false;
1099 if (ExtensionKeybindingRegistryGtk::shortcut_handling_suspended())
1100 return false;
1102 // We first find out the browser command associated to the |event|.
1103 // Then if the command is a reserved one, and should be processed immediately
1104 // according to the |event|, the command will be executed immediately.
1105 // Otherwise we just set |*is_keyboard_shortcut| properly and return false.
1107 // First check if it's a custom accelerator.
1108 int id = GetCustomCommandId(os_event);
1110 // Then check if it's a predefined accelerator bound to the window.
1111 if (id == -1) {
1112 // This piece of code is based on the fact that calling
1113 // gtk_window_activate_key() method against |window_| may only trigger a
1114 // browser command execution, by matching a global accelerator
1115 // defined in above |kAcceleratorMap|.
1117 // Here we need to retrieve the command id (if any) associated to the
1118 // keyboard event. Instead of looking up the command id in above
1119 // |kAcceleratorMap| table by ourselves, we block the command execution of
1120 // the |browser_| object then send the keyboard event to the |window_| by
1121 // calling gtk_window_activate_key() method, as if we are activating an
1122 // accelerator key. Then we can retrieve the command id from the
1123 // |browser_| object.
1125 // Pros of this approach:
1126 // 1. We don't need to care about keyboard layout problem, as
1127 // gtk_window_activate_key() method handles it for us.
1129 // Cons:
1130 // 1. The logic is a little complicated.
1131 // 2. We should be careful not to introduce any accelerators that trigger
1132 // customized code instead of browser commands.
1133 bool original_block_command_state =
1134 browser_->command_controller()->block_command_execution();
1135 browser_->command_controller()->SetBlockCommandExecution(true);
1136 gtk_window_activate_key(window_, os_event);
1137 // We don't need to care about the WindowOpenDisposition value,
1138 // because all commands executed in this path use the default value.
1139 id = browser_->command_controller()->GetLastBlockedCommand(NULL);
1140 browser_->command_controller()->SetBlockCommandExecution(
1141 original_block_command_state);
1144 if (id == -1)
1145 return false;
1147 // Executing the command may cause |this| object to be destroyed.
1148 if (browser_->command_controller()->IsReservedCommandOrKey(id, event) &&
1149 !event.match_edit_command) {
1150 return chrome::ExecuteCommand(browser_.get(), id);
1153 // The |event| is a keyboard shortcut.
1154 DCHECK(is_keyboard_shortcut != NULL);
1155 *is_keyboard_shortcut = true;
1157 return false;
1160 void BrowserWindowGtk::HandleKeyboardEvent(
1161 const NativeWebKeyboardEvent& event) {
1162 GdkEventKey* os_event = &event.os_event->key;
1164 if (!os_event || event.type != blink::WebInputEvent::RawKeyDown)
1165 return;
1167 // Handles a key event in following sequence:
1168 // 1. Our special key accelerators, such as ctrl-tab, etc.
1169 // 2. Gtk accelerators.
1170 // This sequence matches the default key press handler of GtkWindow.
1172 // It's not necessary to care about the keyboard layout, as
1173 // gtk_window_activate_key() takes care of it automatically.
1174 int id = GetCustomCommandId(os_event);
1175 if (id != -1)
1176 chrome::ExecuteCommand(browser_.get(), id);
1177 else
1178 gtk_window_activate_key(window_, os_event);
1181 void BrowserWindowGtk::Cut() {
1182 gtk_window_util::DoCut(
1183 window_, browser_->tab_strip_model()->GetActiveWebContents());
1186 void BrowserWindowGtk::Copy() {
1187 gtk_window_util::DoCopy(
1188 window_, browser_->tab_strip_model()->GetActiveWebContents());
1191 void BrowserWindowGtk::Paste() {
1192 gtk_window_util::DoPaste(
1193 window_, browser_->tab_strip_model()->GetActiveWebContents());
1196 WindowOpenDisposition BrowserWindowGtk::GetDispositionForPopupBounds(
1197 const gfx::Rect& bounds) {
1198 return NEW_POPUP;
1201 FindBar* BrowserWindowGtk::CreateFindBar() {
1202 return new FindBarGtk(this);
1205 WebContentsModalDialogHost* BrowserWindowGtk::GetWebContentsModalDialogHost() {
1206 return NULL;
1209 void BrowserWindowGtk::ShowAvatarBubble(WebContents* web_contents,
1210 const gfx::Rect& rect) {
1211 GtkWidget* widget = web_contents->GetView()->GetContentNativeView();
1212 new AvatarMenuBubbleGtk(browser_.get(), widget, BubbleGtk::ANCHOR_TOP_RIGHT,
1213 &rect);
1216 void BrowserWindowGtk::ShowAvatarBubbleFromAvatarButton() {
1217 if (titlebar_->avatar_button())
1218 titlebar_->avatar_button()->ShowAvatarBubble();
1221 void BrowserWindowGtk::ShowPasswordGenerationBubble(
1222 const gfx::Rect& rect,
1223 const autofill::PasswordForm& form,
1224 autofill::PasswordGenerator* password_generator) {
1225 WebContents* web_contents =
1226 browser_->tab_strip_model()->GetActiveWebContents();
1227 if (!web_contents || !web_contents->GetView()->GetContentNativeView()) {
1228 return;
1231 new PasswordGenerationBubbleGtk(rect, form, web_contents, password_generator);
1234 void BrowserWindowGtk::ConfirmBrowserCloseWithPendingDownloads(
1235 int download_count,
1236 Browser::DownloadClosePreventionType dialog_type,
1237 bool app_modal,
1238 const base::Callback<void(bool)>& callback) {
1239 DownloadInProgressDialogGtk::Show(
1240 GetNativeWindow(), download_count, dialog_type, app_modal, callback);
1244 BrowserWindowGtk::GetRenderViewHeightInsetWithDetachedBookmarkBar() {
1245 if (!bookmark_bar_.get() ||
1246 browser_->bookmark_bar_state() != BookmarkBar::DETACHED) {
1247 return 0;
1249 return bookmark_bar_->max_height();
1252 void BrowserWindowGtk::Observe(int type,
1253 const content::NotificationSource& source,
1254 const content::NotificationDetails& details) {
1255 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, type);
1256 // The profile avatar icon may have changed.
1257 gtk_util::SetWindowIcon(window_, browser_->profile());
1260 void BrowserWindowGtk::TabDetachedAt(WebContents* contents, int index) {
1261 // We use index here rather than comparing |contents| because by this time
1262 // the model has already removed |contents| from its list, so
1263 // browser_->tab_strip_model()->GetActiveWebContents() will return NULL or
1264 // something else.
1265 if (index == browser_->tab_strip_model()->active_index()) {
1266 infobar_container_->ChangeInfoBarService(NULL);
1267 UpdateDevToolsForContents(NULL);
1269 contents_container_->DetachTab(contents);
1272 void BrowserWindowGtk::ActiveWindowChanged(GdkWindow* active_window) {
1273 // Do nothing if we're in the process of closing the browser window.
1274 if (!window_)
1275 return;
1277 bool is_active = gtk_widget_get_window(GTK_WIDGET(window_)) == active_window;
1278 bool changed = (is_active != is_active_);
1280 if (is_active && changed) {
1281 // If there's an app modal dialog (e.g., JS alert), try to redirect
1282 // the user's attention to the window owning the dialog.
1283 if (AppModalDialogQueue::GetInstance()->HasActiveDialog()) {
1284 AppModalDialogQueue::GetInstance()->ActivateModalDialog();
1285 return;
1289 is_active_ = is_active;
1290 if (changed) {
1291 SetBackgroundColor();
1292 InvalidateWindow();
1293 // For some reason, the above two calls cause the window shape to be
1294 // lost so reset it.
1295 UpdateWindowShape(bounds_.width(), bounds_.height());
1299 SkColor BrowserWindowGtk::GetInfoBarSeparatorColor() const {
1300 GtkThemeService* theme_service = GtkThemeService::GetFrom(
1301 browser()->profile());
1302 return gfx::GdkColorToSkColor(theme_service->GetBorderColor());
1305 void BrowserWindowGtk::InfoBarContainerStateChanged(bool is_animating) {
1306 InvalidateInfoBarBits();
1309 bool BrowserWindowGtk::DrawInfoBarArrows(int* x) const {
1310 if (x) {
1311 // This is a views specific call that made its way into the interface. We
1312 // go through GetXPositionOfLocationIcon() since we need widget relativity.
1313 *x = 0;
1314 NOTREACHED();
1316 return true;
1319 extensions::ActiveTabPermissionGranter*
1320 BrowserWindowGtk::GetActiveTabPermissionGranter() {
1321 WebContents* tab = GetDisplayedTab();
1322 if (!tab)
1323 return NULL;
1324 return extensions::TabHelper::FromWebContents(tab)->
1325 active_tab_permission_granter();
1328 void BrowserWindowGtk::DestroyBrowser() {
1329 browser_.reset();
1332 gboolean BrowserWindowGtk::OnConfigure(GtkWidget* widget,
1333 GdkEventConfigure* event) {
1334 gfx::Rect bounds(event->x, event->y, event->width, event->height);
1336 // When the window moves, we'll get multiple configure-event signals. We can
1337 // also get events when the bounds haven't changed, but the window's stacking
1338 // has, which we aren't interested in. http://crbug.com/70125
1339 if (bounds == configure_bounds_)
1340 return FALSE;
1342 GetLocationBar()->GetOmniboxView()->CloseOmniboxPopup();
1344 WebContents* tab = GetDisplayedTab();
1345 if (tab)
1346 tab->GetRenderViewHost()->NotifyMoveOrResizeStarted();
1348 if (bounds_.size() != bounds.size())
1349 UpdateWindowShape(bounds.width(), bounds.height());
1351 // We update |bounds_| but not |restored_bounds_| here. The latter needs
1352 // to be updated conditionally when the window is non-maximized and non-
1353 // fullscreen, but whether those state updates have been processed yet is
1354 // window-manager specific. We update |restored_bounds_| in the debounced
1355 // handler below, after the window state has been updated.
1356 bounds_ = bounds;
1357 configure_bounds_ = bounds;
1359 // The GdkEventConfigure* we get here doesn't have quite the right
1360 // coordinates though (they're relative to the drawable window area, rather
1361 // than any window manager decorations, if enabled), so we need to call
1362 // gtk_window_get_position() to get the right values. (Otherwise session
1363 // restore, if enabled, will restore windows to incorrect positions.) That's
1364 // a round trip to the X server though, so we set a debounce timer and only
1365 // call it (in OnDebouncedBoundsChanged() below) after we haven't seen a
1366 // reconfigure event in a short while.
1367 // We don't use Reset() because the timer may not yet be running.
1368 // (In that case Stop() is a no-op.)
1369 window_configure_debounce_timer_.Stop();
1370 window_configure_debounce_timer_.Start(FROM_HERE,
1371 base::TimeDelta::FromMilliseconds(kDebounceTimeoutMilliseconds), this,
1372 &BrowserWindowGtk::OnDebouncedBoundsChanged);
1374 return FALSE;
1377 void BrowserWindowGtk::OnDebouncedBoundsChanged() {
1378 gtk_window_util::UpdateWindowPosition(this, &bounds_, &restored_bounds_);
1379 SaveWindowPosition();
1382 gboolean BrowserWindowGtk::OnWindowState(GtkWidget* sender,
1383 GdkEventWindowState* event) {
1384 state_ = event->new_window_state;
1386 if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) {
1387 content::NotificationService::current()->Notify(
1388 chrome::NOTIFICATION_BROWSER_WINDOW_MAXIMIZED,
1389 content::Source<BrowserWindow>(this),
1390 content::NotificationService::NoDetails());
1393 titlebar_->UpdateCustomFrame(UseCustomFrame() && !IsFullscreen());
1394 UpdateWindowShape(bounds_.width(), bounds_.height());
1395 SaveWindowPosition();
1396 return FALSE;
1399 // Callback for the delete event. This event is fired when the user tries to
1400 // close the window (e.g., clicking on the X in the window manager title bar).
1401 gboolean BrowserWindowGtk::OnMainWindowDeleteEvent(GtkWidget* widget,
1402 GdkEvent* event) {
1403 Close();
1405 // Return true to prevent the gtk window from being destroyed. Close will
1406 // destroy it for us.
1407 return TRUE;
1410 void BrowserWindowGtk::OnMainWindowDestroy(GtkWidget* widget) {
1411 // Make sure we destroy this object while the main window is still valid.
1412 extension_keybinding_registry_.reset();
1414 // BUG 8712. When we gtk_widget_destroy() in Close(), this will emit the
1415 // signal right away, and we will be here (while Close() is still in the
1416 // call stack). In order to not reenter Close(), and to also follow the
1417 // expectations of BrowserList, we should run the BrowserWindowGtk destructor
1418 // not now, but after the run loop goes back to process messages. Otherwise
1419 // we will remove ourself from BrowserList while it's being iterated.
1420 // Additionally, now that we know the window is gone, we need to make sure to
1421 // set window_ to NULL, otherwise we will try to close the window again when
1422 // we call Close() in the destructor.
1424 // We don't want to use DeleteSoon() here since it won't work on a nested pump
1425 // (like in UI tests).
1426 base::MessageLoop::current()->PostTask(
1427 FROM_HERE, base::Bind(&base::DeletePointer<BrowserWindowGtk>, this));
1430 void BrowserWindowGtk::UnMaximize() {
1431 gtk_window_util::UnMaximize(window_, bounds_, restored_bounds_);
1434 bool BrowserWindowGtk::CanClose() const {
1435 // You cannot close a frame for which there is an active originating drag
1436 // session.
1437 if (tabstrip_->IsDragSessionActive())
1438 return false;
1440 // Give beforeunload handlers the chance to cancel the close before we hide
1441 // the window below.
1442 if (!browser_->ShouldCloseWindow())
1443 return false;
1445 bool fast_tab_closing_enabled =
1446 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableFastUnload);
1448 if (!browser_->tab_strip_model()->empty()) {
1449 // Tab strip isn't empty. Hide the window (so it appears to have closed
1450 // immediately) and close all the tabs, allowing the renderers to shut
1451 // down. When the tab strip is empty we'll be called back again.
1452 gtk_widget_hide(GTK_WIDGET(window_));
1453 browser_->OnWindowClosing();
1455 if (fast_tab_closing_enabled)
1456 browser_->tab_strip_model()->CloseAllTabs();
1457 return false;
1458 } else if (fast_tab_closing_enabled &&
1459 !browser_->HasCompletedUnloadProcessing()) {
1460 // The browser needs to finish running unload handlers.
1461 // Hide the window (so it appears to have closed immediately), and
1462 // the browser will call us back again when it is ready to close.
1463 gtk_widget_hide(GTK_WIDGET(window_));
1464 return false;
1467 // Empty TabStripModel, it's now safe to allow the Window to be closed.
1468 content::NotificationService::current()->Notify(
1469 chrome::NOTIFICATION_WINDOW_CLOSED,
1470 content::Source<GtkWindow>(window_),
1471 content::NotificationService::NoDetails());
1472 return true;
1475 bool BrowserWindowGtk::ShouldShowWindowIcon() const {
1476 return browser_->SupportsWindowFeature(Browser::FEATURE_TITLEBAR);
1479 void BrowserWindowGtk::AddFindBar(FindBarGtk* findbar) {
1480 gtk_floating_container_add_floating(
1481 GTK_FLOATING_CONTAINER(render_area_floating_container_),
1482 findbar->widget());
1485 void BrowserWindowGtk::ResetCustomFrameCursor() {
1486 if (!frame_cursor_)
1487 return;
1489 frame_cursor_ = NULL;
1490 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window_)), NULL);
1493 // static
1494 BrowserWindowGtk* BrowserWindowGtk::GetBrowserWindowForNativeWindow(
1495 gfx::NativeWindow window) {
1496 if (window) {
1497 return static_cast<BrowserWindowGtk*>(
1498 g_object_get_qdata(G_OBJECT(window), GetBrowserWindowQuarkKey()));
1501 return NULL;
1504 // static
1505 GtkWindow* BrowserWindowGtk::GetBrowserWindowForXID(XID xid) {
1506 GtkWindow* window = ui::GetGtkWindowFromX11Window(xid);
1507 // Use GetBrowserWindowForNativeWindow() to verify the GtkWindow we found
1508 // is actually a browser window (and not e.g. a dialog).
1509 if (!GetBrowserWindowForNativeWindow(window))
1510 return NULL;
1511 return window;
1514 GtkWidget* BrowserWindowGtk::titlebar_widget() const {
1515 return titlebar_->widget();
1518 // static
1519 void BrowserWindowGtk::RegisterProfilePrefs(
1520 user_prefs::PrefRegistrySyncable* registry) {
1521 bool custom_frame_default = false;
1522 // Avoid checking the window manager if we're not connected to an X server (as
1523 // is the case in Valgrind tests).
1524 if (ui::XDisplayExists())
1525 custom_frame_default = GetCustomFramePrefDefault();
1527 registry->RegisterBooleanPref(
1528 prefs::kUseCustomChromeFrame,
1529 custom_frame_default,
1530 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
1533 WebContents* BrowserWindowGtk::GetDisplayedTab() {
1534 return contents_container_->tab();
1537 void BrowserWindowGtk::QueueToolbarRedraw() {
1538 gtk_widget_queue_draw(toolbar_->widget());
1541 void BrowserWindowGtk::SetGeometryHints() {
1542 // If we call gtk_window_maximize followed by gtk_window_present, compiz gets
1543 // confused and maximizes the window, but doesn't set the
1544 // GDK_WINDOW_STATE_MAXIMIZED bit. So instead, we keep track of whether to
1545 // maximize and call it after gtk_window_present.
1546 gfx::Rect bounds;
1547 chrome::GetSavedWindowBoundsAndShowState(browser_.get(),
1548 &bounds,
1549 &show_state_after_show_);
1550 // We don't blindly call SetBounds here: that sets a forced position
1551 // on the window and we intentionally *don't* do that for normal
1552 // windows. Most programs do not restore their window position on
1553 // Linux, instead letting the window manager choose a position.
1555 // However, in cases like dropping a tab where the bounds are
1556 // specifically set, we do want to position explicitly. We also
1557 // force the position as part of session restore, as applications
1558 // that restore other, similar state (for instance GIMP, audacity,
1559 // pidgin, dia, and gkrellm) do tend to restore their positions.
1561 // For popup windows, we assume that if x == y == 0, the opening page
1562 // did not specify a position. Let the WM position the popup instead.
1563 bool is_popup = browser_->is_type_popup();
1564 bool popup_without_position = is_popup &&
1565 bounds.x() == 0 && bounds.y() == 0;
1566 bool move = browser_->bounds_overridden() && !popup_without_position;
1567 SetBoundsImpl(bounds, !is_popup, move);
1570 void BrowserWindowGtk::ConnectHandlersToSignals() {
1571 g_signal_connect(window_, "delete-event",
1572 G_CALLBACK(OnMainWindowDeleteEventThunk), this);
1573 g_signal_connect(window_, "destroy",
1574 G_CALLBACK(OnMainWindowDestroyThunk), this);
1575 g_signal_connect(window_, "configure-event",
1576 G_CALLBACK(OnConfigureThunk), this);
1577 g_signal_connect(window_, "window-state-event",
1578 G_CALLBACK(OnWindowStateThunk), this);
1579 g_signal_connect(window_, "key-press-event",
1580 G_CALLBACK(OnKeyPressThunk), this);
1581 g_signal_connect(window_, "motion-notify-event",
1582 G_CALLBACK(OnMouseMoveEventThunk), this);
1583 g_signal_connect(window_, "button-press-event",
1584 G_CALLBACK(OnButtonPressEventThunk), this);
1585 g_signal_connect(window_, "focus-in-event",
1586 G_CALLBACK(OnFocusInThunk), this);
1587 g_signal_connect(window_, "focus-out-event",
1588 G_CALLBACK(OnFocusOutThunk), this);
1591 void BrowserWindowGtk::InitWidgets() {
1592 ConnectHandlersToSignals();
1594 bounds_ = configure_bounds_ = restored_bounds_ =
1595 GetInitialWindowBounds(window_);
1597 // This vbox encompasses all of the widgets within the browser. This is
1598 // everything except the custom frame border.
1599 window_vbox_ = gtk_vbox_new(FALSE, 0);
1600 gtk_widget_show(window_vbox_);
1602 // We hold an always hidden GtkMenuBar inside our browser window simply to
1603 // fool the Unity desktop, which will mirror the contents of the first
1604 // GtkMenuBar it sees into the global menu bar. (It doesn't seem to check the
1605 // visibility of the GtkMenuBar, so we can just permanently hide it.)
1606 global_menu_bar_.reset(new GlobalMenuBar(browser_.get()));
1607 gtk_container_add(GTK_CONTAINER(window_vbox_), global_menu_bar_->widget());
1609 // The window container draws the custom browser frame.
1610 window_container_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
1611 gtk_widget_set_name(window_container_, "chrome-custom-frame-border");
1612 gtk_widget_set_app_paintable(window_container_, TRUE);
1613 gtk_widget_set_double_buffered(window_container_, FALSE);
1614 gtk_widget_set_redraw_on_allocate(window_container_, TRUE);
1615 g_signal_connect(window_container_, "expose-event",
1616 G_CALLBACK(OnCustomFrameExposeThunk), this);
1617 gtk_container_add(GTK_CONTAINER(window_container_), window_vbox_);
1619 tabstrip_.reset(new TabStripGtk(browser_->tab_strip_model(), this));
1620 tabstrip_->Init();
1622 // Build the titlebar (tabstrip + header space + min/max/close buttons).
1623 titlebar_.reset(new BrowserTitlebar(this, window_));
1624 titlebar_->Init();
1626 // Insert the tabstrip into the window.
1627 gtk_box_pack_start(GTK_BOX(window_vbox_), titlebar_->widget(), FALSE, FALSE,
1630 toolbar_.reset(new BrowserToolbarGtk(browser_.get(), this));
1631 toolbar_->Init(window_);
1632 gtk_box_pack_start(GTK_BOX(window_vbox_), toolbar_->widget(),
1633 FALSE, FALSE, 0);
1634 g_signal_connect_after(toolbar_->widget(), "expose-event",
1635 G_CALLBACK(OnExposeDrawInfobarBitsThunk), this);
1636 // This vbox surrounds the render area: find bar, info bars and render view.
1637 // The reason is that this area as a whole needs to be grouped in its own
1638 // GdkWindow hierarchy so that animations originating inside it (infobar,
1639 // download shelf, find bar) are all clipped to that area. This is why
1640 // |render_area_vbox_| is packed in |render_area_event_box_|.
1641 render_area_vbox_ = gtk_vbox_new(FALSE, 0);
1642 gtk_widget_set_name(render_area_vbox_, "chrome-render-area-vbox");
1643 render_area_floating_container_ = gtk_floating_container_new();
1644 gtk_container_add(GTK_CONTAINER(render_area_floating_container_),
1645 render_area_vbox_);
1647 GtkWidget* location_icon = toolbar_->GetLocationBarView()->
1648 location_icon_widget();
1649 g_signal_connect(location_icon, "size-allocate",
1650 G_CALLBACK(OnLocationIconSizeAllocateThunk), this);
1651 g_signal_connect_after(location_icon, "expose-event",
1652 G_CALLBACK(OnExposeDrawInfobarBitsThunk), this);
1654 toolbar_border_ = gtk_event_box_new();
1655 gtk_box_pack_start(GTK_BOX(render_area_vbox_),
1656 toolbar_border_, FALSE, FALSE, 0);
1657 gtk_widget_set_size_request(toolbar_border_, -1, 1);
1658 gtk_widget_set_no_show_all(toolbar_border_, TRUE);
1659 g_signal_connect_after(toolbar_border_, "expose-event",
1660 G_CALLBACK(OnExposeDrawInfobarBitsThunk), this);
1662 if (IsToolbarSupported())
1663 gtk_widget_show(toolbar_border_);
1665 infobar_container_.reset(
1666 new InfoBarContainerGtk(this, browser_->profile()));
1667 gtk_box_pack_start(GTK_BOX(render_area_vbox_),
1668 infobar_container_->widget(),
1669 FALSE, FALSE, 0);
1671 status_bubble_.reset(new StatusBubbleGtk(browser_->profile()));
1673 contents_container_.reset(new TabContentsContainerGtk(
1674 status_bubble_.get(),
1675 implicit_cast<content::WebContentsDelegate*>(browser_.get())->
1676 EmbedsFullscreenWidget()));
1677 devtools_container_.reset(new TabContentsContainerGtk(NULL, false));
1678 // DevTools container should only have DevTools-specific view ID.
1679 ViewIDUtil::SetDelegateForWidget(devtools_container_->widget(), NULL);
1680 ViewIDUtil::SetID(devtools_container_->widget(), VIEW_ID_DEV_TOOLS_DOCKED);
1682 devtools_floating_container_ = gtk_floating_container_new();
1683 gtk_container_add(GTK_CONTAINER(devtools_floating_container_),
1684 devtools_container_->widget());
1685 gtk_floating_container_add_floating(
1686 GTK_FLOATING_CONTAINER(devtools_floating_container_),
1687 contents_container_->widget());
1688 g_signal_connect(devtools_floating_container_, "set-floating-position",
1689 G_CALLBACK(OnDevToolsContainerSetFloatingPosition), this);
1690 gtk_box_pack_end(GTK_BOX(render_area_vbox_),
1691 devtools_floating_container_, TRUE, TRUE, 0);
1693 gtk_widget_show_all(render_area_floating_container_);
1695 render_area_event_box_ = gtk_event_box_new();
1696 // Set a white background so during startup the user sees white in the
1697 // content area before we get a WebContents in place.
1698 gtk_widget_modify_bg(render_area_event_box_, GTK_STATE_NORMAL,
1699 &ui::kGdkWhite);
1700 gtk_container_add(GTK_CONTAINER(render_area_event_box_),
1701 render_area_floating_container_);
1702 gtk_widget_show(render_area_event_box_);
1703 gtk_box_pack_end(GTK_BOX(window_vbox_), render_area_event_box_,
1704 TRUE, TRUE, 0);
1706 if (IsBookmarkBarSupported()) {
1707 bookmark_bar_.reset(new BookmarkBarGtk(this,
1708 browser_.get(),
1709 tabstrip_.get()));
1710 PlaceBookmarkBar(false);
1711 gtk_widget_show(bookmark_bar_->widget());
1713 g_signal_connect_after(bookmark_bar_->widget(), "expose-event",
1714 G_CALLBACK(OnBookmarkBarExposeThunk), this);
1715 g_signal_connect(bookmark_bar_->widget(), "size-allocate",
1716 G_CALLBACK(OnBookmarkBarSizeAllocateThunk), this);
1719 // We have to realize the window before we try to apply a window shape mask.
1720 gtk_widget_realize(GTK_WIDGET(window_));
1721 state_ = gdk_window_get_state(gtk_widget_get_window(GTK_WIDGET(window_)));
1722 // Note that calling this the first time is necessary to get the
1723 // proper control layout.
1724 UpdateCustomFrame();
1726 // Add the keybinding registry, now that the window has been realized.
1727 extension_keybinding_registry_.reset(new ExtensionKeybindingRegistryGtk(
1728 browser_->profile(),
1729 window_,
1730 extensions::ExtensionKeybindingRegistry::ALL_EXTENSIONS,
1731 this));
1733 // We have to call this after the first window is created, but after that only
1734 // when the theme changes. This sets the icon that will be used for windows
1735 // that have not explicitly been assigned an icon.
1736 static bool default_icon_set = false;
1737 if (!default_icon_set) {
1738 gtk_util::SetDefaultWindowIcon(window_);
1739 default_icon_set = true;
1741 // Set this window's (potentially profile-avatar-emblemed) icon, overriding
1742 // the default.
1743 gtk_util::SetWindowIcon(window_, browser_->profile());
1745 gtk_container_add(GTK_CONTAINER(window_), window_container_);
1746 gtk_widget_show(window_container_);
1747 browser_->tab_strip_model()->AddObserver(this);
1750 void BrowserWindowGtk::SetBackgroundColor() {
1751 Profile* profile = browser()->profile();
1752 GtkThemeService* theme_provider = GtkThemeService::GetFrom(profile);
1753 int frame_color_id;
1754 if (UsingCustomPopupFrame()) {
1755 frame_color_id = ThemeProperties::COLOR_TOOLBAR;
1756 } else if (DrawFrameAsActive()) {
1757 frame_color_id = browser()->profile()->IsOffTheRecord()
1758 ? ThemeProperties::COLOR_FRAME_INCOGNITO
1759 : ThemeProperties::COLOR_FRAME;
1760 } else {
1761 frame_color_id = browser()->profile()->IsOffTheRecord()
1762 ? ThemeProperties::COLOR_FRAME_INCOGNITO_INACTIVE
1763 : ThemeProperties::COLOR_FRAME_INACTIVE;
1766 SkColor frame_color = theme_provider->GetColor(frame_color_id);
1768 // Paint the frame color on the left, right and bottom.
1769 GdkColor frame_color_gdk = gfx::SkColorToGdkColor(frame_color);
1770 gtk_widget_modify_bg(GTK_WIDGET(window_), GTK_STATE_NORMAL,
1771 &frame_color_gdk);
1773 GdkColor border_color = theme_provider->GetBorderColor();
1774 gtk_widget_modify_bg(toolbar_border_, GTK_STATE_NORMAL, &border_color);
1777 void BrowserWindowGtk::UpdateWindowShape(int width, int height) {
1778 using gtk_window_util::kFrameBorderThickness;
1779 GdkRegion* mask = GetWindowShape(width, height);
1780 gdk_window_shape_combine_region(
1781 gtk_widget_get_window(GTK_WIDGET(window_)), mask, 0, 0);
1782 if (mask)
1783 gdk_region_destroy(mask);
1785 if (UseCustomFrame() && !IsFullscreen() && !IsMaximized()) {
1786 gtk_alignment_set_padding(GTK_ALIGNMENT(window_container_), 1,
1787 kFrameBorderThickness, kFrameBorderThickness, kFrameBorderThickness);
1788 } else {
1789 gtk_alignment_set_padding(GTK_ALIGNMENT(window_container_), 0, 0, 0, 0);
1793 GdkRegion* BrowserWindowGtk::GetWindowShape(int width, int height) const {
1794 if (UseCustomFrame() && !IsFullscreen() && !IsMaximized()) {
1795 // Make the corners rounded. We set a mask that includes most of the
1796 // window except for a few pixels in each corner.
1797 GdkRectangle top_top_rect = { 3, 0, width - 6, 1 };
1798 GdkRectangle top_mid_rect = { 1, 1, width - 2, 2 };
1799 GdkRectangle mid_rect = { 0, 3, width, height - 6 };
1800 // The bottom two rects are mirror images of the top two rects.
1801 GdkRectangle bot_mid_rect = top_mid_rect;
1802 bot_mid_rect.y = height - 3;
1803 GdkRectangle bot_bot_rect = top_top_rect;
1804 bot_bot_rect.y = height - 1;
1805 GdkRegion* mask = gdk_region_rectangle(&top_top_rect);
1806 gdk_region_union_with_rect(mask, &top_mid_rect);
1807 gdk_region_union_with_rect(mask, &mid_rect);
1808 gdk_region_union_with_rect(mask, &bot_mid_rect);
1809 gdk_region_union_with_rect(mask, &bot_bot_rect);
1810 return mask;
1811 } else if (UseCustomFrame()) {
1812 // Disable rounded corners. Simply passing in a NULL region doesn't
1813 // seem to work on KWin, so manually set the shape to the whole window.
1814 GdkRectangle rect = { 0, 0, width, height };
1815 GdkRegion* mask = gdk_region_rectangle(&rect);
1816 return mask;
1817 } else {
1818 // XFCE disables the system decorations if there's an xshape set. Do not
1819 // use the KWin hack when the custom frame is not enabled.
1820 return NULL;
1824 void BrowserWindowGtk::ConnectAccelerators() {
1825 accel_group_ = gtk_accel_group_new();
1826 gtk_window_add_accel_group(window_, accel_group_);
1828 AcceleratorsGtk* accelerators = AcceleratorsGtk::GetInstance();
1829 for (AcceleratorsGtk::const_iterator iter = accelerators->begin();
1830 iter != accelerators->end(); ++iter) {
1831 gtk_accel_group_connect(
1832 accel_group_,
1833 ui::GetGdkKeyCodeForAccelerator(iter->second),
1834 ui::GetGdkModifierForAccelerator(iter->second),
1835 GtkAccelFlags(0),
1836 g_cclosure_new(G_CALLBACK(OnGtkAccelerator),
1837 GINT_TO_POINTER(iter->first), NULL));
1841 void BrowserWindowGtk::UpdateCustomFrame() {
1842 gtk_window_set_decorated(window_, !UseCustomFrame());
1843 titlebar_->UpdateCustomFrame(UseCustomFrame() && !IsFullscreen());
1844 UpdateWindowShape(bounds_.width(), bounds_.height());
1847 void BrowserWindowGtk::InvalidateWindow() {
1848 GtkAllocation allocation;
1849 gtk_widget_get_allocation(GTK_WIDGET(window_), &allocation);
1850 gdk_window_invalidate_rect(gtk_widget_get_window(GTK_WIDGET(window_)),
1851 &allocation, TRUE);
1854 void BrowserWindowGtk::SaveWindowPosition() {
1855 // Browser::SaveWindowPlacement is used for session restore.
1856 ui::WindowShowState show_state = ui::SHOW_STATE_NORMAL;
1857 if (IsMaximized())
1858 show_state = ui::SHOW_STATE_MAXIMIZED;
1859 else if (IsMinimized())
1860 show_state = ui::SHOW_STATE_MINIMIZED;
1862 if (chrome::ShouldSaveWindowPlacement(browser_.get()))
1863 chrome::SaveWindowPlacement(browser_.get(), restored_bounds_, show_state);
1865 // We also need to save the placement for startup.
1866 // This is a web of calls between views and delegates on Windows, but the
1867 // crux of the logic follows. See also cocoa/browser_window_controller.mm.
1868 if (!browser_->profile()->GetPrefs())
1869 return;
1871 std::string window_name = chrome::GetWindowPlacementKey(browser_.get());
1872 DictionaryPrefUpdate update(browser_->profile()->GetPrefs(),
1873 window_name.c_str());
1874 base::DictionaryValue* window_preferences = update.Get();
1875 // Note that we store left/top for consistency with Windows, but that we
1876 // *don't* obey them; we only use them for computing width/height. See
1877 // comments in SetGeometryHints().
1878 window_preferences->SetInteger("left", restored_bounds_.x());
1879 window_preferences->SetInteger("top", restored_bounds_.y());
1880 window_preferences->SetInteger("right", restored_bounds_.right());
1881 window_preferences->SetInteger("bottom", restored_bounds_.bottom());
1882 window_preferences->SetBoolean("maximized", IsMaximized());
1884 gfx::Rect work_area(gfx::Screen::GetNativeScreen()->GetDisplayMatching(
1885 restored_bounds_).work_area());
1886 window_preferences->SetInteger("work_area_left", work_area.x());
1887 window_preferences->SetInteger("work_area_top", work_area.y());
1888 window_preferences->SetInteger("work_area_right", work_area.right());
1889 window_preferences->SetInteger("work_area_bottom", work_area.bottom());
1892 void BrowserWindowGtk::InvalidateInfoBarBits() {
1893 gtk_widget_queue_draw(toolbar_border_);
1894 gtk_widget_queue_draw(toolbar_->widget());
1895 if (bookmark_bar_.get() &&
1896 browser_->bookmark_bar_state() != BookmarkBar::DETACHED) {
1897 gtk_widget_queue_draw(bookmark_bar_->widget());
1901 int BrowserWindowGtk::GetXPositionOfLocationIcon(GtkWidget* relative_to) {
1902 GtkWidget* location_icon = toolbar_->GetLocationBarView()->
1903 location_icon_widget();
1905 GtkAllocation location_icon_allocation;
1906 gtk_widget_get_allocation(location_icon, &location_icon_allocation);
1908 int x = 0;
1909 gtk_widget_translate_coordinates(
1910 location_icon, relative_to,
1911 (location_icon_allocation.width + 1) / 2,
1912 0, &x, NULL);
1914 if (!gtk_widget_get_has_window(relative_to)) {
1915 GtkAllocation allocation;
1916 gtk_widget_get_allocation(relative_to, &allocation);
1917 x += allocation.x;
1920 return x;
1923 void BrowserWindowGtk::MaybeShowBookmarkBar(bool animate) {
1924 TRACE_EVENT0("ui::gtk", "BrowserWindowGtk::MaybeShowBookmarkBar");
1925 if (!IsBookmarkBarSupported())
1926 return;
1928 if (GetDisplayedTab())
1929 bookmark_bar_->SetPageNavigator(browser_.get());
1931 BookmarkBar::State state = browser_->bookmark_bar_state();
1932 toolbar_->UpdateForBookmarkBarVisibility(state == BookmarkBar::DETACHED);
1933 PlaceBookmarkBar(state == BookmarkBar::DETACHED);
1934 bookmark_bar_->SetBookmarkBarState(
1935 state,
1936 animate ? BookmarkBar::ANIMATE_STATE_CHANGE :
1937 BookmarkBar::DONT_ANIMATE_STATE_CHANGE);
1940 void BrowserWindowGtk::OnLocationIconSizeAllocate(GtkWidget* sender,
1941 GtkAllocation* allocation) {
1942 // The position of the arrow may have changed, so we'll have to redraw it.
1943 InvalidateInfoBarBits();
1946 gboolean BrowserWindowGtk::OnExposeDrawInfobarBits(GtkWidget* sender,
1947 GdkEventExpose* expose) {
1948 TRACE_EVENT0("ui::gtk", "BrowserWindowGtk::OnExposeDrawInfobarBits");
1949 // Maybe draw infobars
1950 infobar_container_->PaintInfobarBitsOn(sender, expose, NULL);
1952 return FALSE;
1955 gboolean BrowserWindowGtk::OnBookmarkBarExpose(GtkWidget* sender,
1956 GdkEventExpose* expose) {
1957 if (browser_->bookmark_bar_state() == BookmarkBar::DETACHED)
1958 return FALSE;
1960 return OnExposeDrawInfobarBits(sender, expose);
1963 void BrowserWindowGtk::OnBookmarkBarSizeAllocate(GtkWidget* sender,
1964 GtkAllocation* allocation) {
1965 TRACE_EVENT0("ui::gtk", "BrowserWindowGtk::OnBookmarkBarSizeAllocate");
1966 // The size of the bookmark bar affects how the infobar arrow is drawn on
1967 // the toolbar.
1968 if (infobar_container_->ContainsInfobars())
1969 InvalidateInfoBarBits();
1971 // Pass the new size to our infobar container.
1972 int arrow_size = InfoBar::kDefaultArrowTargetHeight;
1973 if (browser_->bookmark_bar_state() != BookmarkBar::DETACHED)
1974 arrow_size += allocation->height;
1975 infobar_container_->SetMaxTopArrowHeight(arrow_size);
1978 // static
1979 gboolean BrowserWindowGtk::OnGtkAccelerator(GtkAccelGroup* accel_group,
1980 GObject* acceleratable,
1981 guint keyval,
1982 GdkModifierType modifier,
1983 void* user_data) {
1984 int command_id = GPOINTER_TO_INT(user_data);
1985 BrowserWindowGtk* browser_window =
1986 GetBrowserWindowForNativeWindow(GTK_WINDOW(acceleratable));
1987 DCHECK(browser_window != NULL);
1988 return chrome::ExecuteCommand(browser_window->browser(), command_id);
1991 // Let the focused widget have first crack at the key event so we don't
1992 // override their accelerators, except if there is a priority keybinding
1993 // handler registered (it should take precedence).
1994 gboolean BrowserWindowGtk::OnKeyPress(GtkWidget* widget, GdkEventKey* event) {
1995 if (extension_keybinding_registry_->HasPriorityHandler(event))
1996 return FALSE;
1998 // If a widget besides the native view is focused, we have to try to handle
1999 // the custom accelerators before letting it handle them.
2000 WebContents* current_web_contents =
2001 browser()->tab_strip_model()->GetActiveWebContents();
2002 // The current tab might not have a render view if it crashed.
2003 if (!current_web_contents ||
2004 !current_web_contents->GetView()->GetContentNativeView() ||
2005 !gtk_widget_is_focus(
2006 current_web_contents->GetView()->GetContentNativeView())) {
2007 int command_id = GetCustomCommandId(event);
2008 if (command_id == -1)
2009 command_id = GetPreHandleCommandId(event);
2011 if (command_id != -1 && chrome::ExecuteCommand(browser_.get(), command_id))
2012 return TRUE;
2014 // Propagate the key event to child widget first, so we don't override their
2015 // accelerators.
2016 if (!gtk_window_propagate_key_event(GTK_WINDOW(widget), event)) {
2017 if (!gtk_window_activate_key(GTK_WINDOW(widget), event)) {
2018 gtk_bindings_activate_event(GTK_OBJECT(widget), event);
2021 } else {
2022 bool rv = gtk_window_propagate_key_event(GTK_WINDOW(widget), event);
2023 DCHECK(rv);
2026 // Prevents the default handler from handling this event.
2027 return TRUE;
2030 gboolean BrowserWindowGtk::OnMouseMoveEvent(GtkWidget* widget,
2031 GdkEventMotion* event) {
2032 // This method is used to update the mouse cursor when over the edge of the
2033 // custom frame. If the custom frame is off or we're over some other widget,
2034 // do nothing.
2035 if (!UseCustomFrame() || event->window != gtk_widget_get_window(widget)) {
2036 // Reset the cursor.
2037 if (frame_cursor_) {
2038 frame_cursor_ = NULL;
2039 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window_)), NULL);
2041 return FALSE;
2044 // Update the cursor if we're on the custom frame border.
2045 GdkWindowEdge edge;
2046 bool has_hit_edge = GetWindowEdge(static_cast<int>(event->x),
2047 static_cast<int>(event->y), &edge);
2048 GdkCursorType new_cursor = GDK_LAST_CURSOR;
2049 if (has_hit_edge)
2050 new_cursor = gtk_window_util::GdkWindowEdgeToGdkCursorType(edge);
2052 GdkCursorType last_cursor = GDK_LAST_CURSOR;
2053 if (frame_cursor_)
2054 last_cursor = frame_cursor_->type;
2056 if (last_cursor != new_cursor) {
2057 if (has_hit_edge) {
2058 frame_cursor_ = gfx::GetCursor(new_cursor);
2059 } else {
2060 frame_cursor_ = NULL;
2062 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window_)),
2063 frame_cursor_);
2065 return FALSE;
2068 gboolean BrowserWindowGtk::OnButtonPressEvent(GtkWidget* widget,
2069 GdkEventButton* event) {
2070 // Handle back/forward.
2071 if (event->type == GDK_BUTTON_PRESS) {
2072 if (event->button == 8) {
2073 chrome::GoBack(browser_.get(), CURRENT_TAB);
2074 return TRUE;
2075 } else if (event->button == 9) {
2076 chrome::GoForward(browser_.get(), CURRENT_TAB);
2077 return TRUE;
2081 // Handle left, middle and right clicks. In particular, we care about clicks
2082 // in the custom frame border and clicks in the titlebar.
2084 // Make the button press coordinate relative to the browser window.
2085 int win_x, win_y;
2086 GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_));
2087 gdk_window_get_origin(gdk_window, &win_x, &win_y);
2089 GdkWindowEdge edge;
2090 gfx::Point point(static_cast<int>(event->x_root - win_x),
2091 static_cast<int>(event->y_root - win_y));
2092 bool has_hit_edge = GetWindowEdge(point.x(), point.y(), &edge);
2094 // Ignore clicks that are in/below the browser toolbar.
2095 GtkWidget* toolbar = toolbar_->widget();
2096 if (!gtk_widget_get_visible(toolbar)) {
2097 // If the toolbar is not showing, use the location of web contents as the
2098 // boundary of where to ignore clicks.
2099 toolbar = render_area_vbox_;
2101 gint toolbar_y;
2102 gtk_widget_get_pointer(toolbar, NULL, &toolbar_y);
2103 bool has_hit_titlebar = !IsFullscreen() && (toolbar_y < 0)
2104 && !has_hit_edge;
2105 if (event->button == 1) {
2106 if (GDK_BUTTON_PRESS == event->type) {
2107 // Raise the window after a click on either the titlebar or the border to
2108 // match the behavior of most window managers, unless that behavior has
2109 // been suppressed.
2110 if ((has_hit_titlebar || has_hit_edge) && !suppress_window_raise_)
2111 gdk_window_raise(gdk_window);
2113 if (has_hit_titlebar) {
2114 return gtk_window_util::HandleTitleBarLeftMousePress(
2115 window_, bounds_, event);
2116 } else if (has_hit_edge) {
2117 gtk_window_begin_resize_drag(window_, edge, event->button,
2118 static_cast<gint>(event->x_root),
2119 static_cast<gint>(event->y_root),
2120 event->time);
2121 return TRUE;
2123 } else if (GDK_2BUTTON_PRESS == event->type) {
2124 if (has_hit_titlebar) {
2125 // Maximize/restore on double click.
2126 if (IsMaximized()) {
2127 UnMaximize();
2128 } else {
2129 gtk_window_maximize(window_);
2131 return TRUE;
2134 } else if (event->button == 2) {
2135 if (has_hit_titlebar || has_hit_edge) {
2136 gdk_window_lower(gdk_window);
2138 return TRUE;
2139 } else if (event->button == 3) {
2140 if (has_hit_titlebar) {
2141 titlebar_->ShowContextMenu(event);
2142 return TRUE;
2146 return FALSE; // Continue to propagate the event.
2149 gboolean BrowserWindowGtk::OnFocusIn(GtkWidget* widget,
2150 GdkEventFocus* event) {
2151 BrowserList::SetLastActive(browser_.get());
2152 return FALSE;
2155 gboolean BrowserWindowGtk::OnFocusOut(GtkWidget* widget,
2156 GdkEventFocus* event) {
2157 return FALSE;
2160 void BrowserWindowGtk::ShowSupportedWindowFeatures() {
2161 if (IsTabStripSupported())
2162 tabstrip_->Show();
2164 if (IsToolbarSupported()) {
2165 toolbar_->Show();
2166 gtk_widget_show(toolbar_border_);
2167 gdk_window_lower(gtk_widget_get_window(toolbar_border_));
2170 if (IsBookmarkBarSupported())
2171 MaybeShowBookmarkBar(false);
2174 void BrowserWindowGtk::HideUnsupportedWindowFeatures() {
2175 if (!IsTabStripSupported())
2176 tabstrip_->Hide();
2178 if (!IsToolbarSupported())
2179 toolbar_->Hide();
2181 // If the bookmark bar shelf is unsupported, then we never create it.
2184 bool BrowserWindowGtk::IsTabStripSupported() const {
2185 return browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP);
2188 bool BrowserWindowGtk::IsToolbarSupported() const {
2189 return browser_->SupportsWindowFeature(Browser::FEATURE_TOOLBAR) ||
2190 browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR);
2193 bool BrowserWindowGtk::IsBookmarkBarSupported() const {
2194 return browser_->SupportsWindowFeature(Browser::FEATURE_BOOKMARKBAR);
2197 bool BrowserWindowGtk::UsingCustomPopupFrame() const {
2198 GtkThemeService* theme_provider = GtkThemeService::GetFrom(
2199 browser()->profile());
2200 return !theme_provider->UsingNativeTheme() && browser()->is_type_popup();
2203 bool BrowserWindowGtk::GetWindowEdge(int x, int y, GdkWindowEdge* edge) {
2204 if (!UseCustomFrame())
2205 return false;
2207 if (IsMaximized() || IsFullscreen())
2208 return false;
2210 return gtk_window_util::GetWindowEdge(
2211 bounds_.size(), kTopResizeAdjust, x, y, edge);
2214 bool BrowserWindowGtk::UseCustomFrame() const {
2215 // We don't use the custom frame for app mode windows or app window popups.
2216 return use_custom_frame_pref_.GetValue() && !browser_->is_app();
2219 void BrowserWindowGtk::PlaceBookmarkBar(bool is_floating) {
2220 TRACE_EVENT0("ui::gtk", "BrowserWindowGtk::PlaceBookmarkBar");
2222 GtkWidget* target_parent = NULL;
2223 if (!is_floating) {
2224 // Place the bookmark bar at the end of |window_vbox_|; this happens after
2225 // we have placed the render area at the end of |window_vbox_| so we will
2226 // be above the render area.
2227 target_parent = window_vbox_;
2228 } else {
2229 // Place the bookmark bar at the end of the render area; this happens after
2230 // the tab contents container has been placed there so we will be
2231 // above the webpage (in terms of y).
2232 target_parent = render_area_vbox_;
2235 GtkWidget* parent = gtk_widget_get_parent(bookmark_bar_->widget());
2236 if (parent != target_parent) {
2237 if (parent)
2238 gtk_container_remove(GTK_CONTAINER(parent), bookmark_bar_->widget());
2240 gtk_box_pack_end(GTK_BOX(target_parent), bookmark_bar_->widget(),
2241 FALSE, FALSE, 0);
2245 bool BrowserWindowGtk::DrawFrameAsActive() const {
2246 if (ui::ActiveWindowWatcherX::WMSupportsActivation())
2247 return is_active_;
2249 // Since we don't get notifications when the active state of the frame
2250 // changes, we can't consistently repaint the frame at the right time. Instead
2251 // we always draw the frame as active.
2252 return true;
2255 void BrowserWindowGtk::UpdateDevToolsForContents(WebContents* contents) {
2256 TRACE_EVENT0("ui::gtk", "BrowserWindowGtk::UpdateDevToolsForContents");
2257 DevToolsWindow* new_devtools_window = contents ?
2258 DevToolsWindow::GetDockedInstanceForInspectedTab(contents) : NULL;
2260 // Replace tab contents.
2261 if (devtools_window_ != new_devtools_window) {
2262 if (devtools_window_)
2263 devtools_container_->DetachTab(devtools_window_->web_contents());
2264 devtools_container_->SetTab(
2265 new_devtools_window ? new_devtools_window->web_contents() : NULL);
2266 if (new_devtools_window) {
2267 // WebContentsViewGtk::WasShown is not called when a web contents is shown
2268 // by anything other than user selecting a Tab.
2269 // See TabContentsViewViews::OnWindowPosChanged for reference on how it
2270 // should be implemented.
2271 new_devtools_window->web_contents()->WasShown();
2275 // Show / hide container if necessary.
2276 bool should_hide = devtools_window_ && !new_devtools_window;
2277 bool should_show = new_devtools_window && !devtools_window_;
2279 if (should_hide)
2280 HideDevToolsContainer();
2282 devtools_window_ = new_devtools_window;
2283 contents_insets_ = devtools_window_ ? devtools_window_->GetContentsInsets() :
2284 gfx::Insets();
2286 if (should_show)
2287 ShowDevToolsContainer();
2289 gtk_widget_queue_resize(devtools_floating_container_);
2290 gtk_widget_queue_draw(devtools_floating_container_);
2293 void BrowserWindowGtk::ShowDevToolsContainer() {
2294 // Move devtools below contents.
2295 GdkWindow* const devtools_gdk_window =
2296 gtk_widget_get_window(devtools_container_->widget());
2297 if (devtools_gdk_window)
2298 gdk_window_lower(devtools_gdk_window);
2301 void BrowserWindowGtk::HideDevToolsContainer() {
2302 // This method is left intentionally blank.
2305 // static
2306 void BrowserWindowGtk::OnDevToolsContainerSetFloatingPosition(
2307 GtkFloatingContainer* container, GtkAllocation* allocation,
2308 BrowserWindowGtk* browser_window) {
2309 gfx::Insets insets = browser_window->contents_insets_;
2311 int contents_width = std::max(0, allocation->width - insets.width());
2312 int contents_height = std::max(0, allocation->height - insets.height());
2313 int contents_x = std::min(insets.left(), allocation->width);
2314 int contents_y = std::min(insets.top(), allocation->height);
2316 gtk_widget_set_size_request(browser_window->contents_container_->widget(),
2317 contents_width, contents_height);
2319 GValue value = { 0, };
2320 g_value_init(&value, G_TYPE_INT);
2321 g_value_set_int(&value, contents_x);
2322 gtk_container_child_set_property(GTK_CONTAINER(container),
2323 browser_window->contents_container_->widget(), "x", &value);
2324 g_value_set_int(&value, contents_y);
2325 gtk_container_child_set_property(GTK_CONTAINER(container),
2326 browser_window->contents_container_->widget(), "y", &value);
2327 g_value_unset(&value);
2330 void BrowserWindowGtk::OnUseCustomChromeFrameChanged() {
2331 UpdateCustomFrame();
2332 ui::SetHideTitlebarWhenMaximizedProperty(
2333 ui::GetX11WindowFromGtkWidget(GTK_WIDGET(window_)),
2334 UseCustomFrame() ? ui::HIDE_TITLEBAR_WHEN_MAXIMIZED :
2335 ui::SHOW_TITLEBAR_WHEN_MAXIMIZED);
2338 // static
2339 bool BrowserWindowGtk::GetCustomFramePrefDefault() {
2340 // Ideally, we'd use the custom frame by default and just fall back on using
2341 // system decorations for the few (?) tiling window managers where the custom
2342 // frame doesn't make sense (e.g. awesome, ion3, ratpoison, xmonad, etc.) or
2343 // other WMs where it has issues (e.g. Fluxbox -- see issue 19130). The EWMH
2344 // _NET_SUPPORTING_WM property makes it easy to look up a name for the current
2345 // WM, but at least some of the WMs in the latter group don't set it.
2346 // Instead, we default to using system decorations for all WMs and
2347 // special-case the ones where the custom frame should be used.
2348 ui::WindowManagerName wm_type = ui::GuessWindowManager();
2349 return (wm_type == ui::WM_BLACKBOX ||
2350 wm_type == ui::WM_COMPIZ ||
2351 wm_type == ui::WM_ENLIGHTENMENT ||
2352 wm_type == ui::WM_METACITY ||
2353 wm_type == ui::WM_MUFFIN ||
2354 wm_type == ui::WM_MUTTER ||
2355 wm_type == ui::WM_OPENBOX ||
2356 wm_type == ui::WM_XFWM4);
2359 // static
2360 BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) {
2361 BrowserWindowGtk* browser_window_gtk = new BrowserWindowGtk(browser);
2362 browser_window_gtk->Init();
2363 return browser_window_gtk;
2366 // static
2367 chrome::HostDesktopType BrowserWindow::AdjustHostDesktopType(
2368 chrome::HostDesktopType desktop_type) {
2369 return desktop_type;