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