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