| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/ui/libgtk2ui/gtk2_ui.h" | 5 #include "chrome/browser/ui/libgtk2ui/gtk2_ui.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 #include <pango/pango.h> | 8 #include <pango/pango.h> |
| 9 #include <set> | 9 #include <set> |
| 10 #include <utility> | 10 #include <utility> |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 // to 0, which breaks -Wsentinel. Get back the normal definition of NULL. | 74 // to 0, which breaks -Wsentinel. Get back the normal definition of NULL. |
| 75 // TODO(thakis): Remove this once we update sysroots. | 75 // TODO(thakis): Remove this once we update sysroots. |
| 76 #define __need_NULL | 76 #define __need_NULL |
| 77 #include <stddef.h> | 77 #include <stddef.h> |
| 78 | 78 |
| 79 namespace libgtk2ui { | 79 namespace libgtk2ui { |
| 80 | 80 |
| 81 namespace { | 81 namespace { |
| 82 | 82 |
| 83 class GtkThemeIconSource : public gfx::ImageSkiaSource { | 83 class GtkThemeIconSource : public gfx::ImageSkiaSource { |
| 84 public: | 84 public: |
| 85 GtkThemeIconSource(int id, const char* icon, bool enabled) | 85 GtkThemeIconSource(int id, const char* icon, bool enabled) |
| 86 : id_(id), | 86 : id_(id), icon_(icon), enabled_(enabled) {} |
| 87 icon_(icon), | 87 |
| 88 enabled_(enabled) { | 88 ~GtkThemeIconSource() override {} |
| 89 |
| 90 gfx::ImageSkiaRep GetImageForScale(float scale) override { |
| 91 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| 92 SkBitmap default_icon = rb.GetImageNamed(id_).AsBitmap(); |
| 93 |
| 94 int scalew = default_icon.width() * scale; |
| 95 int scaleh = default_icon.height() * scale; |
| 96 |
| 97 // Ask GTK to render the icon to a buffer, which we will steal from. |
| 98 GtkIconTheme* icon_theme = gtk_icon_theme_get_default(); |
| 99 GdkPixbuf* gdk_icon = gtk_icon_theme_load_icon( |
| 100 icon_theme, icon_, 20 * scale, (GtkIconLookupFlags)0, NULL); |
| 101 |
| 102 // This can theoretically happen if an icon theme doesn't provide a |
| 103 // specific image. This should realistically never happen, but I bet there |
| 104 // are some theme authors who don't reliably provide all icons. |
| 105 if (!gdk_icon) |
| 106 return gfx::ImageSkiaRep(); |
| 107 |
| 108 #if GTK_MAJOR_VERSION == 2 |
| 109 GtkIconSource* icon_source = gtk_icon_source_new(); |
| 110 gtk_icon_source_set_pixbuf(icon_source, gdk_icon); |
| 111 |
| 112 GdkPixbuf* temp = gtk_style_render_icon( |
| 113 gtk_rc_get_style(NativeThemeGtk2::instance()->GetButton()), icon_source, |
| 114 GTK_TEXT_DIR_NONE, enabled_ ? GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE, |
| 115 (GtkIconSize)-1, NativeThemeGtk2::instance()->GetButton(), NULL); |
| 116 |
| 117 gtk_icon_source_free(icon_source); |
| 118 g_object_unref(gdk_icon); |
| 119 |
| 120 gdk_icon = temp; |
| 121 #endif |
| 122 |
| 123 SkBitmap retval; |
| 124 retval.allocN32Pixels(scalew, scaleh); |
| 125 retval.eraseColor(0); |
| 126 |
| 127 const SkBitmap icon = GdkPixbufToImageSkia(gdk_icon); |
| 128 g_object_unref(gdk_icon); |
| 129 |
| 130 SkCanvas canvas(retval); |
| 131 SkPaint paint; |
| 132 |
| 133 #if GTK_MAJOR_VERSION > 2 |
| 134 if (!enabled_) |
| 135 paint.setAlpha(128); |
| 136 #endif |
| 137 |
| 138 canvas.drawBitmap(icon, (scalew / 2) - (icon.width() / 2), |
| 139 (scaleh / 2) - (icon.height() / 2), &paint); |
| 140 |
| 141 return gfx::ImageSkiaRep(retval, scale); |
| 142 } |
| 143 |
| 144 private: |
| 145 int id_; |
| 146 const char* icon_; |
| 147 bool enabled_; |
| 148 |
| 149 DISALLOW_COPY_AND_ASSIGN(GtkThemeIconSource); |
| 150 }; |
| 151 |
| 152 class GtkButtonImageSource : public gfx::ImageSkiaSource { |
| 153 public: |
| 154 GtkButtonImageSource(const char* idr_string, gfx::Size size) |
| 155 : width_(size.width()), height_(size.height()) { |
| 156 is_blue_ = !!strstr(idr_string, "IDR_BLUE"); |
| 157 focus_ = !!strstr(idr_string, "_FOCUSED_"); |
| 158 |
| 159 if (strstr(idr_string, "_DISABLED")) { |
| 160 state_ = ui::NativeTheme::kDisabled; |
| 161 } else if (strstr(idr_string, "_HOVER")) { |
| 162 state_ = ui::NativeTheme::kHovered; |
| 163 } else if (strstr(idr_string, "_PRESSED")) { |
| 164 state_ = ui::NativeTheme::kPressed; |
| 165 } else { |
| 166 state_ = ui::NativeTheme::kNormal; |
| 167 } |
| 168 } |
| 169 |
| 170 ~GtkButtonImageSource() override {} |
| 171 |
| 172 gfx::ImageSkiaRep GetImageForScale(float scale) override { |
| 173 int width = width_ * scale; |
| 174 int height = height_ * scale; |
| 175 |
| 176 SkBitmap border; |
| 177 border.allocN32Pixels(width, height); |
| 178 border.eraseColor(0); |
| 179 |
| 180 // Create a temporary GTK button to snapshot |
| 181 GtkWidget* window = gtk_offscreen_window_new(); |
| 182 GtkWidget* button = gtk_toggle_button_new(); |
| 183 |
| 184 if (state_ == ui::NativeTheme::kPressed) |
| 185 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), true); |
| 186 else if (state_ == ui::NativeTheme::kDisabled) |
| 187 gtk_widget_set_sensitive(button, false); |
| 188 |
| 189 gtk_widget_set_size_request(button, width, height); |
| 190 gtk_container_add(GTK_CONTAINER(window), button); |
| 191 |
| 192 if (is_blue_) |
| 193 TurnButtonBlue(button); |
| 194 |
| 195 gtk_widget_show_all(window); |
| 196 |
| 197 cairo_surface_t* surface = cairo_image_surface_create_for_data( |
| 198 static_cast<unsigned char*>(border.getAddr(0, 0)), |
| 199 CAIRO_FORMAT_ARGB32, width, height, width * 4); |
| 200 cairo_t* cr = cairo_create(surface); |
| 201 |
| 202 #if GTK_MAJOR_VERSION == 2 |
| 203 if (focus_) |
| 204 GTK_WIDGET_SET_FLAGS(button, GTK_HAS_FOCUS); |
| 205 |
| 206 int w, h; |
| 207 GdkPixmap* pixmap; |
| 208 |
| 209 { |
| 210 // http://crbug.com/346740 |
| 211 ANNOTATE_SCOPED_MEMORY_LEAK; |
| 212 pixmap = gtk_widget_get_snapshot(button, NULL); |
| 89 } | 213 } |
| 90 | 214 |
| 91 ~GtkThemeIconSource() override {} | 215 gdk_drawable_get_size(GDK_DRAWABLE(pixmap), &w, &h); |
| 216 GdkColormap* colormap = gdk_drawable_get_colormap(pixmap); |
| 217 GdkPixbuf* pixbuf = gdk_pixbuf_get_from_drawable( |
| 218 NULL, GDK_DRAWABLE(pixmap), colormap, 0, 0, 0, 0, w, h); |
| 92 | 219 |
| 93 gfx::ImageSkiaRep GetImageForScale(float scale) override { | 220 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); |
| 94 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 221 cairo_paint(cr); |
| 95 SkBitmap default_icon = rb.GetImageNamed(id_).AsBitmap(); | |
| 96 | 222 |
| 97 int scalew = default_icon.width() * scale; | 223 g_object_unref(pixbuf); |
| 98 int scaleh = default_icon.height() * scale; | 224 g_object_unref(pixmap); |
| 225 #else |
| 226 gtk_widget_draw(button, cr); |
| 99 | 227 |
| 100 // Ask GTK to render the icon to a buffer, which we will steal from. | 228 // There's probably a better way to do this |
| 101 GtkIconTheme* icon_theme = gtk_icon_theme_get_default(); | 229 if (focus_) |
| 102 GdkPixbuf* gdk_icon = gtk_icon_theme_load_icon( | 230 gtk_render_focus(gtk_widget_get_style_context(button), cr, 0, 0, |
| 103 icon_theme, | 231 width, height); |
| 104 icon_, | |
| 105 20 * scale, | |
| 106 (GtkIconLookupFlags)0, | |
| 107 NULL); | |
| 108 | |
| 109 // This can theoretically happen if an icon theme doesn't provide a | |
| 110 // specific image. This should realistically never happen, but I bet there | |
| 111 // are some theme authors who don't reliably provide all icons. | |
| 112 if (!gdk_icon) | |
| 113 return gfx::ImageSkiaRep(); | |
| 114 | |
| 115 #if GTK_MAJOR_VERSION == 2 | |
| 116 GtkIconSource* icon_source = gtk_icon_source_new(); | |
| 117 gtk_icon_source_set_pixbuf(icon_source, gdk_icon); | |
| 118 | |
| 119 GdkPixbuf* temp = gtk_style_render_icon( | |
| 120 gtk_rc_get_style(NativeThemeGtk2::instance()->GetButton()), | |
| 121 icon_source, | |
| 122 GTK_TEXT_DIR_NONE, | |
| 123 enabled_ ? GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE, | |
| 124 (GtkIconSize)-1, | |
| 125 NativeThemeGtk2::instance()->GetButton(), | |
| 126 NULL); | |
| 127 | |
| 128 gtk_icon_source_free(icon_source); | |
| 129 g_object_unref(gdk_icon); | |
| 130 | |
| 131 gdk_icon = temp; | |
| 132 #endif | 232 #endif |
| 133 | 233 |
| 134 SkBitmap retval; | 234 cairo_destroy(cr); |
| 135 retval.allocN32Pixels(scalew, scaleh); | 235 cairo_surface_destroy(surface); |
| 136 retval.eraseColor(0); | |
| 137 | 236 |
| 138 const SkBitmap icon = GdkPixbufToImageSkia(gdk_icon); | 237 gtk_widget_destroy(window); |
| 139 g_object_unref(gdk_icon); | |
| 140 | 238 |
| 141 SkCanvas canvas(retval); | 239 return gfx::ImageSkiaRep(border, scale); |
| 142 SkPaint paint; | 240 } |
| 143 | 241 |
| 144 #if GTK_MAJOR_VERSION > 2 | 242 private: |
| 145 if (!enabled_) | 243 bool is_blue_; |
| 146 paint.setAlpha(128); | 244 bool focus_; |
| 147 #endif | 245 ui::NativeTheme::State state_; |
| 246 int width_; |
| 247 int height_; |
| 148 | 248 |
| 149 canvas.drawBitmap(icon, | 249 DISALLOW_COPY_AND_ASSIGN(GtkButtonImageSource); |
| 150 (scalew / 2) - (icon.width() / 2), | |
| 151 (scaleh / 2) - (icon.height() / 2), | |
| 152 &paint); | |
| 153 | |
| 154 return gfx::ImageSkiaRep(retval, scale); | |
| 155 } | |
| 156 | |
| 157 private: | |
| 158 int id_; | |
| 159 const char* icon_; | |
| 160 bool enabled_; | |
| 161 | |
| 162 DISALLOW_COPY_AND_ASSIGN(GtkThemeIconSource); | |
| 163 }; | 250 }; |
| 164 | 251 |
| 252 class GtkButtonPainter : public views::Painter { |
| 253 public: |
| 254 explicit GtkButtonPainter(std::string idr) : idr_(idr) {} |
| 255 ~GtkButtonPainter() override {} |
| 165 | 256 |
| 166 class GtkButtonImageSource : public gfx::ImageSkiaSource { | 257 gfx::Size GetMinimumSize() const override { return gfx::Size(); } |
| 167 public: | 258 void Paint(gfx::Canvas* canvas, const gfx::Size& size) override { |
| 168 GtkButtonImageSource(const char* idr_string, gfx::Size size) | 259 gfx::ImageSkiaSource* source = new GtkButtonImageSource(idr_.c_str(), size); |
| 169 : width_(size.width()), | 260 gfx::ImageSkia image(source, 1); |
| 170 height_(size.height()) { | 261 canvas->DrawImageInt(image, 0, 0); |
| 171 is_blue_ = !!strstr(idr_string, "IDR_BLUE"); | 262 } |
| 172 focus_ = !!strstr(idr_string, "_FOCUSED_"); | |
| 173 | 263 |
| 174 if (strstr(idr_string, "_DISABLED")) { | 264 private: |
| 175 state_ = ui::NativeTheme::kDisabled; | 265 std::string idr_; |
| 176 } else if (strstr(idr_string, "_HOVER")) { | |
| 177 state_ = ui::NativeTheme::kHovered; | |
| 178 } else if (strstr(idr_string, "_PRESSED")) { | |
| 179 state_ = ui::NativeTheme::kPressed; | |
| 180 } else { | |
| 181 state_ = ui::NativeTheme::kNormal; | |
| 182 } | |
| 183 } | |
| 184 | 266 |
| 185 ~GtkButtonImageSource() override {} | 267 DISALLOW_COPY_AND_ASSIGN(GtkButtonPainter); |
| 186 | |
| 187 gfx::ImageSkiaRep GetImageForScale(float scale) override { | |
| 188 int width = width_ * scale; | |
| 189 int height = height_ * scale; | |
| 190 | |
| 191 SkBitmap border; | |
| 192 border.allocN32Pixels(width, height); | |
| 193 border.eraseColor(0); | |
| 194 | |
| 195 // Create a temporary GTK button to snapshot | |
| 196 GtkWidget* window = gtk_offscreen_window_new(); | |
| 197 GtkWidget* button = gtk_toggle_button_new(); | |
| 198 | |
| 199 if (state_ == ui::NativeTheme::kPressed) | |
| 200 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), true); | |
| 201 else if (state_ == ui::NativeTheme::kDisabled) | |
| 202 gtk_widget_set_sensitive(button, false); | |
| 203 | |
| 204 gtk_widget_set_size_request(button, width, height); | |
| 205 gtk_container_add(GTK_CONTAINER(window), button); | |
| 206 | |
| 207 if (is_blue_) | |
| 208 TurnButtonBlue(button); | |
| 209 | |
| 210 gtk_widget_show_all(window); | |
| 211 | |
| 212 | |
| 213 cairo_surface_t* surface = cairo_image_surface_create_for_data( | |
| 214 static_cast<unsigned char*>(border.getAddr(0, 0)), | |
| 215 CAIRO_FORMAT_ARGB32, | |
| 216 width, height, | |
| 217 width * 4); | |
| 218 cairo_t* cr = cairo_create(surface); | |
| 219 | |
| 220 #if GTK_MAJOR_VERSION == 2 | |
| 221 if (focus_) | |
| 222 GTK_WIDGET_SET_FLAGS(button, GTK_HAS_FOCUS); | |
| 223 | |
| 224 int w, h; | |
| 225 GdkPixmap* pixmap; | |
| 226 | |
| 227 { | |
| 228 // http://crbug.com/346740 | |
| 229 ANNOTATE_SCOPED_MEMORY_LEAK; | |
| 230 pixmap = gtk_widget_get_snapshot(button, NULL); | |
| 231 } | |
| 232 | |
| 233 gdk_drawable_get_size(GDK_DRAWABLE(pixmap), &w, &h); | |
| 234 GdkColormap* colormap = gdk_drawable_get_colormap(pixmap); | |
| 235 GdkPixbuf* pixbuf = gdk_pixbuf_get_from_drawable(NULL, | |
| 236 GDK_DRAWABLE(pixmap), | |
| 237 colormap, | |
| 238 0, 0, 0, 0, w, h); | |
| 239 | |
| 240 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); | |
| 241 cairo_paint(cr); | |
| 242 | |
| 243 g_object_unref(pixbuf); | |
| 244 g_object_unref(pixmap); | |
| 245 #else | |
| 246 gtk_widget_draw(button, cr); | |
| 247 | |
| 248 // There's probably a better way to do this | |
| 249 if (focus_) | |
| 250 gtk_render_focus(gtk_widget_get_style_context(button), | |
| 251 cr, 0, 0, width, height); | |
| 252 #endif | |
| 253 | |
| 254 cairo_destroy(cr); | |
| 255 cairo_surface_destroy(surface); | |
| 256 | |
| 257 gtk_widget_destroy(window); | |
| 258 | |
| 259 return gfx::ImageSkiaRep(border, scale); | |
| 260 } | |
| 261 | |
| 262 private: | |
| 263 bool is_blue_; | |
| 264 bool focus_; | |
| 265 ui::NativeTheme::State state_; | |
| 266 int width_; | |
| 267 int height_; | |
| 268 | |
| 269 DISALLOW_COPY_AND_ASSIGN(GtkButtonImageSource); | |
| 270 }; | 268 }; |
| 271 | 269 |
| 272 | |
| 273 class GtkButtonPainter : public views::Painter { | |
| 274 public: | |
| 275 explicit GtkButtonPainter(std::string idr) : idr_(idr) {} | |
| 276 ~GtkButtonPainter() override {} | |
| 277 | |
| 278 gfx::Size GetMinimumSize() const override { | |
| 279 return gfx::Size(); | |
| 280 } | |
| 281 void Paint(gfx::Canvas* canvas, const gfx::Size& size) override { | |
| 282 gfx::ImageSkiaSource* source = | |
| 283 new GtkButtonImageSource(idr_.c_str(), size); | |
| 284 gfx::ImageSkia image(source, 1); | |
| 285 canvas->DrawImageInt(image, 0, 0); | |
| 286 } | |
| 287 | |
| 288 private: | |
| 289 std::string idr_; | |
| 290 | |
| 291 DISALLOW_COPY_AND_ASSIGN(GtkButtonPainter); | |
| 292 }; | |
| 293 | |
| 294 | |
| 295 | |
| 296 struct GObjectDeleter { | 270 struct GObjectDeleter { |
| 297 void operator()(void* ptr) { | 271 void operator()(void* ptr) { |
| 298 g_object_unref(ptr); | 272 g_object_unref(ptr); |
| 299 } | 273 } |
| 300 }; | 274 }; |
| 301 struct GtkIconInfoDeleter { | 275 struct GtkIconInfoDeleter { |
| 302 void operator()(GtkIconInfo* ptr) { | 276 void operator()(GtkIconInfo* ptr) { |
| 303 G_GNUC_BEGIN_IGNORE_DEPRECATIONS | 277 G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
| 304 gtk_icon_info_free(ptr); | 278 gtk_icon_info_free(ptr); |
| 305 G_GNUC_END_IGNORE_DEPRECATIONS | 279 G_GNUC_END_IGNORE_DEPRECATIONS |
| (...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 776 | 750 |
| 777 if (border->PaintsButtonState(paintstate[i].focus, paintstate[i].state)) { | 751 if (border->PaintsButtonState(paintstate[i].focus, paintstate[i].state)) { |
| 778 std::string idr = is_blue ? paintstate[i].idr_blue : paintstate[i].idr; | 752 std::string idr = is_blue ? paintstate[i].idr_blue : paintstate[i].idr; |
| 779 painter = new GtkButtonPainter(idr); | 753 painter = new GtkButtonPainter(idr); |
| 780 } | 754 } |
| 781 | 755 |
| 782 gtk_border->SetPainter(paintstate[i].focus, paintstate[i].state, painter); | 756 gtk_border->SetPainter(paintstate[i].focus, paintstate[i].state, painter); |
| 783 } | 757 } |
| 784 | 758 |
| 785 return std::move(gtk_border); | 759 return std::move(gtk_border); |
| 786 ; | |
| 787 } | 760 } |
| 788 | 761 |
| 789 void Gtk2UI::AddWindowButtonOrderObserver( | 762 void Gtk2UI::AddWindowButtonOrderObserver( |
| 790 views::WindowButtonOrderObserver* observer) { | 763 views::WindowButtonOrderObserver* observer) { |
| 791 if (!leading_buttons_.empty() || !trailing_buttons_.empty()) { | 764 if (!leading_buttons_.empty() || !trailing_buttons_.empty()) { |
| 792 observer->OnWindowButtonOrderingChange(leading_buttons_, | 765 observer->OnWindowButtonOrderingChange(leading_buttons_, |
| 793 trailing_buttons_); | 766 trailing_buttons_); |
| 794 } | 767 } |
| 795 | 768 |
| 796 observer_list_.AddObserver(observer); | 769 observer_list_.AddObserver(observer); |
| (...skipping 586 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1383 const float rounded = roundf(scale * 10) / 10; | 1356 const float rounded = roundf(scale * 10) / 10; |
| 1384 // See crbug.com/484400 | 1357 // See crbug.com/484400 |
| 1385 return rounded < 1.3 ? 1.0 : rounded; | 1358 return rounded < 1.3 ? 1.0 : rounded; |
| 1386 } | 1359 } |
| 1387 | 1360 |
| 1388 } // namespace libgtk2ui | 1361 } // namespace libgtk2ui |
| 1389 | 1362 |
| 1390 views::LinuxUI* BuildGtk2UI() { | 1363 views::LinuxUI* BuildGtk2UI() { |
| 1391 return new libgtk2ui::Gtk2UI; | 1364 return new libgtk2ui::Gtk2UI; |
| 1392 } | 1365 } |
| OLD | NEW |