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

Side by Side Diff: chrome/browser/ui/gtk/tabs/dragged_view_gtk.cc

Issue 231733005: Delete the GTK+ port of Chrome. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remerge to ToT Created 6 years, 8 months 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
OLDNEW
(Empty)
1 // Copyright (c) 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.
4
5 #include "chrome/browser/ui/gtk/tabs/dragged_view_gtk.h"
6
7 #include <gdk/gdk.h>
8
9 #include <algorithm>
10
11 #include "base/debug/trace_event.h"
12 #include "base/i18n/rtl.h"
13 #include "base/stl_util.h"
14 #include "chrome/browser/extensions/tab_helper.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/themes/theme_service.h"
17 #include "chrome/browser/themes/theme_service_factory.h"
18 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
19 #include "chrome/browser/ui/gtk/gtk_util.h"
20 #include "chrome/browser/ui/gtk/tabs/drag_data.h"
21 #include "chrome/browser/ui/gtk/tabs/tab_renderer_gtk.h"
22 #include "chrome/browser/ui/tabs/tab_strip_model.h"
23 #include "content/public/browser/render_view_host.h"
24 #include "content/public/browser/web_contents.h"
25 #include "third_party/skia/include/core/SkShader.h"
26 #include "ui/base/gtk/gtk_screen_util.h"
27 #include "ui/base/x/x11_util.h"
28 #include "ui/gfx/gtk_util.h"
29
30 using content::WebContents;
31
32 namespace {
33
34 // The size of the dragged window frame.
35 const int kDragFrameBorderSize = 1;
36 const int kTwiceDragFrameBorderSize = 2 * kDragFrameBorderSize;
37
38 // Used to scale the dragged window sizes.
39 const float kScalingFactor = 0.5;
40
41 const int kAnimateToBoundsDurationMs = 150;
42
43 const gdouble kTransparentAlpha = (200.0f / 255.0f);
44 const gdouble kOpaqueAlpha = 1.0f;
45 const double kDraggedTabBorderColor[] = { 103.0 / 0xff,
46 129.0 / 0xff,
47 162.0 / 0xff };
48
49 } // namespace
50
51 ////////////////////////////////////////////////////////////////////////////////
52 // DraggedViewGtk, public:
53
54 DraggedViewGtk::DraggedViewGtk(DragData* drag_data,
55 const gfx::Point& mouse_tab_offset,
56 const gfx::Size& contents_size)
57 : drag_data_(drag_data),
58 mini_width_(-1),
59 normal_width_(-1),
60 attached_(false),
61 parent_window_width_(-1),
62 mouse_tab_offset_(mouse_tab_offset),
63 attached_tab_size_(TabRendererGtk::GetMinimumSelectedSize()),
64 contents_size_(contents_size),
65 close_animation_(this) {
66 std::vector<WebContents*> data_sources(drag_data_->GetDraggedTabsContents());
67 for (size_t i = 0; i < data_sources.size(); i++) {
68 renderers_.push_back(new TabRendererGtk(GtkThemeService::GetFrom(
69 Profile::FromBrowserContext(data_sources[i]->GetBrowserContext()))));
70 }
71
72 for (size_t i = 0; i < drag_data_->size(); i++) {
73 WebContents* web_contents = drag_data_->get(i)->contents_;
74 renderers_[i]->UpdateData(
75 web_contents,
76 extensions::TabHelper::FromWebContents(web_contents)->is_app(),
77 false); // loading_only
78 renderers_[i]->set_is_active(
79 static_cast<int>(i) == drag_data_->source_tab_index());
80 }
81
82 container_ = gtk_window_new(GTK_WINDOW_POPUP);
83 SetContainerColorMap();
84 gtk_widget_set_app_paintable(container_, TRUE);
85 g_signal_connect(container_, "expose-event", G_CALLBACK(OnExposeThunk), this);
86 gtk_widget_add_events(container_, GDK_STRUCTURE_MASK);
87
88 // We contain the tab renderer in a GtkFixed in order to maintain the
89 // requested size. Otherwise, the widget will fill the entire window and
90 // cause a crash when rendering because the bounds don't match our images.
91 fixed_ = gtk_fixed_new();
92 for (size_t i = 0; i < renderers_.size(); i++)
93 gtk_fixed_put(GTK_FIXED(fixed_), renderers_[i]->widget(), 0, 0);
94
95 gtk_container_add(GTK_CONTAINER(container_), fixed_);
96 gtk_widget_show_all(container_);
97 }
98
99 DraggedViewGtk::~DraggedViewGtk() {
100 gtk_widget_destroy(container_);
101 STLDeleteElements(&renderers_);
102 }
103
104 void DraggedViewGtk::MoveDetachedTo(const gfx::Point& screen_point) {
105 DCHECK(!attached_);
106 gfx::Point distance_from_origin =
107 GetDistanceFromTabStripOriginToMousePointer();
108 int y = screen_point.y() - ScaleValue(distance_from_origin.y());
109 int x = screen_point.x() - ScaleValue(distance_from_origin.x());
110 gtk_window_move(GTK_WINDOW(container_), x, y);
111 }
112
113 void DraggedViewGtk::MoveAttachedTo(const gfx::Point& tabstrip_point) {
114 DCHECK(attached_);
115 int x = tabstrip_point.x() + GetWidthInTabStripUpToMousePointer() -
116 ScaleValue(GetWidthInTabStripUpToMousePointer());
117 int y = tabstrip_point.y() + mouse_tab_offset_.y() -
118 ScaleValue(mouse_tab_offset_.y());
119 gtk_window_move(GTK_WINDOW(container_), x, y);
120 }
121
122 gfx::Point DraggedViewGtk::GetDistanceFromTabStripOriginToMousePointer() {
123 gfx::Point start_point(GetWidthInTabStripUpToMousePointer(),
124 mouse_tab_offset_.y());
125 if (base::i18n::IsRTL())
126 start_point.Offset(parent_window_width_ - GetTotalWidthInTabStrip(), 0);
127 return start_point;
128 }
129
130 void DraggedViewGtk::Attach(
131 int normal_width, int mini_width, int window_width) {
132 attached_ = true;
133 parent_window_width_ = window_width;
134 normal_width_ = normal_width;
135 mini_width_ = mini_width;
136
137 int dragged_tab_width =
138 drag_data_->GetSourceTabData()->mini_ ? mini_width : normal_width;
139
140 Resize(dragged_tab_width);
141
142 if (ui::IsScreenComposited()) {
143 GdkWindow* gdk_window = gtk_widget_get_window(container_);
144 gdk_window_set_opacity(gdk_window, kOpaqueAlpha);
145 }
146 }
147
148 void DraggedViewGtk::Resize(int width) {
149 attached_tab_size_.set_width(width);
150 ResizeContainer();
151 }
152
153 void DraggedViewGtk::Detach() {
154 attached_ = false;
155 ResizeContainer();
156
157 if (ui::IsScreenComposited()) {
158 GdkWindow* gdk_window = gtk_widget_get_window(container_);
159 gdk_window_set_opacity(gdk_window, kTransparentAlpha);
160 }
161 }
162
163 void DraggedViewGtk::Update() {
164 gtk_widget_queue_draw(container_);
165 }
166
167 int DraggedViewGtk::GetWidthInTabStripFromTo(int from, int to) {
168 DCHECK(from <= static_cast<int>(drag_data_->size()));
169 DCHECK(to <= static_cast<int>(drag_data_->size()));
170
171 // TODO(dpapad): Get 16 from TabStripGtk::kTabHOffset.
172 int mini_tab_count = 0, non_mini_tab_count = 0;
173 drag_data_->GetNumberOfMiniNonMiniTabs(from, to,
174 &mini_tab_count, &non_mini_tab_count);
175 int width = non_mini_tab_count * static_cast<int>(floor(normal_width_ + 0.5))
176 + mini_tab_count * mini_width_ - std::max(to - from - 1, 0) * 16;
177 return width;
178 }
179
180 int DraggedViewGtk::GetTotalWidthInTabStrip() {
181 return GetWidthInTabStripFromTo(0, drag_data_->size());
182 }
183
184 int DraggedViewGtk::GetWidthInTabStripUpToSourceTab() {
185 if (!base::i18n::IsRTL()) {
186 return GetWidthInTabStripFromTo(0, drag_data_->source_tab_index());
187 } else {
188 return GetWidthInTabStripFromTo(
189 drag_data_->source_tab_index() + 1, drag_data_->size());
190 }
191 }
192
193 int DraggedViewGtk::GetWidthInTabStripUpToMousePointer() {
194 int width = GetWidthInTabStripUpToSourceTab() + mouse_tab_offset_.x();
195 if (!base::i18n::IsRTL() && drag_data_->source_tab_index() > 0) {
196 width -= 16;
197 } else if (base::i18n::IsRTL() &&
198 drag_data_->source_tab_index() <
199 static_cast<int>(drag_data_->size()) - 1) {
200 width -= 16;
201 }
202 return width;
203 }
204
205 void DraggedViewGtk::AnimateToBounds(const gfx::Rect& bounds,
206 const base::Closure& callback) {
207 animation_callback_ = callback;
208
209 gint x, y, width, height;
210 GdkWindow* gdk_window = gtk_widget_get_window(container_);
211 gdk_window_get_origin(gdk_window, &x, &y);
212 gdk_window_get_geometry(gdk_window, NULL, NULL,
213 &width, &height, NULL);
214
215 animation_start_bounds_ = gfx::Rect(x, y, width, height);
216 animation_end_bounds_ = bounds;
217
218 close_animation_.SetSlideDuration(kAnimateToBoundsDurationMs);
219 close_animation_.SetTweenType(gfx::Tween::EASE_OUT);
220 if (!close_animation_.IsShowing()) {
221 close_animation_.Reset();
222 close_animation_.Show();
223 }
224 }
225
226 ////////////////////////////////////////////////////////////////////////////////
227 // DraggedViewGtk, gfx::AnimationDelegate implementation:
228
229 void DraggedViewGtk::AnimationProgressed(const gfx::Animation* animation) {
230 int delta_x = (animation_end_bounds_.x() - animation_start_bounds_.x());
231 int x = animation_start_bounds_.x() +
232 static_cast<int>(delta_x * animation->GetCurrentValue());
233 int y = animation_end_bounds_.y();
234 GdkWindow* gdk_window = gtk_widget_get_window(container_);
235 gdk_window_move(gdk_window, x, y);
236 }
237
238 void DraggedViewGtk::AnimationEnded(const gfx::Animation* animation) {
239 animation_callback_.Run();
240 }
241
242 void DraggedViewGtk::AnimationCanceled(const gfx::Animation* animation) {
243 AnimationEnded(animation);
244 }
245
246 ////////////////////////////////////////////////////////////////////////////////
247 // DraggedViewGtk, private:
248
249 void DraggedViewGtk::Layout() {
250 if (attached_) {
251 for (size_t i = 0; i < renderers_.size(); i++) {
252 gfx::Rect rect(GetPreferredSize());
253 rect.set_width(GetAttachedTabWidthAt(i));
254 renderers_[i]->SetBounds(rect);
255 }
256 } else {
257 int left = 0;
258 if (base::i18n::IsRTL())
259 left = GetPreferredSize().width() - attached_tab_size_.width();
260
261 // The renderer_'s width should be attached_tab_size_.width() in both LTR
262 // and RTL locales. Wrong width will cause the wrong positioning of the tab
263 // view in dragging. Please refer to http://crbug.com/6223 for details.
264 renderers_[drag_data_->source_tab_index()]->SetBounds(
265 gfx::Rect(left, 0, attached_tab_size_.width(),
266 attached_tab_size_.height()));
267 }
268 }
269
270 gfx::Size DraggedViewGtk::GetPreferredSize() {
271 if (attached_) {
272 gfx::Size preferred_size(attached_tab_size_);
273 preferred_size.set_width(GetTotalWidthInTabStrip());
274 return preferred_size;
275 }
276
277 int width = std::max(attached_tab_size_.width(), contents_size_.width()) +
278 kTwiceDragFrameBorderSize;
279 int height = attached_tab_size_.height() + kDragFrameBorderSize +
280 contents_size_.height();
281 return gfx::Size(width, height);
282 }
283
284 void DraggedViewGtk::ResizeContainer() {
285 gfx::Size size = GetPreferredSize();
286 gtk_window_resize(GTK_WINDOW(container_),
287 ScaleValue(size.width()), ScaleValue(size.height()));
288 Layout();
289 }
290
291 int DraggedViewGtk::ScaleValue(int value) {
292 return attached_ ? value : static_cast<int>(value * kScalingFactor);
293 }
294
295 gfx::Rect DraggedViewGtk::bounds() const {
296 gint x, y, width, height;
297 gtk_window_get_position(GTK_WINDOW(container_), &x, &y);
298 gtk_window_get_size(GTK_WINDOW(container_), &width, &height);
299 return gfx::Rect(x, y, width, height);
300 }
301
302 int DraggedViewGtk::GetAttachedTabWidthAt(int index) {
303 return drag_data_->get(index)->mini_? mini_width_ : normal_width_;
304 }
305
306 void DraggedViewGtk::SetContainerColorMap() {
307 GdkScreen* screen = gtk_widget_get_screen(container_);
308 GdkColormap* colormap = gdk_screen_get_rgba_colormap(screen);
309
310 // If rgba is not available, use rgb instead.
311 if (!colormap)
312 colormap = gdk_screen_get_rgb_colormap(screen);
313
314 gtk_widget_set_colormap(container_, colormap);
315 }
316
317 void DraggedViewGtk::SetContainerTransparency() {
318 cairo_t* cairo_context = gdk_cairo_create(gtk_widget_get_window(container_));
319 if (!cairo_context)
320 return;
321
322 // Make the background of the dragged tab window fully transparent. All of
323 // the content of the window (child widgets) will be completely opaque.
324 gfx::Size size = bounds().size();
325 cairo_scale(cairo_context, static_cast<double>(size.width()),
326 static_cast<double>(size.height()));
327 cairo_set_source_rgba(cairo_context, 1.0f, 1.0f, 1.0f, 0.0f);
328 cairo_set_operator(cairo_context, CAIRO_OPERATOR_SOURCE);
329 cairo_paint(cairo_context);
330 cairo_destroy(cairo_context);
331 }
332
333 void DraggedViewGtk::SetContainerShapeMask() {
334 // Create a 1bpp bitmap the size of |container_|.
335 gfx::Size size(GetPreferredSize());
336 GdkPixmap* pixmap = gdk_pixmap_new(NULL, size.width(), size.height(), 1);
337 cairo_t* cairo_context = gdk_cairo_create(GDK_DRAWABLE(pixmap));
338
339 // Set the transparency.
340 cairo_set_source_rgba(cairo_context, 1.0f, 1.0f, 1.0f, 0.0f);
341
342 // Blit the rendered bitmap into a pixmap. Any pixel set in the pixmap will
343 // be opaque in the container window.
344 if (!attached_)
345 cairo_scale(cairo_context, kScalingFactor, kScalingFactor);
346 for (size_t i = 0; i < renderers_.size(); i++) {
347 if (static_cast<int>(i) == 0)
348 cairo_set_operator(cairo_context, CAIRO_OPERATOR_SOURCE);
349 else
350 cairo_set_operator(cairo_context, CAIRO_OPERATOR_OVER);
351
352 GtkAllocation allocation;
353 gtk_widget_get_allocation(container_, &allocation);
354 PaintTab(i, container_, cairo_context, allocation.width);
355 }
356
357 if (!attached_) {
358 // Make the render area depiction opaque (leaving enough room for the
359 // border).
360 cairo_identity_matrix(cairo_context);
361 // On Lucid running VNC, the X server will reject RGBA (1,1,1,1) as an
362 // invalid value below in gdk_window_shape_combine_mask(). Using (0,0,0,1)
363 // instead. The value doesn't really matter, as long as the alpha is not 0.
364 cairo_set_source_rgba(cairo_context, 0.0f, 0.0f, 0.0f, 1.0f);
365 int tab_height = static_cast<int>(
366 kScalingFactor * renderers_[drag_data_->source_tab_index()]->height() -
367 kDragFrameBorderSize);
368 cairo_rectangle(cairo_context,
369 0, tab_height,
370 size.width(), size.height() - tab_height);
371 cairo_fill(cairo_context);
372 }
373
374 cairo_destroy(cairo_context);
375
376 // Set the shape mask.
377 GdkWindow* gdk_window = gtk_widget_get_window(container_);
378 gdk_window_shape_combine_mask(gdk_window, pixmap, 0, 0);
379 g_object_unref(pixmap);
380 }
381
382 gboolean DraggedViewGtk::OnExpose(GtkWidget* widget, GdkEventExpose* event) {
383 TRACE_EVENT0("ui::gtk", "DraggedViewGtk::OnExpose");
384
385 if (ui::IsScreenComposited())
386 SetContainerTransparency();
387 else
388 SetContainerShapeMask();
389
390 // Only used when not attached.
391 int tab_height = static_cast<int>(
392 kScalingFactor * renderers_[drag_data_->source_tab_index()]->height());
393
394 GtkAllocation allocation;
395 gtk_widget_get_allocation(widget, &allocation);
396
397 // Draw the render area.
398 if (!attached_) {
399 content::RenderWidgetHost* render_widget_host =
400 drag_data_->GetSourceWebContents()->GetRenderViewHost();
401
402 // This leaves room for the border.
403 gfx::Rect dest_rect(kDragFrameBorderSize, tab_height,
404 allocation.width - kTwiceDragFrameBorderSize,
405 allocation.height - tab_height -
406 kDragFrameBorderSize);
407 render_widget_host->CopyFromBackingStoreToGtkWindow(
408 dest_rect, GDK_DRAWABLE(gtk_widget_get_window(widget)));
409 }
410
411 cairo_t* cr = gdk_cairo_create(gtk_widget_get_window(widget));
412 // Draw the border.
413 if (!attached_) {
414 cairo_set_line_width(cr, kDragFrameBorderSize);
415 cairo_set_source_rgb(cr, kDraggedTabBorderColor[0],
416 kDraggedTabBorderColor[1],
417 kDraggedTabBorderColor[2]);
418 // |offset| is the distance from the edge of the image to the middle of
419 // the border line.
420 double offset = kDragFrameBorderSize / 2.0 - 0.5;
421 double left_x = offset;
422 double top_y = tab_height - kDragFrameBorderSize + offset;
423 double right_x = allocation.width - offset;
424 double bottom_y = allocation.height - offset;
425
426 cairo_move_to(cr, left_x, top_y);
427 cairo_line_to(cr, left_x, bottom_y);
428 cairo_line_to(cr, right_x, bottom_y);
429 cairo_line_to(cr, right_x, top_y);
430 cairo_line_to(cr, left_x, top_y);
431 cairo_stroke(cr);
432 }
433
434 // Draw the tab.
435 if (!attached_)
436 cairo_scale(cr, kScalingFactor, kScalingFactor);
437 // Painting all but the active tab first, from last to first.
438 for (int i = renderers_.size() - 1; i >= 0; i--) {
439 if (i == drag_data_->source_tab_index())
440 continue;
441 PaintTab(i, widget, cr, allocation.width);
442 }
443 // Painting the active tab last, so that it appears on top.
444 PaintTab(drag_data_->source_tab_index(), widget, cr,
445 allocation.width);
446
447 cairo_destroy(cr);
448
449 // We've already drawn the tab, so don't propagate the expose-event signal.
450 return TRUE;
451 }
452
453 void DraggedViewGtk::PaintTab(int index, GtkWidget* widget, cairo_t* cr,
454 int widget_width) {
455 renderers_[index]->set_mini(drag_data_->get(index)->mini_);
456 cairo_surface_t* surface = renderers_[index]->PaintToSurface(widget, cr);
457
458 int paint_at = 0;
459 if (!base::i18n::IsRTL()) {
460 paint_at = std::max(GetWidthInTabStripFromTo(0, index) - 16, 0);
461 } else {
462 paint_at = GetTotalWidthInTabStrip() -
463 GetWidthInTabStripFromTo(0, index + 1);
464 if (!attached_) {
465 paint_at = widget_width / kScalingFactor -
466 GetWidthInTabStripFromTo(0, index + 1);
467 }
468 }
469
470 cairo_set_source_surface(cr, surface, paint_at, 0);
471 cairo_paint(cr);
472 cairo_surface_destroy(surface);
473 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698