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