Preventing bitmap crash differently.
[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 wxASSERT_MSG( window, wxT("DC needs a window") );
250
251 m_penGC = (GdkGC *) NULL;
252 m_brushGC = (GdkGC *) NULL;
253 m_textGC = (GdkGC *) NULL;
254 m_bgGC = (GdkGC *) NULL;
255 m_cmap = (GdkColormap *) NULL;
256 m_owner = (wxWindow *)NULL;
257 m_isMemDC = FALSE;
258 m_isScreenDC = FALSE;
259 m_font = window->GetFont();
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.ConvertToImage();
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.ConvertToImage();
1003 image.Rescale( ww, hh );
1004 if (is_mono)
1005 use_bitmap = wxBitmap(image.ConvertToMono(255,255,255), 1);
1006 else
1007 use_bitmap = wxBitmap(image);
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 #ifndef __WXGTK20__ // TODO fix crash
1022 if (!m_currentClippingRegion.IsNull())
1023 {
1024 GdkColor col;
1025 new_mask = gdk_pixmap_new( wxGetRootWindow()->window, ww, hh, 1 );
1026 GdkGC *gc = gdk_gc_new( new_mask );
1027 col.pixel = 0;
1028 gdk_gc_set_foreground( gc, &col );
1029 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh );
1030 col.pixel = 0;
1031 gdk_gc_set_background( gc, &col );
1032 col.pixel = 1;
1033 gdk_gc_set_foreground( gc, &col );
1034 gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() );
1035 gdk_gc_set_clip_origin( gc, -xx, -yy );
1036 gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED );
1037 gdk_gc_set_stipple( gc, mask );
1038 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh );
1039 gdk_gc_unref( gc );
1040 }
1041 #endif
1042 if (is_mono)
1043 {
1044 if (new_mask)
1045 gdk_gc_set_clip_mask( m_textGC, new_mask );
1046 else
1047 gdk_gc_set_clip_mask( m_textGC, mask );
1048 gdk_gc_set_clip_origin( m_textGC, xx, yy );
1049 }
1050 else
1051 {
1052 if (new_mask)
1053 gdk_gc_set_clip_mask( m_penGC, new_mask );
1054 else
1055 gdk_gc_set_clip_mask( m_penGC, mask );
1056 gdk_gc_set_clip_origin( m_penGC, xx, yy );
1057 }
1058
1059 if (new_mask)
1060 gdk_bitmap_unref( new_mask );
1061 }
1062
1063 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1064 drawing a mono-bitmap (XBitmap) we use the current text GC */
1065 if (is_mono)
1066 gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), 0, 0, xx, yy, -1, -1 );
1067 else
1068 gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
1069
1070 /* remove mask again if any */
1071 if (useMask && mask)
1072 {
1073 if (is_mono)
1074 {
1075 gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL );
1076 gdk_gc_set_clip_origin( m_textGC, 0, 0 );
1077 if (!m_currentClippingRegion.IsNull())
1078 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
1079 }
1080 else
1081 {
1082 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
1083 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
1084 if (!m_currentClippingRegion.IsNull())
1085 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
1086 }
1087 }
1088 }
1089
1090 bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest,
1091 wxCoord width, wxCoord height,
1092 wxDC *source,
1093 wxCoord xsrc, wxCoord ysrc,
1094 int logical_func,
1095 bool useMask,
1096 wxCoord xsrcMask, wxCoord ysrcMask )
1097 {
1098 /* this is the nth try to get this utterly useless function to
1099 work. it now completely ignores the scaling or translation
1100 of the source dc, but scales correctly on the target dc and
1101 knows about possible mask information in a memory dc. */
1102
1103 wxCHECK_MSG( Ok(), FALSE, wxT("invalid window dc") );
1104
1105 wxCHECK_MSG( source, FALSE, wxT("invalid source dc") );
1106
1107 if (!m_window) return FALSE;
1108
1109 #if 1
1110 // transform the source DC coords to the device ones
1111 xsrc = source->XLOG2DEV(xsrc);
1112 ysrc = source->YLOG2DEV(ysrc);
1113 #endif
1114
1115 wxClientDC *srcDC = (wxClientDC*)source;
1116 wxMemoryDC *memDC = (wxMemoryDC*)source;
1117
1118 bool use_bitmap_method = FALSE;
1119 bool is_mono = FALSE;
1120
1121 /* TODO: use the mask origin when drawing transparently */
1122 if (xsrcMask == -1 && ysrcMask == -1)
1123 {
1124 xsrcMask = xsrc; ysrcMask = ysrc;
1125 }
1126
1127 if (srcDC->m_isMemDC)
1128 {
1129 if (!memDC->m_selected.Ok()) return FALSE;
1130
1131 /* we use the "XCopyArea" way to copy a memory dc into
1132 y different window if the memory dc BOTH
1133 a) doesn't have any mask or its mask isn't used
1134 b) it is clipped
1135 c) is not 1-bit */
1136
1137 if (useMask && (memDC->m_selected.GetMask()))
1138 {
1139 /* we HAVE TO use the direct way for memory dcs
1140 that have mask since the XCopyArea doesn't know
1141 about masks */
1142 use_bitmap_method = TRUE;
1143 }
1144 else if (memDC->m_selected.GetDepth() == 1)
1145 {
1146 /* we HAVE TO use the direct way for memory dcs
1147 that are bitmaps because XCopyArea doesn't cope
1148 with different bit depths */
1149 is_mono = TRUE;
1150 use_bitmap_method = TRUE;
1151 }
1152 else if ((xsrc == 0) && (ysrc == 0) &&
1153 (width == memDC->m_selected.GetWidth()) &&
1154 (height == memDC->m_selected.GetHeight()))
1155 {
1156 /* we SHOULD use the direct way if all of the bitmap
1157 in the memory dc is copied in which case XCopyArea
1158 wouldn't be able able to boost performace by reducing
1159 the area to be scaled */
1160 use_bitmap_method = TRUE;
1161 }
1162 else
1163 {
1164 use_bitmap_method = FALSE;
1165 }
1166 }
1167
1168 CalcBoundingBox( xdest, ydest );
1169 CalcBoundingBox( xdest + width, ydest + height );
1170
1171 /* scale/translate size and position */
1172 wxCoord xx = XLOG2DEV(xdest);
1173 wxCoord yy = YLOG2DEV(ydest);
1174
1175 wxCoord ww = XLOG2DEVREL(width);
1176 wxCoord hh = YLOG2DEVREL(height);
1177
1178 /* compare to current clipping region */
1179 if (!m_currentClippingRegion.IsNull())
1180 {
1181 wxRegion tmp( xx,yy,ww,hh );
1182 tmp.Intersect( m_currentClippingRegion );
1183 if (tmp.IsEmpty())
1184 return TRUE;
1185 }
1186
1187 int old_logical_func = m_logicalFunction;
1188 SetLogicalFunction( logical_func );
1189
1190 if (use_bitmap_method)
1191 {
1192 /* scale/translate bitmap size */
1193 wxCoord bm_width = memDC->m_selected.GetWidth();
1194 wxCoord bm_height = memDC->m_selected.GetHeight();
1195
1196 wxCoord bm_ww = XLOG2DEVREL( bm_width );
1197 wxCoord bm_hh = YLOG2DEVREL( bm_height );
1198
1199 /* scale bitmap if required */
1200 wxBitmap use_bitmap;
1201
1202 if ((bm_width != bm_ww) || (bm_height != bm_hh))
1203 {
1204 wxImage image = memDC->m_selected.ConvertToImage();
1205 image = image.Scale( bm_ww, bm_hh );
1206
1207 if (is_mono)
1208 use_bitmap = wxBitmap(image.ConvertToMono(255,255,255), 1);
1209 else
1210 use_bitmap = wxBitmap(image);
1211 }
1212 else
1213 {
1214 use_bitmap = memDC->m_selected;
1215 }
1216
1217 /* apply mask if any */
1218 GdkBitmap *mask = (GdkBitmap *) NULL;
1219 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
1220
1221 if (useMask && mask)
1222 {
1223 GdkBitmap *new_mask = (GdkBitmap*) NULL;
1224 #ifndef __WXGTK20__ // TODO fix crash
1225 if (!m_currentClippingRegion.IsNull())
1226 {
1227 GdkColor col;
1228 new_mask = gdk_pixmap_new( wxGetRootWindow()->window, bm_ww, bm_hh, 1 );
1229 GdkGC *gc = gdk_gc_new( new_mask );
1230 col.pixel = 0;
1231 gdk_gc_set_foreground( gc, &col );
1232 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh );
1233 col.pixel = 0;
1234 gdk_gc_set_background( gc, &col );
1235 col.pixel = 1;
1236 gdk_gc_set_foreground( gc, &col );
1237 gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() );
1238 gdk_gc_set_clip_origin( gc, -xx, -yy );
1239 gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED );
1240 gdk_gc_set_stipple( gc, mask );
1241 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh );
1242 gdk_gc_unref( gc );
1243 }
1244 #endif
1245 if (is_mono)
1246 {
1247 if (new_mask)
1248 gdk_gc_set_clip_mask( m_textGC, new_mask );
1249 else
1250 gdk_gc_set_clip_mask( m_textGC, mask );
1251 gdk_gc_set_clip_origin( m_textGC, xx, yy );
1252 }
1253 else
1254 {
1255 if (new_mask)
1256 gdk_gc_set_clip_mask( m_penGC, new_mask );
1257 else
1258 gdk_gc_set_clip_mask( m_penGC, mask );
1259 gdk_gc_set_clip_origin( m_penGC, xx, yy );
1260 }
1261 if (new_mask)
1262 gdk_bitmap_unref( new_mask );
1263 }
1264
1265 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1266 drawing a mono-bitmap (XBitmap) we use the current text GC */
1267
1268 if (is_mono)
1269 gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), xsrc, ysrc, xx, yy, ww, hh );
1270 else
1271 gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), xsrc, ysrc, xx, yy, ww, hh );
1272
1273 /* remove mask again if any */
1274 if (useMask && mask)
1275 {
1276 if (is_mono)
1277 {
1278 gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL );
1279 gdk_gc_set_clip_origin( m_textGC, 0, 0 );
1280 if (!m_currentClippingRegion.IsNull())
1281 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
1282 }
1283 else
1284 {
1285 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
1286 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
1287 if (!m_currentClippingRegion.IsNull())
1288 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
1289 }
1290 }
1291 }
1292 else /* use_bitmap_method */
1293 {
1294 if ((width != ww) || (height != hh))
1295 {
1296 /* draw source window into a bitmap as we cannot scale
1297 a window in contrast to a bitmap. this would actually
1298 work with memory dcs as well, but we'd lose the mask
1299 information and waste one step in this process since
1300 a memory already has a bitmap. all this is slightly
1301 inefficient as we could take an XImage directly from
1302 an X window, but we'd then also have to care that
1303 the window is not outside the screen (in which case
1304 we'd get a BadMatch or what not).
1305 Is a double XGetImage and combined XGetPixel and
1306 XPutPixel really faster? I'm not sure. look at wxXt
1307 for a different implementation of the same problem. */
1308
1309 wxBitmap bitmap( width, height );
1310
1311 /* copy including child window contents */
1312 gdk_gc_set_subwindow( m_penGC, GDK_INCLUDE_INFERIORS );
1313 gdk_window_copy_area( bitmap.GetPixmap(), m_penGC, 0, 0,
1314 srcDC->GetWindow(),
1315 xsrc, ysrc, width, height );
1316 gdk_gc_set_subwindow( m_penGC, GDK_CLIP_BY_CHILDREN );
1317
1318 /* scale image */
1319 wxImage image = bitmap.ConvertToImage();
1320 image = image.Scale( ww, hh );
1321
1322 /* convert to bitmap */
1323 bitmap = wxBitmap(image);
1324
1325 /* draw scaled bitmap */
1326 gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
1327
1328 }
1329 else
1330 {
1331 /* No scaling and not a memory dc with a mask either */
1332
1333 /* copy including child window contents */
1334 gdk_gc_set_subwindow( m_penGC, GDK_INCLUDE_INFERIORS );
1335 gdk_window_copy_area( m_window, m_penGC, xx, yy,
1336 srcDC->GetWindow(),
1337 xsrc, ysrc, width, height );
1338 gdk_gc_set_subwindow( m_penGC, GDK_CLIP_BY_CHILDREN );
1339 }
1340 }
1341
1342 SetLogicalFunction( old_logical_func );
1343 return TRUE;
1344 }
1345
1346 void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y )
1347 {
1348 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1349
1350 if (!m_window) return;
1351
1352 GdkFont *font = m_font.GetInternalFont( m_scaleY );
1353
1354 wxCHECK_RET( font, wxT("invalid font") );
1355
1356 #if defined(__WXGTK20__)
1357 wxCHECK_RET( m_context, wxT("no Pango context") );
1358 #endif
1359
1360 x = XLOG2DEV(x);
1361 y = YLOG2DEV(y);
1362
1363 #if defined(__WXGTK20__) && wxUSE_WCHAR_T
1364 // TODO: the layout engine should be abstracted at a higher level!
1365 PangoLayout *layout = pango_layout_new(m_context);
1366 pango_layout_set_font_description(layout, m_fontdesc);
1367 {
1368 const wxWX2MBbuf data = text.mb_str(wxConvUTF8);
1369 pango_layout_set_text(layout, data, strlen(data));
1370 }
1371 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
1372 PangoRectangle rect;
1373 pango_layout_line_get_extents(line, NULL, &rect);
1374 wxCoord width = rect.width;
1375 wxCoord height = rect.height;
1376 gdk_draw_layout( m_window, m_textGC, x, y, layout );
1377 #else // GTK+ 1.x
1378 wxCoord width = gdk_string_width( font, text.mbc_str() );
1379 wxCoord height = font->ascent + font->descent;
1380
1381 if ( m_backgroundMode == wxSOLID )
1382 {
1383 gdk_gc_set_foreground( m_textGC, m_textBackgroundColour.GetColor() );
1384 gdk_draw_rectangle( m_window, m_textGC, TRUE, x, y, width, height );
1385 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
1386 }
1387 gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text.mbc_str() );
1388 #endif // GTK+ 2.0/1.x
1389
1390 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1391 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1392 properties (see wxXt implementation) */
1393 if (m_font.GetUnderlined())
1394 {
1395 wxCoord ul_y = y + font->ascent;
1396 if (font->descent > 0) ul_y++;
1397 gdk_draw_line( m_window, m_textGC, x, ul_y, x + width, ul_y);
1398 }
1399
1400 #if defined(__WXGTK20__) && wxUSE_WCHAR_T
1401 g_object_unref( G_OBJECT( layout ) );
1402 #endif
1403
1404 width = wxCoord(width / m_scaleX);
1405 height = wxCoord(height / m_scaleY);
1406 CalcBoundingBox (x + width, y + height);
1407 CalcBoundingBox (x, y);
1408 }
1409
1410 void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle )
1411 {
1412 if (angle == 0.0)
1413 {
1414 DrawText(text, x, y);
1415 return;
1416 }
1417
1418 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1419
1420 if (!m_window) return;
1421
1422 GdkFont *font = m_font.GetInternalFont( m_scaleY );
1423
1424 wxCHECK_RET( font, wxT("invalid font") );
1425
1426 // the size of the text
1427 wxCoord w = gdk_string_width( font, text.mbc_str() );
1428 wxCoord h = font->ascent + font->descent;
1429
1430 // draw the string normally
1431 wxBitmap src(w, h);
1432 wxMemoryDC dc;
1433 dc.SelectObject(src);
1434 dc.SetFont(GetFont());
1435 dc.SetBackground(*wxWHITE_BRUSH);
1436 dc.SetBrush(*wxBLACK_BRUSH);
1437 dc.Clear();
1438 dc.DrawText(text, 0, 0);
1439 dc.SelectObject(wxNullBitmap);
1440
1441 // Calculate the size of the rotated bounding box.
1442 double rad = DegToRad(angle);
1443 double dx = cos(rad),
1444 dy = sin(rad);
1445
1446 // the rectngle vertices are counted clockwise with the first one being at
1447 // (0, 0) (or, rather, at (x, y))
1448 double x2 = w*dx,
1449 y2 = -w*dy; // y axis points to the bottom, hence minus
1450 double x4 = h*dy,
1451 y4 = h*dx;
1452 double x3 = x4 + x2,
1453 y3 = y4 + y2;
1454
1455 // calc max and min
1456 wxCoord maxX = (wxCoord)(dmax(x2, dmax(x3, x4)) + 0.5),
1457 maxY = (wxCoord)(dmax(y2, dmax(y3, y4)) + 0.5),
1458 minX = (wxCoord)(dmin(x2, dmin(x3, x4)) - 0.5),
1459 minY = (wxCoord)(dmin(y2, dmin(y3, y4)) - 0.5);
1460
1461 // prepare to blit-with-rotate the bitmap to the DC
1462 wxImage image = src.ConvertToImage();
1463
1464 GdkColor *colText = m_textForegroundColour.GetColor(),
1465 *colBack = m_textBackgroundColour.GetColor();
1466
1467 bool textColSet = TRUE;
1468
1469 unsigned char *data = image.GetData();
1470
1471 // paint pixel by pixel
1472 for ( wxCoord srcX = 0; srcX < w; srcX++ )
1473 {
1474 for ( wxCoord srcY = 0; srcY < h; srcY++ )
1475 {
1476 // transform source coords to dest coords
1477 double r = sqrt((double)srcX*srcX + srcY*srcY);
1478 double angleOrig = atan2((double)srcY, (double)srcX) - rad;
1479 wxCoord dstX = (wxCoord)(r*cos(angleOrig) + 0.5),
1480 dstY = (wxCoord)(r*sin(angleOrig) + 0.5);
1481
1482 // black pixel?
1483 bool textPixel = data[(srcY*w + srcX)*3] == 0;
1484 if ( textPixel || (m_backgroundMode == wxSOLID) )
1485 {
1486 // change colour if needed
1487 if ( textPixel != textColSet )
1488 {
1489 gdk_gc_set_foreground( m_textGC, textPixel ? colText
1490 : colBack );
1491
1492 textColSet = textPixel;
1493 }
1494
1495 // don't use DrawPoint() because it uses the current pen
1496 // colour, and we don't need it here
1497 gdk_draw_point( m_window, m_textGC,
1498 XLOG2DEV(x + dstX), YLOG2DEV(y + dstY) );
1499 }
1500 }
1501 }
1502
1503 // it would be better to draw with non underlined font and draw the line
1504 // manually here (it would be more straight...)
1505 #if 0
1506 if ( m_font.GetUnderlined() )
1507 {
1508 gdk_draw_line( m_window, m_textGC,
1509 XLOG2DEV(x + x4), YLOG2DEV(y + y4 + font->descent),
1510 XLOG2DEV(x + x3), YLOG2DEV(y + y3 + font->descent));
1511 }
1512 #endif // 0
1513
1514 // restore the font colour
1515 gdk_gc_set_foreground( m_textGC, colText );
1516
1517 // update the bounding box
1518 CalcBoundingBox(x + minX, y + minY);
1519 CalcBoundingBox(x + maxX, y + maxY);
1520 }
1521
1522 void wxWindowDC::DoGetTextExtent(const wxString &string,
1523 wxCoord *width, wxCoord *height,
1524 wxCoord *descent, wxCoord *externalLeading,
1525 wxFont *theFont) const
1526 {
1527 wxFont fontToUse = m_font;
1528 if (theFont) fontToUse = *theFont;
1529
1530 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
1531 if (width) (*width) = wxCoord(gdk_string_width( font, string.mbc_str() ) / m_scaleX);
1532 if (height) (*height) = wxCoord((font->ascent + font->descent) / m_scaleY);
1533 if (descent) (*descent) = wxCoord(font->descent / m_scaleY);
1534 if (externalLeading) (*externalLeading) = 0; // ??
1535 }
1536
1537 wxCoord wxWindowDC::GetCharWidth() const
1538 {
1539 GdkFont *font = m_font.GetInternalFont( m_scaleY );
1540 wxCHECK_MSG( font, -1, wxT("invalid font") );
1541
1542 return wxCoord(gdk_string_width( font, "H" ) / m_scaleX);
1543 }
1544
1545 wxCoord wxWindowDC::GetCharHeight() const
1546 {
1547 GdkFont *font = m_font.GetInternalFont( m_scaleY );
1548 wxCHECK_MSG( font, -1, wxT("invalid font") );
1549
1550 return wxCoord((font->ascent + font->descent) / m_scaleY);
1551 }
1552
1553 void wxWindowDC::Clear()
1554 {
1555 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1556
1557 if (!m_window) return;
1558
1559 /* - we either are a memory dc or have a window as the
1560 owner. anything else shouldn't happen.
1561 - we don't use gdk_window_clear() as we don't set
1562 the window's background colour anymore. it is too
1563 much pain to keep the DC's and the window's back-
1564 ground colour in synch. */
1565
1566 if (m_owner)
1567 {
1568 int width,height;
1569 m_owner->GetSize( &width, &height );
1570 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
1571 return;
1572 }
1573
1574 if (m_isMemDC)
1575 {
1576 int width,height;
1577 GetSize( &width, &height );
1578 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
1579 return;
1580 }
1581 }
1582
1583 void wxWindowDC::SetFont( const wxFont &font )
1584 {
1585 wxCHECK_RET( font.Ok(), _T("invalid font in wxWindowDC::SetFont") );
1586
1587 m_font = font;
1588 #ifdef __WXGTK20__
1589 // fix fontdesc?
1590 #endif
1591 }
1592
1593 void wxWindowDC::SetPen( const wxPen &pen )
1594 {
1595 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1596
1597 if (m_pen == pen) return;
1598
1599 m_pen = pen;
1600
1601 if (!m_pen.Ok()) return;
1602
1603 if (!m_window) return;
1604
1605 gint width = m_pen.GetWidth();
1606 if (width <= 0)
1607 {
1608 // CMB: if width is non-zero scale it with the dc
1609 width = 1;
1610 }
1611 else
1612 {
1613 // X doesn't allow different width in x and y and so we take
1614 // the average
1615 double w = 0.5 +
1616 ( fabs((double) XLOG2DEVREL(width)) +
1617 fabs((double) YLOG2DEVREL(width)) ) / 2.0;
1618 width = (int)w;
1619 }
1620
1621 static const wxGTKDash dotted[] = {1, 1};
1622 static const wxGTKDash short_dashed[] = {2, 2};
1623 static const wxGTKDash wxCoord_dashed[] = {2, 4};
1624 static const wxGTKDash dotted_dashed[] = {3, 3, 1, 3};
1625
1626 // We express dash pattern in pen width unit, so we are
1627 // independent of zoom factor and so on...
1628 int req_nb_dash;
1629 const wxGTKDash *req_dash;
1630
1631 GdkLineStyle lineStyle = GDK_LINE_SOLID;
1632 switch (m_pen.GetStyle())
1633 {
1634 case wxUSER_DASH:
1635 {
1636 lineStyle = GDK_LINE_ON_OFF_DASH;
1637 req_nb_dash = m_pen.GetDashCount();
1638 req_dash = (wxGTKDash*)m_pen.GetDash();
1639 break;
1640 }
1641 case wxDOT:
1642 {
1643 lineStyle = GDK_LINE_ON_OFF_DASH;
1644 req_nb_dash = 2;
1645 req_dash = dotted;
1646 break;
1647 }
1648 case wxLONG_DASH:
1649 {
1650 lineStyle = GDK_LINE_ON_OFF_DASH;
1651 req_nb_dash = 2;
1652 req_dash = wxCoord_dashed;
1653 break;
1654 }
1655 case wxSHORT_DASH:
1656 {
1657 lineStyle = GDK_LINE_ON_OFF_DASH;
1658 req_nb_dash = 2;
1659 req_dash = short_dashed;
1660 break;
1661 }
1662 case wxDOT_DASH:
1663 {
1664 // lineStyle = GDK_LINE_DOUBLE_DASH;
1665 lineStyle = GDK_LINE_ON_OFF_DASH;
1666 req_nb_dash = 4;
1667 req_dash = dotted_dashed;
1668 break;
1669 }
1670
1671 case wxTRANSPARENT:
1672 case wxSTIPPLE_MASK_OPAQUE:
1673 case wxSTIPPLE:
1674 case wxSOLID:
1675 default:
1676 {
1677 lineStyle = GDK_LINE_SOLID;
1678 req_dash = (wxGTKDash*)NULL;
1679 req_nb_dash = 0;
1680 break;
1681 }
1682 }
1683
1684 #if (GTK_MINOR_VERSION > 0) || (GTK_MAJOR_VERSION > 1)
1685 if (req_dash && req_nb_dash)
1686 {
1687 wxGTKDash *real_req_dash = new wxGTKDash[req_nb_dash];
1688 if (real_req_dash)
1689 {
1690 for (int i = 0; i < req_nb_dash; i++)
1691 real_req_dash[i] = req_dash[i] * width;
1692 gdk_gc_set_dashes( m_penGC, 0, real_req_dash, req_nb_dash );
1693 delete[] real_req_dash;
1694 }
1695 else
1696 {
1697 // No Memory. We use non-scaled dash pattern...
1698 gdk_gc_set_dashes( m_penGC, 0, (wxGTKDash*)req_dash, req_nb_dash );
1699 }
1700 }
1701 #endif
1702
1703 GdkCapStyle capStyle = GDK_CAP_ROUND;
1704 switch (m_pen.GetCap())
1705 {
1706 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
1707 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
1708 case wxCAP_ROUND:
1709 default:
1710 {
1711 if (width <= 1)
1712 {
1713 width = 0;
1714 capStyle = GDK_CAP_NOT_LAST;
1715 }
1716 else
1717 {
1718 capStyle = GDK_CAP_ROUND;
1719 }
1720 break;
1721 }
1722 }
1723
1724 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
1725 switch (m_pen.GetJoin())
1726 {
1727 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
1728 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
1729 case wxJOIN_ROUND:
1730 default: { joinStyle = GDK_JOIN_ROUND; break; }
1731 }
1732
1733 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
1734
1735 m_pen.GetColour().CalcPixel( m_cmap );
1736 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
1737 }
1738
1739 void wxWindowDC::SetBrush( const wxBrush &brush )
1740 {
1741 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1742
1743 if (m_brush == brush) return;
1744
1745 m_brush = brush;
1746
1747 if (!m_brush.Ok()) return;
1748
1749 if (!m_window) return;
1750
1751 m_brush.GetColour().CalcPixel( m_cmap );
1752 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
1753
1754 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
1755
1756 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
1757 {
1758 if (m_brush.GetStipple()->GetPixmap())
1759 {
1760 gdk_gc_set_fill( m_brushGC, GDK_TILED );
1761 gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() );
1762 }
1763 else
1764 {
1765 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
1766 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() );
1767 }
1768 }
1769
1770 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
1771 {
1772 gdk_gc_set_fill( m_textGC, GDK_OPAQUE_STIPPLED);
1773 gdk_gc_set_stipple( m_textGC, m_brush.GetStipple()->GetMask()->GetBitmap() );
1774 }
1775
1776 if (IS_HATCH(m_brush.GetStyle()))
1777 {
1778 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
1779 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
1780 gdk_gc_set_stipple( m_brushGC, hatches[num] );
1781 }
1782 }
1783
1784 void wxWindowDC::SetBackground( const wxBrush &brush )
1785 {
1786 /* CMB 21/7/98: Added SetBackground. Sets background brush
1787 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1788
1789 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1790
1791 if (m_backgroundBrush == brush) return;
1792
1793 m_backgroundBrush = brush;
1794
1795 if (!m_backgroundBrush.Ok()) return;
1796
1797 if (!m_window) return;
1798
1799 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
1800 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
1801 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
1802 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
1803 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
1804
1805 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
1806
1807 if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok()))
1808 {
1809 if (m_backgroundBrush.GetStipple()->GetPixmap())
1810 {
1811 gdk_gc_set_fill( m_bgGC, GDK_TILED );
1812 gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
1813 }
1814 else
1815 {
1816 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
1817 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetBitmap() );
1818 }
1819 }
1820
1821 if (IS_HATCH(m_backgroundBrush.GetStyle()))
1822 {
1823 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
1824 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
1825 gdk_gc_set_stipple( m_bgGC, hatches[num] );
1826 }
1827 }
1828
1829 void wxWindowDC::SetLogicalFunction( int function )
1830 {
1831 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1832
1833 if (m_logicalFunction == function)
1834 return;
1835
1836 // VZ: shouldn't this be a CHECK?
1837 if (!m_window)
1838 return;
1839
1840 GdkFunction mode = GDK_COPY;
1841 switch (function)
1842 {
1843 case wxXOR: mode = GDK_XOR; break;
1844 case wxINVERT: mode = GDK_INVERT; break;
1845 #if (GTK_MINOR_VERSION > 0)
1846 case wxOR_REVERSE: mode = GDK_OR_REVERSE; break;
1847 case wxAND_REVERSE: mode = GDK_AND_REVERSE; break;
1848 case wxCLEAR: mode = GDK_CLEAR; break;
1849 case wxSET: mode = GDK_SET; break;
1850 case wxOR_INVERT: mode = GDK_OR_INVERT; break;
1851 case wxAND: mode = GDK_AND; break;
1852 case wxOR: mode = GDK_OR; break;
1853 case wxEQUIV: mode = GDK_EQUIV; break;
1854 case wxNAND: mode = GDK_NAND; break;
1855 case wxAND_INVERT: mode = GDK_AND_INVERT; break;
1856 case wxCOPY: mode = GDK_COPY; break;
1857 case wxNO_OP: mode = GDK_NOOP; break;
1858 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
1859
1860 // unsupported by GTK
1861 case wxNOR: mode = GDK_COPY; break;
1862 #endif
1863 default:
1864 {
1865 wxFAIL_MSG( wxT("unsupported logical function") );
1866 break;
1867 }
1868 }
1869
1870 m_logicalFunction = function;
1871
1872 gdk_gc_set_function( m_penGC, mode );
1873 gdk_gc_set_function( m_brushGC, mode );
1874
1875 // to stay compatible with wxMSW, we don't apply ROPs to the text
1876 // operations (i.e. DrawText/DrawRotatedText).
1877 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1878 gdk_gc_set_function( m_textGC, mode );
1879 }
1880
1881 void wxWindowDC::SetTextForeground( const wxColour &col )
1882 {
1883 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1884
1885 // don't set m_textForegroundColour to an invalid colour as we'd crash
1886 // later then (we use m_textForegroundColour.GetColor() without checking
1887 // in a few places)
1888 if ( !col.Ok() || (m_textForegroundColour == col) )
1889 return;
1890
1891 m_textForegroundColour = col;
1892
1893 if ( m_window )
1894 {
1895 m_textForegroundColour.CalcPixel( m_cmap );
1896 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
1897 }
1898 }
1899
1900 void wxWindowDC::SetTextBackground( const wxColour &col )
1901 {
1902 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1903
1904 // same as above
1905 if ( !col.Ok() || (m_textBackgroundColour == col) )
1906 return;
1907
1908 m_textBackgroundColour = col;
1909
1910 if ( m_window )
1911 {
1912 m_textBackgroundColour.CalcPixel( m_cmap );
1913 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
1914 }
1915 }
1916
1917 void wxWindowDC::SetBackgroundMode( int mode )
1918 {
1919 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1920
1921 m_backgroundMode = mode;
1922
1923 if (!m_window) return;
1924
1925 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1926 // transparent/solid background mode
1927
1928 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
1929 {
1930 gdk_gc_set_fill( m_brushGC,
1931 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
1932 }
1933 }
1934
1935 void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
1936 {
1937 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1938 }
1939
1940 void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
1941 {
1942 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1943
1944 if (!m_window) return;
1945
1946 wxRect rect;
1947 rect.x = XLOG2DEV(x);
1948 rect.y = YLOG2DEV(y);
1949 rect.width = XLOG2DEVREL(width);
1950 rect.height = YLOG2DEVREL(height);
1951
1952 if (!m_currentClippingRegion.IsNull())
1953 m_currentClippingRegion.Intersect( rect );
1954 else
1955 m_currentClippingRegion.Union( rect );
1956
1957 #if USE_PAINT_REGION
1958 if (!m_paintClippingRegion.IsNull())
1959 m_currentClippingRegion.Intersect( m_paintClippingRegion );
1960 #endif
1961
1962 wxCoord xx, yy, ww, hh;
1963 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
1964 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
1965
1966 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
1967 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
1968 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
1969 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
1970 }
1971
1972 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
1973 {
1974 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1975
1976 if (region.Empty())
1977 {
1978 DestroyClippingRegion();
1979 return;
1980 }
1981
1982 if (!m_window) return;
1983
1984 if (!m_currentClippingRegion.IsNull())
1985 m_currentClippingRegion.Intersect( region );
1986 else
1987 m_currentClippingRegion.Union( region );
1988
1989 #if USE_PAINT_REGION
1990 if (!m_paintClippingRegion.IsNull())
1991 m_currentClippingRegion.Intersect( m_paintClippingRegion );
1992 #endif
1993
1994 wxCoord xx, yy, ww, hh;
1995 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
1996 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
1997
1998 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
1999 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2000 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2001 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
2002 }
2003
2004 void wxWindowDC::DestroyClippingRegion()
2005 {
2006 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2007
2008 wxDC::DestroyClippingRegion();
2009
2010 m_currentClippingRegion.Clear();
2011
2012 #if USE_PAINT_REGION
2013 if (!m_paintClippingRegion.IsEmpty())
2014 m_currentClippingRegion.Union( m_paintClippingRegion );
2015 #endif
2016
2017 if (!m_window) return;
2018
2019 if (m_currentClippingRegion.IsEmpty())
2020 {
2021 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
2022 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
2023 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
2024 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
2025 }
2026 else
2027 {
2028 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2029 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2030 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2031 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
2032 }
2033 }
2034
2035 void wxWindowDC::Destroy()
2036 {
2037 if (m_penGC) wxFreePoolGC( m_penGC );
2038 m_penGC = (GdkGC*) NULL;
2039 if (m_brushGC) wxFreePoolGC( m_brushGC );
2040 m_brushGC = (GdkGC*) NULL;
2041 if (m_textGC) wxFreePoolGC( m_textGC );
2042 m_textGC = (GdkGC*) NULL;
2043 if (m_bgGC) wxFreePoolGC( m_bgGC );
2044 m_bgGC = (GdkGC*) NULL;
2045 }
2046
2047 void wxWindowDC::ComputeScaleAndOrigin()
2048 {
2049 /* CMB: copy scale to see if it changes */
2050 double origScaleX = m_scaleX;
2051 double origScaleY = m_scaleY;
2052
2053 wxDC::ComputeScaleAndOrigin();
2054
2055 /* CMB: if scale has changed call SetPen to recalulate the line width */
2056 if ((m_scaleX != origScaleX || m_scaleY != origScaleY) &&
2057 (m_pen.Ok()))
2058 {
2059 /* this is a bit artificial, but we need to force wxDC to think
2060 the pen has changed */
2061 wxPen pen = m_pen;
2062 m_pen = wxNullPen;
2063 SetPen( pen );
2064 }
2065 }
2066
2067 // Resolution in pixels per logical inch
2068 wxSize wxWindowDC::GetPPI() const
2069 {
2070 return wxSize( (int) (m_mm_to_pix_x * 25.4 + 0.5), (int) (m_mm_to_pix_y * 25.4 + 0.5));
2071 }
2072
2073 int wxWindowDC::GetDepth() const
2074 {
2075 wxFAIL_MSG(wxT("not implemented"));
2076
2077 return -1;
2078 }
2079
2080
2081 //-----------------------------------------------------------------------------
2082 // wxPaintDC
2083 //-----------------------------------------------------------------------------
2084
2085 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxClientDC)
2086
2087 wxPaintDC::wxPaintDC( wxWindow *win )
2088 : wxClientDC( win )
2089 {
2090 #if USE_PAINT_REGION
2091 if (!win->m_clipPaintRegion)
2092 return;
2093
2094 m_paintClippingRegion = win->GetUpdateRegion();
2095 GdkRegion *region = m_paintClippingRegion.GetRegion();
2096 if ( region )
2097 {
2098 m_paintClippingRegion = win->GetUpdateRegion();
2099 GdkRegion *region = m_paintClippingRegion.GetRegion();
2100 if ( region )
2101 {
2102 m_currentClippingRegion.Union( m_paintClippingRegion );
2103
2104 gdk_gc_set_clip_region( m_penGC, region );
2105 gdk_gc_set_clip_region( m_brushGC, region );
2106 gdk_gc_set_clip_region( m_textGC, region );
2107 gdk_gc_set_clip_region( m_bgGC, region );
2108 }
2109 }
2110 #endif // USE_PAINT_REGION
2111 }
2112
2113 //-----------------------------------------------------------------------------
2114 // wxClientDC
2115 //-----------------------------------------------------------------------------
2116
2117 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
2118
2119 wxClientDC::wxClientDC( wxWindow *win )
2120 : wxWindowDC( win )
2121 {
2122 wxCHECK_RET( win, _T("NULL window in wxClientDC::wxClientDC") );
2123
2124 #ifdef __WXUNIVERSAL__
2125 wxPoint ptOrigin = win->GetClientAreaOrigin();
2126 SetDeviceOrigin(ptOrigin.x, ptOrigin.y);
2127 wxSize size = win->GetClientSize();
2128 SetClippingRegion(wxPoint(0, 0), size);
2129 #endif // __WXUNIVERSAL__
2130 }
2131
2132 void wxClientDC::DoGetSize(int *width, int *height) const
2133 {
2134 wxCHECK_RET( m_owner, _T("GetSize() doesn't work without window") );
2135
2136 m_owner->GetClientSize( width, height );
2137 }
2138
2139 // ----------------------------------------------------------------------------
2140 // wxDCModule
2141 // ----------------------------------------------------------------------------
2142
2143 class wxDCModule : public wxModule
2144 {
2145 public:
2146 bool OnInit();
2147 void OnExit();
2148
2149 private:
2150 DECLARE_DYNAMIC_CLASS(wxDCModule)
2151 };
2152
2153 IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
2154
2155 bool wxDCModule::OnInit()
2156 {
2157 wxInitGCPool();
2158 return TRUE;
2159 }
2160
2161 void wxDCModule::OnExit()
2162 {
2163 wxCleanUpGCPool();
2164 }