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