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