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