X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b737ad10dec946cd7d5e38c43c666e8efe89f0ae..8a31648287be0ef976f133de2786b137f1e98340:/src/gtk/artgtk.cpp diff --git a/src/gtk/artgtk.cpp b/src/gtk/artgtk.cpp index 47aa4c93db..88c32a4cac 100644 --- a/src/gtk/artgtk.cpp +++ b/src/gtk/artgtk.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: artstd.cpp +// Name: src/gtk/artgtk.cpp // Purpose: stock wxArtProvider instance with native GTK+ stock icons // Author: Vaclav Slavik // Modified by: @@ -20,12 +20,8 @@ #pragma hdrstop #endif -#if defined(__WXGTK20__) && !defined(__WXUNIVERSAL__) - #include "wx/artprov.h" -#include "wx/module.h" - -#include +#include "wx/gtk/private.h" // compatibility with older GTK+ versions: #ifndef GTK_STOCK_FILE @@ -45,27 +41,32 @@ class wxGTK2ArtProvider : public wxArtProvider protected: virtual wxBitmap CreateBitmap(const wxArtID& id, const wxArtClient& client, const wxSize& size); + virtual wxIconBundle CreateIconBundle(const wxArtID& id, + const wxArtClient& client); }; /*static*/ void wxArtProvider::InitNativeProvider() { - wxArtProvider::PushProvider(new wxGTK2ArtProvider); + Push(new wxGTK2ArtProvider); } // ---------------------------------------------------------------------------- // CreateBitmap routine // ---------------------------------------------------------------------------- -static const char *wxArtIDToStock(const wxArtID& id) +namespace +{ + +wxString wxArtIDToStock(const wxArtID& id) { #define ART(wxid, gtkid) \ if (id == wxid) return gtkid; - + ART(wxART_ERROR, GTK_STOCK_DIALOG_ERROR) ART(wxART_INFORMATION, GTK_STOCK_DIALOG_INFO) ART(wxART_WARNING, GTK_STOCK_DIALOG_WARNING) ART(wxART_QUESTION, GTK_STOCK_DIALOG_QUESTION) - + //ART(wxART_HELP_SIDE_PANEL, ) ART(wxART_HELP_SETTINGS, GTK_STOCK_SELECT_FONT) //ART(wxART_HELP_BOOK, ) @@ -80,6 +81,8 @@ static const char *wxArtIDToStock(const wxArtID& id) ART(wxART_GO_DOWN, GTK_STOCK_GO_DOWN) ART(wxART_GO_TO_PARENT, GTK_STOCK_GO_UP) ART(wxART_GO_HOME, GTK_STOCK_HOME) + ART(wxART_GOTO_FIRST, GTK_STOCK_GOTO_FIRST) + ART(wxART_GOTO_LAST, GTK_STOCK_GOTO_LAST) ART(wxART_FILE_OPEN, GTK_STOCK_OPEN) ART(wxART_PRINT, GTK_STOCK_PRINT) ART(wxART_HELP, GTK_STOCK_HELP) @@ -87,17 +90,14 @@ static const char *wxArtIDToStock(const wxArtID& id) //ART(wxART_REPORT_VIEW, ) //ART(wxART_LIST_VIEW, ) //ART(wxART_NEW_DIR, ) -#ifdef __WXGTK24__ ART(wxART_FOLDER, GTK_STOCK_DIRECTORY) ART(wxART_FOLDER_OPEN, GTK_STOCK_DIRECTORY) -#endif //ART(wxART_GO_DIR_UP, ) ART(wxART_EXECUTABLE_FILE, GTK_STOCK_EXECUTE) ART(wxART_NORMAL_FILE, GTK_STOCK_FILE) ART(wxART_TICK_MARK, GTK_STOCK_APPLY) ART(wxART_CROSS_MARK, GTK_STOCK_CANCEL) -#ifdef __WXGTK24__ ART(wxART_FLOPPY, GTK_STOCK_FLOPPY) ART(wxART_CDROM, GTK_STOCK_CDROM) ART(wxART_HARDDISK, GTK_STOCK_HARDDISK) @@ -110,36 +110,43 @@ static const char *wxArtIDToStock(const wxArtID& id) ART(wxART_CUT, GTK_STOCK_CUT) ART(wxART_PASTE, GTK_STOCK_PASTE) ART(wxART_DELETE, GTK_STOCK_DELETE) + ART(wxART_NEW, GTK_STOCK_NEW) ART(wxART_UNDO, GTK_STOCK_UNDO) ART(wxART_REDO, GTK_STOCK_REDO) + ART(wxART_PLUS, GTK_STOCK_ADD) + ART(wxART_MINUS, GTK_STOCK_REMOVE) + + ART(wxART_CLOSE, GTK_STOCK_CLOSE) ART(wxART_QUIT, GTK_STOCK_QUIT) ART(wxART_FIND, GTK_STOCK_FIND) ART(wxART_FIND_AND_REPLACE, GTK_STOCK_FIND_AND_REPLACE) -#endif - - return NULL; - + #undef ART + + // allow passing GTK+ stock IDs to wxArtProvider -- if a recognized wx + // ID wasn't found, pass it to GTK+ in the hope it is a GTK+ or theme + // icon name: + return id; } -GtkIconSize wxArtClientToIconSize(const wxArtClient& client) +GtkIconSize ArtClientToIconSize(const wxArtClient& client) { if (client == wxART_TOOLBAR) return GTK_ICON_SIZE_LARGE_TOOLBAR; - else if (client == wxART_MENU) + else if (client == wxART_MENU || client == wxART_FRAME_ICON) return GTK_ICON_SIZE_MENU; else if (client == wxART_CMN_DIALOG || client == wxART_MESSAGE_BOX) return GTK_ICON_SIZE_DIALOG; else if (client == wxART_BUTTON) return GTK_ICON_SIZE_BUTTON; else - return GTK_ICON_SIZE_BUTTON; // this is arbitrary + return GTK_ICON_SIZE_INVALID; // this is arbitrary } -static GtkIconSize FindClosestIconSize(const wxSize& size) +GtkIconSize FindClosestIconSize(const wxSize& size) { #define NUM_SIZES 6 static struct @@ -172,8 +179,8 @@ static GtkIconSize FindClosestIconSize(const wxSize& size) // only use larger bitmaps, scaling down looks better than scaling up: if (size.x > s_sizes[i].x || size.y > s_sizes[i].y) continue; - - unsigned dist = (size.x - s_sizes[i].x) * (size.x - s_sizes[i].x) + + + unsigned dist = (size.x - s_sizes[i].x) * (size.x - s_sizes[i].x) + (size.y - s_sizes[i].y) * (size.y - s_sizes[i].y); if (dist == 0) return s_sizes[i].icon; @@ -181,83 +188,100 @@ static GtkIconSize FindClosestIconSize(const wxSize& size) { distance = dist; best = s_sizes[i].icon; - } + } } return best; } - -static GtkStyle *gs_gtkStyle = NULL; - -static GdkPixbuf *CreateStockIcon(const char *stockid, GtkIconSize size) +GdkPixbuf *CreateStockIcon(const char *stockid, GtkIconSize size) { // FIXME: This code is not 100% correct, because stock pixmap are // context-dependent and may be affected by theme engine, the // correct value can only be obtained for given GtkWidget object. - // + // // Fool-proof implementation of stock bitmaps would extend wxBitmap // with "stock-id" representation (in addition to pixmap and pixbuf // ones) and would convert it to pixbuf when rendered. - - if (gs_gtkStyle == NULL) - { - GtkWidget *widget = gtk_button_new(); - gs_gtkStyle = gtk_rc_get_style(widget); - wxASSERT( gs_gtkStyle != NULL ); - g_object_ref(G_OBJECT(gs_gtkStyle)); - gtk_widget_destroy(widget); - } - GtkIconSet *iconset = gtk_style_lookup_icon_set(gs_gtkStyle, stockid); + GtkStyle* style = gtk_widget_get_style(wxGTKPrivate::GetButtonWidget()); + GtkIconSet* iconset = gtk_style_lookup_icon_set(style, stockid); if (!iconset) return NULL; - return gtk_icon_set_render_icon(iconset, gs_gtkStyle, + return gtk_icon_set_render_icon(iconset, style, gtk_widget_get_default_direction(), GTK_STATE_NORMAL, size, NULL, NULL); } -#ifdef __WXGTK24__ -static GdkPixbuf *CreateThemeIcon(const char *iconname, - GtkIconSize iconsize, const wxSize& sz) +GdkPixbuf *CreateThemeIcon(const char *iconname, int size) { - wxSize size(sz); - if (size == wxDefaultSize) + return gtk_icon_theme_load_icon + ( + gtk_icon_theme_get_default(), + iconname, + size, + (GtkIconLookupFlags)0, + NULL + ); +} + + +// creates either stock or theme icon +GdkPixbuf *CreateGtkIcon(const char *icon_name, + GtkIconSize stock_size, const wxSize& pixel_size) +{ + // try stock GTK+ icon first + GdkPixbuf *pixbuf = CreateStockIcon(icon_name, stock_size); + if ( pixbuf ) + return pixbuf; + + // if that fails, try theme icon + wxSize size(pixel_size); + if ( pixel_size == wxDefaultSize ) + gtk_icon_size_lookup(stock_size, &size.x, &size.y); + return CreateThemeIcon(icon_name, size.x); +} + +template +wxIconBundle DoCreateIconBundle(const char *stockid, + const SizeType *sizes_from, + const SizeType *sizes_to, + LoaderFunc get_icon) + +{ + wxIconBundle bundle; + + for ( const SizeType *i = sizes_from; i != sizes_to; ++i ) { - gtk_icon_size_lookup(iconsize, &size.x, &size.y); + GdkPixbuf *pixbuf = get_icon(stockid, *i); + if ( !pixbuf ) + continue; + + wxIcon icon; + icon.SetPixbuf(pixbuf); + bundle.AddIcon(icon); } - - return gtk_icon_theme_load_icon( - gtk_icon_theme_get_default(), - iconname, - size.x, - (GtkIconLookupFlags)0, NULL); + + return bundle; } -#endif + +} // anonymous namespace wxBitmap wxGTK2ArtProvider::CreateBitmap(const wxArtID& id, const wxArtClient& client, const wxSize& size) { - wxCharBuffer stockid = wxArtIDToStock(id); + const wxString stockid = wxArtIDToStock(id); + GtkIconSize stocksize = (size == wxDefaultSize) ? - wxArtClientToIconSize(client) : + ArtClientToIconSize(client) : FindClosestIconSize(size); + // we must have some size, this is arbitrary + if (stocksize == GTK_ICON_SIZE_INVALID) + stocksize = GTK_ICON_SIZE_BUTTON; - // allow passing GTK+ stock IDs to wxArtProvider: - if (!stockid) - stockid = id.ToAscii(); - - GdkPixbuf *pixbuf = CreateStockIcon(stockid, stocksize); - -#ifdef __WXGTK24__ - if (!gtk_check_version(2,4,0)) - { - if (!pixbuf) - pixbuf = CreateThemeIcon(stockid, stocksize, size); - } -#endif + GdkPixbuf *pixbuf = CreateGtkIcon(stockid.utf8_str(), stocksize, size); if (pixbuf && size != wxDefaultSize && (size.x != gdk_pixbuf_get_width(pixbuf) || @@ -267,42 +291,85 @@ wxBitmap wxGTK2ArtProvider::CreateBitmap(const wxArtID& id, GDK_INTERP_BILINEAR); if (p2) { - gdk_pixbuf_unref(pixbuf); + g_object_unref (pixbuf); pixbuf = p2; } } - - if (!pixbuf) - return wxNullBitmap; wxBitmap bmp; - bmp.SetWidth(gdk_pixbuf_get_width(pixbuf)); - bmp.SetHeight(gdk_pixbuf_get_height(pixbuf)); - bmp.SetPixbuf(pixbuf); + if (pixbuf != NULL) + bmp.SetPixbuf(pixbuf); return bmp; } -// ---------------------------------------------------------------------------- -// Cleanup -// ---------------------------------------------------------------------------- - -class wxArtGtkModule: public wxModule +wxIconBundle +wxGTK2ArtProvider::CreateIconBundle(const wxArtID& id, + const wxArtClient& WXUNUSED(client)) { -public: - bool OnInit() { return true; } - void OnExit() + const wxString stockid = wxArtIDToStock(id); + + // try to load the bundle as stock icon first + GtkStyle* style = gtk_widget_get_style(wxGTKPrivate::GetButtonWidget()); + GtkIconSet* iconset = gtk_style_lookup_icon_set(style, stockid.utf8_str()); + if ( iconset ) { - if (gs_gtkStyle) - { - g_object_unref(G_OBJECT(gs_gtkStyle)); - gs_gtkStyle = NULL; - } + GtkIconSize *sizes; + gint n_sizes; + gtk_icon_set_get_sizes(iconset, &sizes, &n_sizes); + wxIconBundle bundle = DoCreateIconBundle + ( + stockid.utf8_str(), + sizes, sizes + n_sizes, + &CreateStockIcon + ); + g_free(sizes); + return bundle; } - DECLARE_DYNAMIC_CLASS(wxArtGtkModule) -}; + // otherwise try icon themes +#ifdef __WXGTK26__ + if ( !gtk_check_version(2,6,0) ) + { + gint *sizes = gtk_icon_theme_get_icon_sizes + ( + gtk_icon_theme_get_default(), + stockid.utf8_str() + ); + if ( !sizes ) + return wxNullIconBundle; + + gint *last = sizes; + while ( *last ) + last++; + + wxIconBundle bundle = DoCreateIconBundle + ( + stockid.utf8_str(), + sizes, last, + &CreateThemeIcon + ); + g_free(sizes); + return bundle; + } +#endif // __WXGTK26__ -IMPLEMENT_DYNAMIC_CLASS(wxArtGtkModule, wxModule) + return wxNullIconBundle; +} + +// ---------------------------------------------------------------------------- +// wxArtProvider::GetNativeSizeHint() +// ---------------------------------------------------------------------------- -#endif // defined(__WXGTK20__) && !defined(__WXUNIVERSAL__) +/*static*/ +wxSize wxArtProvider::GetNativeSizeHint(const wxArtClient& client) +{ + // Gtk has specific sizes for each client, see artgtk.cpp + GtkIconSize gtk_size = ArtClientToIconSize(client); + // no size hints for this client + if (gtk_size == GTK_ICON_SIZE_INVALID) + return wxDefaultSize; + gint width, height; + gtk_icon_size_lookup( gtk_size, &width, &height); + return wxSize(width, height); +}