1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/dc.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Copyright: (c) 1998 Robert Roebling
6 // Licence: wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
8
9 // For compilers that support precompilation, includes "wx.h".
10 #include "wx/wxprec.h"
11
12 #ifdef __WXGTK3__
13
14 #include "wx/window.h"
15 #include "wx/dcclient.h"
16 #include "wx/dcmemory.h"
17 #include "wx/dcscreen.h"
18 #include "wx/display.h"
19 #include "wx/gdicmn.h"
20 #include "wx/icon.h"
21 #include "wx/gtk/dc.h"
22
23 #include "wx/gtk/private/wrapgtk.h"
24
wxGTKCairoDCImpl(wxDC * owner)25 wxGTKCairoDCImpl::wxGTKCairoDCImpl(wxDC* owner)
26 : wxGCDCImpl(owner)
27 {
28 m_layoutDir = wxLayout_Default;
29 }
30
wxGTKCairoDCImpl(wxDC * owner,wxWindow * window,wxLayoutDirection dir,int width)31 wxGTKCairoDCImpl::wxGTKCairoDCImpl(wxDC* owner, wxWindow* window, wxLayoutDirection dir, int width)
32 : wxGCDCImpl(owner, 0)
33 , m_size(width, 0)
34 {
35 m_layoutDir = dir;
36 if ( window )
37 {
38 m_window = window;
39 m_font = window->GetFont();
40 m_textForegroundColour = window->GetForegroundColour();
41 m_textBackgroundColour = window->GetBackgroundColour();
42 m_contentScaleFactor = window->GetContentScaleFactor();
43 }
44 }
45
InitSize(GdkWindow * window)46 void wxGTKCairoDCImpl::InitSize(GdkWindow* window)
47 {
48 m_size.x = gdk_window_get_width(window);
49 m_size.y = gdk_window_get_height(window);
50 }
51
DoDrawBitmap(const wxBitmap & bitmap,int x,int y,bool useMask)52 void wxGTKCairoDCImpl::DoDrawBitmap(const wxBitmap& bitmap, int x, int y, bool useMask)
53 {
54 wxCHECK_RET(IsOk(), "invalid DC");
55
56 cairo_t* cr = NULL;
57 if (m_graphicContext)
58 cr = static_cast<cairo_t*>(m_graphicContext->GetNativeContext());
59 if (cr)
60 {
61 cairo_save(cr);
62 if (m_layoutDir == wxLayout_RightToLeft)
63 {
64 // bitmap is not mirrored
65 cairo_scale(cr, -1, 1);
66 x = -x - bitmap.GetWidth();
67 }
68 bitmap.Draw(cr, x, y, useMask, &m_textForegroundColour, &m_textBackgroundColour);
69 cairo_restore(cr);
70 }
71 }
72
DoDrawIcon(const wxIcon & icon,int x,int y)73 void wxGTKCairoDCImpl::DoDrawIcon(const wxIcon& icon, int x, int y)
74 {
75 DoDrawBitmap(icon, x, y, true);
76 }
77
78 #if wxUSE_IMAGE
79 bool wxDoFloodFill(wxDC* dc, int x, int y, const wxColour& col, wxFloodFillStyle style);
80
DoFloodFill(int x,int y,const wxColour & col,wxFloodFillStyle style)81 bool wxGTKCairoDCImpl::DoFloodFill(int x, int y, const wxColour& col, wxFloodFillStyle style)
82 {
83 return wxDoFloodFill(GetOwner(), x, y, col, style);
84 }
85 #endif
86
DoDrawText(const wxString & text,int x,int y)87 void wxGTKCairoDCImpl::DoDrawText(const wxString& text, int x, int y)
88 {
89 wxCHECK_RET(IsOk(), "invalid DC");
90
91 if (text.empty())
92 return;
93
94 if (m_layoutDir == wxLayout_RightToLeft && text.find('\n') != wxString::npos)
95 {
96 // RTL needs each line separately to position text properly.
97 // DrawLabel() will split the text and call back for each line.
98 GetOwner()->DrawLabel(text, wxRect(x, y, 0, 0));
99 return;
100 }
101
102 int w, h;
103 DoGetTextExtent(text, &w, &h);
104
105 CalcBoundingBox(x, y);
106 CalcBoundingBox(x + w, y + h);
107
108 if (m_layoutDir == wxLayout_RightToLeft)
109 {
110 m_graphicContext->PushState();
111 // text is not mirrored
112 m_graphicContext->Scale(-1, 1);
113 x = -x - w;
114 }
115
116 wxCompositionMode curMode = m_graphicContext->GetCompositionMode();
117 m_graphicContext->SetCompositionMode(wxCOMPOSITION_OVER);
118
119 if (m_backgroundMode == wxBRUSHSTYLE_TRANSPARENT)
120 m_graphicContext->DrawText(text, x, y);
121 else
122 m_graphicContext->DrawText(text, x, y, m_graphicContext->CreateBrush(m_textBackgroundColour));
123
124 m_graphicContext->SetCompositionMode(curMode);
125
126 if (m_layoutDir == wxLayout_RightToLeft)
127 m_graphicContext->PopState();
128 }
129
DoDrawRotatedText(const wxString & text,int x,int y,double angle)130 void wxGTKCairoDCImpl::DoDrawRotatedText(const wxString& text, int x, int y, double angle)
131 {
132 wxCHECK_RET(IsOk(), "invalid DC");
133
134 // save current bounding box
135 // rotation will cause DoDrawText() to update it incorrectly
136 const bool isBBoxValid = m_isBBoxValid;
137 const int minX = m_minX;
138 const int minY = m_minY;
139 const int maxX = m_maxX;
140 const int maxY = m_maxY;
141
142 const double rad = wxDegToRad(-angle);
143 m_graphicContext->PushState();
144 m_graphicContext->Translate(x, y);
145 m_graphicContext->Rotate(rad);
146 DoDrawText(text, 0, 0);
147 m_graphicContext->PopState();
148
149 // restore bounding box and update it correctly
150 m_isBBoxValid = isBBoxValid;
151 m_minX = minX;
152 m_minY = minY;
153 m_maxX = maxX;
154 m_maxY = maxY;
155
156 CalcBoundingBox(x, y);
157 int w, h;
158 DoGetTextExtent(text, &w, &h);
159 cairo_matrix_t m;
160 cairo_matrix_init_translate(&m, x, y);
161 cairo_matrix_rotate(&m, rad);
162 double xx = w, yy = 0;
163 cairo_matrix_transform_point(&m, &xx, &yy);
164 CalcBoundingBox(int(xx), int(yy));
165 xx = w; yy = h;
166 cairo_matrix_transform_point(&m, &xx, &yy);
167 CalcBoundingBox(int(xx), int(yy));
168 xx = 0; yy = h;
169 cairo_matrix_transform_point(&m, &xx, &yy);
170 CalcBoundingBox(int(xx), int(yy));
171 }
172
DoDrawCheckMark(int x,int y,int width,int height)173 void wxGTKCairoDCImpl::DoDrawCheckMark(int x, int y, int width, int height)
174 {
175 if (m_layoutDir == wxLayout_RightToLeft)
176 {
177 wxCHECK_RET(IsOk(), "invalid DC");
178
179 // checkmark is not mirrored
180 m_graphicContext->PushState();
181 m_graphicContext->Scale(-1, 1);
182 BaseType::DoDrawCheckMark(-x - width, y, width, height);
183 m_graphicContext->PopState();
184 }
185 else
186 BaseType::DoDrawCheckMark(x, y, width, height);
187 }
188
DoGetAsBitmap(const wxRect *) const189 wxBitmap wxGTKCairoDCImpl::DoGetAsBitmap(const wxRect* /*subrect*/) const
190 {
191 wxFAIL_MSG("DoGetAsBitmap not implemented");
192 return wxBitmap();
193 }
194
DoGetPixel(int x,int y,wxColour * col) const195 bool wxGTKCairoDCImpl::DoGetPixel(int x, int y, wxColour* col) const
196 {
197 if (col)
198 {
199 cairo_t* cr = NULL;
200 if (m_graphicContext)
201 cr = static_cast<cairo_t*>(m_graphicContext->GetNativeContext());
202 if (cr)
203 {
204 cairo_surface_t* surface = cairo_get_target(cr);
205 x = LogicalToDeviceX(x);
206 y = LogicalToDeviceY(y);
207 GdkPixbuf* pixbuf = gdk_pixbuf_get_from_surface(surface, x, y, 1, 1);
208 if (pixbuf)
209 {
210 const guchar* src = gdk_pixbuf_get_pixels(pixbuf);
211 col->Set(src[0], src[1], src[2]);
212 g_object_unref(pixbuf);
213 return true;
214 }
215 *col = wxColour();
216 }
217 }
218 return false;
219 }
220
DoGetSize(int * width,int * height) const221 void wxGTKCairoDCImpl::DoGetSize(int* width, int* height) const
222 {
223 if (width)
224 *width = m_size.x;
225 if (height)
226 *height = m_size.y;
227 }
228
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)229 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)
230 {
231 wxCHECK_MSG(IsOk(), false, "invalid DC");
232 wxCHECK_MSG(source && source->IsOk(), false, "invalid source DC");
233
234 cairo_t* cr = NULL;
235 if (m_graphicContext)
236 cr = static_cast<cairo_t*>(m_graphicContext->GetNativeContext());
237 cairo_t* cr_src = NULL;
238 wxGraphicsContext* gc_src = source->GetGraphicsContext();
239 if (gc_src)
240 cr_src = static_cast<cairo_t*>(gc_src->GetNativeContext());
241
242 if (cr == NULL || cr_src == NULL)
243 return false;
244
245 const int xsrc_dev = source->LogicalToDeviceX(xsrc);
246 const int ysrc_dev = source->LogicalToDeviceY(ysrc);
247
248 cairo_surface_t* surfaceSrc = cairo_get_target(cr_src);
249 cairo_surface_flush(surfaceSrc);
250
251 cairo_surface_t* surfaceTmp = NULL;
252 // If destination (this) and source wxDC refer to the same Cairo context
253 // it means that we operate on one surface and results of drawing
254 // can be invalid if destination and source regions overlap.
255 // In such situation we have to copy source surface to the temporary
256 // surface and use this copy in the drawing operations.
257 if ( cr == cr_src )
258 {
259 // Check if destination and source regions overlap.
260 // If necessary, copy source surface to the temporary one.
261 if (wxRect(xdest, ydest, dstWidth, dstHeight)
262 .Intersects(wxRect(xsrc, ysrc, srcWidth, srcHeight)))
263 {
264 const int w = cairo_image_surface_get_width(surfaceSrc);
265 const int h = cairo_image_surface_get_height(surfaceSrc);
266 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
267 if ( cairo_version() >= CAIRO_VERSION_ENCODE(1, 12, 0) )
268 {
269 surfaceTmp = cairo_surface_create_similar_image(surfaceSrc,
270 cairo_image_surface_get_format(surfaceSrc),
271 w, h);
272 }
273 else
274 #endif // Cairo 1.12
275 {
276 surfaceTmp = cairo_surface_create_similar(surfaceSrc,
277 CAIRO_CONTENT_COLOR_ALPHA,
278 w, h);
279 }
280 cairo_t* crTmp = cairo_create(surfaceTmp);
281 cairo_set_source_surface(crTmp, surfaceSrc, 0, 0);
282 cairo_rectangle(crTmp, 0.0, 0.0, w, h);
283 cairo_set_operator(crTmp, CAIRO_OPERATOR_SOURCE);
284 cairo_fill(crTmp);
285 cairo_destroy(crTmp);
286 cairo_surface_flush(surfaceTmp);
287 surfaceSrc = surfaceTmp;
288 }
289 }
290 cairo_save(cr);
291 if (m_layoutDir == wxLayout_RightToLeft)
292 {
293 // blit is not mirrored
294 cairo_scale(cr, -1, 1);
295 xdest = -xdest - dstWidth;
296 }
297 cairo_translate(cr, xdest, ydest);
298 cairo_rectangle(cr, 0, 0, dstWidth, dstHeight);
299 double sx, sy;
300 source->GetUserScale(&sx, &sy);
301
302 const wxBitmap& bitmap = source->GetImpl()->GetSelectedBitmap();
303 const double bmpScale = bitmap.IsOk() ? bitmap.GetScaleFactor() : 1.0;
304
305 cairo_scale(cr, dstWidth / (sx * srcWidth * bmpScale), dstHeight / (sy * srcHeight * bmpScale));
306 cairo_set_source_surface(cr, surfaceSrc, -xsrc_dev, -ysrc_dev);
307 const wxRasterOperationMode rop_save = m_logicalFunction;
308 SetLogicalFunction(rop);
309 cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST);
310 cairo_surface_t* maskSurf = NULL;
311 if (useMask)
312 {
313 if (bitmap.IsOk())
314 {
315 wxMask* mask = bitmap.GetMask();
316 if (mask)
317 maskSurf = *mask;
318 }
319 }
320 if (maskSurf)
321 {
322 int xsrcMask_dev = xsrc_dev;
323 int ysrcMask_dev = ysrc_dev;
324 if (xsrcMask != -1)
325 xsrcMask_dev = source->LogicalToDeviceX(xsrcMask);
326 if (ysrcMask != -1)
327 ysrcMask_dev = source->LogicalToDeviceY(ysrcMask);
328 cairo_clip(cr);
329 cairo_mask_surface(cr, maskSurf, -xsrcMask_dev, -ysrcMask_dev);
330 }
331 else
332 {
333 cairo_fill(cr);
334 }
335 cairo_restore(cr);
336 if ( surfaceTmp )
337 {
338 cairo_surface_destroy(surfaceTmp);
339 }
340 m_logicalFunction = rop_save;
341 return true;
342 }
343
GetCairoContext() const344 void* wxGTKCairoDCImpl::GetCairoContext() const
345 {
346 cairo_t* cr = NULL;
347 if (m_graphicContext)
348 cr = static_cast<cairo_t*>(m_graphicContext->GetNativeContext());
349 return cr;
350 }
351
GetPPI() const352 wxSize wxGTKCairoDCImpl::GetPPI() const
353 {
354 if ( m_window )
355 {
356 return wxDisplay(m_window).GetPPI();
357 }
358
359 // For a non-window-based DC the concept of PPI doesn't make much sense
360 // anyhow, so just return the hardcoded value used by the base class.
361 return wxGCDCImpl::GetPPI();
362 }
363
SetLayoutDirection(wxLayoutDirection dir)364 void wxGTKCairoDCImpl::SetLayoutDirection(wxLayoutDirection dir)
365 {
366 if (dir == wxLayout_Default && m_window)
367 dir = m_window->GetLayoutDirection();
368
369 m_layoutDir = dir;
370 }
371
GetLayoutDirection() const372 wxLayoutDirection wxGTKCairoDCImpl::GetLayoutDirection() const
373 {
374 // LTR unless explicitly RTL
375 return
376 m_layoutDir == wxLayout_RightToLeft
377 ? wxLayout_RightToLeft
378 : wxLayout_LeftToRight;
379 }
380
AdjustForRTL(cairo_t * cr)381 void wxGTKCairoDCImpl::AdjustForRTL(cairo_t* cr)
382 {
383 if (m_layoutDir == wxLayout_RightToLeft)
384 {
385 cairo_translate(cr, m_size.x, 0);
386 cairo_scale(cr, -1, 1);
387 }
388 }
389 //-----------------------------------------------------------------------------
390
wxWindowDCImpl(wxWindowDC * owner,wxWindow * window)391 wxWindowDCImpl::wxWindowDCImpl(wxWindowDC* owner, wxWindow* window)
392 : wxGTKCairoDCImpl(owner, window)
393 {
394 GtkWidget* widget = window->m_wxwindow;
395 if (widget == NULL)
396 widget = window->m_widget;
397 GdkWindow* gdkWindow = NULL;
398 if (widget)
399 {
400 gdkWindow = gtk_widget_get_window(widget);
401 m_ok = true;
402 }
403 if (gdkWindow)
404 {
405 cairo_t* cr = gdk_cairo_create(gdkWindow);
406 SetLayoutDirection(wxLayout_Default);
407 AdjustForRTL(cr);
408 wxGraphicsContext* gc = wxGraphicsContext::CreateFromNative(cr);
409 cairo_destroy(cr);
410 gc->SetContentScaleFactor(m_contentScaleFactor);
411 SetGraphicsContext(gc);
412 GtkAllocation a;
413 gtk_widget_get_allocation(widget, &a);
414 int x, y;
415 if (gtk_widget_get_has_window(widget))
416 {
417 m_size.x = gdk_window_get_width(gdkWindow);
418 m_size.y = gdk_window_get_height(gdkWindow);
419 x = m_size.x - a.width;
420 y = m_size.y - a.height;
421 }
422 else
423 {
424 m_size.x = a.width;
425 m_size.y = a.height;
426 x = a.x;
427 y = a.y;
428 cairo_rectangle(cr, a.x, a.y, a.width, a.height);
429 cairo_clip(cr);
430 }
431 if (x || y)
432 SetDeviceLocalOrigin(x, y);
433 }
434 else
435 SetGraphicsContext(wxGraphicsContext::Create());
436 }
437 //-----------------------------------------------------------------------------
438
wxClientDCImpl(wxClientDC * owner,wxWindow * window)439 wxClientDCImpl::wxClientDCImpl(wxClientDC* owner, wxWindow* window)
440 : wxGTKCairoDCImpl(owner, window)
441 {
442 GtkWidget* widget = window->m_wxwindow;
443 if (widget == NULL)
444 widget = window->m_widget;
445 GdkWindow* gdkWindow = NULL;
446 if (widget)
447 {
448 window->GetClientSize(&m_size.x, &m_size.y);
449 gdkWindow = gtk_widget_get_window(widget);
450 m_ok = true;
451 }
452 if (gdkWindow)
453 {
454 cairo_t* cr = gdk_cairo_create(gdkWindow);
455 SetLayoutDirection(wxLayout_Default);
456 AdjustForRTL(cr);
457 wxGraphicsContext* gc = wxGraphicsContext::CreateFromNative(cr);
458 cairo_destroy(cr);
459 gc->SetContentScaleFactor(m_contentScaleFactor);
460 SetGraphicsContext(gc);
461 if (!gtk_widget_get_has_window(widget))
462 {
463 GtkAllocation a;
464 gtk_widget_get_allocation(widget, &a);
465 cairo_rectangle(cr, a.x, a.y, a.width, a.height);
466 cairo_clip(cr);
467 SetDeviceLocalOrigin(a.x, a.y);
468 }
469 }
470 else
471 SetGraphicsContext(wxGraphicsContext::Create());
472 }
473 //-----------------------------------------------------------------------------
474
wxPaintDCImpl(wxPaintDC * owner,wxWindow * window)475 wxPaintDCImpl::wxPaintDCImpl(wxPaintDC* owner, wxWindow* window)
476 : wxGTKCairoDCImpl(owner, window)
477 , m_clip(window->m_nativeUpdateRegion)
478 {
479 cairo_t* cr = window->GTKPaintContext();
480 wxCHECK_RET(cr, "using wxPaintDC without being in a native paint event");
481 InitSize(gtk_widget_get_window(window->m_wxwindow));
482 wxGraphicsContext* gc = wxGraphicsContext::CreateFromNative(cr);
483 gc->SetContentScaleFactor(m_contentScaleFactor);
484 SetGraphicsContext(gc);
485 // context is already adjusted for RTL
486 m_layoutDir = window->GetLayoutDirection();
487 }
488
DestroyClippingRegion()489 void wxPaintDCImpl::DestroyClippingRegion()
490 {
491 BaseType::DestroyClippingRegion();
492
493 // re-establish clip for paint update area
494 int x, y, w, h;
495 m_clip.GetBox(x, y, w, h);
496 cairo_t* cr = static_cast<cairo_t*>(GetCairoContext());
497 cairo_rectangle(cr,
498 DeviceToLogicalX(x), DeviceToLogicalY(y),
499 DeviceToLogicalXRel(w), DeviceToLogicalYRel(h));
500 cairo_clip(cr);
501 }
502 //-----------------------------------------------------------------------------
503
wxScreenDCImpl(wxScreenDC * owner)504 wxScreenDCImpl::wxScreenDCImpl(wxScreenDC* owner)
505 : wxGTKCairoDCImpl(owner, static_cast<wxWindow*>(NULL))
506 {
507 GdkWindow* window = gdk_get_default_root_window();
508 InitSize(window);
509
510 cairo_t* cr = gdk_cairo_create(window);
511 wxGraphicsContext* gc = wxGraphicsContext::CreateFromNative(cr);
512 cairo_destroy(cr);
513 gc->SetContentScaleFactor(m_contentScaleFactor);
514 SetGraphicsContext(gc);
515 }
516
GetPPI() const517 wxSize wxScreenDCImpl::GetPPI() const
518 {
519 return wxGetDisplayPPI();
520 }
521
522 //-----------------------------------------------------------------------------
523
wxMemoryDCImpl(wxMemoryDC * owner)524 wxMemoryDCImpl::wxMemoryDCImpl(wxMemoryDC* owner)
525 : wxGTKCairoDCImpl(owner)
526 {
527 m_ok = false;
528 }
529
wxMemoryDCImpl(wxMemoryDC * owner,wxBitmap & bitmap)530 wxMemoryDCImpl::wxMemoryDCImpl(wxMemoryDC* owner, wxBitmap& bitmap)
531 : wxGTKCairoDCImpl(owner, static_cast<wxWindow*>(NULL))
532 , m_bitmap(bitmap)
533 {
534 Setup();
535 }
536
wxMemoryDCImpl(wxMemoryDC * owner,wxDC *)537 wxMemoryDCImpl::wxMemoryDCImpl(wxMemoryDC* owner, wxDC*)
538 : wxGTKCairoDCImpl(owner)
539 {
540 m_ok = false;
541 }
542
DoGetAsBitmap(const wxRect * subrect) const543 wxBitmap wxMemoryDCImpl::DoGetAsBitmap(const wxRect* subrect) const
544 {
545 return subrect ? m_bitmap.GetSubBitmap(*subrect) : m_bitmap;
546 }
547
DoSelect(const wxBitmap & bitmap)548 void wxMemoryDCImpl::DoSelect(const wxBitmap& bitmap)
549 {
550 m_bitmap = bitmap;
551 Setup();
552 }
553
GetSelectedBitmap() const554 const wxBitmap& wxMemoryDCImpl::GetSelectedBitmap() const
555 {
556 return m_bitmap;
557 }
558
GetSelectedBitmap()559 wxBitmap& wxMemoryDCImpl::GetSelectedBitmap()
560 {
561 return m_bitmap;
562 }
563
Setup()564 void wxMemoryDCImpl::Setup()
565 {
566 wxGraphicsContext* gc = NULL;
567 m_ok = m_bitmap.IsOk();
568 if (m_ok)
569 {
570 m_size = m_bitmap.GetScaledSize();
571 m_contentScaleFactor = m_bitmap.GetScaleFactor();
572 cairo_t* cr = m_bitmap.CairoCreate();
573 AdjustForRTL(cr);
574 gc = wxGraphicsContext::CreateFromNative(cr);
575 cairo_destroy(cr);
576 gc->SetContentScaleFactor(m_contentScaleFactor);
577 }
578 SetGraphicsContext(gc);
579 }
580 //-----------------------------------------------------------------------------
581
wxGTKCairoDC(cairo_t * cr,wxWindow * window,wxLayoutDirection dir,int width)582 wxGTKCairoDC::wxGTKCairoDC(cairo_t* cr, wxWindow* window, wxLayoutDirection dir, int width)
583 : wxDC(new wxGTKCairoDCImpl(this, window, dir, width))
584 {
585 wxGraphicsContext* gc = wxGraphicsContext::CreateFromNative(cr);
586 gc->SetContentScaleFactor(window->GetContentScaleFactor());
587 SetGraphicsContext(gc);
588 if (dir == wxLayout_Default)
589 SetLayoutDirection(window->GetLayoutDirection());
590 // else context is already adjusted for RTL
591 }
592
593 #else
594
595 #include "wx/gtk/dc.h"
596
597 //-----------------------------------------------------------------------------
598 // wxGTKDCImpl
599 //-----------------------------------------------------------------------------
600
601 wxIMPLEMENT_ABSTRACT_CLASS(wxGTKDCImpl, wxDCImpl);
602
wxGTKDCImpl(wxDC * owner)603 wxGTKDCImpl::wxGTKDCImpl( wxDC *owner )
604 : wxDCImpl( owner )
605 {
606 m_ok = FALSE;
607
608 m_pen = *wxBLACK_PEN;
609 m_font = *wxNORMAL_FONT;
610 m_brush = *wxWHITE_BRUSH;
611 }
612
~wxGTKDCImpl()613 wxGTKDCImpl::~wxGTKDCImpl()
614 {
615 }
616
DoSetClippingRegion(wxCoord x,wxCoord y,wxCoord width,wxCoord height)617 void wxGTKDCImpl::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
618 {
619 wxASSERT_MSG( width >= 0 && height >= 0,
620 "Clipping box size values cannot be negative" );
621
622 wxRect newRegion(x, y, width, height);
623
624 wxRect clipRegion;
625 if ( m_clipping )
626 {
627 // New clipping box is an intersection
628 // of required clipping box and the current one.
629 wxRect curRegion(m_clipX1, m_clipY1, m_clipX2 - m_clipX1, m_clipY2 - m_clipY1);
630 clipRegion = curRegion.Intersect(newRegion);
631 }
632 else
633 {
634 // Effective clipping box is an intersection
635 // of required clipping box and DC surface.
636 int dcWidth, dcHeight;
637 DoGetSize(&dcWidth, &dcHeight);
638 wxRect dcRect(DeviceToLogicalX(0), DeviceToLogicalY(0),
639 DeviceToLogicalXRel(dcWidth), DeviceToLogicalYRel(dcHeight));
640 clipRegion = dcRect.Intersect(newRegion);
641
642 m_clipping = true;
643 }
644
645 if ( clipRegion.IsEmpty() )
646 {
647 m_clipX1 = m_clipY1 = m_clipX2 = m_clipY2 = 0;
648 }
649 else
650 {
651 m_clipX1 = clipRegion.GetLeftTop().x;
652 m_clipY1 = clipRegion.GetLeftTop().y;
653 m_clipX2 = clipRegion.GetBottomRight().x + 1;
654 m_clipY2 = clipRegion.GetBottomRight().y + 1;
655 }
656 }
657
658 // ---------------------------------------------------------------------------
659 // get DC capabilities
660 // ---------------------------------------------------------------------------
661
DoGetSizeMM(int * width,int * height) const662 void wxGTKDCImpl::DoGetSizeMM( int* width, int* height ) const
663 {
664 int w = 0;
665 int h = 0;
666 GetOwner()->GetSize( &w, &h );
667 if (width) *width = int( double(w) / (m_userScaleX*GetMMToPXx()) );
668 if (height) *height = int( double(h) / (m_userScaleY*GetMMToPXy()) );
669 }
670
671 // Resolution in pixels per logical inch
GetPPI() const672 wxSize wxGTKDCImpl::GetPPI() const
673 {
674 // TODO (should probably be pure virtual)
675 return wxSize(0, 0);
676 }
677 #endif
678