]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/dcclient.cpp
More comments about non-native GTH widgets.
[wxWidgets.git] / src / gtk / dcclient.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/dcclient.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // RCS-ID: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Chris Breeze
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #ifdef __VMS
14 #define XCopyPlane XCOPYPLANE
15 #endif
16
17 #include "wx/dcclient.h"
18
19 #ifndef WX_PRECOMP
20 #include "wx/window.h"
21 #include "wx/log.h"
22 #include "wx/dcmemory.h"
23 #include "wx/math.h" // for floating-point functions
24 #include "wx/image.h"
25 #endif
26
27 #include "wx/module.h"
28 #include "wx/fontutil.h"
29
30 #include "wx/gtk/win_gtk.h"
31 #include "wx/gtk/private.h"
32
33 #include <gdk/gdkx.h>
34
35 //-----------------------------------------------------------------------------
36 // local defines
37 //-----------------------------------------------------------------------------
38
39 #define USE_PAINT_REGION 1
40
41 //-----------------------------------------------------------------------------
42 // local data
43 //-----------------------------------------------------------------------------
44
45 #include "bdiag.xbm"
46 #include "fdiag.xbm"
47 #include "cdiag.xbm"
48 #include "horiz.xbm"
49 #include "verti.xbm"
50 #include "cross.xbm"
51 #define num_hatches 6
52
53 #define IS_15_PIX_HATCH(s) ((s)==wxCROSSDIAG_HATCH || (s)==wxHORIZONTAL_HATCH || (s)==wxVERTICAL_HATCH)
54 #define IS_16_PIX_HATCH(s) ((s)!=wxCROSSDIAG_HATCH && (s)!=wxHORIZONTAL_HATCH && (s)!=wxVERTICAL_HATCH)
55
56
57 static GdkPixmap *hatches[num_hatches];
58 static GdkPixmap **hatch_bitmap = (GdkPixmap **) NULL;
59
60 extern GtkWidget *wxGetRootWindow();
61
62 //-----------------------------------------------------------------------------
63 // constants
64 //-----------------------------------------------------------------------------
65
66 const double RAD2DEG = 180.0 / M_PI;
67
68 // ----------------------------------------------------------------------------
69 // private functions
70 // ----------------------------------------------------------------------------
71
72 static inline double dmax(double a, double b) { return a > b ? a : b; }
73 static inline double dmin(double a, double b) { return a < b ? a : b; }
74
75 static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
76
77 //-----------------------------------------------------------------------------
78 // temporary implementation of the missing GDK function
79 //-----------------------------------------------------------------------------
80
81 #include "gdk/gdkprivate.h"
82
83 static
84 void gdk_wx_draw_bitmap(GdkDrawable *drawable,
85 GdkGC *gc,
86 GdkDrawable *src,
87 gint xsrc,
88 gint ysrc,
89 gint xdest,
90 gint ydest,
91 gint width,
92 gint height)
93 {
94 wxCHECK_RET( drawable, _T("NULL drawable in gdk_wx_draw_bitmap") );
95 wxCHECK_RET( src, _T("NULL src in gdk_wx_draw_bitmap") );
96 wxCHECK_RET( gc, _T("NULL gc in gdk_wx_draw_bitmap") );
97
98 gint src_width, src_height;
99 gdk_drawable_get_size(src, &src_width, &src_height);
100 if (width == -1) width = src_width;
101 if (height == -1) height = src_height;
102
103 XCopyPlane( GDK_WINDOW_XDISPLAY(drawable),
104 GDK_WINDOW_XID(src),
105 GDK_WINDOW_XID(drawable),
106 GDK_GC_XGC(gc),
107 xsrc, ysrc,
108 width, height,
109 0, 0,
110 1 );
111 }
112
113 //-----------------------------------------------------------------------------
114 // Implement Pool of Graphic contexts. Creating them takes too much time.
115 //-----------------------------------------------------------------------------
116
117 enum wxPoolGCType
118 {
119 wxGC_ERROR = 0,
120 wxTEXT_MONO,
121 wxBG_MONO,
122 wxPEN_MONO,
123 wxBRUSH_MONO,
124 wxTEXT_COLOUR,
125 wxBG_COLOUR,
126 wxPEN_COLOUR,
127 wxBRUSH_COLOUR,
128 wxTEXT_SCREEN,
129 wxBG_SCREEN,
130 wxPEN_SCREEN,
131 wxBRUSH_SCREEN
132 };
133
134 struct wxGC
135 {
136 GdkGC *m_gc;
137 wxPoolGCType m_type;
138 bool m_used;
139 };
140
141 #define GC_POOL_ALLOC_SIZE 100
142
143 static int wxGCPoolSize = 0;
144
145 static wxGC *wxGCPool = NULL;
146
147 static void wxInitGCPool()
148 {
149 // This really could wait until the first call to
150 // wxGetPoolGC, but we will make the first allocation
151 // now when other initialization is being performed.
152
153 // Set initial pool size.
154 wxGCPoolSize = GC_POOL_ALLOC_SIZE;
155
156 // Allocate initial pool.
157 wxGCPool = (wxGC *)malloc(wxGCPoolSize * sizeof(wxGC));
158 if (wxGCPool == NULL)
159 {
160 // If we cannot malloc, then fail with error
161 // when debug is enabled. If debug is not enabled,
162 // the problem will eventually get caught
163 // in wxGetPoolGC.
164 wxFAIL_MSG( wxT("Cannot allocate GC pool") );
165 return;
166 }
167
168 // Zero initial pool.
169 memset(wxGCPool, 0, wxGCPoolSize * sizeof(wxGC));
170 }
171
172 static void wxCleanUpGCPool()
173 {
174 for (int i = 0; i < wxGCPoolSize; i++)
175 {
176 if (wxGCPool[i].m_gc)
177 g_object_unref (wxGCPool[i].m_gc);
178 }
179
180 free(wxGCPool);
181 wxGCPool = NULL;
182 wxGCPoolSize = 0;
183 }
184
185 static GdkGC* wxGetPoolGC( GdkWindow *window, wxPoolGCType type )
186 {
187 wxGC *pptr;
188
189 // Look for an available GC.
190 for (int i = 0; i < wxGCPoolSize; i++)
191 {
192 if (!wxGCPool[i].m_gc)
193 {
194 wxGCPool[i].m_gc = gdk_gc_new( window );
195 gdk_gc_set_exposures( wxGCPool[i].m_gc, FALSE );
196 wxGCPool[i].m_type = type;
197 wxGCPool[i].m_used = false;
198 }
199 if ((!wxGCPool[i].m_used) && (wxGCPool[i].m_type == type))
200 {
201 wxGCPool[i].m_used = true;
202 return wxGCPool[i].m_gc;
203 }
204 }
205
206 // We did not find an available GC.
207 // We need to grow the GC pool.
208 pptr = (wxGC *)realloc(wxGCPool,
209 (wxGCPoolSize + GC_POOL_ALLOC_SIZE)*sizeof(wxGC));
210 if (pptr != NULL)
211 {
212 // Initialize newly allocated pool.
213 wxGCPool = pptr;
214 memset(&wxGCPool[wxGCPoolSize], 0,
215 GC_POOL_ALLOC_SIZE*sizeof(wxGC));
216
217 // Initialize entry we will return.
218 wxGCPool[wxGCPoolSize].m_gc = gdk_gc_new( window );
219 gdk_gc_set_exposures( wxGCPool[wxGCPoolSize].m_gc, FALSE );
220 wxGCPool[wxGCPoolSize].m_type = type;
221 wxGCPool[wxGCPoolSize].m_used = true;
222
223 // Set new value of pool size.
224 wxGCPoolSize += GC_POOL_ALLOC_SIZE;
225
226 // Return newly allocated entry.
227 return wxGCPool[wxGCPoolSize-GC_POOL_ALLOC_SIZE].m_gc;
228 }
229
230 // The realloc failed. Fall through to error.
231 wxFAIL_MSG( wxT("No GC available") );
232
233 return (GdkGC*) NULL;
234 }
235
236 static void wxFreePoolGC( GdkGC *gc )
237 {
238 for (int i = 0; i < wxGCPoolSize; i++)
239 {
240 if (wxGCPool[i].m_gc == gc)
241 {
242 wxGCPool[i].m_used = false;
243 return;
244 }
245 }
246
247 wxFAIL_MSG( wxT("Wrong GC") );
248 }
249
250 //-----------------------------------------------------------------------------
251 // wxWindowDC
252 //-----------------------------------------------------------------------------
253
254 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
255
256 wxWindowDC::wxWindowDC()
257 {
258 m_penGC = (GdkGC *) NULL;
259 m_brushGC = (GdkGC *) NULL;
260 m_textGC = (GdkGC *) NULL;
261 m_bgGC = (GdkGC *) NULL;
262 m_cmap = (GdkColormap *) NULL;
263 m_isMemDC = false;
264 m_isScreenDC = false;
265 m_owner = (wxWindow *)NULL;
266 m_context = (PangoContext *)NULL;
267 m_layout = (PangoLayout *)NULL;
268 m_fontdesc = (PangoFontDescription *)NULL;
269 }
270
271 wxWindowDC::wxWindowDC( wxWindow *window )
272 {
273 wxASSERT_MSG( window, wxT("DC needs a window") );
274
275 m_penGC = (GdkGC *) NULL;
276 m_brushGC = (GdkGC *) NULL;
277 m_textGC = (GdkGC *) NULL;
278 m_bgGC = (GdkGC *) NULL;
279 m_cmap = (GdkColormap *) NULL;
280 m_owner = (wxWindow *)NULL;
281 m_isMemDC = false;
282 m_isScreenDC = false;
283 m_font = window->GetFont();
284
285 GtkWidget *widget = window->m_wxwindow;
286
287 // Some controls don't have m_wxwindow - like wxStaticBox, but the user
288 // code should still be able to create wxClientDCs for them, so we will
289 // use the parent window here then.
290 if ( !widget )
291 {
292 window = window->GetParent();
293 widget = window->m_wxwindow;
294 }
295
296 wxASSERT_MSG( widget, wxT("DC needs a widget") );
297
298 m_context = window->GtkGetPangoDefaultContext();
299 m_layout = pango_layout_new( m_context );
300 m_fontdesc = pango_font_description_copy( widget->style->font_desc );
301
302 GtkPizza *pizza = GTK_PIZZA( widget );
303 m_window = pizza->bin_window;
304
305 // Window not realized ?
306 if (!m_window)
307 {
308 // Don't report problems as per MSW.
309 m_ok = true;
310
311 return;
312 }
313
314 m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget );
315
316 SetUpDC();
317
318 /* this must be done after SetUpDC, bacause SetUpDC calls the
319 repective SetBrush, SetPen, SetBackground etc functions
320 to set up the DC. SetBackground call m_owner->SetBackground
321 and this might not be desired as the standard dc background
322 is white whereas a window might assume gray to be the
323 standard (as e.g. wxStatusBar) */
324
325 m_owner = window;
326 }
327
328 wxWindowDC::~wxWindowDC()
329 {
330 Destroy();
331
332 if (m_layout)
333 g_object_unref (m_layout);
334 if (m_fontdesc)
335 pango_font_description_free( m_fontdesc );
336 }
337
338 void wxWindowDC::SetUpDC()
339 {
340 m_ok = true;
341
342 wxASSERT_MSG( !m_penGC, wxT("GCs already created") );
343
344 if (m_isScreenDC)
345 {
346 m_penGC = wxGetPoolGC( m_window, wxPEN_SCREEN );
347 m_brushGC = wxGetPoolGC( m_window, wxBRUSH_SCREEN );
348 m_textGC = wxGetPoolGC( m_window, wxTEXT_SCREEN );
349 m_bgGC = wxGetPoolGC( m_window, wxBG_SCREEN );
350 }
351 else
352 if (m_isMemDC && (((wxMemoryDC*)this)->m_selected.GetDepth() == 1))
353 {
354 m_penGC = wxGetPoolGC( m_window, wxPEN_MONO );
355 m_brushGC = wxGetPoolGC( m_window, wxBRUSH_MONO );
356 m_textGC = wxGetPoolGC( m_window, wxTEXT_MONO );
357 m_bgGC = wxGetPoolGC( m_window, wxBG_MONO );
358 }
359 else
360 {
361 m_penGC = wxGetPoolGC( m_window, wxPEN_COLOUR );
362 m_brushGC = wxGetPoolGC( m_window, wxBRUSH_COLOUR );
363 m_textGC = wxGetPoolGC( m_window, wxTEXT_COLOUR );
364 m_bgGC = wxGetPoolGC( m_window, wxBG_COLOUR );
365 }
366
367 /* background colour */
368 m_backgroundBrush = *wxWHITE_BRUSH;
369 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
370 #ifdef __WXGTK24__
371 const GdkColor *bg_col = m_backgroundBrush.GetColour().GetColor();
372 #else
373 GdkColor *bg_col = m_backgroundBrush.GetColour().GetColor();
374 #endif
375
376 /* m_textGC */
377 m_textForegroundColour.CalcPixel( m_cmap );
378 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
379
380 m_textBackgroundColour.CalcPixel( m_cmap );
381 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
382
383 gdk_gc_set_fill( m_textGC, GDK_SOLID );
384
385 /* m_penGC */
386 m_pen.GetColour().CalcPixel( m_cmap );
387 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
388 gdk_gc_set_background( m_penGC, bg_col );
389
390 gdk_gc_set_line_attributes( m_penGC, 0, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_ROUND );
391
392 /* m_brushGC */
393 m_brush.GetColour().CalcPixel( m_cmap );
394 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
395 gdk_gc_set_background( m_brushGC, bg_col );
396
397 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
398
399 /* m_bgGC */
400 gdk_gc_set_background( m_bgGC, bg_col );
401 gdk_gc_set_foreground( m_bgGC, bg_col );
402
403 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
404
405 /* ROPs */
406 gdk_gc_set_function( m_textGC, GDK_COPY );
407 gdk_gc_set_function( m_brushGC, GDK_COPY );
408 gdk_gc_set_function( m_penGC, GDK_COPY );
409
410 /* clipping */
411 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
412 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
413 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
414 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
415
416 if (!hatch_bitmap)
417 {
418 hatch_bitmap = hatches;
419 hatch_bitmap[0] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, bdiag_bits, bdiag_width, bdiag_height );
420 hatch_bitmap[1] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cdiag_bits, cdiag_width, cdiag_height );
421 hatch_bitmap[2] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, fdiag_bits, fdiag_width, fdiag_height );
422 hatch_bitmap[3] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cross_bits, cross_width, cross_height );
423 hatch_bitmap[4] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, horiz_bits, horiz_width, horiz_height );
424 hatch_bitmap[5] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, verti_bits, verti_width, verti_height );
425 }
426 }
427
428 void wxWindowDC::DoGetSize( int* width, int* height ) const
429 {
430 wxCHECK_RET( m_owner, _T("GetSize() doesn't work without window") );
431
432 m_owner->GetSize(width, height);
433 }
434
435 extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
436 const wxColour & col, int style);
437
438 bool wxWindowDC::DoFloodFill(wxCoord x, wxCoord y,
439 const wxColour& col, int style)
440 {
441 return wxDoFloodFill(this, x, y, col, style);
442 }
443
444 bool wxWindowDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const
445 {
446 // Generic (and therefore rather inefficient) method.
447 // Could be improved.
448 wxMemoryDC memdc;
449 wxBitmap bitmap(1, 1);
450 memdc.SelectObject(bitmap);
451 memdc.Blit(0, 0, 1, 1, (wxDC*) this, x1, y1);
452 memdc.SelectObject(wxNullBitmap);
453
454 wxImage image = bitmap.ConvertToImage();
455 col->Set(image.GetRed(0, 0), image.GetGreen(0, 0), image.GetBlue(0, 0));
456 return true;
457 }
458
459 void wxWindowDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
460 {
461 wxCHECK_RET( Ok(), wxT("invalid window dc") );
462
463 if (m_pen.GetStyle() != wxTRANSPARENT)
464 {
465 if (m_window)
466 gdk_draw_line( m_window, m_penGC, XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2) );
467
468 CalcBoundingBox(x1, y1);
469 CalcBoundingBox(x2, y2);
470 }
471 }
472
473 void wxWindowDC::DoCrossHair( wxCoord x, wxCoord y )
474 {
475 wxCHECK_RET( Ok(), wxT("invalid window dc") );
476
477 if (m_pen.GetStyle() != wxTRANSPARENT)
478 {
479 int w = 0;
480 int h = 0;
481 GetSize( &w, &h );
482 wxCoord xx = XLOG2DEV(x);
483 wxCoord yy = YLOG2DEV(y);
484 if (m_window)
485 {
486 gdk_draw_line( m_window, m_penGC, 0, yy, XLOG2DEVREL(w), yy );
487 gdk_draw_line( m_window, m_penGC, xx, 0, xx, YLOG2DEVREL(h) );
488 }
489 }
490 }
491
492 void wxWindowDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2,
493 wxCoord xc, wxCoord yc )
494 {
495 wxCHECK_RET( Ok(), wxT("invalid window dc") );
496
497 wxCoord xx1 = XLOG2DEV(x1);
498 wxCoord yy1 = YLOG2DEV(y1);
499 wxCoord xx2 = XLOG2DEV(x2);
500 wxCoord yy2 = YLOG2DEV(y2);
501 wxCoord xxc = XLOG2DEV(xc);
502 wxCoord yyc = YLOG2DEV(yc);
503 double dx = xx1 - xxc;
504 double dy = yy1 - yyc;
505 double radius = sqrt((double)(dx*dx+dy*dy));
506 wxCoord r = (wxCoord)radius;
507 double radius1, radius2;
508
509 if (xx1 == xx2 && yy1 == yy2)
510 {
511 radius1 = 0.0;
512 radius2 = 360.0;
513 }
514 else if ( wxIsNullDouble(radius) )
515 {
516 radius1 =
517 radius2 = 0.0;
518 }
519 else
520 {
521 radius1 = (xx1 - xxc == 0) ?
522 (yy1 - yyc < 0) ? 90.0 : -90.0 :
523 -atan2(double(yy1-yyc), double(xx1-xxc)) * RAD2DEG;
524 radius2 = (xx2 - xxc == 0) ?
525 (yy2 - yyc < 0) ? 90.0 : -90.0 :
526 -atan2(double(yy2-yyc), double(xx2-xxc)) * RAD2DEG;
527 }
528 wxCoord alpha1 = wxCoord(radius1 * 64.0);
529 wxCoord alpha2 = wxCoord((radius2 - radius1) * 64.0);
530 while (alpha2 <= 0) alpha2 += 360*64;
531 while (alpha1 > 360*64) alpha1 -= 360*64;
532
533 if (m_window)
534 {
535 if (m_brush.GetStyle() != wxTRANSPARENT)
536 {
537 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
538 {
539 gdk_gc_set_ts_origin( m_textGC,
540 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
541 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
542 gdk_draw_arc( m_window, m_textGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
543 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
544 } else
545 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
546 {
547 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
548 gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
549 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
550 } else
551 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
552 {
553 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
554 gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
555 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
556 } else
557 if (m_brush.GetStyle() == wxSTIPPLE)
558 {
559 gdk_gc_set_ts_origin( m_brushGC,
560 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
561 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
562 gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
563 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
564 }
565 else
566 {
567 gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
568 }
569 }
570
571 if (m_pen.GetStyle() != wxTRANSPARENT)
572 {
573 gdk_draw_arc( m_window, m_penGC, FALSE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
574
575 gdk_draw_line( m_window, m_penGC, xx1, yy1, xxc, yyc );
576 gdk_draw_line( m_window, m_penGC, xxc, yyc, xx2, yy2 );
577 }
578 }
579
580 CalcBoundingBox (x1, y1);
581 CalcBoundingBox (x2, y2);
582 }
583
584 void wxWindowDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea )
585 {
586 wxCHECK_RET( Ok(), wxT("invalid window dc") );
587
588 wxCoord xx = XLOG2DEV(x);
589 wxCoord yy = YLOG2DEV(y);
590 wxCoord ww = m_signX * XLOG2DEVREL(width);
591 wxCoord hh = m_signY * YLOG2DEVREL(height);
592
593 // CMB: handle -ve width and/or height
594 if (ww < 0) { ww = -ww; xx = xx - ww; }
595 if (hh < 0) { hh = -hh; yy = yy - hh; }
596
597 if (m_window)
598 {
599 wxCoord start = wxCoord(sa * 64.0);
600 wxCoord end = wxCoord((ea-sa) * 64.0);
601
602 if (m_brush.GetStyle() != wxTRANSPARENT)
603 {
604 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
605 {
606 gdk_gc_set_ts_origin( m_textGC,
607 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
608 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
609 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy, ww, hh, start, end );
610 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
611 } else
612 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
613 {
614 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
615 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
616 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
617 } else
618 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
619 {
620 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
621 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
622 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
623 } else
624 if (m_brush.GetStyle() == wxSTIPPLE)
625 {
626 gdk_gc_set_ts_origin( m_brushGC,
627 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
628 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
629 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
630 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
631 }
632 else
633 {
634 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
635 }
636 }
637
638 if (m_pen.GetStyle() != wxTRANSPARENT)
639 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, start, end );
640 }
641
642 CalcBoundingBox (x, y);
643 CalcBoundingBox (x + width, y + height);
644 }
645
646 void wxWindowDC::DoDrawPoint( wxCoord x, wxCoord y )
647 {
648 wxCHECK_RET( Ok(), wxT("invalid window dc") );
649
650 if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window)
651 gdk_draw_point( m_window, m_penGC, XLOG2DEV(x), YLOG2DEV(y) );
652
653 CalcBoundingBox (x, y);
654 }
655
656 void wxWindowDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset )
657 {
658 wxCHECK_RET( Ok(), wxT("invalid window dc") );
659
660 if (m_pen.GetStyle() == wxTRANSPARENT) return;
661 if (n <= 0) return;
662
663 //Check, if scaling is necessary
664 const bool doScale =
665 xoffset != 0 || yoffset != 0 || XLOG2DEV(10) != 10 || YLOG2DEV(10) != 10;
666
667 // GdkPoint and wxPoint have the same memory layout, so we can cast one to the other
668 GdkPoint* gpts = reinterpret_cast<GdkPoint*>(points);
669
670 if (doScale)
671 gpts = new GdkPoint[n];
672
673 for (int i = 0; i < n; i++)
674 {
675 if (doScale)
676 {
677 gpts[i].x = XLOG2DEV(points[i].x + xoffset);
678 gpts[i].y = YLOG2DEV(points[i].y + yoffset);
679 }
680 CalcBoundingBox(points[i].x + xoffset, points[i].y + yoffset);
681 }
682
683 if (m_window)
684 gdk_draw_lines( m_window, m_penGC, gpts, n);
685
686 if (doScale)
687 delete[] gpts;
688 }
689
690 void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle) )
691 {
692 wxCHECK_RET( Ok(), wxT("invalid window dc") );
693
694 if (n <= 0) return;
695
696 //Check, if scaling is necessary
697 const bool doScale =
698 xoffset != 0 || yoffset != 0 || XLOG2DEV(10) != 10 || YLOG2DEV(10) != 10;
699
700 // GdkPoint and wxPoint have the same memory layout, so we can cast one to the other
701 GdkPoint* gdkpoints = reinterpret_cast<GdkPoint*>(points);
702
703 if (doScale)
704 gdkpoints = new GdkPoint[n];
705
706 int i;
707 for (i = 0 ; i < n ; i++)
708 {
709 if (doScale)
710 {
711 gdkpoints[i].x = XLOG2DEV(points[i].x + xoffset);
712 gdkpoints[i].y = YLOG2DEV(points[i].y + yoffset);
713 }
714 CalcBoundingBox(points[i].x + xoffset, points[i].y + yoffset);
715 }
716
717 if (m_window)
718 {
719 if (m_brush.GetStyle() != wxTRANSPARENT)
720 {
721 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
722 {
723 gdk_gc_set_ts_origin( m_textGC,
724 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
725 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
726 gdk_draw_polygon( m_window, m_textGC, TRUE, gdkpoints, n );
727 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
728 } else
729 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
730 {
731 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
732 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
733 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
734 } else
735 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
736 {
737 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
738 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
739 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
740 } else
741 if (m_brush.GetStyle() == wxSTIPPLE)
742 {
743 gdk_gc_set_ts_origin( m_brushGC,
744 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
745 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
746 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
747 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
748 }
749 else
750 {
751 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
752 }
753 }
754
755 if (m_pen.GetStyle() != wxTRANSPARENT)
756 {
757 /*
758 for (i = 0 ; i < n ; i++)
759 {
760 gdk_draw_line( m_window, m_penGC,
761 gdkpoints[i%n].x,
762 gdkpoints[i%n].y,
763 gdkpoints[(i+1)%n].x,
764 gdkpoints[(i+1)%n].y);
765 }
766 */
767 gdk_draw_polygon( m_window, m_penGC, FALSE, gdkpoints, n );
768
769 }
770 }
771
772 if (doScale)
773 delete[] gdkpoints;
774 }
775
776 void wxWindowDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
777 {
778 wxCHECK_RET( Ok(), wxT("invalid window dc") );
779
780 wxCoord xx = XLOG2DEV(x);
781 wxCoord yy = YLOG2DEV(y);
782 wxCoord ww = m_signX * XLOG2DEVREL(width);
783 wxCoord hh = m_signY * YLOG2DEVREL(height);
784
785 // CMB: draw nothing if transformed w or h is 0
786 if (ww == 0 || hh == 0) return;
787
788 // CMB: handle -ve width and/or height
789 if (ww < 0) { ww = -ww; xx = xx - ww; }
790 if (hh < 0) { hh = -hh; yy = yy - hh; }
791
792 if (m_window)
793 {
794 if (m_brush.GetStyle() != wxTRANSPARENT)
795 {
796 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
797 {
798 gdk_gc_set_ts_origin( m_textGC,
799 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
800 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
801 gdk_draw_rectangle( m_window, m_textGC, TRUE, xx, yy, ww, hh );
802 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
803 } else
804 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
805 {
806 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
807 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
808 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
809 } else
810 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
811 {
812 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
813 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
814 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
815 } else
816 if (m_brush.GetStyle() == wxSTIPPLE)
817 {
818 gdk_gc_set_ts_origin( m_brushGC,
819 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
820 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
821 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
822 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
823 }
824 else
825 {
826 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
827 }
828 }
829
830 if (m_pen.GetStyle() != wxTRANSPARENT)
831 gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-1, hh-1 );
832 }
833
834 CalcBoundingBox( x, y );
835 CalcBoundingBox( x + width, y + height );
836 }
837
838 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
839 {
840 wxCHECK_RET( Ok(), wxT("invalid window dc") );
841
842 if (radius < 0.0) radius = - radius * ((width < height) ? width : height);
843
844 wxCoord xx = XLOG2DEV(x);
845 wxCoord yy = YLOG2DEV(y);
846 wxCoord ww = m_signX * XLOG2DEVREL(width);
847 wxCoord hh = m_signY * YLOG2DEVREL(height);
848 wxCoord rr = XLOG2DEVREL((wxCoord)radius);
849
850 // CMB: handle -ve width and/or height
851 if (ww < 0) { ww = -ww; xx = xx - ww; }
852 if (hh < 0) { hh = -hh; yy = yy - hh; }
853
854 // CMB: if radius is zero use DrawRectangle() instead to avoid
855 // X drawing errors with small radii
856 if (rr == 0)
857 {
858 DrawRectangle( x, y, width, height );
859 return;
860 }
861
862 // CMB: draw nothing if transformed w or h is 0
863 if (ww == 0 || hh == 0) return;
864
865 // CMB: adjust size if outline is drawn otherwise the result is
866 // 1 pixel too wide and high
867 if (m_pen.GetStyle() != wxTRANSPARENT)
868 {
869 ww--;
870 hh--;
871 }
872
873 if (m_window)
874 {
875 // CMB: ensure dd is not larger than rectangle otherwise we
876 // get an hour glass shape
877 wxCoord dd = 2 * rr;
878 if (dd > ww) dd = ww;
879 if (dd > hh) dd = hh;
880 rr = dd / 2;
881
882 if (m_brush.GetStyle() != wxTRANSPARENT)
883 {
884 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
885 {
886 gdk_gc_set_ts_origin( m_textGC,
887 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
888 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
889 gdk_draw_rectangle( m_window, m_textGC, TRUE, xx+rr, yy, ww-dd+1, hh );
890 gdk_draw_rectangle( m_window, m_textGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
891 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
892 gdk_draw_arc( m_window, m_textGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
893 gdk_draw_arc( m_window, m_textGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
894 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
895 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
896 } else
897 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
898 {
899 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
900 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
901 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
902 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
903 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
904 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
905 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
906 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
907 } else
908 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
909 {
910 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
911 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
912 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
913 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
914 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
915 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
916 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
917 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
918 } else
919 if (m_brush.GetStyle() == wxSTIPPLE)
920 {
921 gdk_gc_set_ts_origin( m_brushGC,
922 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
923 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
924 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
925 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
926 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
927 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
928 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
929 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
930 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
931 }
932 else
933 {
934 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
935 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
936 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
937 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
938 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
939 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
940 }
941 }
942
943 if (m_pen.GetStyle() != wxTRANSPARENT)
944 {
945 gdk_draw_line( m_window, m_penGC, xx+rr+1, yy, xx+ww-rr, yy );
946 gdk_draw_line( m_window, m_penGC, xx+rr+1, yy+hh, xx+ww-rr, yy+hh );
947 gdk_draw_line( m_window, m_penGC, xx, yy+rr+1, xx, yy+hh-rr );
948 gdk_draw_line( m_window, m_penGC, xx+ww, yy+rr+1, xx+ww, yy+hh-rr );
949 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, dd, dd, 90*64, 90*64 );
950 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
951 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
952 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
953 }
954 }
955
956 // this ignores the radius
957 CalcBoundingBox( x, y );
958 CalcBoundingBox( x + width, y + height );
959 }
960
961 void wxWindowDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
962 {
963 wxCHECK_RET( Ok(), wxT("invalid window dc") );
964
965 wxCoord xx = XLOG2DEV(x);
966 wxCoord yy = YLOG2DEV(y);
967 wxCoord ww = m_signX * XLOG2DEVREL(width);
968 wxCoord hh = m_signY * YLOG2DEVREL(height);
969
970 // CMB: handle -ve width and/or height
971 if (ww < 0) { ww = -ww; xx = xx - ww; }
972 if (hh < 0) { hh = -hh; yy = yy - hh; }
973
974 if (m_window)
975 {
976 if (m_brush.GetStyle() != wxTRANSPARENT)
977 {
978 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
979 {
980 gdk_gc_set_ts_origin( m_textGC,
981 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
982 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
983 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
984 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
985 } else
986 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
987 {
988 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
989 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
990 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
991 } else
992 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
993 {
994 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
995 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
996 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
997 } else
998 if (m_brush.GetStyle() == wxSTIPPLE)
999 {
1000 gdk_gc_set_ts_origin( m_brushGC,
1001 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
1002 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
1003 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
1004 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
1005 }
1006 else
1007 {
1008 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
1009 }
1010 }
1011
1012 if (m_pen.GetStyle() != wxTRANSPARENT)
1013 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, 0, 360*64 );
1014 }
1015
1016 CalcBoundingBox( x, y );
1017 CalcBoundingBox( x + width, y + height );
1018 }
1019
1020 void wxWindowDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
1021 {
1022 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
1023 DoDrawBitmap( (const wxBitmap&)icon, x, y, true );
1024 }
1025
1026 void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap,
1027 wxCoord x, wxCoord y,
1028 bool useMask )
1029 {
1030 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1031
1032 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
1033
1034 bool is_mono = bitmap.GetDepth() == 1;
1035
1036 // scale/translate size and position
1037 int xx = XLOG2DEV(x);
1038 int yy = YLOG2DEV(y);
1039
1040 int w = bitmap.GetWidth();
1041 int h = bitmap.GetHeight();
1042
1043 CalcBoundingBox( x, y );
1044 CalcBoundingBox( x + w, y + h );
1045
1046 if (!m_window) return;
1047
1048 int ww = XLOG2DEVREL(w);
1049 int hh = YLOG2DEVREL(h);
1050
1051 // compare to current clipping region
1052 if (!m_currentClippingRegion.IsNull())
1053 {
1054 wxRegion tmp( xx,yy,ww,hh );
1055 tmp.Intersect( m_currentClippingRegion );
1056 if (tmp.IsEmpty())
1057 return;
1058 }
1059
1060 // scale bitmap if required
1061 wxBitmap use_bitmap = bitmap;
1062 if ((w != ww) || (h != hh))
1063 use_bitmap = use_bitmap.Rescale( 0, 0, ww, hh, ww, hh );
1064
1065 #if !GTK_CHECK_VERSION(2,2,0)
1066 // NB: We can't render pixbufs with GTK+ < 2.2, we need to use pixmaps code.
1067 // Pixbufs-based bitmaps with alpha channel don't have a mask, so we
1068 // have to call GetPixmap() here -- it converts the pixbuf into pixmap
1069 // and also creates the mask as a side-effect:
1070 use_bitmap.GetPixmap();
1071 #endif
1072
1073 // apply mask if any
1074 GdkBitmap *mask = (GdkBitmap *) NULL;
1075 if (useMask && use_bitmap.GetMask())
1076 mask = use_bitmap.GetMask()->GetBitmap();
1077
1078 GdkGC* use_gc = is_mono ? m_textGC : m_penGC;
1079
1080 GdkBitmap *new_mask = (GdkBitmap*) NULL;
1081
1082 if (mask != NULL)
1083 {
1084 if (!m_currentClippingRegion.IsNull())
1085 {
1086 GdkColor col;
1087 new_mask = gdk_pixmap_new( wxGetRootWindow()->window, ww, hh, 1 );
1088 GdkGC *gc = gdk_gc_new( new_mask );
1089 col.pixel = 0;
1090 gdk_gc_set_foreground( gc, &col );
1091 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh );
1092 col.pixel = 0;
1093 gdk_gc_set_background( gc, &col );
1094 col.pixel = 1;
1095 gdk_gc_set_foreground( gc, &col );
1096 gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() );
1097 gdk_gc_set_clip_origin( gc, -xx, -yy );
1098 gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED );
1099 gdk_gc_set_stipple( gc, mask );
1100 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh );
1101 mask = new_mask;
1102 g_object_unref (gc);
1103 }
1104
1105 gdk_gc_set_clip_mask(use_gc, mask);
1106 gdk_gc_set_clip_origin(use_gc, xx, yy);
1107 }
1108
1109 // Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1110 // drawing a mono-bitmap (XBitmap) we use the current text GC
1111 if (is_mono)
1112 {
1113 GdkPixmap *bitmap2 = gdk_pixmap_new( wxGetRootWindow()->window, ww, hh, -1 );
1114 GdkGC *gc = gdk_gc_new( bitmap2 );
1115 gdk_gc_set_foreground( gc, m_textForegroundColour.GetColor() );
1116 gdk_gc_set_background( gc, m_textBackgroundColour.GetColor() );
1117 gdk_wx_draw_bitmap( bitmap2, gc, use_bitmap.GetPixmap(), 0, 0, 0, 0, -1, -1 );
1118
1119 gdk_draw_drawable(m_window, use_gc, bitmap2, 0, 0, xx, yy, -1, -1);
1120
1121 g_object_unref (bitmap2);
1122 g_object_unref (gc);
1123 }
1124 else
1125 {
1126 #if GTK_CHECK_VERSION(2,2,0)
1127 if (!gtk_check_version(2,2,0) && use_bitmap.HasPixbuf())
1128 {
1129 gdk_draw_pixbuf(m_window, use_gc,
1130 use_bitmap.GetPixbuf(),
1131 0, 0, xx, yy, -1, -1,
1132 GDK_RGB_DITHER_NORMAL, xx, yy);
1133 }
1134 else
1135 #endif
1136 {
1137 gdk_draw_drawable(m_window, use_gc,
1138 use_bitmap.GetPixmap(),
1139 0, 0, xx, yy, -1, -1);
1140 }
1141 }
1142
1143 // remove mask again if any
1144 if (mask != NULL)
1145 {
1146 gdk_gc_set_clip_mask(use_gc, NULL);
1147 gdk_gc_set_clip_origin(use_gc, 0, 0);
1148 if (!m_currentClippingRegion.IsNull())
1149 gdk_gc_set_clip_region(use_gc, m_currentClippingRegion.GetRegion());
1150 if (new_mask != NULL)
1151 g_object_unref(new_mask);
1152 }
1153 }
1154
1155 bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest,
1156 wxCoord width, wxCoord height,
1157 wxDC *source,
1158 wxCoord xsrc, wxCoord ysrc,
1159 int logical_func,
1160 bool useMask,
1161 wxCoord xsrcMask, wxCoord ysrcMask )
1162 {
1163 wxCHECK_MSG( Ok(), false, wxT("invalid window dc") );
1164
1165 wxCHECK_MSG( source, false, wxT("invalid source dc") );
1166
1167 if (!m_window) return false;
1168
1169 // transform the source DC coords to the device ones
1170 xsrc = source->LogicalToDeviceX(xsrc);
1171 ysrc = source->LogicalToDeviceY(ysrc);
1172
1173 wxClientDC *srcDC = (wxClientDC*)source;
1174 wxMemoryDC *memDC = (wxMemoryDC*)source;
1175
1176 bool use_bitmap_method = false;
1177 bool is_mono = false;
1178
1179 if (xsrcMask == -1 && ysrcMask == -1)
1180 {
1181 xsrcMask = xsrc;
1182 ysrcMask = ysrc;
1183 }
1184
1185 if (srcDC->m_isMemDC)
1186 {
1187 if (!memDC->m_selected.Ok()) return false;
1188
1189 is_mono = (memDC->m_selected.GetDepth() == 1);
1190
1191 // we use the "XCopyArea" way to copy a memory dc into
1192 // a different window if the memory dc BOTH
1193 // a) doesn't have any mask or its mask isn't used
1194 // b) it is clipped
1195 // c) is not 1-bit
1196
1197 if (useMask && (memDC->m_selected.GetMask()))
1198 {
1199 // we HAVE TO use the direct way for memory dcs
1200 // that have mask since the XCopyArea doesn't know
1201 // about masks
1202 use_bitmap_method = true;
1203 }
1204 else if (is_mono)
1205 {
1206 // we HAVE TO use the direct way for memory dcs
1207 // that are bitmaps because XCopyArea doesn't cope
1208 // with different bit depths
1209 use_bitmap_method = true;
1210 }
1211 else if ((xsrc == 0) && (ysrc == 0) &&
1212 (width == memDC->m_selected.GetWidth()) &&
1213 (height == memDC->m_selected.GetHeight()))
1214 {
1215 // we SHOULD use the direct way if all of the bitmap
1216 // in the memory dc is copied in which case XCopyArea
1217 // wouldn't be able able to boost performace by reducing
1218 // the area to be scaled
1219 use_bitmap_method = true;
1220 }
1221 }
1222
1223 CalcBoundingBox( xdest, ydest );
1224 CalcBoundingBox( xdest + width, ydest + height );
1225
1226 // scale/translate size and position
1227 wxCoord xx = XLOG2DEV(xdest);
1228 wxCoord yy = YLOG2DEV(ydest);
1229
1230 wxCoord ww = XLOG2DEVREL(width);
1231 wxCoord hh = YLOG2DEVREL(height);
1232
1233 // compare to current clipping region
1234 if (!m_currentClippingRegion.IsNull())
1235 {
1236 wxRegion tmp( xx,yy,ww,hh );
1237 tmp.Intersect( m_currentClippingRegion );
1238 if (tmp.IsEmpty())
1239 return true;
1240 }
1241
1242 int old_logical_func = m_logicalFunction;
1243 SetLogicalFunction( logical_func );
1244
1245 if (use_bitmap_method)
1246 {
1247 // scale/translate bitmap size
1248 wxCoord bm_width = memDC->m_selected.GetWidth();
1249 wxCoord bm_height = memDC->m_selected.GetHeight();
1250
1251 // Get clip coords for the bitmap. If we don't
1252 // use wxBitmap::Rescale(), which can clip the
1253 // bitmap, these are the same as the original
1254 // coordinates
1255 wxCoord cx = xx;
1256 wxCoord cy = yy;
1257 wxCoord cw = ww;
1258 wxCoord ch = hh;
1259
1260 // interpret userscale of src too
1261 double xsc,ysc;
1262 memDC->GetUserScale(&xsc,&ysc);
1263 bm_width = (int) (bm_width / xsc);
1264 bm_height = (int) (bm_height / ysc);
1265
1266 wxCoord bm_ww = XLOG2DEVREL( bm_width );
1267 wxCoord bm_hh = YLOG2DEVREL( bm_height );
1268
1269 // Scale bitmap if required
1270 wxBitmap use_bitmap = memDC->m_selected;
1271 if ((memDC->m_selected.GetWidth()!= bm_ww) || ( memDC->m_selected.GetHeight()!= bm_hh))
1272 {
1273 // This indicates that the blitting code below will get
1274 // a clipped bitmap and therefore needs to move the origin
1275 // accordingly
1276 wxRegion tmp( xx,yy,ww,hh );
1277 tmp.Intersect( m_currentClippingRegion );
1278 tmp.GetBox(cx,cy,cw,ch);
1279
1280 // Scale and clipped bitmap
1281 use_bitmap = memDC->m_selected.Rescale(cx-xx,cy-yy,cw,ch,bm_ww,bm_hh);
1282 }
1283
1284 // apply mask if any
1285 GdkBitmap *mask = (GdkBitmap *) NULL;
1286 if (useMask && use_bitmap.GetMask())
1287 mask = use_bitmap.GetMask()->GetBitmap();
1288
1289 GdkGC* use_gc = is_mono ? m_textGC : m_penGC;
1290
1291 GdkBitmap *new_mask = (GdkBitmap*) NULL;
1292
1293 if (mask != NULL)
1294 {
1295 if (!m_currentClippingRegion.IsNull())
1296 {
1297 GdkColor col;
1298 new_mask = gdk_pixmap_new( wxGetRootWindow()->window, bm_ww, bm_hh, 1 );
1299 GdkGC *gc = gdk_gc_new( new_mask );
1300 col.pixel = 0;
1301 gdk_gc_set_foreground( gc, &col );
1302 gdk_gc_set_ts_origin( gc, -xsrcMask, -ysrcMask);
1303 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh );
1304 col.pixel = 0;
1305 gdk_gc_set_background( gc, &col );
1306 col.pixel = 1;
1307 gdk_gc_set_foreground( gc, &col );
1308 gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() );
1309 // was: gdk_gc_set_clip_origin( gc, -xx, -yy );
1310 gdk_gc_set_clip_origin( gc, -cx, -cy );
1311 gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED );
1312 gdk_gc_set_stipple( gc, mask );
1313 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh );
1314 mask = new_mask;
1315 g_object_unref (gc);
1316 }
1317
1318 gdk_gc_set_clip_mask(use_gc, mask);
1319 if (new_mask != NULL)
1320 gdk_gc_set_clip_origin(use_gc, cx, cy);
1321 else
1322 gdk_gc_set_clip_origin(use_gc, cx - xsrcMask, cy - ysrcMask);
1323 }
1324
1325 // Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1326 // drawing a mono-bitmap (XBitmap) we use the current text GC
1327
1328 if (is_mono)
1329 {
1330 GdkPixmap *bitmap = gdk_pixmap_new( wxGetRootWindow()->window, bm_ww, bm_hh, -1 );
1331 GdkGC *gc = gdk_gc_new( bitmap );
1332 gdk_gc_set_foreground( gc, m_textForegroundColour.GetColor() );
1333 gdk_gc_set_background( gc, m_textBackgroundColour.GetColor() );
1334 gdk_wx_draw_bitmap( bitmap, gc, use_bitmap.GetPixmap(), 0, 0, 0, 0, -1, -1 );
1335
1336 gdk_draw_drawable(m_window, use_gc, bitmap, xsrc, ysrc, cx, cy, cw, ch);
1337
1338 g_object_unref (bitmap);
1339 g_object_unref (gc);
1340 }
1341 else
1342 {
1343 // was: gdk_draw_drawable( m_window, m_penGC, use_bitmap.GetPixmap(), xsrc, ysrc, xx, yy, ww, hh );
1344 gdk_draw_drawable(m_window, use_gc, use_bitmap.GetPixmap(), xsrc, ysrc, cx, cy, cw, ch);
1345 }
1346
1347 // remove mask again if any
1348 if (mask != NULL)
1349 {
1350 gdk_gc_set_clip_mask(use_gc, NULL);
1351 gdk_gc_set_clip_origin(use_gc, 0, 0);
1352 if (!m_currentClippingRegion.IsNull())
1353 gdk_gc_set_clip_region(use_gc, m_currentClippingRegion.GetRegion());
1354 }
1355
1356 if (new_mask)
1357 g_object_unref (new_mask);
1358 }
1359 else // use_bitmap_method
1360 {
1361 if ((width != ww) || (height != hh))
1362 {
1363 // get clip coords
1364 wxRegion tmp( xx,yy,ww,hh );
1365 tmp.Intersect( m_currentClippingRegion );
1366 wxCoord cx,cy,cw,ch;
1367 tmp.GetBox(cx,cy,cw,ch);
1368
1369 // rescale bitmap
1370 wxBitmap bitmap = memDC->m_selected.Rescale( cx-xx, cy-yy, cw, ch, ww, hh );
1371
1372 // draw scaled bitmap
1373 // was: gdk_draw_drawable( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
1374 gdk_draw_drawable( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, cx, cy, -1, -1 );
1375 }
1376 else
1377 {
1378 // No scaling and not a memory dc with a mask either
1379
1380 // copy including child window contents
1381 gdk_gc_set_subwindow( m_penGC, GDK_INCLUDE_INFERIORS );
1382 gdk_draw_drawable( m_window, m_penGC,
1383 srcDC->GetWindow(),
1384 xsrc, ysrc, xx, yy,
1385 width, height );
1386 gdk_gc_set_subwindow( m_penGC, GDK_CLIP_BY_CHILDREN );
1387 }
1388 }
1389
1390 SetLogicalFunction( old_logical_func );
1391
1392 return true;
1393 }
1394
1395 void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y )
1396 {
1397 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1398
1399 if (!m_window) return;
1400
1401 if (text.empty()) return;
1402
1403 x = XLOG2DEV(x);
1404 y = YLOG2DEV(y);
1405
1406 wxCHECK_RET( m_context, wxT("no Pango context") );
1407 wxCHECK_RET( m_layout, wxT("no Pango layout") );
1408 wxCHECK_RET( m_fontdesc, wxT("no Pango font description") );
1409
1410 bool underlined = m_font.Ok() && m_font.GetUnderlined();
1411
1412 const wxCharBuffer data = wxGTK_CONV( text );
1413 if ( !data )
1414 return;
1415 const size_t datalen = strlen(data);
1416 pango_layout_set_text( m_layout, data, datalen);
1417
1418 if (underlined)
1419 {
1420 PangoAttrList *attrs = pango_attr_list_new();
1421 PangoAttribute *a = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
1422 a->start_index = 0;
1423 a->end_index = datalen;
1424 pango_attr_list_insert(attrs, a);
1425 pango_layout_set_attributes(m_layout, attrs);
1426 pango_attr_list_unref(attrs);
1427 }
1428
1429 int w,h;
1430
1431 if (fabs(m_scaleY - 1.0) > 0.00001)
1432 {
1433 // If there is a user or actually any scale applied to
1434 // the device context, scale the font.
1435
1436 // scale font description
1437 gint oldSize = pango_font_description_get_size( m_fontdesc );
1438 double size = oldSize;
1439 size = size * m_scaleY;
1440 pango_font_description_set_size( m_fontdesc, (gint)size );
1441
1442 // actually apply scaled font
1443 pango_layout_set_font_description( m_layout, m_fontdesc );
1444
1445 pango_layout_get_pixel_size( m_layout, &w, &h );
1446 if ( m_backgroundMode == wxSOLID )
1447 {
1448 gdk_gc_set_foreground(m_textGC, m_textBackgroundColour.GetColor());
1449 gdk_draw_rectangle(m_window, m_textGC, TRUE, x, y, w, h);
1450 gdk_gc_set_foreground(m_textGC, m_textForegroundColour.GetColor());
1451 }
1452
1453 // Draw layout.
1454 gdk_draw_layout( m_window, m_textGC, x, y, m_layout );
1455
1456 // reset unscaled size
1457 pango_font_description_set_size( m_fontdesc, oldSize );
1458
1459 // actually apply unscaled font
1460 pango_layout_set_font_description( m_layout, m_fontdesc );
1461 }
1462 else
1463 {
1464 pango_layout_get_pixel_size( m_layout, &w, &h );
1465 if ( m_backgroundMode == wxSOLID )
1466 {
1467 gdk_gc_set_foreground(m_textGC, m_textBackgroundColour.GetColor());
1468 gdk_draw_rectangle(m_window, m_textGC, TRUE, x, y, w, h);
1469 gdk_gc_set_foreground(m_textGC, m_textForegroundColour.GetColor());
1470 }
1471 // Draw layout.
1472 gdk_draw_layout( m_window, m_textGC, x, y, m_layout );
1473 }
1474
1475 if (underlined)
1476 {
1477 // undo underline attributes setting:
1478 pango_layout_set_attributes(m_layout, NULL);
1479 }
1480
1481 wxCoord width = w;
1482 wxCoord height = h;
1483
1484 width = wxCoord(width / m_scaleX);
1485 height = wxCoord(height / m_scaleY);
1486 CalcBoundingBox (x + width, y + height);
1487 CalcBoundingBox (x, y);
1488 }
1489
1490
1491 // TODO: There is an example of rotating text with GTK2 that would probably be
1492 // a better approach here:
1493 // http://www.daa.com.au/pipermail/pygtk/2003-April/005052.html
1494
1495 void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle )
1496 {
1497 if (!m_window || text.empty())
1498 return;
1499
1500 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1501
1502 if ( wxIsNullDouble(angle) )
1503 {
1504 DrawText(text, x, y);
1505 return;
1506 }
1507
1508 wxCoord w;
1509 wxCoord h;
1510
1511 // TODO: implement later without GdkFont for GTK 2.0
1512 GetTextExtent(text, &w, &h, NULL,NULL, &m_font);
1513
1514 // draw the string normally
1515 wxBitmap src(w, h);
1516 wxMemoryDC dc;
1517 dc.SelectObject(src);
1518 dc.SetFont(GetFont());
1519 dc.SetBackground(*wxBLACK_BRUSH);
1520 dc.SetBrush(*wxBLACK_BRUSH);
1521 dc.Clear();
1522 dc.SetTextForeground( *wxWHITE );
1523 dc.DrawText(text, 0, 0);
1524 dc.SelectObject(wxNullBitmap);
1525
1526 // Calculate the size of the rotated bounding box.
1527 double rad = DegToRad(angle);
1528 double dx = cos(rad),
1529 dy = sin(rad);
1530
1531 // the rectngle vertices are counted clockwise with the first one being at
1532 // (0, 0) (or, rather, at (x, y))
1533 double x2 = w*dx,
1534 y2 = -w*dy; // y axis points to the bottom, hence minus
1535 double x4 = h*dy,
1536 y4 = h*dx;
1537 double x3 = x4 + x2,
1538 y3 = y4 + y2;
1539
1540 // calc max and min
1541 wxCoord maxX = (wxCoord)(dmax(x2, dmax(x3, x4)) + 0.5),
1542 maxY = (wxCoord)(dmax(y2, dmax(y3, y4)) + 0.5),
1543 minX = (wxCoord)(dmin(x2, dmin(x3, x4)) - 0.5),
1544 minY = (wxCoord)(dmin(y2, dmin(y3, y4)) - 0.5);
1545
1546
1547 wxImage image = src.ConvertToImage();
1548
1549 image.ConvertColourToAlpha( m_textForegroundColour.Red(),
1550 m_textForegroundColour.Green(),
1551 m_textForegroundColour.Blue() );
1552 image = image.Rotate( rad, wxPoint(0,0) );
1553
1554 int i_angle = (int) angle;
1555 i_angle = i_angle % 360;
1556 if (i_angle < 0)
1557 i_angle += 360;
1558 int xoffset = 0;
1559 if ((i_angle >= 90.0) && (i_angle < 270.0))
1560 xoffset = image.GetWidth();
1561 int yoffset = 0;
1562 if ((i_angle >= 0.0) && (i_angle < 180.0))
1563 yoffset = image.GetHeight();
1564
1565 if ((i_angle >= 0) && (i_angle < 90))
1566 yoffset -= (int)( cos(rad)*h );
1567 if ((i_angle >= 90) && (i_angle < 180))
1568 xoffset -= (int)( sin(rad)*h );
1569 if ((i_angle >= 180) && (i_angle < 270))
1570 yoffset -= (int)( cos(rad)*h );
1571 if ((i_angle >= 270) && (i_angle < 360))
1572 xoffset -= (int)( sin(rad)*h );
1573
1574 int i_x = x - xoffset;
1575 int i_y = y - yoffset;
1576
1577 src = image;
1578 DoDrawBitmap( src, i_x, i_y, true );
1579
1580
1581 // it would be better to draw with non underlined font and draw the line
1582 // manually here (it would be more straight...)
1583 #if 0
1584 if ( m_font.GetUnderlined() )
1585 {
1586 gdk_draw_line( m_window, m_textGC,
1587 XLOG2DEV(x + x4), YLOG2DEV(y + y4 + font->descent),
1588 XLOG2DEV(x + x3), YLOG2DEV(y + y3 + font->descent));
1589 }
1590 #endif // 0
1591
1592 // update the bounding box
1593 CalcBoundingBox(x + minX, y + minY);
1594 CalcBoundingBox(x + maxX, y + maxY);
1595 }
1596
1597 void wxWindowDC::DoGetTextExtent(const wxString &string,
1598 wxCoord *width, wxCoord *height,
1599 wxCoord *descent, wxCoord *externalLeading,
1600 wxFont *theFont) const
1601 {
1602 if ( width )
1603 *width = 0;
1604 if ( height )
1605 *height = 0;
1606 if ( descent )
1607 *descent = 0;
1608 if ( externalLeading )
1609 *externalLeading = 0;
1610
1611 if (string.empty())
1612 return;
1613
1614 // ensure that theFont is always non-NULL
1615 if ( !theFont || !theFont->Ok() )
1616 theFont = wx_const_cast(wxFont *, &m_font);
1617
1618 // and use it if it's valid
1619 if ( theFont->Ok() )
1620 {
1621 pango_layout_set_font_description
1622 (
1623 m_layout,
1624 theFont->GetNativeFontInfo()->description
1625 );
1626 }
1627
1628 // Set layout's text
1629 const wxCharBuffer dataUTF8 = wxGTK_CONV_FONT(string, *theFont);
1630 if ( !dataUTF8 )
1631 {
1632 // hardly ideal, but what else can we do if conversion failed?
1633 return;
1634 }
1635
1636 pango_layout_set_text( m_layout, dataUTF8, strlen(dataUTF8) );
1637
1638 if (descent)
1639 {
1640 int h;
1641 pango_layout_get_pixel_size( m_layout, width, &h );
1642 PangoLayoutIter *iter = pango_layout_get_iter(m_layout);
1643 int baseline = pango_layout_iter_get_baseline(iter);
1644 pango_layout_iter_free(iter);
1645 *descent = h - PANGO_PIXELS(baseline);
1646
1647 if (height)
1648 *height = (wxCoord) h;
1649 }
1650 else
1651 {
1652 pango_layout_get_pixel_size( m_layout, width, height );
1653 }
1654
1655 // Reset old font description
1656 if (theFont)
1657 pango_layout_set_font_description( m_layout, m_fontdesc );
1658 }
1659
1660 wxCoord wxWindowDC::GetCharWidth() const
1661 {
1662 pango_layout_set_text( m_layout, "H", 1 );
1663 int w;
1664 pango_layout_get_pixel_size( m_layout, &w, NULL );
1665 return w;
1666 }
1667
1668 wxCoord wxWindowDC::GetCharHeight() const
1669 {
1670 PangoFontMetrics *metrics = pango_context_get_metrics (m_context, m_fontdesc, NULL);
1671 return PANGO_PIXELS (pango_font_metrics_get_descent (metrics) + pango_font_metrics_get_ascent (metrics));
1672 }
1673
1674 void wxWindowDC::Clear()
1675 {
1676 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1677
1678 if (!m_window) return;
1679
1680 // VZ: the code below results in infinite recursion and crashes when
1681 // dc.Clear() is done from OnPaint() so I disable it for now.
1682 // I don't know what the correct fix is but Clear() surely should not
1683 // reenter OnPaint()!
1684 #if 0
1685 /* - we either are a memory dc or have a window as the
1686 owner. anything else shouldn't happen.
1687 - we don't use gdk_window_clear() as we don't set
1688 the window's background colour anymore. it is too
1689 much pain to keep the DC's and the window's back-
1690 ground colour in synch. */
1691
1692 if (m_owner)
1693 {
1694 m_owner->Clear();
1695 return;
1696 }
1697
1698 if (m_isMemDC)
1699 {
1700 int width,height;
1701 GetSize( &width, &height );
1702 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
1703 return;
1704 }
1705 #else // 1
1706 int width,height;
1707 GetSize( &width, &height );
1708 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
1709 #endif // 0/1
1710 }
1711
1712 void wxWindowDC::SetFont( const wxFont &font )
1713 {
1714 m_font = font;
1715
1716 if (m_font.Ok())
1717 {
1718 if (m_fontdesc)
1719 pango_font_description_free( m_fontdesc );
1720
1721 m_fontdesc = pango_font_description_copy( m_font.GetNativeFontInfo()->description );
1722
1723
1724 if (m_owner)
1725 {
1726 PangoContext *oldContext = m_context;
1727
1728 m_context = m_owner->GtkGetPangoDefaultContext();
1729
1730 // If we switch back/forth between different contexts
1731 // we also have to create a new layout. I think so,
1732 // at least, and it doesn't hurt to do it.
1733 if (oldContext != m_context)
1734 {
1735 if (m_layout)
1736 g_object_unref (m_layout);
1737
1738 m_layout = pango_layout_new( m_context );
1739 }
1740 }
1741
1742 pango_layout_set_font_description( m_layout, m_fontdesc );
1743 }
1744 }
1745
1746 void wxWindowDC::SetPen( const wxPen &pen )
1747 {
1748 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1749
1750 if (m_pen == pen) return;
1751
1752 m_pen = pen;
1753
1754 if (!m_pen.Ok()) return;
1755
1756 if (!m_window) return;
1757
1758 gint width = m_pen.GetWidth();
1759 if (width <= 0)
1760 {
1761 // CMB: if width is non-zero scale it with the dc
1762 width = 1;
1763 }
1764 else
1765 {
1766 // X doesn't allow different width in x and y and so we take
1767 // the average
1768 double w = 0.5 +
1769 ( fabs((double) XLOG2DEVREL(width)) +
1770 fabs((double) YLOG2DEVREL(width)) ) / 2.0;
1771 width = (int)w;
1772 if ( !width )
1773 {
1774 // width can't be 0 or an internal GTK error occurs inside
1775 // gdk_gc_set_dashes() below
1776 width = 1;
1777 }
1778 }
1779
1780 static const wxGTKDash dotted[] = {1, 1};
1781 static const wxGTKDash short_dashed[] = {2, 2};
1782 static const wxGTKDash wxCoord_dashed[] = {2, 4};
1783 static const wxGTKDash dotted_dashed[] = {3, 3, 1, 3};
1784
1785 // We express dash pattern in pen width unit, so we are
1786 // independent of zoom factor and so on...
1787 int req_nb_dash;
1788 const wxGTKDash *req_dash;
1789
1790 GdkLineStyle lineStyle = GDK_LINE_SOLID;
1791 switch (m_pen.GetStyle())
1792 {
1793 case wxUSER_DASH:
1794 {
1795 lineStyle = GDK_LINE_ON_OFF_DASH;
1796 req_nb_dash = m_pen.GetDashCount();
1797 req_dash = (wxGTKDash*)m_pen.GetDash();
1798 break;
1799 }
1800 case wxDOT:
1801 {
1802 lineStyle = GDK_LINE_ON_OFF_DASH;
1803 req_nb_dash = 2;
1804 req_dash = dotted;
1805 break;
1806 }
1807 case wxLONG_DASH:
1808 {
1809 lineStyle = GDK_LINE_ON_OFF_DASH;
1810 req_nb_dash = 2;
1811 req_dash = wxCoord_dashed;
1812 break;
1813 }
1814 case wxSHORT_DASH:
1815 {
1816 lineStyle = GDK_LINE_ON_OFF_DASH;
1817 req_nb_dash = 2;
1818 req_dash = short_dashed;
1819 break;
1820 }
1821 case wxDOT_DASH:
1822 {
1823 // lineStyle = GDK_LINE_DOUBLE_DASH;
1824 lineStyle = GDK_LINE_ON_OFF_DASH;
1825 req_nb_dash = 4;
1826 req_dash = dotted_dashed;
1827 break;
1828 }
1829
1830 case wxTRANSPARENT:
1831 case wxSTIPPLE_MASK_OPAQUE:
1832 case wxSTIPPLE:
1833 case wxSOLID:
1834 default:
1835 {
1836 lineStyle = GDK_LINE_SOLID;
1837 req_dash = (wxGTKDash*)NULL;
1838 req_nb_dash = 0;
1839 break;
1840 }
1841 }
1842
1843 if (req_dash && req_nb_dash)
1844 {
1845 wxGTKDash *real_req_dash = new wxGTKDash[req_nb_dash];
1846 if (real_req_dash)
1847 {
1848 for (int i = 0; i < req_nb_dash; i++)
1849 real_req_dash[i] = req_dash[i] * width;
1850 gdk_gc_set_dashes( m_penGC, 0, real_req_dash, req_nb_dash );
1851 delete[] real_req_dash;
1852 }
1853 else
1854 {
1855 // No Memory. We use non-scaled dash pattern...
1856 gdk_gc_set_dashes( m_penGC, 0, (wxGTKDash*)req_dash, req_nb_dash );
1857 }
1858 }
1859
1860 GdkCapStyle capStyle = GDK_CAP_ROUND;
1861 switch (m_pen.GetCap())
1862 {
1863 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
1864 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
1865 case wxCAP_ROUND:
1866 default:
1867 {
1868 if (width <= 1)
1869 {
1870 width = 0;
1871 capStyle = GDK_CAP_NOT_LAST;
1872 }
1873 else
1874 {
1875 capStyle = GDK_CAP_ROUND;
1876 }
1877 break;
1878 }
1879 }
1880
1881 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
1882 switch (m_pen.GetJoin())
1883 {
1884 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
1885 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
1886 case wxJOIN_ROUND:
1887 default: { joinStyle = GDK_JOIN_ROUND; break; }
1888 }
1889
1890 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
1891
1892 m_pen.GetColour().CalcPixel( m_cmap );
1893 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
1894 }
1895
1896 void wxWindowDC::SetBrush( const wxBrush &brush )
1897 {
1898 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1899
1900 if (m_brush == brush) return;
1901
1902 m_brush = brush;
1903
1904 if (!m_brush.Ok()) return;
1905
1906 if (!m_window) return;
1907
1908 m_brush.GetColour().CalcPixel( m_cmap );
1909 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
1910
1911 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
1912
1913 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
1914 {
1915 if (m_brush.GetStipple()->GetDepth() != 1)
1916 {
1917 gdk_gc_set_fill( m_brushGC, GDK_TILED );
1918 gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() );
1919 }
1920 else
1921 {
1922 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
1923 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetPixmap() );
1924 }
1925 }
1926
1927 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
1928 {
1929 gdk_gc_set_fill( m_textGC, GDK_OPAQUE_STIPPLED);
1930 gdk_gc_set_stipple( m_textGC, m_brush.GetStipple()->GetMask()->GetBitmap() );
1931 }
1932
1933 if (m_brush.IsHatch())
1934 {
1935 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
1936 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
1937 gdk_gc_set_stipple( m_brushGC, hatches[num] );
1938 }
1939 }
1940
1941 void wxWindowDC::SetBackground( const wxBrush &brush )
1942 {
1943 /* CMB 21/7/98: Added SetBackground. Sets background brush
1944 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1945
1946 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1947
1948 if (m_backgroundBrush == brush) return;
1949
1950 m_backgroundBrush = brush;
1951
1952 if (!m_backgroundBrush.Ok()) return;
1953
1954 if (!m_window) return;
1955
1956 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
1957 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
1958 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
1959 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
1960 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
1961
1962 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
1963
1964 if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok()))
1965 {
1966 if (m_backgroundBrush.GetStipple()->GetDepth() != 1)
1967 {
1968 gdk_gc_set_fill( m_bgGC, GDK_TILED );
1969 gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
1970 }
1971 else
1972 {
1973 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
1974 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
1975 }
1976 }
1977
1978 if (m_backgroundBrush.IsHatch())
1979 {
1980 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
1981 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
1982 gdk_gc_set_stipple( m_bgGC, hatches[num] );
1983 }
1984 }
1985
1986 void wxWindowDC::SetLogicalFunction( int function )
1987 {
1988 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1989
1990 if (m_logicalFunction == function)
1991 return;
1992
1993 // VZ: shouldn't this be a CHECK?
1994 if (!m_window)
1995 return;
1996
1997 GdkFunction mode;
1998 switch (function)
1999 {
2000 case wxXOR: mode = GDK_XOR; break;
2001 case wxINVERT: mode = GDK_INVERT; break;
2002 case wxOR_REVERSE: mode = GDK_OR_REVERSE; break;
2003 case wxAND_REVERSE: mode = GDK_AND_REVERSE; break;
2004 case wxCLEAR: mode = GDK_CLEAR; break;
2005 case wxSET: mode = GDK_SET; break;
2006 case wxOR_INVERT: mode = GDK_OR_INVERT; break;
2007 case wxAND: mode = GDK_AND; break;
2008 case wxOR: mode = GDK_OR; break;
2009 case wxEQUIV: mode = GDK_EQUIV; break;
2010 case wxNAND: mode = GDK_NAND; break;
2011 case wxAND_INVERT: mode = GDK_AND_INVERT; break;
2012 case wxCOPY: mode = GDK_COPY; break;
2013 case wxNO_OP: mode = GDK_NOOP; break;
2014 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
2015
2016 // unsupported by GTK
2017 case wxNOR: mode = GDK_COPY; break;
2018 default:
2019 wxFAIL_MSG( wxT("unsupported logical function") );
2020 mode = GDK_COPY;
2021 }
2022
2023 m_logicalFunction = function;
2024
2025 gdk_gc_set_function( m_penGC, mode );
2026 gdk_gc_set_function( m_brushGC, mode );
2027
2028 // to stay compatible with wxMSW, we don't apply ROPs to the text
2029 // operations (i.e. DrawText/DrawRotatedText).
2030 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
2031 gdk_gc_set_function( m_textGC, mode );
2032 }
2033
2034 void wxWindowDC::SetTextForeground( const wxColour &col )
2035 {
2036 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2037
2038 // don't set m_textForegroundColour to an invalid colour as we'd crash
2039 // later then (we use m_textForegroundColour.GetColor() without checking
2040 // in a few places)
2041 if ( !col.Ok() || (m_textForegroundColour == col) )
2042 return;
2043
2044 m_textForegroundColour = col;
2045
2046 if ( m_window )
2047 {
2048 m_textForegroundColour.CalcPixel( m_cmap );
2049 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
2050 }
2051 }
2052
2053 void wxWindowDC::SetTextBackground( const wxColour &col )
2054 {
2055 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2056
2057 // same as above
2058 if ( !col.Ok() || (m_textBackgroundColour == col) )
2059 return;
2060
2061 m_textBackgroundColour = col;
2062
2063 if ( m_window )
2064 {
2065 m_textBackgroundColour.CalcPixel( m_cmap );
2066 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
2067 }
2068 }
2069
2070 void wxWindowDC::SetBackgroundMode( int mode )
2071 {
2072 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2073
2074 m_backgroundMode = mode;
2075
2076 if (!m_window) return;
2077
2078 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
2079 // transparent/solid background mode
2080
2081 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
2082 {
2083 gdk_gc_set_fill( m_brushGC,
2084 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
2085 }
2086 }
2087
2088 void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
2089 {
2090 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
2091 }
2092
2093 void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
2094 {
2095 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2096
2097 if (!m_window) return;
2098
2099 wxRect rect;
2100 rect.x = XLOG2DEV(x);
2101 rect.y = YLOG2DEV(y);
2102 rect.width = XLOG2DEVREL(width);
2103 rect.height = YLOG2DEVREL(height);
2104
2105 if (!m_currentClippingRegion.IsNull())
2106 m_currentClippingRegion.Intersect( rect );
2107 else
2108 m_currentClippingRegion.Union( rect );
2109
2110 #if USE_PAINT_REGION
2111 if (!m_paintClippingRegion.IsNull())
2112 m_currentClippingRegion.Intersect( m_paintClippingRegion );
2113 #endif
2114
2115 wxCoord xx, yy, ww, hh;
2116 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
2117 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
2118
2119 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2120 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2121 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2122 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
2123 }
2124
2125 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
2126 {
2127 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2128
2129 if (region.Empty())
2130 {
2131 DestroyClippingRegion();
2132 return;
2133 }
2134
2135 if (!m_window) return;
2136
2137 if (!m_currentClippingRegion.IsNull())
2138 m_currentClippingRegion.Intersect( region );
2139 else
2140 m_currentClippingRegion.Union( region );
2141
2142 #if USE_PAINT_REGION
2143 if (!m_paintClippingRegion.IsNull())
2144 m_currentClippingRegion.Intersect( m_paintClippingRegion );
2145 #endif
2146
2147 wxCoord xx, yy, ww, hh;
2148 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
2149 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
2150
2151 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2152 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2153 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2154 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
2155 }
2156
2157 void wxWindowDC::DestroyClippingRegion()
2158 {
2159 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2160
2161 wxDC::DestroyClippingRegion();
2162
2163 m_currentClippingRegion.Clear();
2164
2165 #if USE_PAINT_REGION
2166 if (!m_paintClippingRegion.IsEmpty())
2167 m_currentClippingRegion.Union( m_paintClippingRegion );
2168 #endif
2169
2170 if (!m_window) return;
2171
2172 if (m_currentClippingRegion.IsEmpty())
2173 {
2174 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
2175 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
2176 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
2177 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
2178 }
2179 else
2180 {
2181 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2182 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2183 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2184 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
2185 }
2186 }
2187
2188 void wxWindowDC::Destroy()
2189 {
2190 if (m_penGC) wxFreePoolGC( m_penGC );
2191 m_penGC = (GdkGC*) NULL;
2192 if (m_brushGC) wxFreePoolGC( m_brushGC );
2193 m_brushGC = (GdkGC*) NULL;
2194 if (m_textGC) wxFreePoolGC( m_textGC );
2195 m_textGC = (GdkGC*) NULL;
2196 if (m_bgGC) wxFreePoolGC( m_bgGC );
2197 m_bgGC = (GdkGC*) NULL;
2198 }
2199
2200 void wxWindowDC::ComputeScaleAndOrigin()
2201 {
2202 const wxRealPoint origScale(m_scaleX, m_scaleY);
2203
2204 wxDC::ComputeScaleAndOrigin();
2205
2206 // if scale has changed call SetPen to recalulate the line width
2207 if ( wxRealPoint(m_scaleX, m_scaleY) != origScale && m_pen.Ok() )
2208 {
2209 // this is a bit artificial, but we need to force wxDC to think the pen
2210 // has changed
2211 wxPen pen = m_pen;
2212 m_pen = wxNullPen;
2213 SetPen( pen );
2214 }
2215 }
2216
2217 // Resolution in pixels per logical inch
2218 wxSize wxWindowDC::GetPPI() const
2219 {
2220 return wxSize( (int) (m_mm_to_pix_x * 25.4 + 0.5), (int) (m_mm_to_pix_y * 25.4 + 0.5));
2221 }
2222
2223 int wxWindowDC::GetDepth() const
2224 {
2225 return gdk_drawable_get_depth(m_window);
2226 }
2227
2228
2229 //-----------------------------------------------------------------------------
2230 // wxPaintDC
2231 //-----------------------------------------------------------------------------
2232
2233 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxClientDC)
2234
2235 // Limit the paint region to the window size. Sometimes
2236 // the paint region is too big, and this risks X11 errors
2237 static void wxLimitRegionToSize(wxRegion& region, const wxSize& sz)
2238 {
2239 wxRect originalRect = region.GetBox();
2240 wxRect rect(originalRect);
2241 if (rect.width + rect.x > sz.x)
2242 rect.width = sz.x - rect.x;
2243 if (rect.height + rect.y > sz.y)
2244 rect.height = sz.y - rect.y;
2245 if (rect != originalRect)
2246 {
2247 region = wxRegion(rect);
2248 wxLogTrace(wxT("painting"), wxT("Limiting region from %d, %d, %d, %d to %d, %d, %d, %d\n"),
2249 originalRect.x, originalRect.y, originalRect.width, originalRect.height,
2250 rect.x, rect.y, rect.width, rect.height);
2251 }
2252 }
2253
2254 wxPaintDC::wxPaintDC( wxWindow *win )
2255 : wxClientDC( win )
2256 {
2257 #if USE_PAINT_REGION
2258 if (!win->m_clipPaintRegion)
2259 return;
2260
2261 wxSize sz = win->GetSize();
2262 m_paintClippingRegion = win->GetUpdateRegion();
2263 wxLimitRegionToSize(m_paintClippingRegion, sz);
2264
2265 GdkRegion *region = m_paintClippingRegion.GetRegion();
2266 if ( region )
2267 {
2268 m_currentClippingRegion.Union( m_paintClippingRegion );
2269 wxLimitRegionToSize(m_currentClippingRegion, sz);
2270
2271 if (sz.x <= 0 || sz.y <= 0)
2272 return ;
2273
2274 gdk_gc_set_clip_region( m_penGC, region );
2275 gdk_gc_set_clip_region( m_brushGC, region );
2276 gdk_gc_set_clip_region( m_textGC, region );
2277 gdk_gc_set_clip_region( m_bgGC, region );
2278 }
2279 #endif // USE_PAINT_REGION
2280 }
2281
2282 //-----------------------------------------------------------------------------
2283 // wxClientDC
2284 //-----------------------------------------------------------------------------
2285
2286 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
2287
2288 wxClientDC::wxClientDC( wxWindow *win )
2289 : wxWindowDC( win )
2290 {
2291 wxCHECK_RET( win, _T("NULL window in wxClientDC::wxClientDC") );
2292
2293 #ifdef __WXUNIVERSAL__
2294 wxPoint ptOrigin = win->GetClientAreaOrigin();
2295 SetDeviceOrigin(ptOrigin.x, ptOrigin.y);
2296 wxSize size = win->GetClientSize();
2297 SetClippingRegion(wxPoint(0, 0), size);
2298 #endif // __WXUNIVERSAL__
2299 }
2300
2301 void wxClientDC::DoGetSize(int *width, int *height) const
2302 {
2303 wxCHECK_RET( m_owner, _T("GetSize() doesn't work without window") );
2304
2305 m_owner->GetClientSize( width, height );
2306 }
2307
2308 // ----------------------------------------------------------------------------
2309 // wxDCModule
2310 // ----------------------------------------------------------------------------
2311
2312 class wxDCModule : public wxModule
2313 {
2314 public:
2315 bool OnInit();
2316 void OnExit();
2317
2318 private:
2319 DECLARE_DYNAMIC_CLASS(wxDCModule)
2320 };
2321
2322 IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
2323
2324 bool wxDCModule::OnInit()
2325 {
2326 wxInitGCPool();
2327 return true;
2328 }
2329
2330 void wxDCModule::OnExit()
2331 {
2332 wxCleanUpGCPool();
2333 }