kernel32: FindFirstChangeNotification needs a static IO_STATUS_BLOCK.
[wine] / dlls / gdi / pen.c
1 /*
2  * GDI pen objects
3  *
4  * Copyright 1993 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "wine/wingdi16.h"
32 #include "gdi.h"
33 #include "gdi_private.h"
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
37
38   /* GDI logical pen object */
39 typedef struct
40 {
41     GDIOBJHDR header;
42     EXTLOGPEN logpen;
43 } PENOBJ;
44
45
46 static HGDIOBJ PEN_SelectObject( HGDIOBJ handle, void *obj, HDC hdc );
47 static INT PEN_GetObject16( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
48 static INT PEN_GetObject( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
49
50 static const struct gdi_obj_funcs pen_funcs =
51 {
52     PEN_SelectObject,  /* pSelectObject */
53     PEN_GetObject16,   /* pGetObject16 */
54     PEN_GetObject,     /* pGetObjectA */
55     PEN_GetObject,     /* pGetObjectW */
56     NULL,              /* pUnrealizeObject */
57     GDI_FreeObject     /* pDeleteObject */
58 };
59
60
61 /***********************************************************************
62  *           CreatePen    (GDI32.@)
63  */
64 HPEN WINAPI CreatePen( INT style, INT width, COLORREF color )
65 {
66     LOGPEN logpen;
67
68     TRACE("%d %d %06lx\n", style, width, color );
69
70     logpen.lopnStyle = style;
71     logpen.lopnWidth.x = width;
72     logpen.lopnWidth.y = 0;
73     logpen.lopnColor = color;
74
75     return CreatePenIndirect( &logpen );
76 }
77
78
79 /***********************************************************************
80  *           CreatePenIndirect    (GDI32.@)
81  */
82 HPEN WINAPI CreatePenIndirect( const LOGPEN * pen )
83 {
84     PENOBJ * penPtr;
85     HPEN hpen;
86
87     if (!(penPtr = GDI_AllocObject( sizeof(PENOBJ), PEN_MAGIC, (HGDIOBJ *)&hpen,
88                                     &pen_funcs ))) return 0;
89     if (pen->lopnStyle == PS_USERSTYLE || pen->lopnStyle == PS_ALTERNATE)
90         penPtr->logpen.elpPenStyle = PS_SOLID;
91     else
92         penPtr->logpen.elpPenStyle = pen->lopnStyle;
93     if (pen->lopnStyle == PS_NULL)
94     {
95         penPtr->logpen.elpWidth = 1;
96         penPtr->logpen.elpColor = RGB(0, 0, 0);
97     }
98     else
99     {
100         penPtr->logpen.elpWidth = abs(pen->lopnWidth.x);
101         penPtr->logpen.elpColor = pen->lopnColor;
102     }
103     penPtr->logpen.elpBrushStyle = BS_SOLID;
104     penPtr->logpen.elpHatch = 0;
105     penPtr->logpen.elpNumEntries = 0;
106     penPtr->logpen.elpStyleEntry[0] = 0;
107
108     GDI_ReleaseObj( hpen );
109     return hpen;
110 }
111
112 /***********************************************************************
113  *           ExtCreatePen    (GDI32.@)
114  *
115  * FIXME: PS_USERSTYLE not handled
116  */
117
118 HPEN WINAPI ExtCreatePen( DWORD style, DWORD width,
119                               const LOGBRUSH * brush, DWORD style_count,
120                               const DWORD *style_bits )
121 {
122     PENOBJ * penPtr;
123     HPEN hpen;
124
125     if ((style & PS_STYLE_MASK) == PS_USERSTYLE)
126     {
127         if (!style_count || !style_bits)
128         {
129             SetLastError(ERROR_INVALID_PARAMETER);
130             return 0;
131         }
132         /* FIXME: PS_USERSTYLE workaround */
133         FIXME("PS_USERSTYLE not handled\n");
134         style = (style & ~PS_STYLE_MASK) | PS_SOLID;
135     }
136     else
137     {
138         if (style_count || style_bits)
139         {
140             SetLastError(ERROR_INVALID_PARAMETER);
141             return 0;
142         }
143     }
144
145     if ((style & PS_STYLE_MASK) == PS_NULL)
146         return CreatePen( PS_NULL, 0, brush->lbColor );
147
148     if ((style & PS_TYPE_MASK) == PS_GEOMETRIC)
149     {
150         /* PS_ALTERNATE is applicable only for cosmetic pens */
151         if ((style & PS_STYLE_MASK) == PS_ALTERNATE)
152         {
153             SetLastError(ERROR_INVALID_PARAMETER);
154             return 0;
155         }
156
157         if (brush->lbHatch && ((brush->lbStyle == BS_SOLID) || (brush->lbStyle == BS_HOLLOW)))
158             FIXME("Hatches not implemented\n"); 
159     }
160     else
161     {
162         /* PS_INSIDEFRAME is applicable only for gemetric pens */
163         if ((style & PS_STYLE_MASK) == PS_INSIDEFRAME || width != 1)
164         {
165             SetLastError(ERROR_INVALID_PARAMETER);
166             return 0;
167         }
168     }
169
170     if (!(penPtr = GDI_AllocObject( sizeof(PENOBJ) +
171                                     style_count * sizeof(DWORD) - sizeof(penPtr->logpen.elpStyleEntry),
172                                     EXT_PEN_MAGIC, (HGDIOBJ *)&hpen,
173                                     &pen_funcs ))) return 0;
174
175     penPtr->logpen.elpPenStyle = style;
176     penPtr->logpen.elpWidth = abs(width);
177     penPtr->logpen.elpBrushStyle = brush->lbStyle;
178     penPtr->logpen.elpColor = brush->lbColor;
179     penPtr->logpen.elpHatch = brush->lbHatch;
180     penPtr->logpen.elpNumEntries = style_count;
181     memcpy(penPtr->logpen.elpStyleEntry, style_bits, style_count * sizeof(DWORD));
182     
183     GDI_ReleaseObj( hpen );
184
185     return hpen;
186 }
187
188
189 /***********************************************************************
190  *           PEN_SelectObject
191  */
192 static HGDIOBJ PEN_SelectObject( HGDIOBJ handle, void *obj, HDC hdc )
193 {
194     HGDIOBJ ret;
195     DC *dc = DC_GetDCPtr( hdc );
196
197     if (!dc) return 0;
198     ret = dc->hPen;
199     if (dc->funcs->pSelectPen) handle = dc->funcs->pSelectPen( dc->physDev, handle );
200     if (handle) dc->hPen = handle;
201     else ret = 0;
202     GDI_ReleaseObj( hdc );
203     return ret;
204 }
205
206
207 /***********************************************************************
208  *           PEN_GetObject16
209  */
210 static INT PEN_GetObject16( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
211 {
212     PENOBJ *pen = obj;
213     LOGPEN16 *logpen;
214
215     if (!buffer) return sizeof(LOGPEN16);
216
217     if (count < sizeof(LOGPEN16)) return 0;
218
219     logpen = buffer;
220     logpen->lopnStyle = pen->logpen.elpPenStyle;
221     logpen->lopnColor = pen->logpen.elpColor;
222     logpen->lopnWidth.x = pen->logpen.elpWidth;
223     logpen->lopnWidth.y = 0;
224
225     return sizeof(LOGPEN16);
226 }
227
228
229 /***********************************************************************
230  *           PEN_GetObject
231  */
232 static INT PEN_GetObject( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
233 {
234     PENOBJ *pen = obj;
235
236     switch (GDIMAGIC(pen->header.wMagic))
237     {
238     case PEN_MAGIC:
239     {
240         LOGPEN *lp;
241
242         if (!buffer) return sizeof(LOGPEN);
243
244         if (count < sizeof(LOGPEN)) return 0;
245
246         if ((pen->logpen.elpPenStyle & PS_STYLE_MASK) == PS_NULL &&
247             count == sizeof(EXTLOGPEN))
248         {
249             EXTLOGPEN *elp = buffer;
250             memcpy(elp, &pen->logpen, sizeof(EXTLOGPEN));
251             elp->elpWidth = 0;
252             return sizeof(EXTLOGPEN);
253         }
254
255         lp = buffer;
256         lp->lopnStyle = pen->logpen.elpPenStyle;
257         lp->lopnColor = pen->logpen.elpColor;
258         lp->lopnWidth.x = pen->logpen.elpWidth;
259         lp->lopnWidth.y = 0;
260         return sizeof(LOGPEN);
261     }
262
263     case EXT_PEN_MAGIC:
264     {
265         INT size = sizeof(EXTLOGPEN) + pen->logpen.elpNumEntries * sizeof(DWORD) - sizeof(pen->logpen.elpStyleEntry);
266
267         if (!buffer) return size;
268
269         if (count < size) return 0;
270         memcpy(buffer, &pen->logpen, size);
271         return size;
272     }
273
274     default:
275         break;
276     }
277     assert(0);
278     return 0;
279 }