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