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