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