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