1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/gtk/image_gtk.cpp
3 // Author:      Paul Cornett
4 // Copyright:   (c) 2020 Paul Cornett
5 // Licence:     wxWindows licence
6 ///////////////////////////////////////////////////////////////////////////////
7 
8 #include "wx/wxprec.h"
9 
10 #include "wx/bitmap.h"
11 #include "wx/window.h"
12 
13 #include "wx/gtk/private/wrapgtk.h"
14 #include "wx/gtk/private/image.h"
15 
16 namespace
17 {
18 // Default provider for HiDPI common case
19 struct BitmapProviderDefault: wxGtkImage::BitmapProvider
20 {
21 #ifdef __WXGTK3__
BitmapProviderDefault__anon7bed05fd0111::BitmapProviderDefault22     BitmapProviderDefault(wxWindow* win) : m_win(win) { }
23     virtual wxBitmap Get() const wxOVERRIDE;
24     virtual void Set(const wxBitmap& bitmap) wxOVERRIDE;
25     wxWindow* const m_win;
26     wxBitmap m_bitmap;
27     wxBitmap m_bitmapDisabled;
28 #else
29     BitmapProviderDefault(wxWindow*) { }
30     virtual wxBitmap Get() const wxOVERRIDE { return wxBitmap(); }
31 #endif
32 };
33 
34 #ifdef __WXGTK3__
Get() const35 wxBitmap BitmapProviderDefault::Get() const
36 {
37     return (m_win == NULL || m_win->IsEnabled()) ? m_bitmap : m_bitmapDisabled;
38 }
39 
Set(const wxBitmap & bitmap)40 void BitmapProviderDefault::Set(const wxBitmap& bitmap)
41 {
42     m_bitmap.UnRef();
43     m_bitmapDisabled.UnRef();
44     if (bitmap.IsOk() && bitmap.GetScaleFactor() > 1)
45     {
46         m_bitmap = bitmap;
47         if (m_win)
48             m_bitmapDisabled = bitmap.CreateDisabled();
49     }
50 }
51 #endif // __WXGTK3__
52 } // namespace
53 
54 extern "C" {
55 static void wxGtkImageClassInit(void* g_class, void* class_data);
56 }
57 
Type()58 GType wxGtkImage::Type()
59 {
60     static GType type;
61     if (type == 0)
62     {
63         const GTypeInfo info = {
64             sizeof(GtkImageClass),
65             NULL, NULL,
66             wxGtkImageClassInit, NULL, NULL,
67             sizeof(wxGtkImage), 0, NULL,
68             NULL
69         };
70         type = g_type_register_static(
71             GTK_TYPE_IMAGE, "wxGtkImage", &info, GTypeFlags(0));
72     }
73     return type;
74 }
75 
New(BitmapProvider * provider)76 GtkWidget* wxGtkImage::New(BitmapProvider* provider)
77 {
78     wxGtkImage* image = WX_GTK_IMAGE(g_object_new(Type(), NULL));
79     image->m_provider = provider;
80     return GTK_WIDGET(image);
81 }
82 
New(wxWindow * win)83 GtkWidget* wxGtkImage::New(wxWindow* win)
84 {
85     return New(new BitmapProviderDefault(win));
86 }
87 
Set(const wxBitmap & bitmap)88 void wxGtkImage::Set(const wxBitmap& bitmap)
89 {
90     m_provider->Set(bitmap);
91 
92     GdkPixbuf* pixbuf = NULL;
93     GdkPixbuf* pixbufNew = NULL;
94     if (bitmap.IsOk())
95     {
96         if (bitmap.GetScaleFactor() <= 1)
97             pixbuf = bitmap.GetPixbuf();
98         else
99         {
100             // Placeholder pixbuf for correct size
101             pixbufNew =
102             pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, false, 8,
103                 int(bitmap.GetScaledWidth()), int(bitmap.GetScaledHeight()));
104         }
105     }
106     gtk_image_set_from_pixbuf(GTK_IMAGE(this), pixbuf);
107     if (pixbufNew)
108         g_object_unref(pixbufNew);
109 }
110 
111 static GtkWidgetClass* wxGtkImageParentClass;
112 
113 extern "C"
114 {
115 #ifdef __WXGTK3__
wxGtkImageDraw(GtkWidget * widget,cairo_t * cr)116 static gboolean wxGtkImageDraw(GtkWidget* widget, cairo_t* cr)
117 #else
118 static gboolean wxGtkImageDraw(GtkWidget* widget, GdkEventExpose* event)
119 #endif
120 {
121     wxGtkImage* image = WX_GTK_IMAGE(widget);
122     const wxBitmap bitmap(image->m_provider->Get());
123     if (!bitmap.IsOk())
124     {
125 #ifdef __WXGTK3__
126         return wxGtkImageParentClass->draw(widget, cr);
127 #else
128         return wxGtkImageParentClass->expose_event(widget, event);
129 #endif
130     }
131 
132     GtkAllocation alloc;
133     gtk_widget_get_allocation(widget, &alloc);
134     int x = (alloc.width  - int(bitmap.GetScaledWidth() )) / 2;
135     int y = (alloc.height - int(bitmap.GetScaledHeight())) / 2;
136 #ifdef __WXGTK3__
137     gtk_render_background(gtk_widget_get_style_context(widget),
138         cr, 0, 0, alloc.width, alloc.height);
139     bitmap.Draw(cr, x, y);
140 #else
141     x += alloc.x;
142     y += alloc.y;
143     gdk_draw_pixbuf(
144         gtk_widget_get_window(widget), gtk_widget_get_style(widget)->black_gc, bitmap.GetPixbuf(),
145         0, 0, x, y,
146         -1, -1, GDK_RGB_DITHER_NORMAL, 0, 0);
147 #endif
148     return false;
149 }
150 
wxGtkImageFinalize(GObject * object)151 static void wxGtkImageFinalize(GObject* object)
152 {
153     wxGtkImage* image = WX_GTK_IMAGE(object);
154     delete image->m_provider;
155     image->m_provider = NULL;
156     G_OBJECT_CLASS(wxGtkImageParentClass)->finalize(object);
157 }
158 
wxGtkImageClassInit(void * g_class,void *)159 static void wxGtkImageClassInit(void* g_class, void* /*class_data*/)
160 {
161 #ifdef __WXGTK3__
162     GTK_WIDGET_CLASS(g_class)->draw = wxGtkImageDraw;
163 #else
164     GTK_WIDGET_CLASS(g_class)->expose_event = wxGtkImageDraw;
165 #endif
166     G_OBJECT_CLASS(g_class)->finalize = wxGtkImageFinalize;
167     wxGtkImageParentClass = GTK_WIDGET_CLASS(g_type_class_peek_parent(g_class));
168 }
169 } // extern "C"
170