]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/dcclient.cpp
support full 32bit range in wxGauge
[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 #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 }
1842
1843 static const wxGTKDash dotted[] = {1, 1};
1844 static const wxGTKDash short_dashed[] = {2, 2};
1845 static const wxGTKDash wxCoord_dashed[] = {2, 4};
1846 static const wxGTKDash dotted_dashed[] = {3, 3, 1, 3};
1847
1848 // We express dash pattern in pen width unit, so we are
1849 // independent of zoom factor and so on...
1850 int req_nb_dash;
1851 const wxGTKDash *req_dash;
1852
1853 GdkLineStyle lineStyle = GDK_LINE_SOLID;
1854 switch (m_pen.GetStyle())
1855 {
1856 case wxUSER_DASH:
1857 {
1858 lineStyle = GDK_LINE_ON_OFF_DASH;
1859 req_nb_dash = m_pen.GetDashCount();
1860 req_dash = (wxGTKDash*)m_pen.GetDash();
1861 break;
1862 }
1863 case wxDOT:
1864 {
1865 lineStyle = GDK_LINE_ON_OFF_DASH;
1866 req_nb_dash = 2;
1867 req_dash = dotted;
1868 break;
1869 }
1870 case wxLONG_DASH:
1871 {
1872 lineStyle = GDK_LINE_ON_OFF_DASH;
1873 req_nb_dash = 2;
1874 req_dash = wxCoord_dashed;
1875 break;
1876 }
1877 case wxSHORT_DASH:
1878 {
1879 lineStyle = GDK_LINE_ON_OFF_DASH;
1880 req_nb_dash = 2;
1881 req_dash = short_dashed;
1882 break;
1883 }
1884 case wxDOT_DASH:
1885 {
1886 // lineStyle = GDK_LINE_DOUBLE_DASH;
1887 lineStyle = GDK_LINE_ON_OFF_DASH;
1888 req_nb_dash = 4;
1889 req_dash = dotted_dashed;
1890 break;
1891 }
1892
1893 case wxTRANSPARENT:
1894 case wxSTIPPLE_MASK_OPAQUE:
1895 case wxSTIPPLE:
1896 case wxSOLID:
1897 default:
1898 {
1899 lineStyle = GDK_LINE_SOLID;
1900 req_dash = (wxGTKDash*)NULL;
1901 req_nb_dash = 0;
1902 break;
1903 }
1904 }
1905
1906 #if (GTK_MINOR_VERSION > 0) || (GTK_MAJOR_VERSION > 1)
1907 if (req_dash && req_nb_dash)
1908 {
1909 wxGTKDash *real_req_dash = new wxGTKDash[req_nb_dash];
1910 if (real_req_dash)
1911 {
1912 for (int i = 0; i < req_nb_dash; i++)
1913 real_req_dash[i] = req_dash[i] * width;
1914 gdk_gc_set_dashes( m_penGC, 0, real_req_dash, req_nb_dash );
1915 delete[] real_req_dash;
1916 }
1917 else
1918 {
1919 // No Memory. We use non-scaled dash pattern...
1920 gdk_gc_set_dashes( m_penGC, 0, (wxGTKDash*)req_dash, req_nb_dash );
1921 }
1922 }
1923 #endif // GTK+ > 1.0
1924
1925 GdkCapStyle capStyle = GDK_CAP_ROUND;
1926 switch (m_pen.GetCap())
1927 {
1928 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
1929 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
1930 case wxCAP_ROUND:
1931 default:
1932 {
1933 if (width <= 1)
1934 {
1935 width = 0;
1936 capStyle = GDK_CAP_NOT_LAST;
1937 }
1938 else
1939 {
1940 capStyle = GDK_CAP_ROUND;
1941 }
1942 break;
1943 }
1944 }
1945
1946 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
1947 switch (m_pen.GetJoin())
1948 {
1949 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
1950 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
1951 case wxJOIN_ROUND:
1952 default: { joinStyle = GDK_JOIN_ROUND; break; }
1953 }
1954
1955 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
1956
1957 m_pen.GetColour().CalcPixel( m_cmap );
1958 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
1959 }
1960
1961 void wxWindowDC::SetBrush( const wxBrush &brush )
1962 {
1963 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1964
1965 if (m_brush == brush) return;
1966
1967 m_brush = brush;
1968
1969 if (!m_brush.Ok()) return;
1970
1971 if (!m_window) return;
1972
1973 m_brush.GetColour().CalcPixel( m_cmap );
1974 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
1975
1976 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
1977
1978 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
1979 {
1980 if (m_brush.GetStipple()->GetPixmap())
1981 {
1982 gdk_gc_set_fill( m_brushGC, GDK_TILED );
1983 gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() );
1984 }
1985 else
1986 {
1987 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
1988 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() );
1989 }
1990 }
1991
1992 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
1993 {
1994 gdk_gc_set_fill( m_textGC, GDK_OPAQUE_STIPPLED);
1995 gdk_gc_set_stipple( m_textGC, m_brush.GetStipple()->GetMask()->GetBitmap() );
1996 }
1997
1998 if (IS_HATCH(m_brush.GetStyle()))
1999 {
2000 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
2001 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
2002 gdk_gc_set_stipple( m_brushGC, hatches[num] );
2003 }
2004 }
2005
2006 void wxWindowDC::SetBackground( const wxBrush &brush )
2007 {
2008 /* CMB 21/7/98: Added SetBackground. Sets background brush
2009 * for Clear() and bg colour for shapes filled with cross-hatch brush */
2010
2011 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2012
2013 if (m_backgroundBrush == brush) return;
2014
2015 m_backgroundBrush = brush;
2016
2017 if (!m_backgroundBrush.Ok()) return;
2018
2019 if (!m_window) return;
2020
2021 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
2022 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
2023 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
2024 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
2025 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
2026
2027 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
2028
2029 if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok()))
2030 {
2031 if (m_backgroundBrush.GetStipple()->GetPixmap())
2032 {
2033 gdk_gc_set_fill( m_bgGC, GDK_TILED );
2034 gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
2035 }
2036 else
2037 {
2038 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
2039 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetBitmap() );
2040 }
2041 }
2042
2043 if (IS_HATCH(m_backgroundBrush.GetStyle()))
2044 {
2045 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
2046 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
2047 gdk_gc_set_stipple( m_bgGC, hatches[num] );
2048 }
2049 }
2050
2051 void wxWindowDC::SetLogicalFunction( int function )
2052 {
2053 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2054
2055 if (m_logicalFunction == function)
2056 return;
2057
2058 // VZ: shouldn't this be a CHECK?
2059 if (!m_window)
2060 return;
2061
2062 GdkFunction mode;
2063 switch (function)
2064 {
2065 case wxXOR: mode = GDK_XOR; break;
2066 case wxINVERT: mode = GDK_INVERT; break;
2067 #if (GTK_MINOR_VERSION > 0) || (GTK_MAJOR_VERSION > 1)
2068 case wxOR_REVERSE: mode = GDK_OR_REVERSE; break;
2069 case wxAND_REVERSE: mode = GDK_AND_REVERSE; break;
2070 case wxCLEAR: mode = GDK_CLEAR; break;
2071 case wxSET: mode = GDK_SET; break;
2072 case wxOR_INVERT: mode = GDK_OR_INVERT; break;
2073 case wxAND: mode = GDK_AND; break;
2074 case wxOR: mode = GDK_OR; break;
2075 case wxEQUIV: mode = GDK_EQUIV; break;
2076 case wxNAND: mode = GDK_NAND; break;
2077 case wxAND_INVERT: mode = GDK_AND_INVERT; break;
2078 case wxCOPY: mode = GDK_COPY; break;
2079 case wxNO_OP: mode = GDK_NOOP; break;
2080 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
2081
2082 // unsupported by GTK
2083 case wxNOR: mode = GDK_COPY; break;
2084 #endif // GTK+ > 1.0
2085 default:
2086 wxFAIL_MSG( wxT("unsupported logical function") );
2087 mode = GDK_COPY;
2088 }
2089
2090 m_logicalFunction = function;
2091
2092 gdk_gc_set_function( m_penGC, mode );
2093 gdk_gc_set_function( m_brushGC, mode );
2094
2095 // to stay compatible with wxMSW, we don't apply ROPs to the text
2096 // operations (i.e. DrawText/DrawRotatedText).
2097 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
2098 gdk_gc_set_function( m_textGC, mode );
2099 }
2100
2101 void wxWindowDC::SetTextForeground( const wxColour &col )
2102 {
2103 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2104
2105 // don't set m_textForegroundColour to an invalid colour as we'd crash
2106 // later then (we use m_textForegroundColour.GetColor() without checking
2107 // in a few places)
2108 if ( !col.Ok() || (m_textForegroundColour == col) )
2109 return;
2110
2111 m_textForegroundColour = col;
2112
2113 if ( m_window )
2114 {
2115 m_textForegroundColour.CalcPixel( m_cmap );
2116 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
2117 }
2118 }
2119
2120 void wxWindowDC::SetTextBackground( const wxColour &col )
2121 {
2122 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2123
2124 // same as above
2125 if ( !col.Ok() || (m_textBackgroundColour == col) )
2126 return;
2127
2128 m_textBackgroundColour = col;
2129
2130 if ( m_window )
2131 {
2132 m_textBackgroundColour.CalcPixel( m_cmap );
2133 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
2134 }
2135 }
2136
2137 void wxWindowDC::SetBackgroundMode( int mode )
2138 {
2139 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2140
2141 m_backgroundMode = mode;
2142
2143 if (!m_window) return;
2144
2145 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
2146 // transparent/solid background mode
2147
2148 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
2149 {
2150 gdk_gc_set_fill( m_brushGC,
2151 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
2152 }
2153 }
2154
2155 void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
2156 {
2157 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
2158 }
2159
2160 void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
2161 {
2162 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2163
2164 if (!m_window) return;
2165
2166 wxRect rect;
2167 rect.x = XLOG2DEV(x);
2168 rect.y = YLOG2DEV(y);
2169 rect.width = XLOG2DEVREL(width);
2170 rect.height = YLOG2DEVREL(height);
2171
2172 if (!m_currentClippingRegion.IsNull())
2173 m_currentClippingRegion.Intersect( rect );
2174 else
2175 m_currentClippingRegion.Union( rect );
2176
2177 #if USE_PAINT_REGION
2178 if (!m_paintClippingRegion.IsNull())
2179 m_currentClippingRegion.Intersect( m_paintClippingRegion );
2180 #endif
2181
2182 wxCoord xx, yy, ww, hh;
2183 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
2184 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
2185
2186 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2187 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2188 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2189 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
2190 }
2191
2192 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
2193 {
2194 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2195
2196 if (region.Empty())
2197 {
2198 DestroyClippingRegion();
2199 return;
2200 }
2201
2202 if (!m_window) return;
2203
2204 if (!m_currentClippingRegion.IsNull())
2205 m_currentClippingRegion.Intersect( region );
2206 else
2207 m_currentClippingRegion.Union( region );
2208
2209 #if USE_PAINT_REGION
2210 if (!m_paintClippingRegion.IsNull())
2211 m_currentClippingRegion.Intersect( m_paintClippingRegion );
2212 #endif
2213
2214 wxCoord xx, yy, ww, hh;
2215 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
2216 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
2217
2218 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2219 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2220 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2221 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
2222 }
2223
2224 void wxWindowDC::DestroyClippingRegion()
2225 {
2226 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2227
2228 wxDC::DestroyClippingRegion();
2229
2230 m_currentClippingRegion.Clear();
2231
2232 #if USE_PAINT_REGION
2233 if (!m_paintClippingRegion.IsEmpty())
2234 m_currentClippingRegion.Union( m_paintClippingRegion );
2235 #endif
2236
2237 if (!m_window) return;
2238
2239 if (m_currentClippingRegion.IsEmpty())
2240 {
2241 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
2242 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
2243 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
2244 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
2245 }
2246 else
2247 {
2248 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2249 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2250 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2251 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
2252 }
2253 }
2254
2255 void wxWindowDC::Destroy()
2256 {
2257 if (m_penGC) wxFreePoolGC( m_penGC );
2258 m_penGC = (GdkGC*) NULL;
2259 if (m_brushGC) wxFreePoolGC( m_brushGC );
2260 m_brushGC = (GdkGC*) NULL;
2261 if (m_textGC) wxFreePoolGC( m_textGC );
2262 m_textGC = (GdkGC*) NULL;
2263 if (m_bgGC) wxFreePoolGC( m_bgGC );
2264 m_bgGC = (GdkGC*) NULL;
2265 }
2266
2267 void wxWindowDC::ComputeScaleAndOrigin()
2268 {
2269 /* CMB: copy scale to see if it changes */
2270 double origScaleX = m_scaleX;
2271 double origScaleY = m_scaleY;
2272
2273 wxDC::ComputeScaleAndOrigin();
2274
2275 /* CMB: if scale has changed call SetPen to recalulate the line width */
2276 if ((m_scaleX != origScaleX || m_scaleY != origScaleY) &&
2277 (m_pen.Ok()))
2278 {
2279 /* this is a bit artificial, but we need to force wxDC to think
2280 the pen has changed */
2281 wxPen pen = m_pen;
2282 m_pen = wxNullPen;
2283 SetPen( pen );
2284 }
2285 }
2286
2287 // Resolution in pixels per logical inch
2288 wxSize wxWindowDC::GetPPI() const
2289 {
2290 return wxSize( (int) (m_mm_to_pix_x * 25.4 + 0.5), (int) (m_mm_to_pix_y * 25.4 + 0.5));
2291 }
2292
2293 int wxWindowDC::GetDepth() const
2294 {
2295 wxFAIL_MSG(wxT("not implemented"));
2296
2297 return -1;
2298 }
2299
2300
2301 //-----------------------------------------------------------------------------
2302 // wxPaintDC
2303 //-----------------------------------------------------------------------------
2304
2305 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxClientDC)
2306
2307 wxPaintDC::wxPaintDC( wxWindow *win )
2308 : wxClientDC( win )
2309 {
2310 #if USE_PAINT_REGION
2311 if (!win->m_clipPaintRegion)
2312 return;
2313
2314 m_paintClippingRegion = win->GetUpdateRegion();
2315 GdkRegion *region = m_paintClippingRegion.GetRegion();
2316 if ( region )
2317 {
2318 m_paintClippingRegion = win->GetUpdateRegion();
2319 GdkRegion *region = m_paintClippingRegion.GetRegion();
2320 if ( region )
2321 {
2322 m_currentClippingRegion.Union( m_paintClippingRegion );
2323
2324 gdk_gc_set_clip_region( m_penGC, region );
2325 gdk_gc_set_clip_region( m_brushGC, region );
2326 gdk_gc_set_clip_region( m_textGC, region );
2327 gdk_gc_set_clip_region( m_bgGC, region );
2328 }
2329 }
2330 #endif // USE_PAINT_REGION
2331 }
2332
2333 //-----------------------------------------------------------------------------
2334 // wxClientDC
2335 //-----------------------------------------------------------------------------
2336
2337 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
2338
2339 wxClientDC::wxClientDC( wxWindow *win )
2340 : wxWindowDC( win )
2341 {
2342 wxCHECK_RET( win, _T("NULL window in wxClientDC::wxClientDC") );
2343
2344 #ifdef __WXUNIVERSAL__
2345 wxPoint ptOrigin = win->GetClientAreaOrigin();
2346 SetDeviceOrigin(ptOrigin.x, ptOrigin.y);
2347 wxSize size = win->GetClientSize();
2348 SetClippingRegion(wxPoint(0, 0), size);
2349 #endif // __WXUNIVERSAL__
2350 }
2351
2352 void wxClientDC::DoGetSize(int *width, int *height) const
2353 {
2354 wxCHECK_RET( m_owner, _T("GetSize() doesn't work without window") );
2355
2356 m_owner->GetClientSize( width, height );
2357 }
2358
2359 // ----------------------------------------------------------------------------
2360 // wxDCModule
2361 // ----------------------------------------------------------------------------
2362
2363 class wxDCModule : public wxModule
2364 {
2365 public:
2366 bool OnInit();
2367 void OnExit();
2368
2369 private:
2370 DECLARE_DYNAMIC_CLASS(wxDCModule)
2371 };
2372
2373 IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
2374
2375 bool wxDCModule::OnInit()
2376 {
2377 wxInitGCPool();
2378 return TRUE;
2379 }
2380
2381 void wxDCModule::OnExit()
2382 {
2383 wxCleanUpGCPool();
2384 }