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