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