Release 971221
[wine] / objects / dc.c
1 /*
2  * GDI Device Context functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  *
6  */
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include "gdi.h"
11 #include "heap.h"
12 #include "metafile.h"
13 #include "stddebug.h"
14 #include "color.h"
15 #include "debug.h"
16 #include "font.h"
17 #include "x11font.h"
18
19 extern void CLIPPING_UpdateGCRegion( DC * dc );     /* objects/clipping.c */
20
21
22   /* ROP code to GC function conversion */
23 const int DC_XROPfunction[16] =
24 {
25     GXclear,        /* R2_BLACK */
26     GXnor,          /* R2_NOTMERGEPEN */
27     GXandInverted,  /* R2_MASKNOTPEN */
28     GXcopyInverted, /* R2_NOTCOPYPEN */
29     GXandReverse,   /* R2_MASKPENNOT */
30     GXinvert,       /* R2_NOT */
31     GXxor,          /* R2_XORPEN */
32     GXnand,         /* R2_NOTMASKPEN */
33     GXand,          /* R2_MASKPEN */
34     GXequiv,        /* R2_NOTXORPEN */
35     GXnoop,         /* R2_NOP */
36     GXorInverted,   /* R2_MERGENOTPEN */
37     GXcopy,         /* R2_COPYPEN */
38     GXorReverse,    /* R2_MERGEPENNOT */
39     GXor,           /* R2_MERGEPEN */
40     GXset           /* R2_WHITE */
41 };
42
43
44 /***********************************************************************
45  *           DC_FillDevCaps
46  *
47  * Fill the device caps structure.
48  */
49 void DC_FillDevCaps( DeviceCaps * caps )
50 {
51     caps->version       = 0x300; 
52     caps->technology    = DT_RASDISPLAY;
53     caps->horzSize      = WidthMMOfScreen(screen) * screenWidth / WidthOfScreen(screen);
54     caps->vertSize      = HeightMMOfScreen(screen) * screenHeight / HeightOfScreen(screen);
55     caps->horzRes       = screenWidth;
56     caps->vertRes       = screenHeight;
57     caps->bitsPixel     = screenDepth;
58     caps->planes        = 1;
59     caps->numBrushes    = 16+6;  /* 16 solid + 6 hatched brushes */
60     caps->numPens       = 16;    /* 16 solid pens */
61     caps->numMarkers    = 0;
62     caps->numFonts      = 0;
63     caps->numColors     = 100;
64     caps->pdeviceSize   = 0;
65     caps->curveCaps     = CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES |
66                           CC_WIDE | CC_STYLED | CC_WIDESTYLED | 
67                           CC_INTERIORS | CC_ROUNDRECT;
68     caps->lineCaps      = LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE |
69                           LC_STYLED | LC_WIDESTYLED | LC_INTERIORS;
70     caps->polygonalCaps = PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON |
71                           PC_SCANLINE | PC_WIDE | PC_STYLED | 
72                           PC_WIDESTYLED | PC_INTERIORS;
73     caps->textCaps      = TC_OP_CHARACTER | TC_OP_STROKE | TC_CP_STROKE |
74                           TC_IA_ABLE | TC_UA_ABLE | TC_SO_ABLE | TC_RA_ABLE;
75     caps->clipCaps      = CP_REGION;
76     caps->rasterCaps    = RC_BITBLT | RC_BANDING | RC_SCALING | RC_BITMAP64 |
77                           RC_DI_BITMAP | RC_DIBTODEV | RC_BIGFONT|
78                           RC_STRETCHBLT | RC_STRETCHDIB | RC_DEVBITS;
79
80     if( !(COLOR_GetSystemPaletteFlags() & COLOR_VIRTUAL) )
81         caps->rasterCaps |= RC_PALETTE;
82
83     caps->aspectX       = 36;  /* ?? */
84     caps->aspectY       = 36;  /* ?? */
85     caps->aspectXY      = 51;
86     caps->logPixelsX    = (int)(caps->horzRes * 25.4 / caps->horzSize);
87     caps->logPixelsY    = (int)(caps->vertRes * 25.4 / caps->vertSize);
88     caps->sizePalette   = (caps->rasterCaps & RC_PALETTE)
89                           ? DefaultVisual(display,DefaultScreen(display))->map_entries
90                           : 0;
91     caps->numReserved   = 0;
92     caps->colorRes      = 0;
93 }
94
95
96 /***********************************************************************
97  *           DC_Init_DC_INFO
98  *
99  * Fill the WIN_DC_INFO structure.
100  */
101 static void DC_Init_DC_INFO( WIN_DC_INFO *win_dc_info )
102 {
103     win_dc_info->flags           = 0;
104     win_dc_info->devCaps         = NULL;
105     win_dc_info->hClipRgn        = 0;
106     win_dc_info->hVisRgn         = 0;
107     win_dc_info->hGCClipRgn      = 0;
108     win_dc_info->hPen            = STOCK_BLACK_PEN;
109     win_dc_info->hBrush          = STOCK_WHITE_BRUSH;
110     win_dc_info->hFont           = STOCK_SYSTEM_FONT;
111     win_dc_info->hBitmap         = 0;
112     win_dc_info->hFirstBitmap    = 0;
113     win_dc_info->hDevice         = 0;
114     win_dc_info->hPalette        = STOCK_DEFAULT_PALETTE;
115     win_dc_info->ROPmode         = R2_COPYPEN;
116     win_dc_info->polyFillMode    = ALTERNATE;
117     win_dc_info->stretchBltMode  = BLACKONWHITE;
118     win_dc_info->relAbsMode      = ABSOLUTE;
119     win_dc_info->backgroundMode  = OPAQUE;
120     win_dc_info->backgroundColor = RGB( 255, 255, 255 );
121     win_dc_info->textColor       = RGB( 0, 0, 0 );
122     win_dc_info->backgroundPixel = 0;
123     win_dc_info->textPixel       = 0;
124     win_dc_info->brushOrgX       = 0;
125     win_dc_info->brushOrgY       = 0;
126     win_dc_info->textAlign       = TA_LEFT | TA_TOP | TA_NOUPDATECP;
127     win_dc_info->charExtra       = 0;
128     win_dc_info->breakTotalExtra = 0;
129     win_dc_info->breakCount      = 0;
130     win_dc_info->breakExtra      = 0;
131     win_dc_info->breakRem        = 0;
132     win_dc_info->bitsPerPixel    = 1;
133     win_dc_info->MapMode         = MM_TEXT;
134     win_dc_info->GraphicsMode    = GM_COMPATIBLE;
135     win_dc_info->DCOrgX          = 0;
136     win_dc_info->DCOrgY          = 0;
137     win_dc_info->CursPosX        = 0;
138     win_dc_info->CursPosY        = 0;
139
140     PATH_InitGdiPath(&win_dc_info->path);
141 }
142
143
144 /***********************************************************************
145  *           DC_AllocDC
146  */
147 DC *DC_AllocDC( const DC_FUNCTIONS *funcs )
148 {
149     HDC16 hdc;
150     DC *dc;
151
152     if (!(hdc = GDI_AllocObject( sizeof(DC), DC_MAGIC ))) return NULL;
153     dc = (DC *) GDI_HEAP_LOCK( hdc );
154
155     dc->hSelf      = hdc;
156     dc->funcs      = funcs;
157     dc->physDev    = NULL;
158     dc->saveLevel  = 0;
159     dc->dwHookData = 0L;
160     dc->hookProc   = NULL;
161     dc->wndOrgX    = 0;
162     dc->wndOrgY    = 0;
163     dc->wndExtX    = 1;
164     dc->wndExtY    = 1;
165     dc->vportOrgX  = 0;
166     dc->vportOrgY  = 0;
167     dc->vportExtX  = 1;
168     dc->vportExtY  = 1;
169
170     DC_Init_DC_INFO( &dc->w );
171
172     return dc;
173 }
174
175
176
177 /***********************************************************************
178  *           DC_GetDCPtr
179  */
180 DC *DC_GetDCPtr( HDC32 hdc )
181 {
182     GDIOBJHDR *ptr = (GDIOBJHDR *)GDI_HEAP_LOCK( hdc );
183     if (!ptr) return NULL;
184     if ((ptr->wMagic == DC_MAGIC) || (ptr->wMagic == METAFILE_DC_MAGIC))
185         return (DC *)ptr;
186     GDI_HEAP_UNLOCK( hdc );
187     return NULL;
188 }
189
190
191 /***********************************************************************
192  *           DC_InitDC
193  *
194  * Setup device-specific DC values for a newly created DC.
195  */
196 void DC_InitDC( DC* dc )
197 {
198     RealizeDefaultPalette( dc->hSelf );
199     SetTextColor32( dc->hSelf, dc->w.textColor );
200     SetBkColor32( dc->hSelf, dc->w.backgroundColor );
201     SelectObject32( dc->hSelf, dc->w.hPen );
202     SelectObject32( dc->hSelf, dc->w.hBrush );
203     SelectObject32( dc->hSelf, dc->w.hFont );
204     CLIPPING_UpdateGCRegion( dc );
205 }
206
207
208 /***********************************************************************
209  *           DC_SetupGCForPatBlt
210  *
211  * Setup the GC for a PatBlt operation using current brush.
212  * If fMapColors is TRUE, X pixels are mapped to Windows colors.
213  * Return FALSE if brush is BS_NULL, TRUE otherwise.
214  */
215 BOOL32 DC_SetupGCForPatBlt( DC * dc, GC gc, BOOL32 fMapColors )
216 {
217     XGCValues val;
218     unsigned long mask;
219     Pixmap pixmap = 0;
220
221     if (dc->u.x.brush.style == BS_NULL) return FALSE;
222     if (dc->u.x.brush.pixel == -1)
223     {
224         /* Special case used for monochrome pattern brushes.
225          * We need to swap foreground and background because
226          * Windows does it the wrong way...
227          */
228         val.foreground = dc->w.backgroundPixel;
229         val.background = dc->w.textPixel;
230     }
231     else
232     {
233         val.foreground = dc->u.x.brush.pixel;
234         val.background = dc->w.backgroundPixel;
235     }
236     if (fMapColors && COLOR_PixelToPalette)
237     {
238         val.foreground = COLOR_PixelToPalette[val.foreground];
239         val.background = COLOR_PixelToPalette[val.background];
240     }
241
242     if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
243
244     val.function = DC_XROPfunction[dc->w.ROPmode-1];
245     /*
246     ** Let's replace GXinvert by GXxor with (black xor white)
247     ** This solves the selection color and leak problems in excel
248     ** FIXME : Let's do that only if we work with X-pixels, not with Win-pixels
249     */
250     if (val.function == GXinvert)
251         {
252         val.foreground = BlackPixelOfScreen(screen) ^ WhitePixelOfScreen(screen);
253         val.function = GXxor;
254         }
255     val.fill_style = dc->u.x.brush.fillStyle;
256     switch(val.fill_style)
257     {
258     case FillStippled:
259     case FillOpaqueStippled:
260         if (dc->w.backgroundMode==OPAQUE) val.fill_style = FillOpaqueStippled;
261         val.stipple = dc->u.x.brush.pixmap;
262         mask = GCStipple;
263         break;
264
265     case FillTiled:
266         if (fMapColors && COLOR_PixelToPalette)
267         {
268             register int x, y;
269             XImage *image;
270             pixmap = XCreatePixmap( display, rootWindow, 8, 8, screenDepth );
271             image = XGetImage( display, dc->u.x.brush.pixmap, 0, 0, 8, 8,
272                                AllPlanes, ZPixmap );
273             for (y = 0; y < 8; y++)
274                 for (x = 0; x < 8; x++)
275                     XPutPixel( image, x, y,
276                                COLOR_PixelToPalette[XGetPixel( image, x, y)] );
277             XPutImage( display, pixmap, gc, image, 0, 0, 0, 0, 8, 8 );
278             XDestroyImage( image );
279             val.tile = pixmap;
280         }
281         else val.tile = dc->u.x.brush.pixmap;
282         mask = GCTile;
283         break;
284
285     default:
286         mask = 0;
287         break;
288     }
289     val.ts_x_origin = dc->w.DCOrgX + dc->w.brushOrgX;
290     val.ts_y_origin = dc->w.DCOrgY + dc->w.brushOrgY;
291     val.fill_rule = (dc->w.polyFillMode==WINDING) ? WindingRule : EvenOddRule;
292     XChangeGC( display, gc, 
293                GCFunction | GCForeground | GCBackground | GCFillStyle |
294                GCFillRule | GCTileStipXOrigin | GCTileStipYOrigin | mask,
295                &val );
296     if (pixmap) XFreePixmap( display, pixmap );
297     return TRUE;
298 }
299
300
301 /***********************************************************************
302  *           DC_SetupGCForBrush
303  *
304  * Setup dc->u.x.gc for drawing operations using current brush.
305  * Return FALSE if brush is BS_NULL, TRUE otherwise.
306  */
307 BOOL32 DC_SetupGCForBrush( DC * dc )
308 {
309     return DC_SetupGCForPatBlt( dc, dc->u.x.gc, FALSE );
310 }
311
312
313 /***********************************************************************
314  *           DC_SetupGCForPen
315  *
316  * Setup dc->u.x.gc for drawing operations using current pen.
317  * Return FALSE if pen is PS_NULL, TRUE otherwise.
318  */
319 BOOL32 DC_SetupGCForPen( DC * dc )
320 {
321     XGCValues val;
322
323     if (dc->u.x.pen.style == PS_NULL) return FALSE;
324
325     if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc); 
326
327     switch (dc->w.ROPmode)
328     {
329     case R2_BLACK :
330         val.foreground = BlackPixelOfScreen( screen );
331         val.function = GXcopy;
332         break;
333     case R2_WHITE :
334         val.foreground = WhitePixelOfScreen( screen );
335         val.function = GXcopy;
336         break;
337     case R2_XORPEN :
338         val.foreground = dc->u.x.pen.pixel;
339         /* It is very unlikely someone wants to XOR with 0 */
340         /* This fixes the rubber-drawings in paintbrush */
341         if (val.foreground == 0)
342             val.foreground = BlackPixelOfScreen( screen )
343                             ^ WhitePixelOfScreen( screen );
344         val.function = GXxor;
345         break;
346     default :
347         val.foreground = dc->u.x.pen.pixel;
348         val.function   = DC_XROPfunction[dc->w.ROPmode-1];
349     }
350     val.background = dc->w.backgroundPixel;
351     val.fill_style = FillSolid;
352     if ((dc->u.x.pen.style!=PS_SOLID) && (dc->u.x.pen.style!=PS_INSIDEFRAME))
353     {
354         XSetDashes( display, dc->u.x.gc, 0,
355                     dc->u.x.pen.dashes, dc->u.x.pen.dash_len );
356         val.line_style = (dc->w.backgroundMode == OPAQUE) ?
357                               LineDoubleDash : LineOnOffDash;
358     }
359     else val.line_style = LineSolid;
360     val.line_width = dc->u.x.pen.width;
361     if (val.line_width <= 1) {
362         val.cap_style = CapNotLast;
363     } else {
364         switch (dc->u.x.pen.endcap)
365         {
366         case PS_ENDCAP_SQUARE:
367             val.cap_style = CapProjecting;
368             break;
369         case PS_ENDCAP_FLAT:
370             val.cap_style = CapButt;
371             break;
372         case PS_ENDCAP_ROUND:
373         default:
374             val.cap_style = CapRound;
375         }
376     }
377     switch (dc->u.x.pen.linejoin)
378     {
379     case PS_JOIN_BEVEL:
380         val.join_style = JoinBevel;
381     case PS_JOIN_MITER:
382         val.join_style = JoinMiter;
383     case PS_JOIN_ROUND:
384     default:
385         val.join_style = JoinRound;
386     }
387     XChangeGC( display, dc->u.x.gc, 
388                GCFunction | GCForeground | GCBackground | GCLineWidth |
389                GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle, &val );
390     return TRUE;
391 }
392
393
394 /***********************************************************************
395  *           DC_SetupGCForText
396  *
397  * Setup dc->u.x.gc for text drawing operations.
398  * Return FALSE if the font is null, TRUE otherwise.
399  */
400 BOOL32 DC_SetupGCForText( DC * dc )
401 {
402     XFontStruct* xfs = XFONT_GetFontStruct( dc->u.x.font );
403
404     if( xfs )
405     {
406         XGCValues val;
407
408         if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
409
410         val.function   = GXcopy;  /* Text is always GXcopy */
411         val.foreground = dc->w.textPixel;
412         val.background = dc->w.backgroundPixel;
413         val.fill_style = FillSolid;
414         val.font       = xfs->fid;
415
416         XChangeGC( display, dc->u.x.gc,
417                    GCFunction | GCForeground | GCBackground | GCFillStyle |
418                    GCFont, &val );
419         return TRUE;
420     } 
421     fprintf( stderr, "DC_SetupGCForText: physical font failure\n" );
422     return FALSE;
423 }
424
425
426 /***********************************************************************
427  *           GetDCState    (GDI.179)
428  */
429 HDC16 WINAPI GetDCState( HDC16 hdc )
430 {
431     DC * newdc, * dc;
432     HGDIOBJ16 handle;
433     
434     if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
435     if (!(handle = GDI_AllocObject( sizeof(DC), DC_MAGIC )))
436     {
437       GDI_HEAP_UNLOCK( hdc );
438       return 0;
439     }
440     newdc = (DC *) GDI_HEAP_LOCK( handle );
441
442     dprintf_dc(stddeb, "GetDCState(%04x): returning %04x\n", hdc, handle );
443
444     memset( &newdc->u.x, 0, sizeof(newdc->u.x) );
445     newdc->w.flags           = dc->w.flags | DC_SAVED;
446     newdc->w.devCaps         = dc->w.devCaps;
447     newdc->w.hPen            = dc->w.hPen;       
448     newdc->w.hBrush          = dc->w.hBrush;     
449     newdc->w.hFont           = dc->w.hFont;      
450     newdc->w.hBitmap         = dc->w.hBitmap;    
451     newdc->w.hFirstBitmap    = dc->w.hFirstBitmap;
452     newdc->w.hDevice         = dc->w.hDevice;
453     newdc->w.hPalette        = dc->w.hPalette;   
454     newdc->w.bitsPerPixel    = dc->w.bitsPerPixel;
455     newdc->w.ROPmode         = dc->w.ROPmode;
456     newdc->w.polyFillMode    = dc->w.polyFillMode;
457     newdc->w.stretchBltMode  = dc->w.stretchBltMode;
458     newdc->w.relAbsMode      = dc->w.relAbsMode;
459     newdc->w.backgroundMode  = dc->w.backgroundMode;
460     newdc->w.backgroundColor = dc->w.backgroundColor;
461     newdc->w.textColor       = dc->w.textColor;
462     newdc->w.backgroundPixel = dc->w.backgroundPixel;
463     newdc->w.textPixel       = dc->w.textPixel;
464     newdc->w.brushOrgX       = dc->w.brushOrgX;
465     newdc->w.brushOrgY       = dc->w.brushOrgY;
466     newdc->w.textAlign       = dc->w.textAlign;
467     newdc->w.charExtra       = dc->w.charExtra;
468     newdc->w.breakTotalExtra = dc->w.breakTotalExtra;
469     newdc->w.breakCount      = dc->w.breakCount;
470     newdc->w.breakExtra      = dc->w.breakExtra;
471     newdc->w.breakRem        = dc->w.breakRem;
472     newdc->w.MapMode         = dc->w.MapMode;
473     newdc->w.DCOrgX          = dc->w.DCOrgX;
474     newdc->w.DCOrgY          = dc->w.DCOrgY;
475     newdc->w.CursPosX        = dc->w.CursPosX;
476     newdc->w.CursPosY        = dc->w.CursPosY;
477     newdc->wndOrgX           = dc->wndOrgX;
478     newdc->wndOrgY           = dc->wndOrgY;
479     newdc->wndExtX           = dc->wndExtX;
480     newdc->wndExtY           = dc->wndExtY;
481     newdc->vportOrgX         = dc->vportOrgX;
482     newdc->vportOrgY         = dc->vportOrgY;
483     newdc->vportExtX         = dc->vportExtX;
484     newdc->vportExtY         = dc->vportExtY;
485
486     newdc->hSelf = (HDC32)handle;
487     newdc->saveLevel = 0;
488
489     PATH_InitGdiPath( &newdc->w.path );
490     
491     /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
492
493     newdc->w.hGCClipRgn = newdc->w.hVisRgn = 0;
494     if (dc->w.hClipRgn)
495     {
496         newdc->w.hClipRgn = CreateRectRgn32( 0, 0, 0, 0 );
497         CombineRgn32( newdc->w.hClipRgn, dc->w.hClipRgn, 0, RGN_COPY );
498     }
499     else
500         newdc->w.hClipRgn = 0;
501     GDI_HEAP_UNLOCK( handle );
502     GDI_HEAP_UNLOCK( hdc );
503     return handle;
504 }
505
506
507 /***********************************************************************
508  *           SetDCState    (GDI.180)
509  */
510 void WINAPI SetDCState( HDC16 hdc, HDC16 hdcs )
511 {
512     DC *dc, *dcs;
513     
514     if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return;
515     if (!(dcs = (DC *) GDI_GetObjPtr( hdcs, DC_MAGIC )))
516     {
517       GDI_HEAP_UNLOCK( hdc );
518       return;
519     }
520     if (!dcs->w.flags & DC_SAVED)
521     {
522       GDI_HEAP_UNLOCK( hdc );
523       GDI_HEAP_UNLOCK( hdcs );
524       return;
525     }
526     dprintf_dc(stddeb, "SetDCState: %04x %04x\n", hdc, hdcs );
527
528     dc->w.flags           = dcs->w.flags & ~DC_SAVED;
529     dc->w.devCaps         = dcs->w.devCaps;
530     dc->w.hFirstBitmap    = dcs->w.hFirstBitmap;
531     dc->w.hDevice         = dcs->w.hDevice;
532     dc->w.ROPmode         = dcs->w.ROPmode;
533     dc->w.polyFillMode    = dcs->w.polyFillMode;
534     dc->w.stretchBltMode  = dcs->w.stretchBltMode;
535     dc->w.relAbsMode      = dcs->w.relAbsMode;
536     dc->w.backgroundMode  = dcs->w.backgroundMode;
537     dc->w.backgroundColor = dcs->w.backgroundColor;
538     dc->w.textColor       = dcs->w.textColor;
539     dc->w.backgroundPixel = dcs->w.backgroundPixel;
540     dc->w.textPixel       = dcs->w.textPixel;
541     dc->w.brushOrgX       = dcs->w.brushOrgX;
542     dc->w.brushOrgY       = dcs->w.brushOrgY;
543     dc->w.textAlign       = dcs->w.textAlign;
544     dc->w.charExtra       = dcs->w.charExtra;
545     dc->w.breakTotalExtra = dcs->w.breakTotalExtra;
546     dc->w.breakCount      = dcs->w.breakCount;
547     dc->w.breakExtra      = dcs->w.breakExtra;
548     dc->w.breakRem        = dcs->w.breakRem;
549     dc->w.MapMode         = dcs->w.MapMode;
550     dc->w.DCOrgX          = dcs->w.DCOrgX;
551     dc->w.DCOrgY          = dcs->w.DCOrgY;
552     dc->w.CursPosX        = dcs->w.CursPosX;
553     dc->w.CursPosY        = dcs->w.CursPosY;
554
555     dc->wndOrgX           = dcs->wndOrgX;
556     dc->wndOrgY           = dcs->wndOrgY;
557     dc->wndExtX           = dcs->wndExtX;
558     dc->wndExtY           = dcs->wndExtY;
559     dc->vportOrgX         = dcs->vportOrgX;
560     dc->vportOrgY         = dcs->vportOrgY;
561     dc->vportExtX         = dcs->vportExtX;
562     dc->vportExtY         = dcs->vportExtY;
563
564     if (!(dc->w.flags & DC_MEMORY)) dc->w.bitsPerPixel = dcs->w.bitsPerPixel;
565     SelectClipRgn32( hdc, dcs->w.hClipRgn );
566
567     SelectObject32( hdc, dcs->w.hBitmap );
568     SelectObject32( hdc, dcs->w.hBrush );
569     SelectObject32( hdc, dcs->w.hFont );
570     SelectObject32( hdc, dcs->w.hPen );
571     GDISelectPalette( hdc, dcs->w.hPalette, FALSE );
572     GDI_HEAP_UNLOCK( hdc );
573     GDI_HEAP_UNLOCK( hdcs );
574 }
575
576
577 /***********************************************************************
578  *           SaveDC16    (GDI.30)
579  */
580 INT16 WINAPI SaveDC16( HDC16 hdc )
581 {
582     return (INT16)SaveDC32( hdc );
583 }
584
585
586 /***********************************************************************
587  *           SaveDC32    (GDI32.292)
588  */
589 INT32 WINAPI SaveDC32( HDC32 hdc )
590 {
591     HDC32 hdcs;
592     DC * dc, * dcs;
593     INT32 ret;
594
595     dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
596     if (!dc) 
597     {
598         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
599         if (!dc) return 0;
600         MF_MetaParam0(dc, META_SAVEDC);
601         GDI_HEAP_UNLOCK( hdc );
602         return 1;  /* ?? */
603     }
604     if (!(hdcs = GetDCState( hdc )))
605     {
606       GDI_HEAP_UNLOCK( hdc );
607       return 0;
608     }
609     dcs = (DC *) GDI_HEAP_LOCK( hdcs );
610
611     /* Copy path. The reason why path saving / restoring is in SaveDC/
612      * RestoreDC and not in GetDCState/SetDCState is that the ...DCState
613      * functions are only in Win16 (which doesn't have paths) and that
614      * SetDCState doesn't allow us to signal an error (which can happen
615      * when copying paths).
616      */
617     if (!PATH_AssignGdiPath( &dcs->w.path, &dc->w.path ))
618     {
619         GDI_HEAP_UNLOCK( hdc );
620         GDI_HEAP_UNLOCK( hdcs );
621         DeleteDC32( hdcs );
622         return 0;
623     }
624     
625     dcs->header.hNext = dc->header.hNext;
626     dc->header.hNext = hdcs;
627     dprintf_dc(stddeb, "SaveDC(%04x): returning %d\n", hdc, dc->saveLevel+1 );
628     ret = ++dc->saveLevel;
629     GDI_HEAP_UNLOCK( hdcs );
630     GDI_HEAP_UNLOCK( hdc );
631     return ret;
632 }
633
634
635 /***********************************************************************
636  *           RestoreDC16    (GDI.39)
637  */
638 BOOL16 WINAPI RestoreDC16( HDC16 hdc, INT16 level )
639 {
640     return RestoreDC32( hdc, level );
641 }
642
643
644 /***********************************************************************
645  *           RestoreDC32    (GDI32.290)
646  */
647 BOOL32 WINAPI RestoreDC32( HDC32 hdc, INT32 level )
648 {
649     DC * dc, * dcs;
650     BOOL32 success;
651
652     dprintf_dc(stddeb, "RestoreDC: %04x %d\n", hdc, level );
653     dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
654     if (!dc) 
655     {
656         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
657         if (!dc) return FALSE;
658         if (level != -1) 
659         {
660           GDI_HEAP_UNLOCK( hdc );
661           return FALSE;
662         }
663         MF_MetaParam1(dc, META_RESTOREDC, level);
664         GDI_HEAP_UNLOCK( hdc );
665         return TRUE;
666     }
667     if (level == -1) level = dc->saveLevel;
668     if ((level < 1) || (level > dc->saveLevel))
669     {
670       GDI_HEAP_UNLOCK( hdc );
671       return FALSE;
672     }
673     
674     success=TRUE;
675     while (dc->saveLevel >= level)
676     {
677         HDC16 hdcs = dc->header.hNext;
678         if (!(dcs = (DC *) GDI_GetObjPtr( hdcs, DC_MAGIC )))
679         {
680           GDI_HEAP_UNLOCK( hdc );
681           return FALSE;
682         }       
683         dc->header.hNext = dcs->header.hNext;
684         if (--dc->saveLevel < level)
685         {
686             SetDCState( hdc, hdcs );
687             if (!PATH_AssignGdiPath( &dc->w.path, &dcs->w.path ))
688                 /* FIXME: This might not be quite right, since we're
689                  * returning FALSE but still destroying the saved DC state */
690                 success=FALSE;
691         }
692         DeleteDC32( hdcs );
693     }
694     GDI_HEAP_UNLOCK( hdc );
695     return success;
696 }
697
698
699 /***********************************************************************
700  *           CreateDC16    (GDI.53)
701  */
702 HDC16 WINAPI CreateDC16( LPCSTR driver, LPCSTR device, LPCSTR output,
703                          const DEVMODE16 *initData )
704 {
705     DC * dc;
706     const DC_FUNCTIONS *funcs;
707
708     if (!(funcs = DRIVER_FindDriver( driver ))) return 0;
709     if (!(dc = DC_AllocDC( funcs ))) return 0;
710     dc->w.flags = 0;
711
712     dprintf_dc(stddeb, "CreateDC(%s %s %s): returning %04x\n",
713                driver, device, output, dc->hSelf );
714
715     if (dc->funcs->pCreateDC &&
716         !dc->funcs->pCreateDC( dc, driver, device, output, initData ))
717     {
718         dprintf_dc( stddeb, "CreateDC: creation aborted by device\n" );
719         GDI_HEAP_FREE( dc->hSelf );
720         return 0;
721     }
722
723     DC_InitDC( dc );
724     GDI_HEAP_UNLOCK( dc->hSelf );
725     return dc->hSelf;
726 }
727
728
729 /***********************************************************************
730  *           CreateDC32A    (GDI32.)
731  */
732 HDC32 WINAPI CreateDC32A( LPCSTR driver, LPCSTR device, LPCSTR output,
733                           const DEVMODE32A *initData )
734 {
735     return CreateDC16( driver, device, output, (const DEVMODE16 *)initData );
736 }
737
738
739 /***********************************************************************
740  *           CreateDC32W    (GDI32.)
741  */
742 HDC32 WINAPI CreateDC32W( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
743                           const DEVMODE32W *initData )
744
745     LPSTR driverA = HEAP_strdupWtoA( GetProcessHeap(), 0, driver );
746     LPSTR deviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, device );
747     LPSTR outputA = HEAP_strdupWtoA( GetProcessHeap(), 0, output );
748     HDC32 res = CreateDC16( driverA, deviceA, outputA,
749                             (const DEVMODE16 *)initData /*FIXME*/ );
750     HeapFree( GetProcessHeap(), 0, driverA );
751     HeapFree( GetProcessHeap(), 0, deviceA );
752     HeapFree( GetProcessHeap(), 0, outputA );
753     return res;
754 }
755
756
757 /***********************************************************************
758  *           CreateIC16    (GDI.153)
759  */
760 HDC16 WINAPI CreateIC16( LPCSTR driver, LPCSTR device, LPCSTR output,
761                          const DEVMODE16* initData )
762 {
763       /* Nothing special yet for ICs */
764     return CreateDC16( driver, device, output, initData );
765 }
766
767
768 /***********************************************************************
769  *           CreateIC32A    (GDI32.49)
770  */
771 HDC32 WINAPI CreateIC32A( LPCSTR driver, LPCSTR device, LPCSTR output,
772                           const DEVMODE32A* initData )
773 {
774       /* Nothing special yet for ICs */
775     return CreateDC32A( driver, device, output, initData );
776 }
777
778
779 /***********************************************************************
780  *           CreateIC32W    (GDI32.50)
781  */
782 HDC32 WINAPI CreateIC32W( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
783                           const DEVMODE32W* initData )
784 {
785       /* Nothing special yet for ICs */
786     return CreateDC32W( driver, device, output, initData );
787 }
788
789
790 /***********************************************************************
791  *           CreateCompatibleDC16    (GDI.52)
792  */
793 HDC16 WINAPI CreateCompatibleDC16( HDC16 hdc )
794 {
795     return (HDC16)CreateCompatibleDC32( hdc );
796 }
797
798
799 /***********************************************************************
800  *           CreateCompatibleDC32   (GDI32.31)
801  */
802 HDC32 WINAPI CreateCompatibleDC32( HDC32 hdc )
803 {
804     DC *dc, *origDC;
805     HBITMAP32 hbitmap;
806     const DC_FUNCTIONS *funcs;
807
808     if ((origDC = (DC *)GDI_GetObjPtr( hdc, DC_MAGIC ))) funcs = origDC->funcs;
809     else funcs = DRIVER_FindDriver( "DISPLAY" );
810     if (!funcs) return 0;
811
812     if (!(dc = DC_AllocDC( funcs ))) return 0;
813
814     dprintf_dc(stddeb, "CreateCompatibleDC(%04x): returning %04x\n",
815                hdc, dc->hSelf );
816
817       /* Create default bitmap */
818     if (!(hbitmap = CreateBitmap32( 1, 1, 1, 1, NULL )))
819     {
820         GDI_HEAP_FREE( dc->hSelf );
821         return 0;
822     }
823     dc->w.flags        = DC_MEMORY;
824     dc->w.bitsPerPixel = 1;
825     dc->w.hBitmap      = hbitmap;
826     dc->w.hFirstBitmap = hbitmap;
827
828     if (dc->funcs->pCreateDC &&
829         !dc->funcs->pCreateDC( dc, NULL, NULL, NULL, NULL ))
830     {
831         dprintf_dc(stddeb, "CreateCompatibleDC: creation aborted by device\n");
832         DeleteObject32( hbitmap );
833         GDI_HEAP_FREE( dc->hSelf );
834         return 0;
835     }
836
837     DC_InitDC( dc );
838     GDI_HEAP_UNLOCK( dc->hSelf );
839     return dc->hSelf;
840 }
841
842
843 /***********************************************************************
844  *           DeleteDC16    (GDI.68)
845  */
846 BOOL16 WINAPI DeleteDC16( HDC16 hdc )
847 {
848     return DeleteDC32( hdc );
849 }
850
851
852 /***********************************************************************
853  *           DeleteDC32    (GDI32.67)
854  */
855 BOOL32 WINAPI DeleteDC32( HDC32 hdc )
856 {
857     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
858     if (!dc) return FALSE;
859
860     dprintf_dc(stddeb, "DeleteDC: %04x\n", hdc );
861
862     while (dc->saveLevel)
863     {
864         DC * dcs;
865         HDC16 hdcs = dc->header.hNext;
866         if (!(dcs = (DC *) GDI_GetObjPtr( hdcs, DC_MAGIC ))) break;
867         dc->header.hNext = dcs->header.hNext;
868         dc->saveLevel--;
869         DeleteDC32( hdcs );
870     }
871     
872     if (!(dc->w.flags & DC_SAVED))
873     {
874         SelectObject32( hdc, STOCK_BLACK_PEN );
875         SelectObject32( hdc, STOCK_WHITE_BRUSH );
876         SelectObject32( hdc, STOCK_SYSTEM_FONT );
877         if (dc->w.flags & DC_MEMORY) DeleteObject32( dc->w.hFirstBitmap );
878         if (dc->funcs->pDeleteDC) dc->funcs->pDeleteDC(dc);
879     }
880
881     if (dc->w.hClipRgn) DeleteObject32( dc->w.hClipRgn );
882     if (dc->w.hVisRgn) DeleteObject32( dc->w.hVisRgn );
883     if (dc->w.hGCClipRgn) DeleteObject32( dc->w.hGCClipRgn );
884     
885     PATH_DestroyGdiPath(&dc->w.path);
886     
887     return GDI_FreeObject( hdc );
888 }
889
890
891 /***********************************************************************
892  *           ResetDC16    (GDI.376)
893  */
894 HDC16 WINAPI ResetDC16( HDC16 hdc, const DEVMODE16 *devmode )
895 {
896     fprintf( stderr, "ResetDC16: empty stub!\n" );
897     return hdc;
898 }
899
900
901 /***********************************************************************
902  *           ResetDC32A    (GDI32.287)
903  */
904 HDC32 WINAPI ResetDC32A( HDC32 hdc, const DEVMODE32A *devmode )
905 {
906     fprintf( stderr, "ResetDC32A: empty stub!\n" );
907     return hdc;
908 }
909
910
911 /***********************************************************************
912  *           ResetDC32W    (GDI32.288)
913  */
914 HDC32 WINAPI ResetDC32W( HDC32 hdc, const DEVMODE32W *devmode )
915 {
916     fprintf( stderr, "ResetDC32A: empty stub!\n" );
917     return hdc;
918 }
919
920
921 /***********************************************************************
922  *           GetDeviceCaps16    (GDI.80)
923  */
924 INT16 WINAPI GetDeviceCaps16( HDC16 hdc, INT16 cap )
925 {
926     return GetDeviceCaps32( hdc, cap );
927 }
928
929
930 /***********************************************************************
931  *           GetDeviceCaps32    (GDI32.171)
932  */
933 INT32 WINAPI GetDeviceCaps32( HDC32 hdc, INT32 cap )
934 {
935     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
936     INT32 ret;
937
938     if (!dc) return 0;
939
940     if ((cap < 0) || (cap > sizeof(DeviceCaps)-sizeof(WORD)))
941     {
942       GDI_HEAP_UNLOCK( hdc );
943       return 0;
944     }
945     
946     dprintf_dc(stddeb, "GetDeviceCaps(%04x,%d): returning %d\n",
947             hdc, cap, *(WORD *)(((char *)dc->w.devCaps) + cap) );
948     ret = *(WORD *)(((char *)dc->w.devCaps) + cap);
949     GDI_HEAP_UNLOCK( hdc );
950     return ret;
951 }
952
953
954 /***********************************************************************
955  *           SetBkColor16    (GDI.1)
956  */
957 COLORREF WINAPI SetBkColor16( HDC16 hdc, COLORREF color )
958 {
959     return SetBkColor32( hdc, color );
960 }
961
962
963 /***********************************************************************
964  *           SetBkColor32    (GDI32.305)
965  */
966 COLORREF WINAPI SetBkColor32( HDC32 hdc, COLORREF color )
967 {
968     COLORREF oldColor;
969     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
970     if (!dc) 
971     {
972         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
973         if (!dc) return 0x80000000;
974         MF_MetaParam2(dc, META_SETBKCOLOR, HIWORD(color), LOWORD(color));
975         GDI_HEAP_UNLOCK( hdc );
976         return 0;  /* ?? */
977     }
978
979     oldColor = dc->w.backgroundColor;
980     dc->w.backgroundColor = color;
981     dc->w.backgroundPixel = COLOR_ToPhysical( dc, color );
982     GDI_HEAP_UNLOCK( hdc );
983     return oldColor;
984 }
985
986
987 /***********************************************************************
988  *           SetTextColor16    (GDI.9)
989  */
990 COLORREF WINAPI SetTextColor16( HDC16 hdc, COLORREF color )
991 {
992     return SetTextColor32( hdc, color );
993 }
994
995
996 /***********************************************************************
997  *           SetTextColor32    (GDI32.338)
998  */
999 COLORREF WINAPI SetTextColor32( HDC32 hdc, COLORREF color )
1000 {
1001     COLORREF oldColor;
1002     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
1003     if (!dc) 
1004     {
1005         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
1006         if (!dc) return 0x80000000;
1007         MF_MetaParam2(dc, META_SETTEXTCOLOR, HIWORD(color), LOWORD(color));
1008         GDI_HEAP_UNLOCK( hdc );
1009         return 0;  /* ?? */
1010     }
1011
1012     oldColor = dc->w.textColor;
1013     dc->w.textColor = color;
1014     dc->w.textPixel = COLOR_ToPhysical( dc, color );
1015     GDI_HEAP_UNLOCK( hdc );
1016     return oldColor;
1017 }
1018
1019
1020 /***********************************************************************
1021  *           SetTextAlign16    (GDI.346)
1022  */
1023 UINT16 WINAPI SetTextAlign16( HDC16 hdc, UINT16 textAlign )
1024 {
1025     return SetTextAlign32( hdc, textAlign );
1026 }
1027
1028
1029 /***********************************************************************
1030  *           SetTextAlign32    (GDI32.336)
1031  */
1032 UINT32 WINAPI SetTextAlign32( HDC32 hdc, UINT32 textAlign )
1033 {
1034     UINT32 prevAlign;
1035     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
1036     if (!dc)
1037     {
1038         if (!(dc = (DC *)GDI_GetObjPtr( hdc, METAFILE_DC_MAGIC ))) return 0;
1039         MF_MetaParam1( dc, META_SETTEXTALIGN, textAlign );
1040         GDI_HEAP_UNLOCK( hdc );
1041         return 1;
1042     }
1043     prevAlign = dc->w.textAlign;
1044     dc->w.textAlign = textAlign;
1045     GDI_HEAP_UNLOCK( hdc );
1046     return prevAlign;
1047 }
1048
1049
1050 /***********************************************************************
1051  *           GetDCOrgEx  (GDI32.168)
1052  */
1053 BOOL32 WINAPI GetDCOrgEx( HDC32 hDC, LPPOINT32 lpp )
1054 {
1055     DC * dc;
1056     if (!lpp) return FALSE;
1057     if (!(dc = (DC *) GDI_GetObjPtr( hDC, DC_MAGIC ))) return FALSE;
1058
1059     if (!(dc->w.flags & DC_MEMORY))
1060     {
1061        Window root;
1062        int w, h, border, depth;
1063        /* FIXME: this is not correct for managed windows */
1064        XGetGeometry( display, dc->u.x.drawable, &root,
1065                     &lpp->x, &lpp->y, &w, &h, &border, &depth );
1066     }
1067     else lpp->x = lpp->y = 0;
1068     lpp->x += dc->w.DCOrgX; lpp->y += dc->w.DCOrgY;
1069     GDI_HEAP_UNLOCK( hDC );
1070     return TRUE;
1071 }
1072
1073
1074 /***********************************************************************
1075  *           GetDCOrg    (GDI.79)
1076  */
1077 DWORD WINAPI GetDCOrg( HDC16 hdc )
1078 {
1079     POINT32     pt;
1080     if( GetDCOrgEx( hdc, &pt) )
1081         return MAKELONG( (WORD)pt.x, (WORD)pt.y );    
1082     return 0;
1083 }
1084
1085
1086 /***********************************************************************
1087  *           SetDCOrg    (GDI.117)
1088  */
1089 DWORD WINAPI SetDCOrg( HDC16 hdc, INT16 x, INT16 y )
1090 {
1091     DWORD prevOrg;
1092     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
1093     if (!dc) return 0;
1094     prevOrg = dc->w.DCOrgX | (dc->w.DCOrgY << 16);
1095     dc->w.DCOrgX = x;
1096     dc->w.DCOrgY = y;
1097     GDI_HEAP_UNLOCK( hdc );
1098     return prevOrg;
1099 }
1100
1101
1102 /***********************************************************************
1103  *           GetGraphicsMode    (GDI32.188)
1104  */
1105 INT32 WINAPI GetGraphicsMode( HDC32 hdc )
1106 {
1107     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
1108     if (!dc) return 0;
1109     return dc->w.GraphicsMode;
1110 }
1111
1112
1113 /***********************************************************************
1114  *           SetGraphicsMode    (GDI32.317)
1115  */
1116 INT32 WINAPI SetGraphicsMode( HDC32 hdc, INT32 mode )
1117 {
1118     INT32 ret;
1119     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
1120     if (!dc) return 0;
1121     if ((mode <= 0) || (mode > GM_LAST)) return 0;
1122     ret = dc->w.GraphicsMode;
1123     dc->w.GraphicsMode = mode;
1124     return ret;
1125 }
1126
1127
1128 /***********************************************************************
1129  *           GetWorldTransform    (GDI32.244)
1130  */
1131 BOOL32 WINAPI GetWorldTransform( HDC32 hdc, LPXFORM xform )
1132 {
1133     fprintf( stdnimp, "GetWorldTransform: empty stub\n" );
1134     return FALSE;
1135 }
1136
1137
1138 /***********************************************************************
1139  *           SetDCHook   (GDI.190)
1140  */
1141 BOOL16 WINAPI SetDCHook( HDC16 hdc, FARPROC16 hookProc, DWORD dwHookData )
1142 {
1143     DC *dc = (DC *)GDI_GetObjPtr( hdc, DC_MAGIC );
1144
1145     dprintf_dc( stddeb, "SetDCHook: hookProc %08x, default is %08x\n",
1146                 (UINT32)hookProc, (UINT32)DCHook );
1147
1148     if (!dc) return FALSE;
1149     dc->hookProc = hookProc;
1150     dc->dwHookData = dwHookData;
1151     GDI_HEAP_UNLOCK( hdc );
1152     return TRUE;
1153 }
1154
1155
1156 /***********************************************************************
1157  *           GetDCHook   (GDI.191)
1158  */
1159 DWORD WINAPI GetDCHook( HDC16 hdc, FARPROC16 *phookProc )
1160 {
1161     DC *dc = (DC *)GDI_GetObjPtr( hdc, DC_MAGIC );
1162     if (!dc) return 0;
1163     *phookProc = dc->hookProc;
1164     GDI_HEAP_UNLOCK( hdc );
1165     return dc->dwHookData;
1166 }
1167
1168
1169 /***********************************************************************
1170  *           SetHookFlags       (GDI.192)
1171  */
1172 WORD WINAPI SetHookFlags(HDC16 hDC, WORD flags)
1173 {
1174     DC* dc = (DC*)GDI_GetObjPtr( hDC, DC_MAGIC );
1175
1176     if( dc )
1177     {
1178         WORD wRet = dc->w.flags & DC_DIRTY;
1179
1180         /* "Undocumented Windows" info is slightly confusing.
1181          */
1182
1183         dprintf_dc(stddeb,"SetHookFlags: hDC %04x, flags %04x\n",hDC,flags);
1184
1185         if( flags & DCHF_INVALIDATEVISRGN )
1186             dc->w.flags |= DC_DIRTY;
1187         else if( flags & DCHF_VALIDATEVISRGN || !flags )
1188             dc->w.flags &= ~DC_DIRTY;
1189         GDI_HEAP_UNLOCK( hDC );
1190         return wRet;
1191     }
1192     return 0;
1193 }
1194