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