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