]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/dcclient.cpp
Implemented Mac-style button toggling within wxButtonToolBar, and line
[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 {
1700 return;
1701 }
1702
1703 // Set new font description
1704 if (theFont)
1705 pango_layout_set_font_description( m_layout, theFont->GetNativeFontInfo()->description );
1706
1707 // Set layout's text
1708 const wxCharBuffer dataUTF8 = wxGTK_CONV(string);
1709 if ( !dataUTF8 )
1710 {
1711 // hardly ideal, but what else can we do if conversion failed?
1712 return;
1713 }
1714
1715 pango_layout_set_text( m_layout, dataUTF8, strlen(dataUTF8) );
1716
1717 if (descent)
1718 {
1719 int h;
1720 pango_layout_get_pixel_size( m_layout, width, &h );
1721 PangoLayoutIter *iter = pango_layout_get_iter(m_layout);
1722 int baseline = pango_layout_iter_get_baseline(iter);
1723 pango_layout_iter_free(iter);
1724 *descent = h - PANGO_PIXELS(baseline);
1725
1726 if (height)
1727 *height = (wxCoord) h;
1728 }
1729 else
1730 {
1731 pango_layout_get_pixel_size( m_layout, width, height );
1732 }
1733
1734 // Reset old font description
1735 if (theFont)
1736 pango_layout_set_font_description( m_layout, m_fontdesc );
1737 }
1738
1739 wxCoord wxWindowDC::GetCharWidth() const
1740 {
1741 pango_layout_set_text( m_layout, "H", 1 );
1742 int w;
1743 pango_layout_get_pixel_size( m_layout, &w, NULL );
1744 return w;
1745 }
1746
1747 wxCoord wxWindowDC::GetCharHeight() const
1748 {
1749 pango_layout_set_text( m_layout, "H", 1 );
1750 int h;
1751 pango_layout_get_pixel_size( m_layout, NULL, &h );
1752 return h;
1753 }
1754
1755 void wxWindowDC::Clear()
1756 {
1757 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1758
1759 if (!m_window) return;
1760
1761 // VZ: the code below results in infinite recursion and crashes when
1762 // dc.Clear() is done from OnPaint() so I disable it for now.
1763 // I don't know what the correct fix is but Clear() surely should not
1764 // reenter OnPaint()!
1765 #if 0
1766 /* - we either are a memory dc or have a window as the
1767 owner. anything else shouldn't happen.
1768 - we don't use gdk_window_clear() as we don't set
1769 the window's background colour anymore. it is too
1770 much pain to keep the DC's and the window's back-
1771 ground colour in synch. */
1772
1773 if (m_owner)
1774 {
1775 m_owner->Clear();
1776 return;
1777 }
1778
1779 if (m_isMemDC)
1780 {
1781 int width,height;
1782 GetSize( &width, &height );
1783 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
1784 return;
1785 }
1786 #else // 1
1787 int width,height;
1788 GetSize( &width, &height );
1789 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
1790 #endif // 0/1
1791 }
1792
1793 void wxWindowDC::SetFont( const wxFont &font )
1794 {
1795 m_font = font;
1796
1797 if (m_font.Ok())
1798 {
1799 if (m_fontdesc)
1800 pango_font_description_free( m_fontdesc );
1801
1802 m_fontdesc = pango_font_description_copy( m_font.GetNativeFontInfo()->description );
1803
1804
1805 if (m_owner)
1806 {
1807 PangoContext *oldContext = m_context;
1808
1809 m_context = m_owner->GtkGetPangoDefaultContext();
1810
1811 // If we switch back/forth between different contexts
1812 // we also have to create a new layout. I think so,
1813 // at least, and it doesn't hurt to do it.
1814 if (oldContext != m_context)
1815 {
1816 if (m_layout)
1817 g_object_unref( G_OBJECT( m_layout ) );
1818
1819 m_layout = pango_layout_new( m_context );
1820 }
1821 }
1822
1823 pango_layout_set_font_description( m_layout, m_fontdesc );
1824 }
1825 }
1826
1827 void wxWindowDC::SetPen( const wxPen &pen )
1828 {
1829 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1830
1831 if (m_pen == pen) return;
1832
1833 m_pen = pen;
1834
1835 if (!m_pen.Ok()) return;
1836
1837 if (!m_window) return;
1838
1839 gint width = m_pen.GetWidth();
1840 if (width <= 0)
1841 {
1842 // CMB: if width is non-zero scale it with the dc
1843 width = 1;
1844 }
1845 else
1846 {
1847 // X doesn't allow different width in x and y and so we take
1848 // the average
1849 double w = 0.5 +
1850 ( fabs((double) XLOG2DEVREL(width)) +
1851 fabs((double) YLOG2DEVREL(width)) ) / 2.0;
1852 width = (int)w;
1853 if ( !width )
1854 {
1855 // width can't be 0 or an internal GTK error occurs inside
1856 // gdk_gc_set_dashes() below
1857 width = 1;
1858 }
1859 }
1860
1861 static const wxGTKDash dotted[] = {1, 1};
1862 static const wxGTKDash short_dashed[] = {2, 2};
1863 static const wxGTKDash wxCoord_dashed[] = {2, 4};
1864 static const wxGTKDash dotted_dashed[] = {3, 3, 1, 3};
1865
1866 // We express dash pattern in pen width unit, so we are
1867 // independent of zoom factor and so on...
1868 int req_nb_dash;
1869 const wxGTKDash *req_dash;
1870
1871 GdkLineStyle lineStyle = GDK_LINE_SOLID;
1872 switch (m_pen.GetStyle())
1873 {
1874 case wxUSER_DASH:
1875 {
1876 lineStyle = GDK_LINE_ON_OFF_DASH;
1877 req_nb_dash = m_pen.GetDashCount();
1878 req_dash = (wxGTKDash*)m_pen.GetDash();
1879 break;
1880 }
1881 case wxDOT:
1882 {
1883 lineStyle = GDK_LINE_ON_OFF_DASH;
1884 req_nb_dash = 2;
1885 req_dash = dotted;
1886 break;
1887 }
1888 case wxLONG_DASH:
1889 {
1890 lineStyle = GDK_LINE_ON_OFF_DASH;
1891 req_nb_dash = 2;
1892 req_dash = wxCoord_dashed;
1893 break;
1894 }
1895 case wxSHORT_DASH:
1896 {
1897 lineStyle = GDK_LINE_ON_OFF_DASH;
1898 req_nb_dash = 2;
1899 req_dash = short_dashed;
1900 break;
1901 }
1902 case wxDOT_DASH:
1903 {
1904 // lineStyle = GDK_LINE_DOUBLE_DASH;
1905 lineStyle = GDK_LINE_ON_OFF_DASH;
1906 req_nb_dash = 4;
1907 req_dash = dotted_dashed;
1908 break;
1909 }
1910
1911 case wxTRANSPARENT:
1912 case wxSTIPPLE_MASK_OPAQUE:
1913 case wxSTIPPLE:
1914 case wxSOLID:
1915 default:
1916 {
1917 lineStyle = GDK_LINE_SOLID;
1918 req_dash = (wxGTKDash*)NULL;
1919 req_nb_dash = 0;
1920 break;
1921 }
1922 }
1923
1924 if (req_dash && req_nb_dash)
1925 {
1926 wxGTKDash *real_req_dash = new wxGTKDash[req_nb_dash];
1927 if (real_req_dash)
1928 {
1929 for (int i = 0; i < req_nb_dash; i++)
1930 real_req_dash[i] = req_dash[i] * width;
1931 gdk_gc_set_dashes( m_penGC, 0, real_req_dash, req_nb_dash );
1932 delete[] real_req_dash;
1933 }
1934 else
1935 {
1936 // No Memory. We use non-scaled dash pattern...
1937 gdk_gc_set_dashes( m_penGC, 0, (wxGTKDash*)req_dash, req_nb_dash );
1938 }
1939 }
1940
1941 GdkCapStyle capStyle = GDK_CAP_ROUND;
1942 switch (m_pen.GetCap())
1943 {
1944 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
1945 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
1946 case wxCAP_ROUND:
1947 default:
1948 {
1949 if (width <= 1)
1950 {
1951 width = 0;
1952 capStyle = GDK_CAP_NOT_LAST;
1953 }
1954 else
1955 {
1956 capStyle = GDK_CAP_ROUND;
1957 }
1958 break;
1959 }
1960 }
1961
1962 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
1963 switch (m_pen.GetJoin())
1964 {
1965 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
1966 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
1967 case wxJOIN_ROUND:
1968 default: { joinStyle = GDK_JOIN_ROUND; break; }
1969 }
1970
1971 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
1972
1973 m_pen.GetColour().CalcPixel( m_cmap );
1974 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
1975 }
1976
1977 void wxWindowDC::SetBrush( const wxBrush &brush )
1978 {
1979 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1980
1981 if (m_brush == brush) return;
1982
1983 m_brush = brush;
1984
1985 if (!m_brush.Ok()) return;
1986
1987 if (!m_window) return;
1988
1989 m_brush.GetColour().CalcPixel( m_cmap );
1990 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
1991
1992 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
1993
1994 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
1995 {
1996 if (m_brush.GetStipple()->GetPixmap())
1997 {
1998 gdk_gc_set_fill( m_brushGC, GDK_TILED );
1999 gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() );
2000 }
2001 else
2002 {
2003 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
2004 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() );
2005 }
2006 }
2007
2008 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
2009 {
2010 gdk_gc_set_fill( m_textGC, GDK_OPAQUE_STIPPLED);
2011 gdk_gc_set_stipple( m_textGC, m_brush.GetStipple()->GetMask()->GetBitmap() );
2012 }
2013
2014 if (m_brush.IsHatch())
2015 {
2016 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
2017 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
2018 gdk_gc_set_stipple( m_brushGC, hatches[num] );
2019 }
2020 }
2021
2022 void wxWindowDC::SetBackground( const wxBrush &brush )
2023 {
2024 /* CMB 21/7/98: Added SetBackground. Sets background brush
2025 * for Clear() and bg colour for shapes filled with cross-hatch brush */
2026
2027 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2028
2029 if (m_backgroundBrush == brush) return;
2030
2031 m_backgroundBrush = brush;
2032
2033 if (!m_backgroundBrush.Ok()) return;
2034
2035 if (!m_window) return;
2036
2037 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
2038 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
2039 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
2040 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
2041 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
2042
2043 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
2044
2045 if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok()))
2046 {
2047 if (m_backgroundBrush.GetStipple()->GetPixmap())
2048 {
2049 gdk_gc_set_fill( m_bgGC, GDK_TILED );
2050 gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
2051 }
2052 else
2053 {
2054 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
2055 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetBitmap() );
2056 }
2057 }
2058
2059 if (m_backgroundBrush.IsHatch())
2060 {
2061 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
2062 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
2063 gdk_gc_set_stipple( m_bgGC, hatches[num] );
2064 }
2065 }
2066
2067 void wxWindowDC::SetLogicalFunction( int function )
2068 {
2069 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2070
2071 if (m_logicalFunction == function)
2072 return;
2073
2074 // VZ: shouldn't this be a CHECK?
2075 if (!m_window)
2076 return;
2077
2078 GdkFunction mode;
2079 switch (function)
2080 {
2081 case wxXOR: mode = GDK_XOR; break;
2082 case wxINVERT: mode = GDK_INVERT; break;
2083 case wxOR_REVERSE: mode = GDK_OR_REVERSE; break;
2084 case wxAND_REVERSE: mode = GDK_AND_REVERSE; break;
2085 case wxCLEAR: mode = GDK_CLEAR; break;
2086 case wxSET: mode = GDK_SET; break;
2087 case wxOR_INVERT: mode = GDK_OR_INVERT; break;
2088 case wxAND: mode = GDK_AND; break;
2089 case wxOR: mode = GDK_OR; break;
2090 case wxEQUIV: mode = GDK_EQUIV; break;
2091 case wxNAND: mode = GDK_NAND; break;
2092 case wxAND_INVERT: mode = GDK_AND_INVERT; break;
2093 case wxCOPY: mode = GDK_COPY; break;
2094 case wxNO_OP: mode = GDK_NOOP; break;
2095 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
2096
2097 // unsupported by GTK
2098 case wxNOR: mode = GDK_COPY; break;
2099 default:
2100 wxFAIL_MSG( wxT("unsupported logical function") );
2101 mode = GDK_COPY;
2102 }
2103
2104 m_logicalFunction = function;
2105
2106 gdk_gc_set_function( m_penGC, mode );
2107 gdk_gc_set_function( m_brushGC, mode );
2108
2109 // to stay compatible with wxMSW, we don't apply ROPs to the text
2110 // operations (i.e. DrawText/DrawRotatedText).
2111 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
2112 gdk_gc_set_function( m_textGC, mode );
2113 }
2114
2115 void wxWindowDC::SetTextForeground( const wxColour &col )
2116 {
2117 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2118
2119 // don't set m_textForegroundColour to an invalid colour as we'd crash
2120 // later then (we use m_textForegroundColour.GetColor() without checking
2121 // in a few places)
2122 if ( !col.Ok() || (m_textForegroundColour == col) )
2123 return;
2124
2125 m_textForegroundColour = col;
2126
2127 if ( m_window )
2128 {
2129 m_textForegroundColour.CalcPixel( m_cmap );
2130 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
2131 }
2132 }
2133
2134 void wxWindowDC::SetTextBackground( const wxColour &col )
2135 {
2136 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2137
2138 // same as above
2139 if ( !col.Ok() || (m_textBackgroundColour == col) )
2140 return;
2141
2142 m_textBackgroundColour = col;
2143
2144 if ( m_window )
2145 {
2146 m_textBackgroundColour.CalcPixel( m_cmap );
2147 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
2148 }
2149 }
2150
2151 void wxWindowDC::SetBackgroundMode( int mode )
2152 {
2153 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2154
2155 m_backgroundMode = mode;
2156
2157 if (!m_window) return;
2158
2159 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
2160 // transparent/solid background mode
2161
2162 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
2163 {
2164 gdk_gc_set_fill( m_brushGC,
2165 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
2166 }
2167 }
2168
2169 void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
2170 {
2171 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
2172 }
2173
2174 void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
2175 {
2176 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2177
2178 if (!m_window) return;
2179
2180 wxRect rect;
2181 rect.x = XLOG2DEV(x);
2182 rect.y = YLOG2DEV(y);
2183 rect.width = XLOG2DEVREL(width);
2184 rect.height = YLOG2DEVREL(height);
2185
2186 if (!m_currentClippingRegion.IsNull())
2187 m_currentClippingRegion.Intersect( rect );
2188 else
2189 m_currentClippingRegion.Union( rect );
2190
2191 #if USE_PAINT_REGION
2192 if (!m_paintClippingRegion.IsNull())
2193 m_currentClippingRegion.Intersect( m_paintClippingRegion );
2194 #endif
2195
2196 wxCoord xx, yy, ww, hh;
2197 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
2198 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
2199
2200 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2201 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2202 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2203 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
2204 }
2205
2206 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
2207 {
2208 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2209
2210 if (region.Empty())
2211 {
2212 DestroyClippingRegion();
2213 return;
2214 }
2215
2216 if (!m_window) return;
2217
2218 if (!m_currentClippingRegion.IsNull())
2219 m_currentClippingRegion.Intersect( region );
2220 else
2221 m_currentClippingRegion.Union( region );
2222
2223 #if USE_PAINT_REGION
2224 if (!m_paintClippingRegion.IsNull())
2225 m_currentClippingRegion.Intersect( m_paintClippingRegion );
2226 #endif
2227
2228 wxCoord xx, yy, ww, hh;
2229 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
2230 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
2231
2232 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2233 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2234 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2235 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
2236 }
2237
2238 void wxWindowDC::DestroyClippingRegion()
2239 {
2240 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2241
2242 wxDC::DestroyClippingRegion();
2243
2244 m_currentClippingRegion.Clear();
2245
2246 #if USE_PAINT_REGION
2247 if (!m_paintClippingRegion.IsEmpty())
2248 m_currentClippingRegion.Union( m_paintClippingRegion );
2249 #endif
2250
2251 if (!m_window) return;
2252
2253 if (m_currentClippingRegion.IsEmpty())
2254 {
2255 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
2256 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
2257 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
2258 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
2259 }
2260 else
2261 {
2262 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2263 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2264 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2265 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
2266 }
2267 }
2268
2269 void wxWindowDC::Destroy()
2270 {
2271 if (m_penGC) wxFreePoolGC( m_penGC );
2272 m_penGC = (GdkGC*) NULL;
2273 if (m_brushGC) wxFreePoolGC( m_brushGC );
2274 m_brushGC = (GdkGC*) NULL;
2275 if (m_textGC) wxFreePoolGC( m_textGC );
2276 m_textGC = (GdkGC*) NULL;
2277 if (m_bgGC) wxFreePoolGC( m_bgGC );
2278 m_bgGC = (GdkGC*) NULL;
2279 }
2280
2281 void wxWindowDC::ComputeScaleAndOrigin()
2282 {
2283 const wxRealPoint origScale(m_scaleX, m_scaleY);
2284
2285 wxDC::ComputeScaleAndOrigin();
2286
2287 // if scale has changed call SetPen to recalulate the line width
2288 if ( wxRealPoint(m_scaleX, m_scaleY) != origScale && m_pen.Ok() )
2289 {
2290 // this is a bit artificial, but we need to force wxDC to think the pen
2291 // has changed
2292 wxPen pen = m_pen;
2293 m_pen = wxNullPen;
2294 SetPen( pen );
2295 }
2296 }
2297
2298 // Resolution in pixels per logical inch
2299 wxSize wxWindowDC::GetPPI() const
2300 {
2301 return wxSize( (int) (m_mm_to_pix_x * 25.4 + 0.5), (int) (m_mm_to_pix_y * 25.4 + 0.5));
2302 }
2303
2304 int wxWindowDC::GetDepth() const
2305 {
2306 return gdk_drawable_get_depth(m_window);
2307 }
2308
2309
2310 //-----------------------------------------------------------------------------
2311 // wxPaintDC
2312 //-----------------------------------------------------------------------------
2313
2314 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxClientDC)
2315
2316 // Limit the paint region to the window size. Sometimes
2317 // the paint region is too big, and this risks X11 errors
2318 static void wxLimitRegionToSize(wxRegion& region, const wxSize& sz)
2319 {
2320 wxRect originalRect = region.GetBox();
2321 wxRect rect(originalRect);
2322 if (rect.width + rect.x > sz.x)
2323 rect.width = sz.x - rect.x;
2324 if (rect.height + rect.y > sz.y)
2325 rect.height = sz.y - rect.y;
2326 if (rect != originalRect)
2327 {
2328 region = wxRegion(rect);
2329 wxLogTrace(wxT("painting"), wxT("Limiting region from %d, %d, %d, %d to %d, %d, %d, %d\n"),
2330 originalRect.x, originalRect.y, originalRect.width, originalRect.height,
2331 rect.x, rect.y, rect.width, rect.height);
2332 }
2333 }
2334
2335 wxPaintDC::wxPaintDC( wxWindow *win )
2336 : wxClientDC( win )
2337 {
2338 #if USE_PAINT_REGION
2339 if (!win->m_clipPaintRegion)
2340 return;
2341
2342 wxSize sz = win->GetSize();
2343 m_paintClippingRegion = win->GetUpdateRegion();
2344 wxLimitRegionToSize(m_paintClippingRegion, sz);
2345
2346 GdkRegion *region = m_paintClippingRegion.GetRegion();
2347 if ( region )
2348 {
2349 m_currentClippingRegion.Union( m_paintClippingRegion );
2350 wxLimitRegionToSize(m_currentClippingRegion, sz);
2351
2352 if (sz.x <= 0 || sz.y <= 0)
2353 return ;
2354
2355 gdk_gc_set_clip_region( m_penGC, region );
2356 gdk_gc_set_clip_region( m_brushGC, region );
2357 gdk_gc_set_clip_region( m_textGC, region );
2358 gdk_gc_set_clip_region( m_bgGC, region );
2359 }
2360 #endif // USE_PAINT_REGION
2361 }
2362
2363 //-----------------------------------------------------------------------------
2364 // wxClientDC
2365 //-----------------------------------------------------------------------------
2366
2367 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
2368
2369 wxClientDC::wxClientDC( wxWindow *win )
2370 : wxWindowDC( win )
2371 {
2372 wxCHECK_RET( win, _T("NULL window in wxClientDC::wxClientDC") );
2373
2374 #ifdef __WXUNIVERSAL__
2375 wxPoint ptOrigin = win->GetClientAreaOrigin();
2376 SetDeviceOrigin(ptOrigin.x, ptOrigin.y);
2377 wxSize size = win->GetClientSize();
2378 SetClippingRegion(wxPoint(0, 0), size);
2379 #endif // __WXUNIVERSAL__
2380 }
2381
2382 void wxClientDC::DoGetSize(int *width, int *height) const
2383 {
2384 wxCHECK_RET( m_owner, _T("GetSize() doesn't work without window") );
2385
2386 m_owner->GetClientSize( width, height );
2387 }
2388
2389 // ----------------------------------------------------------------------------
2390 // wxDCModule
2391 // ----------------------------------------------------------------------------
2392
2393 class wxDCModule : public wxModule
2394 {
2395 public:
2396 bool OnInit();
2397 void OnExit();
2398
2399 private:
2400 DECLARE_DYNAMIC_CLASS(wxDCModule)
2401 };
2402
2403 IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
2404
2405 bool wxDCModule::OnInit()
2406 {
2407 wxInitGCPool();
2408 return true;
2409 }
2410
2411 void wxDCModule::OnExit()
2412 {
2413 wxCleanUpGCPool();
2414 }