| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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/ui/gtk/tabs/tab_gtk.h" | 5 #include "chrome/browser/ui/gtk/tabs/tab_gtk.h" |
| 6 | 6 |
| 7 #include <gdk/gdkkeysyms.h> | 7 #include <gdk/gdkkeysyms.h> |
| 8 | 8 |
| 9 #include "base/memory/singleton.h" | 9 #include "base/memory/singleton.h" |
| 10 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
| 11 #include "chrome/app/chrome_command_ids.h" | 11 #include "chrome/app/chrome_command_ids.h" |
| 12 #include "chrome/browser/ui/gtk/accelerators_gtk.h" | 12 #include "chrome/browser/ui/gtk/accelerators_gtk.h" |
| 13 #include "chrome/browser/ui/gtk/menu_gtk.h" | 13 #include "chrome/browser/ui/gtk/menu_gtk.h" |
| 14 #include "chrome/browser/ui/gtk/tabs/tab_strip_menu_controller.h" |
| 14 #include "chrome/browser/ui/tabs/tab_menu_model.h" | 15 #include "chrome/browser/ui/tabs/tab_menu_model.h" |
| 15 #include "grit/generated_resources.h" | 16 #include "grit/generated_resources.h" |
| 16 #include "grit/theme_resources.h" | 17 #include "grit/theme_resources.h" |
| 17 #include "ui/base/dragdrop/gtk_dnd_util.h" | 18 #include "ui/base/dragdrop/gtk_dnd_util.h" |
| 18 #include "ui/base/models/accelerator_gtk.h" | 19 #include "ui/base/models/accelerator_gtk.h" |
| 19 #include "ui/gfx/path.h" | 20 #include "ui/gfx/path.h" |
| 20 | 21 |
| 21 namespace { | 22 namespace { |
| 22 | 23 |
| 23 // Returns the width of the title for the current font, in pixels. | 24 // Returns the width of the title for the current font, in pixels. |
| 24 int GetTitleWidth(gfx::Font* font, string16 title) { | 25 int GetTitleWidth(gfx::Font* font, string16 title) { |
| 25 DCHECK(font); | 26 DCHECK(font); |
| 26 if (title.empty()) | 27 if (title.empty()) |
| 27 return 0; | 28 return 0; |
| 28 | 29 |
| 29 return font->GetStringWidth(title); | 30 return font->GetStringWidth(title); |
| 30 } | 31 } |
| 31 | 32 |
| 32 } // namespace | 33 } // namespace |
| 33 | 34 |
| 34 class TabGtk::ContextMenuController : public ui::SimpleMenuModel::Delegate, | |
| 35 public MenuGtk::Delegate { | |
| 36 public: | |
| 37 explicit ContextMenuController(TabGtk* tab) | |
| 38 : tab_(tab), | |
| 39 model_(this, tab->delegate()->IsTabPinned(tab)) { | |
| 40 menu_.reset(new MenuGtk(this, &model_)); | |
| 41 } | |
| 42 | |
| 43 virtual ~ContextMenuController() {} | |
| 44 | |
| 45 void RunMenu(const gfx::Point& point, guint32 event_time) { | |
| 46 menu_->PopupAsContext(point, event_time); | |
| 47 } | |
| 48 | |
| 49 void Cancel() { | |
| 50 tab_ = NULL; | |
| 51 menu_->Cancel(); | |
| 52 } | |
| 53 | |
| 54 private: | |
| 55 // Overridden from ui::SimpleMenuModel::Delegate: | |
| 56 virtual bool IsCommandIdChecked(int command_id) const { | |
| 57 return false; | |
| 58 } | |
| 59 virtual bool IsCommandIdEnabled(int command_id) const { | |
| 60 return tab_ && tab_->delegate()->IsCommandEnabledForTab( | |
| 61 static_cast<TabStripModel::ContextMenuCommand>(command_id), | |
| 62 tab_); | |
| 63 } | |
| 64 virtual bool GetAcceleratorForCommandId( | |
| 65 int command_id, | |
| 66 ui::Accelerator* accelerator) { | |
| 67 int browser_command; | |
| 68 if (!TabStripModel::ContextMenuCommandToBrowserCommand(command_id, | |
| 69 &browser_command)) | |
| 70 return false; | |
| 71 const ui::AcceleratorGtk* accelerator_gtk = | |
| 72 AcceleratorsGtk::GetInstance()->GetPrimaryAcceleratorForCommand( | |
| 73 browser_command); | |
| 74 if (accelerator_gtk) | |
| 75 *accelerator = *accelerator_gtk; | |
| 76 return !!accelerator_gtk; | |
| 77 } | |
| 78 | |
| 79 virtual void ExecuteCommand(int command_id) { | |
| 80 if (!tab_) | |
| 81 return; | |
| 82 tab_->delegate()->ExecuteCommandForTab( | |
| 83 static_cast<TabStripModel::ContextMenuCommand>(command_id), tab_); | |
| 84 } | |
| 85 | |
| 86 GtkWidget* GetImageForCommandId(int command_id) const { | |
| 87 int browser_cmd_id; | |
| 88 return TabStripModel::ContextMenuCommandToBrowserCommand(command_id, | |
| 89 &browser_cmd_id) ? | |
| 90 MenuGtk::Delegate::GetDefaultImageForCommandId(browser_cmd_id) : | |
| 91 NULL; | |
| 92 } | |
| 93 | |
| 94 // The context menu. | |
| 95 scoped_ptr<MenuGtk> menu_; | |
| 96 | |
| 97 // The Tab the context menu was brought up for. Set to NULL when the menu | |
| 98 // is canceled. | |
| 99 TabGtk* tab_; | |
| 100 | |
| 101 // The model. | |
| 102 TabMenuModel model_; | |
| 103 | |
| 104 DISALLOW_COPY_AND_ASSIGN(ContextMenuController); | |
| 105 }; | |
| 106 | |
| 107 class TabGtk::TabGtkObserverHelper { | 35 class TabGtk::TabGtkObserverHelper { |
| 108 public: | 36 public: |
| 109 explicit TabGtkObserverHelper(TabGtk* tab) | 37 explicit TabGtkObserverHelper(TabGtk* tab) |
| 110 : tab_(tab) { | 38 : tab_(tab) { |
| 111 MessageLoopForUI::current()->AddObserver(tab_); | 39 MessageLoopForUI::current()->AddObserver(tab_); |
| 112 } | 40 } |
| 113 | 41 |
| 114 ~TabGtkObserverHelper() { | 42 ~TabGtkObserverHelper() { |
| 115 MessageLoopForUI::current()->RemoveObserver(tab_); | 43 MessageLoopForUI::current()->RemoveObserver(tab_); |
| 116 } | 44 } |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 } | 97 } |
| 170 } | 98 } |
| 171 | 99 |
| 172 gboolean TabGtk::OnButtonPressEvent(GtkWidget* widget, GdkEventButton* event) { | 100 gboolean TabGtk::OnButtonPressEvent(GtkWidget* widget, GdkEventButton* event) { |
| 173 // Every button press ensures either a button-release-event or a drag-fail | 101 // Every button press ensures either a button-release-event or a drag-fail |
| 174 // signal for |widget|. | 102 // signal for |widget|. |
| 175 if (event->button == 1 && event->type == GDK_BUTTON_PRESS) { | 103 if (event->button == 1 && event->type == GDK_BUTTON_PRESS) { |
| 176 // Store whether or not we were selected just now... we only want to be | 104 // Store whether or not we were selected just now... we only want to be |
| 177 // able to drag foreground tabs, so we don't start dragging the tab if | 105 // able to drag foreground tabs, so we don't start dragging the tab if |
| 178 // it was in the background. | 106 // it was in the background. |
| 179 bool just_selected = !IsSelected(); | 107 if (!IsActive()) { |
| 180 if (just_selected) { | 108 if (event->state & GDK_CONTROL_MASK) |
| 181 delegate_->SelectTab(this); | 109 delegate_->ToggleTabSelection(this); |
| 110 else if (event->state & GDK_SHIFT_MASK) |
| 111 delegate_->ExtendTabSelection(this); |
| 112 else |
| 113 delegate_->ActivateTab(this); |
| 182 } | 114 } |
| 183 | |
| 184 // Hook into the message loop to handle dragging. | 115 // Hook into the message loop to handle dragging. |
| 185 observer_.reset(new TabGtkObserverHelper(this)); | 116 observer_.reset(new TabGtkObserverHelper(this)); |
| 186 | 117 |
| 187 // Store the button press event, used to initiate a drag. | 118 // Store the button press event, used to initiate a drag. |
| 188 last_mouse_down_ = gdk_event_copy(reinterpret_cast<GdkEvent*>(event)); | 119 last_mouse_down_ = gdk_event_copy(reinterpret_cast<GdkEvent*>(event)); |
| 189 } else if (event->button == 3) { | 120 } else if (event->button == 3) { |
| 190 // Only show the context menu if the left mouse button isn't down (i.e., | 121 // Only show the context menu if the left mouse button isn't down (i.e., |
| 191 // the user might want to drag instead). | 122 // the user might want to drag instead). |
| 192 if (!last_mouse_down_) { | 123 if (!last_mouse_down_) { |
| 193 menu_controller_.reset(new ContextMenuController(this)); | 124 menu_controller_.reset(delegate()->GetTabStripMenuControllerForTab(this)); |
| 194 menu_controller_->RunMenu(gfx::Point(event->x_root, event->y_root), | 125 menu_controller_->RunMenu(gfx::Point(event->x_root, event->y_root), |
| 195 event->time); | 126 event->time); |
| 196 } | 127 } |
| 197 } | 128 } |
| 198 | 129 |
| 199 return TRUE; | 130 return TRUE; |
| 200 } | 131 } |
| 201 | 132 |
| 202 gboolean TabGtk::OnButtonReleaseEvent(GtkWidget* widget, | 133 gboolean TabGtk::OnButtonReleaseEvent(GtkWidget* widget, |
| 203 GdkEventButton* event) { | 134 GdkEventButton* event) { |
| 204 if (event->button == 1) { | 135 if (event->button == 1) { |
| 136 if (IsActive() && !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))) { |
| 137 delegate_->ActivateTab(this); |
| 138 } |
| 205 observer_.reset(); | 139 observer_.reset(); |
| 206 | 140 |
| 207 if (last_mouse_down_) { | 141 if (last_mouse_down_) { |
| 208 gdk_event_free(last_mouse_down_); | 142 gdk_event_free(last_mouse_down_); |
| 209 last_mouse_down_ = NULL; | 143 last_mouse_down_ = NULL; |
| 210 } | 144 } |
| 211 } | 145 } |
| 212 | 146 |
| 213 // Middle mouse up means close the tab, but only if the mouse is over it | 147 // Middle mouse up means close the tab, but only if the mouse is over it |
| 214 // (like a button). | 148 // (like a button). |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 286 static_cast<gint>(new_x), static_cast<gint>(new_y))) { | 220 static_cast<gint>(new_x), static_cast<gint>(new_y))) { |
| 287 StartDragging(gfx::Point( | 221 StartDragging(gfx::Point( |
| 288 static_cast<int>(last_mouse_down_->button.x), | 222 static_cast<int>(last_mouse_down_->button.x), |
| 289 static_cast<int>(last_mouse_down_->button.y))); | 223 static_cast<int>(last_mouse_down_->button.y))); |
| 290 } | 224 } |
| 291 } | 225 } |
| 292 | 226 |
| 293 /////////////////////////////////////////////////////////////////////////////// | 227 /////////////////////////////////////////////////////////////////////////////// |
| 294 // TabGtk, TabRendererGtk overrides: | 228 // TabGtk, TabRendererGtk overrides: |
| 295 | 229 |
| 230 bool TabGtk::IsActive() const { |
| 231 return delegate_->IsTabActive(this); |
| 232 } |
| 233 |
| 296 bool TabGtk::IsSelected() const { | 234 bool TabGtk::IsSelected() const { |
| 297 return delegate_->IsTabSelected(this); | 235 return delegate_->IsTabSelected(this); |
| 298 } | 236 } |
| 299 | 237 |
| 300 bool TabGtk::IsVisible() const { | 238 bool TabGtk::IsVisible() const { |
| 301 return GTK_WIDGET_FLAGS(event_box_) & GTK_VISIBLE; | 239 return GTK_WIDGET_FLAGS(event_box_) & GTK_VISIBLE; |
| 302 } | 240 } |
| 303 | 241 |
| 304 void TabGtk::SetVisible(bool visible) const { | 242 void TabGtk::SetVisible(bool visible) const { |
| 305 if (visible) { | 243 if (visible) { |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 387 gdk_event_free(last_mouse_down_); | 325 gdk_event_free(last_mouse_down_); |
| 388 last_mouse_down_ = NULL; | 326 last_mouse_down_ = NULL; |
| 389 } | 327 } |
| 390 | 328 |
| 391 // Notify the drag helper that we're done with any potential drag operations. | 329 // Notify the drag helper that we're done with any potential drag operations. |
| 392 // Clean up the drag helper, which is re-created on the next mouse press. | 330 // Clean up the drag helper, which is re-created on the next mouse press. |
| 393 delegate_->EndDrag(canceled); | 331 delegate_->EndDrag(canceled); |
| 394 | 332 |
| 395 observer_.reset(); | 333 observer_.reset(); |
| 396 } | 334 } |
| OLD | NEW |