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