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