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