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