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

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

Issue 6251001: Move chrome/browser/gtk/ to chrome/browser/ui/gtk/... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 11 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
« no previous file with comments | « chrome/browser/gtk/gtk_util.h ('k') | chrome/browser/gtk/hover_controller_gtk.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/gtk/gtk_util.h"
6
7 #include <cairo/cairo.h>
8 #include <gtk/gtk.h>
9 #include <gdk/gdkx.h>
10
11 #include <cstdarg>
12 #include <map>
13
14 #include "app/l10n_util.h"
15 #include "app/resource_bundle.h"
16 #include "app/x11_util.h"
17 #include "base/environment.h"
18 #include "base/i18n/rtl.h"
19 #include "base/linux_util.h"
20 #include "base/logging.h"
21 #include "base/nix/xdg_util.h"
22 #include "base/string_number_conversions.h"
23 #include "base/utf_string_conversions.h"
24 #include "chrome/browser/autocomplete/autocomplete.h"
25 #include "chrome/browser/autocomplete/autocomplete_classifier.h"
26 #include "chrome/browser/autocomplete/autocomplete_match.h"
27 #include "chrome/browser/browser_list.h"
28 #include "chrome/browser/browser_window.h"
29 #include "chrome/browser/gtk/cairo_cached_surface.h"
30 #include "chrome/browser/gtk/gtk_theme_provider.h"
31 #include "chrome/browser/profiles/profile.h"
32 #include "chrome/browser/renderer_host/render_view_host.h"
33 #include "chrome/browser/tab_contents/tab_contents.h"
34 #include "chrome/common/renderer_preferences.h"
35 #include "gfx/gtk_util.h"
36 #include "googleurl/src/gurl.h"
37 #include "grit/theme_resources.h"
38 #include "third_party/skia/include/core/SkBitmap.h"
39 #include "third_party/skia/include/core/SkColor.h"
40
41 #if defined(OS_CHROMEOS)
42 #include "chrome/browser/chromeos/frame/browser_view.h"
43 #include "chrome/browser/chromeos/native_dialog_window.h"
44 #include "chrome/browser/chromeos/options/options_window_view.h"
45 #include "views/window/window.h"
46 #else
47 #include "chrome/browser/gtk/browser_window_gtk.h"
48 #endif
49
50 using WebKit::WebDragOperationsMask;
51 using WebKit::WebDragOperation;
52 using WebKit::WebDragOperationNone;
53 using WebKit::WebDragOperationCopy;
54 using WebKit::WebDragOperationLink;
55 using WebKit::WebDragOperationMove;
56
57 namespace {
58
59 const char kBoldLabelMarkup[] = "<span weight='bold'>%s</span>";
60
61 // Callback used in RemoveAllChildren.
62 void RemoveWidget(GtkWidget* widget, gpointer container) {
63 gtk_container_remove(GTK_CONTAINER(container), widget);
64 }
65
66 // These two functions are copped almost directly from gtk core. The only
67 // difference is that they accept middle clicks.
68 gboolean OnMouseButtonPressed(GtkWidget* widget, GdkEventButton* event,
69 gpointer userdata) {
70 if (event->type == GDK_BUTTON_PRESS) {
71 if (gtk_button_get_focus_on_click(GTK_BUTTON(widget)) &&
72 !GTK_WIDGET_HAS_FOCUS(widget)) {
73 gtk_widget_grab_focus(widget);
74 }
75
76 gint button_mask = GPOINTER_TO_INT(userdata);
77 if (button_mask & (1 << event->button))
78 gtk_button_pressed(GTK_BUTTON(widget));
79 }
80
81 return TRUE;
82 }
83
84 gboolean OnMouseButtonReleased(GtkWidget* widget, GdkEventButton* event,
85 gpointer userdata) {
86 gint button_mask = GPOINTER_TO_INT(userdata);
87 if (button_mask && (1 << event->button))
88 gtk_button_released(GTK_BUTTON(widget));
89
90 return TRUE;
91 }
92
93 // Returns the approximate number of characters that can horizontally fit in
94 // |pixel_width| pixels.
95 int GetCharacterWidthForPixels(GtkWidget* widget, int pixel_width) {
96 DCHECK(GTK_WIDGET_REALIZED(widget))
97 << " widget must be realized to compute font metrics correctly";
98
99 PangoContext* context = gtk_widget_create_pango_context(widget);
100 PangoFontMetrics* metrics = pango_context_get_metrics(context,
101 widget->style->font_desc, pango_context_get_language(context));
102
103 // This technique (max of char and digit widths) matches the code in
104 // gtklabel.c.
105 int char_width = pixel_width * PANGO_SCALE /
106 std::max(pango_font_metrics_get_approximate_char_width(metrics),
107 pango_font_metrics_get_approximate_digit_width(metrics));
108
109 pango_font_metrics_unref(metrics);
110 g_object_unref(context);
111
112 return char_width;
113 }
114
115 void OnLabelRealize(GtkWidget* label, gpointer pixel_width) {
116 gtk_label_set_width_chars(
117 GTK_LABEL(label),
118 GetCharacterWidthForPixels(label,GPOINTER_TO_INT(pixel_width)));
119 }
120
121 // Ownership of |icon_list| is passed to the caller.
122 GList* GetIconList() {
123 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
124 GList* icon_list = NULL;
125 icon_list = g_list_append(icon_list, rb.GetPixbufNamed(IDR_PRODUCT_ICON_32));
126 icon_list = g_list_append(icon_list, rb.GetPixbufNamed(IDR_PRODUCT_LOGO_16));
127 return icon_list;
128 }
129
130 // Expose event handler for a container that simply suppresses the default
131 // drawing and propagates the expose event to the container's children.
132 gboolean PaintNoBackground(GtkWidget* widget,
133 GdkEventExpose* event,
134 gpointer unused) {
135 GList* children = gtk_container_get_children(GTK_CONTAINER(widget));
136 for (GList* item = children; item; item = item->next) {
137 gtk_container_propagate_expose(GTK_CONTAINER(widget),
138 GTK_WIDGET(item->data),
139 event);
140 }
141 g_list_free(children);
142
143 return TRUE;
144 }
145
146 #if defined(OS_CHROMEOS)
147
148 TabContents* GetBrowserWindowSelectedTabContents(BrowserWindow* window) {
149 chromeos::BrowserView* browser_view = static_cast<chromeos::BrowserView*>(
150 window);
151 return browser_view->GetSelectedTabContents();
152 }
153
154 GtkWidget* GetBrowserWindowFocusedWidget(BrowserWindow* window) {
155 gfx::NativeView widget = gtk_window_get_focus(window->GetNativeHandle());
156
157 if (widget == NULL) {
158 chromeos::BrowserView* browser_view = static_cast<chromeos::BrowserView*>(
159 window);
160 widget = browser_view->saved_focused_widget();
161 }
162
163 return widget;
164 }
165
166 #else
167
168 TabContents* GetBrowserWindowSelectedTabContents(BrowserWindow* window) {
169 BrowserWindowGtk* browser_window = static_cast<BrowserWindowGtk*>(
170 window);
171 return browser_window->browser()->GetSelectedTabContents();
172 }
173
174 GtkWidget* GetBrowserWindowFocusedWidget(BrowserWindow* window) {
175 return gtk_window_get_focus(window->GetNativeHandle());
176 }
177
178 #endif
179
180 } // namespace
181
182 namespace event_utils {
183
184 WindowOpenDisposition DispositionFromEventFlags(guint event_flags) {
185 if ((event_flags & GDK_BUTTON2_MASK) || (event_flags & GDK_CONTROL_MASK)) {
186 return (event_flags & GDK_SHIFT_MASK) ?
187 NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
188 }
189
190 if (event_flags & GDK_SHIFT_MASK)
191 return NEW_WINDOW;
192 return false /*event.IsAltDown()*/ ? SAVE_TO_DISK : CURRENT_TAB;
193 }
194
195 } // namespace event_utils
196
197 namespace gtk_util {
198
199 const GdkColor kGdkWhite = GDK_COLOR_RGB(0xff, 0xff, 0xff);
200 const GdkColor kGdkGray = GDK_COLOR_RGB(0x7f, 0x7f, 0x7f);
201 const GdkColor kGdkBlack = GDK_COLOR_RGB(0x00, 0x00, 0x00);
202 const GdkColor kGdkGreen = GDK_COLOR_RGB(0x00, 0xff, 0x00);
203
204 GtkWidget* CreateLabeledControlsGroup(std::vector<GtkWidget*>* labels,
205 const char* text, ...) {
206 va_list ap;
207 va_start(ap, text);
208 GtkWidget* table = gtk_table_new(0, 2, FALSE);
209 gtk_table_set_col_spacing(GTK_TABLE(table), 0, kLabelSpacing);
210 gtk_table_set_row_spacings(GTK_TABLE(table), kControlSpacing);
211
212 for (guint row = 0; text; ++row) {
213 gtk_table_resize(GTK_TABLE(table), row + 1, 2);
214 GtkWidget* control = va_arg(ap, GtkWidget*);
215 GtkWidget* label = gtk_label_new(text);
216 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
217 if (labels)
218 labels->push_back(label);
219
220 gtk_table_attach(GTK_TABLE(table), label,
221 0, 1, row, row + 1,
222 GTK_FILL, GTK_FILL,
223 0, 0);
224 gtk_table_attach_defaults(GTK_TABLE(table), control,
225 1, 2, row, row + 1);
226 text = va_arg(ap, const char*);
227 }
228 va_end(ap);
229
230 return table;
231 }
232
233 GtkWidget* CreateGtkBorderBin(GtkWidget* child, const GdkColor* color,
234 int top, int bottom, int left, int right) {
235 // Use a GtkEventBox to get the background painted. However, we can't just
236 // use a container border, since it won't paint there. Use an alignment
237 // inside to get the sizes exactly of how we want the border painted.
238 GtkWidget* ebox = gtk_event_box_new();
239 if (color)
240 gtk_widget_modify_bg(ebox, GTK_STATE_NORMAL, color);
241 GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
242 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), top, bottom, left, right);
243 gtk_container_add(GTK_CONTAINER(alignment), child);
244 gtk_container_add(GTK_CONTAINER(ebox), alignment);
245 return ebox;
246 }
247
248 GtkWidget* LeftAlignMisc(GtkWidget* misc) {
249 gtk_misc_set_alignment(GTK_MISC(misc), 0, 0.5);
250 return misc;
251 }
252
253 GtkWidget* CreateBoldLabel(const std::string& text) {
254 GtkWidget* label = gtk_label_new(NULL);
255 char* markup = g_markup_printf_escaped(kBoldLabelMarkup, text.c_str());
256 gtk_label_set_markup(GTK_LABEL(label), markup);
257 g_free(markup);
258
259 return LeftAlignMisc(label);
260 }
261
262 void GetWidgetSizeFromCharacters(
263 GtkWidget* widget, double width_chars, double height_lines,
264 int* width, int* height) {
265 DCHECK(GTK_WIDGET_REALIZED(widget))
266 << " widget must be realized to compute font metrics correctly";
267 PangoContext* context = gtk_widget_create_pango_context(widget);
268 PangoFontMetrics* metrics = pango_context_get_metrics(context,
269 widget->style->font_desc, pango_context_get_language(context));
270 if (width) {
271 *width = static_cast<int>(
272 pango_font_metrics_get_approximate_char_width(metrics) *
273 width_chars / PANGO_SCALE);
274 }
275 if (height) {
276 *height = static_cast<int>(
277 (pango_font_metrics_get_ascent(metrics) +
278 pango_font_metrics_get_descent(metrics)) *
279 height_lines / PANGO_SCALE);
280 }
281 pango_font_metrics_unref(metrics);
282 g_object_unref(context);
283 }
284
285 void GetWidgetSizeFromResources(
286 GtkWidget* widget, int width_chars, int height_lines,
287 int* width, int* height) {
288 DCHECK(GTK_WIDGET_REALIZED(widget))
289 << " widget must be realized to compute font metrics correctly";
290
291 double chars = 0;
292 if (width)
293 base::StringToDouble(l10n_util::GetStringUTF8(width_chars), &chars);
294
295 double lines = 0;
296 if (height)
297 base::StringToDouble(l10n_util::GetStringUTF8(height_lines), &lines);
298
299 GetWidgetSizeFromCharacters(widget, chars, lines, width, height);
300 }
301
302 void SetWindowSizeFromResources(GtkWindow* window,
303 int width_id, int height_id, bool resizable) {
304 int width = -1;
305 int height = -1;
306 gtk_util::GetWidgetSizeFromResources(GTK_WIDGET(window), width_id, height_id,
307 (width_id != -1) ? &width : NULL,
308 (height_id != -1) ? &height : NULL);
309
310 if (resizable) {
311 gtk_window_set_default_size(window, width, height);
312 } else {
313 // For a non-resizable window, GTK tries to snap the window size
314 // to the minimum size around the content. We use the sizes in
315 // the resources to set *minimum* window size to allow windows
316 // with long titles to be wide enough to display their titles.
317 //
318 // But if GTK wants to make the window *wider* due to very wide
319 // controls, we should allow that too, so be careful to pick the
320 // wider of the resources size and the natural window size.
321
322 gtk_widget_show_all(GTK_BIN(window)->child);
323 GtkRequisition requisition;
324 gtk_widget_size_request(GTK_WIDGET(window), &requisition);
325 gtk_widget_set_size_request(
326 GTK_WIDGET(window),
327 width == -1 ? -1 : std::max(width, requisition.width),
328 height == -1 ? -1 : std::max(height, requisition.height));
329 }
330 gtk_window_set_resizable(window, resizable ? TRUE : FALSE);
331 }
332
333 void CenterOverWindow(GtkWindow* window, GtkWindow* parent) {
334 gfx::Rect frame_bounds = gtk_util::GetWidgetScreenBounds(GTK_WIDGET(parent));
335 gfx::Point origin = frame_bounds.origin();
336 gfx::Size size = gtk_util::GetWidgetSize(GTK_WIDGET(window));
337 origin.Offset(
338 (frame_bounds.width() - size.width()) / 2,
339 (frame_bounds.height() - size.height()) / 2);
340
341 // Prevent moving window out of monitor bounds.
342 GdkScreen* screen = gtk_window_get_screen(parent);
343 if (screen) {
344 // It would be better to check against workarea for given monitor
345 // but getting workarea for particular monitor is tricky.
346 gint monitor = gdk_screen_get_monitor_at_window(screen,
347 GTK_WIDGET(parent)->window);
348 GdkRectangle rect;
349 gdk_screen_get_monitor_geometry(screen, monitor, &rect);
350
351 // Check the right bottom corner.
352 if (origin.x() > rect.x + rect.width - size.width())
353 origin.set_x(rect.x + rect.width - size.width());
354 if (origin.y() > rect.y + rect.height - size.height())
355 origin.set_y(rect.y + rect.height - size.height());
356
357 // Check the left top corner.
358 if (origin.x() < rect.x)
359 origin.set_x(rect.x);
360 if (origin.y() < rect.y)
361 origin.set_y(rect.y);
362 }
363
364 gtk_window_move(window, origin.x(), origin.y());
365
366 // Move to user expected desktop if window is already visible.
367 if (GTK_WIDGET(window)->window) {
368 x11_util::ChangeWindowDesktop(
369 x11_util::GetX11WindowFromGtkWidget(GTK_WIDGET(window)),
370 x11_util::GetX11WindowFromGtkWidget(GTK_WIDGET(parent)));
371 }
372 }
373
374 void MakeAppModalWindowGroup() {
375 #if GTK_CHECK_VERSION(2, 14, 0)
376 // Older versions of GTK+ don't give us gtk_window_group_list() which is what
377 // we need to add current non-browser modal dialogs to the list. If
378 // we have 2.14+ we can do things the correct way.
379 GtkWindowGroup* window_group = gtk_window_group_new();
380 for (BrowserList::const_iterator it = BrowserList::begin();
381 it != BrowserList::end(); ++it) {
382 // List all windows in this current group
383 GtkWindowGroup* old_group =
384 gtk_window_get_group((*it)->window()->GetNativeHandle());
385
386 GList* all_windows = gtk_window_group_list_windows(old_group);
387 for (GList* window = all_windows; window; window = window->next) {
388 gtk_window_group_add_window(window_group, GTK_WINDOW(window->data));
389 }
390 g_list_free(all_windows);
391 }
392 g_object_unref(window_group);
393 #else
394 // Otherwise just grab all browser windows and be slightly broken.
395 GtkWindowGroup* window_group = gtk_window_group_new();
396 for (BrowserList::const_iterator it = BrowserList::begin();
397 it != BrowserList::end(); ++it) {
398 gtk_window_group_add_window(window_group,
399 (*it)->window()->GetNativeHandle());
400 }
401 g_object_unref(window_group);
402 #endif
403 }
404
405 void AppModalDismissedUngroupWindows() {
406 #if GTK_CHECK_VERSION(2, 14, 0)
407 if (BrowserList::begin() != BrowserList::end()) {
408 std::vector<GtkWindow*> transient_windows;
409
410 // All windows should be part of one big modal group right now.
411 GtkWindowGroup* window_group = gtk_window_get_group(
412 (*BrowserList::begin())->window()->GetNativeHandle());
413 GList* windows = gtk_window_group_list_windows(window_group);
414
415 for (GList* item = windows; item; item = item->next) {
416 GtkWindow* window = GTK_WINDOW(item->data);
417 GtkWindow* transient_for = gtk_window_get_transient_for(window);
418 if (transient_for) {
419 transient_windows.push_back(window);
420 } else {
421 GtkWindowGroup* window_group = gtk_window_group_new();
422 gtk_window_group_add_window(window_group, window);
423 g_object_unref(window_group);
424 }
425 }
426
427 // Put each transient window in the same group as its transient parent.
428 for (std::vector<GtkWindow*>::iterator it = transient_windows.begin();
429 it != transient_windows.end(); ++it) {
430 GtkWindow* transient_parent = gtk_window_get_transient_for(*it);
431 GtkWindowGroup* group = gtk_window_get_group(transient_parent);
432 gtk_window_group_add_window(group, *it);
433 }
434 }
435 #else
436 // This is slightly broken in the case where a different window had a dialog,
437 // but its the best we can do since we don't have newer gtk stuff.
438 for (BrowserList::const_iterator it = BrowserList::begin();
439 it != BrowserList::end(); ++it) {
440 GtkWindowGroup* window_group = gtk_window_group_new();
441 gtk_window_group_add_window(window_group,
442 (*it)->window()->GetNativeHandle());
443 g_object_unref(window_group);
444 }
445 #endif
446 }
447
448 void RemoveAllChildren(GtkWidget* container) {
449 gtk_container_foreach(GTK_CONTAINER(container), RemoveWidget, container);
450 }
451
452 void ForceFontSizePixels(GtkWidget* widget, double size_pixels) {
453 GtkStyle* style = widget->style;
454 PangoFontDescription* font_desc = style->font_desc;
455 // pango_font_description_set_absolute_size sets the font size in device
456 // units, which for us is pixels.
457 pango_font_description_set_absolute_size(font_desc,
458 PANGO_SCALE * size_pixels);
459 gtk_widget_modify_font(widget, font_desc);
460 }
461
462 void UndoForceFontSize(GtkWidget* widget) {
463 gtk_widget_modify_font(widget, NULL);
464 }
465
466 gfx::Point GetWidgetScreenPosition(GtkWidget* widget) {
467 if (!widget->window) {
468 NOTREACHED() << "Must only be called on realized widgets.";
469 return gfx::Point(0, 0);
470 }
471
472 gint x, y;
473 gdk_window_get_origin(widget->window, &x, &y);
474
475 if (!GTK_IS_WINDOW(widget)) {
476 x += widget->allocation.x;
477 y += widget->allocation.y;
478 }
479
480 return gfx::Point(x, y);
481 }
482
483 gfx::Rect GetWidgetScreenBounds(GtkWidget* widget) {
484 gfx::Point position = GetWidgetScreenPosition(widget);
485 return gfx::Rect(position.x(), position.y(),
486 widget->allocation.width, widget->allocation.height);
487 }
488
489 gfx::Size GetWidgetSize(GtkWidget* widget) {
490 GtkRequisition size;
491 gtk_widget_size_request(widget, &size);
492 return gfx::Size(size.width, size.height);
493 }
494
495 void ConvertWidgetPointToScreen(GtkWidget* widget, gfx::Point* p) {
496 DCHECK(widget);
497 DCHECK(p);
498
499 gfx::Point position = GetWidgetScreenPosition(widget);
500 p->SetPoint(p->x() + position.x(), p->y() + position.y());
501 }
502
503 void InitRCStyles() {
504 static const char kRCText[] =
505 // Make our dialogs styled like the GNOME HIG.
506 //
507 // TODO(evanm): content-area-spacing was introduced in a later
508 // version of GTK, so we need to set that manually on all dialogs.
509 // Perhaps it would make sense to have a shared FixupDialog() function.
510 "style \"gnome-dialog\" {\n"
511 " xthickness = 12\n"
512 " GtkDialog::action-area-border = 0\n"
513 " GtkDialog::button-spacing = 6\n"
514 " GtkDialog::content-area-spacing = 18\n"
515 " GtkDialog::content-area-border = 12\n"
516 "}\n"
517 // Note we set it at the "application" priority, so users can override.
518 "widget \"GtkDialog\" style : application \"gnome-dialog\"\n"
519
520 // Make our about dialog special, so the image is flush with the edge.
521 "style \"about-dialog\" {\n"
522 " GtkDialog::action-area-border = 12\n"
523 " GtkDialog::button-spacing = 6\n"
524 " GtkDialog::content-area-spacing = 18\n"
525 " GtkDialog::content-area-border = 0\n"
526 "}\n"
527 "widget \"about-dialog\" style : application \"about-dialog\"\n";
528
529 gtk_rc_parse_string(kRCText);
530 }
531
532 GtkWidget* CenterWidgetInHBox(GtkWidget* hbox, GtkWidget* widget,
533 bool pack_at_end, int padding) {
534 GtkWidget* centering_vbox = gtk_vbox_new(FALSE, 0);
535 gtk_box_pack_start(GTK_BOX(centering_vbox), widget, TRUE, FALSE, 0);
536 if (pack_at_end)
537 gtk_box_pack_end(GTK_BOX(hbox), centering_vbox, FALSE, FALSE, padding);
538 else
539 gtk_box_pack_start(GTK_BOX(hbox), centering_vbox, FALSE, FALSE, padding);
540
541 return centering_vbox;
542 }
543
544 bool IsScreenComposited() {
545 GdkScreen* screen = gdk_screen_get_default();
546 return gdk_screen_is_composited(screen) == TRUE;
547 }
548
549 void EnumerateTopLevelWindows(x11_util::EnumerateWindowsDelegate* delegate) {
550 std::vector<XID> stack;
551 if (!x11_util::GetXWindowStack(&stack)) {
552 // Window Manager doesn't support _NET_CLIENT_LIST_STACKING, so fall back
553 // to old school enumeration of all X windows. Some WMs parent 'top-level'
554 // windows in unnamed actual top-level windows (ion WM), so extend the
555 // search depth to all children of top-level windows.
556 const int kMaxSearchDepth = 1;
557 x11_util::EnumerateAllWindows(delegate, kMaxSearchDepth);
558 return;
559 }
560
561 std::vector<XID>::iterator iter;
562 for (iter = stack.begin(); iter != stack.end(); iter++) {
563 if (delegate->ShouldStopIterating(*iter))
564 return;
565 }
566 }
567
568 void SetButtonClickableByMouseButtons(GtkWidget* button,
569 bool left, bool middle, bool right) {
570 gint button_mask = 0;
571 if (left)
572 button_mask |= 1 << 1;
573 if (middle)
574 button_mask |= 1 << 2;
575 if (right)
576 button_mask |= 1 << 3;
577 void* userdata = GINT_TO_POINTER(button_mask);
578
579 g_signal_connect(button, "button-press-event",
580 G_CALLBACK(OnMouseButtonPressed), userdata);
581 g_signal_connect(button, "button-release-event",
582 G_CALLBACK(OnMouseButtonReleased), userdata);
583 }
584
585 void SetButtonTriggersNavigation(GtkWidget* button) {
586 SetButtonClickableByMouseButtons(button, true, true, false);
587 }
588
589 int MirroredLeftPointForRect(GtkWidget* widget, const gfx::Rect& bounds) {
590 if (!base::i18n::IsRTL())
591 return bounds.x();
592 return widget->allocation.width - bounds.x() - bounds.width();
593 }
594
595 int MirroredXCoordinate(GtkWidget* widget, int x) {
596 if (base::i18n::IsRTL())
597 return widget->allocation.width - x;
598 return x;
599 }
600
601 bool WidgetContainsCursor(GtkWidget* widget) {
602 gint x = 0;
603 gint y = 0;
604 gtk_widget_get_pointer(widget, &x, &y);
605 return WidgetBounds(widget).Contains(x, y);
606 }
607
608 void SetWindowIcon(GtkWindow* window) {
609 GList* icon_list = GetIconList();
610 gtk_window_set_icon_list(window, icon_list);
611 g_list_free(icon_list);
612 }
613
614 void SetDefaultWindowIcon() {
615 GList* icon_list = GetIconList();
616 gtk_window_set_default_icon_list(icon_list);
617 g_list_free(icon_list);
618 }
619
620 GtkWidget* AddButtonToDialog(GtkWidget* dialog, const gchar* text,
621 const gchar* stock_id, gint response_id) {
622 GtkWidget* button = gtk_button_new_with_label(text);
623 gtk_button_set_image(GTK_BUTTON(button),
624 gtk_image_new_from_stock(stock_id,
625 GTK_ICON_SIZE_BUTTON));
626 gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button,
627 response_id);
628 return button;
629 }
630
631 GtkWidget* BuildDialogButton(GtkWidget* dialog, int ids_id,
632 const gchar* stock_id) {
633 GtkWidget* button = gtk_button_new_with_mnemonic(
634 gfx::ConvertAcceleratorsFromWindowsStyle(
635 l10n_util::GetStringUTF8(ids_id)).c_str());
636 gtk_button_set_image(GTK_BUTTON(button),
637 gtk_image_new_from_stock(stock_id,
638 GTK_ICON_SIZE_BUTTON));
639 return button;
640 }
641
642 GtkWidget* CreateEntryImageHBox(GtkWidget* entry, GtkWidget* image) {
643 GtkWidget* hbox = gtk_hbox_new(FALSE, gtk_util::kControlSpacing);
644 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
645 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
646 return hbox;
647 }
648
649 void SetLabelColor(GtkWidget* label, const GdkColor* color) {
650 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, color);
651 gtk_widget_modify_fg(label, GTK_STATE_ACTIVE, color);
652 gtk_widget_modify_fg(label, GTK_STATE_PRELIGHT, color);
653 gtk_widget_modify_fg(label, GTK_STATE_INSENSITIVE, color);
654 }
655
656 GtkWidget* IndentWidget(GtkWidget* content) {
657 GtkWidget* content_alignment = gtk_alignment_new(0.0, 0.5, 1.0, 1.0);
658 gtk_alignment_set_padding(GTK_ALIGNMENT(content_alignment), 0, 0,
659 gtk_util::kGroupIndent, 0);
660 gtk_container_add(GTK_CONTAINER(content_alignment), content);
661 return content_alignment;
662 }
663
664 void UpdateGtkFontSettings(RendererPreferences* prefs) {
665 DCHECK(prefs);
666
667 // From http://library.gnome.org/devel/gtk/unstable/GtkSettings.html, this is
668 // the default value for gtk-cursor-blink-time.
669 static const gint kGtkDefaultCursorBlinkTime = 1200;
670
671 gint cursor_blink_time = kGtkDefaultCursorBlinkTime;
672 gboolean cursor_blink = TRUE;
673 gint antialias = 0;
674 gint hinting = 0;
675 gchar* hint_style = NULL;
676 gchar* rgba_style = NULL;
677 g_object_get(gtk_settings_get_default(),
678 "gtk-cursor-blink-time", &cursor_blink_time,
679 "gtk-cursor-blink", &cursor_blink,
680 "gtk-xft-antialias", &antialias,
681 "gtk-xft-hinting", &hinting,
682 "gtk-xft-hintstyle", &hint_style,
683 "gtk-xft-rgba", &rgba_style,
684 NULL);
685
686 // Set some reasonable defaults.
687 prefs->should_antialias_text = true;
688 prefs->hinting = RENDERER_PREFERENCES_HINTING_SYSTEM_DEFAULT;
689 prefs->subpixel_rendering =
690 RENDERER_PREFERENCES_SUBPIXEL_RENDERING_SYSTEM_DEFAULT;
691
692 if (cursor_blink) {
693 // Dividing by 2*1000ms follows the WebKit GTK port and makes the blink
694 // frequency appear similar to the omnibox. Without this the blink is too
695 // slow.
696 prefs->caret_blink_interval = cursor_blink_time / 2000.;
697 } else {
698 prefs->caret_blink_interval = 0;
699 }
700
701 // g_object_get() doesn't tell us whether the properties were present or not,
702 // but if they aren't (because gnome-settings-daemon isn't running), we'll get
703 // NULL values for the strings.
704 if (hint_style && rgba_style) {
705 prefs->should_antialias_text = antialias;
706
707 if (hinting == 0 || strcmp(hint_style, "hintnone") == 0) {
708 prefs->hinting = RENDERER_PREFERENCES_HINTING_NONE;
709 } else if (strcmp(hint_style, "hintslight") == 0) {
710 prefs->hinting = RENDERER_PREFERENCES_HINTING_SLIGHT;
711 } else if (strcmp(hint_style, "hintmedium") == 0) {
712 prefs->hinting = RENDERER_PREFERENCES_HINTING_MEDIUM;
713 } else if (strcmp(hint_style, "hintfull") == 0) {
714 prefs->hinting = RENDERER_PREFERENCES_HINTING_FULL;
715 }
716
717 if (strcmp(rgba_style, "none") == 0) {
718 prefs->subpixel_rendering = RENDERER_PREFERENCES_SUBPIXEL_RENDERING_NONE;
719 } else if (strcmp(rgba_style, "rgb") == 0) {
720 prefs->subpixel_rendering = RENDERER_PREFERENCES_SUBPIXEL_RENDERING_RGB;
721 } else if (strcmp(rgba_style, "bgr") == 0) {
722 prefs->subpixel_rendering = RENDERER_PREFERENCES_SUBPIXEL_RENDERING_BGR;
723 } else if (strcmp(rgba_style, "vrgb") == 0) {
724 prefs->subpixel_rendering = RENDERER_PREFERENCES_SUBPIXEL_RENDERING_VRGB;
725 } else if (strcmp(rgba_style, "vbgr") == 0) {
726 prefs->subpixel_rendering = RENDERER_PREFERENCES_SUBPIXEL_RENDERING_VBGR;
727 }
728 }
729
730 if (hint_style)
731 g_free(hint_style);
732 if (rgba_style)
733 g_free(rgba_style);
734 }
735
736 gfx::Point ScreenPoint(GtkWidget* widget) {
737 int x, y;
738 gdk_display_get_pointer(gtk_widget_get_display(widget), NULL, &x, &y,
739 NULL);
740 return gfx::Point(x, y);
741 }
742
743 gfx::Point ClientPoint(GtkWidget* widget) {
744 int x, y;
745 gtk_widget_get_pointer(widget, &x, &y);
746 return gfx::Point(x, y);
747 }
748
749 GdkPoint MakeBidiGdkPoint(gint x, gint y, gint width, bool ltr) {
750 GdkPoint point = {ltr ? x : width - x, y};
751 return point;
752 }
753
754 void DrawTextEntryBackground(GtkWidget* offscreen_entry,
755 GtkWidget* widget_to_draw_on,
756 GdkRectangle* dirty_rec,
757 GdkRectangle* rec) {
758 GtkStyle* gtk_owned_style = gtk_rc_get_style(offscreen_entry);
759 // GTK owns the above and we're going to have to make our own copy of it
760 // that we can edit.
761 GtkStyle* our_style = gtk_style_copy(gtk_owned_style);
762 our_style = gtk_style_attach(our_style, widget_to_draw_on->window);
763
764 // TODO(erg): Draw the focus ring if appropriate...
765
766 // We're using GTK rendering; draw a GTK entry widget onto the background.
767 gtk_paint_shadow(our_style, widget_to_draw_on->window,
768 GTK_STATE_NORMAL, GTK_SHADOW_IN, dirty_rec,
769 widget_to_draw_on, "entry",
770 rec->x, rec->y, rec->width, rec->height);
771
772 // Draw the interior background (not all themes draw the entry background
773 // above; this is a noop on themes that do).
774 gint xborder = our_style->xthickness;
775 gint yborder = our_style->ythickness;
776 gint width = rec->width - 2 * xborder;
777 gint height = rec->height - 2 * yborder;
778 if (width > 0 && height > 0) {
779 gtk_paint_flat_box(our_style, widget_to_draw_on->window,
780 GTK_STATE_NORMAL, GTK_SHADOW_NONE, dirty_rec,
781 widget_to_draw_on, "entry_bg",
782 rec->x + xborder, rec->y + yborder,
783 width, height);
784 }
785
786 gtk_style_detach(our_style);
787 g_object_unref(our_style);
788 }
789
790 void DrawThemedToolbarBackground(GtkWidget* widget,
791 cairo_t* cr,
792 GdkEventExpose* event,
793 const gfx::Point& tabstrip_origin,
794 GtkThemeProvider* theme_provider) {
795 // Fill the entire region with the toolbar color.
796 GdkColor color = theme_provider->GetGdkColor(
797 BrowserThemeProvider::COLOR_TOOLBAR);
798 gdk_cairo_set_source_color(cr, &color);
799 cairo_fill(cr);
800
801 // The toolbar is supposed to blend in with the active tab, so we have to pass
802 // coordinates for the IDR_THEME_TOOLBAR bitmap relative to the top of the
803 // tab strip.
804 CairoCachedSurface* background = theme_provider->GetSurfaceNamed(
805 IDR_THEME_TOOLBAR, widget);
806 background->SetSource(cr, tabstrip_origin.x(), tabstrip_origin.y());
807 // We tile the toolbar background in both directions.
808 cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
809 cairo_rectangle(cr,
810 tabstrip_origin.x(),
811 tabstrip_origin.y(),
812 event->area.x + event->area.width - tabstrip_origin.x(),
813 event->area.y + event->area.height - tabstrip_origin.y());
814 cairo_fill(cr);
815 }
816
817 GdkColor AverageColors(GdkColor color_one, GdkColor color_two) {
818 GdkColor average_color;
819 average_color.pixel = 0;
820 average_color.red = (color_one.red + color_two.red) / 2;
821 average_color.green = (color_one.green + color_two.green) / 2;
822 average_color.blue = (color_one.blue + color_two.blue) / 2;
823 return average_color;
824 }
825
826 void SetAlwaysShowImage(GtkWidget* image_menu_item) {
827 // Compile time check: if it's available, just use the API.
828 // GTK_CHECK_VERSION is TRUE if the passed version is compatible.
829 #if GTK_CHECK_VERSION(2, 16, 1)
830 gtk_image_menu_item_set_always_show_image(
831 GTK_IMAGE_MENU_ITEM(image_menu_item), TRUE);
832 #else
833 // Run time check: if the API is not available, set the property manually.
834 // This will still only work with GTK 2.16+ as the property doesn't exist
835 // in earlier versions.
836 // gtk_check_version() returns NULL if the passed version is compatible.
837 if (!gtk_check_version(2, 16, 1)) {
838 GValue true_value = { 0 };
839 g_value_init(&true_value, G_TYPE_BOOLEAN);
840 g_value_set_boolean(&true_value, TRUE);
841 g_object_set_property(G_OBJECT(image_menu_item), "always-show-image",
842 &true_value);
843 }
844 #endif
845 }
846
847 void StackPopupWindow(GtkWidget* popup, GtkWidget* toplevel) {
848 DCHECK(GTK_IS_WINDOW(popup) && GTK_WIDGET_TOPLEVEL(popup) &&
849 GTK_WIDGET_REALIZED(popup));
850 DCHECK(GTK_IS_WINDOW(toplevel) && GTK_WIDGET_TOPLEVEL(toplevel) &&
851 GTK_WIDGET_REALIZED(toplevel));
852
853 // Stack the |popup| window directly above the |toplevel| window.
854 // The popup window is a direct child of the root window, so we need to
855 // find a similar ancestor for the toplevel window (which might have been
856 // reparented by a window manager). We grab the server while we're doing
857 // this -- otherwise, we'll get an error if the window manager reparents the
858 // toplevel window right after we call GetHighestAncestorWindow().
859 gdk_x11_display_grab(gtk_widget_get_display(toplevel));
860 XID toplevel_window_base = x11_util::GetHighestAncestorWindow(
861 x11_util::GetX11WindowFromGtkWidget(toplevel),
862 x11_util::GetX11RootWindow());
863 if (toplevel_window_base) {
864 XID window_xid = x11_util::GetX11WindowFromGtkWidget(popup);
865 XID window_parent = x11_util::GetParentWindow(window_xid);
866 if (window_parent == x11_util::GetX11RootWindow()) {
867 x11_util::RestackWindow(window_xid, toplevel_window_base, true);
868 } else {
869 // The window manager shouldn't reparent override-redirect windows.
870 DLOG(ERROR) << "override-redirect window " << window_xid
871 << "'s parent is " << window_parent
872 << ", rather than root window "
873 << x11_util::GetX11RootWindow();
874 }
875 }
876 gdk_x11_display_ungrab(gtk_widget_get_display(toplevel));
877 }
878
879 gfx::Rect GetWidgetRectRelativeToToplevel(GtkWidget* widget) {
880 DCHECK(GTK_WIDGET_REALIZED(widget));
881
882 GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
883 DCHECK(toplevel);
884 DCHECK(GTK_WIDGET_REALIZED(toplevel));
885
886 gint x = 0, y = 0;
887 gtk_widget_translate_coordinates(widget,
888 toplevel,
889 0, 0,
890 &x, &y);
891 return gfx::Rect(x, y, widget->allocation.width, widget->allocation.height);
892 }
893
894 void SuppressDefaultPainting(GtkWidget* container) {
895 g_signal_connect(container, "expose-event",
896 G_CALLBACK(PaintNoBackground), NULL);
897 }
898
899 WindowOpenDisposition DispositionForCurrentButtonPressEvent() {
900 GdkEvent* event = gtk_get_current_event();
901 if (!event) {
902 NOTREACHED();
903 return NEW_FOREGROUND_TAB;
904 }
905
906 guint state = event->button.state;
907 gdk_event_free(event);
908 return event_utils::DispositionFromEventFlags(state);
909 }
910
911 bool GrabAllInput(GtkWidget* widget) {
912 guint time = gtk_get_current_event_time();
913
914 if (!GTK_WIDGET_VISIBLE(widget))
915 return false;
916
917 if (!gdk_pointer_grab(widget->window, TRUE,
918 GdkEventMask(GDK_BUTTON_PRESS_MASK |
919 GDK_BUTTON_RELEASE_MASK |
920 GDK_ENTER_NOTIFY_MASK |
921 GDK_LEAVE_NOTIFY_MASK |
922 GDK_POINTER_MOTION_MASK),
923 NULL, NULL, time) == 0) {
924 return false;
925 }
926
927 if (!gdk_keyboard_grab(widget->window, TRUE, time) == 0) {
928 gdk_display_pointer_ungrab(gdk_drawable_get_display(widget->window), time);
929 return false;
930 }
931
932 gtk_grab_add(widget);
933 return true;
934 }
935
936 gfx::Rect WidgetBounds(GtkWidget* widget) {
937 // To quote the gtk docs:
938 //
939 // Widget coordinates are a bit odd; for historical reasons, they are
940 // defined as widget->window coordinates for widgets that are not
941 // GTK_NO_WINDOW widgets, and are relative to widget->allocation.x,
942 // widget->allocation.y for widgets that are GTK_NO_WINDOW widgets.
943 //
944 // So the base is always (0,0).
945 return gfx::Rect(0, 0, widget->allocation.width, widget->allocation.height);
946 }
947
948 void SetWMLastUserActionTime(GtkWindow* window) {
949 gdk_x11_window_set_user_time(GTK_WIDGET(window)->window, XTimeNow());
950 }
951
952 guint32 XTimeNow() {
953 struct timespec ts;
954 clock_gettime(CLOCK_MONOTONIC, &ts);
955 return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
956 }
957
958 bool URLFromPrimarySelection(Profile* profile, GURL* url) {
959 GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
960 DCHECK(clipboard);
961 gchar* selection_text = gtk_clipboard_wait_for_text(clipboard);
962 if (!selection_text)
963 return false;
964
965 // Use autocomplete to clean up the text, going so far as to turn it into
966 // a search query if necessary.
967 AutocompleteMatch match;
968 profile->GetAutocompleteClassifier()->Classify(UTF8ToWide(selection_text),
969 std::wstring(), false, &match, NULL);
970 g_free(selection_text);
971 if (!match.destination_url.is_valid())
972 return false;
973
974 *url = match.destination_url;
975 return true;
976 }
977
978 bool AddWindowAlphaChannel(GtkWidget* window) {
979 GdkScreen* screen = gtk_widget_get_screen(window);
980 GdkColormap* rgba = gdk_screen_get_rgba_colormap(screen);
981 if (rgba)
982 gtk_widget_set_colormap(window, rgba);
983
984 return rgba;
985 }
986
987 void GetTextColors(GdkColor* normal_base,
988 GdkColor* selected_base,
989 GdkColor* normal_text,
990 GdkColor* selected_text) {
991 GtkWidget* fake_entry = gtk_entry_new();
992 GtkStyle* style = gtk_rc_get_style(fake_entry);
993
994 if (normal_base)
995 *normal_base = style->base[GTK_STATE_NORMAL];
996 if (selected_base)
997 *selected_base = style->base[GTK_STATE_SELECTED];
998 if (normal_text)
999 *normal_text = style->text[GTK_STATE_NORMAL];
1000 if (selected_text)
1001 *selected_text = style->text[GTK_STATE_SELECTED];
1002
1003 g_object_ref_sink(fake_entry);
1004 g_object_unref(fake_entry);
1005 }
1006
1007 #if defined(OS_CHROMEOS)
1008
1009 GtkWindow* GetDialogTransientParent(GtkWindow* dialog) {
1010 GtkWindow* parent = gtk_window_get_transient_for(dialog);
1011 if (!parent)
1012 parent = chromeos::GetOptionsViewParent();
1013
1014 return parent;
1015 }
1016
1017 void ShowDialog(GtkWidget* dialog) {
1018 // Make sure all controls are visible so that we get correct size.
1019 gtk_widget_show_all(GTK_DIALOG(dialog)->vbox);
1020
1021 // Get dialog window size.
1022 gint width = 0;
1023 gint height = 0;
1024 gtk_window_get_size(GTK_WINDOW(dialog), &width, &height);
1025
1026 chromeos::ShowNativeDialog(GetDialogTransientParent(GTK_WINDOW(dialog)),
1027 dialog,
1028 gtk_window_get_resizable(GTK_WINDOW(dialog)) ?
1029 chromeos::DIALOG_FLAG_RESIZEABLE :
1030 chromeos::DIALOG_FLAG_DEFAULT,
1031 gfx::Size(width, height),
1032 gfx::Size());
1033 }
1034
1035 void ShowDialogWithLocalizedSize(GtkWidget* dialog,
1036 int width_id,
1037 int height_id,
1038 bool resizeable) {
1039 int width = (width_id == -1) ? 0 :
1040 views::Window::GetLocalizedContentsWidth(width_id);
1041 int height = (height_id == -1) ? 0 :
1042 views::Window::GetLocalizedContentsHeight(height_id);
1043
1044 chromeos::ShowNativeDialog(GetDialogTransientParent(GTK_WINDOW(dialog)),
1045 dialog,
1046 resizeable ? chromeos::DIALOG_FLAG_RESIZEABLE :
1047 chromeos::DIALOG_FLAG_DEFAULT,
1048 gfx::Size(width, height),
1049 gfx::Size());
1050 }
1051
1052 void ShowModalDialogWithMinLocalizedWidth(GtkWidget* dialog,
1053 int width_id) {
1054 int width = (width_id == -1) ? 0 :
1055 views::Window::GetLocalizedContentsWidth(width_id);
1056
1057 chromeos::ShowNativeDialog(GetDialogTransientParent(GTK_WINDOW(dialog)),
1058 dialog,
1059 chromeos::DIALOG_FLAG_MODAL,
1060 gfx::Size(),
1061 gfx::Size(width, 0));
1062 }
1063
1064 void PresentWindow(GtkWidget* window, int timestamp) {
1065 GtkWindow* host_window = chromeos::GetNativeDialogWindow(window);
1066 if (!host_window)
1067 host_window = GTK_WINDOW(window);
1068 if (timestamp)
1069 gtk_window_present_with_time(host_window, timestamp);
1070 else
1071 gtk_window_present(host_window);
1072 }
1073
1074 GtkWindow* GetDialogWindow(GtkWidget* dialog) {
1075 return chromeos::GetNativeDialogWindow(dialog);
1076 }
1077
1078 gfx::Rect GetDialogBounds(GtkWidget* dialog) {
1079 return chromeos::GetNativeDialogContentsBounds(dialog);
1080 }
1081
1082 #else
1083
1084 void ShowDialog(GtkWidget* dialog) {
1085 gtk_widget_show_all(dialog);
1086 }
1087
1088 void ShowDialogWithLocalizedSize(GtkWidget* dialog,
1089 int width_id,
1090 int height_id,
1091 bool resizeable) {
1092 gtk_widget_realize(dialog);
1093 SetWindowSizeFromResources(GTK_WINDOW(dialog),
1094 width_id,
1095 height_id,
1096 resizeable);
1097 gtk_widget_show_all(dialog);
1098 }
1099
1100 void ShowModalDialogWithMinLocalizedWidth(GtkWidget* dialog,
1101 int width_id) {
1102 gtk_widget_show_all(dialog);
1103
1104 // Suggest a minimum size.
1105 gint width;
1106 GtkRequisition req;
1107 gtk_widget_size_request(dialog, &req);
1108 gtk_util::GetWidgetSizeFromResources(dialog, width_id, 0, &width, NULL);
1109 if (width > req.width)
1110 gtk_widget_set_size_request(dialog, width, -1);
1111 }
1112
1113 void PresentWindow(GtkWidget* window, int timestamp) {
1114 if (timestamp)
1115 gtk_window_present_with_time(GTK_WINDOW(window), timestamp);
1116 else
1117 gtk_window_present(GTK_WINDOW(window));
1118 }
1119
1120 GtkWindow* GetDialogWindow(GtkWidget* dialog) {
1121 return GTK_WINDOW(dialog);
1122 }
1123
1124 gfx::Rect GetDialogBounds(GtkWidget* dialog) {
1125 gint x = 0, y = 0, width = 1, height = 1;
1126 gtk_window_get_position(GTK_WINDOW(dialog), &x, &y);
1127 gtk_window_get_size(GTK_WINDOW(dialog), &width, &height);
1128
1129 return gfx::Rect(x, y, width, height);
1130 }
1131
1132 #endif
1133
1134 string16 GetStockPreferencesMenuLabel() {
1135 GtkStockItem stock_item;
1136 string16 preferences;
1137 if (gtk_stock_lookup(GTK_STOCK_PREFERENCES, &stock_item)) {
1138 const char16 kUnderscore[] = { '_', 0 };
1139 RemoveChars(UTF8ToUTF16(stock_item.label), kUnderscore, &preferences);
1140 }
1141 return preferences;
1142 }
1143
1144 bool IsWidgetAncestryVisible(GtkWidget* widget) {
1145 GtkWidget* parent = widget;
1146 while (parent && GTK_WIDGET_VISIBLE(parent))
1147 parent = parent->parent;
1148 return !parent;
1149 }
1150
1151 void SetGtkFont(const std::string& font_name) {
1152 g_object_set(gtk_settings_get_default(),
1153 "gtk-font-name", font_name.c_str(), NULL);
1154 }
1155
1156 void SetLabelWidth(GtkWidget* label, int pixel_width) {
1157 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1158
1159 // Do the simple thing in LTR because the bug only affects right-aligned
1160 // text. Also, when using the workaround, the label tries to maintain
1161 // uniform line-length, which we don't really want.
1162 if (gtk_widget_get_direction(label) == GTK_TEXT_DIR_LTR) {
1163 gtk_widget_set_size_request(label, pixel_width, -1);
1164 } else {
1165 // The label has to be realized before we can adjust its width.
1166 if (GTK_WIDGET_REALIZED(label)) {
1167 OnLabelRealize(label, GINT_TO_POINTER(pixel_width));
1168 } else {
1169 g_signal_connect(label, "realize", G_CALLBACK(OnLabelRealize),
1170 GINT_TO_POINTER(pixel_width));
1171 }
1172 }
1173 }
1174
1175 void InitLabelSizeRequestAndEllipsizeMode(GtkWidget* label) {
1176 GtkRequisition size;
1177 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_NONE);
1178 gtk_widget_set_size_request(label, -1, -1);
1179 gtk_widget_size_request(label, &size);
1180 gtk_widget_set_size_request(label, size.width, size.height);
1181 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
1182 }
1183
1184 GdkDragAction WebDragOpToGdkDragAction(WebDragOperationsMask op) {
1185 GdkDragAction action = static_cast<GdkDragAction>(0);
1186 if (op & WebDragOperationCopy)
1187 action = static_cast<GdkDragAction>(action | GDK_ACTION_COPY);
1188 if (op & WebDragOperationLink)
1189 action = static_cast<GdkDragAction>(action | GDK_ACTION_LINK);
1190 if (op & WebDragOperationMove)
1191 action = static_cast<GdkDragAction>(action | GDK_ACTION_MOVE);
1192 return action;
1193 }
1194
1195 WebDragOperationsMask GdkDragActionToWebDragOp(GdkDragAction action) {
1196 WebDragOperationsMask op = WebDragOperationNone;
1197 if (action & GDK_ACTION_COPY)
1198 op = static_cast<WebDragOperationsMask>(op | WebDragOperationCopy);
1199 if (action & GDK_ACTION_LINK)
1200 op = static_cast<WebDragOperationsMask>(op | WebDragOperationLink);
1201 if (action & GDK_ACTION_MOVE)
1202 op = static_cast<WebDragOperationsMask>(op | WebDragOperationMove);
1203 return op;
1204 }
1205
1206 void ApplyMessageDialogQuirks(GtkWidget* dialog) {
1207 if (gtk_window_get_modal(GTK_WINDOW(dialog))) {
1208 // Work around a KDE 3 window manager bug.
1209 scoped_ptr<base::Environment> env(base::Environment::Create());
1210 if (base::nix::DESKTOP_ENVIRONMENT_KDE3 ==
1211 base::nix::GetDesktopEnvironment(env.get()))
1212 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(dialog), FALSE);
1213 }
1214 }
1215
1216 // Performs Cut/Copy/Paste operation on the |window|.
1217 // If the current render view is focused, then just call the specified |method|
1218 // against the current render view host, otherwise emit the specified |signal|
1219 // against the focused widget.
1220 // TODO(suzhe): This approach does not work for plugins.
1221 void DoCutCopyPaste(BrowserWindow* window,
1222 void (RenderViewHost::*method)(),
1223 const char* signal) {
1224 GtkWidget* widget = GetBrowserWindowFocusedWidget(window);
1225 if (widget == NULL)
1226 return; // Do nothing if no focused widget.
1227
1228 TabContents* current_tab = GetBrowserWindowSelectedTabContents(window);
1229 if (current_tab && widget == current_tab->GetContentNativeView()) {
1230 (current_tab->render_view_host()->*method)();
1231 } else {
1232 guint id;
1233 if ((id = g_signal_lookup(signal, G_OBJECT_TYPE(widget))) != 0)
1234 g_signal_emit(widget, id, 0);
1235 }
1236 }
1237
1238 void DoCut(BrowserWindow* window) {
1239 DoCutCopyPaste(window, &RenderViewHost::Cut, "cut-clipboard");
1240 }
1241
1242 void DoCopy(BrowserWindow* window) {
1243 DoCutCopyPaste(window, &RenderViewHost::Copy, "copy-clipboard");
1244 }
1245
1246 void DoPaste(BrowserWindow* window) {
1247 DoCutCopyPaste(window, &RenderViewHost::Paste, "paste-clipboard");
1248 }
1249
1250 } // namespace gtk_util
OLDNEW
« no previous file with comments | « chrome/browser/gtk/gtk_util.h ('k') | chrome/browser/gtk/hover_controller_gtk.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698