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