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