]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/dc.cpp
supporting native content scaling on OSX
[wxWidgets.git] / src / gtk / dc.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/dc.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // RCS-ID: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #ifdef __WXGTK3__
14
15 #include "wx/window.h"
16 #include "wx/dcclient.h"
17 #include "wx/dcmemory.h"
18 #include "wx/dcscreen.h"
19 #include "wx/icon.h"
20 #include "wx/gtk/dc.h"
21
22 #include <gtk/gtk.h>
23
24 wxGTKCairoDCImpl::wxGTKCairoDCImpl(wxDC* owner)
25 : base_type(owner)
26 {
27 m_width = 0;
28 m_height = 0;
29 }
30
31 wxGTKCairoDCImpl::wxGTKCairoDCImpl(wxDC* owner, int)
32 : base_type(owner, 0)
33 {
34 m_width = 0;
35 m_height = 0;
36 }
37
38 wxGTKCairoDCImpl::wxGTKCairoDCImpl(wxDC* owner, wxWindow* window)
39 : base_type(owner, 0)
40 {
41 m_window = window;
42 m_font = window->GetFont();
43 m_textForegroundColour = window->GetForegroundColour();
44 m_textBackgroundColour = window->GetBackgroundColour();
45 m_width = 0;
46 m_height = 0;
47 }
48
49 void wxGTKCairoDCImpl::DoDrawBitmap(const wxBitmap& bitmap, int x, int y, bool useMask)
50 {
51 wxCHECK_RET(IsOk(), "invalid DC");
52
53 cairo_t* cr = NULL;
54 if (m_graphicContext)
55 cr = static_cast<cairo_t*>(m_graphicContext->GetNativeContext());
56 if (cr)
57 {
58 cairo_save(cr);
59 bitmap.Draw(cr, x, y, useMask, &m_textForegroundColour, &m_textBackgroundColour);
60 cairo_restore(cr);
61 }
62 }
63
64 void wxGTKCairoDCImpl::DoDrawIcon(const wxIcon& icon, int x, int y)
65 {
66 DoDrawBitmap(icon, x, y, true);
67 }
68
69 #if wxUSE_IMAGE
70 bool wxDoFloodFill(wxDC* dc, int x, int y, const wxColour& col, wxFloodFillStyle style);
71
72 bool wxGTKCairoDCImpl::DoFloodFill(int x, int y, const wxColour& col, wxFloodFillStyle style)
73 {
74 return wxDoFloodFill(GetOwner(), x, y, col, style);
75 }
76 #endif
77
78 wxBitmap wxGTKCairoDCImpl::DoGetAsBitmap(const wxRect* /*subrect*/) const
79 {
80 wxFAIL_MSG("DoGetAsBitmap not implemented");
81 return wxBitmap();
82 }
83
84 bool wxGTKCairoDCImpl::DoGetPixel(int x, int y, wxColour* col) const
85 {
86 if (col)
87 {
88 cairo_t* cr = NULL;
89 if (m_graphicContext)
90 cr = static_cast<cairo_t*>(m_graphicContext->GetNativeContext());
91 if (cr)
92 {
93 cairo_surface_t* surface = cairo_get_target(cr);
94 x = LogicalToDeviceX(x);
95 y = LogicalToDeviceY(y);
96 GdkPixbuf* pixbuf = gdk_pixbuf_get_from_surface(surface, x, y, 1, 1);
97 if (pixbuf)
98 {
99 const guchar* src = gdk_pixbuf_get_pixels(pixbuf);
100 col->Set(src[0], src[1], src[2]);
101 g_object_unref(pixbuf);
102 return true;
103 }
104 *col = wxColour();
105 }
106 }
107 return false;
108 }
109
110 void wxGTKCairoDCImpl::DoGetSize(int* width, int* height) const
111 {
112 if (width)
113 *width = m_width;
114 if (height)
115 *height = m_height;
116 }
117
118 bool wxGTKCairoDCImpl::DoStretchBlit(int xdest, int ydest, int dstWidth, int dstHeight, wxDC* source, int xsrc, int ysrc, int srcWidth, int srcHeight, wxRasterOperationMode rop, bool useMask, int xsrcMask, int ysrcMask)
119 {
120 wxCHECK_MSG(IsOk(), false, "invalid DC");
121 wxCHECK_MSG(source && source->IsOk(), false, "invalid source DC");
122
123 cairo_t* cr = NULL;
124 if (m_graphicContext)
125 cr = static_cast<cairo_t*>(m_graphicContext->GetNativeContext());
126 cairo_t* cr_src = NULL;
127 wxGraphicsContext* gc_src = source->GetGraphicsContext();
128 if (gc_src)
129 cr_src = static_cast<cairo_t*>(gc_src->GetNativeContext());
130
131 if (cr == NULL || cr_src == NULL)
132 return false;
133
134 const int xsrc_dev = source->LogicalToDeviceX(xsrc);
135 const int ysrc_dev = source->LogicalToDeviceY(ysrc);
136
137 cairo_surface_t* surface = cairo_get_target(cr_src);
138 cairo_surface_flush(surface);
139 cairo_save(cr);
140 cairo_translate(cr, xdest, ydest);
141 cairo_rectangle(cr, 0, 0, dstWidth, dstHeight);
142 double sx, sy;
143 source->GetUserScale(&sx, &sy);
144 cairo_scale(cr, dstWidth / (sx * srcWidth), dstHeight / (sy * srcHeight));
145 cairo_set_source_surface(cr, surface, -xsrc_dev, -ysrc_dev);
146 const wxRasterOperationMode rop_save = m_logicalFunction;
147 SetLogicalFunction(rop);
148 cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST);
149 cairo_surface_t* maskSurf = NULL;
150 if (useMask)
151 {
152 const wxBitmap& bitmap = source->GetImpl()->GetSelectedBitmap();
153 if (bitmap.IsOk())
154 {
155 wxMask* mask = bitmap.GetMask();
156 if (mask)
157 maskSurf = *mask;
158 }
159 }
160 if (maskSurf)
161 {
162 int xsrcMask_dev = xsrc_dev;
163 int ysrcMask_dev = ysrc_dev;
164 if (xsrcMask != -1)
165 xsrcMask_dev = source->LogicalToDeviceX(xsrcMask);
166 if (ysrcMask != -1)
167 ysrcMask_dev = source->LogicalToDeviceY(ysrcMask);
168 cairo_clip(cr);
169 cairo_mask_surface(cr, maskSurf, -xsrcMask_dev, -ysrcMask_dev);
170 }
171 else
172 {
173 cairo_fill(cr);
174 }
175 cairo_restore(cr);
176 m_logicalFunction = rop_save;
177 return true;
178 }
179
180 void* wxGTKCairoDCImpl::GetCairoContext() const
181 {
182 cairo_t* cr = NULL;
183 if (m_graphicContext)
184 cr = static_cast<cairo_t*>(m_graphicContext->GetNativeContext());
185 if (cr)
186 cairo_reference(cr);
187 return cr;
188 }
189 //-----------------------------------------------------------------------------
190
191 wxWindowDCImpl::wxWindowDCImpl(wxWindowDC* owner, wxWindow* window)
192 : base_type(owner, window)
193 {
194 GtkWidget* widget = window->m_wxwindow;
195 if (widget == NULL)
196 widget = window->m_widget;
197 GdkWindow* gdkWindow = NULL;
198 if (widget)
199 {
200 gdkWindow = gtk_widget_get_window(widget);
201 m_ok = true;
202 }
203 if (gdkWindow)
204 {
205 cairo_t* cr = gdk_cairo_create(gdkWindow);
206 SetGraphicsContext(wxGraphicsContext::CreateFromNative(cr));
207 GtkAllocation a;
208 gtk_widget_get_allocation(widget, &a);
209 int x, y;
210 if (gtk_widget_get_has_window(widget))
211 {
212 m_width = gdk_window_get_width(gdkWindow);
213 m_height = gdk_window_get_height(gdkWindow);
214 x = m_width - a.width;
215 y = m_height - a.height;
216 }
217 else
218 {
219 m_width = a.width;
220 m_height = a.height;
221 x = a.x;
222 y = a.y;
223 cairo_rectangle(cr, a.x, a.y, a.width, a.height);
224 cairo_clip(cr);
225 }
226 if (x || y)
227 SetDeviceLocalOrigin(x, y);
228 }
229 else
230 SetGraphicsContext(wxGraphicsContext::Create());
231 }
232 //-----------------------------------------------------------------------------
233
234 wxClientDCImpl::wxClientDCImpl(wxClientDC* owner, wxWindow* window)
235 : base_type(owner, window)
236 {
237 GtkWidget* widget = window->m_wxwindow;
238 if (widget == NULL)
239 widget = window->m_widget;
240 GdkWindow* gdkWindow = NULL;
241 if (widget)
242 {
243 gdkWindow = gtk_widget_get_window(widget);
244 m_ok = true;
245 }
246 if (gdkWindow)
247 {
248 cairo_t* cr = gdk_cairo_create(gdkWindow);
249 SetGraphicsContext(wxGraphicsContext::CreateFromNative(cr));
250 if (gtk_widget_get_has_window(widget))
251 {
252 m_width = gdk_window_get_width(gdkWindow);
253 m_height = gdk_window_get_height(gdkWindow);
254 }
255 else
256 {
257 GtkAllocation a;
258 gtk_widget_get_allocation(widget, &a);
259 m_width = a.width;
260 m_height = a.height;
261 cairo_rectangle(cr, a.x, a.y, a.width, a.height);
262 cairo_clip(cr);
263 SetDeviceLocalOrigin(a.x, a.y);
264 }
265 }
266 else
267 SetGraphicsContext(wxGraphicsContext::Create());
268 }
269 //-----------------------------------------------------------------------------
270
271 wxPaintDCImpl::wxPaintDCImpl(wxPaintDC* owner, wxWindow* window)
272 : base_type(owner, window)
273 {
274 cairo_t* cr = window->GTKPaintContext();
275 wxCHECK_RET(cr, "using wxPaintDC without being in a native paint event");
276 GdkWindow* gdkWindow = gtk_widget_get_window(window->m_wxwindow);
277 m_width = gdk_window_get_width(gdkWindow);
278 m_height = gdk_window_get_height(gdkWindow);
279 cairo_reference(cr);
280 SetGraphicsContext(wxGraphicsContext::CreateFromNative(cr));
281 }
282 //-----------------------------------------------------------------------------
283
284 wxScreenDCImpl::wxScreenDCImpl(wxScreenDC* owner)
285 : base_type(owner, 0)
286 {
287 GdkWindow* window = gdk_get_default_root_window();
288 m_width = gdk_window_get_width(window);
289 m_height = gdk_window_get_height(window);
290 cairo_t* cr = gdk_cairo_create(window);
291 SetGraphicsContext(wxGraphicsContext::CreateFromNative(cr));
292 }
293 //-----------------------------------------------------------------------------
294
295 wxMemoryDCImpl::wxMemoryDCImpl(wxMemoryDC* owner)
296 : base_type(owner)
297 {
298 m_ok = false;
299 }
300
301 wxMemoryDCImpl::wxMemoryDCImpl(wxMemoryDC* owner, wxBitmap& bitmap)
302 : base_type(owner, 0)
303 , m_bitmap(bitmap)
304 {
305 Setup();
306 }
307
308 wxMemoryDCImpl::wxMemoryDCImpl(wxMemoryDC* owner, wxDC*)
309 : base_type(owner)
310 {
311 m_ok = false;
312 }
313
314 wxBitmap wxMemoryDCImpl::DoGetAsBitmap(const wxRect* subrect) const
315 {
316 return subrect ? m_bitmap.GetSubBitmap(*subrect) : m_bitmap;
317 }
318
319 void wxMemoryDCImpl::DoSelect(const wxBitmap& bitmap)
320 {
321 m_bitmap = bitmap;
322 Setup();
323 }
324
325 const wxBitmap& wxMemoryDCImpl::GetSelectedBitmap() const
326 {
327 return m_bitmap;
328 }
329
330 wxBitmap& wxMemoryDCImpl::GetSelectedBitmap()
331 {
332 return m_bitmap;
333 }
334
335 void wxMemoryDCImpl::Setup()
336 {
337 wxGraphicsContext* gc = NULL;
338 m_ok = m_bitmap.IsOk();
339 if (m_ok)
340 {
341 m_width = m_bitmap.GetWidth();
342 m_height = m_bitmap.GetHeight();
343 cairo_t* cr = m_bitmap.CairoCreate();
344 gc = wxGraphicsContext::CreateFromNative(cr);
345 }
346 SetGraphicsContext(gc);
347 }
348 //-----------------------------------------------------------------------------
349
350 wxGTKCairoDC::wxGTKCairoDC(cairo_t* cr)
351 : base_type(new wxGTKCairoDCImpl(this, 0))
352 {
353 cairo_reference(cr);
354 SetGraphicsContext(wxGraphicsContext::CreateFromNative(cr));
355 }
356
357 #else
358
359 #include "wx/gtk/dc.h"
360
361 //-----------------------------------------------------------------------------
362 // wxGTKDCImpl
363 //-----------------------------------------------------------------------------
364
365 IMPLEMENT_ABSTRACT_CLASS(wxGTKDCImpl, wxDCImpl)
366
367 wxGTKDCImpl::wxGTKDCImpl( wxDC *owner )
368 : wxDCImpl( owner )
369 {
370 m_ok = FALSE;
371
372 m_pen = *wxBLACK_PEN;
373 m_font = *wxNORMAL_FONT;
374 m_brush = *wxWHITE_BRUSH;
375 }
376
377 wxGTKDCImpl::~wxGTKDCImpl()
378 {
379 }
380
381 void wxGTKDCImpl::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
382 {
383 m_clipping = TRUE;
384 m_clipX1 = x;
385 m_clipY1 = y;
386 m_clipX2 = x + width;
387 m_clipY2 = y + height;
388 }
389
390 // ---------------------------------------------------------------------------
391 // get DC capabilities
392 // ---------------------------------------------------------------------------
393
394 void wxGTKDCImpl::DoGetSizeMM( int* width, int* height ) const
395 {
396 int w = 0;
397 int h = 0;
398 GetOwner()->GetSize( &w, &h );
399 if (width) *width = int( double(w) / (m_userScaleX*m_mm_to_pix_x) );
400 if (height) *height = int( double(h) / (m_userScaleY*m_mm_to_pix_y) );
401 }
402
403 // Resolution in pixels per logical inch
404 wxSize wxGTKDCImpl::GetPPI() const
405 {
406 // TODO (should probably be pure virtual)
407 return wxSize(0, 0);
408 }
409 #endif