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