Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Side by Side Diff: chrome/browser/gtk/browser_actions_toolbar_gtk.cc

Issue 463056: GTK: hook up drag and drop of browser actions (for reordering).... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/gtk/browser_actions_toolbar_gtk.h ('k') | chrome/common/gtk_util.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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_actions_toolbar_gtk.h" 5 #include "chrome/browser/gtk/browser_actions_toolbar_gtk.h"
6 6
7 #include <gtk/gtk.h>
8 #include <vector> 7 #include <vector>
9 8
10 #include "app/gfx/canvas_paint.h" 9 #include "app/gfx/canvas_paint.h"
11 #include "app/gfx/gtk_util.h" 10 #include "app/gfx/gtk_util.h"
12 #include "chrome/browser/browser.h" 11 #include "chrome/browser/browser.h"
13 #include "chrome/browser/extensions/extension_browser_event_router.h" 12 #include "chrome/browser/extensions/extension_browser_event_router.h"
14 #include "chrome/browser/extensions/extensions_service.h" 13 #include "chrome/browser/extensions/extensions_service.h"
15 #include "chrome/browser/extensions/image_loading_tracker.h" 14 #include "chrome/browser/extensions/image_loading_tracker.h"
16 #include "chrome/browser/gtk/extension_popup_gtk.h" 15 #include "chrome/browser/gtk/extension_popup_gtk.h"
17 #include "chrome/browser/gtk/gtk_chrome_button.h" 16 #include "chrome/browser/gtk/gtk_chrome_button.h"
18 #include "chrome/browser/gtk/gtk_theme_provider.h" 17 #include "chrome/browser/gtk/gtk_theme_provider.h"
19 #include "chrome/browser/profile.h" 18 #include "chrome/browser/profile.h"
20 #include "chrome/browser/tab_contents/tab_contents.h" 19 #include "chrome/browser/tab_contents/tab_contents.h"
21 #include "chrome/common/extensions/extension.h" 20 #include "chrome/common/extensions/extension.h"
22 #include "chrome/common/extensions/extension_action.h" 21 #include "chrome/common/extensions/extension_action.h"
23 #include "chrome/common/gtk_util.h" 22 #include "chrome/common/gtk_util.h"
24 #include "chrome/common/notification_details.h" 23 #include "chrome/common/notification_details.h"
25 #include "chrome/common/notification_service.h" 24 #include "chrome/common/notification_service.h"
26 #include "chrome/common/notification_source.h" 25 #include "chrome/common/notification_source.h"
27 #include "chrome/common/notification_type.h" 26 #include "chrome/common/notification_type.h"
28 27
28 namespace {
29
29 // The size of each button on the toolbar. 30 // The size of each button on the toolbar.
30 static const int kButtonSize = 29; 31 const int kButtonSize = 29;
31 32
32 // The padding between browser action buttons. Visually, the actual number of 33 // The padding between browser action buttons. Visually, the actual number of
33 // "empty" (non-drawing) pixels is this value + 2 when adjacent browser icons 34 // "empty" (non-drawing) pixels is this value + 2 when adjacent browser icons
34 // use their maximum allowed size. 35 // use their maximum allowed size.
35 static const int kBrowserActionButtonPadding = 3; 36 const int kButtonPadding = 3;
37
38 const char* kDragTarget = "application/x-chrome-browseraction";
39
40 GtkTargetEntry GetDragTargetEntry() {
41 static std::string drag_target_string(kDragTarget);
42 GtkTargetEntry drag_target;
43 drag_target.target = const_cast<char*>(drag_target_string.c_str());
44 drag_target.flags = GTK_TARGET_SAME_APP;
45 drag_target.info = 0;
46 return drag_target;
47 }
48
49 } // namespace
36 50
37 class BrowserActionButton : public NotificationObserver, 51 class BrowserActionButton : public NotificationObserver,
38 public ImageLoadingTracker::Observer { 52 public ImageLoadingTracker::Observer {
39 public: 53 public:
40 BrowserActionButton(BrowserActionsToolbarGtk* toolbar, 54 BrowserActionButton(BrowserActionsToolbarGtk* toolbar,
41 Extension* extension) 55 Extension* extension)
42 : toolbar_(toolbar), 56 : toolbar_(toolbar),
43 extension_(extension), 57 extension_(extension),
44 button_(gtk_chrome_button_new()), 58 button_(gtk_chrome_button_new()),
45 tracker_(NULL), 59 tracker_(NULL),
46 tab_specific_icon_(NULL), 60 tab_specific_icon_(NULL),
47 default_icon_(NULL) { 61 default_icon_(NULL) {
48 DCHECK(extension_->browser_action()); 62 DCHECK(extension_->browser_action());
49 63
50 gtk_widget_set_size_request(button_.get(), kButtonSize, kButtonSize); 64 gtk_widget_set_size_request(button_.get(), kButtonSize, kButtonSize);
51 65
52 UpdateState(); 66 UpdateState();
53 67
54 // The Browser Action API does not allow the default icon path to be 68 // The Browser Action API does not allow the default icon path to be
55 // changed at runtime, so we can load this now and cache it. 69 // changed at runtime, so we can load this now and cache it.
56 std::string path = extension_->browser_action()->default_icon_path(); 70 std::string path = extension_->browser_action()->default_icon_path();
57 if (!path.empty()) { 71 if (!path.empty()) {
58 tracker_ = new ImageLoadingTracker(this, 1); 72 tracker_ = new ImageLoadingTracker(this, 1);
59 tracker_->PostLoadImageTask(extension_->GetResource(path), 73 tracker_->PostLoadImageTask(extension_->GetResource(path),
60 gfx::Size(Extension::kBrowserActionIconMaxSize, 74 gfx::Size(Extension::kBrowserActionIconMaxSize,
61 Extension::kBrowserActionIconMaxSize)); 75 Extension::kBrowserActionIconMaxSize));
62 } 76 }
63 77
64 // We need to hook up extension popups here. http://crbug.com/23897
65 g_signal_connect(button_.get(), "clicked", 78 g_signal_connect(button_.get(), "clicked",
66 G_CALLBACK(OnButtonClicked), this); 79 G_CALLBACK(OnButtonClicked), this);
67 g_signal_connect_after(button_.get(), "expose-event", 80 g_signal_connect_after(button_.get(), "expose-event",
68 G_CALLBACK(OnExposeEvent), this); 81 G_CALLBACK(OnExposeEvent), this);
82 g_signal_connect(button_.get(), "drag-begin",
83 G_CALLBACK(&OnDragBegin), this);
69 84
70 registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED, 85 registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED,
71 Source<ExtensionAction>(extension->browser_action())); 86 Source<ExtensionAction>(extension->browser_action()));
72 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, 87 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
73 NotificationService::AllSources()); 88 NotificationService::AllSources());
74 89
75 OnThemeChanged(); 90 OnThemeChanged();
76 } 91 }
77 92
78 ~BrowserActionButton() { 93 ~BrowserActionButton() {
79 if (tab_specific_icon_) 94 if (tab_specific_icon_)
80 g_object_unref(tab_specific_icon_); 95 g_object_unref(tab_specific_icon_);
81 96
82 if (default_icon_) 97 if (default_icon_)
83 g_object_unref(default_icon_); 98 g_object_unref(default_icon_);
84 99
85 button_.Destroy(); 100 button_.Destroy();
86 101
87 if (tracker_) 102 if (tracker_)
88 tracker_->StopTrackingImageLoad(); 103 tracker_->StopTrackingImageLoad();
89 } 104 }
90 105
91 GtkWidget* widget() { return button_.get(); } 106 GtkWidget* widget() { return button_.get(); }
92 107
108 Extension* extension() { return extension_; }
109
110 // NotificationObserver implementation.
93 void Observe(NotificationType type, 111 void Observe(NotificationType type,
94 const NotificationSource& source, 112 const NotificationSource& source,
95 const NotificationDetails& details) { 113 const NotificationDetails& details) {
96 if (type == NotificationType::EXTENSION_BROWSER_ACTION_UPDATED) 114 if (type == NotificationType::EXTENSION_BROWSER_ACTION_UPDATED)
97 UpdateState(); 115 UpdateState();
98 else if (type == NotificationType::BROWSER_THEME_CHANGED) 116 else if (type == NotificationType::BROWSER_THEME_CHANGED)
99 OnThemeChanged(); 117 OnThemeChanged();
100 else 118 else
101 NOTREACHED(); 119 NOTREACHED();
102 } 120 }
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 gtk_image_new_from_pixbuf(image)); 159 gtk_image_new_from_pixbuf(image));
142 } 160 }
143 161
144 void OnThemeChanged() { 162 void OnThemeChanged() {
145 gtk_chrome_button_set_use_gtk_rendering(GTK_CHROME_BUTTON(button_.get()), 163 gtk_chrome_button_set_use_gtk_rendering(GTK_CHROME_BUTTON(button_.get()),
146 GtkThemeProvider::GetFrom( 164 GtkThemeProvider::GetFrom(
147 toolbar_->browser()->profile())->UseGtkTheme()); 165 toolbar_->browser()->profile())->UseGtkTheme());
148 } 166 }
149 167
150 static void OnButtonClicked(GtkWidget* widget, BrowserActionButton* action) { 168 static void OnButtonClicked(GtkWidget* widget, BrowserActionButton* action) {
151 if (action->extension_->browser_action()->has_popup()) { 169 if (action->extension_->browser_action()->has_popup()) {
152 ExtensionPopupGtk::Show( 170 ExtensionPopupGtk::Show(
153 action->extension_->browser_action()->popup_url(), 171 action->extension_->browser_action()->popup_url(),
154 action->toolbar_->browser(), 172 action->toolbar_->browser(),
155 gtk_util::GetWidgetRectRelativeToToplevel(widget)); 173 gtk_util::GetWidgetRectRelativeToToplevel(widget));
156 } else { 174 } else {
157 ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted( 175 ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted(
158 action->toolbar_->browser()->profile(), action->extension_->id(), 176 action->toolbar_->browser()->profile(), action->extension_->id(),
159 action->toolbar_->browser()); 177 action->toolbar_->browser());
160 } 178 }
161 } 179 }
162 180
163 static gboolean OnExposeEvent(GtkWidget* widget, 181 static gboolean OnExposeEvent(GtkWidget* widget,
164 GdkEventExpose* event, 182 GdkEventExpose* event,
165 BrowserActionButton* button) { 183 BrowserActionButton* button) {
166 int tab_id = button->toolbar_->GetCurrentTabId(); 184 int tab_id = button->toolbar_->GetCurrentTabId();
167 if (tab_id < 0) 185 if (tab_id < 0)
168 return FALSE; 186 return FALSE;
169 187
170 ExtensionAction* action = button->extension_->browser_action(); 188 ExtensionAction* action = button->extension_->browser_action();
171 if (action->GetBadgeText(tab_id).empty()) 189 if (action->GetBadgeText(tab_id).empty())
172 return FALSE; 190 return FALSE;
173 191
174 gfx::CanvasPaint canvas(event, false); 192 gfx::CanvasPaint canvas(event, false);
175 gfx::Rect bounding_rect(widget->allocation); 193 gfx::Rect bounding_rect(widget->allocation);
176 action->PaintBadge(&canvas, bounding_rect, tab_id); 194 action->PaintBadge(&canvas, bounding_rect, tab_id);
177 return FALSE; 195 return FALSE;
178 } 196 }
179 197
198 static void OnDragBegin(GtkWidget* widget,
199 GdkDragContext* drag_context,
200 BrowserActionButton* button) {
201 // Simply pass along the notification to the toolbar. The point of this
202 // function is to tell the toolbar which BrowserActionButton initiated the
203 // drag.
204 button->toolbar_->DragStarted(button, drag_context);
205 }
206
180 // The toolbar containing this button. 207 // The toolbar containing this button.
181 BrowserActionsToolbarGtk* toolbar_; 208 BrowserActionsToolbarGtk* toolbar_;
182 209
183 // The extension that contains this browser action. 210 // The extension that contains this browser action.
184 Extension* extension_; 211 Extension* extension_;
185 212
186 // The gtk widget for this browser action. 213 // The gtk widget for this browser action.
187 OwnedWidgetGtk button_; 214 OwnedWidgetGtk button_;
188 215
189 // Loads the button's icons for us on the file thread. 216 // Loads the button's icons for us on the file thread.
190 ImageLoadingTracker* tracker_; 217 ImageLoadingTracker* tracker_;
191 218
192 // If we are displaying a tab-specific icon, it will be here. 219 // If we are displaying a tab-specific icon, it will be here.
193 GdkPixbuf* tab_specific_icon_; 220 GdkPixbuf* tab_specific_icon_;
194 221
195 // If the browser action has a default icon, it will be here. 222 // If the browser action has a default icon, it will be here.
196 GdkPixbuf* default_icon_; 223 GdkPixbuf* default_icon_;
197 224
198 NotificationRegistrar registrar_; 225 NotificationRegistrar registrar_;
199 226
200 friend class BrowserActionsToolbarGtk; 227 friend class BrowserActionsToolbarGtk;
201 }; 228 };
202 229
203 BrowserActionsToolbarGtk::BrowserActionsToolbarGtk(Browser* browser) 230 BrowserActionsToolbarGtk::BrowserActionsToolbarGtk(Browser* browser)
204 : browser_(browser), 231 : browser_(browser),
205 profile_(browser->profile()), 232 profile_(browser->profile()),
206 model_(NULL), 233 model_(NULL),
207 hbox_(gtk_hbox_new(FALSE, kBrowserActionButtonPadding)) { 234 hbox_(gtk_hbox_new(FALSE, kButtonPadding)),
235 drag_button_(NULL),
236 drop_index_(-1) {
208 ExtensionsService* extension_service = profile_->GetExtensionsService(); 237 ExtensionsService* extension_service = profile_->GetExtensionsService();
209 // The |extension_service| can be NULL in Incognito. 238 // The |extension_service| can be NULL in Incognito.
210 if (extension_service) { 239 if (!extension_service)
211 model_ = extension_service->toolbar_model(); 240 return;
212 model_->AddObserver(this); 241
213 CreateAllButtons(); 242 model_ = extension_service->toolbar_model();
214 } 243 model_->AddObserver(this);
244 SetupDrags();
245 CreateAllButtons();
215 } 246 }
216 247
217 BrowserActionsToolbarGtk::~BrowserActionsToolbarGtk() { 248 BrowserActionsToolbarGtk::~BrowserActionsToolbarGtk() {
218 if (model_) 249 if (model_)
219 model_->RemoveObserver(this); 250 model_->RemoveObserver(this);
220 hbox_.Destroy(); 251 hbox_.Destroy();
221 } 252 }
222 253
223 int BrowserActionsToolbarGtk::GetCurrentTabId() { 254 int BrowserActionsToolbarGtk::GetCurrentTabId() {
224 TabContents* selected_tab = browser_->GetSelectedTabContents(); 255 TabContents* selected_tab = browser_->GetSelectedTabContents();
225 if (!selected_tab) 256 if (!selected_tab)
226 return -1; 257 return -1;
227 258
228 return selected_tab->controller().session_id().id(); 259 return selected_tab->controller().session_id().id();
229 } 260 }
230 261
231 void BrowserActionsToolbarGtk::Update() { 262 void BrowserActionsToolbarGtk::Update() {
232 for (ExtensionButtonMap::iterator iter = extension_button_map_.begin(); 263 for (ExtensionButtonMap::iterator iter = extension_button_map_.begin();
233 iter != extension_button_map_.end(); ++iter) { 264 iter != extension_button_map_.end(); ++iter) {
234 iter->second->UpdateState(); 265 iter->second->UpdateState();
235 } 266 }
236 } 267 }
237 268
269 void BrowserActionsToolbarGtk::SetupDrags() {
270 GtkTargetEntry drag_target = GetDragTargetEntry();
271 gtk_drag_dest_set(widget(), GTK_DEST_DEFAULT_DROP, &drag_target, 1,
272 GDK_ACTION_MOVE);
273
274 g_signal_connect(widget(), "drag-motion",
275 G_CALLBACK(OnDragMotionThunk), this);
276 }
277
238 void BrowserActionsToolbarGtk::CreateAllButtons() { 278 void BrowserActionsToolbarGtk::CreateAllButtons() {
279 extension_button_map_.clear();
280
281 int i = 0;
239 for (ExtensionList::iterator iter = model_->begin(); 282 for (ExtensionList::iterator iter = model_->begin();
240 iter != model_->end(); ++iter) { 283 iter != model_->end(); ++iter) {
241 CreateButtonForExtension(*iter); 284 CreateButtonForExtension(*iter, i++);
242 } 285 }
243 } 286 }
244 287
245 void BrowserActionsToolbarGtk::CreateButtonForExtension(Extension* extension) { 288 void BrowserActionsToolbarGtk::CreateButtonForExtension(Extension* extension,
289 int index) {
246 RemoveButtonForExtension(extension); 290 RemoveButtonForExtension(extension);
247 linked_ptr<BrowserActionButton> button( 291 linked_ptr<BrowserActionButton> button(
248 new BrowserActionButton(this, extension)); 292 new BrowserActionButton(this, extension));
249 gtk_box_pack_end(GTK_BOX(hbox_.get()), button->widget(), FALSE, FALSE, 0); 293 gtk_box_pack_start(GTK_BOX(hbox_.get()), button->widget(), FALSE, FALSE, 0);
294 gtk_box_reorder_child(GTK_BOX(hbox_.get()), button->widget(), index);
250 gtk_widget_show(button->widget()); 295 gtk_widget_show(button->widget());
251 extension_button_map_[extension->id()] = button; 296 extension_button_map_[extension->id()] = button;
252 297
298 GtkTargetEntry drag_target = GetDragTargetEntry();
299 gtk_drag_source_set(button->widget(), GDK_BUTTON1_MASK, &drag_target, 1,
300 GDK_ACTION_MOVE);
301 // We ignore whether the drag was a "success" or "failure" in Gtk's opinion.
302 g_signal_connect(button->widget(), "drag-end",
303 G_CALLBACK(&OnDragEndThunk), this);
304
253 UpdateVisibility(); 305 UpdateVisibility();
254 } 306 }
255 307
256 void BrowserActionsToolbarGtk::RemoveButtonForExtension(Extension* extension) { 308 void BrowserActionsToolbarGtk::RemoveButtonForExtension(Extension* extension) {
257 if (extension_button_map_.erase(extension->id())) 309 if (extension_button_map_.erase(extension->id()))
258 UpdateVisibility(); 310 UpdateVisibility();
259 } 311 }
260 312
261 void BrowserActionsToolbarGtk::UpdateVisibility() { 313 void BrowserActionsToolbarGtk::UpdateVisibility() {
262 if (button_count() == 0) 314 if (button_count() == 0)
263 gtk_widget_hide(widget()); 315 gtk_widget_hide(widget());
264 else 316 else
265 gtk_widget_show(widget()); 317 gtk_widget_show(widget());
266 } 318 }
267 319
268 void BrowserActionsToolbarGtk::BrowserActionAdded(Extension* extension, 320 void BrowserActionsToolbarGtk::BrowserActionAdded(Extension* extension,
269 int index) { 321 int index) {
270 // TODO(estade): respect |index|. 322 CreateButtonForExtension(extension, index);
271 CreateButtonForExtension(extension);
272 } 323 }
273 324
274 void BrowserActionsToolbarGtk::BrowserActionRemoved(Extension* extension) { 325 void BrowserActionsToolbarGtk::BrowserActionRemoved(Extension* extension) {
326 if (drag_button_ != NULL) {
327 // Break the current drag.
328 gtk_grab_remove(widget());
329
330 // Re-generate the toolbar to clean up unfinished drag business (i.e., we
331 // may have re-ordered some buttons; this will put them back where they
332 // belong).
333 CreateAllButtons();
334 }
335
275 RemoveButtonForExtension(extension); 336 RemoveButtonForExtension(extension);
276 } 337 }
338
339 void BrowserActionsToolbarGtk::BrowserActionMoved(Extension* extension,
340 int index) {
341 // We initiated this move action, and have already moved the button.
342 if (drag_button_ != NULL)
343 return;
344
345 BrowserActionButton* button = extension_button_map_[extension->id()].get();
346 if (!button) {
347 NOTREACHED();
348 return;
349 }
350
351 gtk_box_reorder_child(GTK_BOX(hbox_.get()), button->widget(), index);
352 }
353
354 void BrowserActionsToolbarGtk::DragStarted(BrowserActionButton* button,
355 GdkDragContext* drag_context) {
356 // No representation of the widget following the cursor.
357 GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
358 gtk_drag_set_icon_pixbuf(drag_context, pixbuf, 0, 0);
359 g_object_unref(pixbuf);
360
361 DCHECK(!drag_button_);
362 drag_button_ = button;
363 }
364
365 gboolean BrowserActionsToolbarGtk::OnDragMotion(GtkWidget* widget,
366 GdkDragContext* drag_context,
367 gint x, gint y, guint time) {
368 drop_index_ = x < kButtonSize ? 0 : x / (kButtonSize + kButtonPadding);
369 // We will go ahead and reorder the child in order to provide visual feedback
370 // to the user. We don't inform the model that it has moved until the drag
371 // ends.
372 gtk_box_reorder_child(GTK_BOX(hbox_.get()), drag_button_->widget(),
373 drop_index_);
374
375 gdk_drag_status(drag_context, GDK_ACTION_MOVE, time);
376 return TRUE;
377 }
378
379 void BrowserActionsToolbarGtk::OnDragEnd(GtkWidget* button,
380 GdkDragContext* drag_context) {
381 if (drop_index_ != -1)
382 model_->MoveBrowserAction(drag_button_->extension(), drop_index_);
383
384 drag_button_ = NULL;
385 drop_index_ = -1;
386 }
OLDNEW
« no previous file with comments | « chrome/browser/gtk/browser_actions_toolbar_gtk.h ('k') | chrome/common/gtk_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698