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