1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_UI_GTK_BROWSER_WINDOW_GTK_H_ 6 #define CHROME_BROWSER_UI_GTK_BROWSER_WINDOW_GTK_H_ 7 #pragma once 8 9 #include <gtk/gtk.h> 10 11 #include <map> 12 13 #include "base/memory/scoped_ptr.h" 14 #include "base/timer.h" 15 #include "build/build_config.h" 16 #include "chrome/browser/prefs/pref_member.h" 17 #include "chrome/browser/tabs/tab_strip_model_observer.h" 18 #include "chrome/browser/ui/browser_window.h" 19 #include "chrome/browser/ui/gtk/infobars/infobar_arrow_model.h" 20 #include "content/common/notification_registrar.h" 21 #include "ui/base/gtk/gtk_signal.h" 22 #include "ui/base/x/active_window_watcher_x.h" 23 #include "ui/base/x/x11_util.h" 24 #include "ui/gfx/rect.h" 25 26 class BookmarkBarGtk; 27 class Browser; 28 class BrowserTitlebar; 29 class BrowserToolbarGtk; 30 class CustomDrawButton; 31 class DownloadShelfGtk; 32 class FindBarGtk; 33 class FullscreenExitBubbleGtk; 34 class GlobalMenuBar; 35 class InfoBarContainerGtk; 36 class LocationBar; 37 class StatusBubbleGtk; 38 class TabContentsContainerGtk; 39 class TabStripGtk; 40 41 // An implementation of BrowserWindow for GTK. 42 // Cross-platform code will interact with this object when 43 // it needs to manipulate the window. 44 45 class BrowserWindowGtk : public BrowserWindow, 46 public NotificationObserver, 47 public TabStripModelObserver, 48 public ui::ActiveWindowWatcherX::Observer, 49 public InfoBarArrowModel::Observer { 50 public: 51 explicit BrowserWindowGtk(Browser* browser); 52 virtual ~BrowserWindowGtk(); 53 54 virtual void Init(); 55 56 // Overridden from BrowserWindow 57 virtual void Show(); 58 virtual void ShowInactive(); 59 virtual void SetBounds(const gfx::Rect& bounds); 60 virtual void Close(); 61 virtual void Activate(); 62 virtual void Deactivate(); 63 virtual bool IsActive() const; 64 virtual void FlashFrame(); 65 virtual gfx::NativeWindow GetNativeHandle(); 66 virtual BrowserWindowTesting* GetBrowserWindowTesting(); 67 virtual StatusBubble* GetStatusBubble(); 68 virtual void ToolbarSizeChanged(bool is_animating); 69 virtual void UpdateTitleBar(); 70 virtual void ShelfVisibilityChanged(); 71 virtual void UpdateDevTools(); 72 virtual void UpdateLoadingAnimations(bool should_animate); 73 virtual void SetStarredState(bool is_starred); 74 virtual gfx::Rect GetRestoredBounds() const; 75 virtual gfx::Rect GetBounds() const; 76 virtual bool IsMaximized() const; 77 virtual void SetFullscreen(bool fullscreen); 78 virtual bool IsFullscreen() const; 79 virtual bool IsFullscreenBubbleVisible() const; 80 virtual LocationBar* GetLocationBar() const; 81 virtual void SetFocusToLocationBar(bool select_all); 82 virtual void UpdateReloadStopState(bool is_loading, bool force); 83 virtual void UpdateToolbar(TabContentsWrapper* contents, 84 bool should_restore_state); 85 virtual void FocusToolbar(); 86 virtual void FocusAppMenu(); 87 virtual void FocusBookmarksToolbar(); 88 virtual void FocusChromeOSStatus(); 89 virtual void RotatePaneFocus(bool forwards); 90 virtual bool IsBookmarkBarVisible() const; 91 virtual bool IsBookmarkBarAnimating() const; 92 virtual bool IsTabStripEditable() const; 93 virtual bool IsToolbarVisible() const; 94 virtual void ConfirmAddSearchProvider(const TemplateURL* template_url, 95 Profile* profile); 96 virtual void ToggleBookmarkBar(); 97 virtual void ShowAboutChromeDialog(); 98 virtual void ShowUpdateChromeDialog(); 99 virtual void ShowTaskManager(); 100 virtual void ShowBackgroundPages(); 101 virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked); 102 virtual bool IsDownloadShelfVisible() const; 103 virtual DownloadShelf* GetDownloadShelf(); 104 virtual void ShowRepostFormWarningDialog(TabContents* tab_contents); 105 virtual void ShowCollectedCookiesDialog(TabContents* tab_contents); 106 virtual void ShowThemeInstallBubble(); 107 virtual void ConfirmBrowserCloseWithPendingDownloads(); 108 virtual void ShowHTMLDialog(HtmlDialogUIDelegate* delegate, 109 gfx::NativeWindow parent_window); 110 virtual void UserChangedTheme(); 111 virtual int GetExtraRenderViewHeight() const; 112 virtual void TabContentsFocused(TabContents* tab_contents); 113 virtual void ShowPageInfo(Profile* profile, 114 const GURL& url, 115 const NavigationEntry::SSLStatus& ssl, 116 bool show_history); 117 virtual void ShowAppMenu(); 118 virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, 119 bool* is_keyboard_shortcut); 120 virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event); 121 virtual void ShowCreateWebAppShortcutsDialog( 122 TabContentsWrapper* tab_contents); 123 virtual void ShowCreateChromeAppShortcutsDialog(Profile* profile, 124 const Extension* app); 125 virtual void Cut(); 126 virtual void Copy(); 127 virtual void Paste(); ToggleTabStripMode()128 virtual void ToggleTabStripMode() {} 129 virtual void PrepareForInstant(); 130 virtual void ShowInstant(TabContentsWrapper* preview); 131 virtual void HideInstant(bool instant_is_active); 132 virtual gfx::Rect GetInstantBounds(); 133 134 // Overridden from NotificationObserver: 135 virtual void Observe(NotificationType type, 136 const NotificationSource& source, 137 const NotificationDetails& details); 138 139 // Overridden from TabStripModelObserver: 140 virtual void TabDetachedAt(TabContentsWrapper* contents, int index); 141 virtual void TabSelectedAt(TabContentsWrapper* old_contents, 142 TabContentsWrapper* new_contents, 143 int index, 144 bool user_gesture); 145 146 // Overridden from ActiveWindowWatcher::Observer. 147 virtual void ActiveWindowChanged(GdkWindow* active_window); 148 149 // Overridden from InfoBarArrowModel::Observer. 150 virtual void PaintStateChanged(); 151 152 // Accessor for the tab strip. tabstrip()153 TabStripGtk* tabstrip() const { return tabstrip_.get(); } 154 155 void UpdateDevToolsForContents(TabContents* contents); 156 157 void OnDebouncedBoundsChanged(); 158 159 // Request the underlying window to unmaximize. Also tries to work around 160 // a window manager "feature" that can prevent this in some edge cases. 161 void UnMaximize(); 162 163 // Returns false if we're not ready to close yet. E.g., a tab may have an 164 // onbeforeunload handler that prevents us from closing. 165 bool CanClose() const; 166 167 bool ShouldShowWindowIcon() const; 168 169 // This should only be called from tests where the debounce timeout introduces 170 // timing issues. 171 void DisableDebounceTimerForTests(bool is_disabled); 172 173 // Add the find bar widget to the window hierarchy. 174 void AddFindBar(FindBarGtk* findbar); 175 176 // Reset the mouse cursor to the default cursor if it was set to something 177 // else for the custom frame. 178 void ResetCustomFrameCursor(); 179 180 // Toggles whether an infobar is showing. 181 // |animate| controls whether we animate to the new state set by |bar|. 182 void SetInfoBarShowing(InfoBar* bar, bool animate); 183 184 // Returns the BrowserWindowGtk registered with |window|. 185 static BrowserWindowGtk* GetBrowserWindowForNativeWindow( 186 gfx::NativeWindow window); 187 188 // Retrieves the GtkWindow associated with |xid|, which is the X Window 189 // ID of the top-level X window of this object. 190 static GtkWindow* GetBrowserWindowForXID(XID xid); 191 browser()192 Browser* browser() const { return browser_.get(); } 193 window()194 GtkWindow* window() const { return window_; } 195 GetToolbar()196 BrowserToolbarGtk* GetToolbar() { return toolbar_.get(); } 197 bounds()198 gfx::Rect bounds() const { return bounds_; } 199 200 // Make changes necessary when the floating state of the bookmark bar changes. 201 // This should only be called by the bookmark bar itself. 202 void BookmarkBarIsFloating(bool is_floating); 203 204 // Returns the tab contents we're currently displaying in the tab contents 205 // container. 206 TabContents* GetDisplayedTabContents(); 207 208 static void RegisterUserPrefs(PrefService* prefs); 209 210 // Returns whether to draw the content drop shadow on the sides and bottom 211 // of the browser window. When false, we still draw a shadow on the top of 212 // the toolbar (under the tab strip), but do not round the top corners. 213 bool ShouldDrawContentDropShadow(); 214 215 // Tells GTK that the toolbar area is invalidated and needs redrawing. We 216 // have this method as a hack because GTK doesn't queue the toolbar area for 217 // redraw when it should. 218 void QueueToolbarRedraw(); 219 220 // Get the position where the infobar arrow should be anchored in 221 // |relative_to| coordinates. This is the middle of the omnibox location icon. 222 int GetXPositionOfLocationIcon(GtkWidget* relative_to); 223 224 protected: 225 virtual void DestroyBrowser(); 226 // Top level window. 227 GtkWindow* window_; 228 // GtkAlignment that holds the interior components of the chromium window. 229 // This is used to draw the custom frame border and content shadow. 230 GtkWidget* window_container_; 231 // VBox that holds everything (tabs, toolbar, bookmarks bar, tab contents). 232 GtkWidget* window_vbox_; 233 // VBox that holds everything below the toolbar. 234 GtkWidget* render_area_vbox_; 235 // Floating container that holds the render area. It is needed to position 236 // the findbar. 237 GtkWidget* render_area_floating_container_; 238 // EventBox that holds render_area_floating_container_. 239 GtkWidget* render_area_event_box_; 240 // Border between toolbar and render area. 241 GtkWidget* toolbar_border_; 242 243 scoped_ptr<Browser> browser_; 244 245 // The download shelf view (view at the bottom of the page). 246 scoped_ptr<DownloadShelfGtk> download_shelf_; 247 248 private: 249 // Shows a fade effect over the tab contents. Repeated calls will be ignored 250 // until the fade is canceled. If |animate| is true the fade should animate. 251 void FadeForInstant(bool animate); 252 253 // Immediately removes the fade. 254 void CancelInstantFade(); 255 256 // Show or hide the bookmark bar. 257 void MaybeShowBookmarkBar(bool animate); 258 259 // Sets the default size for the window and the the way the user is allowed to 260 // resize it. 261 void SetGeometryHints(); 262 263 // Connect to signals on |window_|. 264 void ConnectHandlersToSignals(); 265 266 // Create the various UI components. 267 void InitWidgets(); 268 269 // Set up background color of the window (depends on if we're incognito or 270 // not). 271 void SetBackgroundColor(); 272 273 // Called when the window size changed. 274 void OnSizeChanged(int width, int height); 275 276 // Applies the window shape to if we're in custom drawing mode. 277 void UpdateWindowShape(int width, int height); 278 279 // Connect accelerators that aren't connected to menu items (like ctrl-o, 280 // ctrl-l, etc.). 281 void ConnectAccelerators(); 282 283 // Change whether we're showing the custom blue frame. 284 // Must be called once at startup. 285 // Triggers relayout of the content. 286 void UpdateCustomFrame(); 287 288 // Save the window position in the prefs. 289 void SaveWindowPosition(); 290 291 // Set the bounds of the current window. If |exterior| is true, set the size 292 // of the window itself, otherwise set the bounds of the web contents. 293 // If |move| is true, set the position of the window, otherwise leave the 294 // position to the WM. 295 void SetBoundsImpl(const gfx::Rect& bounds, bool exterior, bool move); 296 297 CHROMEGTK_CALLBACK_1(BrowserWindowGtk, gboolean, OnConfigure, 298 GdkEventConfigure*); 299 CHROMEGTK_CALLBACK_1(BrowserWindowGtk, gboolean, OnWindowState, 300 GdkEventWindowState*); 301 CHROMEGTK_CALLBACK_1(BrowserWindowGtk, gboolean, OnMainWindowDeleteEvent, 302 GdkEvent*); 303 CHROMEGTK_CALLBACK_0(BrowserWindowGtk, void, OnMainWindowDestroy); 304 // Callback for when the custom frame alignment needs to be redrawn. 305 // The content area includes the toolbar and web page but not the tab strip. 306 CHROMEGTK_CALLBACK_1(BrowserWindowGtk, gboolean, OnCustomFrameExpose, 307 GdkEventExpose*); 308 309 // A helper method that draws the shadow above the toolbar and in the frame 310 // border during an expose. 311 void DrawContentShadow(cairo_t* cr); 312 313 // Draws the tab image as the frame so we can write legible text. 314 void DrawPopupFrame(cairo_t* cr, GtkWidget* widget, GdkEventExpose* event); 315 316 // Draws the normal custom frame using theme_frame. 317 void DrawCustomFrame(cairo_t* cr, GtkWidget* widget, GdkEventExpose* event); 318 319 // The background frame image needs to be offset by the size of the top of 320 // the window to the top of the tabs when the full skyline isn't displayed 321 // for some reason. 322 int GetVerticalOffset(); 323 324 // Returns which frame image we should use based on the window's current 325 // activation state / incognito state. 326 int GetThemeFrameResource(); 327 328 // Invalidate all the widgets that need to redraw when the infobar draw state 329 // has changed. 330 void InvalidateInfoBarBits(); 331 332 // Gets the size (width and height) of the infobar arrow. The size depends on 333 // the state of the bookmark bar. 334 gfx::Size GetInfobarArrowSize(); 335 336 // When the location icon moves, we have to redraw the arrow. 337 CHROMEGTK_CALLBACK_1(BrowserWindowGtk, void, OnLocationIconSizeAllocate, 338 GtkAllocation*); 339 340 // Used to draw the infobar arrow and drop shadow. This is connected to 341 // multiple widgets' expose events because it overlaps several widgets. 342 CHROMEGTK_CALLBACK_1(BrowserWindowGtk, gboolean, OnExposeDrawInfobarBits, 343 GdkEventExpose*); 344 345 // Used to draw the infobar bits for the bookmark bar. When the bookmark 346 // bar is in floating mode, it has to draw a drop shadow only; otherwise 347 // it is responsible for its portion of the arrow as well as some shadowing. 348 CHROMEGTK_CALLBACK_1(BrowserWindowGtk, gboolean, OnBookmarkBarExpose, 349 GdkEventExpose*); 350 351 // Callback for "size-allocate" signal on bookmark bar; this is relevant 352 // because when the bookmark bar changes dimensions, the infobar arrow has to 353 // change its shape, and we need to queue appropriate redraws. 354 CHROMEGTK_CALLBACK_1(BrowserWindowGtk, void, OnBookmarkBarSizeAllocate, 355 GtkAllocation*); 356 357 // Callback for accelerator activation. |user_data| stores the command id 358 // of the matched accelerator. 359 static gboolean OnGtkAccelerator(GtkAccelGroup* accel_group, 360 GObject* acceleratable, 361 guint keyval, 362 GdkModifierType modifier, 363 void* user_data); 364 365 // Key press event callback. 366 CHROMEGTK_CALLBACK_1(BrowserWindowGtk, gboolean, OnKeyPress, GdkEventKey*); 367 368 // Mouse move and mouse button press callbacks. 369 CHROMEGTK_CALLBACK_1(BrowserWindowGtk, gboolean, OnMouseMoveEvent, 370 GdkEventMotion*); 371 CHROMEGTK_CALLBACK_1(BrowserWindowGtk, gboolean, OnButtonPressEvent, 372 GdkEventButton*); 373 374 // Maps and Unmaps the xid of |widget| to |window|. 375 static void MainWindowMapped(GtkWidget* widget); 376 static void MainWindowUnMapped(GtkWidget* widget); 377 378 // Tracks focus state of browser. 379 CHROMEGTK_CALLBACK_1(BrowserWindowGtk, gboolean, OnFocusIn, 380 GdkEventFocus*); 381 CHROMEGTK_CALLBACK_1(BrowserWindowGtk, gboolean, OnFocusOut, 382 GdkEventFocus*); 383 384 // Callback for the loading animation(s) associated with this window. 385 void LoadingAnimationCallback(); 386 387 // Shows UI elements for supported window features. 388 void ShowSupportedWindowFeatures(); 389 390 // Hides UI elements for unsupported window features. 391 void HideUnsupportedWindowFeatures(); 392 393 // Helper functions that query |browser_| concerning support for UI features 394 // in this window. (For example, a popup window might not support a tabstrip). 395 bool IsTabStripSupported() const; 396 bool IsToolbarSupported() const; 397 bool IsBookmarkBarSupported() const; 398 399 // Whether we should draw the tab background instead of the theme_frame 400 // background because this window is a popup. 401 bool UsingCustomPopupFrame() const; 402 403 // Checks to see if the mouse pointer at |x|, |y| is over the border of the 404 // custom frame (a spot that should trigger a window resize). Returns true if 405 // it should and sets |edge|. 406 bool GetWindowEdge(int x, int y, GdkWindowEdge* edge); 407 408 // Returns |true| if we should use the custom frame. 409 bool UseCustomFrame(); 410 411 // Returns |true| if the window bounds match the monitor size. 412 bool BoundsMatchMonitorSize(); 413 414 // Put the bookmark bar where it belongs. 415 void PlaceBookmarkBar(bool is_floating); 416 417 // Determine whether we use should default to native decorations or the custom 418 // frame based on the currently-running window manager. 419 static bool GetCustomFramePrefDefault(); 420 421 NotificationRegistrar registrar_; 422 423 // The position and size of the current window. 424 gfx::Rect bounds_; 425 426 // The position and size of the non-maximized, non-fullscreen window. 427 gfx::Rect restored_bounds_; 428 429 GdkWindowState state_; 430 431 // Controls a hidden GtkMenuBar that we keep updated so GNOME can take a look 432 // inside "our menu bar" and present it in the top panel, akin to Mac OS. 433 scoped_ptr<GlobalMenuBar> global_menu_bar_; 434 435 // The container for the titlebar + tab strip. 436 scoped_ptr<BrowserTitlebar> titlebar_; 437 438 // The object that manages all of the widgets in the toolbar. 439 scoped_ptr<BrowserToolbarGtk> toolbar_; 440 441 // The object that manages the bookmark bar. This will be NULL if the 442 // bookmark bar is not supported. 443 scoped_ptr<BookmarkBarGtk> bookmark_bar_; 444 445 // Caches the hover state of the bookmark bar. 446 bool bookmark_bar_is_floating_; 447 448 // The status bubble manager. Always non-NULL. 449 scoped_ptr<StatusBubbleGtk> status_bubble_; 450 451 // A container that manages the GtkWidget*s that are the webpage display 452 // (along with associated infobars, shelves, and other things that are part 453 // of the content area). 454 scoped_ptr<TabContentsContainerGtk> contents_container_; 455 456 // A container that manages the GtkWidget*s of developer tools for the 457 // selected tab contents. 458 scoped_ptr<TabContentsContainerGtk> devtools_container_; 459 460 // Split pane containing the contents_container_ and the devtools_container_. 461 GtkWidget* contents_split_; 462 463 // The tab strip. Always non-NULL. 464 scoped_ptr<TabStripGtk> tabstrip_; 465 466 // The container for info bars. Always non-NULL. 467 scoped_ptr<InfoBarContainerGtk> infobar_container_; 468 469 // The timer used to update frames for the Loading Animation. 470 base::RepeatingTimer<BrowserWindowGtk> loading_animation_timer_; 471 472 // The timer used to save the window position for session restore. 473 base::OneShotTimer<BrowserWindowGtk> window_configure_debounce_timer_; 474 475 // Whether the custom chrome frame pref is set. Normally you want to use 476 // UseCustomFrame() above to determine whether to use the custom frame or 477 // not. 478 BooleanPrefMember use_custom_frame_pref_; 479 480 // A map which translates an X Window ID into its respective GtkWindow. 481 static std::map<XID, GtkWindow*> xid_map_; 482 483 // The current window cursor. We set it to a resize cursor when over the 484 // custom frame border. We set it to NULL if we want the default cursor. 485 GdkCursor* frame_cursor_; 486 487 // True if the window manager thinks the window is active. Not all window 488 // managers keep track of this state (_NET_ACTIVE_WINDOW), in which case 489 // this will always be true. 490 bool is_active_; 491 492 // Keep track of the last click time and the last click position so we can 493 // filter out extra GDK_BUTTON_PRESS events when a double click happens. 494 guint32 last_click_time_; 495 gfx::Point last_click_position_; 496 497 // If true, maximize the window after we call BrowserWindow::Show for the 498 // first time. This is to work around a compiz bug. 499 bool maximize_after_show_; 500 501 // If true, don't call gdk_window_raise() when we get a click in the title 502 // bar or window border. This is to work around a compiz bug. 503 bool suppress_window_raise_; 504 505 // The accelerator group used to handle accelerators, owned by this object. 506 GtkAccelGroup* accel_group_; 507 508 scoped_ptr<FullscreenExitBubbleGtk> fullscreen_exit_bubble_; 509 510 // If true, the debounce timer won't be used and OnDebounceBoundsChanged won't 511 // be called. This should only be enabled in tests where the debounce timeout 512 // introduces timing issues (e.g. in OmniBoxApiTest it dismisses the 513 // autocomplete popup before the results can be read) and the final window 514 // position is unimportant. 515 bool debounce_timer_disabled_; 516 517 // The model that tracks the paint state of the arrow for the infobar 518 // directly below the toolbar. 519 InfoBarArrowModel infobar_arrow_model_; 520 521 DISALLOW_COPY_AND_ASSIGN(BrowserWindowGtk); 522 }; 523 524 #endif // CHROME_BROWSER_UI_GTK_BROWSER_WINDOW_GTK_H_ 525