Release 960902
[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 "bitmap.h"
12 #include "metafile.h"
13 #include "stddebug.h"
14 #include "color.h"
15 #include "debug.h"
16 #include "font.h"
17 #include "callback.h"
18 #include "xmalloc.h"
19
20 extern void CLIPPING_UpdateGCRegion( DC * dc );     /* objects/clipping.c */
21 extern BOOL DCHook( HDC, WORD, DWORD, DWORD );      /* windows/dce.c */
22
23   /* Default DC values */
24 static const WIN_DC_INFO DC_defaultValues =
25 {
26     0,                      /* flags */
27     NULL,                   /* devCaps */
28     0,                      /* hMetaFile */
29     0,                      /* hClipRgn */
30     0,                      /* hVisRgn */
31     0,                      /* hGCClipRgn */
32     STOCK_BLACK_PEN,        /* hPen */
33     STOCK_WHITE_BRUSH,      /* hBrush */
34     STOCK_SYSTEM_FONT,      /* hFont */
35     0,                      /* hBitmap */
36     0,                      /* hFirstBitmap */
37     0,                      /* hDevice */
38     STOCK_DEFAULT_PALETTE,  /* hPalette */
39     R2_COPYPEN,             /* ROPmode */
40     ALTERNATE,              /* polyFillMode */
41     BLACKONWHITE,           /* stretchBltMode */
42     ABSOLUTE,               /* relAbsMode */
43     OPAQUE,                 /* backgroundMode */
44     RGB( 255, 255, 255 ),   /* backgroundColor */
45     RGB( 0, 0, 0 ),         /* textColor */
46     0,                      /* backgroundPixel */
47     0,                      /* textPixel */
48     0,                      /* brushOrgX */
49     0,                      /* brushOrgY */
50     TA_LEFT | TA_TOP | TA_NOUPDATECP,  /* textAlign */
51     0,                      /* charExtra */
52     0,                      /* breakTotalExtra */
53     0,                      /* breakCount */
54     0,                      /* breakExtra */
55     0,                      /* breakRem */
56     1,                      /* bitsPerPixel */
57     MM_TEXT,                /* MapMode */
58     0,                      /* DCOrgX */
59     0,                      /* DCOrgY */
60     0,                      /* CursPosX */
61     0,                      /* CursPosY */
62     0,                      /* WndOrgX */
63     0,                      /* WndOrgY */
64     1,                      /* WndExtX */
65     1,                      /* WndExtY */
66     0,                      /* VportOrgX */
67     0,                      /* VportOrgY */
68     1,                      /* VportExtX */
69     1                       /* VportExtY */
70 };
71
72   /* ROP code to GC function conversion */
73 const int DC_XROPfunction[16] =
74 {
75     GXclear,        /* R2_BLACK */
76     GXnor,          /* R2_NOTMERGEPEN */
77     GXandInverted,  /* R2_MASKNOTPEN */
78     GXcopyInverted, /* R2_NOTCOPYPEN */
79     GXandReverse,   /* R2_MASKPENNOT */
80     GXinvert,       /* R2_NOT */
81     GXxor,          /* R2_XORPEN */
82     GXnand,         /* R2_NOTMASKPEN */
83     GXand,          /* R2_MASKPEN */
84     GXequiv,        /* R2_NOTXORPEN */
85     GXnoop,         /* R2_NOP */
86     GXorInverted,   /* R2_MERGENOTPEN */
87     GXcopy,         /* R2_COPYPEN */
88     GXorReverse,    /* R2_MERGEPENNOT */
89     GXor,           /* R2_MERGEPEN */
90     GXset           /* R2_WHITE */
91 };
92
93
94 /***********************************************************************
95  *           DC_FillDevCaps
96  *
97  * Fill the device caps structure.
98  */
99 void DC_FillDevCaps( DeviceCaps * caps )
100 {
101     caps->version       = 0x300; 
102     caps->technology    = DT_RASDISPLAY;
103     caps->horzSize      = WidthMMOfScreen(screen) * screenWidth / WidthOfScreen(screen);
104     caps->vertSize      = HeightMMOfScreen(screen) * screenHeight / HeightOfScreen(screen);
105     caps->horzRes       = screenWidth;
106     caps->vertRes       = screenHeight;
107     caps->bitsPixel     = screenDepth;
108     caps->planes        = 1;
109     caps->numBrushes    = 16+6;  /* 16 solid + 6 hatched brushes */
110     caps->numPens       = 16;    /* 16 solid pens */
111     caps->numMarkers    = 0;
112     caps->numFonts      = 0;
113     caps->numColors     = 100;
114     caps->pdeviceSize   = 0;
115     caps->curveCaps     = CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES |
116                           CC_WIDE | CC_STYLED | CC_WIDESTYLED | 
117                           CC_INTERIORS | CC_ROUNDRECT;
118     caps->lineCaps      = LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE |
119                           LC_STYLED | LC_WIDESTYLED | LC_INTERIORS;
120     caps->polygonalCaps = PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON |
121                           PC_SCANLINE | PC_WIDE | PC_STYLED | 
122                           PC_WIDESTYLED | PC_INTERIORS;
123     caps->textCaps      = TC_OP_CHARACTER | TC_OP_STROKE | TC_CP_STROKE |
124                           TC_IA_ABLE | TC_UA_ABLE | TC_SO_ABLE | TC_RA_ABLE;
125     caps->clipCaps      = CP_REGION;
126     caps->rasterCaps    = RC_BITBLT | RC_BANDING | RC_SCALING | RC_BITMAP64 |
127                           RC_DI_BITMAP | RC_DIBTODEV | RC_BIGFONT|
128                           RC_STRETCHBLT | RC_STRETCHDIB | RC_DEVBITS;
129
130     if( !(COLOR_GetSystemPaletteFlags() & COLOR_VIRTUAL) )
131         caps->rasterCaps |= RC_PALETTE;
132
133     caps->aspectX       = 36;  /* ?? */
134     caps->aspectY       = 36;  /* ?? */
135     caps->aspectXY      = 51;
136     caps->logPixelsX    = (int)(caps->horzRes * 25.4 / caps->horzSize);
137     caps->logPixelsY    = (int)(caps->vertRes * 25.4 / caps->vertSize);
138     caps->sizePalette   = (caps->rasterCaps & RC_PALETTE)
139                           ? DefaultVisual(display,DefaultScreen(display))->map_entries
140                           : 0;
141     caps->numReserved   = 0;
142     caps->colorRes      = 0;
143 }
144
145
146 /***********************************************************************
147  *           DC_InitDC
148  *
149  * Setup device-specific DC values for a newly created DC.
150  */
151 void DC_InitDC( DC* dc )
152 {
153     RealizeDefaultPalette( dc->hSelf );
154     SetTextColor( dc->hSelf, dc->w.textColor );
155     SetBkColor( dc->hSelf, dc->w.backgroundColor );
156     SelectObject( dc->hSelf, dc->w.hPen );
157     SelectObject( dc->hSelf, dc->w.hBrush );
158     SelectObject( dc->hSelf, dc->w.hFont );
159     CLIPPING_UpdateGCRegion( dc );
160 }
161
162
163 /***********************************************************************
164  *           DC_SetupGCForPatBlt
165  *
166  * Setup the GC for a PatBlt operation using current brush.
167  * If fMapColors is TRUE, X pixels are mapped to Windows colors.
168  * Return FALSE if brush is BS_NULL, TRUE otherwise.
169  */
170 BOOL DC_SetupGCForPatBlt( DC * dc, GC gc, BOOL fMapColors )
171 {
172     XGCValues val;
173     unsigned long mask;
174     Pixmap pixmap = 0;
175
176     if (dc->u.x.brush.style == BS_NULL) return FALSE;
177     if (dc->u.x.brush.pixel == -1)
178     {
179         /* Special case used for monochrome pattern brushes.
180          * We need to swap foreground and background because
181          * Windows does it the wrong way...
182          */
183         val.foreground = dc->w.backgroundPixel;
184         val.background = dc->w.textPixel;
185     }
186     else
187     {
188         val.foreground = dc->u.x.brush.pixel;
189         val.background = dc->w.backgroundPixel;
190     }
191     if (fMapColors && COLOR_PixelToPalette)
192     {
193         val.foreground = COLOR_PixelToPalette[val.foreground];
194         val.background = COLOR_PixelToPalette[val.background];
195     }
196
197     if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
198
199     val.function = DC_XROPfunction[dc->w.ROPmode-1];
200     val.fill_style = dc->u.x.brush.fillStyle;
201     switch(val.fill_style)
202     {
203     case FillStippled:
204     case FillOpaqueStippled:
205         if (dc->w.backgroundMode==OPAQUE) val.fill_style = FillOpaqueStippled;
206         val.stipple = dc->u.x.brush.pixmap;
207         mask = GCStipple;
208         break;
209
210     case FillTiled:
211         if (fMapColors && COLOR_PixelToPalette)
212         {
213             register int x, y;
214             XImage *image;
215             pixmap = XCreatePixmap( display, rootWindow, 8, 8, screenDepth );
216             image = XGetImage( display, dc->u.x.brush.pixmap, 0, 0, 8, 8,
217                                AllPlanes, ZPixmap );
218             for (y = 0; y < 8; y++)
219                 for (x = 0; x < 8; x++)
220                     XPutPixel( image, x, y,
221                                COLOR_PixelToPalette[XGetPixel( image, x, y)] );
222             XPutImage( display, pixmap, gc, image, 0, 0, 0, 0, 8, 8 );
223             XDestroyImage( image );
224             val.tile = pixmap;
225         }
226         else val.tile = dc->u.x.brush.pixmap;
227         mask = GCTile;
228         break;
229
230     default:
231         mask = 0;
232         break;
233     }
234     val.ts_x_origin = dc->w.DCOrgX + dc->w.brushOrgX;
235     val.ts_y_origin = dc->w.DCOrgY + dc->w.brushOrgY;
236     val.fill_rule = (dc->w.polyFillMode==WINDING) ? WindingRule : EvenOddRule;
237     XChangeGC( display, gc, 
238                GCFunction | GCForeground | GCBackground | GCFillStyle |
239                GCFillRule | GCTileStipXOrigin | GCTileStipYOrigin | mask,
240                &val );
241     if (pixmap) XFreePixmap( display, pixmap );
242     return TRUE;
243 }
244
245
246 /***********************************************************************
247  *           DC_SetupGCForBrush
248  *
249  * Setup dc->u.x.gc for drawing operations using current brush.
250  * Return FALSE if brush is BS_NULL, TRUE otherwise.
251  */
252 BOOL DC_SetupGCForBrush( DC * dc )
253 {
254     return DC_SetupGCForPatBlt( dc, dc->u.x.gc, FALSE );
255 }
256
257
258 /***********************************************************************
259  *           DC_SetupGCForPen
260  *
261  * Setup dc->u.x.gc for drawing operations using current pen.
262  * Return FALSE if pen is PS_NULL, TRUE otherwise.
263  */
264 BOOL DC_SetupGCForPen( DC * dc )
265 {
266     XGCValues val;
267
268     if (dc->u.x.pen.style == PS_NULL) return FALSE;
269
270     if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc); 
271
272     if ((screenDepth <= 8) &&  /* FIXME: Should check for palette instead */
273         ((dc->w.ROPmode == R2_BLACK) || (dc->w.ROPmode == R2_WHITE)))
274     {
275         val.function   = GXcopy;
276         val.foreground = COLOR_ToPhysical( NULL, (dc->w.ROPmode == R2_BLACK) ?
277                                                RGB(0,0,0) : RGB(255,255,255) );
278     }
279     else
280     {
281         val.function   = DC_XROPfunction[dc->w.ROPmode-1];
282         val.foreground = dc->u.x.pen.pixel;
283     }
284     val.background = dc->w.backgroundPixel;
285     val.fill_style = FillSolid;
286     if ((dc->u.x.pen.style!=PS_SOLID) && (dc->u.x.pen.style!=PS_INSIDEFRAME))
287     {
288         XSetDashes( display, dc->u.x.gc, 0,
289                     dc->u.x.pen.dashes, dc->u.x.pen.dash_len );
290         val.line_style = (dc->w.backgroundMode == OPAQUE) ?
291                               LineDoubleDash : LineOnOffDash;
292     }
293     else val.line_style = LineSolid;
294     val.line_width = dc->u.x.pen.width;
295     val.cap_style  = CapRound;
296     val.join_style = JoinBevel;
297     XChangeGC( display, dc->u.x.gc, 
298                GCFunction | GCForeground | GCBackground | GCLineWidth |
299                GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle, &val );
300     return TRUE;
301 }
302
303
304 /***********************************************************************
305  *           DC_SetupGCForText
306  *
307  * Setup dc->u.x.gc for text drawing operations.
308  * Return FALSE if the font is null, TRUE otherwise.
309  */
310 BOOL DC_SetupGCForText( DC * dc )
311 {
312     XGCValues val;
313
314     if (!dc->u.x.font.fstruct)
315     {
316         fprintf( stderr, "DC_SetupGCForText: fstruct is NULL. Please report this\n" );
317         return FALSE;
318     }
319    
320     if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
321
322     val.function   = GXcopy;  /* Text is always GXcopy */
323     val.foreground = dc->w.textPixel;
324     val.background = dc->w.backgroundPixel;
325     val.fill_style = FillSolid;
326     val.font       = dc->u.x.font.fstruct->fid;
327     XChangeGC( display, dc->u.x.gc, 
328                GCFunction | GCForeground | GCBackground | GCFillStyle |
329                GCFont, &val );
330     return TRUE;
331 }
332
333
334 /***********************************************************************
335  *           DC_CallHookProc
336  */
337 BOOL DC_CallHookProc(DC* dc, WORD code, LPARAM lParam)
338 {
339   BOOL bRet = FALSE;
340   FARPROC16 ptr = GDI_GetDefDCHook();
341
342   dprintf_dc(stddeb,"CallDCHook: code %04x\n", code);
343
344   /* if 16-bit callback is, in fact, a thunk to DCHook simply call DCHook */
345
346   if( dc->hookProc && !(dc->w.flags & (DC_SAVED | DC_MEMORY)) )
347     bRet = (dc->hookProc == ptr) ?
348           DCHook(dc->hSelf, code, dc->dwHookData, lParam):
349           CallDCHookProc(dc->hookProc, dc->hSelf, code, dc->dwHookData, lParam);
350
351   return bRet;
352 }
353
354 /***********************************************************************
355  *           GetDCState    (GDI.179)
356  */
357 HDC GetDCState( HDC hdc )
358 {
359     DC * newdc, * dc;
360     HANDLE handle;
361     
362     if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
363     if (!(handle = GDI_AllocObject( sizeof(DC), DC_MAGIC ))) return 0;
364     newdc = (DC *) GDI_HEAP_LIN_ADDR( handle );
365
366     dprintf_dc(stddeb, "GetDCState(%04x): returning %04x\n", hdc, handle );
367
368     memset( &newdc->u.x, 0, sizeof(newdc->u.x) );
369     memcpy( &newdc->w, &dc->w, sizeof(dc->w) );
370     memcpy( &newdc->u.x.pen, &dc->u.x.pen, sizeof(dc->u.x.pen) );
371
372     newdc->hSelf = (HDC)handle;
373     newdc->saveLevel = 0;
374     newdc->w.flags |= DC_SAVED;
375
376     newdc->w.hGCClipRgn = 0;
377     newdc->w.hVisRgn = CreateRectRgn( 0, 0, 0, 0 );
378     CombineRgn( newdc->w.hVisRgn, dc->w.hVisRgn, 0, RGN_COPY ); 
379     if (dc->w.hClipRgn)
380     {
381         newdc->w.hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
382         CombineRgn( newdc->w.hClipRgn, dc->w.hClipRgn, 0, RGN_COPY );
383     }
384     return handle;
385 }
386
387
388 /***********************************************************************
389  *           SetDCState    (GDI.180)
390  */
391 void SetDCState( HDC hdc, HDC hdcs )
392 {
393     DC * dc, * dcs;
394     HRGN hVisRgn, hClipRgn, hGCClipRgn;
395     HFONT hfont;
396     HBRUSH hbrush;
397     
398     if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return;
399     if (!(dcs = (DC *) GDI_GetObjPtr( hdcs, DC_MAGIC ))) return;
400     if (!dcs->w.flags & DC_SAVED) return;
401     dprintf_dc(stddeb, "SetDCState: %04x %04x\n", hdc, hdcs );
402
403       /* Save the regions, font & brush before overwriting everything */
404     hVisRgn    = dc->w.hVisRgn;
405     hClipRgn   = dc->w.hClipRgn;
406     hGCClipRgn = dc->w.hGCClipRgn;
407     hfont      = dc->w.hFont;
408     hbrush     = dc->w.hBrush;
409     memcpy( &dc->w, &dcs->w, sizeof(dc->w) );
410     memcpy( &dc->u.x.pen, &dcs->u.x.pen, sizeof(dc->u.x.pen) );
411     dc->w.flags &= ~DC_SAVED;
412
413       /* Restore the regions */
414     dc->w.hVisRgn    = hVisRgn;
415     dc->w.hClipRgn   = hClipRgn;
416     dc->w.hGCClipRgn = hGCClipRgn;
417     dc->w.hFont      = hfont;
418     dc->w.hBrush     = hbrush;
419     CombineRgn( dc->w.hVisRgn, dcs->w.hVisRgn, 0, RGN_COPY );
420     SelectClipRgn( hdc, dcs->w.hClipRgn );
421
422     SelectObject( hdc, dcs->w.hBrush );
423     SelectObject( hdc, dcs->w.hFont );
424 }
425
426
427 /***********************************************************************
428  *           SaveDC    (GDI.30)
429  */
430 int SaveDC( HDC hdc )
431 {
432     HDC hdcs;
433     DC * dc, * dcs;
434
435     dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
436     if (!dc) 
437     {
438         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
439         if (!dc) return 0;
440         MF_MetaParam0(dc, META_SAVEDC);
441         return 1;  /* ?? */
442     }
443     if (!(hdcs = GetDCState( hdc ))) return 0;
444     dcs = (DC *) GDI_HEAP_LIN_ADDR( hdcs );
445     dcs->header.hNext = dc->header.hNext;
446     dc->header.hNext = hdcs;
447     dprintf_dc(stddeb, "SaveDC(%04x): returning %d\n", hdc, dc->saveLevel+1 );
448     return ++dc->saveLevel;
449 }
450
451
452 /***********************************************************************
453  *           RestoreDC    (GDI.39)
454  */
455 BOOL RestoreDC( HDC hdc, short level )
456 {
457     DC * dc, * dcs;
458
459     dprintf_dc(stddeb, "RestoreDC: %04x %d\n", hdc, level );
460     dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
461     if (!dc) 
462     {
463         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
464         if (!dc) return FALSE;
465         if (level != -1) return FALSE;
466         MF_MetaParam1(dc, META_RESTOREDC, level);
467         return TRUE;
468     }
469     if (level == -1) level = dc->saveLevel;
470     if ((level < 1) || (level > (short)dc->saveLevel)) return FALSE;
471     
472     while ((short)dc->saveLevel >= level)
473     {
474         HDC hdcs = dc->header.hNext;
475         if (!(dcs = (DC *) GDI_GetObjPtr( hdcs, DC_MAGIC ))) return FALSE;
476         dc->header.hNext = dcs->header.hNext;
477         if ((short)--dc->saveLevel < level) SetDCState( hdc, hdcs );
478         DeleteDC( hdcs );
479     }
480     return TRUE;
481 }
482
483
484 /***********************************************************************
485  *           CreateDC    (GDI.53)
486  */
487 HDC CreateDC( LPCSTR driver, LPCSTR device, LPCSTR output, const DEVMODE* initData )
488 {
489     DC * dc;
490     HDC16 handle;
491     const DC_FUNCTIONS *funcs;
492
493     if (!(funcs = DRIVER_FindDriver( driver ))) return 0;
494
495     handle = GDI_AllocObject( sizeof(DC), DC_MAGIC );
496     if (!handle) return 0;
497     dc = (DC *) GDI_HEAP_LIN_ADDR( handle );
498
499     dprintf_dc(stddeb, "CreateDC(%s %s %s): returning %04x\n",
500             driver, device, output, handle );
501
502     dc->hSelf      = handle;
503     dc->funcs      = funcs;
504     dc->physDev    = NULL;
505     dc->saveLevel  = 0;
506     dc->dwHookData = 0L;
507     dc->hookProc   = (SEGPTR)0;
508
509     memcpy( &dc->w, &DC_defaultValues, sizeof(DC_defaultValues) );
510     dc->w.flags = 0;
511
512     if (dc->funcs->pCreateDC &&
513         !dc->funcs->pCreateDC( dc, driver, device, output, initData ))
514     {
515         dprintf_dc( stddeb, "CreateDC: creation aborted by device\n" );
516         GDI_HEAP_FREE( handle );
517         return 0;
518     }
519
520     DC_InitDC( dc );
521
522     return handle;
523 }
524
525
526 /***********************************************************************
527  *           CreateIC    (GDI.153)
528  */
529 HDC CreateIC( LPCSTR driver, LPCSTR device, LPCSTR output, const DEVMODE* initData )
530 {
531       /* Nothing special yet for ICs */
532     return CreateDC( driver, device, output, initData );
533 }
534
535
536 /***********************************************************************
537  *           CreateCompatibleDC    (GDI.52)
538  */
539 HDC CreateCompatibleDC( HDC hdc )
540 {
541     DC *dc, *origDC;
542     HDC16 handle;
543     HBITMAP hbitmap;
544     const DC_FUNCTIONS *funcs;
545
546     if ((origDC = (DC *)GDI_GetObjPtr( hdc, DC_MAGIC ))) funcs = origDC->funcs;
547     else funcs = DRIVER_FindDriver( "DISPLAY" );
548     if (!funcs) return 0;
549
550     handle = GDI_AllocObject( sizeof(DC), DC_MAGIC );
551     if (!handle) return 0;
552     dc = (DC *) GDI_HEAP_LIN_ADDR( handle );
553
554     dprintf_dc(stddeb, "CreateCompatibleDC(%04x): returning %04x\n", hdc, handle );
555
556       /* Create default bitmap */
557     if (!(hbitmap = CreateBitmap( 1, 1, 1, 1, NULL )))
558     {
559         GDI_HEAP_FREE( handle );
560         return 0;
561     }
562
563     memcpy( &dc->w, &DC_defaultValues, sizeof(DC_defaultValues) );
564
565     dc->hSelf          = handle;
566     dc->funcs          = funcs;
567     dc->physDev        = NULL;
568     dc->saveLevel      = 0;
569     dc->dwHookData     = 0L;
570     dc->hookProc       = (SEGPTR)0;
571     dc->w.flags        = DC_MEMORY;
572     dc->w.bitsPerPixel = 1;
573     dc->w.hBitmap      = hbitmap;
574     dc->w.hFirstBitmap = hbitmap;
575
576     if (dc->funcs->pCreateDC &&
577         !dc->funcs->pCreateDC( dc, NULL, NULL, NULL, NULL ))
578     {
579         dprintf_dc( stddeb, "CreateDC: creation aborted by device\n" );
580         DeleteObject( hbitmap );
581         GDI_HEAP_FREE( handle );
582         return 0;
583     }
584
585     DC_InitDC( dc );
586
587     return handle;
588 }
589
590
591 /***********************************************************************
592  *           DeleteDC    (GDI.68)
593  */
594 BOOL DeleteDC( HDC hdc )
595 {
596     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
597     if (!dc) return FALSE;
598
599     dprintf_dc(stddeb, "DeleteDC: %04x\n", hdc );
600
601     while (dc->saveLevel)
602     {
603         DC * dcs;
604         HDC hdcs = dc->header.hNext;
605         if (!(dcs = (DC *) GDI_GetObjPtr( hdcs, DC_MAGIC ))) break;
606         dc->header.hNext = dcs->header.hNext;
607         dc->saveLevel--;
608         DeleteDC( hdcs );
609     }
610     
611     if (!(dc->w.flags & DC_SAVED))
612     {
613         SelectObject( hdc, STOCK_BLACK_PEN );
614         SelectObject( hdc, STOCK_WHITE_BRUSH );
615         SelectObject( hdc, STOCK_SYSTEM_FONT );
616         if (dc->w.flags & DC_MEMORY) DeleteObject( dc->w.hFirstBitmap );
617         if (dc->funcs->pDeleteDC) dc->funcs->pDeleteDC(dc);
618     }
619
620     if (dc->w.hClipRgn) DeleteObject( dc->w.hClipRgn );
621     if (dc->w.hVisRgn) DeleteObject( dc->w.hVisRgn );
622     if (dc->w.hGCClipRgn) DeleteObject( dc->w.hGCClipRgn );
623     
624     return GDI_FreeObject( hdc );
625 }
626
627
628 /***********************************************************************
629  *           ResetDC    (GDI.376)
630  */
631 HDC ResetDC( HDC hdc, /* DEVMODE */ void *devmode )
632 {
633     fprintf( stderr, "ResetDC: empty stub!\n" );
634     return hdc;
635 }
636
637
638 /***********************************************************************
639  *           GetDeviceCaps    (GDI.80)
640  */
641 int GetDeviceCaps( HDC hdc, WORD cap )
642 {
643     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
644     if (!dc) return 0;
645
646     if (cap > sizeof(DeviceCaps)-sizeof(WORD)) return 0;
647     
648     dprintf_dc(stddeb, "GetDeviceCaps(%04x,%d): returning %d\n",
649             hdc, cap, *(WORD *)(((char *)dc->w.devCaps) + cap) );
650     return *(WORD *)(((char *)dc->w.devCaps) + cap);
651 }
652
653
654 /***********************************************************************
655  *           SetBkColor    (GDI.1) (GDI32.305)
656  */
657 COLORREF SetBkColor( HDC32 hdc, COLORREF color )
658 {
659     COLORREF oldColor;
660     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
661     if (!dc) 
662     {
663         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
664         if (!dc) return 0x80000000;
665         MF_MetaParam2(dc, META_SETBKCOLOR, HIWORD(color), LOWORD(color));
666         return 0;  /* ?? */
667     }
668
669     oldColor = dc->w.backgroundColor;
670     dc->w.backgroundColor = color;
671     dc->w.backgroundPixel = COLOR_ToPhysical( dc, color );
672     return oldColor;
673 }
674
675
676 /***********************************************************************
677  *           SetTextColor    (GDI.9) (GDI32.338)
678  */
679 COLORREF SetTextColor( HDC32 hdc, COLORREF color )
680 {
681     COLORREF oldColor;
682     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
683     if (!dc) 
684     {
685         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
686         if (!dc) return 0x80000000;
687         MF_MetaParam2(dc, META_SETTEXTCOLOR, HIWORD(color), LOWORD(color));
688         return 0;  /* ?? */
689     }
690
691     oldColor = dc->w.textColor;
692     dc->w.textColor = color;
693     dc->w.textPixel = COLOR_ToPhysical( dc, color );
694     return oldColor;
695 }
696
697
698 /***********************************************************************
699  *           SetTextAlign    (GDI.346)
700  */
701 WORD SetTextAlign( HDC hdc, WORD textAlign )
702 {
703     WORD prevAlign;
704     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
705     if (!dc)
706     {
707         if (!(dc = (DC *)GDI_GetObjPtr( hdc, METAFILE_DC_MAGIC ))) return 0;
708         MF_MetaParam1( dc, META_SETTEXTALIGN, textAlign );
709         return 1;
710     }
711     prevAlign = dc->w.textAlign;
712     dc->w.textAlign = textAlign;
713     return prevAlign;
714 }
715
716
717 /***********************************************************************
718  *           GetDCOrg    (GDI.79)
719  */
720 DWORD GetDCOrg( HDC hdc )
721 {
722     Window root;
723     int x, y, w, h, border, depth;
724
725     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
726     if (!dc) return 0;
727     if (dc->w.flags & DC_MEMORY) return 0;
728     XGetGeometry( display, dc->u.x.drawable, &root,
729                   &x, &y, &w, &h, &border, &depth );
730     return MAKELONG( dc->w.DCOrgX + (WORD)x, dc->w.DCOrgY + (WORD)y );
731 }
732
733
734 /***********************************************************************
735  *           SetDCOrg    (GDI.117)
736  */
737 DWORD SetDCOrg( HDC hdc, short x, short y )
738 {
739     DWORD prevOrg;
740     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
741     if (!dc) return 0;
742     prevOrg = dc->w.DCOrgX | (dc->w.DCOrgY << 16);
743     dc->w.DCOrgX = x;
744     dc->w.DCOrgY = y;
745     return prevOrg;
746 }
747
748
749 /***********************************************************************
750  *           SetDCHook   (GDI.190)
751  */
752 BOOL SetDCHook( HDC hDC, FARPROC16 hookProc, DWORD dwHookData )
753 {
754     DC *dc = (DC *)GDI_GetObjPtr( hDC, DC_MAGIC );
755
756     dprintf_dc( stddeb, "SetDCHook: hookProc %08x, default is %08x\n",
757                 (unsigned)hookProc,(unsigned)GDI_GetDefDCHook() );
758
759     if (!dc) return FALSE;
760     dc->hookProc = hookProc;
761     dc->dwHookData = dwHookData;
762     return TRUE;
763 }
764
765
766 /***********************************************************************
767  *           GetDCHook   (GDI.191)
768  */
769 DWORD GetDCHook( HDC hDC, FARPROC16 *phookProc )
770 {
771     DC *dc = (DC *)GDI_GetObjPtr( hDC, DC_MAGIC );
772     if (!dc) return 0;
773     *phookProc = dc->hookProc;
774     return dc->dwHookData;
775 }
776
777
778 /***********************************************************************
779  *           SetHookFlags       (GDI.192)
780  */
781 WORD SetHookFlags(HDC hDC, WORD flags)
782 {
783   DC* dc = (DC*)GDI_GetObjPtr( hDC, DC_MAGIC );
784
785   if( dc )
786     {
787         WORD wRet = dc->w.flags & DC_DIRTY;
788
789         /* "Undocumented Windows" info is slightly
790          *  confusing
791          */
792
793         dprintf_dc(stddeb,"SetHookFlags: hDC %04x, flags %04x\n",hDC,flags);
794
795         if( flags & DCHF_INVALIDATEVISRGN )
796             dc->w.flags |= DC_DIRTY;
797         else if( flags & DCHF_VALIDATEVISRGN || !flags )
798             dc->w.flags &= ~DC_DIRTY;
799         return wRet;
800     }
801   return 0;
802 }
803