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