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