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