1 /********************************************************************************
2 *                                                                               *
3 *  D e v i c e   C o n t e x t   F o r   W i n d o w s   a n d   I m a g e s    *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1999,2020 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or modify          *
9 * it under the terms of the GNU Lesser General Public License as published by   *
10 * the Free Software Foundation; either version 3 of the License, or             *
11 * (at your option) any later version.                                           *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 *
16 * GNU Lesser General Public License for more details.                           *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public License      *
19 * along with this program.  If not, see <http://www.gnu.org/licenses/>          *
20 ********************************************************************************/
21 #include "xincs.h"
22 #include "fxver.h"
23 #include "fxdefs.h"
24 #include "fxmath.h"
25 #include "fxkeys.h"
26 #include "FXArray.h"
27 #include "FXHash.h"
28 #include "FXMutex.h"
29 #include "FXStream.h"
30 #include "FXString.h"
31 #include "FXObject.h"
32 #include "FXSize.h"
33 #include "FXPoint.h"
34 #include "FXRectangle.h"
35 #include "FXStringDictionary.h"
36 #include "FXSettings.h"
37 #include "FXRegistry.h"
38 #include "FXAccelTable.h"
39 #include "FXVisual.h"
40 #include "FXFont.h"
41 #include "FXCursor.h"
42 #include "FXEvent.h"
43 #include "FXWindow.h"
44 #include "FXApp.h"
45 #include "FXDrawable.h"
46 #include "FXImage.h"
47 #include "FXBitmap.h"
48 #include "FXIcon.h"
49 #include "FXWindow.h"
50 #include "FXFrame.h"
51 #include "FXComposite.h"
52 #include "FXRootWindow.h"
53 #include "FXShell.h"
54 #include "FXRegion.h"
55 #include "FXDCWindow.h"
56 
57 
58 /*
59   Notes:
60 
61   - Associate a DC with a surface before you begin using it:
62 
63      long SomeWidget::onPaint(FXObject*,FXSelector,void* ptr){
64        FXDCWindow dc(this,ptr);
65        dc.drawLine(...);
66        ... jadajadajada ...
67        return 1;
68        }
69 
70     The association is automatically broken when you go out of scope; the
71     destructor of the FXDCWindow does this for you.
72 
73   - Optimizations: only perform style/attribute changes just before an actual
74     drawing command takes place:- X-Windows apparently already does this;
75     MS-Windows also?
76 
77   - We assume the following initial state:
78 
79     BLIT Function:        BLT_SRC
80     Foreground:           black (0)
81     Background:           white (1)
82     Line Width:           0 (meaning thinnest/fastest, no guaranteed pixelation)
83     Cap Style:            CAP_BUTT
84     Join Style:           JOIN_MITER
85     Line Style:           LINE_SOLID
86     Fill Style:           FILL_SOLID
87     Fill Rule:            RULE_EVEN_ODD
88     Font:                 None
89     Other Paremeters:     To Be Determined
90 
91   - Under X-Windows, end() will restore the GC to the state above; flags
92     keeps track of which changes have been made to minimize the necessary
93     updating.
94 
95   - Under X, graphics_exposures should be OFF:- at least some SGI IRIX machines
96     have broken implementations of graphics_exposures.
97 
98   - Try suggestions from "Kevin Radke" <kmradke@isualum.com> below:
99 
100     Sorry about the huge delay with this code.  Work has been horribly busy
101     and I wasn't able to dig up the CD with the original code.  However, if I
102     remember
103     correctly (and this code snippet I found was from that test), I changed from
104     using
105     cosmetic pens to use geometric pens and specifying a line join style of
106     PS_JOIN_BEVEL.
107 
108     I.E.
109 
110         LOGBRUSH logBrush;
111         logBrush.lbStyle = BS_SOLID;
112         logBrush.lbColor = RGB(red, green, blue);
113         logBrush.lbHatch = HS_CROSS;  // Not used
114 
115         // NYI Only solid lines are valid on Windows 95.  style is ignored
116         return ExtCreatePen (PS_GEOMETRIC | PS_JOIN_BEVEL | style,
117                                         width, &logBrush, 0, NULL);
118 
119 
120     this returns an HPEN.
121 
122     I remember this being significantly slower than cosmetic pens (under NT4)
123     and at the time that I scrapped the code, and dealt with the drawing
124     differences
125     between X and Win32 at a higher level.
126 
127     This won't work on Win95/Win98 (without using paths), and after a closer
128     look at
129     the docs here it makes more sense to specify PS_ENDCAP_SQUARE to draw
130     the last pixel instead of the line join style.  I remember experimenting
131     with both, so
132     the code I found may have been in intermediate (unworking) version.
133 
134     In any case, it isn't too hard to experiment to see which has the required
135     behavior.  I've unfortunately been away from FOX work for a few months
136     or I'd try it myself.
137 
138   - Device caps for DirectX:
139     http://www.molybdenium.de/devicecaps/e_index.html
140 */
141 
142 using namespace FX;
143 
144 namespace FX {
145 
146 
147 /********************************************************************************
148 *                                   MS-Windows                                  *
149 ********************************************************************************/
150 
151 #ifdef WIN32
152 
153 // This one is not defined in the Cygwin header files
154 #ifndef PS_JOIN_MASK
155 #define PS_JOIN_MASK 0x0000F000
156 #endif
157 
158 // Construct for expose event painting
FXDCWindow(FXDrawable * draw,FXEvent * event)159 FXDCWindow::FXDCWindow(FXDrawable* draw,FXEvent* event):FXDC(draw->getApp()),surface(NULL),rect(0,0,0,0),devfg(0),devbg(0){
160   oldpalette=NULL;
161   oldbrush=NULL;
162   oldpen=NULL;
163   needsNewBrush=false;
164   needsNewPen=false;
165   needsPath=false;
166   needsClipReset=false;
167   begin(draw);
168   rect.x=clip.x=event->rect.x;
169   rect.y=clip.y=event->rect.y;
170   rect.w=clip.w=event->rect.w;
171   rect.h=clip.h=event->rect.h;
172   HRGN hrgn=CreateRectRgn(clip.x,clip.y,clip.x+clip.w,clip.y+clip.h);
173   SelectClipRgn((HDC)ctx,hrgn);
174   DeleteObject(hrgn);
175   }
176 
177 
178 // Construct for normal painting
FXDCWindow(FXDrawable * draw)179 FXDCWindow::FXDCWindow(FXDrawable* draw):FXDC(draw->getApp()),surface(NULL),rect(0,0,0,0),devfg(0),devbg(0){
180   oldpalette=NULL;
181   oldbrush=NULL;
182   oldpen=NULL;
183   needsNewBrush=false;
184   needsNewPen=false;
185   needsPath=false;
186   needsClipReset=false;
187   begin(draw);
188   }
189 
190 
191 // Destruct
~FXDCWindow()192 FXDCWindow::~FXDCWindow(){
193   end();
194   }
195 
196 
197 // Begin locks in a drawable surface
begin(FXDrawable * draw)198 void FXDCWindow::begin(FXDrawable *draw){
199   if(!draw){ fxerror("FXDCWindow::begin: NULL drawable.\n"); }
200   if(!draw->id()){ fxerror("FXDCWindow::begin: drawable not created yet.\n"); }
201 
202   surface=draw;     // Careful:- surface->id() can be HWND or HBITMAP depending on drawable
203   ctx=draw->GetDC();
204   rect.x=clip.x=0;
205   rect.y=clip.y=0;
206   rect.w=clip.w=draw->getWidth();
207   rect.h=clip.h=draw->getHeight();
208 
209   // Select and realize palette, if necessary
210   if(surface->visual->colormap){
211     oldpalette=::SelectPalette((HDC)ctx,(HPALETTE)surface->visual->colormap,false);
212     ::RealizePalette((HDC)ctx);
213     }
214 
215   devfg=~0;
216   devbg=0;
217 
218   // Create our default pen (black, solid, one pixel wide)
219   LOGBRUSH lb;
220   lb.lbStyle=BS_SOLID;
221   lb.lbColor=PALETTERGB(0,0,0);
222   lb.lbHatch=0;
223   oldpen=::SelectObject((HDC)ctx,ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,1,&lb,0,NULL));
224 
225   // Create our default brush (solid white, for fills)
226   lb.lbStyle=BS_SOLID;
227   lb.lbColor=PALETTERGB(255,255,255);
228   lb.lbHatch=0;
229   oldbrush=::SelectObject((HDC)ctx,CreateBrushIndirect(&lb));
230 
231   // Text alignment
232   ::SetTextAlign((HDC)ctx,TA_BASELINE|TA_LEFT);
233 
234   // Polygon fill mode
235   ::SetPolyFillMode((HDC)ctx,ALTERNATE);
236 
237   // Reset flags
238   needsNewBrush=false;
239   needsNewPen=false;
240   needsPath=false;
241   needsClipReset=false;
242   }
243 
244 
245 // End unlocks the drawable surface
end()246 void FXDCWindow::end(){
247   if(ctx){
248     ::DeleteObject(::SelectObject((HDC)ctx,oldpen));
249     ::DeleteObject(::SelectObject((HDC)ctx,oldbrush));
250     if(surface->visual->colormap){
251       SelectPalette((HDC)ctx,(HPALETTE)oldpalette,false);
252       }
253     surface->ReleaseDC((HDC)ctx);
254     if(needsClipReset){
255       DWORD dwFlags=GetWindowLong((HWND)surface->id(),GWL_STYLE);
256       SetWindowLong((HWND)surface->id(),GWL_STYLE,dwFlags|WS_CLIPCHILDREN);
257       }
258     ctx=NULL;
259     }
260   surface=NULL;
261   }
262 
263 
264 // Read back pixel
readPixel(FXint x,FXint y)265 FXColor FXDCWindow::readPixel(FXint x,FXint y){
266   FXColor color=FXRGBA(0,0,0,0);
267   if(!surface){ fxerror("FXDCWindow::readPixel: DC not connected to drawable.\n"); }
268   if(0<=x && 0<=y && x<surface->getWidth() && y<surface->getHeight()){
269     COLORREF clr=GetPixel((HDC)ctx,x,y);
270     color=FXRGB(GetRValue(clr),GetGValue(clr),GetBValue(clr));
271     }
272   return color;
273   }
274 
275 
276 // Draw pixel in current foreground color
drawPoint(FXint x,FXint y)277 void FXDCWindow::drawPoint(FXint x,FXint y){
278   if(!surface){ fxerror("FXDCWindow::drawPoint: DC not connected to drawable.\n"); }
279   ::SetPixel((HDC)ctx,x,y,devfg);
280   }
281 
282 
283 // Draw points
drawPoints(const FXPoint * points,FXuint npoints)284 void FXDCWindow::drawPoints(const FXPoint* points,FXuint npoints){
285   FXuint i;
286   if(!surface){ fxerror("FXDCWindow::drawPoints: DC not connected to drawable.\n"); }
287   for(i=0; i<npoints; i++){
288     ::SetPixel((HDC)ctx,points[i].x,points[i].y,devfg);
289     }
290   }
291 
292 
293 // Draw points relative
drawPointsRel(const FXPoint * points,FXuint npoints)294 void FXDCWindow::drawPointsRel(const FXPoint* points,FXuint npoints){
295   int x=0,y=0;
296   FXuint i;
297   if(!surface){ fxerror("FXDCWindow::drawPointsRel: DC not connected to drawable.\n"); }
298   for(i=0; i<npoints; i++){
299     x+=points[i].x;
300     y+=points[i].y;
301     ::SetPixel((HDC)ctx,x,y,devfg);
302     }
303   }
304 
305 
306 // Draw line
drawLine(FXint x1,FXint y1,FXint x2,FXint y2)307 void FXDCWindow::drawLine(FXint x1,FXint y1,FXint x2,FXint y2){
308   if(!surface){ fxerror("FXDCWindow::drawLine: DC not connected to drawable.\n"); }
309   if(needsNewPen) updatePen();
310   if(needsPath){
311     ::BeginPath((HDC)ctx);
312     }
313   POINT pts[2];
314   pts[0].x=x1; pts[0].y=y1;
315   pts[1].x=x2; pts[1].y=y2;
316   ::Polyline((HDC)ctx,pts,2);
317   if(needsPath){
318     ::EndPath((HDC)ctx);
319     ::StrokePath((HDC)ctx);
320     }
321   }
322 
323 
324 // Draw lines
drawLines(const FXPoint * points,FXuint npoints)325 void FXDCWindow::drawLines(const FXPoint* points,FXuint npoints){
326   FXuint i;
327   POINT pts[1360];      // Worst case limit according to MSDN
328   if(!surface){ fxerror("FXDCWindow::drawLines: DC not connected to drawable.\n"); }
329   if(needsNewPen) updatePen();
330   if(needsPath){
331     ::BeginPath((HDC)ctx);
332     }
333   if(1360<=npoints){
334     ::MoveToEx((HDC)ctx,points[0].x,points[0].y,NULL);
335     for(i=1; i<npoints; i++) ::LineTo((HDC)ctx,points[i].x,points[i].y);
336     }
337   else{
338     for(i=0; i<npoints; i++){
339       pts[i].x=points[i].x;
340       pts[i].y=points[i].y;
341       }
342     ::Polyline((HDC)ctx,pts,npoints);
343     }
344   if(needsPath){
345     ::EndPath((HDC)ctx);
346     ::StrokePath((HDC)ctx);
347     }
348   }
349 
350 
351 // Draw lines relative
drawLinesRel(const FXPoint * points,FXuint npoints)352 void FXDCWindow::drawLinesRel(const FXPoint* points,FXuint npoints){
353   int x=0,y=0;
354   FXuint i;
355   POINT pts[1360];      // Worst case limit according to MSDN
356   if(!surface){ fxerror("FXDCWindow::drawLinesRel: DC not connected to drawable.\n"); }
357   if(needsNewPen) updatePen();
358   if(needsPath){
359     ::BeginPath((HDC)ctx);
360     }
361   if(1360<=npoints){
362     ::MoveToEx((HDC)ctx,points[0].x,points[0].y,NULL);
363     for(i=1; i<npoints; i++){
364       x+=points[i].x;
365       y+=points[i].y;
366       ::LineTo((HDC)ctx,x,y);
367       }
368     }
369   else{
370     for(i=0; i<npoints; i++){
371       x+=points[i].x; pts[i].x=x;
372       y+=points[i].y; pts[i].y=y;
373       }
374     ::Polyline((HDC)ctx,pts,npoints);
375     }
376   if(needsPath){
377     ::EndPath((HDC)ctx);
378     ::StrokePath((HDC)ctx);
379     }
380   }
381 
382 
383 // Draw line segments
drawLineSegments(const FXSegment * segments,FXuint nsegments)384 void FXDCWindow::drawLineSegments(const FXSegment* segments,FXuint nsegments){
385   FXuint i;
386   POINT pts[2];
387   if(!surface){ fxerror("FXDCWindow::drawLineSegments: DC not connected to drawable.\n"); }
388   if(needsNewPen) updatePen();
389   if(needsPath){
390     ::BeginPath((HDC)ctx);
391     }
392   for(i=0; i<nsegments; i++){
393     pts[0].x=segments[i].x1; pts[0].y=segments[i].y1;
394     pts[1].x=segments[i].x2; pts[1].y=segments[i].y2;
395     ::Polyline((HDC)ctx,pts,2);
396     }
397   if(needsPath){
398     ::EndPath((HDC)ctx);
399     ::StrokePath((HDC)ctx);
400     }
401   }
402 
403 
404 // Unfilled rectangle
drawRectangle(FXint x,FXint y,FXint w,FXint h)405 void FXDCWindow::drawRectangle(FXint x,FXint y,FXint w,FXint h){
406   if(!surface){ fxerror("FXDCWindow::drawRectangle: DC not connected to drawable.\n"); }
407   if(needsNewPen) updatePen();
408   HBRUSH hbrush=(HBRUSH)::SelectObject((HDC)ctx,(HBRUSH)GetStockObject(NULL_BRUSH));
409   ::Rectangle((HDC)ctx,x,y,x+w+1,y+h+1);
410   ::SelectObject((HDC)ctx,hbrush);
411   }
412 
413 
414 // Draw unfilled rectangles
drawRectangles(const FXRectangle * rectangles,FXuint nrectangles)415 void FXDCWindow::drawRectangles(const FXRectangle* rectangles,FXuint nrectangles){
416   FXuint i;
417   if(!surface){ fxerror("FXDCWindow::drawRectangles: DC not connected to drawable.\n"); }
418   if(needsNewPen) updatePen();
419   HBRUSH hbrush=(HBRUSH)::SelectObject((HDC)ctx,(HBRUSH)GetStockObject(NULL_BRUSH));
420   for(i=0; i<nrectangles; i++){
421     ::Rectangle((HDC)ctx,rectangles[i].x,rectangles[i].y,rectangles[i].x+rectangles[i].w+1,rectangles[i].y+rectangles[i].h+1);
422     }
423   ::SelectObject((HDC)ctx,hbrush);
424   }
425 
426 
427 // Unfilled rounded rectangle
drawRoundRectangle(FXint x,FXint y,FXint w,FXint h,FXint ew,FXint eh)428 void FXDCWindow::drawRoundRectangle(FXint x,FXint y,FXint w,FXint h,FXint ew,FXint eh){
429   if(!surface){ fxerror("FXDCWindow::drawRoundRectangle: DC not connected to drawable.\n"); }
430   if(needsNewPen) updatePen();
431   HBRUSH hbrush=(HBRUSH)::SelectObject((HDC)ctx,(HBRUSH)GetStockObject(NULL_BRUSH));
432   if(ew+ew>w) ew=w>>1;
433   if(eh+eh>h) eh=h>>1;
434   ::RoundRect((HDC)ctx,x,y,x+w+1,y+h+1,ew,eh);
435   ::SelectObject((HDC)ctx,hbrush);
436   }
437 
438 
439 // Draw arc; angles in degrees*64, ang2 relative to ang1
440 // If angle is negative flip the start and end; also, if ang2 is zero,
441 // don't draw anything at all (patch: Sander Jansen <sander@knology.net>).
drawArc(FXint x,FXint y,FXint w,FXint h,FXint ang1,FXint ang2)442 void FXDCWindow::drawArc(FXint x,FXint y,FXint w,FXint h,FXint ang1,FXint ang2){
443   FXbool reversed=(ang2<0);
444   if(!surface){ fxerror("FXDCWindow::drawArc: DC not connected to drawable.\n"); }
445   if(ang2==0) return;
446   if(needsNewPen) updatePen();
447   ang2+=ang1;
448   w+=1;
449   h+=1;
450   int xStart=int(x+0.5*w+w*Math::cos(ang1*PI/(180.0*64.0)));
451   int yStart=int(y+0.5*h-h*Math::sin(ang1*PI/(180.0*64.0)));
452   int xEnd=int(x+0.5*w+w*Math::cos(ang2*PI/(180.0*64.0)));
453   int yEnd=int(y+0.5*h-h*Math::sin(ang2*PI/(180.0*64.0)));
454   if(needsPath){
455     ::BeginPath((HDC)ctx);
456     }
457   if(reversed)
458     ::Arc((HDC)ctx,x,y,x+w,y+h,xEnd,yEnd,xStart,yStart);
459   else
460     ::Arc((HDC)ctx,x,y,x+w,y+h,xStart,yStart,xEnd,yEnd);
461   if(needsPath){
462     ::EndPath((HDC)ctx);
463     ::StrokePath((HDC)ctx);
464     }
465   }
466 
467 
468 // Draw arcs
drawArcs(const FXArc * arcs,FXuint narcs)469 void FXDCWindow::drawArcs(const FXArc* arcs,FXuint narcs){
470   FXuint i;
471   if(!surface){ fxerror("FXDCWindow::drawArcs: DC not connected to drawable.\n"); }
472   for(i=0; i<narcs; i++){
473     drawArc(arcs[i].x,arcs[i].y,arcs[i].w,arcs[i].h,arcs[i].a,arcs[i].b);
474     }
475   }
476 
477 
478 // Draw ellipse
drawEllipse(FXint x,FXint y,FXint w,FXint h)479 void FXDCWindow::drawEllipse(FXint x,FXint y,FXint w,FXint h){
480   if(!surface){ fxerror("FXDCWindow::drawEllipse: DC not connected to drawable.\n"); }
481   if(needsNewBrush) updateBrush();
482   if(needsNewPen) updatePen();
483   w+=1;
484   h+=1;
485   if(needsPath){
486     ::BeginPath((HDC)ctx);
487     }
488   ::Arc((HDC)ctx,x,y,x+w,y+h,x+(w>>1),y+(h>>1),x+(w>>1),y+(h>>1));
489   if(needsPath){
490     ::EndPath((HDC)ctx);
491     ::StrokePath((HDC)ctx);
492     }
493   }
494 
495 
496 // Fill using currently selected ROP code
fillRectangle(FXint x,FXint y,FXint w,FXint h)497 void FXDCWindow::fillRectangle(FXint x,FXint y,FXint w,FXint h){
498   if(!surface){ fxerror("FXDCWindow::fillRectangle: DC not connected to drawable.\n"); }
499   if(needsNewBrush) updateBrush();
500   HPEN hpen=(HPEN)::SelectObject((HDC)ctx,GetStockObject(NULL_PEN));
501   ::Rectangle((HDC)ctx,x,y,x+w+1,y+h+1);
502   ::SelectObject((HDC)ctx,hpen);
503   }
504 
505 
506 // Fill using currently selected ROP code
fillRectangles(const FXRectangle * rectangles,FXuint nrectangles)507 void FXDCWindow::fillRectangles(const FXRectangle* rectangles,FXuint nrectangles){
508   FXuint i;
509   if(!surface){ fxerror("FXDCWindow::fillRectangles: DC not connected to drawable.\n"); }
510   if(needsNewBrush) updateBrush();
511   HPEN hpen=(HPEN)::SelectObject((HDC)ctx,GetStockObject(NULL_PEN));
512   for(i=0; i<nrectangles; i++){
513     ::Rectangle((HDC)ctx,rectangles[i].x,rectangles[i].y,rectangles[i].x+rectangles[i].w+1,rectangles[i].y+rectangles[i].h+1);
514     }
515   ::SelectObject((HDC)ctx,hpen);
516   }
517 
518 
519 // Fill using currently selected ROP mode
fillRoundRectangle(FXint x,FXint y,FXint w,FXint h,FXint ew,FXint eh)520 void FXDCWindow::fillRoundRectangle(FXint x,FXint y,FXint w,FXint h,FXint ew,FXint eh){
521   if(!surface){ fxerror("FXDCWindow::fillRoundRectangle: DC not connected to drawable.\n"); }
522   if(needsNewBrush) updateBrush();
523   HPEN hpen=(HPEN)::SelectObject((HDC)ctx,GetStockObject(NULL_PEN));
524   if(ew+ew>w) ew=w>>1;
525   if(eh+eh>h) eh=h>>1;
526   ::RoundRect((HDC)ctx,x,y,x+w+1,y+h+1,ew,eh);
527   ::SelectObject((HDC)ctx,hpen);
528   }
529 
530 
531 // Fill chord
fillChord(FXint x,FXint y,FXint w,FXint h,FXint ang1,FXint ang2)532 void FXDCWindow::fillChord(FXint x,FXint y,FXint w,FXint h,FXint ang1,FXint ang2){
533   FXbool reversed=(ang2<0);
534   if(!surface){ fxerror("FXDCWindow::fillChord: DC not connected to drawable.\n"); }
535   if(ang2==0) return;
536   if(needsNewBrush) updateBrush();
537   ang2+=ang1;
538   w+=1;
539   h+=1;
540   int xStart=int(x+0.5*w+w*Math::cos(ang1*PI/(180.0*64.0)));
541   int yStart=int(y+0.5*h-h*Math::sin(ang1*PI/(180.0*64.0)));
542   int xEnd=int(x+0.5*w+w*Math::cos(ang2*PI/(180.0*64.0)));
543   int yEnd=int(y+0.5*h-h*Math::sin(ang2*PI/(180.0*64.0)));
544   HPEN hpen=(HPEN)::SelectObject((HDC)ctx,GetStockObject(NULL_PEN));
545   if(reversed)
546     ::Chord((HDC)ctx,x,y,x+w,y+h,xEnd,yEnd,xStart,yStart);
547   else
548     ::Chord((HDC)ctx,x,y,x+w,y+h,xStart,yStart,xEnd,yEnd);
549   ::SelectObject((HDC)ctx,hpen);
550   }
551 
552 
553 // Fill chords
fillChords(const FXArc * chords,FXuint nchords)554 void FXDCWindow::fillChords(const FXArc* chords,FXuint nchords){
555   FXuint i;
556   if(!surface){ fxerror("FXDCWindow::fillChords: DC not connected to drawable.\n"); }
557   for(i=0; i<nchords; i++){
558     fillChord(chords[i].x,chords[i].y,chords[i].w,chords[i].h,chords[i].a,chords[i].b);
559     }
560   }
561 
562 
563 // Draw filled arc; angles are in degrees*64; ang2 is relative from ang1
564 // If angle is negative flip the start and end; also, if ang2 is zero,
565 // don't draw anything at all (patch: Sander Jansen <sander@knology.net>).
fillArc(FXint x,FXint y,FXint w,FXint h,FXint ang1,FXint ang2)566 void FXDCWindow::fillArc(FXint x,FXint y,FXint w,FXint h,FXint ang1,FXint ang2){
567   FXbool reversed=(ang2<0);
568   if(!surface){ fxerror("FXDCWindow::fillArc: DC not connected to drawable.\n"); }
569   if(ang2==0) return;
570   if(needsNewBrush) updateBrush();
571   ang2+=ang1;
572   w+=1;
573   h+=1;
574   int xStart=int(x+0.5*w+w*Math::cos(ang1*PI/(180.0*64.0)));
575   int yStart=int(y+0.5*h-h*Math::sin(ang1*PI/(180.0*64.0)));
576   int xEnd=int(x+0.5*w+w*Math::cos(ang2*PI/(180.0*64.0)));
577   int yEnd=int(y+0.5*h-h*Math::sin(ang2*PI/(180.0*64.0)));
578   HPEN hpen=(HPEN)::SelectObject((HDC)ctx,GetStockObject(NULL_PEN));
579   if(reversed)
580     ::Pie((HDC)ctx,x,y,x+w,y+h,xEnd,yEnd,xStart,yStart);
581   else
582     ::Pie((HDC)ctx,x,y,x+w,y+h,xStart,yStart,xEnd,yEnd);
583   ::SelectObject((HDC)ctx,hpen);
584   }
585 
586 //Ellipse((HDC)ctx,x,y,x+w,y+h);
587 
588 // Fill arcs
fillArcs(const FXArc * arcs,FXuint narcs)589 void FXDCWindow::fillArcs(const FXArc* arcs,FXuint narcs){
590   FXuint i;
591   if(!surface){ fxerror("FXDCWindow::fillArcs: DC not connected to drawable.\n"); }
592   for(i=0; i<narcs; i++){
593     fillArc(arcs[i].x,arcs[i].y,arcs[i].w,arcs[i].h,arcs[i].a,arcs[i].b);
594     }
595   }
596 
597 
598 // Fill ellipse
fillEllipse(FXint x,FXint y,FXint w,FXint h)599 void FXDCWindow::fillEllipse(FXint x,FXint y,FXint w,FXint h){
600   if(!surface){ fxerror("FXDCWindow::fillEllipse: DC not connected to drawable.\n"); }
601   if(needsNewBrush) updateBrush();
602   w+=1;
603   h+=1;
604   HPEN hpen=(HPEN)::SelectObject((HDC)ctx,GetStockObject(NULL_PEN));
605   ::Pie((HDC)ctx,x,y,x+w,y+h,x+(w>>1),y+(h>>1),x+(w>>1),y+(h>>1));
606   ::SelectObject((HDC)ctx,hpen);
607   }
608 
609 
610 // Filled simple polygon
fillPolygon(const FXPoint * points,FXuint npoints)611 void FXDCWindow::fillPolygon(const FXPoint* points,FXuint npoints){
612   FXuint i;
613   POINT pts[1360];      // Worst case limit according to MSDN
614   if(!surface){ fxerror("FXDCWindow::fillPolygon: DC not connected to drawable.\n"); }
615   if(npoints>=1360){ fxerror("FXDCWindow::fillPolygon: too many points.\n"); }
616   if(needsNewBrush) updateBrush();
617   HPEN hpen=(HPEN)::SelectObject((HDC)ctx,GetStockObject(NULL_PEN));
618   for(i=0; i<npoints; i++){
619     pts[i].x=points[i].x;
620     pts[i].y=points[i].y;
621     }
622   ::Polygon((HDC)ctx,pts,npoints);
623   ::SelectObject((HDC)ctx,hpen);
624   }
625 
626 
627 // Filled concave polygon
fillConcavePolygon(const FXPoint * points,FXuint npoints)628 void FXDCWindow::fillConcavePolygon(const FXPoint* points,FXuint npoints){
629   FXuint i;
630   POINT pts[1360];      // Worst case limit according to MSDN
631   if(!surface){ fxerror("FXDCWindow::fillConcavePolygon: DC not connected to drawable.\n"); }
632   if(npoints>=1360){ fxerror("FXDCWindow::fillConcavePolygon: too many points.\n"); }
633   if(needsNewBrush) updateBrush();
634   HPEN hpen=(HPEN)::SelectObject((HDC)ctx,GetStockObject(NULL_PEN));
635   for(i=0; i<npoints; i++){
636     pts[i].x=points[i].x;
637     pts[i].y=points[i].y;
638     }
639   ::Polygon((HDC)ctx,pts,npoints);
640   ::SelectObject((HDC)ctx,hpen);
641   }
642 
643 
644 // Filled complex polygon relative
fillComplexPolygon(const FXPoint * points,FXuint npoints)645 void FXDCWindow::fillComplexPolygon(const FXPoint* points,FXuint npoints){
646   FXuint i;
647   POINT pts[1360];      // Worst case limit according to MSDN
648   if(!surface){ fxerror("FXDCWindow::fillComplexPolygon: DC not connected to drawable.\n"); }
649   if(npoints>=1360){ fxerror("FXDCWindow::fillComplexPolygon: too many points.\n"); }
650   if(needsNewBrush) updateBrush();
651   HPEN hpen=(HPEN)::SelectObject((HDC)ctx,GetStockObject(NULL_PEN));
652   for(i=0; i<npoints; i++){
653     pts[i].x=points[i].x;
654     pts[i].y=points[i].y;
655     }
656   ::Polygon((HDC)ctx,pts,npoints);
657   ::SelectObject((HDC)ctx,hpen);
658   }
659 
660 
661 // Filled simple polygon with relative points
fillPolygonRel(const FXPoint * points,FXuint npoints)662 void FXDCWindow::fillPolygonRel(const FXPoint* points,FXuint npoints){
663   int x=0,y=0;
664   FXuint i;
665   POINT pts[1360];      // Worst case limit according to MSDN
666   if(!surface){ fxerror("FXDCWindow::fillPolygonRel: DC not connected to drawable.\n"); }
667   if(npoints>=1360){ fxerror("FXDCWindow::fillPolygonRel: too many points.\n"); }
668   if(needsNewBrush) updateBrush();
669   HPEN hpen=(HPEN)::SelectObject((HDC)ctx,GetStockObject(NULL_PEN));
670   for(i=0; i<npoints; i++){
671     x+=points[i].x; pts[i].x=x;
672     y+=points[i].y; pts[i].y=y;
673     }
674   ::Polygon((HDC)ctx,pts,npoints);
675   ::SelectObject((HDC)ctx,hpen);
676   }
677 
678 
679 // Filled concave polygon relative
fillConcavePolygonRel(const FXPoint * points,FXuint npoints)680 void FXDCWindow::fillConcavePolygonRel(const FXPoint* points,FXuint npoints){
681   int x=0,y=0;
682   FXuint i;
683   POINT pts[1360];      // Worst case limit according to MSDN
684   if(!surface){ fxerror("FXDCWindow::fillConcavePolygonRel: DC not connected to drawable.\n"); }
685   if(npoints>=1360){ fxerror("FXDCWindow::fillConcavePolygonRel: too many points.\n"); }
686   if(needsNewBrush) updateBrush();
687   HPEN hpen=(HPEN)::SelectObject((HDC)ctx,GetStockObject(NULL_PEN));
688   for(i=0; i<npoints; i++){
689     x+=points[i].x; pts[i].x=x;
690     y+=points[i].y; pts[i].y=y;
691     }
692   ::Polygon((HDC)ctx,pts,npoints);
693   ::SelectObject((HDC)ctx,hpen);
694   }
695 
696 
697 // Filled complex polygon relative
fillComplexPolygonRel(const FXPoint * points,FXuint npoints)698 void FXDCWindow::fillComplexPolygonRel(const FXPoint* points,FXuint npoints){
699   int x=0,y=0;
700   FXuint i;
701   POINT pts[1360];      // Worst case limit according to MSDN
702   if(!surface){ fxerror("FXDCWindow::fillComplexPolygonRel: DC not connected to drawable.\n"); }
703   if(npoints>=1360){ fxerror("FXDCWindow::fillComplexPolygonRel: too many points.\n"); }
704   if(needsNewBrush) updateBrush();
705   HPEN hpen=(HPEN)::SelectObject((HDC)ctx,GetStockObject(NULL_PEN));
706   for(i=0; i<npoints; i++){
707     x+=points[i].x; pts[i].x=x;
708     y+=points[i].y; pts[i].y=y;
709     }
710   ::Polygon((HDC)ctx,pts,npoints);
711   ::SelectObject((HDC)ctx,hpen);
712   }
713 
714 
715 // Fill vertical gradient rectangle
fillVerticalGradient(FXint x,FXint y,FXint w,FXint h,FXColor top,FXColor bottom)716 void FXDCWindow::fillVerticalGradient(FXint x,FXint y,FXint w,FXint h,FXColor top,FXColor bottom){
717 #if defined(__BORLANDC__) || defined(__WATCOMC__) || defined(__CYGWIN__) || (_MSC_VER >= 1300)
718   TRIVERTEX v[2];
719   GRADIENT_RECT r;
720   r.UpperLeft=0;
721   r.LowerRight=1;
722   v[0].x=x;
723   v[0].y=y;
724   v[0].Red=FXREDVAL(top)<<8;
725   v[0].Green=FXGREENVAL(top)<<8;
726   v[0].Blue=FXBLUEVAL(top)<<8;
727   v[0].Alpha=0xFF00;
728   v[1].x=x+w;
729   v[1].y=y+h;
730   v[1].Red=FXREDVAL(bottom)<<8;
731   v[1].Green=FXGREENVAL(bottom)<<8;
732   v[1].Blue=FXBLUEVAL(bottom)<<8;
733   v[1].Alpha=0xFF00;
734   ::GradientFill((HDC)ctx,v,2,&r,1,GRADIENT_FILL_RECT_V);
735 #endif
736   }
737 
738 
739 // Fill horizontal gradient rectangle
fillHorizontalGradient(FXint x,FXint y,FXint w,FXint h,FXColor left,FXColor right)740 void FXDCWindow::fillHorizontalGradient(FXint x,FXint y,FXint w,FXint h,FXColor left,FXColor right){
741 #if defined(__BORLANDC__) || defined(__WATCOMC__) || defined(__CYGWIN__) || (_MSC_VER >= 1300)
742   TRIVERTEX v[2];
743   GRADIENT_RECT r;
744   r.UpperLeft=0;
745   r.LowerRight=1;
746   v[0].x=x;
747   v[0].y=y;
748   v[0].Red=FXREDVAL(left)<<8;
749   v[0].Green=FXGREENVAL(left)<<8;
750   v[0].Blue=FXBLUEVAL(left)<<8;
751   v[0].Alpha=0xFF00;
752   v[1].x=x+w;
753   v[1].y=y+h;
754   v[1].Red=FXREDVAL(right)<<8;
755   v[1].Green=FXGREENVAL(right)<<8;
756   v[1].Blue=FXBLUEVAL(right)<<8;
757   v[1].Alpha=0xFF00;
758   ::GradientFill((HDC)ctx,v,2,&r,1,GRADIENT_FILL_RECT_H);
759 #endif
760   }
761 
762 
763 // Set text font
setFont(FXFont * fnt)764 void FXDCWindow::setFont(FXFont *fnt){
765   if(!surface){ fxerror("FXDCWindow::setFont: DC not connected to drawable.\n"); }
766   if(!fnt || !fnt->id()){ fxerror("FXDCWindow::setFont: illegal or NULL font specified.\n"); }
767   ::SelectObject((HDC)ctx,fnt->id());
768   font=fnt;
769   }
770 
771 
772 // Draw string with base line starting at x, y
drawText(FXint x,FXint y,const FXchar * string,FXuint length)773 void FXDCWindow::drawText(FXint x,FXint y,const FXchar* string,FXuint length){
774   if(!surface){ fxerror("FXDCWindow::drawText: DC not connected to drawable.\n"); }
775   if(!font){ fxerror("FXDCWindow::drawText: no font selected.\n"); }
776   FXnchar sbuffer[4096];
777   FXint count=utf2ncs(sbuffer,string,ARRAYNUMBER(sbuffer),length);
778   FXint bkmode=::SetBkMode((HDC)ctx,TRANSPARENT);
779   ::TextOutW((HDC)ctx,x,y,sbuffer,count);
780   ::SetBkMode((HDC)ctx,bkmode);
781   }
782 
783 
784 // Draw text starting at x, y over filled background
drawImageText(FXint x,FXint y,const FXchar * string,FXuint length)785 void FXDCWindow::drawImageText(FXint x,FXint y,const FXchar* string,FXuint length){
786   if(!surface){ fxerror("FXDCWindow::drawImageText: DC not connected to drawable.\n"); }
787   if(!font){ fxerror("FXDCWindow::drawImageText: no font selected.\n"); }
788   FXnchar sbuffer[4096];
789   FXint count=utf2ncs(sbuffer,string,ARRAYNUMBER(sbuffer),length);
790   FXint bkmode=::SetBkMode((HDC)ctx,OPAQUE);
791   ::TextOutW((HDC)ctx,x,y,sbuffer,count);
792 //    RECT r;
793 //    r.left=clip.x; r.top=clip.y; r.right=clip.x+clip.w; r.bottom=clip.y+clip.h;
794 //    ExtTextOutW((HDC)ctx,x,y,ETO_OPAQUE|ETO_CLIPPED,&r,sbuffer,count,NULL);
795   ::SetBkMode((HDC)ctx,bkmode);
796   }
797 
798 
799 // Draw string with base line starting at x, y
drawText(FXint x,FXint y,const FXString & string)800 void FXDCWindow::drawText(FXint x,FXint y,const FXString& string){
801   drawText(x,y,string.text(),string.length());
802   }
803 
804 
805 // Draw text starting at x, y over filled background
drawImageText(FXint x,FXint y,const FXString & string)806 void FXDCWindow::drawImageText(FXint x,FXint y,const FXString& string){
807   drawImageText(x,y,string.text(),string.length());
808   }
809 
810 
811 // Draw area from source
812 // Some of these ROP codes do not have names; the full list can be found in the MSDN docs
813 // at Platform SDK/Reference/Appendixes/Win32 Appendixes/Raster Operation Codes/Ternary Raster Operations
drawArea(const FXDrawable * source,FXint sx,FXint sy,FXint sw,FXint sh,FXint dx,FXint dy)814 void FXDCWindow::drawArea(const FXDrawable* source,FXint sx,FXint sy,FXint sw,FXint sh,FXint dx,FXint dy){
815   if(!surface){ fxerror("FXDCWindow::drawArea: DC not connected to drawable.\n"); }
816   if(!source || !source->id()){ fxerror("FXDCWindow::drawArea: illegal source specified.\n"); }
817   HDC shdc=(HDC)source->GetDC();
818   switch(rop){
819     case BLT_CLR:                     // D := 0
820       ::BitBlt((HDC)ctx,dx,dy,sw,sh,shdc,sx,sy,BLACKNESS);
821       break;
822     case BLT_SRC_AND_DST:             // D := S & D
823       ::BitBlt((HDC)ctx,dx,dy,sw,sh,shdc,sx,sy,SRCAND);
824       break;
825     case BLT_SRC_AND_NOT_DST:         // D := S & ~D
826       ::BitBlt((HDC)ctx,dx,dy,sw,sh,shdc,sx,sy,SRCERASE);
827       break;
828     case BLT_SRC:                     // D := S
829       ::BitBlt((HDC)ctx,dx,dy,sw,sh,shdc,sx,sy,SRCCOPY);
830       break;
831     case BLT_NOT_SRC_AND_DST:         // D := ~S & D
832       ::BitBlt((HDC)ctx,dx,dy,sw,sh,shdc,sx,sy,0x220326);
833       break;
834     case BLT_DST:                     // D := D
835       break;
836     case BLT_SRC_XOR_DST:             // D := S ^ D
837       ::BitBlt((HDC)ctx,dx,dy,sw,sh,shdc,sx,sy,SRCINVERT);
838       break;
839     case BLT_SRC_OR_DST:              // D := S | D
840       ::BitBlt((HDC)ctx,dx,dy,sw,sh,shdc,sx,sy,SRCPAINT);
841       break;
842     case BLT_NOT_SRC_AND_NOT_DST:     // D := ~S & ~D  ==  D := ~(S | D)
843       ::BitBlt((HDC)ctx,dx,dy,sw,sh,shdc,sx,sy,NOTSRCERASE);
844       break;
845     case BLT_NOT_SRC_XOR_DST:         // D := ~S ^ D
846       ::BitBlt((HDC)ctx,dx,dy,sw,sh,shdc,sx,sy,0x990066); // Not sure about this one
847       break;
848     case BLT_NOT_DST:                 // D := ~D
849       ::BitBlt((HDC)ctx,dx,dy,sw,sh,shdc,sx,sy,DSTINVERT);
850       break;
851     case BLT_SRC_OR_NOT_DST:          // D := S | ~D
852       ::BitBlt((HDC)ctx,dx,dy,sw,sh,shdc,sx,sy,0xDD0228);
853       break;
854     case BLT_NOT_SRC:                 // D := ~S
855       ::BitBlt((HDC)ctx,dx,dy,sw,sh,shdc,sx,sy,NOTSRCCOPY);
856       break;
857     case BLT_NOT_SRC_OR_DST:          // D := ~S | D
858       ::BitBlt((HDC)ctx,dx,dy,sw,sh,shdc,sx,sy,MERGEPAINT);
859       break;
860     case BLT_NOT_SRC_OR_NOT_DST:      // D := ~S | ~D  ==  ~(S & D)
861       ::BitBlt((HDC)ctx,dx,dy,sw,sh,shdc,sx,sy,0x7700E6);
862       break;
863     case BLT_SET:                     // D := 1
864       ::BitBlt((HDC)ctx,dx,dy,sw,sh,shdc,sx,sy,WHITENESS);
865       break;
866     }
867   source->ReleaseDC(shdc);
868   }
869 
870 
871 // Draw area stretched area from source
drawArea(const FXDrawable * source,FXint sx,FXint sy,FXint sw,FXint sh,FXint dx,FXint dy,FXint dw,FXint dh)872 void FXDCWindow::drawArea(const FXDrawable* source,FXint sx,FXint sy,FXint sw,FXint sh,FXint dx,FXint dy,FXint dw,FXint dh){
873   if(!surface){ fxerror("FXDCWindow::drawArea: DC not connected to drawable.\n"); }
874   if(!source || !source->id()){ fxerror("FXDCWindow::drawArea: illegal source specified.\n"); }
875   HDC shdc=(HDC)source->GetDC();
876   switch(rop){
877     case BLT_CLR:                     // D := 0
878       ::StretchBlt((HDC)ctx,dx,dy,dw,dh,shdc,sx,sy,sw,sh,BLACKNESS);
879       break;
880     case BLT_SRC_AND_DST:             // D := S & D
881       ::StretchBlt((HDC)ctx,dx,dy,dw,dh,shdc,sx,sy,sw,sh,SRCAND);
882       break;
883     case BLT_SRC_AND_NOT_DST:         // D := S & ~D
884       ::StretchBlt((HDC)ctx,dx,dy,dw,dh,shdc,sx,sy,sw,sh,SRCERASE);
885       break;
886     case BLT_SRC:                     // D := S
887       ::StretchBlt((HDC)ctx,dx,dy,dw,dh,shdc,sx,sy,sw,sh,SRCCOPY);
888       break;
889     case BLT_NOT_SRC_AND_DST:         // D := ~S & D
890       ::StretchBlt((HDC)ctx,dx,dy,dw,dh,shdc,sx,sy,sw,sh,0x220326);
891       break;
892     case BLT_DST:                     // D := D
893       break;
894     case BLT_SRC_XOR_DST:             // D := S ^ D
895       ::StretchBlt((HDC)ctx,dx,dy,dw,dh,shdc,sx,sy,sw,sh,SRCINVERT);
896       break;
897     case BLT_SRC_OR_DST:              // D := S | D
898       ::StretchBlt((HDC)ctx,dx,dy,dw,dh,shdc,sx,sy,sw,sh,SRCPAINT);
899       break;
900     case BLT_NOT_SRC_AND_NOT_DST:     // D := ~S & ~D ==  D := ~(S | D)
901       ::StretchBlt((HDC)ctx,dx,dy,dw,dh,shdc,sx,sy,sw,sh,NOTSRCERASE);
902       break;
903     case BLT_NOT_SRC_XOR_DST:         // D := ~S ^ D
904       ::StretchBlt((HDC)ctx,dx,dy,dw,dh,shdc,sx,sy,sw,sh,0x990066); // Not sure about this one
905       break;
906     case BLT_NOT_DST:                 // D := ~D
907       ::StretchBlt((HDC)ctx,dx,dy,dw,dh,shdc,sx,sy,sw,sh,DSTINVERT);
908       break;
909     case BLT_SRC_OR_NOT_DST:          // D := S | ~D
910       ::StretchBlt((HDC)ctx,dx,dy,dw,dh,shdc,sx,sy,sw,sh,0xDD0228);
911       break;
912     case BLT_NOT_SRC:                 // D := ~S
913       ::StretchBlt((HDC)ctx,dx,dy,dw,dh,shdc,sx,sy,sw,sh,NOTSRCCOPY);
914       break;
915     case BLT_NOT_SRC_OR_DST:          // D := ~S | D
916       ::StretchBlt((HDC)ctx,dx,dy,dw,dh,shdc,sx,sy,sw,sh,MERGEPAINT);
917       break;
918     case BLT_NOT_SRC_OR_NOT_DST:      // D := ~S | ~D ==  ~(S & D)
919       ::StretchBlt((HDC)ctx,dx,dy,dw,dh,shdc,sx,sy,sw,sh,0x7700E6);
920       break;
921     case BLT_SET:                     // D := 1
922       ::StretchBlt((HDC)ctx,dx,dy,dw,dh,shdc,sx,sy,sw,sh,WHITENESS);
923       break;
924     }
925   source->ReleaseDC(shdc);
926   }
927 
928 
929 // Draw image
drawImage(const FXImage * image,FXint dx,FXint dy)930 void FXDCWindow::drawImage(const FXImage* image,FXint dx,FXint dy){
931   if(!surface){ fxerror("FXDCWindow::drawImage: DC not connected to drawable.\n"); }
932   if(!image || !image->id()){ fxerror("FXDCWindow::drawImage: illegal image specified.\n"); }
933   HDC dcMem=(HDC)image->GetDC();
934   switch(rop){
935     case BLT_CLR:                     // D := 0
936       ::BitBlt((HDC)ctx,dx,dy,image->width,image->height,dcMem,0,0,BLACKNESS);
937       break;
938     case BLT_SRC_AND_DST:             // D := S & D
939       ::BitBlt((HDC)ctx,dx,dy,image->width,image->height,dcMem,0,0,SRCAND);
940       break;
941     case BLT_SRC_AND_NOT_DST:         // D := S & ~D
942       ::BitBlt((HDC)ctx,dx,dy,image->width,image->height,dcMem,0,0,SRCERASE);
943       break;
944     case BLT_SRC:                     // D := S
945       ::BitBlt((HDC)ctx,dx,dy,image->width,image->height,dcMem,0,0,SRCCOPY);
946       break;
947     case BLT_NOT_SRC_AND_DST:         // D := ~S & D
948       ::BitBlt((HDC)ctx,dx,dy,image->width,image->height,dcMem,0,0,0x220326);
949       break;
950     case BLT_DST:                     // D := D
951       break;
952     case BLT_SRC_XOR_DST:             // D := S ^ D
953       ::BitBlt((HDC)ctx,dx,dy,image->width,image->height,dcMem,0,0,SRCINVERT);
954       break;
955     case BLT_SRC_OR_DST:              // D := S | D
956       ::BitBlt((HDC)ctx,dx,dy,image->width,image->height,dcMem,0,0,SRCPAINT);
957       break;
958     case BLT_NOT_SRC_AND_NOT_DST:     // D := ~S & ~D  ==  D := ~(S | D)
959       ::BitBlt((HDC)ctx,dx,dy,image->width,image->height,dcMem,0,0,NOTSRCERASE);
960       break;
961     case BLT_NOT_SRC_XOR_DST:         // D := ~S ^ D
962       ::BitBlt((HDC)ctx,dx,dy,image->width,image->height,dcMem,0,0,0x990066); // Not sure about this one
963       break;
964     case BLT_NOT_DST:                 // D := ~D
965       ::BitBlt((HDC)ctx,dx,dy,image->width,image->height,dcMem,0,0,DSTINVERT);
966       break;
967     case BLT_SRC_OR_NOT_DST:          // D := S | ~D
968       ::BitBlt((HDC)ctx,dx,dy,image->width,image->height,dcMem,0,0,0xDD0228);
969       break;
970     case BLT_NOT_SRC:                 // D := ~S
971       ::BitBlt((HDC)ctx,dx,dy,image->width,image->height,dcMem,0,0,NOTSRCCOPY);
972       break;
973     case BLT_NOT_SRC_OR_DST:          // D := ~S | D
974       ::BitBlt((HDC)ctx,dx,dy,image->width,image->height,dcMem,0,0,MERGEPAINT);
975       break;
976     case BLT_NOT_SRC_OR_NOT_DST:      // D := ~S | ~D  ==  ~(S & D)
977       ::BitBlt((HDC)ctx,dx,dy,image->width,image->height,dcMem,0,0,0x7700E6);
978       break;
979     case BLT_SET:                     // D := 1
980       ::BitBlt((HDC)ctx,dx,dy,image->width,image->height,dcMem,0,0,WHITENESS);
981       break;
982 /*
983       BLENDFUNCTION bf;
984       bf.BlendOp=AC_SRC_OVER;   // For RGBA image
985       bf.BlendFlags=0;
986       bf.SourceConstantAlpha=0xff;
987       bf.AlphaFormat=AC_SRC_ALPHA;
988       AlphaBlend((HDC)ctx,dx,dy,image->width,image->height,dcMem,0,0,image->width,image->height,bf);
989 */
990     }
991   image->ReleaseDC(dcMem);
992   }
993 
994 
995 // Draw bitmap
drawBitmap(const FXBitmap * bitmap,FXint dx,FXint dy)996 void FXDCWindow::drawBitmap(const FXBitmap* bitmap,FXint dx,FXint dy) {
997   if(!surface) fxerror("FXDCWindow::drawBitmap: DC not connected to drawable.\n");
998   if(!bitmap || !bitmap->id()) fxerror("FXDCWindow::drawBitmap: illegal bitmap specified.\n");
999   HDC dcMem=(HDC)bitmap->GetDC();
1000   switch(rop){
1001     case BLT_CLR:                     // D := 0
1002       ::BitBlt((HDC)ctx,dx,dy,bitmap->width,bitmap->height,dcMem,0,0,BLACKNESS);
1003       break;
1004     case BLT_SRC_AND_DST:             // D := S & D
1005       ::BitBlt((HDC)ctx,dx,dy,bitmap->width,bitmap->height,dcMem,0,0,SRCAND);
1006       break;
1007     case BLT_SRC_AND_NOT_DST:         // D := S & ~D
1008       ::BitBlt((HDC)ctx,dx,dy,bitmap->width,bitmap->height,dcMem,0,0,SRCERASE);
1009       break;
1010     case BLT_SRC:                     // D := S
1011       ::BitBlt((HDC)ctx,dx,dy,bitmap->width,bitmap->height,dcMem,0,0,SRCCOPY);
1012       break;
1013     case BLT_NOT_SRC_AND_DST:         // D := ~S & D
1014       ::BitBlt((HDC)ctx,dx,dy,bitmap->width,bitmap->height,dcMem,0,0,0x220326);
1015       break;
1016     case BLT_DST:                     // D := D
1017       break;
1018     case BLT_SRC_XOR_DST:             // D := S ^ D
1019       ::BitBlt((HDC)ctx,dx,dy,bitmap->width,bitmap->height,dcMem,0,0,SRCINVERT);
1020       break;
1021     case BLT_SRC_OR_DST:              // D := S | D
1022       ::BitBlt((HDC)ctx,dx,dy,bitmap->width,bitmap->height,dcMem,0,0,SRCPAINT);
1023       break;
1024     case BLT_NOT_SRC_AND_NOT_DST:     // D := ~S & ~D  ==  D := ~(S | D)
1025       ::BitBlt((HDC)ctx,dx,dy,bitmap->width,bitmap->height,dcMem,0,0,NOTSRCERASE);
1026       break;
1027     case BLT_NOT_SRC_XOR_DST:         // D := ~S ^ D
1028       ::BitBlt((HDC)ctx,dx,dy,bitmap->width,bitmap->height,dcMem,0,0,0x990066); // Not sure about this one
1029       break;
1030     case BLT_NOT_DST:                 // D := ~D
1031       ::BitBlt((HDC)ctx,dx,dy,bitmap->width,bitmap->height,dcMem,0,0,DSTINVERT);
1032       break;
1033     case BLT_SRC_OR_NOT_DST:          // D := S | ~D
1034       ::BitBlt((HDC)ctx,dx,dy,bitmap->width,bitmap->height,dcMem,0,0,0xDD0228);
1035       break;
1036     case BLT_NOT_SRC:                 // D := ~S
1037       ::BitBlt((HDC)ctx,dx,dy,bitmap->width,bitmap->height,dcMem,0,0,NOTSRCCOPY);
1038       break;
1039     case BLT_NOT_SRC_OR_DST:          // D := ~S | D
1040       ::BitBlt((HDC)ctx,dx,dy,bitmap->width,bitmap->height,dcMem,0,0,MERGEPAINT);
1041       break;
1042     case BLT_NOT_SRC_OR_NOT_DST:      // D := ~S | ~D  ==  ~(S & D)
1043       ::BitBlt((HDC)ctx,dx,dy,bitmap->width,bitmap->height,dcMem,0,0,0x7700E6);
1044       break;
1045     case BLT_SET:                     // D := 1
1046       ::BitBlt((HDC)ctx,dx,dy,bitmap->width,bitmap->height,dcMem,0,0,WHITENESS);
1047       break;
1048     }
1049   bitmap->ReleaseDC(dcMem);
1050   }
1051 
1052 
1053 // Draw icon
drawIcon(const FXIcon * icon,FXint dx,FXint dy)1054 void FXDCWindow::drawIcon(const FXIcon* icon,FXint dx,FXint dy){
1055   if(!surface){ fxerror("FXDCWindow::drawIcon: DC not connected to drawable.\n"); }
1056   if(!icon || !icon->id() || !icon->shape){ fxerror("FXDCWindow::drawIcon: illegal icon specified.\n"); }
1057   HDC hdcsrc=(HDC)icon->GetDC();
1058   if(icon->getOptions()&IMAGE_OPAQUE){
1059     ::BitBlt((HDC)ctx,dx,dy,icon->getWidth(),icon->getHeight(),hdcsrc,0,0,SRCCOPY);
1060     }
1061   else{
1062     HDC hdcmsk=::CreateCompatibleDC((HDC)ctx);
1063     HBITMAP holdbmp=(HBITMAP)::SelectObject(hdcmsk,(HBITMAP)icon->shape);
1064     COLORREF coldback=::SetBkColor((HDC)ctx,RGB(255,255,255));
1065     COLORREF coldtext=::SetTextColor((HDC)ctx,RGB(0,0,0));
1066     ::BitBlt((HDC)ctx,dx,dy,icon->getWidth(),icon->getHeight(),hdcmsk,0,0,SRCAND);
1067     ::BitBlt((HDC)ctx,dx,dy,icon->getWidth(),icon->getHeight(),hdcsrc,0,0,SRCPAINT);
1068     ::SelectObject(hdcmsk,holdbmp);
1069     ::DeleteDC(hdcmsk);
1070     ::SetBkColor((HDC)ctx,coldback);
1071     ::SetTextColor((HDC)ctx,coldtext);
1072     }
1073   icon->ReleaseDC(hdcsrc);
1074   }
1075 
1076 
1077 // This may be done faster, I suspect; but I'm tired of looking at this now;
1078 // at least it's correct as it stands..
drawIconShaded(const FXIcon * icon,FXint dx,FXint dy)1079 void FXDCWindow::drawIconShaded(const FXIcon* icon,FXint dx,FXint dy){
1080   if(!surface){ fxerror("FXDCWindow::drawIconShaded: DC not connected to drawable.\n"); }
1081   if(!icon || !icon->id() || !icon->shape){ fxerror("FXDCWindow::drawIconShaded: illegal icon specified.\n"); }
1082   FXColor selbackColor=getApp()->getSelbackColor();
1083   HDC hdcsrc=(HDC)icon->GetDC();
1084   HDC hdcmsk=::CreateCompatibleDC((HDC)ctx);
1085 
1086   // Set shape mask
1087   HBITMAP holdbmp=(HBITMAP)::SelectObject(hdcmsk,(HBITMAP)icon->shape);
1088 
1089   // Set colors
1090   COLORREF coldback=::SetBkColor((HDC)ctx,RGB(255,255,255));
1091   COLORREF coldtext=::SetTextColor((HDC)ctx,RGB(0,0,0));
1092 
1093   // Paint icon
1094   ::BitBlt((HDC)ctx,dx,dy,icon->getWidth(),icon->getHeight(),hdcmsk,0,0,SRCAND);
1095   ::BitBlt((HDC)ctx,dx,dy,icon->getWidth(),icon->getHeight(),hdcsrc,0,0,SRCPAINT);
1096 
1097   // Select brush
1098   HBRUSH hbrush=::CreatePatternBrush((HBITMAP)getApp()->stipples[STIPPLE_GRAY]);
1099   HBRUSH holdbrush=(HBRUSH)::SelectObject((HDC)ctx,hbrush);
1100   ::SetBrushOrgEx((HDC)ctx,dx,dy,NULL);
1101 
1102   // Make black where pattern is 0 and shape is 0 [DPSoa]
1103   ::BitBlt((HDC)ctx,dx,dy,icon->getWidth(),icon->getHeight(),hdcmsk,0,0,0x00A803A9);
1104 
1105   // Set colors
1106   ::SetTextColor((HDC)ctx,RGB(FXREDVAL(selbackColor),FXGREENVAL(selbackColor),FXBLUEVAL(selbackColor)));
1107   ::SetBkColor((HDC)ctx,RGB(0,0,0));
1108 
1109   // Make selbackcolor where pattern is 0 and shape is 0 [DPSoo]
1110   ::BitBlt((HDC)ctx,dx,dy,icon->getWidth(),icon->getHeight(),hdcmsk,0,0,0x00FE02A9);
1111 
1112   // Resetore ctx
1113   ::SelectObject(hdcmsk,holdbmp);
1114   ::DeleteDC(hdcmsk);
1115   ::SelectObject((HDC)ctx,holdbrush);
1116   ::DeleteObject(hbrush);
1117   ::SetBkColor((HDC)ctx,coldback);
1118   ::SetTextColor((HDC)ctx,coldtext);
1119   ::SetBrushOrgEx((HDC)ctx,tx,ty,NULL);
1120   icon->ReleaseDC(hdcsrc);
1121   }
1122 
1123 
1124 
1125 // Draw a sunken or etched-in icon.
drawIconSunken(const FXIcon * icon,FXint dx,FXint dy)1126 void FXDCWindow::drawIconSunken(const FXIcon* icon,FXint dx,FXint dy){
1127   if(!surface){ fxerror("FXDCWindow::drawIconSunken: DC not connected to drawable.\n"); }
1128   if(!icon || !icon->id() || !icon->shape){ fxerror("FXDCWindow::drawIconSunken: illegal icon specified.\n"); }
1129   FXColor shadowColor=getApp()->getShadowColor();
1130   FXColor hiliteColor=getApp()->getHiliteColor();
1131   HDC hdcsrc=(HDC)icon->GetDC();
1132   HDC hdcmono=::CreateCompatibleDC((HDC)ctx);
1133 
1134   // Set etch mask
1135   HBITMAP holdbmp=(HBITMAP)::SelectObject(hdcmono,(HBITMAP)icon->etch);
1136 
1137   // Set colors
1138   COLORREF coldback=::SetBkColor((HDC)ctx,RGB(255,255,255));
1139   COLORREF coldtext=::SetTextColor((HDC)ctx,RGB(0,0,0));
1140 
1141   // While brush colors apply to the pattern
1142   HBRUSH hbrhilite=::CreateSolidBrush(RGB(FXREDVAL(hiliteColor),FXGREENVAL(hiliteColor),FXBLUEVAL(hiliteColor)));
1143   HBRUSH holdbrush=(HBRUSH)::SelectObject((HDC)ctx,hbrhilite);
1144 
1145   // BitBlt the black bits in the monochrome bitmap into highlight colors
1146   // in the destination DC (offset a bit). This BitBlt(), and the next one,
1147   // use an unnamed raster op (0xB8074a) whose effect is D := ((D ^ P) & S) ^ P.
1148   // Or at least I think it is ;) The code = PSDPxax, so that's correct JVZ
1149   ::BitBlt((HDC)ctx,dx+1,dy+1,icon->getWidth(),icon->getHeight(),hdcmono,0,0,0xB8074A);
1150   HBRUSH hbrshadow=::CreateSolidBrush(RGB(FXREDVAL(shadowColor),FXGREENVAL(shadowColor),FXBLUEVAL(shadowColor)));
1151   ::SelectObject((HDC)ctx,hbrshadow);
1152 
1153   // Now BitBlt the black bits in the monochrome bitmap into the
1154   // shadow color on the destination DC.
1155   ::BitBlt((HDC)ctx,dx,dy,icon->getWidth(),icon->getHeight(),hdcmono,0,0,0xB8074A);
1156 
1157   // Resetore ctx
1158   ::SelectObject(hdcmono,holdbmp);
1159   ::DeleteDC(hdcmono);
1160   ::SelectObject((HDC)ctx,holdbrush);
1161   ::DeleteObject(hbrhilite);
1162   ::DeleteObject(hbrshadow);
1163   ::SetBkColor((HDC)ctx,coldback);
1164   ::SetTextColor((HDC)ctx,coldtext);
1165   icon->ReleaseDC(hdcsrc);
1166   }
1167 
1168 
1169 // Draw hash box
drawHashBox(FXint x,FXint y,FXint w,FXint h,FXint b)1170 void FXDCWindow::drawHashBox(FXint x,FXint y,FXint w,FXint h,FXint b){
1171   if(!surface){ fxerror("FXDCWindow::drawHashBox: DC not connected to drawable.\n"); }
1172   HBRUSH hbrush=::CreatePatternBrush((HBITMAP)getApp()->stipples[STIPPLE_GRAY]);
1173   HBRUSH holdbrush=(HBRUSH)::SelectObject((HDC)ctx,hbrush);
1174   COLORREF coldback=::SetBkColor((HDC)ctx,RGB(255,255,255));
1175   COLORREF coldtext=::SetTextColor((HDC)ctx,RGB(0,0,0));
1176   ::PatBlt((HDC)ctx,x,y,w-b,b,PATINVERT);
1177   ::PatBlt((HDC)ctx,x+w-b,y,b,h-b,PATINVERT);
1178   ::PatBlt((HDC)ctx,x+b,y+h-b,w-b,b,PATINVERT);
1179   ::PatBlt((HDC)ctx,x,y+b,b,h-b,PATINVERT);
1180   ::SelectObject((HDC)ctx,holdbrush);
1181   ::DeleteObject(hbrush);
1182   ::SetBkColor((HDC)ctx,coldback);
1183   ::SetTextColor((HDC)ctx,coldtext);
1184   }
1185 
1186 
1187 // Draw focus rectangle
drawFocusRectangle(FXint x,FXint y,FXint w,FXint h)1188 void FXDCWindow::drawFocusRectangle(FXint x,FXint y,FXint w,FXint h){
1189   if(!surface){ fxerror("FXDCWindow::drawFocusRectangle: DC not connected to drawable.\n"); }
1190   HBRUSH hbrush=::CreatePatternBrush((HBITMAP)getApp()->stipples[STIPPLE_GRAY]);
1191   HBRUSH holdbrush=(HBRUSH)::SelectObject((HDC)ctx,hbrush);
1192   COLORREF coldback=::SetBkColor((HDC)ctx,RGB(255,255,255));
1193   COLORREF coldtext=::SetTextColor((HDC)ctx,RGB(0,0,0));
1194   ::SetBrushOrgEx((HDC)ctx,x,y,NULL);
1195   ::PatBlt((HDC)ctx,x,y,w-1,1,PATINVERT);
1196   ::PatBlt((HDC)ctx,x+w-1,y,1,h-1,PATINVERT);
1197   ::PatBlt((HDC)ctx,x+1,y+h-1,w-1,1,PATINVERT);
1198   ::PatBlt((HDC)ctx,x,y+1,1,h-1,PATINVERT);
1199   ::SelectObject((HDC)ctx,holdbrush);
1200   ::DeleteObject(hbrush);
1201   ::SetBkColor((HDC)ctx,coldback);
1202   ::SetTextColor((HDC)ctx,coldtext);
1203   ::SetBrushOrgEx((HDC)ctx,tx,ty,NULL);
1204   }
1205 
1206 
FXStipplePattern2Hatch(FXStipplePattern pat)1207 static DWORD FXStipplePattern2Hatch(FXStipplePattern pat){
1208   switch(pat){
1209     case STIPPLE_HORZ: return HS_HORIZONTAL;
1210     case STIPPLE_VERT: return HS_VERTICAL;
1211     case STIPPLE_CROSS: return HS_CROSS;
1212     case STIPPLE_DIAG: return HS_BDIAGONAL;
1213     case STIPPLE_REVDIAG: return HS_FDIAGONAL;
1214     case STIPPLE_CROSSDIAG: return HS_DIAGCROSS;
1215     default: return HS_CROSS;
1216     }
1217   }
1218 
1219 
updatePen()1220 void FXDCWindow::updatePen(){
1221   DWORD dashes[32];
1222   DWORD penstyle,i;
1223   LOGBRUSH lb;
1224 
1225   // Setup brush of this pen
1226   switch(fill){
1227     case FILL_SOLID:
1228       lb.lbStyle=BS_SOLID;
1229       lb.lbColor=devfg;
1230       lb.lbHatch=0;
1231       break;
1232     case FILL_TILED:
1233       lb.lbStyle=BS_SOLID;
1234       lb.lbColor=devfg;
1235       lb.lbHatch=0;
1236       break;
1237     case FILL_STIPPLED:
1238       if(stipple){
1239         lb.lbStyle=BS_PATTERN;
1240         lb.lbColor=devfg;
1241         lb.lbHatch=(FXuval)stipple->id();    // This should be a HBITMAP
1242         }
1243       else if(pattern>=STIPPLE_0 && pattern<=STIPPLE_16){
1244         lb.lbStyle=BS_PATTERN;
1245         lb.lbColor=devfg;
1246         lb.lbHatch=(FXuval)getApp()->stipples[pattern];
1247         }
1248       else{
1249         lb.lbStyle=BS_HATCHED;
1250         lb.lbColor=devfg;
1251         lb.lbHatch=FXStipplePattern2Hatch(pattern);
1252         }
1253       break;
1254     case FILL_OPAQUESTIPPLED:
1255       if(stipple){
1256         lb.lbStyle=BS_PATTERN;
1257         lb.lbColor=devfg;
1258         lb.lbHatch=(FXuval)stipple->id();    // This should be a HBITMAP
1259         }
1260       else if(pattern>=STIPPLE_0 && pattern<=STIPPLE_16){
1261         lb.lbStyle=BS_PATTERN;
1262         lb.lbColor=devfg;
1263         lb.lbHatch=(FXuval)getApp()->stipples[pattern];
1264         }
1265       else{
1266         lb.lbStyle=BS_HATCHED;
1267         lb.lbColor=devfg;
1268         lb.lbHatch=FXStipplePattern2Hatch(pattern);
1269         }
1270       break;
1271     }
1272 
1273   penstyle=0;
1274 
1275   // Cap style
1276   if(cap==CAP_ROUND)
1277     penstyle|=PS_JOIN_ROUND;
1278   else if(cap==CAP_PROJECTING)
1279     penstyle|=PS_ENDCAP_SQUARE;
1280   else
1281     penstyle|=PS_ENDCAP_FLAT;
1282 
1283   // Join style
1284   if(join==JOIN_MITER)
1285     penstyle|=PS_JOIN_MITER;
1286   else if(join==JOIN_ROUND)
1287     penstyle|=PS_JOIN_ROUND;
1288   else
1289     penstyle|=PS_JOIN_BEVEL;
1290 
1291   // Kind of pen
1292   //if(width<=1 && fill==FILL_SOLID)
1293   //  penstyle|=PS_COSMETIC;
1294   //else
1295     penstyle|=PS_GEOMETRIC;
1296 
1297   // Line style
1298   if(style==LINE_SOLID){
1299     penstyle|=PS_SOLID;
1300     ::DeleteObject(::SelectObject((HDC)ctx,::ExtCreatePen(penstyle,width,&lb,0,NULL)));
1301     }
1302   else if(dashoff==0 && dashlen==2 && dashpat[0]==1 && dashpat[1]==1){
1303     penstyle|=PS_DOT;
1304     ::DeleteObject(::SelectObject((HDC)ctx,::ExtCreatePen(penstyle,width,&lb,0,NULL)));
1305     }
1306   else if(dashoff==0 && dashlen==2 && dashpat[0]==3 && dashpat[1]==1){
1307     penstyle|=PS_DASH;
1308     ::DeleteObject(::SelectObject((HDC)ctx,::ExtCreatePen(penstyle,width,&lb,0,NULL)));
1309     }
1310   else if(dashoff==0 && dashlen==4 && dashpat[0]==3 && dashpat[1]==1 && dashpat[2]==1 && dashpat[3]==1){
1311     penstyle|=PS_DASHDOT;
1312     ::DeleteObject(::SelectObject((HDC)ctx,::ExtCreatePen(penstyle,width,&lb,0,NULL)));
1313     }
1314   else if(dashoff==0 && dashlen==6 && dashpat[0]==3 && dashpat[1]==1 && dashpat[2]==1 && dashpat[3]==1 && dashpat[4]==1 && dashpat[5]==1){
1315     penstyle|=PS_DASHDOTDOT;
1316     ::DeleteObject(::SelectObject((HDC)ctx,::ExtCreatePen(penstyle,width,&lb,0,NULL)));
1317     }
1318   else{
1319     penstyle|=PS_USERSTYLE;
1320     for(i=0; i<dashlen; i++){ dashes[i]=dashpat[(i+dashoff)%dashlen]; }
1321     ::DeleteObject(::SelectObject((HDC)ctx,::ExtCreatePen(penstyle,width,&lb,dashlen,dashes)));
1322     }
1323   if(fill==FILL_STIPPLED){
1324     ::SetBkMode((HDC)ctx,TRANSPARENT);         // Alas, only works for BS_HATCHED...
1325     }
1326   else{
1327     ::SetBkMode((HDC)ctx,OPAQUE);
1328     }
1329   if(fill!=FILL_SOLID){
1330     ::SetBrushOrgEx((HDC)ctx,tx,ty,NULL);
1331     }
1332   needsPath=(width>1);
1333   needsNewPen=false;
1334   }
1335 
1336 
updateBrush()1337 void FXDCWindow::updateBrush(){
1338   LOGBRUSH lb;
1339   switch(fill){
1340     case FILL_SOLID:
1341       lb.lbStyle=BS_SOLID;
1342       lb.lbColor=devfg;
1343       lb.lbHatch=0;
1344       ::DeleteObject(::SelectObject((HDC)ctx,::CreateBrushIndirect(&lb)));
1345       break;
1346     case FILL_TILED:
1347       if(tile){
1348         ::DeleteObject(::SelectObject((HDC)ctx,::CreatePatternBrush((HBITMAP)tile->id())));
1349         }
1350       else{
1351         lb.lbStyle=BS_SOLID;
1352         lb.lbColor=devfg;
1353         lb.lbHatch=0;
1354         ::DeleteObject(::SelectObject((HDC)ctx,::CreateBrushIndirect(&lb)));
1355         }
1356       break;
1357     case FILL_STIPPLED:
1358       if(stipple){
1359         lb.lbStyle=BS_PATTERN;
1360         lb.lbColor=devfg;
1361         lb.lbHatch=(FXuval)stipple->id();     // This should be a HBITMAP
1362         }
1363       else if(pattern>=STIPPLE_0 && pattern<=STIPPLE_16){
1364         lb.lbStyle=BS_PATTERN;
1365         lb.lbColor=devfg;
1366         lb.lbHatch=(FXuval)getApp()->stipples[pattern];
1367         }
1368       else{
1369         lb.lbStyle=BS_HATCHED;
1370         lb.lbColor=devfg;
1371         lb.lbHatch=FXStipplePattern2Hatch(pattern);
1372         }
1373       ::DeleteObject(::SelectObject((HDC)ctx,::CreateBrushIndirect(&lb)));
1374       break;
1375     case FILL_OPAQUESTIPPLED:
1376       if(stipple){
1377         lb.lbStyle=BS_PATTERN;
1378         lb.lbColor=devfg;
1379         lb.lbHatch=(FXuval)stipple->id();     // This should be a HBITMAP
1380         }
1381       else if(pattern>=STIPPLE_0 && pattern<=STIPPLE_16){
1382         lb.lbStyle=BS_PATTERN;
1383         lb.lbColor=devfg;
1384         lb.lbHatch=(FXuval)getApp()->stipples[pattern];
1385         }
1386       else{
1387         lb.lbStyle=BS_HATCHED;
1388         lb.lbColor=devfg;
1389         lb.lbHatch=FXStipplePattern2Hatch(pattern);
1390         }
1391       ::DeleteObject(::SelectObject((HDC)ctx,::CreateBrushIndirect(&lb)));
1392       break;
1393     }
1394   if(fill==FILL_STIPPLED){
1395     ::SetBkMode((HDC)ctx,TRANSPARENT);         // Alas, only works for BS_HATCHED...
1396     }
1397   else{
1398     ::SetBkMode((HDC)ctx,OPAQUE);
1399     }
1400   if(fill!=FILL_SOLID){
1401     ::SetBrushOrgEx((HDC)ctx,tx,ty,NULL);
1402     }
1403   needsNewBrush=false;
1404   }
1405 
1406 
1407 // Set foreground color
setForeground(FXColor clr)1408 void FXDCWindow::setForeground(FXColor clr){
1409   if(!surface){ fxerror("FXDCWindow::setForeground: DC not connected to drawable.\n"); }
1410   devfg=surface->visual->getPixel(clr);
1411   needsNewPen=true;
1412   needsNewBrush=true;
1413   ::SetTextColor((HDC)ctx,devfg);
1414   fg=clr;
1415   }
1416 
1417 
1418 // Set background color
setBackground(FXColor clr)1419 void FXDCWindow::setBackground(FXColor clr){
1420   if(!surface){ fxerror("FXDCWindow::setBackground: DC not connected to drawable.\n"); }
1421   devbg=surface->visual->getPixel(clr);
1422   ::SetBkColor((HDC)ctx,devbg);
1423   bg=clr;
1424   }
1425 
1426 
1427 // Set dash pattern (for the LINE_ONOFF_DASH line style)
setDashes(FXuint dashoffset,const FXchar * dashpattern,FXuint dashlength)1428 void FXDCWindow::setDashes(FXuint dashoffset,const FXchar *dashpattern,FXuint dashlength){
1429   FXuint len,i;
1430   if(!surface){ fxerror("FXDCWindow::setDashes: DC not connected to drawable.\n"); }
1431   if(dashlength>32){ fxerror("FXDCWindow::setDashes: bad dashlength parameter.\n"); }
1432   for(i=len=0; i<dashlength; i++){
1433     dashpat[i]=dashpattern[i];
1434     len+=(FXuint)dashpattern[i];
1435     }
1436   dashlen=dashlength;
1437   dashoff=dashoffset%len;
1438   needsNewPen=true;
1439   }
1440 
1441 
1442 // Set line width
setLineWidth(FXuint linewidth)1443 void FXDCWindow::setLineWidth(FXuint linewidth){
1444   if(!surface){ fxerror("FXDCWindow::setLineWidth: DC not connected to drawable.\n"); }
1445   width=linewidth;
1446   needsNewPen=true;
1447   }
1448 
1449 
1450 // Set line cap style
setLineCap(FXCapStyle capstyle)1451 void FXDCWindow::setLineCap(FXCapStyle capstyle){
1452   if(!surface){ fxerror("FXDCWindow::setLineCap: DC not connected to drawable.\n"); }
1453   cap=capstyle;
1454   needsNewPen=true;
1455   }
1456 
1457 
1458 // Set line join style
setLineJoin(FXJoinStyle joinstyle)1459 void FXDCWindow::setLineJoin(FXJoinStyle joinstyle){
1460   if(!surface){ fxerror("FXDCWindow::setLineJoin: DC not connected to drawable.\n"); }
1461   join=joinstyle;
1462   needsNewPen=true;
1463   }
1464 
1465 
1466 // Set line style
setLineStyle(FXLineStyle linestyle)1467 void FXDCWindow::setLineStyle(FXLineStyle linestyle){
1468   if(!surface){ fxerror("FXDCWindow::setLineStyle: DC not connected to drawable.\n"); }
1469   style=linestyle;
1470   needsNewPen=true;
1471   }
1472 
1473 
1474 // Set fill style
setFillStyle(FXFillStyle fillstyle)1475 void FXDCWindow::setFillStyle(FXFillStyle fillstyle){
1476   if(!surface){ fxerror("FXDCWindow::setFillStyle: DC not connected to drawable.\n"); }
1477   fill=fillstyle;
1478   needsNewBrush=true;
1479   needsNewPen=true;
1480   }
1481 
1482 
1483 // Set fill rule
setFillRule(FXFillRule fillrule)1484 void FXDCWindow::setFillRule(FXFillRule fillrule){
1485   if(!surface){ fxerror("FXDCWindow::setFillRule: DC not connected to drawable.\n"); }
1486   if(fillrule==RULE_EVEN_ODD)
1487     ::SetPolyFillMode((HDC)ctx,ALTERNATE);
1488   else
1489     ::SetPolyFillMode((HDC)ctx,WINDING);
1490   rule=fillrule;
1491   }
1492 
1493 
1494 // Set blit function
setFunction(FXFunction func)1495 void FXDCWindow::setFunction(FXFunction func){
1496   if(!surface){ fxerror("FXDCWindow::setFunction: DC not connected to drawable.\n"); }
1497   rop=func;
1498 
1499   // Also set ROP2 code for lines
1500   switch(rop){
1501     case BLT_CLR:                     // D := 0
1502       ::SetROP2((HDC)ctx,R2_BLACK);
1503       break;
1504     case BLT_SRC_AND_DST:             // D := S & D
1505       ::SetROP2((HDC)ctx,R2_MASKPEN);
1506       break;
1507     case BLT_SRC_AND_NOT_DST:         // D := S & ~D
1508       ::SetROP2((HDC)ctx,R2_MASKPENNOT);
1509       break;
1510     case BLT_SRC:                     // D := S
1511       ::SetROP2((HDC)ctx,R2_COPYPEN);
1512       break;
1513     case BLT_NOT_SRC_AND_DST:         // D := ~S & D
1514       ::SetROP2((HDC)ctx,R2_MASKNOTPEN);
1515       break;
1516     case BLT_DST:                     // D := D
1517       ::SetROP2((HDC)ctx,R2_NOP);
1518       break;
1519     case BLT_SRC_XOR_DST:             // D := S ^ D
1520       ::SetROP2((HDC)ctx,R2_XORPEN);
1521       break;
1522     case BLT_SRC_OR_DST:              // D := S | D
1523       ::SetROP2((HDC)ctx,R2_MERGEPEN);
1524       break;
1525     case BLT_NOT_SRC_AND_NOT_DST:     // D := ~S & ~D  ==  D := ~(S | D)
1526       ::SetROP2((HDC)ctx,R2_NOTMERGEPEN);
1527       break;
1528     case BLT_NOT_SRC_XOR_DST:         // D := ~S ^ D
1529       ::SetROP2((HDC)ctx,R2_NOTXORPEN); // Is this the right one?
1530       break;
1531     case BLT_NOT_DST:                 // D := ~D
1532       ::SetROP2((HDC)ctx,R2_NOT);
1533       break;
1534     case BLT_SRC_OR_NOT_DST:          // D := S | ~D
1535       ::SetROP2((HDC)ctx,R2_MERGEPENNOT);
1536       break;
1537     case BLT_NOT_SRC:                 // D := ~S
1538       ::SetROP2((HDC)ctx,R2_NOTCOPYPEN);
1539       break;
1540     case BLT_NOT_SRC_OR_DST:          // D := ~S | D
1541       ::SetROP2((HDC)ctx,R2_MERGENOTPEN);
1542       break;
1543     case BLT_NOT_SRC_OR_NOT_DST:      // D := ~S | ~D  ==  ~(S & D)
1544       ::SetROP2((HDC)ctx,R2_NOTMASKPEN);
1545       break;
1546     case BLT_SET:                     // D := 1
1547       ::SetROP2((HDC)ctx,R2_WHITE);
1548       break;
1549     }
1550   }
1551 
1552 
1553 // Set tile image
setTile(FXImage * image,FXint dx,FXint dy)1554 void FXDCWindow::setTile(FXImage* image,FXint dx,FXint dy){
1555   if(!surface){ fxerror("FXDCWindow::setTile: DC not connected to drawable.\n"); }
1556   if(!image || !image->id()){ fxerror("FXDCWindow::setTile: illegal image specified.\n"); }
1557   tile=image;
1558   tx=dx;
1559   ty=dy;
1560   }
1561 
1562 
1563 // Set stipple pattern
setStipple(FXBitmap * bitmap,FXint dx,FXint dy)1564 void FXDCWindow::setStipple(FXBitmap* bitmap,FXint dx,FXint dy){
1565   if(!surface){ fxerror("FXDCWindow::setStipple: DC not connected to drawable.\n"); }
1566   if(!bitmap || !bitmap->id()){ fxerror("FXDCWindow::setStipple: illegal image specified.\n"); }
1567   stipple=bitmap;
1568   pattern=STIPPLE_NONE;
1569   needsNewBrush=true;
1570   needsNewPen=true;
1571   tx=dx;
1572   ty=dy;
1573   }
1574 
1575 
setStipple(FXStipplePattern pat,FXint dx,FXint dy)1576 void FXDCWindow::setStipple(FXStipplePattern pat,FXint dx,FXint dy){
1577   if(!surface){ fxerror("FXDCWindow::setStipple: DC not connected to drawable.\n"); }
1578   stipple=NULL;
1579   pattern=pat;
1580   needsNewBrush=true;
1581   needsNewPen=true;
1582   tx=dx;
1583   ty=dy;
1584   }
1585 
1586 
1587 // Patch from "Dimitris Servis" <servis@deslab.ntua.gr>
1588 // The new clip rectangle should be the intersect of the region
1589 // boundary rectangle and the paint rectangle.
1590 // Another patch from Ivan Markov <ivan.markov@wizcom.bg> to delete
1591 // the region which must be disposed off explicitly.
setClipRegion(const FXRegion & region)1592 void FXDCWindow::setClipRegion(const FXRegion& region){
1593   if(!surface){ fxerror("FXDCWindow::setClipRegion: DC not connected to drawable.\n"); }
1594   FXRectangle rectangle=region.bounds();
1595   clip.x=FXMAX(rectangle.x,rect.x);
1596   clip.y=FXMAX(rectangle.y,rect.y);
1597   clip.w=FXMIN(rectangle.x+rectangle.w,rect.x+rect.w)-clip.x;
1598   clip.h=FXMIN(rectangle.y+rectangle.h,rect.y+rect.h)-clip.y;
1599   if(clip.w<=0) clip.w=0;
1600   if(clip.h<=0) clip.h=0;
1601   HRGN hrgn=::CreateRectRgn(clip.x,clip.y,clip.x+clip.w,clip.y+clip.h);
1602   ::CombineRgn(hrgn,hrgn,(HRGN)region.region,RGN_AND);
1603   ::SelectClipRgn((HDC)ctx,hrgn);
1604   ::DeleteObject(hrgn);
1605   }
1606 
1607 
1608 // Set clip rectangle
setClipRectangle(FXint x,FXint y,FXint w,FXint h)1609 void FXDCWindow::setClipRectangle(FXint x,FXint y,FXint w,FXint h){
1610   if(!surface){ fxerror("FXDCWindow::setClipRectangle: DC not connected to drawable.\n"); }
1611   clip.x=FXMAX(x,rect.x);
1612   clip.y=FXMAX(y,rect.y);
1613   clip.w=FXMIN(x+w,rect.x+rect.w)-clip.x;
1614   clip.h=FXMIN(y+h,rect.y+rect.h)-clip.y;
1615   if(clip.w<=0) clip.w=0;
1616   if(clip.h<=0) clip.h=0;
1617   HRGN hrgn=::CreateRectRgn(clip.x,clip.y,clip.x+clip.w,clip.y+clip.h);
1618   ::SelectClipRgn((HDC)ctx,hrgn);
1619   ::DeleteObject(hrgn);
1620   }
1621 
1622 
1623 // Set clip rectangle
setClipRectangle(const FXRectangle & rectangle)1624 void FXDCWindow::setClipRectangle(const FXRectangle& rectangle){
1625   if(!surface){ fxerror("FXDCWindow::setClipRectangle: DC not connected to drawable.\n"); }
1626   clip.x=FXMAX(rectangle.x,rect.x);
1627   clip.y=FXMAX(rectangle.y,rect.y);
1628   clip.w=FXMIN(rectangle.x+rectangle.w,rect.x+rect.w)-clip.x;
1629   clip.h=FXMIN(rectangle.y+rectangle.h,rect.y+rect.h)-clip.y;
1630   if(clip.w<=0) clip.w=0;
1631   if(clip.h<=0) clip.h=0;
1632   HRGN hrgn=::CreateRectRgn(clip.x,clip.y,clip.x+clip.w,clip.y+clip.h);
1633   ::SelectClipRgn((HDC)ctx,hrgn);
1634   ::DeleteObject(hrgn);
1635   }
1636 
1637 
1638 // Clear clip rectangle
clearClipRectangle()1639 void FXDCWindow::clearClipRectangle(){
1640   if(!surface){ fxerror("FXDCWindow::clearClipRectangle: DC not connected to drawable.\n"); }
1641   clip=rect;
1642   HRGN hrgn=::CreateRectRgn(clip.x,clip.y,clip.x+clip.w,clip.y+clip.h);
1643   ::SelectClipRgn((HDC)ctx,hrgn);
1644   ::DeleteObject(hrgn);
1645   }
1646 
1647 
1648 
1649 // Set clip mask
setClipMask(FXBitmap * bitmap,FXint dx,FXint dy)1650 void FXDCWindow::setClipMask(FXBitmap* bitmap,FXint dx,FXint dy){
1651   if(!surface){ fxerror("FXDCWindow::setClipMask: DC not connected to drawable.\n"); }
1652   if(!bitmap || !bitmap->id()){ fxerror("FXDCWindow::setClipMask: illegal mask specified.\n"); }
1653   FXASSERT(false);
1654   mask=bitmap;
1655   cx=dx;
1656   cy=dy;
1657   }
1658 
1659 
1660 // Clear clip mask
clearClipMask()1661 void FXDCWindow::clearClipMask(){
1662   if(!surface){ fxerror("FXDCWindow::clearClipMask: DC not connected to drawable.\n"); }
1663   FXASSERT(false);
1664   mask=NULL;
1665   cx=0;
1666   cy=0;
1667   }
1668 
1669 
1670 // Window will clip against child windows
clipChildren(FXbool yes)1671 void FXDCWindow::clipChildren(FXbool yes){
1672   if(!surface){ fxerror("FXDCWindow::clipChildren: window has not yet been created.\n"); }
1673   DWORD    dwFlags=::GetWindowLong((HWND)surface->id(),GWL_STYLE);
1674   HPEN     hPen;
1675   HBRUSH   hBrush;
1676   HFONT    hFont;
1677   COLORREF textcolor;
1678   COLORREF backcolor;
1679   FXint    fillmode;
1680   if(yes){
1681     if(!(dwFlags&WS_CLIPCHILDREN)){
1682       if((HWND)surface->id()!=GetDesktopWindow()){
1683         hPen=(HPEN)SelectObject((HDC)ctx,::GetStockObject(NULL_PEN));
1684         hBrush=(HBRUSH)::SelectObject((HDC)ctx,::GetStockObject(NULL_BRUSH));
1685         hFont=(HFONT)::SelectObject((HDC)ctx,::GetStockObject(SYSTEM_FONT));
1686         textcolor=::GetTextColor((HDC)ctx);
1687         backcolor=::GetBkColor((HDC)ctx);
1688         fillmode=::GetPolyFillMode((HDC)ctx);
1689 
1690         ::ReleaseDC((HWND)surface->id(),(HDC)ctx);
1691         ::SetWindowLong((HWND)surface->id(),GWL_STYLE,dwFlags|WS_CLIPCHILDREN);
1692         ctx=::GetDC((HWND)surface->id());
1693 
1694         ::SelectObject((HDC)ctx,hFont);
1695         ::SelectObject((HDC)ctx,hPen);
1696         ::SelectObject((HDC)ctx,hBrush);
1697 
1698         if(surface->visual->colormap){
1699           ::SelectPalette((HDC)ctx,(HPALETTE)surface->visual->colormap,false);
1700           ::RealizePalette((HDC)ctx);
1701           }
1702         ::SetTextAlign((HDC)ctx,TA_BASELINE|TA_LEFT);
1703         ::SetTextColor((HDC)ctx,textcolor);
1704         ::SetBkColor((HDC)ctx,backcolor);
1705         ::SetPolyFillMode((HDC)ctx,fillmode);
1706         needsClipReset=false;
1707         }
1708       }
1709     }
1710   else{
1711     if(dwFlags&WS_CLIPCHILDREN){
1712       if((HWND)surface->id()!=GetDesktopWindow()){
1713         hPen=(HPEN)::SelectObject((HDC)ctx,::GetStockObject(NULL_PEN));
1714         hBrush=(HBRUSH)::SelectObject((HDC)ctx,::GetStockObject(NULL_BRUSH));
1715         hFont=(HFONT)::SelectObject((HDC)ctx,::GetStockObject(SYSTEM_FONT));
1716         textcolor=::GetTextColor((HDC)ctx);
1717         backcolor=::GetBkColor((HDC)ctx);
1718         fillmode=::GetPolyFillMode((HDC)ctx);
1719 
1720         ::ReleaseDC((HWND)surface->id(),(HDC)ctx);
1721         ::SetWindowLong((HWND)surface->id(),GWL_STYLE,dwFlags&~WS_CLIPCHILDREN);
1722         ctx=::GetDC((HWND)surface->id());
1723 
1724         ::SelectObject((HDC)ctx,hFont);
1725         ::SelectObject((HDC)ctx,hPen);
1726         ::SelectObject((HDC)ctx,hBrush);
1727 
1728         if(surface->visual->colormap){
1729           ::SelectPalette((HDC)ctx,(HPALETTE)surface->visual->colormap,false);
1730           ::RealizePalette((HDC)ctx);
1731           }
1732         ::SetTextAlign((HDC)ctx,TA_BASELINE|TA_LEFT);
1733         ::SetTextColor((HDC)ctx,textcolor);
1734         ::SetBkColor((HDC)ctx,backcolor);
1735         ::SetPolyFillMode((HDC)ctx,fillmode);
1736         needsClipReset=true;
1737         }
1738       }
1739     }
1740   }
1741 
1742 /********************************************************************************
1743 *                                    X-Windows                                  *
1744 ********************************************************************************/
1745 
1746 #else
1747 
1748 
1749 // Construct for expose event painting
1750 FXDCWindow::FXDCWindow(FXDrawable* draw,FXEvent* event):FXDC(draw->getApp()),surface(NULL),rect(0,0,0,0),devfg(0),devbg(0){
1751 #ifdef HAVE_XFT_H
1752   xftDraw=NULL;
1753 #endif
1754   begin(draw);
1755   rect.x=clip.x=event->rect.x;
1756   rect.y=clip.y=event->rect.y;
1757   rect.w=clip.w=event->rect.w;
1758   rect.h=clip.h=event->rect.h;
1759   XSetClipRectangles((Display*)getApp()->getDisplay(),(GC)ctx,0,0,(XRectangle*)(void*)&clip,1,Unsorted);
1760 #ifdef HAVE_XFT_H
1761   XftDrawSetClipRectangles((XftDraw*)xftDraw,0,0,(XRectangle*)(void*)&clip,1);
1762 #endif
1763   flags|=GCClipMask;
1764   }
1765 
1766 
1767 // Construct for normal painting
1768 FXDCWindow::FXDCWindow(FXDrawable* draw):FXDC(draw->getApp()),surface(NULL),rect(0,0,0,0),devfg(0),devbg(0){
1769 #ifdef HAVE_XFT_H
1770   xftDraw=NULL;
1771 #endif
1772   begin(draw);
1773   }
1774 
1775 
1776 // Destruct
1777 FXDCWindow::~FXDCWindow(){
1778   end();
1779   }
1780 
1781 
1782 // Begin locks in a drawable surface
1783 void FXDCWindow::begin(FXDrawable *draw){
1784   if(!draw){ fxerror("FXDCWindow::begin: NULL drawable.\n"); }
1785   if(!draw->id()){ fxerror("FXDCWindow::begin: drawable not created yet.\n"); }
1786   surface=draw;
1787   rect.x=clip.x=0;
1788   rect.y=clip.y=0;
1789   rect.w=clip.w=draw->getWidth();
1790   rect.h=clip.h=draw->getHeight();
1791   devfg=~0;
1792   devbg=0;
1793   ctx=surface->visual->gc;
1794   flags=0;
1795 #ifdef HAVE_XFT_H
1796   xftDraw=(void*)XftDrawCreate((Display*)getApp()->getDisplay(),(Drawable)surface->id(),(Visual*)surface->visual->visual,(Colormap)surface->visual->colormap);
1797 #endif
1798   }
1799 
1800 
1801 // End unlock the drawable surface; restore it
1802 void FXDCWindow::end(){
1803   if(flags){
1804     XGCValues gcv;
1805     if(flags&GCFunction) gcv.function=BLT_SRC;
1806     if(flags&GCForeground) gcv.foreground=BlackPixel((Display*)getApp()->getDisplay(),DefaultScreen((Display*)getApp()->getDisplay()));
1807     if(flags&GCBackground) gcv.background=WhitePixel((Display*)getApp()->getDisplay(),DefaultScreen((Display*)getApp()->getDisplay()));
1808     if(flags&GCLineWidth) gcv.line_width=0;
1809     if(flags&GCCapStyle) gcv.cap_style=CAP_BUTT;
1810     if(flags&GCJoinStyle) gcv.join_style=JOIN_MITER;
1811     if(flags&GCLineStyle) gcv.line_style=LINE_SOLID;
1812     if(flags&GCFillStyle) gcv.fill_style=FILL_SOLID;
1813     if(flags&GCStipple) gcv.stipple=getApp()->stipples[STIPPLE_WHITE];    // Needed for IRIX6.4 bug workaround!
1814     if(flags&GCFillRule) gcv.fill_rule=RULE_EVEN_ODD;
1815 #ifndef HAVE_XFT_H
1816     if(flags&GCFont) gcv.font=getApp()->getNormalFont()->id();
1817 #endif
1818     if(flags&GCClipMask) gcv.clip_mask=None;
1819     if(flags&GCClipXOrigin) gcv.clip_x_origin=0;
1820     if(flags&GCClipYOrigin) gcv.clip_y_origin=0;
1821     if(flags&GCDashOffset) gcv.dash_offset=0;
1822     if(flags&GCDashList) gcv.dashes=4;
1823     if(flags&GCTileStipXOrigin) gcv.ts_x_origin=0;
1824     if(flags&GCTileStipYOrigin) gcv.ts_y_origin=0;
1825     if(flags&GCGraphicsExposures) gcv.graphics_exposures=True;
1826     if(flags&GCSubwindowMode) gcv.subwindow_mode=ClipByChildren;
1827     XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,flags,&gcv);
1828     flags=0;
1829     }
1830   surface=NULL;
1831 #ifdef HAVE_XFT_H
1832   if(xftDraw){
1833     XftDrawDestroy((XftDraw*)xftDraw);
1834     xftDraw=NULL;
1835     }
1836 #endif
1837   }
1838 
1839 
1840 // Read back pixel
1841 FXColor FXDCWindow::readPixel(FXint x,FXint y){
1842   FXColor color=FXRGBA(0,0,0,0);
1843   if(!surface){ fxerror("FXDCWindow::readPixel: DC not connected to drawable.\n"); }
1844   if(0<=x && 0<=y && x<surface->getWidth() && y<surface->getHeight()){
1845     XImage* xim=XGetImage((Display*)getApp()->getDisplay(),surface->id(),x,y,1,1,AllPlanes,ZPixmap);
1846     if(xim && xim->data){
1847       color=surface->visual->getColor(XGetPixel(xim,0,0));
1848       XDestroyImage(xim);
1849       }
1850     }
1851   return color;
1852   }
1853 
1854 
1855 // Draw point
1856 void FXDCWindow::drawPoint(FXint x,FXint y){
1857   if(!surface){ fxerror("FXDCWindow::drawPoint: DC not connected to drawable.\n"); }
1858   XDrawPoint((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x,y);
1859   }
1860 
1861 
1862 // Draw points
1863 void FXDCWindow::drawPoints(const FXPoint* points,FXuint npoints){
1864   if(!surface){ fxerror("FXDCWindow::drawPoints: DC not connected to drawable.\n"); }
1865   XDrawPoints((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(XPoint*)points,npoints,CoordModeOrigin);
1866   }
1867 
1868 
1869 // Draw points relative
1870 void FXDCWindow::drawPointsRel(const FXPoint* points,FXuint npoints){
1871   if(!surface){ fxerror("FXDCWindow::drawPointsRel: DC not connected to drawable.\n"); }
1872   XDrawPoints((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(XPoint*)points,npoints,CoordModePrevious);
1873   }
1874 
1875 
1876 // Draw line
1877 void FXDCWindow::drawLine(FXint x1,FXint y1,FXint x2,FXint y2){
1878   if(!surface){ fxerror("FXDCWindow::drawLine: DC not connected to drawable.\n"); }
1879   XDrawLine((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x1,y1,x2,y2);
1880   }
1881 
1882 
1883 // Draw lines
1884 void FXDCWindow::drawLines(const FXPoint* points,FXuint npoints){
1885   if(!surface){ fxerror("FXDCWindow::drawLines: DC not connected to drawable.\n"); }
1886   XDrawLines((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(XPoint*)points,npoints,CoordModeOrigin);
1887   }
1888 
1889 
1890 // Draw lines relative
1891 void FXDCWindow::drawLinesRel(const FXPoint* points,FXuint npoints){
1892   if(!surface){ fxerror("FXDCWindow::drawLinesRel: DC not connected to drawable.\n"); }
1893   XDrawLines((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(XPoint*)points,npoints,CoordModePrevious);
1894   }
1895 
1896 
1897 // Draw line segments
1898 void FXDCWindow::drawLineSegments(const FXSegment* segments,FXuint nsegments){
1899   if(!surface){ fxerror("FXDCWindow::drawLineSegments: DC not connected to drawable.\n"); }
1900   XDrawSegments((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(XSegment*)segments,nsegments);
1901   }
1902 
1903 
1904 // Draw rectangle
1905 void FXDCWindow::drawRectangle(FXint x,FXint y,FXint w,FXint h){
1906   if(!surface){ fxerror("FXDCWindow::drawRectangle: DC not connected to drawable.\n"); }
1907   XDrawRectangle((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x,y,w,h);
1908   }
1909 
1910 
1911 // Draw rectangles
1912 void FXDCWindow::drawRectangles(const FXRectangle* rectangles,FXuint nrectangles){
1913   if(!surface){ fxerror("FXDCWindow::drawRectangles: DC not connected to drawable.\n"); }
1914   XDrawRectangles((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(XRectangle*)rectangles,nrectangles);
1915   }
1916 
1917 
1918 // Draw round rectangle
1919 void FXDCWindow::drawRoundRectangle(FXint x,FXint y,FXint w,FXint h,FXint ew,FXint eh){
1920   XArc arcs[4]; XSegment segs[4]; XGCValues gcv;
1921   if(!surface){ fxerror("FXDCWindow::drawRoundRectangle: DC not connected to drawable.\n"); }
1922   if(ew+ew>w) ew=w>>1;
1923   if(eh+eh>h) eh=h>>1;
1924   arcs[0].x=arcs[2].x=x;
1925   arcs[0].y=arcs[1].y=y;
1926   arcs[1].x=arcs[3].x=x+w-(ew<<1);
1927   arcs[2].y=arcs[3].y=y+h-(eh<<1);
1928   arcs[0].width=arcs[1].width=arcs[2].width=arcs[3].width=ew<<1;
1929   arcs[0].height=arcs[1].height=arcs[2].height=arcs[3].height=eh<<1;
1930   arcs[0].angle1=5760;
1931   arcs[0].angle2=5760;
1932   arcs[1].angle1=0;
1933   arcs[1].angle2=5760;
1934   arcs[2].angle1=11520;
1935   arcs[2].angle2=5760;
1936   arcs[3].angle1=17280;
1937   arcs[3].angle2=5760;
1938   segs[0].x1=segs[1].x1=x+ew;
1939   segs[0].x2=segs[1].x2=x+w-ew;
1940   segs[0].y1=segs[0].y2=y;
1941   segs[1].y1=segs[1].y2=y+h;
1942   segs[2].x1=segs[2].x2=x;
1943   segs[3].x1=segs[3].x2=x+w;
1944   segs[2].y1=segs[3].y1=y+eh;
1945   segs[2].y2=segs[3].y2=y+h-eh;
1946   gcv.cap_style=CapButt;
1947   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCCapStyle,&gcv);
1948   XDrawArcs((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,arcs,4);
1949   XDrawSegments((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,segs,4);
1950   gcv.cap_style=cap;
1951   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCCapStyle,&gcv);
1952   }
1953 
1954 
1955 // Draw arc
1956 void FXDCWindow::drawArc(FXint x,FXint y,FXint w,FXint h,FXint ang1,FXint ang2){
1957   if(!surface){ fxerror("FXDCWindow::drawArc: DC not connected to drawable.\n"); }
1958   XDrawArc((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x,y,w,h,ang1,ang2);
1959   }
1960 
1961 
1962 // Draw arcs
1963 void FXDCWindow::drawArcs(const FXArc* arcs,FXuint narcs){
1964   if(!surface){ fxerror("FXDCWindow::drawArcs: DC not connected to drawable.\n"); }
1965   XDrawArcs((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(XArc*)arcs,narcs);
1966   }
1967 
1968 
1969 // Draw ellipse
1970 void FXDCWindow::drawEllipse(FXint x,FXint y,FXint w,FXint h){
1971   if(!surface){ fxerror("FXDCWindow::drawEllipse: DC not connected to drawable.\n"); }
1972   XDrawArc((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x,y,w,h,0,23040);
1973   }
1974 
1975 
1976 // Fill rectangle
1977 void FXDCWindow::fillRectangle(FXint x,FXint y,FXint w,FXint h){
1978   if(!surface){ fxerror("FXDCWindow::fillRectangle: DC not connected to drawable.\n"); }
1979   XFillRectangle((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x,y,w,h);
1980   }
1981 
1982 
1983 // Fill rectangles
1984 void FXDCWindow::fillRectangles(const FXRectangle* rectangles,FXuint nrectangles){
1985   if(!surface){ fxerror("FXDCWindow::fillRectangles: DC not connected to drawable.\n"); }
1986   XFillRectangles((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(XRectangle*)rectangles,nrectangles);
1987   }
1988 
1989 
1990 // Fill rounded rectangle
1991 void FXDCWindow::fillRoundRectangle(FXint x,FXint y,FXint w,FXint h,FXint ew,FXint eh){
1992   XArc arcs[4]; XRectangle recs[3];
1993   if(!surface){ fxerror("FXDCWindow::fillRoundRectangle: DC not connected to drawable.\n"); }
1994   if(ew+ew>w) ew=w>>1;
1995   if(eh+eh>h) eh=h>>1;
1996   arcs[0].x=arcs[2].x=x;
1997   arcs[0].y=arcs[1].y=y;
1998   arcs[1].x=arcs[3].x=x+w-(ew<<1);
1999   arcs[2].y=arcs[3].y=y+h-(eh<<1);
2000   arcs[0].width=arcs[1].width=arcs[2].width=arcs[3].width=ew<<1;
2001   arcs[0].height=arcs[1].height=arcs[2].height=arcs[3].height=eh<<1;
2002   arcs[0].angle1=5760;
2003   arcs[0].angle2=5760;
2004   arcs[1].angle1=0;
2005   arcs[1].angle2=5760;
2006   arcs[2].angle1=11520;
2007   arcs[2].angle2=5760;
2008   arcs[3].angle1=17280;
2009   arcs[3].angle2=5760;
2010   recs[0].x=recs[2].x=x+ew;
2011   recs[0].width=recs[2].width=w-(ew<<1);
2012   recs[0].height=recs[2].height=eh;
2013   recs[0].y=y;
2014   recs[2].y=y+h-eh;
2015   recs[1].x=x;
2016   recs[1].y=y+eh;
2017   recs[1].width=w;
2018   recs[1].height=h-(eh<<1);
2019   XFillArcs((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,arcs,4);
2020   XFillRectangles((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,recs,3);
2021   }
2022 
2023 
2024 // Fill chord
2025 void FXDCWindow::fillChord(FXint x,FXint y,FXint w,FXint h,FXint ang1,FXint ang2){
2026   if(!surface){ fxerror("FXDCWindow::fillChord: DC not connected to drawable.\n"); }
2027   XSetArcMode((Display*)getApp()->getDisplay(),(GC)ctx,ArcChord);
2028   XFillArc((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x,y,w,h,ang1,ang2);
2029   XSetArcMode((Display*)getApp()->getDisplay(),(GC)ctx,ArcPieSlice);
2030   }
2031 
2032 
2033 // Fill chords
2034 void FXDCWindow::fillChords(const FXArc* chords,FXuint nchords){
2035   if(!surface){ fxerror("FXDCWindow::fillChords: DC not connected to drawable.\n"); }
2036   XSetArcMode((Display*)getApp()->getDisplay(),(GC)ctx,ArcChord);
2037   XFillArcs((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(XArc*)chords,nchords);
2038   XSetArcMode((Display*)getApp()->getDisplay(),(GC)ctx,ArcPieSlice);
2039   }
2040 
2041 
2042 // Fill arc
2043 void FXDCWindow::fillArc(FXint x,FXint y,FXint w,FXint h,FXint ang1,FXint ang2){
2044   if(!surface){ fxerror("FXDCWindow::fillArc: DC not connected to drawable.\n"); }
2045   XFillArc((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x,y,w,h,ang1,ang2);
2046   }
2047 
2048 
2049 // Fill arcs
2050 void FXDCWindow::fillArcs(const FXArc* arcs,FXuint narcs){
2051   if(!surface){ fxerror("FXDCWindow::fillArcs: DC not connected to drawable.\n"); }
2052   XFillArcs((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(XArc*)arcs,narcs);
2053   }
2054 
2055 
2056 // Fill ellipse
2057 void FXDCWindow::fillEllipse(FXint x,FXint y,FXint w,FXint h){
2058   if(!surface){ fxerror("FXDCWindow::fillEllipse: DC not connected to drawable.\n"); }
2059   XFillArc((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x,y,w,h,0,23040);
2060   }
2061 
2062 
2063 // Fill polygon
2064 void FXDCWindow::fillPolygon(const FXPoint* points,FXuint npoints){
2065   if(!surface){ fxerror("FXDCWindow::fillArcs: DC not connected to drawable.\n"); }
2066   XFillPolygon((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(XPoint*)points,npoints,Convex,CoordModeOrigin);
2067   }
2068 
2069 
2070 // Fill concave polygon
2071 void FXDCWindow::fillConcavePolygon(const FXPoint* points,FXuint npoints){
2072   if(!surface){ fxerror("FXDCWindow::fillConcavePolygon: DC not connected to drawable.\n"); }
2073   XFillPolygon((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(XPoint*)points,npoints,Nonconvex,CoordModeOrigin);
2074   }
2075 
2076 
2077 // Fill complex polygon
2078 void FXDCWindow::fillComplexPolygon(const FXPoint* points,FXuint npoints){
2079   if(!surface){ fxerror("FXDCWindow::fillComplexPolygon: DC not connected to drawable.\n"); }
2080   XFillPolygon((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(XPoint*)points,npoints,Complex,CoordModeOrigin);
2081   }
2082 
2083 
2084 // Fill polygon relative
2085 void FXDCWindow::fillPolygonRel(const FXPoint* points,FXuint npoints){
2086   if(!surface){ fxerror("FXDCWindow::fillPolygonRel: DC not connected to drawable.\n"); }
2087   XFillPolygon((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(XPoint*)points,npoints,Convex,CoordModePrevious);
2088   }
2089 
2090 
2091 // Fill concave polygon relative
2092 void FXDCWindow::fillConcavePolygonRel(const FXPoint* points,FXuint npoints){
2093   if(!surface){ fxerror("FXDCWindow::fillConcavePolygonRel: DC not connected to drawable.\n"); }
2094   XFillPolygon((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(XPoint*)points,npoints,Nonconvex,CoordModePrevious);
2095   }
2096 
2097 
2098 // Fill complex polygon relative
2099 void FXDCWindow::fillComplexPolygonRel(const FXPoint* points,FXuint npoints){
2100   if(!surface){ fxerror("FXDCWindow::fillComplexPolygonRel: DC not connected to drawable.\n"); }
2101   XFillPolygon((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(XPoint*)points,npoints,Complex,CoordModePrevious);
2102   }
2103 
2104 
2105 // Fill vertical gradient rectangle
2106 void FXDCWindow::fillVerticalGradient(FXint x,FXint y,FXint w,FXint h,FXColor top,FXColor bottom){
2107   FXint rr,gg,bb,dr,dg,db,r1,g1,b1,r2,g2,b2,yl,yh,yy,dy,n,t;
2108   if(!surface){ fxerror("FXDCWindow::fillVerticalGradient: DC not connected to drawable.\n"); }
2109   if(0<w && 0<h){
2110     r1=FXREDVAL(top);
2111     r2=FXREDVAL(bottom);
2112     g1=FXGREENVAL(top);
2113     g2=FXGREENVAL(bottom);
2114     b1=FXBLUEVAL(top);
2115     b2=FXBLUEVAL(bottom);
2116     dr=r2-r1;
2117     dg=g2-g1;
2118     db=b2-b1;
2119     n=FXABS(dr);
2120     if((t=FXABS(dg))>n) n=t;
2121     if((t=FXABS(db))>n) n=t;
2122     n++;
2123     if(n>h) n=h;
2124     if(n>128) n=128;
2125     rr=(r1<<16)+32767;
2126     gg=(g1<<16)+32767;
2127     bb=(b1<<16)+32767;
2128     yy=32767;
2129     dr=(dr<<16)/n;
2130     dg=(dg<<16)/n;
2131     db=(db<<16)/n;
2132     dy=(h<<16)/n;
2133     do{
2134       yl=yy>>16;
2135       yy+=dy;
2136       yh=yy>>16;
2137       setForeground(FXRGB(rr>>16,gg>>16,bb>>16));
2138       fillRectangle(x,y+yl,w,yh-yl);
2139       rr+=dr;
2140       gg+=dg;
2141       bb+=db;
2142       }
2143     while(yh<h);
2144     }
2145 #if 0
2146   XLinearGradient grad;
2147   XFixed stops[2];
2148   XRenderColor colors[2];
2149 
2150   grad.p1.x=0;
2151   grad.p1.y=0;
2152   grad.p2.x=0;
2153   grad.p2.y=h<<16;
2154 
2155   stops[0]=0;
2156   stops[1]=1<<16;
2157 
2158   colors[0].red=FXREDVAL(top)*257;
2159   colors[0].green=FXGREENVAL(top)*257;
2160   colors[0].blue=FXBLUEVAL(top)*257;
2161   colors[0].alpha=FXALPHAVAL(top)*257;
2162   colors[1].red=FXREDVAL(bottom)*257;
2163   colors[1].green=FXGREENVAL(bottom)*257;
2164   colors[1].blue=FXBLUEVAL(bottom)*257;
2165   colors[1].alpha=FXALPHAVAL(bottom)*257;
2166 
2167   Picture picture=XRenderCreateLinearGradient((Display*)getApp()->getDisplay(),&grad,stops,colors,2);
2168   XRenderComposite((Display*)getApp()->getDisplay(),PictOpSrc,picture,0,surface->xrenderpicture,0,0,0,0,x,y,w,h);
2169   XRenderFreePicture((Display*)getApp()->getDisplay(),picture);
2170 #endif
2171   }
2172 
2173 
2174 
2175 // Fill horizontal gradient rectangle
2176 void FXDCWindow::fillHorizontalGradient(FXint x,FXint y,FXint w,FXint h,FXColor left,FXColor right){
2177   FXint rr,gg,bb,dr,dg,db,r1,g1,b1,r2,g2,b2,xl,xh,xx,dx,n,t;
2178   if(!surface){ fxerror("FXDCWindow::fillHorizontalGradient: DC not connected to drawable.\n"); }
2179   if(0<w && 0<h){
2180     r1=FXREDVAL(left);
2181     r2=FXREDVAL(right);
2182     g1=FXGREENVAL(left);
2183     g2=FXGREENVAL(right);
2184     b1=FXBLUEVAL(left);
2185     b2=FXBLUEVAL(right);
2186     dr=r2-r1;
2187     dg=g2-g1;
2188     db=b2-b1;
2189     n=FXABS(dr);
2190     if((t=FXABS(dg))>n) n=t;
2191     if((t=FXABS(db))>n) n=t;
2192     n++;
2193     if(n>w) n=w;
2194     if(n>128) n=128;
2195     rr=(r1<<16)+32767;
2196     gg=(g1<<16)+32767;
2197     bb=(b1<<16)+32767;
2198     xx=32767;
2199     dr=(dr<<16)/n;
2200     dg=(dg<<16)/n;
2201     db=(db<<16)/n;
2202     dx=(w<<16)/n;
2203     do{
2204       xl=xx>>16;
2205       xx+=dx;
2206       xh=xx>>16;
2207       setForeground(FXRGB(rr>>16,gg>>16,bb>>16));
2208       fillRectangle(x+xl,y,xh-xl,h);
2209       rr+=dr;
2210       gg+=dg;
2211       bb+=db;
2212       }
2213     while(xh<w);
2214     }
2215 #if 0
2216   XLinearGradient grad;
2217   XFixed stops[2];
2218   XRenderColor colors[2];
2219 
2220   grad.p1.x=0;
2221   grad.p1.y=0;
2222   grad.p2.x=w<<16;
2223   grad.p2.y=0;
2224 
2225   stops[0]=0;
2226   stops[1]=1<<16;
2227 
2228   colors[0].red=FXREDVAL(left)*257;
2229   colors[0].green=FXGREENVAL(left)*257;
2230   colors[0].blue=FXBLUEVAL(left)*257;
2231   colors[0].alpha=FXALPHAVAL(left)*257;
2232   colors[1].red=FXREDVAL(right)*257;
2233   colors[1].green=FXGREENVAL(right)*257;
2234   colors[1].blue=FXBLUEVAL(right)*257;
2235   colors[1].alpha=FXALPHAVAL(right)*257;
2236 
2237   Picture picture=XRenderCreateLinearGradient((Display*)getApp()->getDisplay(),&grad,stops,colors,2);
2238   XRenderComposite((Display*)getApp()->getDisplay(),PictOpSrc,picture,0,surface->xrenderpicture,0,0,0,0,x,y,w,h);
2239   XRenderFreePicture((Display*)getApp()->getDisplay(),picture);
2240 #endif
2241   }
2242 
2243 
2244 // Set text font
2245 void FXDCWindow::setFont(FXFont *fnt){
2246   if(!surface){ fxerror("FXDCWindow::setFont: DC not connected to drawable.\n"); }
2247   if(!fnt || !fnt->id()){ fxerror("FXDCWindow::setFont: illegal or NULL font specified.\n"); }
2248 #ifndef HAVE_XFT_H
2249   XSetFont((Display*)getApp()->getDisplay(),(GC)ctx,fnt->id());
2250   flags|=GCFont;
2251 #endif
2252   font=fnt;
2253   }
2254 
2255 
2256 /*
2257 
2258  We eventually want subclassable fonts.
2259  FXDCWindow knows about surface, but does not know about font type.
2260  Thus, drawText() here should vector to new API's in FXFont.
2261  New API gets FXDC* (or FXDC&) so that it can obtain colors, &c.
2262  Thus, all knowledge of font-technology is kept inside FXFont.
2263  Knowledge of FXDCWindow surface is kept inside FXDCWindow.
2264 
2265  But FXDC may have some responsibility for layout of characters.
2266 
2267  Of course, certain font types can only draw on certain DC types...
2268 
2269 
2270 void FXDCWindow::drawText(FXint x,FXint y,const FXchar* string,FXuint length){
2271   if(!surface){ fxerror("FXDCWindow::drawText: DC not connected to drawable.\n"); }
2272   if(!font){ fxerror("FXDCWindow::drawText: no font selected.\n"); }
2273   font->drawText(this,x,y,string,length);
2274   }
2275 */
2276 
2277 
2278 
2279 #define FS ((XFontStruct*)(font->font))
2280 
2281 
2282 static FXint utf2db(XChar2b *dst,const FXchar *src,FXint n){
2283   FXint len,p;
2284   FXwchar w;
2285   for(p=len=0; p<n; p+=wclen(src+p),len++){
2286     w=wc(src+p);
2287     dst[len].byte1=(w>>8);
2288     dst[len].byte2=(w&255);
2289     }
2290   return len;
2291   }
2292 
2293 
2294 // Draw string with base line starting at x, y
2295 void FXDCWindow::drawText(FXint x,FXint y,const FXchar* string,FXuint length){
2296   if(!surface){ fxerror("FXDCWindow::drawText: DC not connected to drawable.\n"); }
2297   if(!font){ fxerror("FXDCWindow::drawText: no font selected.\n"); }
2298 #ifdef HAVE_XFT_H
2299   XftColor color;
2300   color.pixel=devfg;
2301   color.color.red=FXREDVAL(fg)*257;
2302   color.color.green=FXGREENVAL(fg)*257;
2303   color.color.blue=FXBLUEVAL(fg)*257;
2304   color.color.alpha=FXALPHAVAL(fg)*257;
2305   XftDrawStringUtf8((XftDraw*)xftDraw,&color,(XftFont*)font->font,x,y,(const FcChar8*)string,length);
2306 #else
2307   FXint count,escapement,defwidth,ww,size,i;
2308   FXdouble ang,ux,uy;
2309   FXuchar r,c;
2310   XChar2b sbuffer[4096];
2311   count=utf2db(sbuffer,string,FXMIN(length,4096));
2312   if(font->getAngle()){
2313     ang=font->getAngle()*0.00027270769562411399179;
2314     defwidth=FS->min_bounds.width;
2315     ux=Math::cos(ang);
2316     uy=Math::sin(ang);
2317     if(FS->per_char){
2318       r=FS->default_char>>8;
2319       c=FS->default_char&255;
2320       size=(FS->max_char_or_byte2-FS->min_char_or_byte2+1);
2321       if(FS->min_char_or_byte2<=c && c<=FS->max_char_or_byte2 && FS->min_byte1<=r && r<=FS->max_byte1){
2322         defwidth=FS->per_char[(r-FS->min_byte1)*size+(c-FS->min_char_or_byte2)].width;
2323         }
2324       for(i=escapement=0; i<count; i++){
2325         XDrawString16((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(FXint)(x+escapement*ux),(FXint)(y-escapement*uy),&sbuffer[i],1);
2326         r=sbuffer[i].byte1;
2327         c=sbuffer[i].byte2;
2328         escapement+=defwidth;
2329         if(FS->min_char_or_byte2<=c && c<=FS->max_char_or_byte2 && FS->min_byte1<=r && r<=FS->max_byte1){
2330           if((ww=FS->per_char[(r-FS->min_byte1)*size+(c-FS->min_char_or_byte2)].width)!=0) escapement+=ww-defwidth;
2331           }
2332         }
2333       }
2334     else{
2335       for(i=escapement=0; i<count; i++){
2336         XDrawString16((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(FXint)(x+escapement*ux),(FXint)(y-escapement*uy),&sbuffer[i],1);
2337         escapement+=defwidth;
2338         }
2339       }
2340     }
2341   else{
2342     XDrawString16((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x,y,sbuffer,count);
2343     }
2344 #endif
2345   }
2346 
2347 
2348 // Draw text starting at x, y over filled background
2349 void FXDCWindow::drawImageText(FXint x,FXint y,const FXchar* string,FXuint length){
2350   if(!surface){ fxerror("FXDCWindow::drawImageText: DC not connected to drawable.\n"); }
2351   if(!font){ fxerror("FXDCWindow::drawImageText: no font selected.\n"); }
2352 #ifdef HAVE_XFT_H
2353   XGlyphInfo extents;
2354   XftColor fgcolor,bgcolor;
2355   fgcolor.pixel=devfg;
2356   fgcolor.color.red=FXREDVAL(fg)*257;
2357   fgcolor.color.green=FXGREENVAL(fg)*257;
2358   fgcolor.color.blue=FXBLUEVAL(fg)*257;
2359   fgcolor.color.alpha=FXALPHAVAL(fg)*257;
2360   bgcolor.pixel=devbg;
2361   bgcolor.color.red=FXREDVAL(bg)*257;
2362   bgcolor.color.green=FXGREENVAL(bg)*257;
2363   bgcolor.color.blue=FXBLUEVAL(bg)*257;
2364   bgcolor.color.alpha=FXALPHAVAL(bg)*257;
2365 
2366   // Area to blank
2367   XftTextExtents8((Display*)getApp()->getDisplay(),(XftFont*)font->font,(const FcChar8*)string,length,&extents);
2368 
2369   // Erase around text [FIXME wrong location]
2370   XftDrawRect((XftDraw*)xftDraw,&bgcolor,x,y-font->getFontAscent(),extents.width,extents.height);
2371 //XftDrawRect((XftDraw*)xftDraw,&bgcolor,x+cache->xoff,y-xftfs->ascent,cache->x2off-cache->xoff,xftfs->ascent+xftfs->descent);
2372 //XftDrawRect((XftDraw*)xftDraw,&bgcolor,x+cache->xoff,y-((XftFont*)font->font)->ascent,cache->x2off-cache->xoff,((XftFont*)font->font)->ascent+((XftFont*)font->font)->descent);
2373   XftDrawStringUtf8((XftDraw*)xftDraw,&fgcolor,(XftFont*)font->font,x,y,(const FcChar8*)string,length);
2374 #else
2375   FXint count,escapement,defwidth,ww,size,i;
2376   FXdouble ang,ux,uy;
2377   FXuchar r,c;
2378   XChar2b sbuffer[4096];
2379   count=utf2db(sbuffer,string,FXMIN(length,4096));
2380   if(font->getAngle()){
2381     ang=font->getAngle()*0.00027270769562411399179;
2382     defwidth=FS->min_bounds.width;
2383     ux=Math::cos(ang);
2384     uy=Math::sin(ang);
2385     if(FS->per_char){
2386       r=FS->default_char>>8;
2387       c=FS->default_char&255;
2388       size=(FS->max_char_or_byte2-FS->min_char_or_byte2+1);
2389       if(FS->min_char_or_byte2<=c && c<=FS->max_char_or_byte2 && FS->min_byte1<=r && r<=FS->max_byte1){
2390         defwidth=FS->per_char[(r-FS->min_byte1)*size+(c-FS->min_char_or_byte2)].width;
2391         }
2392       for(i=escapement=0; i<count; i++){
2393         XDrawString16((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(FXint)(x+escapement*ux),(FXint)(y-escapement*uy),&sbuffer[i],1);
2394         r=sbuffer[i].byte1;
2395         c=sbuffer[i].byte2;
2396         escapement+=defwidth;
2397         if(FS->min_char_or_byte2<=c && c<=FS->max_char_or_byte2 && FS->min_byte1<=r && r<=FS->max_byte1){
2398           if((ww=FS->per_char[(r-FS->min_byte1)*size+(c-FS->min_char_or_byte2)].width)!=0) escapement+=ww-defwidth;
2399           }
2400         }
2401       }
2402     else{
2403       for(i=escapement=0; i<count; i++){
2404         XDrawImageString16((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,(FXint)(x+escapement*ux),(FXint)(y-escapement*uy),&sbuffer[i],1);
2405         escapement+=defwidth;
2406         }
2407       }
2408     }
2409   else{
2410     XDrawImageString16((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x,y,sbuffer,count);
2411     }
2412 #endif
2413   }
2414 
2415 #undef FS
2416 
2417 
2418 
2419 // Draw string with base line starting at x, y
2420 void FXDCWindow::drawText(FXint x,FXint y,const FXString& string){
2421   drawText(x,y,string.text(),string.length());
2422   }
2423 
2424 
2425 // Draw text starting at x, y over filled background
2426 void FXDCWindow::drawImageText(FXint x,FXint y,const FXString& string){
2427   drawImageText(x,y,string.text(),string.length());
2428   }
2429 
2430 
2431 // Draw area
2432 void FXDCWindow::drawArea(const FXDrawable* source,FXint sx,FXint sy,FXint sw,FXint sh,FXint dx,FXint dy){
2433   if(!surface){ fxerror("FXDCWindow::drawArea: DC not connected to drawable.\n"); }
2434   if(!source || !source->id()){ fxerror("FXDCWindow::drawArea: illegal source specified.\n"); }
2435   XCopyArea((Display*)getApp()->getDisplay(),source->id(),surface->id(),(GC)ctx,sx,sy,sw,sh,dx,dy);
2436   }
2437 
2438 
2439 // Draw area stretched area from source; FIXME this works but it's like molasses!
2440 void FXDCWindow::drawArea(const FXDrawable* source,FXint sx,FXint sy,FXint sw,FXint sh,FXint dx,FXint dy,FXint dw,FXint dh){
2441   FXint i,j,x,y,xs,ys;
2442   if(!surface){ fxerror("FXDCWindow::drawArea: DC not connected to drawable.\n"); }
2443   if(!source || !source->id()){ fxerror("FXDCWindow::drawArea: illegal source specified.\n"); }
2444   xs=(sw<<16)/dw;
2445   ys=(sh<<16)/dh;
2446   i=0;
2447   y=ys>>1;
2448   do{
2449     j=0;
2450     x=xs>>1;
2451     do{
2452       XCopyArea((Display*)getApp()->getDisplay(),source->id(),surface->id(),(GC)ctx,sx+(x>>16),sy+(y>>16),1,1,dx+j,dy+i);
2453       x+=xs;
2454       }
2455     while(++j<dw);
2456     y+=ys;
2457     }
2458   while(++i<dh);
2459   }
2460 
2461 
2462 // Draw image
2463 void FXDCWindow::drawImage(const FXImage* image,FXint dx,FXint dy){
2464   if(!surface){ fxerror("FXDCWindow::drawImage: DC not connected to drawable.\n"); }
2465   if(!image || !image->id()){ fxerror("FXDCWindow::drawImage: illegal image specified.\n"); }
2466   XCopyArea((Display*)getApp()->getDisplay(),image->id(),surface->id(),(GC)ctx,0,0,image->width,image->height,dx,dy);
2467   }
2468 
2469 
2470 // Draw bitmap
2471 void FXDCWindow::drawBitmap(const FXBitmap* bitmap,FXint dx,FXint dy) {
2472   if(!surface) fxerror("FXDCWindow::drawBitmap: DC not connected to drawable.\n");
2473   if(!bitmap || !bitmap->id()) fxerror("FXDCWindow::drawBitmap: illegal bitmap specified.\n");
2474   XCopyPlane((Display*)getApp()->getDisplay(),bitmap->id(),surface->id(),(GC)ctx,0,0,bitmap->width,bitmap->height,dx,dy,1);
2475   }
2476 
2477 
2478 // Draw a vanilla icon
2479 void FXDCWindow::drawIcon(const FXIcon* icon,FXint dx,FXint dy){
2480   if(!surface){ fxerror("FXDCWindow::drawIcon: DC not connected to drawable.\n"); }
2481   if(!icon || !icon->id() || !icon->shape){ fxerror("FXDCWindow::drawIcon: illegal icon specified.\n"); }
2482   FXRectangle d=clip*FXRectangle(dx,dy,icon->width,icon->height);
2483   if(d.w>0 && d.h>0){
2484     if(icon->getOptions()&IMAGE_OPAQUE){
2485       XCopyArea((Display*)getApp()->getDisplay(),icon->id(),surface->id(),(GC)ctx,d.x-dx,d.y-dy,d.w,d.h,d.x,d.y);
2486       }
2487     else{
2488       XGCValues gcv;
2489       gcv.clip_mask=icon->shape;
2490       gcv.clip_x_origin=dx;
2491       gcv.clip_y_origin=dy;
2492       XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCClipMask|GCClipXOrigin|GCClipYOrigin,&gcv);
2493       XCopyArea((Display*)getApp()->getDisplay(),icon->id(),surface->id(),(GC)ctx,d.x-dx,d.y-dy,d.w,d.h,d.x,d.y);
2494       XSetClipRectangles((Display*)getApp()->getDisplay(),(GC)ctx,0,0,(XRectangle*)(void*)&clip,1,Unsorted); // Restore old clip rectangle
2495       flags|=GCClipMask;
2496       }
2497     }
2498   }
2499 
2500 
2501 // Draw a shaded icon, like when it is selected
2502 void FXDCWindow::drawIconShaded(const FXIcon* icon,FXint dx,FXint dy){
2503   if(!surface){ fxerror("FXDCWindow::drawIconShaded: DC not connected to drawable.\n"); }
2504   if(!icon || !icon->id() || !icon->shape){ fxerror("FXDCWindow::drawIconShaded: illegal icon specified.\n"); }
2505   FXRectangle d=clip*FXRectangle(dx,dy,icon->width,icon->height);
2506   if(d.w>0 && d.h>0){
2507     XGCValues gcv;
2508     gcv.clip_mask=icon->shape;
2509     gcv.clip_x_origin=dx;
2510     gcv.clip_y_origin=dy;
2511     XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCClipMask|GCClipXOrigin|GCClipYOrigin,&gcv);
2512     XCopyArea((Display*)getApp()->getDisplay(),icon->id(),surface->id(),(GC)ctx,d.x-dx,d.y-dy,d.w,d.h,d.x,d.y);
2513     gcv.function=BLT_SRC;
2514     gcv.stipple=getApp()->stipples[STIPPLE_GRAY];
2515     gcv.fill_style=FILL_STIPPLED;
2516     gcv.ts_x_origin=dx;
2517     gcv.ts_y_origin=dy;
2518     gcv.foreground=surface->visual->getPixel(getApp()->getSelbackColor());
2519     XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCForeground|GCFunction|GCTileStipXOrigin|GCTileStipYOrigin|GCStipple|GCFillStyle,&gcv);
2520     XFillRectangle((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,d.x,d.y,d.w,d.h);
2521     gcv.function=rop;
2522     gcv.fill_style=fill;
2523     gcv.ts_x_origin=tx;
2524     gcv.ts_y_origin=ty;
2525     XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCTileStipXOrigin|GCTileStipYOrigin|GCFunction|GCFillStyle,&gcv);  // Restore old raster op function and fill style
2526     XSetClipRectangles((Display*)getApp()->getDisplay(),(GC)ctx,0,0,(XRectangle*)(void*)&clip,1,Unsorted); // Restore old clip rectangle
2527     flags|=GCClipMask;
2528     }
2529   }
2530 
2531 
2532 // This draws a sunken icon
2533 void FXDCWindow::drawIconSunken(const FXIcon* icon,FXint dx,FXint dy){
2534   if(!surface){ fxerror("FXDCWindow::drawIconSunken: DC not connected to drawable.\n"); }
2535   if(!icon || !icon->id() || !icon->etch){ fxerror("FXDCWindow::drawIconSunken: illegal icon specified.\n"); }
2536   XGCValues gcv;
2537   FXColor base=getApp()->getBaseColor();
2538   FXColor clr=FXRGB((85*FXREDVAL(base))/100,(85*FXGREENVAL(base))/100,(85*FXBLUEVAL(base))/100);
2539 
2540   // Erase to black
2541   gcv.background=0;
2542   gcv.foreground=0xffffffff;
2543   gcv.function=BLT_NOT_SRC_AND_DST;
2544   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCForeground|GCBackground|GCFunction,&gcv);
2545   XCopyPlane((Display*)getApp()->getDisplay(),icon->etch,surface->id(),(GC)ctx,0,0,icon->width,icon->height,dx+1,dy+1,1);
2546 
2547   // Paint highlight part
2548   gcv.function=BLT_SRC_OR_DST;
2549   gcv.foreground=surface->visual->getPixel(getApp()->getHiliteColor());
2550   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCForeground|GCFunction,&gcv);
2551   XCopyPlane((Display*)getApp()->getDisplay(),icon->etch,surface->id(),(GC)ctx,0,0,icon->width,icon->height,dx+1,dy+1,1);
2552 
2553   // Erase to black
2554   gcv.foreground=0xffffffff;
2555   gcv.function=BLT_NOT_SRC_AND_DST;
2556   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCForeground|GCFunction,&gcv);
2557   XCopyPlane((Display*)getApp()->getDisplay(),icon->etch,surface->id(),(GC)ctx,0,0,icon->width,icon->height,dx,dy,1);
2558 
2559   // Paint shadow part
2560   gcv.function=BLT_SRC_OR_DST;
2561   gcv.foreground=surface->visual->getPixel(clr);
2562   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCForeground|GCFunction,&gcv);
2563   XCopyPlane((Display*)getApp()->getDisplay(),icon->etch,surface->id(),(GC)ctx,0,0,icon->width,icon->height,dx,dy,1);
2564 
2565   // Restore stuff
2566   gcv.foreground=devfg;
2567   gcv.background=devbg;
2568   gcv.function=rop;
2569   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCForeground|GCBackground|GCFunction,&gcv);
2570   }
2571 
2572 
2573 // Draw hash box
2574 void FXDCWindow::drawHashBox(FXint x,FXint y,FXint w,FXint h,FXint b){
2575   XGCValues gcv;
2576   if(!surface){ fxerror("FXDCWindow::drawHashBox: DC not connected to drawable.\n"); }
2577   gcv.stipple=getApp()->stipples[STIPPLE_GRAY];
2578   gcv.fill_style=FILL_STIPPLED;
2579   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCStipple|GCFillStyle,&gcv);
2580   XFillRectangle((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x,y,w-b,b);
2581   XFillRectangle((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x+w-b,y,b,h-b);
2582   XFillRectangle((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x+b,y+h-b,w-b,b);
2583   XFillRectangle((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x,y+b,b,h-b);
2584   gcv.stipple=getApp()->stipples[STIPPLE_WHITE];    // Needed for IRIX6.4 bug workaround!
2585   gcv.fill_style=fill;
2586   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCStipple|GCFillStyle,&gcv);
2587   }
2588 
2589 
2590 // Draw focus rectangle
2591 void FXDCWindow::drawFocusRectangle(FXint x,FXint y,FXint w,FXint h){
2592   XGCValues gcv;
2593   if(!surface){ fxerror("FXDCWindow::drawFocusRectangle: DC not connected to drawable.\n"); }
2594   gcv.stipple=getApp()->stipples[STIPPLE_GRAY];
2595   gcv.fill_style=FILL_STIPPLED;
2596   gcv.background=0;
2597   gcv.foreground=0xffffffff;    // Maybe should use FILL_OPAQUESTIPPLED and current fg/bg color and BLT_SRC
2598   gcv.function=BLT_SRC_XOR_DST; // This would be more flexible
2599   gcv.ts_x_origin=x;
2600   gcv.ts_y_origin=y;
2601   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCTileStipXOrigin|GCTileStipYOrigin|GCForeground|GCBackground|GCFunction|GCStipple|GCFillStyle,&gcv);
2602   XFillRectangle((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x,y,w-1,1);
2603   XFillRectangle((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x+w-1,y,1,h-1);
2604   XFillRectangle((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x+1,y+h-1,w-1,1);
2605   XFillRectangle((Display*)getApp()->getDisplay(),surface->id(),(GC)ctx,x,y+1,1,h-1);
2606   gcv.stipple=getApp()->stipples[STIPPLE_WHITE];    // Needed for IRIX6.4 bug workaround!
2607   gcv.fill_style=fill;
2608   gcv.background=devbg;
2609   gcv.foreground=devfg;
2610   gcv.function=rop;
2611   gcv.ts_x_origin=tx;
2612   gcv.ts_y_origin=ty;
2613   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCTileStipXOrigin|GCTileStipYOrigin|GCForeground|GCBackground|GCFunction|GCStipple|GCFillStyle,&gcv);
2614   }
2615 
2616 
2617 // Set foreground color
2618 void FXDCWindow::setForeground(FXColor clr){
2619   if(!surface){ fxerror("FXDCWindow::setForeground: DC not connected to drawable.\n"); }
2620   devfg=surface->visual->getPixel(clr);
2621   XSetForeground((Display*)getApp()->getDisplay(),(GC)ctx,devfg);
2622   flags|=GCForeground;
2623   fg=clr;
2624   }
2625 
2626 
2627 // Set background color
2628 void FXDCWindow::setBackground(FXColor clr){
2629   if(!surface){ fxerror("FXDCWindow::setBackground: DC not connected to drawable.\n"); }
2630   devbg=surface->visual->getPixel(clr);
2631   XSetBackground((Display*)getApp()->getDisplay(),(GC)ctx,devbg);
2632   flags|=GCBackground;
2633   bg=clr;
2634   }
2635 
2636 
2637 // Set dashes
2638 void FXDCWindow::setDashes(FXuint dashoffset,const FXchar *dashpattern,FXuint dashlength){
2639   FXuint len,i;
2640   if(!surface){ fxerror("FXDCWindow::setDashes: DC not connected to drawable.\n"); }
2641   if(dashlength>32){ fxerror("FXDCWindow::setDashes: bad dashlength parameter.\n"); }
2642   for(i=len=0; i<dashlength; i++){
2643     dashpat[i]=dashpattern[i];
2644     len+=(FXuint)dashpattern[i];
2645     }
2646   dashlen=dashlength;
2647   dashoff=dashoffset%len;
2648   XSetDashes((Display*)getApp()->getDisplay(),(GC)ctx,dashoff,(char*)dashpat,dashlen);
2649   flags|=(GCDashList|GCDashOffset);
2650   }
2651 
2652 
2653 // Set line width
2654 void FXDCWindow::setLineWidth(FXuint linewidth){
2655   XGCValues gcv;
2656   if(!surface){ fxerror("FXDCWindow::setLineWidth: DC not connected to drawable.\n"); }
2657   gcv.line_width=linewidth;
2658   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCLineWidth,&gcv);
2659   flags|=GCLineWidth;
2660   width=linewidth;
2661   }
2662 
2663 
2664 // Set line cap style
2665 void FXDCWindow::setLineCap(FXCapStyle capstyle){
2666   XGCValues gcv;
2667   if(!surface){ fxerror("FXDCWindow::setLineCap: DC not connected to drawable.\n"); }
2668   gcv.cap_style=capstyle;
2669   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCCapStyle,&gcv);
2670   flags|=GCCapStyle;
2671   cap=capstyle;
2672   }
2673 
2674 
2675 // Set line join style
2676 void FXDCWindow::setLineJoin(FXJoinStyle joinstyle){
2677   XGCValues gcv;
2678   if(!surface){ fxerror("FXDCWindow::setLineJoin: DC not connected to drawable.\n"); }
2679   gcv.join_style=joinstyle;
2680   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCJoinStyle,&gcv);
2681   flags|=GCJoinStyle;
2682   join=joinstyle;
2683   }
2684 
2685 
2686 // Set line style
2687 void FXDCWindow::setLineStyle(FXLineStyle linestyle){
2688   XGCValues gcv;
2689   if(!surface){ fxerror("FXDCWindow::setLineStyle: DC not connected to drawable.\n"); }
2690   gcv.line_style=linestyle;
2691   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCLineStyle,&gcv);
2692   flags|=GCLineStyle;
2693   style=linestyle;
2694   }
2695 
2696 
2697 // Set fill style
2698 void FXDCWindow::setFillStyle(FXFillStyle fillstyle){
2699   if(!surface){ fxerror("FXDCWindow::setFillStyle: DC not connected to drawable.\n"); }
2700   XSetFillStyle((Display*)getApp()->getDisplay(),(GC)ctx,fillstyle);
2701   flags|=GCFillStyle;
2702   fill=fillstyle;
2703   }
2704 
2705 
2706 // Set polygon fill rule
2707 void FXDCWindow::setFillRule(FXFillRule fillrule){
2708   if(!surface){ fxerror("FXDCWindow::setFillRule: DC not connected to drawable.\n"); }
2709   XSetFillRule((Display*)getApp()->getDisplay(),(GC)ctx,fillrule);
2710   flags|=GCFillRule;
2711   rule=fillrule;
2712   }
2713 
2714 
2715 // Set raster function
2716 void FXDCWindow::setFunction(FXFunction func){
2717   if(!surface){ fxerror("FXDCWindow::setFunction: DC not connected to drawable.\n"); }
2718   XSetFunction((Display*)getApp()->getDisplay(),(GC)ctx,func);
2719   flags|=GCFunction;
2720   rop=func;
2721   }
2722 
2723 
2724 // Set tile pattern
2725 void FXDCWindow::setTile(FXImage* image,FXint dx,FXint dy){
2726   XGCValues gcv;
2727   if(!surface){ fxerror("FXDCWindow::setTile: DC not connected to drawable.\n"); }
2728   if(!image || !image->id()){ fxerror("FXDCWindow::setTile: illegal image specified.\n"); }
2729   gcv.tile=image->id();
2730   gcv.ts_x_origin=dx;
2731   gcv.ts_y_origin=dy;
2732   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCTileStipXOrigin|GCTileStipYOrigin|GCTile,&gcv);
2733   if(dx) flags|=GCTileStipXOrigin;
2734   if(dy) flags|=GCTileStipYOrigin;
2735   tile=image;
2736   tx=dx;
2737   ty=dy;
2738   }
2739 
2740 
2741 // Set stipple bitmap
2742 void FXDCWindow::setStipple(FXBitmap* bitmap,FXint dx,FXint dy){
2743   XGCValues gcv;
2744   if(!surface){ fxerror("FXDCWindow::setStipple: DC not connected to drawable.\n"); }
2745   if(!bitmap || !bitmap->id()){ fxerror("FXDCWindow::setStipple: illegal image specified.\n"); }
2746   gcv.stipple=bitmap->id();
2747   gcv.ts_x_origin=dx;
2748   gcv.ts_y_origin=dy;
2749   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCTileStipXOrigin|GCTileStipYOrigin|GCStipple,&gcv);
2750   if(dx) flags|=GCTileStipXOrigin;
2751   if(dy) flags|=GCTileStipYOrigin;
2752   flags|=GCStipple;
2753   stipple=bitmap;
2754   pattern=STIPPLE_NONE;
2755   tx=dx;
2756   ty=dy;
2757   }
2758 
2759 
2760 // Set stipple pattern
2761 void FXDCWindow::setStipple(FXStipplePattern pat,FXint dx,FXint dy){
2762   XGCValues gcv;
2763   if(!surface){ fxerror("FXDCWindow::setStipple: DC not connected to drawable.\n"); }
2764   if(pat>STIPPLE_CROSSDIAG) pat=STIPPLE_CROSSDIAG;
2765   FXASSERT(getApp()->stipples[pat]);
2766   gcv.stipple=getApp()->stipples[pat];
2767   gcv.ts_x_origin=dx;
2768   gcv.ts_y_origin=dy;
2769   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCTileStipXOrigin|GCTileStipYOrigin|GCStipple,&gcv);
2770   if(dx) flags|=GCTileStipXOrigin;
2771   if(dy) flags|=GCTileStipYOrigin;
2772   stipple=NULL;
2773   pattern=pat;
2774   flags|=GCStipple;
2775   tx=dx;
2776   ty=dy;
2777   }
2778 
2779 
2780 // Set clip region
2781 void FXDCWindow::setClipRegion(const FXRegion& region){
2782   if(!surface){ fxerror("FXDCWindow::setClipRegion: DC not connected to drawable.\n"); }
2783   XSetRegion((Display*)getApp()->getDisplay(),(GC)ctx,(Region)region.region);///// Should intersect region and rect??
2784 #ifdef HAVE_XFT_H
2785   XftDrawSetClip((XftDraw*)xftDraw,(Region)region.region);
2786 #endif
2787   flags|=GCClipMask;
2788   }
2789 
2790 
2791 // Set clip rectangle
2792 void FXDCWindow::setClipRectangle(FXint x,FXint y,FXint w,FXint h){
2793   if(!surface){ fxerror("FXDCWindow::setClipRectangle: DC not connected to drawable.\n"); }
2794   clip.x=FXMAX(x,rect.x);
2795   clip.y=FXMAX(y,rect.y);
2796   clip.w=FXMIN(x+w,rect.x+rect.w)-clip.x;
2797   clip.h=FXMIN(y+h,rect.y+rect.h)-clip.y;
2798   if(clip.w<=0) clip.w=0;
2799   if(clip.h<=0) clip.h=0;
2800   XSetClipRectangles((Display*)getApp()->getDisplay(),(GC)ctx,0,0,(XRectangle*)(void*)&clip,1,Unsorted);
2801 #ifdef HAVE_XFT_H
2802   XftDrawSetClipRectangles((XftDraw*)xftDraw,0,0,(XRectangle*)(void*)&clip,1);
2803 #endif
2804   flags|=GCClipMask;
2805   }
2806 
2807 
2808 // Set clip rectangle
2809 void FXDCWindow::setClipRectangle(const FXRectangle& rectangle){
2810   if(!surface){ fxerror("FXDCWindow::setClipRectangle: DC not connected to drawable.\n"); }
2811   clip.x=FXMAX(rectangle.x,rect.x);
2812   clip.y=FXMAX(rectangle.y,rect.y);
2813   clip.w=FXMIN(rectangle.x+rectangle.w,rect.x+rect.w)-clip.x;
2814   clip.h=FXMIN(rectangle.y+rectangle.h,rect.y+rect.h)-clip.y;
2815   if(clip.w<=0) clip.w=0;
2816   if(clip.h<=0) clip.h=0;
2817   XSetClipRectangles((Display*)getApp()->getDisplay(),(GC)ctx,0,0,(XRectangle*)(void*)&clip,1,Unsorted);
2818 #ifdef HAVE_XFT_H
2819   XftDrawSetClipRectangles((XftDraw*)xftDraw,0,0,(XRectangle*)(void*)&clip,1);
2820 #endif
2821   flags|=GCClipMask;
2822   }
2823 
2824 
2825 // Clear clip rectangle
2826 void FXDCWindow::clearClipRectangle(){
2827   if(!surface){ fxerror("FXDCWindow::clearClipRectangle: DC not connected to drawable.\n"); }
2828   clip=rect;
2829   XSetClipRectangles((Display*)getApp()->getDisplay(),(GC)ctx,0,0,(XRectangle*)(void*)&clip,1,Unsorted);
2830 #ifdef HAVE_XFT_H
2831   XftDrawSetClipRectangles((XftDraw*)xftDraw,0,0,(XRectangle*)(void*)&clip,1);
2832 #endif
2833   flags|=GCClipMask;
2834   }
2835 
2836 
2837 // Set clip mask
2838 void FXDCWindow::setClipMask(FXBitmap* bitmap,FXint dx,FXint dy){
2839   XGCValues gcv;
2840   if(!surface){ fxerror("FXDCWindow::setClipMask: DC not connected to drawable.\n"); }
2841   if(!bitmap || !bitmap->id()){ fxerror("FXDCWindow::setClipMask: illegal mask specified.\n"); }
2842   gcv.clip_mask=bitmap->id();
2843   gcv.clip_x_origin=dx;
2844   gcv.clip_y_origin=dy;
2845   XChangeGC((Display*)getApp()->getDisplay(),(GC)ctx,GCClipMask|GCClipXOrigin|GCClipYOrigin,&gcv);
2846   if(dx) flags|=GCClipXOrigin;
2847   if(dy) flags|=GCClipYOrigin;
2848   flags|=GCClipMask;
2849   mask=bitmap;
2850   cx=dx;
2851   cy=dy;
2852   }
2853 
2854 
2855 // Clear clip mask
2856 void FXDCWindow::clearClipMask(){
2857   if(!surface){ fxerror("FXDCWindow::clearClipMask: DC not connected to drawable.\n"); }
2858   clip=rect;
2859   XSetClipRectangles((Display*)getApp()->getDisplay(),(GC)ctx,0,0,(XRectangle*)(void*)&clip,1,Unsorted);
2860   flags|=GCClipMask;
2861   mask=NULL;
2862   cx=0;
2863   cy=0;
2864   }
2865 
2866 
2867 // Set clip child windows
2868 void FXDCWindow::clipChildren(FXbool yes){
2869   if(!surface){ fxerror("FXDCWindow::clipChildren: window has not yet been created.\n"); }
2870   if(yes){
2871     XSetSubwindowMode((Display*)getApp()->getDisplay(),(GC)ctx,ClipByChildren);
2872 #ifdef HAVE_XFT_H
2873     XftDrawSetSubwindowMode((XftDraw*)xftDraw,ClipByChildren);
2874 #endif
2875     flags&=~GCSubwindowMode;
2876     }
2877   else{
2878     XSetSubwindowMode((Display*)getApp()->getDisplay(),(GC)ctx,IncludeInferiors);
2879 #ifdef HAVE_XFT_H
2880     XftDrawSetSubwindowMode((XftDraw*)xftDraw,IncludeInferiors);
2881 #endif
2882     flags|=GCSubwindowMode;
2883     }
2884   }
2885 
2886 
2887 #endif
2888 
2889 }
2890