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