]> git.saurik.com Git - wxWidgets.git/blame - src/motif/dcclient.cpp
Applied patch [ 726350 ] wxGrid - MovePageDown()
[wxWidgets.git] / src / motif / dcclient.cpp
CommitLineData
4bb6408c
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: dcclient.cpp
3// Purpose: wxClientDC class
4// Author: Julian Smart
5// Modified by:
6// Created: 01/02/97
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
af0bb3b1 9// Licence: wxWindows licence
4bb6408c
JS
10/////////////////////////////////////////////////////////////////////////////
11
16c1f7f3 12/*
af0bb3b1
VZ
13 About pens, brushes, and the autoSetting flag:
14
729be74d
MB
15 Under X, pens and brushes control some of the same X drawing
16 parameters. Therefore, it is impossible to independently maintain
17 the current pen and the current brush. Also, some settings depend on
18 the current logical function. The m_currentFill, etc. instance
19 variables remember state across the brush and pen.
af0bb3b1
VZ
20
21 Since pens are used more than brushes, the autoSetting flag is used to
22 indicate that a brush was recently used, and SetPen must be called to
23 reinstall the current pen's parameters. If autoSetting includes 0x2, then the
24 pens color may need to be set based on XOR.
25
26 There is, unfortunately, some confusion between setting the current pen/brush
27 and actually installing the brush/pen parameters. Both functionalies are
28 perform by SetPen and SetBrush. C'est la vie.
16c1f7f3
JS
29*/
30
af0bb3b1
VZ
31// ============================================================================
32// declarations
33// ============================================================================
34
35// ----------------------------------------------------------------------------
36// headers
37// ----------------------------------------------------------------------------
38
4bb6408c 39#ifdef __GNUG__
af0bb3b1 40 #pragma implementation "dcclient.h"
4bb6408c
JS
41#endif
42
43#include "wx/dcclient.h"
44#include "wx/dcmemory.h"
dfc54541 45#include "wx/window.h"
16c1f7f3 46#include "wx/app.h"
a91b47e8 47#include "wx/image.h"
b1699cd3 48#include "wx/log.h"
a91b47e8 49
4bb6408c
JS
50#include <math.h>
51
338dd992
JJ
52#ifdef __VMS__
53#pragma message disable nosimpint
54#endif
dfc54541 55#include <Xm/Xm.h>
338dd992
JJ
56#ifdef __VMS__
57#pragma message enable nosimpint
58#endif
dfc54541
JS
59
60#include "wx/motif/private.h"
61
280108ed
VZ
62#ifdef __EMX__
63 #include <float.h> // for M_PI
64#endif // __EMX__
65
16c1f7f3
JS
66#include "bdiag.xbm"
67#include "fdiag.xbm"
68#include "cdiag.xbm"
69#include "horiz.xbm"
70#include "verti.xbm"
71#include "cross.xbm"
72
73static Pixmap bdiag, cdiag, fdiag, cross, horiz, verti;
74
af0bb3b1 75// ----------------------------------------------------------------------------
4bb6408c 76// constants
af0bb3b1 77// ----------------------------------------------------------------------------
4bb6408c 78
af0bb3b1 79// Fudge factor (VZ: what??)
aaa38880 80#define WX_GC_CF 1
4bb6408c 81
af0bb3b1
VZ
82// ----------------------------------------------------------------------------
83// macros
84// ----------------------------------------------------------------------------
4bb6408c 85
af0bb3b1
VZ
86 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
87 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxWindowDC)
88 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
4bb6408c 89
af0bb3b1
VZ
90// ----------------------------------------------------------------------------
91// prototypes
92// ----------------------------------------------------------------------------
93
94static void XCopyRemote(Display *src_display, Display *dest_display,
95 Drawable src, Drawable dest,
96 GC destgc,
97 int srcx, int srcy,
98 unsigned int w, unsigned int h,
99 int destx, int desty,
100 bool more, XImage **cache);
101
102// ============================================================================
103// implementation
104// ============================================================================
105
95724b1a
VZ
106/*
107 * compare two doubles and return the larger rounded
108 * to the nearest int
109 */
110static int roundmax(double a, double b)
111{
112 return (int)((a > b ? a : b) + 0.5);
113}
114
115/*
116 * compare two doubles and return the smaller rounded
117 * to the nearest int
118 */
119static int roundmin(double a, double b)
120{
121 return (int)((a < b ? a : b) - 0.5);
122}
123
124
af0bb3b1
VZ
125// ----------------------------------------------------------------------------
126// wxWindowDC
127// ----------------------------------------------------------------------------
128
129wxWindowDC::wxWindowDC()
dfc54541
JS
130{
131 m_gc = (WXGC) 0;
132 m_gcBacking = (WXGC) 0;
133 m_window = NULL;
134 m_backgroundPixel = -1;
135 m_currentPenWidth = 1;
136 m_currentPenJoin = -1;
137 m_currentPenDashCount = -1;
69c44812 138 m_currentPenDash = (wxX11Dash*) NULL;
dfc54541
JS
139 m_currentStyle = -1;
140 m_currentFill = -1;
2d120f83 141 // m_currentBkMode = wxTRANSPARENT;
dfc54541
JS
142 m_colour = wxColourDisplay();
143 m_display = (WXDisplay*) NULL;
16c1f7f3
JS
144 m_currentRegion = (WXRegion) 0;
145 m_userRegion = (WXRegion) 0;
146 m_pixmap = (WXPixmap) 0;
147 m_autoSetting = 0;
e97f20a0 148 m_oldFont = (WXFont) 0;
af0bb3b1 149}
dfc54541
JS
150
151wxWindowDC::wxWindowDC( wxWindow *window )
152{
16c1f7f3 153 wxASSERT_MSG( (window != (wxWindow*) NULL), "You must pass a valid wxWindow to wxWindowDC/wxClientDC/wxPaintDC constructor." );
af0bb3b1 154
dfc54541 155 m_window = window;
60f5b880 156 m_font = window->GetFont();
dfc54541
JS
157 m_gc = (WXGC) 0;
158 m_gcBacking = (WXGC) 0;
dfc54541
JS
159 m_backgroundPixel = -1;
160 m_currentPenWidth = 1;
161 m_currentPenJoin = -1;
162 m_currentPenDashCount = -1;
69c44812 163 m_currentPenDash = (wxX11Dash*) NULL;
dfc54541
JS
164 m_currentStyle = -1;
165 m_currentFill = -1;
2d120f83 166 // m_currentBkMode = wxTRANSPARENT;
dfc54541 167 m_colour = wxColourDisplay();
16c1f7f3
JS
168 m_currentRegion = (WXRegion) 0;
169 m_userRegion = (WXRegion) 0;
dfc54541 170 m_ok = TRUE;
16c1f7f3 171 m_autoSetting = 0;
af0bb3b1 172
16c1f7f3
JS
173 m_display = window->GetXDisplay();
174 m_pixmap = window->GetXWindow();
175 Display* display = (Display*) m_display;
af0bb3b1 176
16c1f7f3 177 XSetWindowColormap (display, (Pixmap) m_pixmap, (Colormap) wxTheApp->GetMainColormap(m_display));
af0bb3b1 178
16c1f7f3
JS
179 XGCValues gcvalues;
180 gcvalues.foreground = BlackPixel (display, DefaultScreen (display));
181 gcvalues.background = WhitePixel (display, DefaultScreen (display));
182 gcvalues.graphics_exposures = False;
66eca538 183 gcvalues.subwindow_mode = IncludeInferiors;
16c1f7f3
JS
184 gcvalues.line_width = 1;
185 m_gc = (WXGC) XCreateGC (display, RootWindow (display, DefaultScreen (display)),
66eca538 186 GCForeground | GCBackground | GCGraphicsExposures | GCLineWidth | GCSubwindowMode,
2d120f83 187 &gcvalues);
af0bb3b1 188
16c1f7f3
JS
189 if (m_window->GetBackingPixmap())
190 {
2d120f83
JS
191 m_gcBacking = (WXGC) XCreateGC (display, RootWindow (display,
192 DefaultScreen (display)),
66eca538 193 GCForeground | GCBackground | GCGraphicsExposures | GCLineWidth | GCSubwindowMode,
2d120f83 194 &gcvalues);
16c1f7f3 195 }
af0bb3b1 196
16c1f7f3 197 m_backgroundPixel = (int) gcvalues.background;
af0bb3b1 198
e97f20a0
JS
199 // Get the current Font so we can set it back later
200 XGCValues valReturn;
201 XGetGCValues((Display*) m_display, (GC) m_gc, GCFont, &valReturn);
202 m_oldFont = (WXFont) valReturn.font;
a91b47e8
JS
203
204 SetBackground(wxBrush(m_window->GetBackgroundColour(), wxSOLID));
af0bb3b1 205}
dfc54541 206
af0bb3b1 207wxWindowDC::~wxWindowDC()
dfc54541 208{
a4294b78 209 if (m_gc && (m_oldFont != (WXFont) 0) && ((long) m_oldFont != -1))
e97f20a0 210 {
2d120f83 211 XSetFont ((Display*) m_display, (GC) m_gc, (Font) m_oldFont);
af0bb3b1 212
2d120f83
JS
213 if (m_window && m_window->GetBackingPixmap())
214 XSetFont ((Display*) m_display,(GC) m_gcBacking, (Font) m_oldFont);
e97f20a0 215 }
af0bb3b1 216
dfc54541
JS
217 if (m_gc)
218 XFreeGC ((Display*) m_display, (GC) m_gc);
219 m_gc = (WXGC) 0;
af0bb3b1 220
dfc54541
JS
221 if (m_gcBacking)
222 XFreeGC ((Display*) m_display, (GC) m_gcBacking);
223 m_gcBacking = (WXGC) 0;
af0bb3b1 224
16c1f7f3
JS
225 if (m_currentRegion)
226 XDestroyRegion ((Region) m_currentRegion);
227 m_currentRegion = (WXRegion) 0;
af0bb3b1 228
16c1f7f3
JS
229 if (m_userRegion)
230 XDestroyRegion ((Region) m_userRegion);
231 m_userRegion = (WXRegion) 0;
af0bb3b1 232}
dfc54541 233
387ebd3e 234extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
3a0a5ada 235 const wxColour & col, int style);
4bb6408c 236
387ebd3e 237bool wxWindowDC::DoFloodFill(wxCoord x, wxCoord y,
3a0a5ada
VS
238 const wxColour& col, int style)
239{
387ebd3e 240 return wxDoFloodFill(this, x, y, col, style);
b1699cd3
JS
241}
242
dc1efb1d 243bool wxWindowDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const
4bb6408c 244{
dc1efb1d
JS
245 // Generic (and therefore rather inefficient) method.
246 // Could be improved.
247 wxMemoryDC memdc;
248 wxBitmap bitmap(1, 1);
249 memdc.SelectObject(bitmap);
250 memdc.Blit(0, 0, 1, 1, (wxDC*) this, x1, y1);
251 memdc.SelectObject(wxNullBitmap);
79f1dd05 252 wxImage image = bitmap.ConvertToImage();
dc1efb1d
JS
253 col->Set(image.GetRed(0, 0), image.GetGreen(0, 0), image.GetBlue(0, 0));
254 return TRUE;
af0bb3b1 255}
4bb6408c 256
7b65ea1a 257void wxWindowDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
4bb6408c 258{
af0bb3b1
VZ
259 wxCHECK_RET( Ok(), "invalid dc" );
260
2d120f83 261 int x1d, y1d, x2d, y2d;
af0bb3b1 262
2d120f83 263 // FreeGetPixelCache();
af0bb3b1 264
2d120f83
JS
265 x1d = XLOG2DEV(x1);
266 y1d = YLOG2DEV(y1);
267 x2d = XLOG2DEV(x2);
268 y2d = YLOG2DEV(y2);
af0bb3b1 269
2d120f83
JS
270 if (m_autoSetting)
271 SetPen (m_pen);
af0bb3b1 272
2d120f83 273 XDrawLine ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, x1d, y1d, x2d, y2d);
af0bb3b1 274
2d120f83 275 if (m_window && m_window->GetBackingPixmap())
af0bb3b1 276 XDrawLine ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(), (GC) m_gcBacking,
2d120f83
JS
277 XLOG2DEV_2(x1), YLOG2DEV_2(y1),
278 XLOG2DEV_2(x2), YLOG2DEV_2(y2));
af0bb3b1 279
2d120f83
JS
280 CalcBoundingBox(x1, y1);
281 CalcBoundingBox(x2, y2);
af0bb3b1 282}
4bb6408c 283
7b65ea1a 284void wxWindowDC::DoCrossHair( wxCoord x, wxCoord y )
4bb6408c 285{
af0bb3b1
VZ
286 wxCHECK_RET( Ok(), "invalid dc" );
287
2d120f83
JS
288 if (m_autoSetting)
289 SetPen (m_pen);
af0bb3b1 290
2d120f83
JS
291 int xx = XLOG2DEV (x);
292 int yy = YLOG2DEV (y);
293 int ww, hh;
294 wxDisplaySize (&ww, &hh);
295 XDrawLine ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, 0, yy,
296 ww, yy);
297 XDrawLine ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xx, 0,
298 xx, hh);
af0bb3b1 299
2d120f83 300 if (m_window && m_window->GetBackingPixmap())
16c1f7f3 301 {
2d120f83
JS
302 xx = XLOG2DEV_2 (x);
303 yy = YLOG2DEV_2 (y);
304 XDrawLine ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(), (GC) m_gcBacking,
305 0, yy,
306 ww, yy);
307 XDrawLine ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(), (GC) m_gcBacking,
308 xx, 0,
309 xx, hh);
16c1f7f3 310 }
af0bb3b1 311}
4bb6408c 312
7b65ea1a 313void wxWindowDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc )
4bb6408c 314{
af0bb3b1
VZ
315 wxCHECK_RET( Ok(), "invalid dc" );
316
2d120f83 317 // FreeGetPixelCache();
af0bb3b1 318
2d120f83
JS
319 int xx1 = XLOG2DEV (x1);
320 int yy1 = YLOG2DEV (y1);
321 int xx2 = XLOG2DEV (x2);
322 int yy2 = YLOG2DEV (y2);
323 int xxc = XLOG2DEV (xc);
324 int yyc = YLOG2DEV (yc);
325 int xxc_2 = XLOG2DEV_2 (xc);
326 int yyc_2 = YLOG2DEV_2 (yc);
af0bb3b1 327
7b65ea1a
MB
328 wxCoord dx = xx1 - xxc;
329 wxCoord dy = yy1 - yyc;
f6bcfd97 330 double radius = sqrt ((double)(dx * dx + dy * dy));
7b65ea1a 331 wxCoord r = (wxCoord) radius;
af0bb3b1 332
2d120f83 333 double radius1, radius2;
af0bb3b1 334
2d120f83 335 if (xx1 == xx2 && yy1 == yy2)
16c1f7f3 336 {
2d120f83
JS
337 radius1 = 0.0;
338 radius2 = 360.0;
16c1f7f3 339 }
2d120f83
JS
340 else if (radius == 0.0)
341 radius1 = radius2 = 0.0;
16c1f7f3 342 else
2d120f83
JS
343 {
344 if (xx1 - xxc == 0)
345 if (yy1 - yyc < 0)
346 radius1 = 90.0;
347 else
348 radius1 = -90.0;
349 else
350 radius1 = -atan2 ((double) (yy1 - yyc), (double) (xx1 - xxc)) * 360.0 / (2 * M_PI);
af0bb3b1 351
2d120f83
JS
352 if (xx2 - xxc == 0)
353 if (yy2 - yyc < 0)
354 radius2 = 90.0;
355 else
356 radius2 = -90.0;
357 else
358 radius2 = -atan2 ((double) (yy2 - yyc), (double) (xx2 - xxc)) * 360.0 / (2 * M_PI);
16c1f7f3 359 }
2d120f83
JS
360 radius1 *= 64.0;
361 radius2 *= 64.0;
362 int alpha1 = (int) radius1;
363 int alpha2 = (int) (radius2 - radius1);
364 while (alpha2 <= 0)
365 alpha2 += 360 * 64;
366 while (alpha2 > 360 * 64)
367 alpha2 -= 360 * 64;
af0bb3b1 368
2d120f83 369 if (m_brush.Ok() && m_brush.GetStyle () != wxTRANSPARENT)
16c1f7f3 370 {
2d120f83
JS
371 SetBrush (m_brush);
372 XFillArc ((Display*) m_display, (Pixmap) m_pixmap, (GC) (GC) m_gc,
373 xxc - r, yyc - r, 2 * r, 2 * r, alpha1, alpha2);
af0bb3b1 374
2d120f83
JS
375 if (m_window && m_window->GetBackingPixmap())
376 XFillArc ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(), (GC) m_gcBacking,
377 xxc_2 - r, yyc_2 - r, 2 * r, 2 * r, alpha1, alpha2);
af0bb3b1 378
16c1f7f3 379 }
af0bb3b1 380
2d120f83 381 if (m_pen.Ok() && m_pen.GetStyle () != wxTRANSPARENT)
16c1f7f3
JS
382 {
383 if (m_autoSetting)
384 SetPen (m_pen);
2d120f83
JS
385 XDrawArc ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc,
386 xxc - r, yyc - r, 2 * r, 2 * r, alpha1, alpha2);
af0bb3b1 387
2d120f83
JS
388 if (m_window && m_window->GetBackingPixmap())
389 XDrawArc ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(), (GC) m_gcBacking,
390 xxc_2 - r, yyc_2 - r, 2 * r, 2 * r, alpha1, alpha2);
16c1f7f3 391 }
2d120f83
JS
392 CalcBoundingBox (x1, y1);
393 CalcBoundingBox (x2, y2);
af0bb3b1 394}
4bb6408c 395
7b65ea1a 396void wxWindowDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea )
4bb6408c 397{
af0bb3b1
VZ
398 wxCHECK_RET( Ok(), "invalid dc" );
399
2d120f83 400 int xd, yd, wd, hd;
af0bb3b1 401
2d120f83
JS
402 xd = XLOG2DEV(x);
403 yd = YLOG2DEV(y);
404 wd = XLOG2DEVREL(width);
405 hd = YLOG2DEVREL(height);
af0bb3b1 406
2d120f83
JS
407 if (sa>=360 || sa<=-360) sa=sa-int(sa/360)*360;
408 if (ea>=360 || ea<=-360) ea=ea-int(ea/360)*360;
409 int start = int(sa*64);
410 int end = int(ea*64);
411 if (start<0) start+=360*64;
412 if (end <0) end +=360*64;
413 if (end>start) end-=start;
414 else end+=360*64-start;
af0bb3b1 415
2d120f83 416 if (m_brush.Ok() && m_brush.GetStyle () != wxTRANSPARENT)
16c1f7f3 417 {
2d120f83 418 m_autoSetting = TRUE; // must be reset
af0bb3b1 419
2d120f83
JS
420 SetBrush (m_brush);
421 XFillArc ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd, yd, wd, hd, start, end);
af0bb3b1 422
2d120f83
JS
423 if (m_window && m_window->GetBackingPixmap())
424 XFillArc ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(), (GC) m_gcBacking,
425 XLOG2DEV_2 (x), YLOG2DEV_2 (y),wd,hd,start,end);
16c1f7f3 426 }
af0bb3b1 427
2d120f83 428 if (m_pen.Ok() && m_pen.GetStyle () != wxTRANSPARENT)
16c1f7f3 429 {
2d120f83
JS
430 if (m_autoSetting)
431 SetPen (m_pen);
432 XDrawArc ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd, yd, wd, hd, start,end);
433 if (m_window && m_window->GetBackingPixmap())
434 XDrawArc ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(), (GC) m_gcBacking,
435 XLOG2DEV_2 (x), YLOG2DEV_2 (y),wd,hd,start,end);
16c1f7f3 436 }
2d120f83
JS
437 CalcBoundingBox (x, y);
438 CalcBoundingBox (x + width, y + height);
af0bb3b1 439}
4bb6408c 440
7b65ea1a 441void wxWindowDC::DoDrawPoint( wxCoord x, wxCoord y )
4bb6408c 442{
af0bb3b1
VZ
443 wxCHECK_RET( Ok(), "invalid dc" );
444
2d120f83 445 // FreeGetPixelCache();
af0bb3b1 446
2d120f83
JS
447 if (m_pen.Ok() && m_autoSetting)
448 SetPen (m_pen);
af0bb3b1 449
2d120f83
JS
450 XDrawPoint ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, XLOG2DEV (x), YLOG2DEV (y));
451 if (m_window && m_window->GetBackingPixmap())
452 XDrawPoint ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking, XLOG2DEV_2 (x), YLOG2DEV_2 (y));
af0bb3b1 453
2d120f83 454 CalcBoundingBox (x, y);
af0bb3b1 455}
4bb6408c 456
7b65ea1a 457void wxWindowDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset )
4bb6408c 458{
af0bb3b1
VZ
459 wxCHECK_RET( Ok(), "invalid dc" );
460
2d120f83 461 // FreeGetPixelCache();
af0bb3b1 462
2d120f83 463 if (m_pen.Ok() && m_pen.GetStyle () != wxTRANSPARENT)
16c1f7f3 464 {
2d120f83
JS
465 if (m_autoSetting)
466 SetPen (m_pen);
af0bb3b1 467
2d120f83
JS
468 XPoint *xpoints = new XPoint[n];
469 int i;
af0bb3b1 470
2d120f83 471 for (i = 0; i < n; i++)
16c1f7f3 472 {
2d120f83
JS
473 xpoints[i].x = XLOG2DEV (points[i].x + xoffset);
474 xpoints[i].y = YLOG2DEV (points[i].y + yoffset);
475 }
476 XDrawLines ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xpoints, n, 0);
af0bb3b1 477
2d120f83
JS
478 if (m_window && m_window->GetBackingPixmap())
479 {
480 for (i = 0; i < n; i++)
481 {
482 xpoints[i].x = XLOG2DEV_2 (points[i].x + xoffset);
483 xpoints[i].y = YLOG2DEV_2 (points[i].y + yoffset);
484 }
485 XDrawLines ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking, xpoints, n, 0);
16c1f7f3 486 }
2d120f83 487 delete[]xpoints;
16c1f7f3 488 }
af0bb3b1 489}
4bb6408c 490
af0bb3b1 491void wxWindowDC::DoDrawPolygon( int n, wxPoint points[],
7b65ea1a 492 wxCoord xoffset, wxCoord yoffset, int fillStyle )
4bb6408c 493{
af0bb3b1 494 wxCHECK_RET( Ok(), "invalid dc" );
4bb6408c 495
2d120f83 496 // FreeGetPixelCache();
af0bb3b1 497
2d120f83
JS
498 XPoint *xpoints1 = new XPoint[n + 1];
499 XPoint *xpoints2 = new XPoint[n + 1];
500 int i;
501 for (i = 0; i < n; i++)
16c1f7f3 502 {
2d120f83
JS
503 xpoints1[i].x = XLOG2DEV (points[i].x + xoffset);
504 xpoints1[i].y = YLOG2DEV (points[i].y + yoffset);
505 xpoints2[i].x = XLOG2DEV_2 (points[i].x + xoffset);
506 xpoints2[i].y = YLOG2DEV_2 (points[i].y + yoffset);
507 CalcBoundingBox (points[i].x + xoffset, points[i].y + yoffset);
16c1f7f3 508 }
af0bb3b1 509
2d120f83
JS
510 // Close figure for XDrawLines (not needed for XFillPolygon)
511 xpoints1[i].x = xpoints1[0].x;
512 xpoints1[i].y = xpoints1[0].y;
513 xpoints2[i].x = xpoints2[0].x;
514 xpoints2[i].y = xpoints2[0].y;
af0bb3b1 515
2d120f83 516 if (m_brush.Ok() && m_brush.GetStyle () != wxTRANSPARENT)
16c1f7f3 517 {
2d120f83
JS
518 SetBrush (m_brush);
519 XSetFillRule ((Display*) m_display, (GC) m_gc, fillStyle == wxODDEVEN_RULE ? EvenOddRule : WindingRule);
520 XFillPolygon ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xpoints1, n, Complex, 0);
521 XSetFillRule ((Display*) m_display, (GC) m_gc, EvenOddRule); // default mode
522 if (m_window && m_window->GetBackingPixmap())
523 {
524 XSetFillRule ((Display*) m_display,(GC) m_gcBacking,
525 fillStyle == wxODDEVEN_RULE ? EvenOddRule : WindingRule);
526 XFillPolygon ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking, xpoints2, n, Complex, 0);
527 XSetFillRule ((Display*) m_display,(GC) m_gcBacking, EvenOddRule); // default mode
528 }
529 }
af0bb3b1 530
2d120f83 531 if (m_pen.Ok() && m_pen.GetStyle () != wxTRANSPARENT)
16c1f7f3 532 {
2d120f83
JS
533 if (m_autoSetting)
534 SetPen (m_pen);
535 XDrawLines ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xpoints1, n + 1, 0);
af0bb3b1 536
2d120f83
JS
537 if (m_window && m_window->GetBackingPixmap())
538 XDrawLines ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking, xpoints2, n + 1, 0);
16c1f7f3 539 }
af0bb3b1 540
2d120f83
JS
541 delete[]xpoints1;
542 delete[]xpoints2;
af0bb3b1 543}
4bb6408c 544
7b65ea1a 545void wxWindowDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
4bb6408c 546{
af0bb3b1 547 wxCHECK_RET( Ok(), "invalid dc" );
4bb6408c 548
2d120f83 549 // FreeGetPixelCache();
af0bb3b1 550
2d120f83 551 int xd, yd, wfd, hfd, wd, hd;
af0bb3b1 552
2d120f83
JS
553 xd = XLOG2DEV(x);
554 yd = YLOG2DEV(y);
555 wfd = XLOG2DEVREL(width);
556 wd = wfd - WX_GC_CF;
557 hfd = YLOG2DEVREL(height);
558 hd = hfd - WX_GC_CF;
af0bb3b1 559
2d120f83
JS
560 if (wfd == 0 || hfd == 0) return;
561 if (wd < 0) { wd = - wd; xd = xd - wd; }
562 if (hd < 0) { hd = - hd; yd = yd - hd; }
af0bb3b1 563
2d120f83 564 if (m_brush.Ok() && m_brush.GetStyle () != wxTRANSPARENT)
16c1f7f3 565 {
2d120f83
JS
566 SetBrush (m_brush);
567 XFillRectangle ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd, yd, wfd, hfd);
af0bb3b1 568
2d120f83
JS
569 if (m_window && m_window->GetBackingPixmap())
570 XFillRectangle ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
16c1f7f3
JS
571 XLOG2DEV_2 (x), YLOG2DEV_2 (y),
572 wfd, hfd);
573 }
af0bb3b1 574
2d120f83 575 if (m_pen.Ok() && m_pen.GetStyle () != wxTRANSPARENT)
16c1f7f3 576 {
2d120f83
JS
577 if (m_autoSetting)
578 SetPen (m_pen);
579 XDrawRectangle ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd, yd, wd, hd);
af0bb3b1 580
2d120f83
JS
581 if (m_window && m_window->GetBackingPixmap())
582 XDrawRectangle ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
16c1f7f3
JS
583 XLOG2DEV_2 (x), YLOG2DEV_2 (y),
584 wd, hd);
585 }
2d120f83
JS
586 CalcBoundingBox (x, y);
587 CalcBoundingBox (x + width, y + height);
af0bb3b1 588}
4bb6408c 589
7b65ea1a 590void wxWindowDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
4bb6408c 591{
af0bb3b1
VZ
592 wxCHECK_RET( Ok(), "invalid dc" );
593
2d120f83 594 // FreeGetPixelCache();
af0bb3b1 595
2d120f83 596 // If radius is negative, it's a proportion of the smaller dimension.
af0bb3b1 597
2d120f83 598 if (radius < 0.0) radius = - radius * ((width < height) ? width : height);
af0bb3b1 599
2d120f83
JS
600 int xd = XLOG2DEV (x);
601 int yd = YLOG2DEV (y);
602 int rd = XLOG2DEVREL ((long) radius);
603 int wd = XLOG2DEVREL (width) - WX_GC_CF;
604 int hd = YLOG2DEVREL (height) - WX_GC_CF;
af0bb3b1 605
2d120f83
JS
606 int rw_d = rd * 2;
607 int rh_d = rw_d;
af0bb3b1 608
2d120f83
JS
609 // If radius is zero use DrawRectangle() instead to avoid
610 // X drawing errors with small radii
611 if (rd == 0)
16c1f7f3 612 {
2d120f83
JS
613 DrawRectangle( x, y, width, height );
614 return;
16c1f7f3 615 }
af0bb3b1 616
2d120f83
JS
617 // Draw nothing if transformed w or h is 0
618 if (wd == 0 || hd == 0) return;
af0bb3b1 619
2d120f83
JS
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)
16c1f7f3 623 {
2d120f83
JS
624 wd--;
625 hd--;
16c1f7f3 626 }
af0bb3b1 627
2d120f83
JS
628 // CMB: ensure dd is not larger than rectangle otherwise we
629 // get an hour glass shape
630 if (rw_d > wd) rw_d = wd;
631 if (rw_d > hd) rw_d = hd;
632 rd = rw_d / 2;
af0bb3b1 633
2d120f83
JS
634 // For backing pixmap
635 int xd2 = XLOG2DEV_2 (x);
636 int yd2 = YLOG2DEV_2 (y);
637 int rd2 = XLOG2DEVREL ((long) radius);
638 int wd2 = XLOG2DEVREL (width) ;
639 int hd2 = YLOG2DEVREL (height) ;
af0bb3b1 640
2d120f83
JS
641 int rw_d2 = rd2 * 2;
642 int rh_d2 = rw_d2;
af0bb3b1 643
2d120f83
JS
644 if (m_brush.Ok() && m_brush.GetStyle () != wxTRANSPARENT)
645 {
646 SetBrush (m_brush);
af0bb3b1 647
2d120f83
JS
648 XFillRectangle ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd + rd, yd,
649 wd - rw_d, hd);
650 XFillRectangle ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd, yd + rd,
651 wd, hd - rh_d);
af0bb3b1 652
2d120f83
JS
653 // Arcs start from 3 o'clock, positive angles anticlockwise
654 // Top-left
655 XFillArc ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd, yd,
656 rw_d, rh_d, 90 * 64, 90 * 64);
657 // Top-right
658 XFillArc ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd + wd - rw_d, yd,
659 // rw_d, rh_d, 0, 90 * 64);
660 rw_d, rh_d, 0, 91 * 64);
661 // Bottom-right
662 XFillArc ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd + wd - rw_d,
663 yd + hd - rh_d,
664 // rw_d, rh_d, 270 * 64, 90 * 64);
665 rw_d, rh_d, 269 * 64, 92 * 64);
666 // Bottom-left
667 XFillArc ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd, yd + hd - rh_d,
668 rw_d, rh_d, 180 * 64, 90 * 64);
af0bb3b1 669
2d120f83
JS
670 if (m_window && m_window->GetBackingPixmap())
671 {
672 XFillRectangle ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
673 xd2 + rd2, yd2, wd2 - rw_d2, hd2);
674 XFillRectangle ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
675 xd2, yd2 + rd2, wd2, hd2 - rh_d2);
af0bb3b1 676
2d120f83
JS
677 XFillArc ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
678 xd2, yd2, rw_d2, rh_d2, 90 * 64, 90 * 64);
679 XFillArc ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
680 xd2 + wd2 - rw_d2, yd2,
681 // rw_d2, rh_d2, 0, 90 * 64);
682 rw_d2, rh_d2, 0, 91 * 64);
683 XFillArc ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
684 xd2 + wd2 - rw_d2,
685 yd2 + hd2 - rh_d2,
686 // rw_d2, rh_d2, 270 * 64, 90 * 64);
687 rw_d2, rh_d2, 269 * 64, 92 * 64);
688 XFillArc ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
689 xd2, yd2 + hd2 - rh_d2,
690 rw_d2, rh_d2, 180 * 64, 90 * 64);
691 }
692 }
af0bb3b1 693
2d120f83
JS
694 if (m_pen.Ok() && m_pen.GetStyle () != wxTRANSPARENT)
695 {
696 SetPen (m_pen);
697 XDrawLine ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd + rd, yd,
698 xd + wd - rd + 1, yd);
699 XDrawLine ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd + rd, yd + hd,
700 xd + wd - rd, yd + hd);
af0bb3b1 701
2d120f83
JS
702 XDrawLine ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd, yd + rd,
703 xd, yd + hd - rd);
704 XDrawLine ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd + wd, yd + rd,
705 xd + wd, yd + hd - rd + 1);
706 XDrawArc ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd, yd,
707 rw_d, rh_d, 90 * 64, 90 * 64);
708 XDrawArc ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd + wd - rw_d, yd,
709 // rw_d, rh_d, 0, 90 * 64);
710 rw_d, rh_d, 0, 91 * 64);
711 XDrawArc ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd + wd - rw_d,
712 yd + hd - rh_d,
713 rw_d, rh_d, 269 * 64, 92 * 64);
714 XDrawArc ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd, yd + hd - rh_d,
715 rw_d, rh_d, 180 * 64, 90 * 64);
af0bb3b1 716
2d120f83
JS
717 if (m_window && m_window->GetBackingPixmap())
718 {
719 XDrawLine ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
720 xd2 + rd2, yd2,
721 xd2 + wd2 - rd2 + 1, yd2);
722 XDrawLine ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
723 xd2 + rd2, yd2 + hd2,
724 xd2 + wd2 - rd2, yd2 + hd2);
af0bb3b1 725
2d120f83
JS
726 XDrawLine ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
727 xd2, yd2 + rd2,
728 xd2, yd2 + hd2 - rd2);
729 XDrawLine ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
730 xd2 + wd2, yd2 + rd2,
731 xd2 + wd2, yd2 + hd2 - rd2 + 1);
732 XDrawArc ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
733 xd2, yd2,
734 rw_d2, rh_d2, 90 * 64, 90 * 64);
735 XDrawArc ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
736 xd2 + wd2 - rw_d2, yd2,
737 // rw_d2, rh_d2, 0, 90 * 64);
738 rw_d2, rh_d2, 0, 91 * 64);
739 XDrawArc ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
740 xd2 + wd2 - rw_d2,
741 yd2 + hd2 - rh_d2,
742 rw_d2, rh_d2, 269 * 64, 92 * 64);
743 XDrawArc ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
744 xd2, yd2 + hd2 - rh_d2,
745 rw_d2, rh_d2, 180 * 64, 90 * 64);
746 }
747 }
748 CalcBoundingBox (x, y);
749 CalcBoundingBox (x + width, y + height);
4bb6408c 750
af0bb3b1
VZ
751
752}
753
7b65ea1a 754void wxWindowDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
4bb6408c 755{
af0bb3b1
VZ
756 wxCHECK_RET( Ok(), "invalid dc" );
757
2d120f83
JS
758 // Check for negative width and height
759 if (height < 0)
16c1f7f3 760 {
2d120f83
JS
761 y = y + height;
762 height = - height ;
16c1f7f3 763 }
af0bb3b1 764
2d120f83 765 if (width < 0)
16c1f7f3 766 {
2d120f83
JS
767 x = x + width;
768 width = - width ;
16c1f7f3 769 }
af0bb3b1 770
2d120f83 771 // FreeGetPixelCache();
af0bb3b1 772
2d120f83 773 static const int angle = 23040;
af0bb3b1 774
2d120f83 775 int xd, yd, wd, hd;
af0bb3b1 776
2d120f83
JS
777 xd = XLOG2DEV(x);
778 yd = YLOG2DEV(y);
779 wd = XLOG2DEVREL(width) ;
780 hd = YLOG2DEVREL(height) ;
af0bb3b1 781
2d120f83
JS
782 if (m_brush.Ok() && m_brush.GetStyle () != wxTRANSPARENT)
783 {
784 SetBrush (m_brush);
785 XFillArc ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd, yd, wd, hd, 0, angle);
786 if (m_window && m_window->GetBackingPixmap())
787 XFillArc ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
788 XLOG2DEV_2 (x), YLOG2DEV_2 (y),
789 XLOG2DEVREL (width) - WX_GC_CF,
790 YLOG2DEVREL (height) - WX_GC_CF, 0, angle);
791 }
af0bb3b1 792
2d120f83
JS
793 if (m_pen.Ok() && m_pen.GetStyle () != wxTRANSPARENT)
794 {
795 if (m_autoSetting)
796 SetPen (m_pen);
797 XDrawArc ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, xd, yd, wd, hd, 0, angle);
798 if (m_window && m_window->GetBackingPixmap())
799 XDrawArc ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
800 XLOG2DEV_2 (x), YLOG2DEV_2 (y),
801 XLOG2DEVREL (width) - WX_GC_CF,
802 YLOG2DEVREL (height) - WX_GC_CF, 0, angle);
803 }
804 CalcBoundingBox (x, y);
805 CalcBoundingBox (x + width, y + height);
4bb6408c 806
af0bb3b1 807}
16c1f7f3 808
af0bb3b1 809bool wxWindowDC::CanDrawBitmap() const
16c1f7f3 810{
af0bb3b1
VZ
811 wxCHECK_MSG( Ok(), FALSE, "invalid dc" );
812
813 return TRUE;
16c1f7f3
JS
814}
815
793f619f 816#if 0
7b65ea1a 817void wxWindowDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y)
af0bb3b1 818{
2d120f83 819 // FreeGetPixelCache();
af0bb3b1 820
2d120f83
JS
821 // Be sure that foreground pixels (1) of
822 // the Icon will be painted with pen colour. [m_pen.SetColour()]
823 // Background pixels (0) will be painted with
824 // last selected background color. [::SetBackground]
825 if (m_pen.Ok() && m_autoSetting)
826 SetPen (m_pen);
af0bb3b1 827
2d120f83 828 int width, height;
aae0472b 829 Pixmap iconPixmap = (Pixmap) icon.GetDrawable();
2d120f83
JS
830 width = icon.GetWidth();
831 height = icon.GetHeight();
832 if (icon.GetDisplay() == m_display)
16c1f7f3 833 {
2d120f83 834 if (icon.GetDepth() <= 1)
16c1f7f3 835 {
2d120f83
JS
836 XCopyPlane ((Display*) m_display, iconPixmap, (Pixmap) m_pixmap, (GC) m_gc,
837 0, 0, width, height,
838 (int) XLOG2DEV (x), (int) YLOG2DEV (y), 1);
16c1f7f3 839 }
2d120f83 840 else
16c1f7f3 841 {
2d120f83
JS
842 XCopyArea ((Display*) m_display, iconPixmap, (Pixmap) m_pixmap, (GC) m_gc,
843 0, 0, width, height,
844 (int) XLOG2DEV (x), (int) YLOG2DEV (y));
16c1f7f3 845 }
af0bb3b1
VZ
846
847
2d120f83 848 if (m_window && m_window->GetBackingPixmap())
16c1f7f3 849 {
2d120f83
JS
850 if (icon.GetDepth() <= 1)
851 {
852 XCopyPlane ((Display*) m_display, iconPixmap, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
853 0, 0, width, height, (int) XLOG2DEV_2 (x), (int) YLOG2DEV_2 (y), 1);
854 }
855 else
856 {
857 XCopyArea ((Display*) m_display, iconPixmap, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
858 0, 0, width, height,
859 (int) XLOG2DEV_2 (x), (int) YLOG2DEV_2 (y));
860 }
16c1f7f3 861 }
2d120f83
JS
862 } else { /* Remote copy (different (Display*) m_displays) */
863 XImage *cache = NULL;
864 if (m_window && m_window->GetBackingPixmap())
865 XCopyRemote((Display*) icon.GetDisplay(), (Display*) m_display, iconPixmap, (Pixmap) m_window->GetBackingPixmap(),
866 (GC) m_gcBacking, 0, 0, width, height,
867 (int) XLOG2DEV_2 (x), (int) YLOG2DEV_2 (y), TRUE, &cache);
868 XCopyRemote((Display*) icon.GetDisplay(), (Display*) m_display, iconPixmap, (Pixmap) m_pixmap, (GC) m_gc,
869 0, 0, width, height,
870 (int) XLOG2DEV (x), (int) YLOG2DEV (y), FALSE, &cache);
16c1f7f3 871 }
2d120f83 872 CalcBoundingBox (x, y);
af0bb3b1
VZ
873}
874#endif // 0
16c1f7f3 875
acbd13a3 876// TODO: use scaled Blit e.g. as per John Price's implementation in Contrib/Utilities
7b65ea1a 877bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
0cbff120
JS
878 wxDC *source, wxCoord xsrc, wxCoord ysrc, int rop, bool useMask,
879 wxCoord xsrcMask, wxCoord ysrcMask )
2d120f83 880{
af0bb3b1
VZ
881 wxCHECK_MSG( Ok(), FALSE, "invalid dc" );
882
883 wxWindowDC* sourceDC = wxDynamicCast(source, wxWindowDC);
884
885 wxASSERT_MSG( sourceDC, "Blit source DC must be wxWindowDC or derived class." );
886
2d120f83 887 // FreeGetPixelCache();
af0bb3b1 888
395539f9
MB
889 // Be sure that foreground pixels (1) of the Icon will be painted with
890 // foreground colour. [m_textForegroundColour] Background pixels (0)
891 // will be painted with backgound colour (m_textBackgroundColour)
892 // Using ::SetPen is horribly slow, so avoid doing it
893 int oldBackgroundPixel = -1;
894 int oldForegroundPixel = -1;
895
896 if (m_textBackgroundColour.Ok())
897 {
898 oldBackgroundPixel = m_backgroundPixel;
899 int pixel = m_textBackgroundColour.AllocColour(m_display);
900
901 XSetBackground ((Display*) m_display, (GC) m_gc, pixel);
902 if (m_window && m_window->GetBackingPixmap())
903 XSetBackground ((Display*) m_display,(GC) m_gcBacking,
904 pixel);
905 }
906 if (m_textForegroundColour.Ok())
907 {
908 oldForegroundPixel = m_currentColour.GetPixel();
909
910 if( m_textForegroundColour.GetPixel() <= -1 )
911 CalculatePixel( m_textForegroundColour,
912 m_textForegroundColour, TRUE);
913
914 int pixel = m_textForegroundColour.GetPixel();
915 if (pixel > -1)
916 SetForegroundPixelWithLogicalFunction(pixel);
917 }
a91b47e8
JS
918
919 // Do bitmap scaling if necessary
920
921 wxBitmap *scaledBitmap = (wxBitmap*) NULL;
922 Pixmap sourcePixmap = (Pixmap) NULL;
923 double scaleX, scaleY;
924 GetUserScale(& scaleX, & scaleY);
395539f9 925 bool retVal = FALSE;
a91b47e8 926
0cbff120
JS
927 /* TODO: use the mask origin when drawing transparently */
928 if (xsrcMask == -1 && ysrcMask == -1)
929 {
930 xsrcMask = xsrc; ysrcMask = ysrc;
931 }
932
a91b47e8
JS
933 // Sorry, can't scale masks just yet
934 if (!useMask && (scaleX != 1.0 || scaleY != 1.0) && sourceDC->IsKindOf(CLASSINFO(wxMemoryDC)))
935 {
936 wxMemoryDC* memDC = (wxMemoryDC*) sourceDC;
937 wxBitmap& bitmap = memDC->GetBitmap();
938
939 wxASSERT_MSG( (bitmap.Ok()), "Bad source bitmap in wxWindowDC::Blit");
940
79f1dd05 941 wxImage image = bitmap.ConvertToImage();
a91b47e8
JS
942 if (!image.Ok())
943 {
aae0472b 944 sourcePixmap = (Pixmap) bitmap.GetDrawable();
a91b47e8
JS
945 }
946 else
947 {
948 int scaledW = (int) (bitmap.GetWidth() * scaleX);
949 int scaledH = (int) (bitmap.GetHeight() * scaleY);
af0bb3b1 950
a91b47e8 951 image = image.Scale(scaledW, scaledH);
79f1dd05 952 scaledBitmap = new wxBitmap(image);
aae0472b 953 sourcePixmap = (Pixmap) scaledBitmap->GetDrawable();
af0bb3b1 954 }
a91b47e8
JS
955 }
956 else
957 sourcePixmap = (Pixmap) sourceDC->m_pixmap;
958
959 if (m_pixmap && sourcePixmap)
2d120f83
JS
960 {
961 /* MATTHEW: [9] */
962 int orig = m_logicalFunction;
af0bb3b1 963
2d120f83 964 SetLogicalFunction (rop);
af0bb3b1 965
2d120f83
JS
966 if (m_display != sourceDC->m_display)
967 {
968 XImage *cache = NULL;
af0bb3b1 969
2d120f83
JS
970 if (m_window && m_window->GetBackingPixmap())
971 XCopyRemote((Display*) sourceDC->m_display, (Display*) m_display,
a91b47e8 972 (Pixmap) sourcePixmap, (Pixmap) m_window->GetBackingPixmap(),
2d120f83
JS
973 (GC) m_gcBacking,
974 source->LogicalToDeviceX (xsrc),
975 source->LogicalToDeviceY (ysrc),
976 source->LogicalToDeviceXRel(width),
977 source->LogicalToDeviceYRel(height),
978 XLOG2DEV_2 (xdest), YLOG2DEV_2 (ydest),
979 TRUE, &cache);
af0bb3b1 980
2d120f83
JS
981 if ( useMask && source->IsKindOf(CLASSINFO(wxMemoryDC)) )
982 {
983 wxMemoryDC *memDC = (wxMemoryDC *)source;
984 wxBitmap& sel = memDC->GetBitmap();
aae0472b 985 if ( sel.Ok() && sel.GetMask() && sel.GetMask()->GetBitmap() )
2d120f83 986 {
aae0472b 987 XSetClipMask ((Display*) m_display, (GC) m_gc, (Pixmap) sel.GetMask()->GetBitmap());
2d120f83
JS
988 XSetClipOrigin ((Display*) m_display, (GC) m_gc, XLOG2DEV (xdest), YLOG2DEV (ydest));
989 }
990 }
af0bb3b1 991
a91b47e8 992 XCopyRemote((Display*) sourceDC->m_display, (Display*) m_display, (Pixmap) sourcePixmap, (Pixmap) m_pixmap, (GC) m_gc,
2d120f83
JS
993 source->LogicalToDeviceX (xsrc),
994 source->LogicalToDeviceY (ysrc),
995 source->LogicalToDeviceXRel(width),
996 source->LogicalToDeviceYRel(height),
997 XLOG2DEV (xdest), YLOG2DEV (ydest),
998 FALSE, &cache);
af0bb3b1 999
2d120f83
JS
1000 if ( useMask )
1001 {
1002 XSetClipMask ((Display*) m_display, (GC) m_gc, None);
1003 XSetClipOrigin ((Display*) m_display, (GC) m_gc, 0, 0);
1004 }
af0bb3b1 1005
2d120f83 1006 } else
395539f9
MB
1007 { //XGCValues values;
1008 //XGetGCValues((Display*)m_display, (GC)m_gc, GCForeground, &values);
1009
2d120f83
JS
1010 if (m_window && m_window->GetBackingPixmap())
1011 {
1012 // +++ MARKUS (mho@comnets.rwth-aachen): error on blitting bitmaps with depth 1
1013 if (source->IsKindOf(CLASSINFO(wxMemoryDC)) && ((wxMemoryDC*) source)->GetBitmap().GetDepth() == 1)
1014 {
a91b47e8 1015 XCopyPlane ((Display*) m_display, (Pixmap) sourcePixmap, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
2d120f83
JS
1016 source->LogicalToDeviceX (xsrc),
1017 source->LogicalToDeviceY (ysrc),
1018 source->LogicalToDeviceXRel(width),
1019 source->LogicalToDeviceYRel(height),
1020 XLOG2DEV_2 (xdest), YLOG2DEV_2 (ydest), 1);
1021 }
1022 else
1023 {
a91b47e8 1024 XCopyArea ((Display*) m_display, (Pixmap) sourcePixmap, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
2d120f83
JS
1025 source->LogicalToDeviceX (xsrc),
1026 source->LogicalToDeviceY (ysrc),
1027 source->LogicalToDeviceXRel(width),
1028 source->LogicalToDeviceYRel(height),
1029 XLOG2DEV_2 (xdest), YLOG2DEV_2 (ydest));
1030 }
1031 }
1032 if ( useMask && source->IsKindOf(CLASSINFO(wxMemoryDC)) )
1033 {
1034 wxMemoryDC *memDC = (wxMemoryDC *)source;
1035 wxBitmap& sel = memDC->GetBitmap();
aae0472b 1036 if ( sel.Ok() && sel.GetMask() && sel.GetMask()->GetBitmap() )
2d120f83 1037 {
aae0472b 1038 XSetClipMask ((Display*) m_display, (GC) m_gc, (Pixmap) sel.GetMask()->GetBitmap());
2d120f83
JS
1039 XSetClipOrigin ((Display*) m_display, (GC) m_gc, XLOG2DEV (xdest), YLOG2DEV (ydest));
1040 }
1041 }
af0bb3b1 1042
2d120f83
JS
1043 // Check if we're copying from a mono bitmap
1044 if (source->IsKindOf(CLASSINFO(wxMemoryDC)) &&
1045 ((wxMemoryDC*)source)->GetBitmap().Ok() && (((wxMemoryDC*)source)->GetBitmap().GetDepth () == 1))
1046 {
a91b47e8 1047 XCopyPlane ((Display*) m_display, (Pixmap) sourcePixmap, (Pixmap) m_pixmap, (GC) m_gc,
2d120f83
JS
1048 source->LogicalToDeviceX (xsrc),
1049 source->LogicalToDeviceY (ysrc),
1050 source->LogicalToDeviceXRel(width),
1051 source->LogicalToDeviceYRel(height),
1052 XLOG2DEV (xdest), YLOG2DEV (ydest), 1);
1053 }
1054 else
1055 {
a91b47e8 1056 XCopyArea ((Display*) m_display, (Pixmap) sourcePixmap, (Pixmap) m_pixmap, (GC) m_gc,
2d120f83
JS
1057 source->LogicalToDeviceX (xsrc),
1058 source->LogicalToDeviceY (ysrc),
1059 source->LogicalToDeviceXRel(width),
1060 source->LogicalToDeviceYRel(height),
1061 XLOG2DEV (xdest), YLOG2DEV (ydest));
af0bb3b1 1062
2d120f83
JS
1063 }
1064 if ( useMask )
1065 {
1066 XSetClipMask ((Display*) m_display, (GC) m_gc, None);
1067 XSetClipOrigin ((Display*) m_display, (GC) m_gc, 0, 0);
1068 }
af0bb3b1 1069
2d120f83
JS
1070 } /* Remote/local (Display*) m_display */
1071 CalcBoundingBox (xdest, ydest);
1072 CalcBoundingBox (xdest + width, ydest + height);
af0bb3b1 1073
2d120f83 1074 SetLogicalFunction(orig);
a91b47e8 1075
395539f9 1076 retVal = TRUE;
16c1f7f3 1077 }
a91b47e8
JS
1078 if (scaledBitmap) delete scaledBitmap;
1079
395539f9
MB
1080 if (oldBackgroundPixel > -1)
1081 {
1082 XSetBackground ((Display*) m_display, (GC) m_gc, oldBackgroundPixel);
1083 if (m_window && m_window->GetBackingPixmap())
1084 XSetBackground ((Display*) m_display,(GC) m_gcBacking,
1085 oldBackgroundPixel);
1086 }
1087 if (oldForegroundPixel > -1)
1088 {
1089 XSetForeground ((Display*) m_display, (GC) m_gc, oldForegroundPixel);
1090 if (m_window && m_window->GetBackingPixmap())
1091 XSetForeground ((Display*) m_display,(GC) m_gcBacking,
1092 oldForegroundPixel);
1093 }
1094
1095 return retVal;
16c1f7f3
JS
1096}
1097
7b65ea1a 1098void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y )
4bb6408c 1099{
af0bb3b1
VZ
1100 wxCHECK_RET( Ok(), "invalid dc" );
1101
1102 // Since X draws from the baseline of the text, must add the text height
2d120f83
JS
1103 int cx = 0;
1104 int cy = 0;
1105 int ascent = 0;
1106 int slen;
af0bb3b1 1107
2b830c41
MB
1108 // Set FillStyle, otherwise X will use current stipple!
1109 XGCValues gcV, gcBackingV;
1110
1111 XGetGCValues ((Display*) m_display, (GC)m_gc, GCFillStyle, &gcV);
1112 XSetFillStyle ((Display*) m_display, (GC) m_gc, FillSolid);
1113 if (m_window && m_window->GetBackingPixmap())
1114 {
1115 XGetGCValues ((Display*) m_display, (GC)m_gcBacking, GCFillStyle,
1116 &gcBackingV );
1117 XSetFillStyle ((Display*) m_display, (GC) m_gcBacking, FillSolid);
1118 }
1119
af0bb3b1
VZ
1120 slen = strlen(text);
1121
2d120f83 1122 if (m_font.Ok())
16c1f7f3 1123 {
2d120f83
JS
1124 WXFontStructPtr pFontStruct = m_font.GetFontStruct(m_userScaleY*m_logicalScaleY, m_display);
1125 int direction, descent;
1126 XCharStruct overall_return;
af0bb3b1 1127#if 0
2d120f83
JS
1128 if (use16)
1129 (void)XTextExtents16((XFontStruct*) pFontStruct, (XChar2b *)(const char*) text, slen, &direction,
1130 &ascent, &descent, &overall_return);
1131 else
af0bb3b1 1132#endif // 0
d3a80c92
MB
1133 (void)XTextExtents((XFontStruct*) pFontStruct,
1134 wxConstCast(text.c_str(), char),
1135 slen, &direction,
af0bb3b1
VZ
1136 &ascent, &descent, &overall_return);
1137
2d120f83
JS
1138 cx = overall_return.width;
1139 cy = ascent + descent;
16c1f7f3 1140 }
af0bb3b1
VZ
1141
1142 // First draw a rectangle representing the text background, if a text
1143 // background is specified
2d120f83 1144 if (m_textBackgroundColour.Ok () && (m_backgroundMode != wxTRANSPARENT))
16c1f7f3 1145 {
2d120f83 1146 wxColour oldPenColour = m_currentColour;
16c1f7f3 1147 m_currentColour = m_textBackgroundColour;
2d120f83
JS
1148 bool sameColour = (oldPenColour.Ok () && m_textBackgroundColour.Ok () &&
1149 (oldPenColour.Red () == m_textBackgroundColour.Red ()) &&
1150 (oldPenColour.Blue () == m_textBackgroundColour.Blue ()) &&
1151 (oldPenColour.Green () == m_textBackgroundColour.Green ()));
af0bb3b1 1152
2d120f83
JS
1153 // This separation of the big && test required for gcc2.7/HP UX 9.02
1154 // or pixel value can be corrupted!
1155 sameColour = (sameColour &&
1156 (oldPenColour.GetPixel() == m_textBackgroundColour.GetPixel()));
af0bb3b1 1157
2d120f83 1158 if (!sameColour || !GetOptimization())
16c1f7f3 1159 {
2d120f83
JS
1160 int pixel = m_textBackgroundColour.AllocColour(m_display);
1161 m_currentColour = m_textBackgroundColour;
af0bb3b1 1162
2d120f83
JS
1163 // Set the GC to the required colour
1164 if (pixel > -1)
1165 {
1166 XSetForeground ((Display*) m_display, (GC) m_gc, pixel);
1167 if (m_window && m_window->GetBackingPixmap())
1168 XSetForeground ((Display*) m_display,(GC) m_gcBacking, pixel);
1169 }
16c1f7f3 1170 }
2d120f83
JS
1171 else
1172 m_textBackgroundColour = oldPenColour ;
af0bb3b1 1173
2d120f83
JS
1174 XFillRectangle ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, XLOG2DEV (x), YLOG2DEV (y), cx, cy);
1175 if (m_window && m_window->GetBackingPixmap())
1176 XFillRectangle ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking,
16c1f7f3
JS
1177 XLOG2DEV_2 (x), YLOG2DEV_2 (y), cx, cy);
1178 }
af0bb3b1 1179
2d120f83
JS
1180 // Now set the text foreground and draw the text
1181 if (m_textForegroundColour.Ok ())
1182 {
1183 wxColour oldPenColour = m_currentColour;
1184 m_currentColour = m_textForegroundColour;
1185 bool sameColour = (oldPenColour.Ok () && m_currentColour.Ok () &&
1186 (oldPenColour.Red () == m_currentColour.Red ()) &&
1187 (oldPenColour.Blue () == m_currentColour.Blue ()) &&
1188 (oldPenColour.Green () == m_currentColour.Green ()) &&
1189 (oldPenColour.GetPixel() == m_currentColour.GetPixel()));
af0bb3b1 1190
2d120f83 1191 if (!sameColour || !GetOptimization())
16c1f7f3 1192 {
395539f9
MB
1193 int pixel = CalculatePixel(m_textForegroundColour,
1194 m_currentColour, FALSE);
af0bb3b1 1195
2d120f83
JS
1196 // Set the GC to the required colour
1197 if (pixel > -1)
1198 {
1199 XSetForeground ((Display*) m_display, (GC) m_gc, pixel);
1200 if (m_window && m_window->GetBackingPixmap())
1201 XSetForeground ((Display*) m_display,(GC) m_gcBacking, pixel);
1202 }
16c1f7f3
JS
1203 }
1204 else
2d120f83
JS
1205 m_textForegroundColour = oldPenColour;
1206 }
af0bb3b1
VZ
1207
1208 // We need to add the ascent, not the whole height, since X draws at the
1209 // point above the descender.
1210#if 0
16c1f7f3 1211 if (use16)
af0bb3b1 1212 XDrawString16((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, XLOG2DEV (x), YLOG2DEV (y) + ascent,
2d120f83
JS
1213 (XChar2b *)(char*) (const char*) text, slen);
1214 else
af0bb3b1
VZ
1215#endif // 0
1216 XDrawString((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, XLOG2DEV (x), YLOG2DEV (y) + ascent, text, slen);
1217
2d120f83 1218 if (m_window && m_window->GetBackingPixmap()) {
af0bb3b1 1219#if 0
2d120f83
JS
1220 if (use16)
1221 XDrawString16((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(), (GC) m_gcBacking,
16c1f7f3
JS
1222 XLOG2DEV_2 (x), YLOG2DEV_2 (y) + ascent,
1223 (XChar2b *)(char*) (const char*) text, slen);
2d120f83 1224 else
af0bb3b1 1225#endif // 0
2d120f83 1226 XDrawString((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(), (GC) m_gcBacking,
d3a80c92
MB
1227 XLOG2DEV_2 (x), YLOG2DEV_2 (y) + ascent,
1228 wxConstCast(text.c_str(), char), slen);
2d120f83 1229 }
af0bb3b1 1230
2b830c41
MB
1231 // restore fill style
1232 XSetFillStyle ((Display*) m_display, (GC) m_gc, gcV.fill_style);
1233 if (m_window && m_window->GetBackingPixmap())
1234 XSetFillStyle ((Display*) m_display, (GC) m_gcBacking,
1235 gcBackingV.fill_style);
1236
7b65ea1a 1237 wxCoord w, h;
2d120f83
JS
1238 GetTextExtent (text, &w, &h);
1239 CalcBoundingBox (x + w, y + h);
1240 CalcBoundingBox (x, y);
af0bb3b1 1241}
4bb6408c 1242
729be74d
MB
1243void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y,
1244 double angle )
95724b1a
VZ
1245{
1246 if (angle == 0.0)
1247 {
1248 DrawText(text, x, y);
1249 return;
1250 }
1251
1252 wxCHECK_RET( Ok(), "invalid dc" );
1253
729be74d
MB
1254 int oldBackgroundPixel = -1;
1255 int oldForegroundPixel = -1;
1256 int foregroundPixel = -1;
1257 int backgroundPixel = -1;
1258
1259 if (m_textBackgroundColour.Ok())
1260 {
1261 oldBackgroundPixel = m_backgroundPixel;
1262 backgroundPixel = m_textBackgroundColour.AllocColour(m_display);
1263 }
1264 if (m_textForegroundColour.Ok())
1265 {
1266 oldForegroundPixel = m_currentColour.GetPixel();
1267
1268 if( m_textForegroundColour.GetPixel() <= -1 )
1269 CalculatePixel( m_textForegroundColour,
1270 m_textForegroundColour, TRUE);
1271
1272 foregroundPixel = m_textForegroundColour.GetPixel();
1273 }
1274
95724b1a
VZ
1275 // Since X draws from the baseline of the text, must add the text height
1276 int cx = 0;
1277 int cy = 0;
1278 int ascent = 0;
729be74d 1279 int slen = text.length();
95724b1a
VZ
1280
1281 if (m_font.Ok())
1282 {
1283 // Calculate text extent.
729be74d
MB
1284 WXFontStructPtr pFontStruct =
1285 m_font.GetFontStruct(m_userScaleY*m_logicalScaleY, m_display);
95724b1a
VZ
1286 int direction, descent;
1287 XCharStruct overall_return;
1288#if 0
1289 if (use16)
729be74d
MB
1290 (void)XTextExtents16((XFontStruct*) pFontStruct,
1291 (XChar2b *)(const char*) text,
1292 slen, &direction,
95724b1a
VZ
1293 &ascent, &descent, &overall_return);
1294 else
1295#endif // 0
729be74d 1296 (void)XTextExtents((XFontStruct*) pFontStruct,
d3a80c92
MB
1297 wxConstCast(text.c_str(), char),
1298 slen, &direction,
95724b1a
VZ
1299 &ascent, &descent, &overall_return);
1300
1301 cx = overall_return.width;
1302 cy = ascent + descent;
1303 }
1304
1305 wxBitmap src(cx, cy);
1306 wxMemoryDC dc;
1307 dc.SelectObject(src);
1308 dc.SetFont(GetFont());
1309 dc.SetBackground(*wxWHITE_BRUSH);
1310 dc.SetBrush(*wxBLACK_BRUSH);
1311 dc.Clear();
1312 dc.DrawText(text, 0, 0);
1313 dc.SetFont(wxNullFont);
1314
1315 // Calculate the size of the rotated bounding box.
1316 double dx = cos(angle / 180.0 * M_PI);
1317 double dy = sin(angle / 180.0 * M_PI);
729be74d 1318 double x4 = cy * dy;
95724b1a
VZ
1319 double y4 = cy * dx;
1320 double x3 = cx * dx;
729be74d 1321 double y3 = -cx * dy;
95724b1a
VZ
1322 double x2 = x3 + x4;
1323 double y2 = y3 + y4;
1324 double x1 = x;
1325 double y1 = y;
1326
1327 // Create image from the source bitmap after writing the text into it.
79f1dd05 1328 wxImage image = src.ConvertToImage();
95724b1a
VZ
1329
1330 int minx = roundmin(0, roundmin(x4, roundmin(x2, x3)));
1331 int miny = roundmin(0, roundmin(y4, roundmin(y2, y3)));
1332 int maxx = roundmax(0, roundmax(x4, roundmax(x2, x3)));
1333 int maxy = roundmax(0, roundmax(y4, roundmax(y2, y3)));
1334
729be74d
MB
1335 bool lastFore = false, lastBack = false;
1336
95724b1a
VZ
1337 // This rotates counterclockwise around the top left corner.
1338 for (int rx = minx; rx < maxx; rx++)
1339 {
1340 for (int ry = miny; ry < maxy; ry++)
1341 {
1342 // transform dest coords to source coords
729be74d
MB
1343 int sx = (int) (rx * dx - ry * dy + 0.5);
1344 int sy = - (int) (-ry * dx - rx * dy + 0.5);
95724b1a
VZ
1345 if (sx >= 0 && sx < cx && sy >= 0 && sy < cy)
1346 {
729be74d
MB
1347 bool textPixel = image.GetRed(sx, sy) == 0;
1348
1349 if (!textPixel && m_backgroundMode != wxSOLID)
1350 continue;
1351
1352 wxCoord ox = (wxCoord) (x1 + rx),
1353 oy = (wxCoord) (y1 + ry);
95724b1a 1354 // draw black pixels, ignore white ones (i.e. transparent b/g)
729be74d 1355 if (textPixel && !lastFore)
95724b1a 1356 {
729be74d
MB
1357 XSetForeground ((Display*) m_display, (GC) m_gc,
1358 foregroundPixel);
1359 lastFore = true;
1360 lastBack = false;
95724b1a 1361 }
729be74d 1362 else if (!textPixel && !lastBack)
95724b1a 1363 {
729be74d
MB
1364 XSetForeground ((Display*) m_display, (GC) m_gc,
1365 backgroundPixel);
1366 lastFore = false;
1367 lastBack = true;
95724b1a 1368 }
95724b1a 1369
729be74d
MB
1370 XDrawPoint ((Display*) m_display, (Pixmap) m_pixmap,
1371 (GC) m_gc, XLOG2DEV (ox), YLOG2DEV (oy));
95724b1a 1372 if (m_window && m_window->GetBackingPixmap())
729be74d
MB
1373 XDrawPoint ((Display*) m_display,
1374 (Pixmap) m_window->GetBackingPixmap(),
1375 (GC) m_gcBacking,
1376 XLOG2DEV_2 (ox), YLOG2DEV_2 (oy));
95724b1a
VZ
1377 }
1378 }
729be74d 1379 }
95724b1a 1380
729be74d
MB
1381 if (oldBackgroundPixel > -1)
1382 {
1383 XSetBackground ((Display*) m_display, (GC) m_gc, oldBackgroundPixel);
95724b1a 1384 if (m_window && m_window->GetBackingPixmap())
729be74d
MB
1385 XSetBackground ((Display*) m_display,(GC) m_gcBacking,
1386 oldBackgroundPixel);
1387 }
1388 if (oldForegroundPixel > -1)
1389 {
1390 XSetForeground ((Display*) m_display, (GC) m_gc, oldForegroundPixel);
1391 if (m_window && m_window->GetBackingPixmap())
1392 XSetForeground ((Display*) m_display,(GC) m_gcBacking,
1393 oldForegroundPixel);
95724b1a 1394 }
95724b1a 1395
729be74d
MB
1396 CalcBoundingBox (minx, miny);
1397 CalcBoundingBox (maxx, maxy);
95724b1a
VZ
1398}
1399
af0bb3b1 1400bool wxWindowDC::CanGetTextExtent() const
4bb6408c 1401{
2d120f83 1402 return TRUE;
af0bb3b1 1403}
4bb6408c 1404
7b65ea1a
MB
1405void wxWindowDC::DoGetTextExtent( const wxString &string, wxCoord *width, wxCoord *height,
1406 wxCoord *descent, wxCoord *externalLeading,
af0bb3b1 1407 wxFont *font ) const
4bb6408c 1408{
af0bb3b1
VZ
1409 wxCHECK_RET( Ok(), "invalid dc" );
1410
2d120f83
JS
1411 wxFont* theFont = font;
1412 if (!theFont)
af0bb3b1
VZ
1413 theFont = (wxFont *)&m_font; // const_cast
1414
2d120f83
JS
1415 if (!theFont->Ok())
1416 {
1417 // TODO: this should be an error log function
1418 wxFAIL_MSG("set a valid font before calling GetTextExtent!");
af0bb3b1 1419
33caefb3
RR
1420 if (width) *width = -1;
1421 if (height) *height = -1;
2d120f83
JS
1422 return;
1423 }
af0bb3b1 1424
2d120f83 1425 WXFontStructPtr pFontStruct = theFont->GetFontStruct(m_userScaleY*m_logicalScaleY, m_display);
af0bb3b1 1426
2d120f83
JS
1427 int direction, ascent, descent2;
1428 XCharStruct overall;
1429 int slen;
af0bb3b1
VZ
1430
1431#if 0
1432 if (use16)
1433 slen = str16len(string);
1434 else
1435#endif // 0
1436 slen = strlen(string);
1437
1438#if 0
2d120f83
JS
1439 if (use16)
1440 XTextExtents16((XFontStruct*) pFontStruct, (XChar2b *) (char*) (const char*) string, slen, &direction,
1441 &ascent, &descent2, &overall);
1442 else
af0bb3b1 1443#endif // 0
d3a80c92
MB
1444 XTextExtents((XFontStruct*) pFontStruct,
1445 wxConstCast(string.c_str(), char), slen, &direction,
2d120f83 1446 &ascent, &descent2, &overall);
af0bb3b1 1447
33caefb3
RR
1448 if (width) *width = XDEV2LOGREL (overall.width);
1449 if (height) *height = YDEV2LOGREL (ascent + descent2);
2d120f83
JS
1450 if (descent)
1451 *descent = descent2;
1452 if (externalLeading)
1453 *externalLeading = 0;
af0bb3b1 1454}
4bb6408c 1455
7b65ea1a 1456wxCoord wxWindowDC::GetCharWidth() const
4bb6408c 1457{
af0bb3b1
VZ
1458 wxCHECK_MSG( Ok(), 0, "invalid dc" );
1459 wxCHECK_MSG( m_font.Ok(), 0, "invalid font" );
1460
2d120f83 1461 WXFontStructPtr pFontStruct = m_font.GetFontStruct(m_userScaleY * m_logicalScaleY, m_display);
af0bb3b1 1462
2d120f83
JS
1463 int direction, ascent, descent;
1464 XCharStruct overall;
1465 XTextExtents ((XFontStruct*) pFontStruct, "x", 1, &direction, &ascent,
16c1f7f3 1466 &descent, &overall);
2d120f83 1467 return XDEV2LOGREL(overall.width);
af0bb3b1 1468}
4bb6408c 1469
7b65ea1a 1470wxCoord wxWindowDC::GetCharHeight() const
4bb6408c 1471{
af0bb3b1
VZ
1472 wxCHECK_MSG( Ok(), 0, "invalid dc" );
1473 wxCHECK_MSG( m_font.Ok(), 0, "invalid font" );
1474
2d120f83 1475 WXFontStructPtr pFontStruct = m_font.GetFontStruct(m_userScaleY*m_logicalScaleY, m_display);
af0bb3b1 1476
2d120f83
JS
1477 int direction, ascent, descent;
1478 XCharStruct overall;
1479 XTextExtents ((XFontStruct*) pFontStruct, "x", 1, &direction, &ascent,
16c1f7f3 1480 &descent, &overall);
2d120f83
JS
1481 // return XDEV2LOGREL(overall.ascent + overall.descent);
1482 return XDEV2LOGREL(ascent + descent);
af0bb3b1 1483}
4bb6408c 1484
af0bb3b1 1485void wxWindowDC::Clear()
4bb6408c 1486{
af0bb3b1
VZ
1487 wxCHECK_RET( Ok(), "invalid dc" );
1488
2d120f83
JS
1489 int w, h;
1490 if (m_window)
16c1f7f3 1491 {
2d120f83 1492 m_window->GetSize(&w, &h);
af0bb3b1 1493
2d120f83
JS
1494 if (m_window && m_window->GetBackingPixmap())
1495 {
1496 w = m_window->GetPixmapWidth();
1497 h = m_window->GetPixmapHeight();
1498 }
16c1f7f3 1499 }
2d120f83 1500 else
16c1f7f3
JS
1501 {
1502 if (this->IsKindOf(CLASSINFO(wxMemoryDC)))
1503 {
2d120f83
JS
1504 wxMemoryDC* memDC = (wxMemoryDC*) this;
1505 w = memDC->GetBitmap().GetWidth();
1506 h = memDC->GetBitmap().GetHeight();
1507 }
16c1f7f3 1508 else
2d120f83 1509 return;
16c1f7f3 1510 }
af0bb3b1 1511
2d120f83
JS
1512 wxBrush saveBrush = m_brush;
1513 SetBrush (m_backgroundBrush);
af0bb3b1 1514
2d120f83 1515 XFillRectangle ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, 0, 0, w, h);
af0bb3b1 1516
2d120f83
JS
1517 if (m_window && m_window->GetBackingPixmap())
1518 XFillRectangle ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking, 0, 0, w, h);
af0bb3b1 1519
2d120f83 1520 m_brush = saveBrush;
af0bb3b1 1521}
4bb6408c 1522
a367b9b3
JS
1523void wxWindowDC::Clear(const wxRect& rect)
1524{
af0bb3b1
VZ
1525 wxCHECK_RET( Ok(), "invalid dc" );
1526
2d120f83
JS
1527 int x = rect.x; int y = rect.y;
1528 int w = rect.width; int h = rect.height;
af0bb3b1 1529
2d120f83
JS
1530 wxBrush saveBrush = m_brush;
1531 SetBrush (m_backgroundBrush);
af0bb3b1 1532
2d120f83 1533 XFillRectangle ((Display*) m_display, (Pixmap) m_pixmap, (GC) m_gc, x, y, w, h);
af0bb3b1 1534
2d120f83
JS
1535 if (m_window && m_window->GetBackingPixmap())
1536 XFillRectangle ((Display*) m_display, (Pixmap) m_window->GetBackingPixmap(),(GC) m_gcBacking, x, y, w, h);
af0bb3b1 1537
2d120f83 1538 m_brush = saveBrush;
af0bb3b1 1539}
a367b9b3 1540
dfc54541 1541void wxWindowDC::SetFont( const wxFont &font )
4bb6408c 1542{
af0bb3b1
VZ
1543 wxCHECK_RET( Ok(), "invalid dc" );
1544
2d120f83 1545 m_font = font;
af0bb3b1 1546
2d120f83 1547 if (!m_font.Ok())
e97f20a0 1548 {
7b65ea1a 1549 if ((m_oldFont != (WXFont) 0) && ((wxCoord) m_oldFont != -1))
2d120f83
JS
1550 {
1551 XSetFont ((Display*) m_display, (GC) m_gc, (Font) m_oldFont);
af0bb3b1 1552
2d120f83
JS
1553 if (m_window && m_window->GetBackingPixmap())
1554 XSetFont ((Display*) m_display,(GC) m_gcBacking, (Font) m_oldFont);
1555 }
1556 return;
e97f20a0 1557 }
af0bb3b1 1558
2d120f83 1559 WXFontStructPtr pFontStruct = m_font.GetFontStruct(m_userScaleY*m_logicalScaleY, m_display);
af0bb3b1 1560
2d120f83
JS
1561 Font fontId = ((XFontStruct*)pFontStruct)->fid;
1562 XSetFont ((Display*) m_display, (GC) m_gc, fontId);
af0bb3b1 1563
2d120f83
JS
1564 if (m_window && m_window->GetBackingPixmap())
1565 XSetFont ((Display*) m_display,(GC) m_gcBacking, fontId);
af0bb3b1 1566}
4bb6408c 1567
395539f9
MB
1568void wxWindowDC::SetForegroundPixelWithLogicalFunction(int pixel)
1569{
1570 if (m_logicalFunction == wxXOR)
1571 {
1572 XGCValues values;
1573 XGetGCValues ((Display*) m_display, (GC) m_gc, GCBackground, &values);
1574 XSetForeground ((Display*) m_display, (GC) m_gc,
1575 pixel ^ values.background);
1576 if (m_window && m_window->GetBackingPixmap())
1577 XSetForeground ((Display*) m_display,(GC) m_gcBacking,
1578 pixel ^ values.background);
1579 }
1580 else
1581 {
1582 XSetForeground ((Display*) m_display, (GC) m_gc, pixel);
1583 if (m_window && m_window->GetBackingPixmap())
1584 XSetForeground ((Display*) m_display,(GC) m_gcBacking, pixel);
1585 }
1586}
1587
1588int wxWindowDC::CalculatePixel(wxColour& colour, wxColour& curCol,
1589 bool roundToWhite) const
1590{
1591 const unsigned char wp = (unsigned char)255;
1592
1593 int pixel = -1;
1594 if(!m_colour) // Mono display
1595 {
1596 unsigned char red = colour.Red ();
1597 unsigned char blue = colour.Blue ();
1598 unsigned char green = colour.Green ();
1599 // white
1600 if((red == wp && blue == wp && green == wp) ||
1601 // not black and roundToWhite was specified
1602 ((red != 0 || blue != 0 || green != 0) && roundToWhite))
1603 {
1604 curCol = *wxWHITE;
1605 pixel = (int)WhitePixel((Display*) m_display,
1606 DefaultScreen((Display*) m_display));
1607 curCol.SetPixel(pixel);
1608 colour.SetPixel(pixel);
1609 }
1610 else
1611 {
1612 curCol = *wxBLACK;
1613 pixel = (int)BlackPixel((Display*) m_display,
1614 DefaultScreen((Display*) m_display));
1615 curCol.SetPixel(pixel);
1616 colour.SetPixel(pixel);
1617 }
1618 }
1619 else
1620 {
1621 curCol = colour;
1622 pixel = colour.AllocColour((Display*) m_display);
1623 curCol.SetPixel(pixel);
1624 }
1625
1626 return pixel;
1627}
1628
dfc54541 1629void wxWindowDC::SetPen( const wxPen &pen )
4bb6408c 1630{
af0bb3b1
VZ
1631 wxCHECK_RET( Ok(), "invalid dc" );
1632
2d120f83
JS
1633 m_pen = pen;
1634 if (!m_pen.Ok())
1635 return;
af0bb3b1 1636
2d120f83
JS
1637 wxBitmap oldStipple = m_currentStipple;
1638 int oldStyle = m_currentStyle;
1639 int oldFill = m_currentFill;
1640 int old_pen_width = m_currentPenWidth;
1641 int old_pen_join = m_currentPenJoin;
1642 int old_pen_cap = m_currentPenCap;
1643 int old_pen_nb_dash = m_currentPenDashCount;
69c44812 1644 wxX11Dash *old_pen_dash = m_currentPenDash;
af0bb3b1 1645
2d120f83
JS
1646 wxColour oldPenColour = m_currentColour;
1647 m_currentColour = m_pen.GetColour ();
1648 m_currentStyle = m_pen.GetStyle ();
1649 m_currentFill = m_pen.GetStyle (); // TODO?
1650 m_currentPenWidth = m_pen.GetWidth ();
1651 m_currentPenJoin = m_pen.GetJoin ();
1652 m_currentPenCap = m_pen.GetCap ();
1653 m_currentPenDashCount = m_pen.GetDashCount();
69c44812 1654 m_currentPenDash = (wxX11Dash*)m_pen.GetDash();
af0bb3b1 1655
2d120f83
JS
1656 if (m_currentStyle == wxSTIPPLE)
1657 m_currentStipple = * m_pen.GetStipple ();
af0bb3b1 1658
2d120f83
JS
1659 bool sameStyle = (oldStyle == m_currentStyle &&
1660 oldFill == m_currentFill &&
1661 old_pen_join == m_currentPenJoin &&
1662 old_pen_cap == m_currentPenCap &&
1663 old_pen_nb_dash == m_currentPenDashCount &&
1664 old_pen_dash == m_currentPenDash &&
1665 old_pen_width == m_currentPenWidth);
af0bb3b1 1666
2d120f83
JS
1667 bool sameColour = (oldPenColour.Ok () &&
1668 (oldPenColour.Red () == m_currentColour.Red ()) &&
1669 (oldPenColour.Blue () == m_currentColour.Blue ()) &&
1670 (oldPenColour.Green () == m_currentColour.Green ()) &&
1671 (oldPenColour.GetPixel() == m_currentColour.GetPixel()));
af0bb3b1 1672
2d120f83 1673 if (!sameStyle || !GetOptimization())
16c1f7f3 1674 {
2d120f83
JS
1675 int scaled_width = (int) XLOG2DEVREL (m_pen.GetWidth ());
1676 if (scaled_width < 0)
1677 scaled_width = 0;
af0bb3b1 1678
2d120f83
JS
1679 int style;
1680 int join;
1681 int cap;
69c44812
MB
1682 static const wxX11Dash dotted[] = {2, 5};
1683 static const wxX11Dash short_dashed[] = {4, 4};
1684 static const wxX11Dash long_dashed[] = {4, 8};
1685 static const wxX11Dash dotted_dashed[] = {6, 6, 2, 6};
af0bb3b1 1686
2d120f83
JS
1687 // We express dash pattern in pen width unit, so we are
1688 // independent of zoom factor and so on...
1689 int req_nb_dash;
69c44812 1690 const wxX11Dash *req_dash;
af0bb3b1 1691
2d120f83
JS
1692 switch (m_pen.GetStyle ())
1693 {
16c1f7f3 1694 case wxUSER_DASH:
2d120f83
JS
1695 req_nb_dash = m_currentPenDashCount;
1696 req_dash = m_currentPenDash;
1697 style = LineOnOffDash;
1698 break;
16c1f7f3 1699 case wxDOT:
2d120f83
JS
1700 req_nb_dash = 2;
1701 req_dash = dotted;
1702 style = LineOnOffDash;
1703 break;
16c1f7f3 1704 case wxSHORT_DASH:
2d120f83
JS
1705 req_nb_dash = 2;
1706 req_dash = short_dashed;
1707 style = LineOnOffDash;
1708 break;
16c1f7f3 1709 case wxLONG_DASH:
2d120f83
JS
1710 req_nb_dash = 2;
1711 req_dash = long_dashed;
1712 style = LineOnOffDash;
1713 break;
16c1f7f3 1714 case wxDOT_DASH:
2d120f83
JS
1715 req_nb_dash = 4;
1716 req_dash = dotted_dashed;
1717 style = LineOnOffDash;
1718 break;
16c1f7f3
JS
1719 case wxSTIPPLE:
1720 case wxSOLID:
1721 case wxTRANSPARENT:
1722 default:
2d120f83 1723 style = LineSolid;
69c44812 1724 req_dash = (wxX11Dash*)NULL;
2d120f83 1725 req_nb_dash = 0;
16c1f7f3 1726 }
af0bb3b1 1727
2d120f83 1728 if (req_dash && req_nb_dash)
16c1f7f3 1729 {
69c44812 1730 wxX11Dash *real_req_dash = new wxX11Dash[req_nb_dash];
2d120f83
JS
1731 if (real_req_dash)
1732 {
1733 int factor = scaled_width == 0 ? 1 : scaled_width;
1734 for (int i = 0; i < req_nb_dash; i++)
1735 real_req_dash[i] = req_dash[i] * factor;
1736 XSetDashes ((Display*) m_display, (GC) m_gc, 0, real_req_dash, req_nb_dash);
af0bb3b1 1737
2d120f83
JS
1738 if (m_window && m_window->GetBackingPixmap())
1739 XSetDashes ((Display*) m_display,(GC) m_gcBacking, 0, real_req_dash, req_nb_dash);
1740 delete[]real_req_dash;
1741 }
1742 else
1743 {
1744 // No Memory. We use non-scaled dash pattern...
1745 XSetDashes ((Display*) m_display, (GC) m_gc, 0, req_dash, req_nb_dash);
af0bb3b1 1746
2d120f83
JS
1747 if (m_window && m_window->GetBackingPixmap())
1748 XSetDashes ((Display*) m_display,(GC) m_gcBacking, 0, req_dash, req_nb_dash);
1749 }
16c1f7f3 1750 }
af0bb3b1 1751
2d120f83
JS
1752 switch (m_pen.GetCap ())
1753 {
16c1f7f3 1754 case wxCAP_PROJECTING:
2d120f83
JS
1755 cap = CapProjecting;
1756 break;
16c1f7f3 1757 case wxCAP_BUTT:
2d120f83
JS
1758 cap = CapButt;
1759 break;
16c1f7f3
JS
1760 case wxCAP_ROUND:
1761 default:
2d120f83
JS
1762 cap = (scaled_width <= 1) ? CapNotLast : CapRound;
1763 break;
1764 }
af0bb3b1 1765
2d120f83
JS
1766 switch (m_pen.GetJoin ())
1767 {
16c1f7f3 1768 case wxJOIN_BEVEL:
2d120f83
JS
1769 join = JoinBevel;
1770 break;
16c1f7f3 1771 case wxJOIN_MITER:
2d120f83
JS
1772 join = JoinMiter;
1773 break;
16c1f7f3
JS
1774 case wxJOIN_ROUND:
1775 default:
2d120f83
JS
1776 join = JoinRound;
1777 break;
1778 }
af0bb3b1 1779
2d120f83 1780 XSetLineAttributes ((Display*) m_display, (GC) m_gc, scaled_width, style, cap, join);
af0bb3b1 1781
2d120f83
JS
1782 if (m_window && m_window->GetBackingPixmap())
1783 XSetLineAttributes ((Display*) m_display,(GC) m_gcBacking, scaled_width, style, cap, join);
16c1f7f3 1784 }
af0bb3b1 1785
16c1f7f3
JS
1786 if (IS_HATCH(m_currentFill) && ((m_currentFill != oldFill) || !GetOptimization()))
1787 {
2d120f83 1788 Pixmap myStipple;
af0bb3b1 1789
2d120f83 1790 oldStipple = wxNullBitmap; // For later reset!!
af0bb3b1 1791
2d120f83
JS
1792 switch (m_currentFill)
1793 {
16c1f7f3 1794 case wxBDIAGONAL_HATCH:
2d120f83
JS
1795 if (bdiag == (Pixmap) 0)
1796 bdiag = XCreateBitmapFromData ((Display*) m_display,
1797 RootWindow ((Display*) m_display, DefaultScreen ((Display*) m_display)),
1798 bdiag_bits, bdiag_width, bdiag_height);
1799 myStipple = bdiag;
1800 break;
16c1f7f3 1801 case wxFDIAGONAL_HATCH:
2d120f83
JS
1802 if (fdiag == (Pixmap) 0)
1803 fdiag = XCreateBitmapFromData ((Display*) m_display,
1804 RootWindow ((Display*) m_display, DefaultScreen ((Display*) m_display)),
1805 fdiag_bits, fdiag_width, fdiag_height);
1806 myStipple = fdiag;
1807 break;
16c1f7f3 1808 case wxCROSS_HATCH:
2d120f83
JS
1809 if (cross == (Pixmap) 0)
1810 cross = XCreateBitmapFromData ((Display*) m_display,
1811 RootWindow ((Display*) m_display, DefaultScreen ((Display*) m_display)),
1812 cross_bits, cross_width, cross_height);
1813 myStipple = cross;
1814 break;
16c1f7f3 1815 case wxHORIZONTAL_HATCH:
2d120f83
JS
1816 if (horiz == (Pixmap) 0)
1817 horiz = XCreateBitmapFromData ((Display*) m_display,
1818 RootWindow ((Display*) m_display, DefaultScreen ((Display*) m_display)),
1819 horiz_bits, horiz_width, horiz_height);
1820 myStipple = horiz;
1821 break;
16c1f7f3 1822 case wxVERTICAL_HATCH:
2d120f83
JS
1823 if (verti == (Pixmap) 0)
1824 verti = XCreateBitmapFromData ((Display*) m_display,
1825 RootWindow ((Display*) m_display, DefaultScreen ((Display*) m_display)),
1826 verti_bits, verti_width, verti_height);
1827 myStipple = verti;
1828 break;
16c1f7f3
JS
1829 case wxCROSSDIAG_HATCH:
1830 default:
2d120f83
JS
1831 if (cdiag == (Pixmap) 0)
1832 cdiag = XCreateBitmapFromData ((Display*) m_display,
1833 RootWindow ((Display*) m_display, DefaultScreen ((Display*) m_display)),
1834 cdiag_bits, cdiag_width, cdiag_height);
1835 myStipple = cdiag;
1836 break;
1837 }
1838 XSetStipple ((Display*) m_display, (GC) m_gc, myStipple);
af0bb3b1 1839
2d120f83
JS
1840 if (m_window && m_window->GetBackingPixmap())
1841 XSetStipple ((Display*) m_display,(GC) m_gcBacking, myStipple);
16c1f7f3
JS
1842 }
1843 else if (m_currentStipple.Ok()
2d120f83 1844 && ((m_currentStipple != oldStipple) || !GetOptimization()))
16c1f7f3 1845 {
aae0472b 1846 XSetStipple ((Display*) m_display, (GC) m_gc, (Pixmap) m_currentStipple.GetDrawable());
af0bb3b1 1847
2d120f83 1848 if (m_window && m_window->GetBackingPixmap())
aae0472b 1849 XSetStipple ((Display*) m_display,(GC) m_gcBacking, (Pixmap) m_currentStipple.GetDrawable());
16c1f7f3 1850 }
af0bb3b1 1851
16c1f7f3
JS
1852 if ((m_currentFill != oldFill) || !GetOptimization())
1853 {
2d120f83 1854 int fill_style;
af0bb3b1 1855
2d120f83
JS
1856 if (m_currentFill == wxSTIPPLE)
1857 fill_style = FillStippled;
1858 else if (IS_HATCH (m_currentFill))
1859 fill_style = FillStippled;
1860 else
1861 fill_style = FillSolid;
1862 XSetFillStyle ((Display*) m_display, (GC) m_gc, fill_style);
1863 if (m_window && m_window->GetBackingPixmap())
1864 XSetFillStyle ((Display*) m_display,(GC) m_gcBacking, fill_style);
16c1f7f3 1865 }
af0bb3b1 1866
16c1f7f3
JS
1867 // must test m_logicalFunction, because it involves background!
1868 if (!sameColour || !GetOptimization()
2d120f83 1869 || ((m_logicalFunction == wxXOR) || (m_autoSetting & 0x2)))
16c1f7f3 1870 {
2d120f83
JS
1871 int pixel = -1;
1872 if (m_pen.GetStyle () == wxTRANSPARENT)
1873 pixel = m_backgroundPixel;
16c1f7f3
JS
1874 else
1875 {
395539f9 1876 pixel = CalculatePixel(m_pen.GetColour(), m_currentColour, FALSE);
16c1f7f3 1877 }
af0bb3b1 1878
2d120f83
JS
1879 // Finally, set the GC to the required colour
1880 if (pixel > -1)
395539f9 1881 SetForegroundPixelWithLogicalFunction(pixel);
16c1f7f3 1882 }
2d120f83
JS
1883 else
1884 m_pen.GetColour().SetPixel(oldPenColour.GetPixel());
af0bb3b1 1885
2d120f83 1886 m_autoSetting = 0;
af0bb3b1 1887}
4bb6408c 1888
dfc54541 1889void wxWindowDC::SetBrush( const wxBrush &brush )
4bb6408c 1890{
af0bb3b1
VZ
1891 wxCHECK_RET( Ok(), "invalid dc" );
1892
2d120f83 1893 m_brush = brush;
af0bb3b1 1894
2d120f83
JS
1895 if (!m_brush.Ok() || m_brush.GetStyle () == wxTRANSPARENT)
1896 return;
af0bb3b1 1897
2d120f83
JS
1898 int oldFill = m_currentFill;
1899 wxBitmap oldStipple = m_currentStipple;
af0bb3b1 1900
2d120f83 1901 m_autoSetting |= 0x1;
af0bb3b1 1902
2d120f83
JS
1903 m_currentFill = m_brush.GetStyle ();
1904 if (m_currentFill == wxSTIPPLE)
1905 m_currentStipple = * m_brush.GetStipple ();
af0bb3b1 1906
2d120f83
JS
1907 wxColour oldBrushColour(m_currentColour);
1908 m_currentColour = m_brush.GetColour ();
af0bb3b1 1909
2d120f83
JS
1910 bool sameColour = (oldBrushColour.Ok () &&
1911 (oldBrushColour.Red () == m_currentColour.Red ()) &&
1912 (oldBrushColour.Blue () == m_currentColour.Blue ()) &&
1913 (oldBrushColour.Green () == m_currentColour.Green ()) &&
1914 (oldBrushColour.GetPixel() == m_currentColour.GetPixel()));
af0bb3b1 1915
2b830c41
MB
1916 int stippleDepth = -1;
1917
2d120f83
JS
1918 if ((oldFill != m_brush.GetStyle ()) || !GetOptimization())
1919 {
1920 switch (brush.GetStyle ())
1921 {
16c1f7f3 1922 case wxTRANSPARENT:
2d120f83 1923 break;
2b830c41
MB
1924 case wxSTIPPLE:
1925 stippleDepth = m_currentStipple.GetDepth();
1926 // fall through!
16c1f7f3
JS
1927 case wxBDIAGONAL_HATCH:
1928 case wxCROSSDIAG_HATCH:
1929 case wxFDIAGONAL_HATCH:
1930 case wxCROSS_HATCH:
1931 case wxHORIZONTAL_HATCH:
1932 case wxVERTICAL_HATCH:
2d120f83 1933 {
2b830c41
MB
1934 if (stippleDepth == -1) stippleDepth = 1;
1935
1936 // Chris Breeze 23/07/97: use background mode to
1937 // determine whether fill style should be solid or
1938 // transparent
1939 int style = stippleDepth == 1 ?
1940 (m_backgroundMode == wxSOLID ?
1941 FillOpaqueStippled : FillStippled) :
1942 FillTiled;
2d120f83
JS
1943 XSetFillStyle ((Display*) m_display, (GC) m_gc, style);
1944 if (m_window && m_window->GetBackingPixmap())
1945 XSetFillStyle ((Display*) m_display,(GC) m_gcBacking, style);
1946 }
1947 break;
16c1f7f3
JS
1948 case wxSOLID:
1949 default:
2d120f83
JS
1950 XSetFillStyle ((Display*) m_display, (GC) m_gc, FillSolid);
1951 if (m_window && m_window->GetBackingPixmap())
2b830c41
MB
1952 XSetFillStyle ((Display*) m_display,(GC) m_gcBacking,
1953 FillSolid);
2d120f83
JS
1954 }
1955 }
af0bb3b1 1956
2d120f83 1957 if (IS_HATCH(m_currentFill) && ((m_currentFill != oldFill) || !GetOptimization()))
16c1f7f3 1958 {
2d120f83 1959 Pixmap myStipple;
af0bb3b1 1960
2d120f83
JS
1961 switch (m_currentFill)
1962 {
16c1f7f3 1963 case wxBDIAGONAL_HATCH:
2d120f83
JS
1964 if (bdiag == (Pixmap) 0)
1965 bdiag = XCreateBitmapFromData ((Display*) m_display,
1966 RootWindow ((Display*) m_display, DefaultScreen ((Display*) m_display)),
1967 bdiag_bits, bdiag_width, bdiag_height);
1968 myStipple = bdiag;
1969 break;
16c1f7f3 1970 case wxFDIAGONAL_HATCH:
2d120f83
JS
1971 if (fdiag == (Pixmap) 0)
1972 fdiag = XCreateBitmapFromData ((Display*) m_display,
1973 RootWindow ((Display*) m_display, DefaultScreen ((Display*) m_display)),
1974 fdiag_bits, fdiag_width, fdiag_height);
1975 myStipple = fdiag;
1976 break;
16c1f7f3 1977 case wxCROSS_HATCH:
2d120f83
JS
1978 if (cross == (Pixmap) 0)
1979 cross = XCreateBitmapFromData ((Display*) m_display,
1980 RootWindow ((Display*) m_display, DefaultScreen ((Display*) m_display)),
1981 cross_bits, cross_width, cross_height);
1982 myStipple = cross;
1983 break;
16c1f7f3 1984 case wxHORIZONTAL_HATCH:
2d120f83
JS
1985 if (horiz == (Pixmap) 0)
1986 horiz = XCreateBitmapFromData ((Display*) m_display,
1987 RootWindow ((Display*) m_display, DefaultScreen ((Display*) m_display)),
1988 horiz_bits, horiz_width, horiz_height);
1989 myStipple = horiz;
1990 break;
16c1f7f3 1991 case wxVERTICAL_HATCH:
2d120f83
JS
1992 if (verti == (Pixmap) 0)
1993 verti = XCreateBitmapFromData ((Display*) m_display,
1994 RootWindow ((Display*) m_display, DefaultScreen ((Display*) m_display)),
1995 verti_bits, verti_width, verti_height);
1996 myStipple = verti;
1997 break;
16c1f7f3
JS
1998 case wxCROSSDIAG_HATCH:
1999 default:
2d120f83
JS
2000 if (cdiag == (Pixmap) 0)
2001 cdiag = XCreateBitmapFromData ((Display*) m_display,
2002 RootWindow ((Display*) m_display, DefaultScreen ((Display*) m_display)),
2003 cdiag_bits, cdiag_width, cdiag_height);
2004 myStipple = cdiag;
2005 break;
2006 }
2007 XSetStipple ((Display*) m_display, (GC) m_gc, myStipple);
af0bb3b1 2008
2d120f83
JS
2009 if (m_window && m_window->GetBackingPixmap())
2010 XSetStipple ((Display*) m_display,(GC) m_gcBacking, myStipple);
16c1f7f3
JS
2011 }
2012 // X can forget the stipple value when resizing a window (apparently)
2013 // so always set the stipple.
2b830c41
MB
2014 else if (m_currentFill != wxSOLID && m_currentFill != wxTRANSPARENT &&
2015 m_currentStipple.Ok()) // && m_currentStipple != oldStipple)
16c1f7f3 2016 {
2b830c41
MB
2017 if (m_currentStipple.GetDepth() == 1)
2018 {
2019 XSetStipple ((Display*) m_display, (GC) m_gc,
aae0472b 2020 (Pixmap) m_currentStipple.GetDrawable());
2d120f83 2021 if (m_window && m_window->GetBackingPixmap())
2b830c41 2022 XSetStipple ((Display*) m_display,(GC) m_gcBacking,
aae0472b 2023 (Pixmap) m_currentStipple.GetDrawable());
2b830c41
MB
2024 }
2025 else
2026 {
2027 XSetTile ((Display*) m_display, (GC) m_gc,
aae0472b 2028 (Pixmap) m_currentStipple.GetDrawable());
2b830c41
MB
2029 if (m_window && m_window->GetBackingPixmap())
2030 XSetTile ((Display*) m_display,(GC) m_gcBacking,
aae0472b 2031 (Pixmap) m_currentStipple.GetDrawable());
2b830c41 2032 }
16c1f7f3 2033 }
af0bb3b1 2034
16c1f7f3
JS
2035 // must test m_logicalFunction, because it involves background!
2036 if (!sameColour || !GetOptimization() || m_logicalFunction == wxXOR)
2037 {
395539f9
MB
2038 int pixel = CalculatePixel(m_brush.GetColour(), m_currentColour, TRUE);
2039
2d120f83 2040 if (pixel > -1)
395539f9 2041 SetForegroundPixelWithLogicalFunction(pixel);
16c1f7f3 2042 }
2d120f83
JS
2043 else
2044 m_brush.GetColour().SetPixel(oldBrushColour.GetPixel());
af0bb3b1 2045}
4bb6408c 2046
dfc54541 2047void wxWindowDC::SetBackground( const wxBrush &brush )
4bb6408c 2048{
af0bb3b1
VZ
2049 wxCHECK_RET( Ok(), "invalid dc" );
2050
2d120f83 2051 m_backgroundBrush = brush;
af0bb3b1 2052
2d120f83
JS
2053 if (!m_backgroundBrush.Ok())
2054 return;
af0bb3b1 2055
395539f9 2056 m_backgroundPixel = m_backgroundBrush.GetColour().AllocColour(m_display);
a91b47e8
JS
2057
2058 // New behaviour, 10/2/99: setting the background brush of a DC
2059 // doesn't affect the window background colour.
2060/*
2d120f83
JS
2061 // XSetWindowBackground doesn't work for non-Window pixmaps
2062 if (!this->IsKindOf(CLASSINFO(wxMemoryDC)))
2063 XSetWindowBackground ((Display*) m_display, (Pixmap) m_pixmap, pixel);
a91b47e8 2064*/
af0bb3b1 2065
2d120f83
JS
2066 // Necessary for ::DrawIcon, which use fg/bg pixel or the GC.
2067 // And Blit,... (Any fct that use XCopyPlane, in fact.)
395539f9 2068 XSetBackground ((Display*) m_display, (GC) m_gc, m_backgroundPixel);
2d120f83 2069 if (m_window && m_window->GetBackingPixmap())
395539f9
MB
2070 XSetBackground ((Display*) m_display,(GC) m_gcBacking,
2071 m_backgroundPixel);
af0bb3b1 2072}
4bb6408c 2073
dfc54541 2074void wxWindowDC::SetLogicalFunction( int function )
4bb6408c 2075{
af0bb3b1
VZ
2076 wxCHECK_RET( Ok(), "invalid dc" );
2077
2d120f83 2078 int x_function;
af0bb3b1 2079
2d120f83
JS
2080 /* MATTHEW: [9] */
2081 if (m_logicalFunction == function)
2082 return;
af0bb3b1 2083
2d120f83 2084 switch (function)
16c1f7f3
JS
2085 {
2086 case wxCLEAR:
2d120f83
JS
2087 x_function = GXclear;
2088 break;
16c1f7f3 2089 case wxXOR:
2d120f83
JS
2090 x_function = GXxor;
2091 break;
16c1f7f3 2092 case wxINVERT:
2d120f83
JS
2093 x_function = GXinvert;
2094 break;
16c1f7f3 2095 case wxOR_REVERSE:
2d120f83
JS
2096 x_function = GXorReverse;
2097 break;
16c1f7f3 2098 case wxAND_REVERSE:
2d120f83
JS
2099 x_function = GXandReverse;
2100 break;
16c1f7f3 2101 case wxAND:
2d120f83
JS
2102 x_function = GXand;
2103 break;
16c1f7f3 2104 case wxOR:
2d120f83
JS
2105 x_function = GXor;
2106 break;
16c1f7f3 2107 case wxAND_INVERT:
2d120f83
JS
2108 x_function = GXandInverted;
2109 break;
16c1f7f3 2110 case wxNO_OP:
2d120f83
JS
2111 x_function = GXnoop;
2112 break;
16c1f7f3 2113 case wxNOR:
2d120f83
JS
2114 x_function = GXnor;
2115 break;
16c1f7f3 2116 case wxEQUIV:
2d120f83
JS
2117 x_function = GXequiv;
2118 break;
16c1f7f3 2119 case wxSRC_INVERT:
2d120f83
JS
2120 x_function = GXcopyInverted;
2121 break;
16c1f7f3 2122 case wxOR_INVERT:
2d120f83
JS
2123 x_function = GXorInverted;
2124 break;
16c1f7f3 2125 case wxNAND:
2d120f83
JS
2126 x_function = GXnand;
2127 break;
16c1f7f3 2128 case wxSET:
2d120f83
JS
2129 x_function = GXset;
2130 break;
16c1f7f3
JS
2131 case wxCOPY:
2132 default:
2d120f83
JS
2133 x_function = GXcopy;
2134 break;
16c1f7f3 2135 }
af0bb3b1 2136
2d120f83
JS
2137 XSetFunction((Display*) m_display, (GC) m_gc, x_function);
2138 if (m_window && m_window->GetBackingPixmap())
2139 XSetFunction((Display*) m_display, (GC) m_gcBacking, x_function);
af0bb3b1 2140
2d120f83
JS
2141 if ((m_logicalFunction == wxXOR) != (function == wxXOR))
2142 /* MATTHEW: [9] Need to redo pen simply */
2143 m_autoSetting |= 0x2;
af0bb3b1 2144
2d120f83 2145 m_logicalFunction = function;
af0bb3b1
VZ
2146
2147}
4bb6408c 2148
dfc54541 2149void wxWindowDC::SetTextForeground( const wxColour &col )
4bb6408c 2150{
af0bb3b1
VZ
2151 wxCHECK_RET( Ok(), "invalid dc" );
2152
2153 if (m_textForegroundColour == col)
2154 return;
2155
2d120f83 2156 m_textForegroundColour = col;
af0bb3b1
VZ
2157
2158}
4bb6408c 2159
dfc54541 2160void wxWindowDC::SetTextBackground( const wxColour &col )
4bb6408c 2161{
af0bb3b1
VZ
2162 wxCHECK_RET( Ok(), "invalid dc" );
2163
2164 if (m_textBackgroundColour == col)
2165 return;
2166
2d120f83 2167 m_textBackgroundColour = col;
af0bb3b1
VZ
2168 if (!m_textBackgroundColour.Ok())
2169 return;
2170}
4bb6408c 2171
dfc54541 2172void wxWindowDC::SetBackgroundMode( int mode )
4bb6408c 2173{
2d120f83 2174 m_backgroundMode = mode;
af0bb3b1 2175}
16c1f7f3
JS
2176
2177void wxWindowDC::SetPalette( const wxPalette& palette )
2178{
2d120f83
JS
2179 if (m_window)
2180 {
2181 if (palette.Ok())
2182 /* Use GetXColormap */
2183 XSetWindowColormap ((Display*) m_display, (Window) m_window->GetXWindow(),
2184 (Colormap) palette.GetXColormap());
2185 else
2186 /* Use wxGetMainColormap */
2187 XSetWindowColormap ((Display*) m_display, (Window) m_window->GetXWindow(),
2188 (Colormap) wxTheApp->GetMainColormap(m_display));
2189 }
af0bb3b1 2190}
4bb6408c 2191
16c1f7f3 2192// Helper function
af0bb3b1 2193void wxWindowDC::SetDCClipping()
4bb6408c 2194{
2d120f83 2195 // m_userRegion is the region set by calling SetClippingRegion
af0bb3b1 2196
2d120f83
JS
2197 if (m_currentRegion)
2198 XDestroyRegion ((Region) m_currentRegion);
af0bb3b1 2199
2d120f83
JS
2200 // We need to take into account
2201 // clipping imposed on a window by a repaint.
2202 // We'll combine it with the user region. But for now,
2203 // just use the currently-defined user clipping region.
2204 if (m_userRegion || (m_window && m_window->GetUpdateRegion().Ok()) )
2205 m_currentRegion = (WXRegion) XCreateRegion ();
2206 else
2207 m_currentRegion = (WXRegion) NULL;
af0bb3b1 2208
2d120f83
JS
2209 if ((m_window && m_window->GetUpdateRegion().Ok()) && m_userRegion)
2210 XIntersectRegion ((Region) m_window->GetUpdateRegion().GetXRegion(), (Region) m_userRegion, (Region) m_currentRegion);
2211 else if (m_userRegion)
2212 XIntersectRegion ((Region) m_userRegion, (Region) m_userRegion, (Region) m_currentRegion);
2213 else if (m_window && m_window->GetUpdateRegion().Ok())
af0bb3b1 2214 XIntersectRegion ((Region) m_window->GetUpdateRegion().GetXRegion(), (Region) m_window->GetUpdateRegion().GetXRegion(),
2d120f83 2215 (Region) m_currentRegion);
af0bb3b1 2216
2d120f83 2217 if (m_currentRegion)
16c1f7f3 2218 {
2d120f83 2219 XSetRegion ((Display*) m_display, (GC) m_gc, (Region) m_currentRegion);
16c1f7f3 2220 }
2d120f83 2221 else
16c1f7f3 2222 {
2d120f83 2223 XSetClipMask ((Display*) m_display, (GC) m_gc, None);
16c1f7f3 2224 }
af0bb3b1 2225
16c1f7f3 2226}
4bb6408c 2227
7b65ea1a 2228void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
4bb6408c 2229{
33caefb3 2230 wxDC::DoSetClippingRegion( x, y, width, height );
af0bb3b1 2231
2d120f83
JS
2232 if (m_userRegion)
2233 XDestroyRegion ((Region) m_userRegion);
2234 m_userRegion = (WXRegion) XCreateRegion ();
2235 XRectangle r;
2236 r.x = XLOG2DEV (x);
2237 r.y = YLOG2DEV (y);
2238 r.width = XLOG2DEVREL(width);
2239 r.height = YLOG2DEVREL(height);
2240 XUnionRectWithRegion (&r, (Region) m_userRegion, (Region) m_userRegion);
af0bb3b1 2241
2d120f83 2242 SetDCClipping ();
af0bb3b1 2243
2d120f83
JS
2244 // Needs to work differently for Pixmap: without this,
2245 // there's a nasty (Display*) m_display bug. 8/12/94
2246 if (m_window && m_window->GetBackingPixmap())
2247 {
2248 XRectangle rects[1];
af0bb3b1 2249 rects[0].x = XLOG2DEV_2(x);
2d120f83
JS
2250 rects[0].y = YLOG2DEV_2(y);
2251 rects[0].width = XLOG2DEVREL(width);
2252 rects[0].height = YLOG2DEVREL(height);
2253 XSetClipRectangles((Display*) m_display, (GC) m_gcBacking, 0, 0, rects, 1, Unsorted);
2254 }
af0bb3b1 2255}
4bb6408c 2256
af0bb3b1 2257void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion& region )
a724d789 2258{
2d120f83 2259 wxRect box = region.GetBox();
af0bb3b1 2260
33caefb3 2261 wxDC::DoSetClippingRegion( box.x, box.y, box.width, box.height );
af0bb3b1 2262
2d120f83
JS
2263 if (m_userRegion)
2264 XDestroyRegion ((Region) m_userRegion);
2265 m_userRegion = (WXRegion) XCreateRegion ();
af0bb3b1 2266
2d120f83 2267 XUnionRegion((Region) m_userRegion, (Region) region.GetXRegion(), (Region) m_userRegion);
af0bb3b1 2268
2d120f83 2269 SetDCClipping ();
af0bb3b1 2270
2d120f83
JS
2271 // Needs to work differently for Pixmap: without this,
2272 // there's a nasty (Display*) m_display bug. 8/12/94
2273 if (m_window && m_window->GetBackingPixmap())
2274 {
2275 XRectangle rects[1];
2276 rects[0].x = XLOG2DEV_2(box.x);
2277 rects[0].y = YLOG2DEV_2(box.y);
2278 rects[0].width = XLOG2DEVREL(box.width);
2279 rects[0].height = YLOG2DEVREL(box.height);
2280 XSetClipRectangles((Display*) m_display, (GC) m_gcBacking, 0, 0, rects, 1, Unsorted);
2281 }
af0bb3b1 2282}
a724d789
JS
2283
2284
af0bb3b1 2285void wxWindowDC::DestroyClippingRegion()
4bb6408c 2286{
2d120f83 2287 wxDC::DestroyClippingRegion();
af0bb3b1 2288
2d120f83
JS
2289 if (m_userRegion)
2290 XDestroyRegion ((Region) m_userRegion);
2291 m_userRegion = NULL;
af0bb3b1 2292
2d120f83 2293 SetDCClipping ();
af0bb3b1 2294
2d120f83
JS
2295 XGCValues gc_val;
2296 gc_val.clip_mask = None;
2297 if (m_window && m_window->GetBackingPixmap())
2298 XChangeGC((Display*) m_display, (GC) m_gcBacking, GCClipMask, &gc_val);
4bb6408c
JS
2299}
2300
af0bb3b1
VZ
2301// Resolution in pixels per logical inch
2302wxSize wxWindowDC::GetPPI() const
4bb6408c 2303{
af0bb3b1 2304 return wxSize(100, 100);
4bb6408c
JS
2305}
2306
af0bb3b1 2307int wxWindowDC::GetDepth() const
7bcb11d3 2308{
af0bb3b1
VZ
2309 // TODO
2310 return 24;
7bcb11d3
JS
2311}
2312
96f201da
RR
2313
2314
2315
af0bb3b1
VZ
2316// ----------------------------------------------------------------------------
2317// wxPaintDC
2318// ----------------------------------------------------------------------------
55acd85e 2319
af0bb3b1 2320wxPaintDC::wxPaintDC(wxWindow* win) : wxWindowDC(win)
55acd85e
JS
2321{
2322 wxRegion* region = NULL;
af0bb3b1 2323
55acd85e 2324 // Combine all the update rects into a region
af0bb3b1
VZ
2325 const wxRectList& updateRects(win->GetUpdateRects());
2326 if ( updateRects.GetCount() != 0 )
55acd85e 2327 {
af0bb3b1
VZ
2328 for ( wxRectList::Node *node = updateRects.GetFirst();
2329 node;
2330 node = node->GetNext() )
55acd85e 2331 {
af0bb3b1
VZ
2332 wxRect* rect = node->GetData();
2333
55acd85e
JS
2334 if (!region)
2335 region = new wxRegion(*rect);
2336 else
2337 // TODO: is this correct? In SetDCClipping above,
2338 // XIntersectRegion is used to combine paint and user
2339 // regions. XIntersectRegion appears to work in that case...
2340 region->Union(*rect);
2341 }
2342 }
2343 else
2344 {
2345 int cw, ch;
2346 win->GetClientSize(&cw, &ch);
2347 region = new wxRegion(wxRect(0, 0, cw, ch));
2348 }
af0bb3b1
VZ
2349
2350 win->SetUpdateRegion(*region);
2351
25f47127
JS
2352 wxRegion& theRegion(win->GetUpdateRegion());
2353 theRegion.SetRects(updateRects); // We also store in terms of rects, for iteration to work.
2354
55acd85e
JS
2355 // Set the clipping region. Any user-defined region will be combined with this
2356 // one in SetDCClipping.
2357 XSetRegion ((Display*) m_display, (GC) m_gc, (Region) region->GetXRegion());
af0bb3b1 2358
55acd85e
JS
2359 delete region;
2360}
2361
2362wxPaintDC::~wxPaintDC()
2363{
2364 XSetClipMask ((Display*) m_display, (GC) m_gc, None);
2365 if (m_window)
af0bb3b1
VZ
2366 m_window->ClearUpdateRegion();
2367}
2368
2369// ----------------------------------------------------------------------------
2370// private functions
2371// ----------------------------------------------------------------------------
2372
2373/*
2374 Used when copying between drawables on different (Display*) m_displays. Not
2375 very fast, but better than giving up.
2376*/
2377
2378static void XCopyRemote(Display *src_display, Display *dest_display,
2379 Drawable src, Drawable dest,
2380 GC destgc,
2381 int srcx, int srcy,
2382 unsigned int w, unsigned int h,
2383 int destx, int desty,
2384 bool more, XImage **cache)
2385{
2386 XImage *image, *destimage;
2387 Colormap destcm, srccm;
2388 static const int CACHE_SIZE = 256;
2389
2390 unsigned int i, j;
2391 unsigned long cachesrc[CACHE_SIZE], cachedest[CACHE_SIZE];
2392 int k, cache_pos, all_cache;
2393
2394 if (!cache || !*cache)
2395 image = XGetImage(src_display, src, srcx, srcy, w, h, AllPlanes, ZPixmap);
2396 else
2397 image = *cache;
2398
2399 destimage = XGetImage(dest_display, dest, destx, desty, w, h, AllPlanes, ZPixmap);
2400
2401 srccm = (Colormap) wxTheApp->GetMainColormap((WXDisplay*) src_display);
2402 destcm = (Colormap) wxTheApp->GetMainColormap((WXDisplay*) dest_display);
2403
2404 cache_pos = 0;
2405 all_cache = FALSE;
2406
2407 for (i = 0; i < w; i++)
2408 for (j = 0; j < h; j++) {
2409 unsigned long pixel;
2410 XColor xcol;
2411
2412 pixel = XGetPixel(image, i, j);
2413 for (k = cache_pos; k--; )
2414 if (cachesrc[k] == pixel) {
2415 pixel = cachedest[k];
2416 goto install;
2417 }
2418 if (all_cache)
2419 for (k = CACHE_SIZE; k-- > cache_pos; )
2420 if (cachesrc[k] == pixel) {
2421 pixel = cachedest[k];
2422 goto install;
2423 }
2424
2425 cachesrc[cache_pos] = xcol.pixel = pixel;
2426 XQueryColor(src_display, srccm, &xcol);
2427 if (!XAllocColor(dest_display, destcm, &xcol))
2428 xcol.pixel = 0;
2429 cachedest[cache_pos] = pixel = xcol.pixel;
2430
2431 if (++cache_pos >= CACHE_SIZE) {
2432 cache_pos = 0;
2433 all_cache = TRUE;
2434 }
2435
2436install:
2437 XPutPixel(destimage, i, j, pixel);
2438 }
2439
2440 XPutImage(dest_display, dest, destgc, destimage, 0, 0, destx, desty, w, h);
2441 XDestroyImage(destimage);
2442
2443 if (more)
2444 *cache = image;
2445 else
2446 XDestroyImage(image);
2447}
2448
2449#if 0
2450
2451/* Helper function for 16-bit fonts */
2452static int str16len(const char *s)
2453{
2454 int count = 0;
2455
2456 while (s[0] && s[1]) {
2457 count++;
2458 s += 2;
2459 }
2460
2461 return count;
55acd85e
JS
2462}
2463
af0bb3b1 2464#endif // 0