| OLD | NEW |
| (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 } | |
| OLD | NEW |