| 1 | ///////////////////////////////////////////////////////////////////////////// |
| 2 | // Name: src/gtk/artstd.cpp |
| 3 | // Purpose: stock wxArtProvider instance with native GTK+ stock icons |
| 4 | // Author: Vaclav Slavik |
| 5 | // Modified by: |
| 6 | // Created: 2004-08-22 |
| 7 | // RCS-ID: $Id$ |
| 8 | // Copyright: (c) Vaclav Slavik, 2004 |
| 9 | // Licence: wxWindows licence |
| 10 | ///////////////////////////////////////////////////////////////////////////// |
| 11 | |
| 12 | // --------------------------------------------------------------------------- |
| 13 | // headers |
| 14 | // --------------------------------------------------------------------------- |
| 15 | |
| 16 | // For compilers that support precompilation, includes "wx.h". |
| 17 | #include "wx/wxprec.h" |
| 18 | |
| 19 | #if defined(__BORLANDC__) |
| 20 | #pragma hdrstop |
| 21 | #endif |
| 22 | |
| 23 | #if !defined(__WXUNIVERSAL__) |
| 24 | |
| 25 | #include "wx/artprov.h" |
| 26 | |
| 27 | #ifndef WX_PRECOMP |
| 28 | #include "wx/module.h" |
| 29 | #endif |
| 30 | |
| 31 | #include <gtk/gtkversion.h> |
| 32 | #if GTK_CHECK_VERSION(2, 9, 0) |
| 33 | // gtk_object_sink |
| 34 | #undef GTK_DISABLE_DEPRECATED |
| 35 | #endif |
| 36 | #include <gtk/gtk.h> |
| 37 | |
| 38 | // compatibility with older GTK+ versions: |
| 39 | #ifndef GTK_STOCK_FILE |
| 40 | #define GTK_STOCK_FILE "gtk-file" |
| 41 | #endif |
| 42 | #ifndef GTK_STOCK_DIRECTORY |
| 43 | #define GTK_STOCK_DIRECTORY "gtk-directory" |
| 44 | #endif |
| 45 | |
| 46 | |
| 47 | // ---------------------------------------------------------------------------- |
| 48 | // wxGTK2ArtProvider |
| 49 | // ---------------------------------------------------------------------------- |
| 50 | |
| 51 | class wxGTK2ArtProvider : public wxArtProvider |
| 52 | { |
| 53 | protected: |
| 54 | virtual wxBitmap CreateBitmap(const wxArtID& id, const wxArtClient& client, |
| 55 | const wxSize& size); |
| 56 | }; |
| 57 | |
| 58 | /*static*/ void wxArtProvider::InitNativeProvider() |
| 59 | { |
| 60 | Push(new wxGTK2ArtProvider); |
| 61 | } |
| 62 | |
| 63 | // ---------------------------------------------------------------------------- |
| 64 | // CreateBitmap routine |
| 65 | // ---------------------------------------------------------------------------- |
| 66 | |
| 67 | static const char *wxArtIDToStock(const wxArtID& id) |
| 68 | { |
| 69 | #define ART(wxid, gtkid) \ |
| 70 | if (id == wxid) return gtkid; |
| 71 | |
| 72 | ART(wxART_ERROR, GTK_STOCK_DIALOG_ERROR) |
| 73 | ART(wxART_INFORMATION, GTK_STOCK_DIALOG_INFO) |
| 74 | ART(wxART_WARNING, GTK_STOCK_DIALOG_WARNING) |
| 75 | ART(wxART_QUESTION, GTK_STOCK_DIALOG_QUESTION) |
| 76 | |
| 77 | //ART(wxART_HELP_SIDE_PANEL, ) |
| 78 | ART(wxART_HELP_SETTINGS, GTK_STOCK_SELECT_FONT) |
| 79 | //ART(wxART_HELP_BOOK, ) |
| 80 | ART(wxART_HELP_FOLDER, GTK_STOCK_DIRECTORY) |
| 81 | ART(wxART_HELP_PAGE, GTK_STOCK_FILE) |
| 82 | ART(wxART_MISSING_IMAGE, GTK_STOCK_MISSING_IMAGE) |
| 83 | ART(wxART_ADD_BOOKMARK, GTK_STOCK_ADD) |
| 84 | ART(wxART_DEL_BOOKMARK, GTK_STOCK_REMOVE) |
| 85 | ART(wxART_GO_BACK, GTK_STOCK_GO_BACK) |
| 86 | ART(wxART_GO_FORWARD, GTK_STOCK_GO_FORWARD) |
| 87 | ART(wxART_GO_UP, GTK_STOCK_GO_UP) |
| 88 | ART(wxART_GO_DOWN, GTK_STOCK_GO_DOWN) |
| 89 | ART(wxART_GO_TO_PARENT, GTK_STOCK_GO_UP) |
| 90 | ART(wxART_GO_HOME, GTK_STOCK_HOME) |
| 91 | ART(wxART_FILE_OPEN, GTK_STOCK_OPEN) |
| 92 | ART(wxART_PRINT, GTK_STOCK_PRINT) |
| 93 | ART(wxART_HELP, GTK_STOCK_HELP) |
| 94 | ART(wxART_TIP, GTK_STOCK_DIALOG_INFO) |
| 95 | //ART(wxART_REPORT_VIEW, ) |
| 96 | //ART(wxART_LIST_VIEW, ) |
| 97 | //ART(wxART_NEW_DIR, ) |
| 98 | #ifdef __WXGTK24__ |
| 99 | ART(wxART_FOLDER, GTK_STOCK_DIRECTORY) |
| 100 | ART(wxART_FOLDER_OPEN, GTK_STOCK_DIRECTORY) |
| 101 | #endif |
| 102 | //ART(wxART_GO_DIR_UP, ) |
| 103 | ART(wxART_EXECUTABLE_FILE, GTK_STOCK_EXECUTE) |
| 104 | ART(wxART_NORMAL_FILE, GTK_STOCK_FILE) |
| 105 | ART(wxART_TICK_MARK, GTK_STOCK_APPLY) |
| 106 | ART(wxART_CROSS_MARK, GTK_STOCK_CANCEL) |
| 107 | |
| 108 | #ifdef __WXGTK24__ |
| 109 | ART(wxART_FLOPPY, GTK_STOCK_FLOPPY) |
| 110 | ART(wxART_CDROM, GTK_STOCK_CDROM) |
| 111 | ART(wxART_HARDDISK, GTK_STOCK_HARDDISK) |
| 112 | ART(wxART_REMOVABLE, GTK_STOCK_HARDDISK) |
| 113 | |
| 114 | ART(wxART_FILE_SAVE, GTK_STOCK_SAVE) |
| 115 | ART(wxART_FILE_SAVE_AS, GTK_STOCK_SAVE_AS) |
| 116 | |
| 117 | ART(wxART_COPY, GTK_STOCK_COPY) |
| 118 | ART(wxART_CUT, GTK_STOCK_CUT) |
| 119 | ART(wxART_PASTE, GTK_STOCK_PASTE) |
| 120 | ART(wxART_DELETE, GTK_STOCK_DELETE) |
| 121 | ART(wxART_NEW, GTK_STOCK_NEW) |
| 122 | |
| 123 | ART(wxART_UNDO, GTK_STOCK_UNDO) |
| 124 | ART(wxART_REDO, GTK_STOCK_REDO) |
| 125 | |
| 126 | ART(wxART_QUIT, GTK_STOCK_QUIT) |
| 127 | |
| 128 | ART(wxART_FIND, GTK_STOCK_FIND) |
| 129 | ART(wxART_FIND_AND_REPLACE, GTK_STOCK_FIND_AND_REPLACE) |
| 130 | #endif |
| 131 | |
| 132 | return NULL; |
| 133 | |
| 134 | #undef ART |
| 135 | } |
| 136 | |
| 137 | GtkIconSize wxArtClientToIconSize(const wxArtClient& client) |
| 138 | { |
| 139 | if (client == wxART_TOOLBAR) |
| 140 | return GTK_ICON_SIZE_LARGE_TOOLBAR; |
| 141 | else if (client == wxART_MENU) |
| 142 | return GTK_ICON_SIZE_MENU; |
| 143 | else if (client == wxART_CMN_DIALOG || client == wxART_MESSAGE_BOX) |
| 144 | return GTK_ICON_SIZE_DIALOG; |
| 145 | else if (client == wxART_BUTTON) |
| 146 | return GTK_ICON_SIZE_BUTTON; |
| 147 | else |
| 148 | return GTK_ICON_SIZE_INVALID; // this is arbitrary |
| 149 | } |
| 150 | |
| 151 | static GtkIconSize FindClosestIconSize(const wxSize& size) |
| 152 | { |
| 153 | #define NUM_SIZES 6 |
| 154 | static struct |
| 155 | { |
| 156 | GtkIconSize icon; |
| 157 | gint x, y; |
| 158 | } s_sizes[NUM_SIZES]; |
| 159 | static bool s_sizesInitialized = false; |
| 160 | |
| 161 | if (!s_sizesInitialized) |
| 162 | { |
| 163 | s_sizes[0].icon = GTK_ICON_SIZE_MENU; |
| 164 | s_sizes[1].icon = GTK_ICON_SIZE_SMALL_TOOLBAR; |
| 165 | s_sizes[2].icon = GTK_ICON_SIZE_LARGE_TOOLBAR; |
| 166 | s_sizes[3].icon = GTK_ICON_SIZE_BUTTON; |
| 167 | s_sizes[4].icon = GTK_ICON_SIZE_DND; |
| 168 | s_sizes[5].icon = GTK_ICON_SIZE_DIALOG; |
| 169 | for (size_t i = 0; i < NUM_SIZES; i++) |
| 170 | { |
| 171 | gtk_icon_size_lookup(s_sizes[i].icon, |
| 172 | &s_sizes[i].x, &s_sizes[i].y); |
| 173 | } |
| 174 | s_sizesInitialized = true; |
| 175 | } |
| 176 | |
| 177 | GtkIconSize best = GTK_ICON_SIZE_DIALOG; // presumably largest |
| 178 | unsigned distance = INT_MAX; |
| 179 | for (size_t i = 0; i < NUM_SIZES; i++) |
| 180 | { |
| 181 | // only use larger bitmaps, scaling down looks better than scaling up: |
| 182 | if (size.x > s_sizes[i].x || size.y > s_sizes[i].y) |
| 183 | continue; |
| 184 | |
| 185 | unsigned dist = (size.x - s_sizes[i].x) * (size.x - s_sizes[i].x) + |
| 186 | (size.y - s_sizes[i].y) * (size.y - s_sizes[i].y); |
| 187 | if (dist == 0) |
| 188 | return s_sizes[i].icon; |
| 189 | else if (dist < distance) |
| 190 | { |
| 191 | distance = dist; |
| 192 | best = s_sizes[i].icon; |
| 193 | } |
| 194 | } |
| 195 | return best; |
| 196 | } |
| 197 | |
| 198 | |
| 199 | static GtkStyle *gs_gtkStyle = NULL; |
| 200 | |
| 201 | static GdkPixbuf *CreateStockIcon(const char *stockid, GtkIconSize size) |
| 202 | { |
| 203 | // FIXME: This code is not 100% correct, because stock pixmap are |
| 204 | // context-dependent and may be affected by theme engine, the |
| 205 | // correct value can only be obtained for given GtkWidget object. |
| 206 | // |
| 207 | // Fool-proof implementation of stock bitmaps would extend wxBitmap |
| 208 | // with "stock-id" representation (in addition to pixmap and pixbuf |
| 209 | // ones) and would convert it to pixbuf when rendered. |
| 210 | |
| 211 | if (gs_gtkStyle == NULL) |
| 212 | { |
| 213 | GtkWidget *widget = gtk_button_new(); |
| 214 | gs_gtkStyle = gtk_rc_get_style(widget); |
| 215 | wxASSERT( gs_gtkStyle != NULL ); |
| 216 | g_object_ref(gs_gtkStyle); |
| 217 | gtk_object_sink((GtkObject*)widget); |
| 218 | } |
| 219 | |
| 220 | GtkIconSet *iconset = gtk_style_lookup_icon_set(gs_gtkStyle, stockid); |
| 221 | |
| 222 | if (!iconset) |
| 223 | return NULL; |
| 224 | |
| 225 | return gtk_icon_set_render_icon(iconset, gs_gtkStyle, |
| 226 | gtk_widget_get_default_direction(), |
| 227 | GTK_STATE_NORMAL, size, NULL, NULL); |
| 228 | } |
| 229 | |
| 230 | #ifdef __WXGTK24__ |
| 231 | static GdkPixbuf *CreateThemeIcon(const char *iconname, |
| 232 | GtkIconSize iconsize, const wxSize& sz) |
| 233 | { |
| 234 | wxSize size(sz); |
| 235 | if (size == wxDefaultSize) |
| 236 | { |
| 237 | gtk_icon_size_lookup(iconsize, &size.x, &size.y); |
| 238 | } |
| 239 | |
| 240 | return gtk_icon_theme_load_icon( |
| 241 | gtk_icon_theme_get_default(), |
| 242 | iconname, |
| 243 | size.x, |
| 244 | (GtkIconLookupFlags)0, NULL); |
| 245 | } |
| 246 | #endif |
| 247 | |
| 248 | wxBitmap wxGTK2ArtProvider::CreateBitmap(const wxArtID& id, |
| 249 | const wxArtClient& client, |
| 250 | const wxSize& size) |
| 251 | { |
| 252 | wxCharBuffer stockid = wxArtIDToStock(id); |
| 253 | GtkIconSize stocksize = (size == wxDefaultSize) ? |
| 254 | wxArtClientToIconSize(client) : |
| 255 | FindClosestIconSize(size); |
| 256 | |
| 257 | // we must have some size, this is arbitrary |
| 258 | if (stocksize == GTK_ICON_SIZE_INVALID) |
| 259 | stocksize = GTK_ICON_SIZE_BUTTON; |
| 260 | |
| 261 | // allow passing GTK+ stock IDs to wxArtProvider: |
| 262 | if (!stockid) |
| 263 | stockid = id.ToAscii(); |
| 264 | |
| 265 | GdkPixbuf *pixbuf = CreateStockIcon(stockid, stocksize); |
| 266 | |
| 267 | #ifdef __WXGTK24__ |
| 268 | if (!pixbuf && !gtk_check_version(2,4,0)) |
| 269 | { |
| 270 | pixbuf = CreateThemeIcon(stockid, stocksize, size); |
| 271 | } |
| 272 | #endif |
| 273 | |
| 274 | if (pixbuf && size != wxDefaultSize && |
| 275 | (size.x != gdk_pixbuf_get_width(pixbuf) || |
| 276 | size.y != gdk_pixbuf_get_height(pixbuf))) |
| 277 | { |
| 278 | GdkPixbuf *p2 = gdk_pixbuf_scale_simple(pixbuf, size.x, size.y, |
| 279 | GDK_INTERP_BILINEAR); |
| 280 | if (p2) |
| 281 | { |
| 282 | g_object_unref (pixbuf); |
| 283 | pixbuf = p2; |
| 284 | } |
| 285 | } |
| 286 | |
| 287 | wxBitmap bmp; |
| 288 | if (pixbuf != NULL) |
| 289 | bmp.SetPixbuf(pixbuf); |
| 290 | |
| 291 | return bmp; |
| 292 | } |
| 293 | |
| 294 | // ---------------------------------------------------------------------------- |
| 295 | // Cleanup |
| 296 | // ---------------------------------------------------------------------------- |
| 297 | |
| 298 | class wxArtGtkModule: public wxModule |
| 299 | { |
| 300 | public: |
| 301 | bool OnInit() { return true; } |
| 302 | void OnExit() |
| 303 | { |
| 304 | if (gs_gtkStyle) |
| 305 | { |
| 306 | g_object_unref(gs_gtkStyle); |
| 307 | gs_gtkStyle = NULL; |
| 308 | } |
| 309 | } |
| 310 | |
| 311 | DECLARE_DYNAMIC_CLASS(wxArtGtkModule) |
| 312 | }; |
| 313 | |
| 314 | IMPLEMENT_DYNAMIC_CLASS(wxArtGtkModule, wxModule) |
| 315 | |
| 316 | #endif // !defined(__WXUNIVERSAL__) |