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