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.
5 #include "ui/gfx/gtk_util.h"
11 #include "base/basictypes.h"
12 #include "base/command_line.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "third_party/skia/include/core/SkBitmap.h"
15 #include "third_party/skia/include/core/SkUnPreMultiply.h"
16 #include "ui/gfx/rect.h"
20 // A process wide singleton that manages our usage of gdk cursors.
21 // gdk_cursor_new() hits the disk in several places and GdkCursor instances can
22 // be reused throughout the process.
23 class GdkCursorCache
{
27 for (GdkCursorMap::iterator
i(cursors_
.begin()); i
!= cursors_
.end(); ++i
) {
28 gdk_cursor_unref(i
->second
);
33 GdkCursor
* GetCursorImpl(GdkCursorType type
) {
34 GdkCursorMap::iterator it
= cursors_
.find(type
);
35 GdkCursor
* cursor
= NULL
;
36 if (it
== cursors_
.end()) {
37 cursor
= gdk_cursor_new(type
);
38 cursors_
.insert(std::make_pair(type
, cursor
));
43 // It is not necessary to add a reference here. The callers can ref the
44 // cursor if they need it for something.
49 typedef std::map
<GdkCursorType
, GdkCursor
*> GdkCursorMap
;
50 GdkCursorMap cursors_
;
52 DISALLOW_COPY_AND_ASSIGN(GdkCursorCache
);
59 static void CommonInitFromCommandLine(const CommandLine
& command_line
,
60 void (*init_func
)(gint
*, gchar
***)) {
61 const std::vector
<std::string
>& args
= command_line
.argv();
62 int argc
= args
.size();
63 scoped_ptr
<char *[]> argv(new char *[argc
+ 1]);
64 for (size_t i
= 0; i
< args
.size(); ++i
) {
65 // TODO(piman@google.com): can gtk_init modify argv? Just being safe
67 argv
[i
] = strdup(args
[i
].c_str());
70 char **argv_pointer
= argv
.get();
72 init_func(&argc
, &argv_pointer
);
73 for (size_t i
= 0; i
< args
.size(); ++i
) {
78 void GtkInitFromCommandLine(const CommandLine
& command_line
) {
79 CommonInitFromCommandLine(command_line
, gtk_init
);
82 void GdkInitFromCommandLine(const CommandLine
& command_line
) {
83 CommonInitFromCommandLine(command_line
, gdk_init
);
86 GdkPixbuf
* GdkPixbufFromSkBitmap(const SkBitmap
& bitmap
) {
90 SkAutoLockPixels
lock_pixels(bitmap
);
92 int width
= bitmap
.width();
93 int height
= bitmap
.height();
95 GdkPixbuf
* pixbuf
= gdk_pixbuf_new(
96 GDK_COLORSPACE_RGB
, // The only colorspace gtk supports.
97 TRUE
, // There is an alpha channel.
101 // SkBitmaps are premultiplied, we need to unpremultiply them.
102 const int kBytesPerPixel
= 4;
103 uint8
* divided
= gdk_pixbuf_get_pixels(pixbuf
);
105 for (int y
= 0, i
= 0; y
< height
; y
++) {
106 for (int x
= 0; x
< width
; x
++) {
107 uint32 pixel
= bitmap
.getAddr32(0, y
)[x
];
109 int alpha
= SkColorGetA(pixel
);
110 if (alpha
!= 0 && alpha
!= 255) {
111 SkColor unmultiplied
= SkUnPreMultiply::PMColorToColor(pixel
);
112 divided
[i
+ 0] = SkColorGetR(unmultiplied
);
113 divided
[i
+ 1] = SkColorGetG(unmultiplied
);
114 divided
[i
+ 2] = SkColorGetB(unmultiplied
);
115 divided
[i
+ 3] = alpha
;
117 divided
[i
+ 0] = SkColorGetR(pixel
);
118 divided
[i
+ 1] = SkColorGetG(pixel
);
119 divided
[i
+ 2] = SkColorGetB(pixel
);
120 divided
[i
+ 3] = alpha
;
129 void SubtractRectanglesFromRegion(GdkRegion
* region
,
130 const std::vector
<Rect
>& cutouts
) {
131 for (size_t i
= 0; i
< cutouts
.size(); ++i
) {
132 GdkRectangle rect
= cutouts
[i
].ToGdkRectangle();
133 GdkRegion
* rect_region
= gdk_region_rectangle(&rect
);
134 gdk_region_subtract(region
, rect_region
);
135 // TODO(deanm): It would be nice to be able to reuse the GdkRegion here.
136 gdk_region_destroy(rect_region
);
140 GdkCursor
* GetCursor(int type
) {
141 CR_DEFINE_STATIC_LOCAL(GdkCursorCache
, impl
, ());
142 return impl
.GetCursorImpl(static_cast<GdkCursorType
>(type
));
145 void InitRCStyles() {
146 static const char kRCText
[] =
147 // Make our dialogs styled like the GNOME HIG.
149 // TODO(evanm): content-area-spacing was introduced in a later
150 // version of GTK, so we need to set that manually on all dialogs.
151 // Perhaps it would make sense to have a shared FixupDialog() function.
152 "style \"gnome-dialog\" {\n"
154 " GtkDialog::action-area-border = 0\n"
155 " GtkDialog::button-spacing = 6\n"
156 " GtkDialog::content-area-spacing = 18\n"
157 " GtkDialog::content-area-border = 12\n"
159 // Note we set it at the "application" priority, so users can override.
160 "widget \"GtkDialog\" style : application \"gnome-dialog\"\n"
162 // Make our about dialog special, so the image is flush with the edge.
163 "style \"about-dialog\" {\n"
164 " GtkDialog::action-area-border = 12\n"
165 " GtkDialog::button-spacing = 6\n"
166 " GtkDialog::content-area-spacing = 18\n"
167 " GtkDialog::content-area-border = 0\n"
169 "widget \"about-dialog\" style : application \"about-dialog\"\n";
171 gtk_rc_parse_string(kRCText
);
174 base::TimeDelta
GetCursorBlinkCycle() {
175 // From http://library.gnome.org/devel/gtk/unstable/GtkSettings.html, this is
176 // the default value for gtk-cursor-blink-time.
177 static const gint kGtkDefaultCursorBlinkTime
= 1200;
179 gint cursor_blink_time
= kGtkDefaultCursorBlinkTime
;
180 gboolean cursor_blink
= TRUE
;
181 g_object_get(gtk_settings_get_default(),
182 "gtk-cursor-blink-time", &cursor_blink_time
,
183 "gtk-cursor-blink", &cursor_blink
,
185 return cursor_blink
?
186 base::TimeDelta::FromMilliseconds(cursor_blink_time
) :