| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/gtk/browser_titlebar.h" | 5 #include "chrome/browser/gtk/browser_titlebar.h" |
| 6 | 6 |
| 7 #include <gdk/gdkkeysyms.h> | 7 #include <gdk/gdkkeysyms.h> |
| 8 #include <gtk/gtk.h> | 8 #include <gtk/gtk.h> |
| 9 | 9 |
| 10 #include <string> | 10 #include <string> |
| 11 #include <vector> | 11 #include <vector> |
| 12 | 12 |
| 13 #include "app/l10n_util.h" | 13 #include "app/l10n_util.h" |
| 14 #include "app/resource_bundle.h" | 14 #include "app/resource_bundle.h" |
| 15 #include "base/command_line.h" | 15 #include "base/command_line.h" |
| 16 #include "base/singleton.h" | 16 #include "base/singleton.h" |
| 17 #include "base/string_piece.h" |
| 18 #include "base/string_tokenizer.h" |
| 17 #include "chrome/app/chrome_dll_resource.h" | 19 #include "chrome/app/chrome_dll_resource.h" |
| 18 #include "chrome/browser/browser.h" | 20 #include "chrome/browser/browser.h" |
| 19 #include "chrome/browser/encoding_menu_controller.h" | 21 #include "chrome/browser/encoding_menu_controller.h" |
| 20 #include "chrome/browser/gtk/accelerators_gtk.h" | 22 #include "chrome/browser/gtk/accelerators_gtk.h" |
| 21 #include "chrome/browser/gtk/browser_window_gtk.h" | 23 #include "chrome/browser/gtk/browser_window_gtk.h" |
| 22 #include "chrome/browser/gtk/custom_button.h" | 24 #include "chrome/browser/gtk/custom_button.h" |
| 25 #include "chrome/browser/gtk/gconf_titlebar_listener.h" |
| 23 #include "chrome/browser/gtk/gtk_theme_provider.h" | 26 #include "chrome/browser/gtk/gtk_theme_provider.h" |
| 24 #include "chrome/browser/gtk/gtk_util.h" | 27 #include "chrome/browser/gtk/gtk_util.h" |
| 25 #include "chrome/browser/gtk/menu_gtk.h" | 28 #include "chrome/browser/gtk/menu_gtk.h" |
| 26 #include "chrome/browser/gtk/nine_box.h" | 29 #include "chrome/browser/gtk/nine_box.h" |
| 27 #include "chrome/browser/gtk/tabs/tab_strip_gtk.h" | 30 #include "chrome/browser/gtk/tabs/tab_strip_gtk.h" |
| 28 #include "chrome/browser/page_menu_model.h" | 31 #include "chrome/browser/page_menu_model.h" |
| 29 #include "chrome/browser/pref_service.h" | 32 #include "chrome/browser/pref_service.h" |
| 30 #include "chrome/browser/profile.h" | 33 #include "chrome/browser/profile.h" |
| 31 #include "chrome/browser/tab_contents/tab_contents.h" | 34 #include "chrome/browser/tab_contents/tab_contents.h" |
| 32 #include "chrome/common/notification_service.h" | 35 #include "chrome/common/notification_service.h" |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 121 if (two_difference > one_difference + 0.1) | 124 if (two_difference > one_difference + 0.1) |
| 122 return *two; | 125 return *two; |
| 123 else | 126 else |
| 124 return *one; | 127 return *one; |
| 125 } | 128 } |
| 126 | 129 |
| 127 } // namespace | 130 } // namespace |
| 128 | 131 |
| 129 BrowserTitlebar::BrowserTitlebar(BrowserWindowGtk* browser_window, | 132 BrowserTitlebar::BrowserTitlebar(BrowserWindowGtk* browser_window, |
| 130 GtkWindow* window) | 133 GtkWindow* window) |
| 131 : browser_window_(browser_window), window_(window), | 134 : browser_window_(browser_window), |
| 135 window_(window), |
| 136 titlebar_left_buttons_vbox_(NULL), |
| 137 titlebar_right_buttons_vbox_(NULL), |
| 138 titlebar_left_buttons_hbox_(NULL), |
| 139 titlebar_right_buttons_hbox_(NULL), |
| 140 top_padding_left_(NULL), |
| 141 top_padding_right_(NULL), |
| 132 app_mode_favicon_(NULL), | 142 app_mode_favicon_(NULL), |
| 133 app_mode_title_(NULL), | 143 app_mode_title_(NULL), |
| 134 using_custom_frame_(false), | 144 using_custom_frame_(false), |
| 135 window_has_focus_(false), | 145 window_has_focus_(false), |
| 136 theme_provider_(NULL) { | 146 theme_provider_(NULL) { |
| 137 Init(); | 147 Init(); |
| 138 } | 148 } |
| 139 | 149 |
| 140 void BrowserTitlebar::Init() { | 150 void BrowserTitlebar::Init() { |
| 141 // The widget hierarchy is shown below. | 151 // The widget hierarchy is shown below. |
| 142 // | 152 // |
| 143 // +- EventBox (container_) -------------------------------------------------+ | 153 // +- EventBox (container_) -------------------------------------+ |
| 144 // +- HBox (container_hbox) -------------------------------------------------+ | 154 // +- HBox (container_hbox_) ------------------------------------+ |
| 145 // |+- Algn. -++- Alignment --------------++- VBox (titlebar_buttons_box_) -+| | 155 // |+ VBox ---++- Algn. -++- Alignment --------------++ VBox ---+| |
| 146 // ||+ Image +|| (titlebar_alignment_) ||+ - Fixed (top_padding_) ------+|| | 156 // || titlebar||+ Image +|| (titlebar_alignment_) || titlebar|| |
| 147 // ||| ||| ||+- HBox -----------------------+|| | 157 // || left ||| ||| || right || |
| 148 // |||spy_guy||| |||+- button -++- button -+ ||| | 158 // || button |||spy_guy||| || button || |
| 149 // ||| |||+- TabStripGtk ---------+|||| minimize || restore | ... ||| | 159 // || vbox ||| |||+- TabStripGtk ---------+|| vbox || |
| 150 // ||| )8\ |||| tab tab tabclose ||||+----------++----------+ ||| | 160 // || ||| )8\ |||| tab tab tabclose ||| || |
| 151 // ||+-------+||+------------------------+||+------------------------------+|| | 161 // || ||+-------+||+------------------------+|| || |
| 152 // |+---------++--------------------------++--------------------------------+| | 162 // |+---------++---------++--------------------------++---------+| |
| 153 // +-------------------------------------------------------------------------+ | 163 // +-------------------------------------------------------------+ |
| 164 // |
| 165 // There are two vboxes on either side of |container_hbox_| because when the |
| 166 // desktop is GNOME, the button placement is configurable based on a metacity |
| 167 // gconf key. We can't just have one vbox and move it back and forth because |
| 168 // the gconf language allows you to place buttons on both sides of the |
| 169 // window. This being Linux, I'm sure there's a bunch of people who have |
| 170 // already configured their window manager to do so and we don't want to get |
| 171 // confused when that happens. The actual contents of these vboxes are lazily |
| 172 // generated so they don't interfere with alignment when everything is |
| 173 // stuffed in the other box. |
| 174 // |
| 175 // Each vbox has the contains the following hierarchy if it contains buttons: |
| 176 // |
| 177 // +- VBox (titlebar_{l,r}_buttons_vbox_) ---------+ |
| 178 // |+- Fixed (top_padding_{l,r}_) ----------------+| |
| 179 // ||+- HBox (titlebar_{l,r}_buttons_hbox_ ------+|| |
| 180 // ||| (buttons of a configurable layout) ||| |
| 181 // ||+-------------------------------------------+|| |
| 182 // |+---------------------------------------------+| |
| 183 // +-----------------------------------------------+ |
| 154 // | 184 // |
| 155 // If we're a popup window or in app mode, we don't display the spy guy or | 185 // If we're a popup window or in app mode, we don't display the spy guy or |
| 156 // the tab strip. Instead, put an hbox in titlebar_alignment_ in place of | 186 // the tab strip. Instead, put an hbox in titlebar_alignment_ in place of |
| 157 // the tab strip. | 187 // the tab strip. |
| 158 // +- Alignment (titlebar_alignment_) -----------------------------------+ | 188 // +- Alignment (titlebar_alignment_) -----------------------------------+ |
| 159 // |+ HBox -------------------------------------------------------------+| | 189 // |+ HBox -------------------------------------------------------------+| |
| 160 // ||+- TabStripGtk -++- Image ----------------++- Label --------------+|| | 190 // ||+- TabStripGtk -++- Image ----------------++- Label --------------+|| |
| 161 // ||| hidden ++ (app_mode_favicon_) || (app_mode_title_) ||| | 191 // ||| hidden ++ (app_mode_favicon_) || (app_mode_title_) ||| |
| 162 // ||| || favicon || page title ||| | 192 // ||| || favicon || page title ||| |
| 163 // ||+---------------++------------------------++----------------------+|| | 193 // ||+---------------++------------------------++----------------------+|| |
| 164 // |+-------------------------------------------------------------------+| | 194 // |+-------------------------------------------------------------------+| |
| 165 // +---------------------------------------------------------------------+ | 195 // +---------------------------------------------------------------------+ |
| 166 GtkWidget* container_hbox = gtk_hbox_new(FALSE, 0); | 196 container_hbox_ = gtk_hbox_new(FALSE, 0); |
| 167 | 197 |
| 168 container_ = gtk_event_box_new(); | 198 container_ = gtk_event_box_new(); |
| 169 gtk_widget_set_name(container_, "chrome-browser-titlebar"); | 199 gtk_widget_set_name(container_, "chrome-browser-titlebar"); |
| 170 gtk_event_box_set_visible_window(GTK_EVENT_BOX(container_), FALSE); | 200 gtk_event_box_set_visible_window(GTK_EVENT_BOX(container_), FALSE); |
| 171 gtk_container_add(GTK_CONTAINER(container_), container_hbox); | 201 gtk_container_add(GTK_CONTAINER(container_), container_hbox_); |
| 172 | 202 |
| 173 g_signal_connect(container_, "scroll-event", G_CALLBACK(OnScroll), this); | 203 g_signal_connect(container_, "scroll-event", G_CALLBACK(OnScroll), this); |
| 174 | 204 |
| 175 g_signal_connect(window_, "window-state-event", | 205 g_signal_connect(window_, "window-state-event", |
| 176 G_CALLBACK(OnWindowStateChanged), this); | 206 G_CALLBACK(OnWindowStateChanged), this); |
| 177 | 207 |
| 208 // Allocate the two button boxes on the left and right parts of the bar. |
| 209 titlebar_left_buttons_vbox_ = gtk_vbox_new(FALSE, 0); |
| 210 gtk_box_pack_start(GTK_BOX(container_hbox_), titlebar_left_buttons_vbox_, |
| 211 FALSE, FALSE, 0); |
| 212 titlebar_right_buttons_vbox_ = gtk_vbox_new(FALSE, 0); |
| 213 gtk_box_pack_end(GTK_BOX(container_hbox_), titlebar_right_buttons_vbox_, |
| 214 FALSE, FALSE, 0); |
| 215 |
| 216 // Either read the gconf database and register for updates (on GNOME), or use |
| 217 // the default value (anywhere else). |
| 218 Singleton<GConfTitlebarListener>()->SetTitlebarButtons(this); |
| 219 |
| 178 if (browser_window_->browser()->profile()->IsOffTheRecord() && | 220 if (browser_window_->browser()->profile()->IsOffTheRecord() && |
| 179 browser_window_->browser()->type() == Browser::TYPE_NORMAL) { | 221 browser_window_->browser()->type() == Browser::TYPE_NORMAL) { |
| 180 GtkWidget* spy_guy = gtk_image_new_from_pixbuf(GetOTRAvatar()); | 222 GtkWidget* spy_guy = gtk_image_new_from_pixbuf(GetOTRAvatar()); |
| 181 gtk_misc_set_alignment(GTK_MISC(spy_guy), 0.0, 1.0); | 223 gtk_misc_set_alignment(GTK_MISC(spy_guy), 0.0, 1.0); |
| 182 GtkWidget* spy_frame = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); | 224 GtkWidget* spy_frame = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); |
| 183 // We use this alignment rather than setting padding on the GtkImage because | 225 // We use this alignment rather than setting padding on the GtkImage because |
| 184 // the image's intrinsic padding doesn't clip the pixbuf during painting. | 226 // the image's intrinsic padding doesn't clip the pixbuf during painting. |
| 185 gtk_alignment_set_padding(GTK_ALIGNMENT(spy_frame), 0, | 227 gtk_alignment_set_padding(GTK_ALIGNMENT(spy_frame), 0, |
| 186 kOTRBottomSpacing, kOTRSideSpacing, kOTRSideSpacing); | 228 kOTRBottomSpacing, kOTRSideSpacing, kOTRSideSpacing); |
| 187 gtk_widget_set_size_request(spy_guy, -1, 0); | 229 gtk_widget_set_size_request(spy_guy, -1, 0); |
| 188 gtk_container_add(GTK_CONTAINER(spy_frame), spy_guy); | 230 gtk_container_add(GTK_CONTAINER(spy_frame), spy_guy); |
| 189 gtk_box_pack_start(GTK_BOX(container_hbox), spy_frame, FALSE, FALSE, 0); | 231 gtk_box_pack_start(GTK_BOX(container_hbox_), spy_frame, FALSE, FALSE, 0); |
| 190 } | 232 } |
| 191 | 233 |
| 192 // We use an alignment to control the titlebar height. | 234 // We use an alignment to control the titlebar height. |
| 193 titlebar_alignment_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); | 235 titlebar_alignment_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); |
| 194 if (browser_window_->browser()->type() == Browser::TYPE_NORMAL) { | 236 if (browser_window_->browser()->type() == Browser::TYPE_NORMAL) { |
| 195 gtk_box_pack_start(GTK_BOX(container_hbox), titlebar_alignment_, TRUE, | 237 gtk_box_pack_start(GTK_BOX(container_hbox_), titlebar_alignment_, TRUE, |
| 196 TRUE, 0); | 238 TRUE, 0); |
| 197 | 239 |
| 198 // Put the tab strip in the titlebar. | 240 // Put the tab strip in the titlebar. |
| 199 gtk_container_add(GTK_CONTAINER(titlebar_alignment_), | 241 gtk_container_add(GTK_CONTAINER(titlebar_alignment_), |
| 200 browser_window_->tabstrip()->widget()); | 242 browser_window_->tabstrip()->widget()); |
| 201 } else { | 243 } else { |
| 202 // App mode specific widgets. | 244 // App mode specific widgets. |
| 203 gtk_box_pack_start(GTK_BOX(container_hbox), titlebar_alignment_, TRUE, | 245 gtk_box_pack_start(GTK_BOX(container_hbox_), titlebar_alignment_, TRUE, |
| 204 TRUE, 0); | 246 TRUE, 0); |
| 205 GtkWidget* app_mode_hbox = gtk_hbox_new(FALSE, kIconTitleSpacing); | 247 GtkWidget* app_mode_hbox = gtk_hbox_new(FALSE, kIconTitleSpacing); |
| 206 gtk_container_add(GTK_CONTAINER(titlebar_alignment_), app_mode_hbox); | 248 gtk_container_add(GTK_CONTAINER(titlebar_alignment_), app_mode_hbox); |
| 207 | 249 |
| 208 // Put the tab strip in the hbox even though we don't show it. Sometimes | 250 // Put the tab strip in the hbox even though we don't show it. Sometimes |
| 209 // we need the position of the tab strip so make sure it's in our widget | 251 // we need the position of the tab strip so make sure it's in our widget |
| 210 // hierarchy. | 252 // hierarchy. |
| 211 gtk_box_pack_start(GTK_BOX(app_mode_hbox), | 253 gtk_box_pack_start(GTK_BOX(app_mode_hbox), |
| 212 browser_window_->tabstrip()->widget(), FALSE, FALSE, 0); | 254 browser_window_->tabstrip()->widget(), FALSE, FALSE, 0); |
| 213 | 255 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 235 // Register with the theme provider to set the |app_mode_title_| label | 277 // Register with the theme provider to set the |app_mode_title_| label |
| 236 // color. | 278 // color. |
| 237 theme_provider_ = GtkThemeProvider::GetFrom( | 279 theme_provider_ = GtkThemeProvider::GetFrom( |
| 238 browser_window_->browser()->profile()); | 280 browser_window_->browser()->profile()); |
| 239 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, | 281 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, |
| 240 NotificationService::AllSources()); | 282 NotificationService::AllSources()); |
| 241 theme_provider_->InitThemesFor(this); | 283 theme_provider_->InitThemesFor(this); |
| 242 UpdateTitleAndIcon(); | 284 UpdateTitleAndIcon(); |
| 243 } | 285 } |
| 244 | 286 |
| 245 // We put the min/max/restore/close buttons in a vbox so they are top aligned | |
| 246 // (up to padding) and don't vertically stretch. | |
| 247 titlebar_buttons_box_ = gtk_vbox_new(FALSE, 0); | |
| 248 GtkWidget* buttons_hbox = gtk_hbox_new(FALSE, kButtonSpacing); | |
| 249 top_padding_ = gtk_fixed_new(); | |
| 250 gtk_widget_set_size_request(top_padding_, -1, kButtonOuterPadding); | |
| 251 gtk_box_pack_start(GTK_BOX(titlebar_buttons_box_), top_padding_, FALSE, FALSE, | |
| 252 0); | |
| 253 gtk_box_pack_start(GTK_BOX(titlebar_buttons_box_), buttons_hbox, FALSE, | |
| 254 FALSE, 0); | |
| 255 | |
| 256 close_button_.reset(BuildTitlebarButton(IDR_CLOSE, IDR_CLOSE_P, IDR_CLOSE_H, | |
| 257 buttons_hbox, | |
| 258 IDS_XPFRAME_CLOSE_TOOLTIP)); | |
| 259 | |
| 260 restore_button_.reset(BuildTitlebarButton(IDR_RESTORE, IDR_RESTORE_P, | |
| 261 IDR_RESTORE_H, buttons_hbox, | |
| 262 IDS_XPFRAME_RESTORE_TOOLTIP)); | |
| 263 maximize_button_.reset(BuildTitlebarButton(IDR_MAXIMIZE, IDR_MAXIMIZE_P, | |
| 264 IDR_MAXIMIZE_H, buttons_hbox, | |
| 265 IDS_XPFRAME_MAXIMIZE_TOOLTIP)); | |
| 266 minimize_button_.reset(BuildTitlebarButton(IDR_MINIMIZE, IDR_MINIMIZE_P, | |
| 267 IDR_MINIMIZE_H, buttons_hbox, | |
| 268 IDS_XPFRAME_MINIMIZE_TOOLTIP)); | |
| 269 | |
| 270 gtk_util::SetButtonClickableByMouseButtons(maximize_button_->widget(), | |
| 271 true, true, true); | |
| 272 | |
| 273 gtk_widget_size_request(close_button_->widget(), &close_button_req_); | |
| 274 gtk_widget_size_request(minimize_button_->widget(), &minimize_button_req_); | |
| 275 gtk_widget_size_request(restore_button_->widget(), &restore_button_req_); | |
| 276 | |
| 277 gtk_box_pack_end(GTK_BOX(container_hbox), titlebar_buttons_box_, FALSE, | |
| 278 FALSE, 0); | |
| 279 | |
| 280 gtk_widget_show_all(container_); | 287 gtk_widget_show_all(container_); |
| 281 | 288 |
| 282 ActiveWindowWatcherX::AddObserver(this); | 289 ActiveWindowWatcherX::AddObserver(this); |
| 283 } | 290 } |
| 284 | 291 |
| 285 BrowserTitlebar::~BrowserTitlebar() { | 292 BrowserTitlebar::~BrowserTitlebar() { |
| 286 ActiveWindowWatcherX::RemoveObserver(this); | 293 ActiveWindowWatcherX::RemoveObserver(this); |
| 294 Singleton<GConfTitlebarListener>()->RemoveObserver(this); |
| 295 } |
| 296 |
| 297 void BrowserTitlebar::BuildButtons(const std::string& button_string) { |
| 298 // Clear out all previous data. |
| 299 close_button_.reset(); |
| 300 restore_button_.reset(); |
| 301 maximize_button_.reset(); |
| 302 minimize_button_.reset(); |
| 303 gtk_util::RemoveAllChildren(titlebar_left_buttons_vbox_); |
| 304 gtk_util::RemoveAllChildren(titlebar_right_buttons_vbox_); |
| 305 titlebar_left_buttons_hbox_ = NULL; |
| 306 titlebar_right_buttons_hbox_ = NULL; |
| 307 top_padding_left_ = NULL; |
| 308 top_padding_right_ = NULL; |
| 309 |
| 310 bool left_side = true; |
| 311 StringTokenizer tokenizer(button_string, ":,"); |
| 312 tokenizer.set_options(StringTokenizer::RETURN_DELIMS); |
| 313 while (tokenizer.GetNext()) { |
| 314 if (tokenizer.token_is_delim()) { |
| 315 if (*tokenizer.token_begin() == ':') |
| 316 left_side = false; |
| 317 } else { |
| 318 base::StringPiece token = tokenizer.token_piece(); |
| 319 if (token == "minimize") { |
| 320 GtkWidget* parent_box = GetButtonHBox(left_side); |
| 321 minimize_button_.reset( |
| 322 BuildTitlebarButton(IDR_MINIMIZE, IDR_MINIMIZE_P, |
| 323 IDR_MINIMIZE_H, parent_box, |
| 324 IDS_XPFRAME_MINIMIZE_TOOLTIP)); |
| 325 |
| 326 gtk_widget_size_request(minimize_button_->widget(), |
| 327 &minimize_button_req_); |
| 328 } else if (token == "maximize") { |
| 329 GtkWidget* parent_box = GetButtonHBox(left_side); |
| 330 restore_button_.reset( |
| 331 BuildTitlebarButton(IDR_RESTORE, IDR_RESTORE_P, |
| 332 IDR_RESTORE_H, parent_box, |
| 333 IDS_XPFRAME_RESTORE_TOOLTIP)); |
| 334 maximize_button_.reset( |
| 335 BuildTitlebarButton(IDR_MAXIMIZE, IDR_MAXIMIZE_P, |
| 336 IDR_MAXIMIZE_H, parent_box, |
| 337 IDS_XPFRAME_MAXIMIZE_TOOLTIP)); |
| 338 |
| 339 gtk_util::SetButtonClickableByMouseButtons(maximize_button_->widget(), |
| 340 true, true, true); |
| 341 gtk_widget_size_request(restore_button_->widget(), |
| 342 &restore_button_req_); |
| 343 } else if (token == "close") { |
| 344 GtkWidget* parent_box = GetButtonHBox(left_side); |
| 345 close_button_.reset( |
| 346 BuildTitlebarButton(IDR_CLOSE, IDR_CLOSE_P, |
| 347 IDR_CLOSE_H, parent_box, |
| 348 IDS_XPFRAME_CLOSE_TOOLTIP)); |
| 349 |
| 350 gtk_widget_size_request(close_button_->widget(), &close_button_req_); |
| 351 } |
| 352 // Ignore any other values like "pin" since we don't have images for |
| 353 // those. |
| 354 } |
| 355 } |
| 356 |
| 357 // Now show the correct widgets in the two hierarchies. |
| 358 gtk_widget_show_all(titlebar_left_buttons_vbox_); |
| 359 gtk_widget_show_all(titlebar_right_buttons_vbox_); |
| 360 UpdateMaximizeRestoreVisibility(); |
| 361 } |
| 362 |
| 363 GtkWidget* BrowserTitlebar::GetButtonHBox(bool left_side) { |
| 364 if (left_side && titlebar_left_buttons_hbox_) |
| 365 return titlebar_left_buttons_hbox_; |
| 366 else if (!left_side && titlebar_right_buttons_hbox_) |
| 367 return titlebar_right_buttons_hbox_; |
| 368 |
| 369 // We put the min/max/restore/close buttons in a vbox so they are top aligned |
| 370 // (up to padding) and don't vertically stretch. |
| 371 GtkWidget* vbox = left_side ? titlebar_left_buttons_vbox_ : |
| 372 titlebar_right_buttons_vbox_; |
| 373 |
| 374 GtkWidget* top_padding = gtk_fixed_new(); |
| 375 gtk_widget_set_size_request(top_padding, -1, kButtonOuterPadding); |
| 376 gtk_box_pack_start(GTK_BOX(vbox), top_padding, FALSE, FALSE, 0); |
| 377 |
| 378 GtkWidget* buttons_hbox = gtk_hbox_new(FALSE, kButtonSpacing); |
| 379 gtk_box_pack_start(GTK_BOX(vbox), buttons_hbox, FALSE, FALSE, 0); |
| 380 |
| 381 if (left_side) { |
| 382 titlebar_left_buttons_hbox_ = buttons_hbox; |
| 383 top_padding_left_ = top_padding; |
| 384 } else { |
| 385 titlebar_right_buttons_hbox_ = buttons_hbox; |
| 386 top_padding_right_ = top_padding; |
| 387 } |
| 388 |
| 389 return buttons_hbox; |
| 287 } | 390 } |
| 288 | 391 |
| 289 CustomDrawButton* BrowserTitlebar::BuildTitlebarButton(int image, | 392 CustomDrawButton* BrowserTitlebar::BuildTitlebarButton(int image, |
| 290 int image_pressed, int image_hot, GtkWidget* box, int tooltip) { | 393 int image_pressed, int image_hot, GtkWidget* box, int tooltip) { |
| 291 CustomDrawButton* button = new CustomDrawButton(image, image_pressed, | 394 CustomDrawButton* button = new CustomDrawButton(image, image_pressed, |
| 292 image_hot, 0); | 395 image_hot, 0); |
| 293 gtk_widget_add_events(GTK_WIDGET(button->widget()), GDK_POINTER_MOTION_MASK); | 396 gtk_widget_add_events(GTK_WIDGET(button->widget()), GDK_POINTER_MOTION_MASK); |
| 294 g_signal_connect(button->widget(), "clicked", | 397 g_signal_connect(button->widget(), "clicked", |
| 295 G_CALLBACK(OnButtonClickedThunk), this); | 398 G_CALLBACK(OnButtonClickedThunk), this); |
| 296 g_signal_connect(button->widget(), "motion-notify-event", | 399 g_signal_connect(button->widget(), "motion-notify-event", |
| 297 G_CALLBACK(OnMouseMoveEvent), browser_window_); | 400 G_CALLBACK(OnMouseMoveEvent), browser_window_); |
| 298 std::string localized_tooltip = l10n_util::GetStringUTF8(tooltip); | 401 std::string localized_tooltip = l10n_util::GetStringUTF8(tooltip); |
| 299 gtk_widget_set_tooltip_text(button->widget(), | 402 gtk_widget_set_tooltip_text(button->widget(), |
| 300 localized_tooltip.c_str()); | 403 localized_tooltip.c_str()); |
| 301 gtk_box_pack_end(GTK_BOX(box), button->widget(), FALSE, FALSE, 0); | 404 gtk_box_pack_start(GTK_BOX(box), button->widget(), FALSE, FALSE, 0); |
| 302 return button; | 405 return button; |
| 303 } | 406 } |
| 304 | 407 |
| 305 void BrowserTitlebar::UpdateCustomFrame(bool use_custom_frame) { | 408 void BrowserTitlebar::UpdateCustomFrame(bool use_custom_frame) { |
| 306 using_custom_frame_ = use_custom_frame; | 409 using_custom_frame_ = use_custom_frame; |
| 307 if (use_custom_frame) | 410 if (use_custom_frame) { |
| 308 gtk_widget_show(titlebar_buttons_box_); | 411 if (titlebar_left_buttons_vbox_) |
| 309 else | 412 gtk_widget_show(titlebar_left_buttons_vbox_); |
| 310 gtk_widget_hide(titlebar_buttons_box_); | 413 if (titlebar_right_buttons_vbox_) |
| 414 gtk_widget_show(titlebar_right_buttons_vbox_); |
| 415 } else { |
| 416 if (titlebar_left_buttons_vbox_) |
| 417 gtk_widget_hide(titlebar_left_buttons_vbox_); |
| 418 if (titlebar_right_buttons_vbox_) |
| 419 gtk_widget_hide(titlebar_right_buttons_vbox_); |
| 420 } |
| 311 UpdateTitlebarAlignment(); | 421 UpdateTitlebarAlignment(); |
| 312 } | 422 } |
| 313 | 423 |
| 314 void BrowserTitlebar::UpdateTitleAndIcon() { | 424 void BrowserTitlebar::UpdateTitleAndIcon() { |
| 315 if (!app_mode_title_) | 425 if (!app_mode_title_) |
| 316 return; | 426 return; |
| 317 | 427 |
| 318 // Get the page title and elide it to the available space. | 428 // Get the page title and elide it to the available space. |
| 319 string16 title = browser_window_->browser()->GetWindowTitleForCurrentTab(); | 429 string16 title = browser_window_->browser()->GetWindowTitleForCurrentTab(); |
| 320 gtk_label_set_text(GTK_LABEL(app_mode_title_), UTF16ToUTF8(title).c_str()); | 430 gtk_label_set_text(GTK_LABEL(app_mode_title_), UTF16ToUTF8(title).c_str()); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 398 // Resize the buttons so that the clickable area extends all the way to the | 508 // Resize the buttons so that the clickable area extends all the way to the |
| 399 // edge of the browser window. | 509 // edge of the browser window. |
| 400 GtkRequisition close_button_req = close_button_req_; | 510 GtkRequisition close_button_req = close_button_req_; |
| 401 GtkRequisition minimize_button_req = minimize_button_req_; | 511 GtkRequisition minimize_button_req = minimize_button_req_; |
| 402 GtkRequisition restore_button_req = restore_button_req_; | 512 GtkRequisition restore_button_req = restore_button_req_; |
| 403 if (using_custom_frame_ && browser_window_->IsMaximized()) { | 513 if (using_custom_frame_ && browser_window_->IsMaximized()) { |
| 404 close_button_req.width += kButtonOuterPadding; | 514 close_button_req.width += kButtonOuterPadding; |
| 405 close_button_req.height += kButtonOuterPadding; | 515 close_button_req.height += kButtonOuterPadding; |
| 406 minimize_button_req.height += kButtonOuterPadding; | 516 minimize_button_req.height += kButtonOuterPadding; |
| 407 restore_button_req.height += kButtonOuterPadding; | 517 restore_button_req.height += kButtonOuterPadding; |
| 408 gtk_widget_hide(top_padding_); | 518 if (top_padding_left_) |
| 519 gtk_widget_hide(top_padding_left_); |
| 520 if (top_padding_right_) |
| 521 gtk_widget_hide(top_padding_right_); |
| 409 } else { | 522 } else { |
| 410 gtk_widget_show(top_padding_); | 523 if (top_padding_left_) |
| 524 gtk_widget_show(top_padding_left_); |
| 525 if (top_padding_right_) |
| 526 gtk_widget_show(top_padding_right_); |
| 411 } | 527 } |
| 412 gtk_widget_set_size_request(close_button_->widget(), | 528 if (close_button_.get()) { |
| 413 close_button_req.width, close_button_req.height); | 529 gtk_widget_set_size_request(close_button_->widget(), |
| 414 gtk_widget_set_size_request(minimize_button_->widget(), | 530 close_button_req.width, |
| 415 minimize_button_req.width, | 531 close_button_req.height); |
| 416 minimize_button_req.height); | 532 } |
| 417 gtk_widget_set_size_request(restore_button_->widget(), | 533 if (minimize_button_.get()) { |
| 418 restore_button_req.width, | 534 gtk_widget_set_size_request(minimize_button_->widget(), |
| 419 restore_button_req.height); | 535 minimize_button_req.width, |
| 536 minimize_button_req.height); |
| 537 } |
| 538 if (maximize_button_.get()) { |
| 539 gtk_widget_set_size_request(restore_button_->widget(), |
| 540 restore_button_req.width, |
| 541 restore_button_req.height); |
| 542 } |
| 420 } | 543 } |
| 421 | 544 |
| 422 void BrowserTitlebar::UpdateTextColor() { | 545 void BrowserTitlebar::UpdateTextColor() { |
| 423 if (app_mode_title_ && theme_provider_) { | 546 if (app_mode_title_ && theme_provider_) { |
| 424 if (theme_provider_->UseGtkTheme()) { | 547 if (theme_provider_->UseGtkTheme()) { |
| 425 // We don't really have any good options here. | 548 // We don't really have any good options here. |
| 426 // | 549 // |
| 427 // Colors from window manager themes aren't exposed in GTK; the window | 550 // Colors from window manager themes aren't exposed in GTK; the window |
| 428 // manager is a separate component and when there is information sharing | 551 // manager is a separate component and when there is information sharing |
| 429 // (in the case of metacity), it's one way where the window manager reads | 552 // (in the case of metacity), it's one way where the window manager reads |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 488 } else if (event->button.button == 2) { | 611 } else if (event->button.button == 2) { |
| 489 y = 0; | 612 y = 0; |
| 490 height = screen_rect.height; | 613 height = screen_rect.height; |
| 491 } | 614 } |
| 492 | 615 |
| 493 browser_window_->SetBounds(gfx::Rect(x, y, width, height)); | 616 browser_window_->SetBounds(gfx::Rect(x, y, width, height)); |
| 494 } | 617 } |
| 495 gdk_event_free(event); | 618 gdk_event_free(event); |
| 496 } | 619 } |
| 497 | 620 |
| 621 void BrowserTitlebar::UpdateMaximizeRestoreVisibility() { |
| 622 if (maximize_button_.get()) { |
| 623 if (browser_window_->IsMaximized()) { |
| 624 gtk_widget_hide(maximize_button_->widget()); |
| 625 gtk_widget_show(restore_button_->widget()); |
| 626 } else { |
| 627 gtk_widget_hide(restore_button_->widget()); |
| 628 gtk_widget_show(maximize_button_->widget()); |
| 629 } |
| 630 } |
| 631 } |
| 632 |
| 498 // static | 633 // static |
| 499 gboolean BrowserTitlebar::OnWindowStateChanged(GtkWindow* window, | 634 gboolean BrowserTitlebar::OnWindowStateChanged(GtkWindow* window, |
| 500 GdkEventWindowState* event, BrowserTitlebar* titlebar) { | 635 GdkEventWindowState* event, BrowserTitlebar* titlebar) { |
| 501 // Update the maximize/restore button. | 636 titlebar->UpdateMaximizeRestoreVisibility(); |
| 502 if (titlebar->browser_window_->IsMaximized()) { | |
| 503 gtk_widget_hide(titlebar->maximize_button_->widget()); | |
| 504 gtk_widget_show(titlebar->restore_button_->widget()); | |
| 505 } else { | |
| 506 gtk_widget_hide(titlebar->restore_button_->widget()); | |
| 507 gtk_widget_show(titlebar->maximize_button_->widget()); | |
| 508 } | |
| 509 titlebar->UpdateTitlebarAlignment(); | 637 titlebar->UpdateTitlebarAlignment(); |
| 510 titlebar->UpdateTextColor(); | 638 titlebar->UpdateTextColor(); |
| 511 return FALSE; | 639 return FALSE; |
| 512 } | 640 } |
| 513 | 641 |
| 514 // static | 642 // static |
| 515 gboolean BrowserTitlebar::OnScroll(GtkWidget* widget, GdkEventScroll* event, | 643 gboolean BrowserTitlebar::OnScroll(GtkWidget* widget, GdkEventScroll* event, |
| 516 BrowserTitlebar* titlebar) { | 644 BrowserTitlebar* titlebar) { |
| 517 TabStripModel* tabstrip_model = | 645 TabStripModel* tabstrip_model = |
| 518 titlebar->browser_window_->browser()->tabstrip_model(); | 646 titlebar->browser_window_->browser()->tabstrip_model(); |
| 519 int index = tabstrip_model->selected_index(); | 647 int index = tabstrip_model->selected_index(); |
| 520 if (event->direction == GDK_SCROLL_LEFT || | 648 if (event->direction == GDK_SCROLL_LEFT || |
| 521 event->direction == GDK_SCROLL_UP) { | 649 event->direction == GDK_SCROLL_UP) { |
| 522 if (index != 0) | 650 if (index != 0) |
| 523 tabstrip_model->SelectPreviousTab(); | 651 tabstrip_model->SelectPreviousTab(); |
| 524 } else if (index + 1 < tabstrip_model->count()) { | 652 } else if (index + 1 < tabstrip_model->count()) { |
| 525 tabstrip_model->SelectNextTab(); | 653 tabstrip_model->SelectNextTab(); |
| 526 } | 654 } |
| 527 return TRUE; | 655 return TRUE; |
| 528 } | 656 } |
| 529 | 657 |
| 530 // static | 658 // static |
| 531 void BrowserTitlebar::OnButtonClicked(GtkWidget* button) { | 659 void BrowserTitlebar::OnButtonClicked(GtkWidget* button) { |
| 532 if (close_button_->widget() == button) { | 660 if (close_button_.get() && close_button_->widget() == button) { |
| 533 browser_window_->Close(); | 661 browser_window_->Close(); |
| 534 } else if (restore_button_->widget() == button) { | 662 } else if (restore_button_.get() && restore_button_->widget() == button) { |
| 535 browser_window_->UnMaximize(); | 663 browser_window_->UnMaximize(); |
| 536 } else if (maximize_button_->widget() == button) { | 664 } else if (maximize_button_.get() && maximize_button_->widget() == button) { |
| 537 MaximizeButtonClicked(); | 665 MaximizeButtonClicked(); |
| 538 } else if (minimize_button_->widget() == button) { | 666 } else if (minimize_button_.get() && minimize_button_->widget() == button) { |
| 539 gtk_window_iconify(window_); | 667 gtk_window_iconify(window_); |
| 540 } | 668 } |
| 541 } | 669 } |
| 542 | 670 |
| 543 // static | 671 // static |
| 544 gboolean BrowserTitlebar::OnButtonPressed(GtkWidget* widget, | 672 gboolean BrowserTitlebar::OnButtonPressed(GtkWidget* widget, |
| 545 GdkEventButton* event, | 673 GdkEventButton* event, |
| 546 BrowserTitlebar* titlebar) { | 674 BrowserTitlebar* titlebar) { |
| 547 if (event->button != 1) | 675 if (event->button != 1) |
| 548 return FALSE; | 676 return FALSE; |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 694 menus::SimpleMenuModel::Delegate* delegate) | 822 menus::SimpleMenuModel::Delegate* delegate) |
| 695 : SimpleMenuModel(delegate) { | 823 : SimpleMenuModel(delegate) { |
| 696 AddItemWithStringId(IDC_NEW_TAB, IDS_TAB_CXMENU_NEWTAB); | 824 AddItemWithStringId(IDC_NEW_TAB, IDS_TAB_CXMENU_NEWTAB); |
| 697 AddItemWithStringId(IDC_RESTORE_TAB, IDS_RESTORE_TAB); | 825 AddItemWithStringId(IDC_RESTORE_TAB, IDS_RESTORE_TAB); |
| 698 AddSeparator(); | 826 AddSeparator(); |
| 699 AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER); | 827 AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER); |
| 700 AddSeparator(); | 828 AddSeparator(); |
| 701 AddCheckItemWithStringId(kShowWindowDecorationsCommand, | 829 AddCheckItemWithStringId(kShowWindowDecorationsCommand, |
| 702 IDS_SHOW_WINDOW_DECORATIONS_MENU); | 830 IDS_SHOW_WINDOW_DECORATIONS_MENU); |
| 703 } | 831 } |
| OLD | NEW |