| 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 | ART(wxART_FOLDER, GTK_STOCK_DIRECTORY) |
| 99 | ART(wxART_FOLDER_OPEN, GTK_STOCK_DIRECTORY) |
| 100 | //ART(wxART_GO_DIR_UP, ) |
| 101 | ART(wxART_EXECUTABLE_FILE, GTK_STOCK_EXECUTE) |
| 102 | ART(wxART_NORMAL_FILE, GTK_STOCK_FILE) |
| 103 | ART(wxART_TICK_MARK, GTK_STOCK_APPLY) |
| 104 | ART(wxART_CROSS_MARK, GTK_STOCK_CANCEL) |
| 105 | |
| 106 | ART(wxART_FLOPPY, GTK_STOCK_FLOPPY) |
| 107 | ART(wxART_CDROM, GTK_STOCK_CDROM) |
| 108 | ART(wxART_HARDDISK, GTK_STOCK_HARDDISK) |
| 109 | ART(wxART_REMOVABLE, GTK_STOCK_HARDDISK) |
| 110 | |
| 111 | ART(wxART_FILE_SAVE, GTK_STOCK_SAVE) |
| 112 | ART(wxART_FILE_SAVE_AS, GTK_STOCK_SAVE_AS) |
| 113 | |
| 114 | ART(wxART_COPY, GTK_STOCK_COPY) |
| 115 | ART(wxART_CUT, GTK_STOCK_CUT) |
| 116 | ART(wxART_PASTE, GTK_STOCK_PASTE) |
| 117 | ART(wxART_DELETE, GTK_STOCK_DELETE) |
| 118 | ART(wxART_NEW, GTK_STOCK_NEW) |
| 119 | |
| 120 | ART(wxART_UNDO, GTK_STOCK_UNDO) |
| 121 | ART(wxART_REDO, GTK_STOCK_REDO) |
| 122 | |
| 123 | ART(wxART_QUIT, GTK_STOCK_QUIT) |
| 124 | |
| 125 | ART(wxART_FIND, GTK_STOCK_FIND) |
| 126 | ART(wxART_FIND_AND_REPLACE, GTK_STOCK_FIND_AND_REPLACE) |
| 127 | |
| 128 | return NULL; |
| 129 | |
| 130 | #undef ART |
| 131 | } |
| 132 | |
| 133 | GtkIconSize wxArtClientToIconSize(const wxArtClient& client) |
| 134 | { |
| 135 | if (client == wxART_TOOLBAR) |
| 136 | return GTK_ICON_SIZE_LARGE_TOOLBAR; |
| 137 | else if (client == wxART_MENU) |
| 138 | return GTK_ICON_SIZE_MENU; |
| 139 | else if (client == wxART_CMN_DIALOG || client == wxART_MESSAGE_BOX) |
| 140 | return GTK_ICON_SIZE_DIALOG; |
| 141 | else if (client == wxART_BUTTON) |
| 142 | return GTK_ICON_SIZE_BUTTON; |
| 143 | else |
| 144 | return GTK_ICON_SIZE_INVALID; // this is arbitrary |
| 145 | } |
| 146 | |
| 147 | static GtkIconSize FindClosestIconSize(const wxSize& size) |
| 148 | { |
| 149 | #define NUM_SIZES 6 |
| 150 | static struct |
| 151 | { |
| 152 | GtkIconSize icon; |
| 153 | gint x, y; |
| 154 | } s_sizes[NUM_SIZES]; |
| 155 | static bool s_sizesInitialized = false; |
| 156 | |
| 157 | if (!s_sizesInitialized) |
| 158 | { |
| 159 | s_sizes[0].icon = GTK_ICON_SIZE_MENU; |
| 160 | s_sizes[1].icon = GTK_ICON_SIZE_SMALL_TOOLBAR; |
| 161 | s_sizes[2].icon = GTK_ICON_SIZE_LARGE_TOOLBAR; |
| 162 | s_sizes[3].icon = GTK_ICON_SIZE_BUTTON; |
| 163 | s_sizes[4].icon = GTK_ICON_SIZE_DND; |
| 164 | s_sizes[5].icon = GTK_ICON_SIZE_DIALOG; |
| 165 | for (size_t i = 0; i < NUM_SIZES; i++) |
| 166 | { |
| 167 | gtk_icon_size_lookup(s_sizes[i].icon, |
| 168 | &s_sizes[i].x, &s_sizes[i].y); |
| 169 | } |
| 170 | s_sizesInitialized = true; |
| 171 | } |
| 172 | |
| 173 | GtkIconSize best = GTK_ICON_SIZE_DIALOG; // presumably largest |
| 174 | unsigned distance = INT_MAX; |
| 175 | for (size_t i = 0; i < NUM_SIZES; i++) |
| 176 | { |
| 177 | // only use larger bitmaps, scaling down looks better than scaling up: |
| 178 | if (size.x > s_sizes[i].x || size.y > s_sizes[i].y) |
| 179 | continue; |
| 180 | |
| 181 | unsigned dist = (size.x - s_sizes[i].x) * (size.x - s_sizes[i].x) + |
| 182 | (size.y - s_sizes[i].y) * (size.y - s_sizes[i].y); |
| 183 | if (dist == 0) |
| 184 | return s_sizes[i].icon; |
| 185 | else if (dist < distance) |
| 186 | { |
| 187 | distance = dist; |
| 188 | best = s_sizes[i].icon; |
| 189 | } |
| 190 | } |
| 191 | return best; |
| 192 | } |
| 193 | |
| 194 | |
| 195 | static GtkStyle *gs_gtkStyle = NULL; |
| 196 | |
| 197 | static GdkPixbuf *CreateStockIcon(const char *stockid, GtkIconSize size) |
| 198 | { |
| 199 | // FIXME: This code is not 100% correct, because stock pixmap are |
| 200 | // context-dependent and may be affected by theme engine, the |
| 201 | // correct value can only be obtained for given GtkWidget object. |
| 202 | // |
| 203 | // Fool-proof implementation of stock bitmaps would extend wxBitmap |
| 204 | // with "stock-id" representation (in addition to pixmap and pixbuf |
| 205 | // ones) and would convert it to pixbuf when rendered. |
| 206 | |
| 207 | if (gs_gtkStyle == NULL) |
| 208 | { |
| 209 | GtkWidget *widget = gtk_button_new(); |
| 210 | gs_gtkStyle = gtk_rc_get_style(widget); |
| 211 | wxASSERT( gs_gtkStyle != NULL ); |
| 212 | g_object_ref(gs_gtkStyle); |
| 213 | gtk_object_sink((GtkObject*)widget); |
| 214 | } |
| 215 | |
| 216 | GtkIconSet *iconset = gtk_style_lookup_icon_set(gs_gtkStyle, stockid); |
| 217 | |
| 218 | if (!iconset) |
| 219 | return NULL; |
| 220 | |
| 221 | return gtk_icon_set_render_icon(iconset, gs_gtkStyle, |
| 222 | gtk_widget_get_default_direction(), |
| 223 | GTK_STATE_NORMAL, size, NULL, NULL); |
| 224 | } |
| 225 | |
| 226 | static GdkPixbuf *CreateThemeIcon(const char *iconname, |
| 227 | GtkIconSize iconsize, const wxSize& sz) |
| 228 | { |
| 229 | wxSize size(sz); |
| 230 | if (size == wxDefaultSize) |
| 231 | { |
| 232 | gtk_icon_size_lookup(iconsize, &size.x, &size.y); |
| 233 | } |
| 234 | |
| 235 | return gtk_icon_theme_load_icon( |
| 236 | gtk_icon_theme_get_default(), |
| 237 | iconname, |
| 238 | size.x, |
| 239 | (GtkIconLookupFlags)0, NULL); |
| 240 | } |
| 241 | |
| 242 | wxBitmap wxGTK2ArtProvider::CreateBitmap(const wxArtID& id, |
| 243 | const wxArtClient& client, |
| 244 | const wxSize& size) |
| 245 | { |
| 246 | wxCharBuffer stockid = wxArtIDToStock(id); |
| 247 | GtkIconSize stocksize = (size == wxDefaultSize) ? |
| 248 | wxArtClientToIconSize(client) : |
| 249 | FindClosestIconSize(size); |
| 250 | |
| 251 | // we must have some size, this is arbitrary |
| 252 | if (stocksize == GTK_ICON_SIZE_INVALID) |
| 253 | stocksize = GTK_ICON_SIZE_BUTTON; |
| 254 | |
| 255 | // allow passing GTK+ stock IDs to wxArtProvider: |
| 256 | if (!stockid) |
| 257 | stockid = id.ToAscii(); |
| 258 | |
| 259 | GdkPixbuf *pixbuf = CreateStockIcon(stockid, stocksize); |
| 260 | if (!pixbuf) |
| 261 | pixbuf = CreateThemeIcon(stockid, stocksize, size); |
| 262 | |
| 263 | if (pixbuf && size != wxDefaultSize && |
| 264 | (size.x != gdk_pixbuf_get_width(pixbuf) || |
| 265 | size.y != gdk_pixbuf_get_height(pixbuf))) |
| 266 | { |
| 267 | GdkPixbuf *p2 = gdk_pixbuf_scale_simple(pixbuf, size.x, size.y, |
| 268 | GDK_INTERP_BILINEAR); |
| 269 | if (p2) |
| 270 | { |
| 271 | g_object_unref (pixbuf); |
| 272 | pixbuf = p2; |
| 273 | } |
| 274 | } |
| 275 | |
| 276 | wxBitmap bmp; |
| 277 | if (pixbuf != NULL) |
| 278 | bmp.SetPixbuf(pixbuf); |
| 279 | |
| 280 | return bmp; |
| 281 | } |
| 282 | |
| 283 | // ---------------------------------------------------------------------------- |
| 284 | // Cleanup |
| 285 | // ---------------------------------------------------------------------------- |
| 286 | |
| 287 | class wxArtGtkModule: public wxModule |
| 288 | { |
| 289 | public: |
| 290 | bool OnInit() { return true; } |
| 291 | void OnExit() |
| 292 | { |
| 293 | if (gs_gtkStyle) |
| 294 | { |
| 295 | g_object_unref(gs_gtkStyle); |
| 296 | gs_gtkStyle = NULL; |
| 297 | } |
| 298 | } |
| 299 | |
| 300 | DECLARE_DYNAMIC_CLASS(wxArtGtkModule) |
| 301 | }; |
| 302 | |
| 303 | IMPLEMENT_DYNAMIC_CLASS(wxArtGtkModule, wxModule) |
| 304 | |
| 305 | #endif // !defined(__WXUNIVERSAL__) |