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