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