Fix some types and function prototypes according to Platform SDK
[wine] / controls / static.c
1 /*
2  * Static control
3  *
4  * Copyright  David W. Metcalfe, 1993
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 "windef.h"
22 #include "wingdi.h"
23 #include "wine/winuser16.h"
24 #include "wownt32.h"
25 #include "cursoricon.h"
26 #include "controls.h"
27 #include "user.h"
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(static);
31
32 static void STATIC_PaintOwnerDrawfn( HWND hwnd, HDC hdc, DWORD style );
33 static void STATIC_PaintTextfn( HWND hwnd, HDC hdc, DWORD style );
34 static void STATIC_PaintRectfn( HWND hwnd, HDC hdc, DWORD style );
35 static void STATIC_PaintIconfn( HWND hwnd, HDC hdc, DWORD style );
36 static void STATIC_PaintBitmapfn( HWND hwnd, HDC hdc, DWORD style );
37 static void STATIC_PaintEtchedfn( HWND hwnd, HDC hdc, DWORD style );
38 static LRESULT WINAPI StaticWndProcA( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
39 static LRESULT WINAPI StaticWndProcW( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
40
41 static COLORREF color_windowframe, color_background, color_window;
42
43 /* offsets for GetWindowLong for static private information */
44 #define HFONT_GWL_OFFSET    0
45 #define HICON_GWL_OFFSET    (sizeof(HFONT))
46 #define STATIC_EXTRA_BYTES  (HICON_GWL_OFFSET + sizeof(HICON))
47
48 typedef void (*pfPaint)( HWND hwnd, HDC hdc, DWORD style );
49
50 static pfPaint staticPaintFunc[SS_TYPEMASK+1] =
51 {
52     STATIC_PaintTextfn,      /* SS_LEFT */
53     STATIC_PaintTextfn,      /* SS_CENTER */
54     STATIC_PaintTextfn,      /* SS_RIGHT */
55     STATIC_PaintIconfn,      /* SS_ICON */
56     STATIC_PaintRectfn,      /* SS_BLACKRECT */
57     STATIC_PaintRectfn,      /* SS_GRAYRECT */
58     STATIC_PaintRectfn,      /* SS_WHITERECT */
59     STATIC_PaintRectfn,      /* SS_BLACKFRAME */
60     STATIC_PaintRectfn,      /* SS_GRAYFRAME */
61     STATIC_PaintRectfn,      /* SS_WHITEFRAME */
62     NULL,                    /* Not defined */
63     STATIC_PaintTextfn,      /* SS_SIMPLE */
64     STATIC_PaintTextfn,      /* SS_LEFTNOWORDWRAP */
65     STATIC_PaintOwnerDrawfn, /* SS_OWNERDRAW */
66     STATIC_PaintBitmapfn,    /* SS_BITMAP */
67     NULL,                    /* SS_ENHMETAFILE */
68     STATIC_PaintEtchedfn,    /* SS_ETCHEDHORIZ */
69     STATIC_PaintEtchedfn,    /* SS_ETCHEDVERT */
70     STATIC_PaintEtchedfn,    /* SS_ETCHEDFRAME */
71 };
72
73
74 /*********************************************************************
75  * static class descriptor
76  */
77 const struct builtin_class_descr STATIC_builtin_class =
78 {
79     "Static",            /* name */
80     CS_GLOBALCLASS | CS_DBLCLKS | CS_PARENTDC, /* style  */
81     StaticWndProcA,      /* procA */
82     StaticWndProcW,      /* procW */
83     STATIC_EXTRA_BYTES,  /* extra */
84     IDC_ARROWA,          /* cursor */
85     0                    /* brush */
86 };
87
88
89 /***********************************************************************
90  *           STATIC_SetIcon
91  *
92  * Set the icon for an SS_ICON control.
93  */
94 static HICON STATIC_SetIcon( HWND hwnd, HICON hicon, DWORD style )
95 {
96     HICON prevIcon;
97     CURSORICONINFO *info = hicon?(CURSORICONINFO *) GlobalLock16(HICON_16(hicon)):NULL;
98
99     if ((style & SS_TYPEMASK) != SS_ICON) return 0;
100     if (hicon && !info) {
101         ERR("huh? hicon!=0, but info=0???\n");
102         return 0;
103     }
104     prevIcon = (HICON)SetWindowLongA( hwnd, HICON_GWL_OFFSET, (LONG)hicon );
105     if (hicon)
106     {
107         SetWindowPos( hwnd, 0, 0, 0, info->nWidth, info->nHeight,
108                         SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
109         GlobalUnlock16(HICON_16(hicon));
110     }
111     return prevIcon;
112 }
113
114 /***********************************************************************
115  *           STATIC_SetBitmap
116  *
117  * Set the bitmap for an SS_BITMAP control.
118  */
119 static HBITMAP STATIC_SetBitmap( HWND hwnd, HBITMAP hBitmap, DWORD style )
120 {
121     HBITMAP hOldBitmap;
122
123     if ((style & SS_TYPEMASK) != SS_BITMAP) return 0;
124     if (hBitmap && GetObjectType(hBitmap) != OBJ_BITMAP) {
125         ERR("huh? hBitmap!=0, but not bitmap\n");
126         return 0;
127     }
128     hOldBitmap = (HBITMAP)SetWindowLongA( hwnd, HICON_GWL_OFFSET, (LONG)hBitmap );
129     if (hBitmap)
130     {
131         BITMAP bm;
132         GetObjectW(hBitmap, sizeof(bm), &bm);
133         SetWindowPos( hwnd, 0, 0, 0, bm.bmWidth, bm.bmHeight,
134                       SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
135     }
136     return hOldBitmap;
137 }
138
139 /***********************************************************************
140  *           STATIC_LoadIconA
141  *
142  * Load the icon for an SS_ICON control.
143  */
144 static HICON STATIC_LoadIconA( HWND hwnd, LPCSTR name )
145 {
146     HINSTANCE hInstance = (HINSTANCE)GetWindowLongA( hwnd, GWL_HINSTANCE );
147     HICON hicon = LoadIconA( hInstance, name );
148     if (!hicon) hicon = LoadIconA( 0, name );
149     return hicon;
150 }
151
152 /***********************************************************************
153  *           STATIC_LoadIconW
154  *
155  * Load the icon for an SS_ICON control.
156  */
157 static HICON STATIC_LoadIconW( HWND hwnd, LPCWSTR name )
158 {
159     HINSTANCE hInstance = (HINSTANCE)GetWindowLongA( hwnd, GWL_HINSTANCE );
160     HICON hicon = LoadIconW( hInstance, name );
161     if (!hicon) hicon = LoadIconW( 0, name );
162     return hicon;
163 }
164
165 /***********************************************************************
166  *           STATIC_LoadBitmapA
167  *
168  * Load the bitmap for an SS_BITMAP control.
169  */
170 static HBITMAP STATIC_LoadBitmapA( HWND hwnd, LPCSTR name )
171 {
172     HINSTANCE hInstance = (HINSTANCE)GetWindowLongA( hwnd, GWL_HINSTANCE );
173     HBITMAP hbitmap = LoadBitmapA( hInstance, name );
174     if (!hbitmap)  /* Try OEM icon (FIXME: is this right?) */
175         hbitmap = LoadBitmapA( 0, name );
176     return hbitmap;
177 }
178
179 /***********************************************************************
180  *           STATIC_LoadBitmapW
181  *
182  * Load the bitmap for an SS_BITMAP control.
183  */
184 static HBITMAP STATIC_LoadBitmapW( HWND hwnd, LPCWSTR name )
185 {
186     HINSTANCE hInstance = (HINSTANCE)GetWindowLongA( hwnd, GWL_HINSTANCE );
187     HBITMAP hbitmap = LoadBitmapW( hInstance, name );
188     if (!hbitmap)  /* Try OEM icon (FIXME: is this right?) */
189         hbitmap = LoadBitmapW( 0, name );
190     return hbitmap;
191 }
192
193 /***********************************************************************
194  *           STATIC_TryPaintFcn
195  *
196  * Try to immediately paint the control.
197  */
198 static VOID STATIC_TryPaintFcn(HWND hwnd, LONG full_style)
199 {
200     LONG style = full_style & SS_TYPEMASK;
201     RECT rc;
202
203     GetClientRect( hwnd, &rc );
204     if (!IsRectEmpty(&rc) && IsWindowVisible(hwnd) && staticPaintFunc[style])
205     {
206         HDC hdc;
207         hdc = GetDC( hwnd );
208         (staticPaintFunc[style])( hwnd, hdc, full_style );
209         ReleaseDC( hwnd, hdc );
210     }
211 }
212
213 /***********************************************************************
214  *           StaticWndProc_common
215  */
216 static LRESULT StaticWndProc_common( HWND hwnd, UINT uMsg, WPARAM wParam,
217                                      LPARAM lParam, BOOL unicode )
218 {
219     LRESULT lResult = 0;
220     LONG full_style = GetWindowLongA( hwnd, GWL_STYLE );
221     LONG style = full_style & SS_TYPEMASK;
222
223     switch (uMsg)
224     {
225     case WM_CREATE:
226         if (style < 0L || style > SS_TYPEMASK)
227         {
228             ERR("Unknown style 0x%02lx\n", style );
229             return -1;
230         }
231         /* initialise colours */
232         color_windowframe  = GetSysColor(COLOR_WINDOWFRAME);
233         color_background   = GetSysColor(COLOR_BACKGROUND);
234         color_window       = GetSysColor(COLOR_WINDOW);
235         break;
236
237     case WM_NCDESTROY:
238         if (style == SS_ICON) {
239 /*
240  * FIXME
241  *           DestroyIcon32( STATIC_SetIcon( wndPtr, 0 ) );
242  *
243  * We don't want to do this yet because DestroyIcon32 is broken. If the icon
244  * had already been loaded by the application the last thing we want to do is
245  * GlobalFree16 the handle.
246  */
247             break;
248         }
249         else return unicode ? DefWindowProcW(hwnd, uMsg, wParam, lParam) :
250                               DefWindowProcA(hwnd, uMsg, wParam, lParam);
251
252     case WM_PAINT:
253         {
254             PAINTSTRUCT ps;
255             BeginPaint(hwnd, &ps);
256             if (staticPaintFunc[style])
257                 (staticPaintFunc[style])( hwnd, ps.hdc, full_style );
258             EndPaint(hwnd, &ps);
259         }
260         break;
261
262     case WM_ENABLE:
263         InvalidateRect(hwnd, NULL, TRUE);
264         break;
265
266     case WM_SYSCOLORCHANGE:
267         color_windowframe  = GetSysColor(COLOR_WINDOWFRAME);
268         color_background   = GetSysColor(COLOR_BACKGROUND);
269         color_window       = GetSysColor(COLOR_WINDOW);
270         InvalidateRect(hwnd, NULL, TRUE);
271         break;
272
273     case WM_NCCREATE:
274         if ((TWEAK_WineLook > WIN31_LOOK) && (full_style & SS_SUNKEN))
275             SetWindowLongA( hwnd, GWL_EXSTYLE,
276                             GetWindowLongA( hwnd, GWL_EXSTYLE ) | WS_EX_STATICEDGE );
277
278         if(unicode)
279             lParam = (LPARAM)(((LPCREATESTRUCTW)lParam)->lpszName);
280         else
281             lParam = (LPARAM)(((LPCREATESTRUCTA)lParam)->lpszName);
282         /* fall through */
283     case WM_SETTEXT:
284         switch (style) {
285         case SS_ICON:
286         {
287             HICON hIcon;
288             if(unicode)
289                 hIcon = STATIC_LoadIconW(hwnd, (LPCWSTR)lParam);
290             else
291                 hIcon = STATIC_LoadIconA(hwnd, (LPCSTR)lParam);
292             /* FIXME : should we also return the previous hIcon here ??? */
293             STATIC_SetIcon(hwnd, hIcon, style);
294             break;
295         }
296         case SS_BITMAP:
297         {
298             HBITMAP hBitmap;
299             if(unicode)
300                 hBitmap = STATIC_LoadBitmapW(hwnd, (LPCWSTR)lParam);
301             else
302                 hBitmap = STATIC_LoadBitmapA(hwnd, (LPCSTR)lParam);
303             STATIC_SetBitmap(hwnd, hBitmap, style);
304             break;
305         }
306         case SS_LEFT:
307         case SS_CENTER:
308         case SS_RIGHT:
309         case SS_SIMPLE:
310         case SS_LEFTNOWORDWRAP:
311         {
312             if (HIWORD(lParam))
313             {
314                 if(unicode)
315                     lResult = DefWindowProcW( hwnd, WM_SETTEXT, wParam, lParam );
316                 else
317                     lResult = DefWindowProcA( hwnd, WM_SETTEXT, wParam, lParam );
318             }
319             if (uMsg == WM_SETTEXT)
320                 STATIC_TryPaintFcn( hwnd, full_style );
321             break;
322         }
323         default:
324             if (HIWORD(lParam))
325             {
326                 if(unicode)
327                     lResult = DefWindowProcW( hwnd, WM_SETTEXT, wParam, lParam );
328                 else
329                     lResult = DefWindowProcA( hwnd, WM_SETTEXT, wParam, lParam );
330             }
331             if(uMsg == WM_SETTEXT)
332                 InvalidateRect(hwnd, NULL, TRUE);
333         }
334         return 1; /* success. FIXME: check text length */
335
336     case WM_SETFONT:
337         if ((style == SS_ICON) || (style == SS_BITMAP)) return 0;
338         SetWindowLongA( hwnd, HFONT_GWL_OFFSET, wParam );
339         if (LOWORD(lParam))
340             InvalidateRect( hwnd, NULL, TRUE );
341         break;
342
343     case WM_GETFONT:
344         return GetWindowLongA( hwnd, HFONT_GWL_OFFSET );
345
346     case WM_NCHITTEST:
347         if (full_style & SS_NOTIFY)
348            return HTCLIENT;
349         else
350            return HTTRANSPARENT;
351
352     case WM_GETDLGCODE:
353         return DLGC_STATIC;
354
355     case STM_GETIMAGE:
356     case STM_GETICON16:
357     case STM_GETICON:
358         return GetWindowLongA( hwnd, HICON_GWL_OFFSET );
359
360     case STM_SETIMAGE:
361         switch(wParam) {
362         case IMAGE_BITMAP:
363             lResult = (LRESULT)STATIC_SetBitmap( hwnd, (HBITMAP)lParam, style );
364             break;
365         case IMAGE_ICON:
366             lResult = (LRESULT)STATIC_SetIcon( hwnd, (HICON)lParam, style );
367             break;
368         default:
369             FIXME("STM_SETIMAGE: Unhandled type %x\n", wParam);
370             break;
371         }
372         InvalidateRect( hwnd, NULL, TRUE );
373         break;
374
375     case STM_SETICON16:
376     case STM_SETICON:
377         lResult = (LRESULT)STATIC_SetIcon( hwnd, (HICON)wParam, style );
378         InvalidateRect( hwnd, NULL, TRUE );
379         break;
380
381     default:
382         return unicode ? DefWindowProcW(hwnd, uMsg, wParam, lParam) :
383                          DefWindowProcA(hwnd, uMsg, wParam, lParam);
384     }
385     return lResult;
386 }
387
388 /***********************************************************************
389  *           StaticWndProcA
390  */
391 static LRESULT WINAPI StaticWndProcA( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
392 {
393     if (!IsWindow( hWnd )) return 0;
394     return StaticWndProc_common(hWnd, uMsg, wParam, lParam, FALSE);
395 }
396
397 /***********************************************************************
398  *           StaticWndProcW
399  */
400 static LRESULT WINAPI StaticWndProcW( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
401 {
402     if (!IsWindow( hWnd )) return 0;
403     return StaticWndProc_common(hWnd, uMsg, wParam, lParam, TRUE);
404 }
405
406 static void STATIC_PaintOwnerDrawfn( HWND hwnd, HDC hdc, DWORD style )
407 {
408   DRAWITEMSTRUCT dis;
409   LONG id = GetWindowLongA( hwnd, GWL_ID );
410
411   dis.CtlType    = ODT_STATIC;
412   dis.CtlID      = id;
413   dis.itemID     = 0;
414   dis.itemAction = ODA_DRAWENTIRE;
415   dis.itemState  = 0;
416   dis.hwndItem   = hwnd;
417   dis.hDC        = hdc;
418   dis.itemData   = 0;
419   GetClientRect( hwnd, &dis.rcItem );
420
421   SendMessageW( GetParent(hwnd), WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd );
422   SendMessageW( GetParent(hwnd), WM_DRAWITEM, id, (LPARAM)&dis );
423 }
424
425 static void STATIC_PaintTextfn( HWND hwnd, HDC hdc, DWORD style )
426 {
427     RECT rc;
428     HBRUSH hBrush;
429     HFONT hFont;
430     WORD wFormat;
431     INT len;
432     WCHAR *text;
433
434     GetClientRect( hwnd, &rc);
435
436     switch (style & SS_TYPEMASK)
437     {
438     case SS_LEFT:
439         wFormat = DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK | DT_NOCLIP;
440         break;
441
442     case SS_CENTER:
443         wFormat = DT_CENTER | DT_EXPANDTABS | DT_WORDBREAK | DT_NOCLIP;
444         break;
445
446     case SS_RIGHT:
447         wFormat = DT_RIGHT | DT_EXPANDTABS | DT_WORDBREAK | DT_NOCLIP;
448         break;
449
450     case SS_SIMPLE:
451         wFormat = DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_NOCLIP;
452         break;
453
454     case SS_LEFTNOWORDWRAP:
455         wFormat = DT_LEFT | DT_EXPANDTABS | DT_VCENTER;
456         break;
457
458     default:
459         return;
460     }
461
462     if (style & SS_NOPREFIX)
463         wFormat |= DT_NOPREFIX;
464
465     if ((hFont = (HFONT)GetWindowLongA( hwnd, HFONT_GWL_OFFSET ))) SelectObject( hdc, hFont );
466
467     if ((style & SS_NOPREFIX) || ((style & SS_TYPEMASK) != SS_SIMPLE))
468     {
469         hBrush = (HBRUSH)SendMessageW( GetParent(hwnd), WM_CTLCOLORSTATIC,
470                                        (WPARAM)hdc, (LPARAM)hwnd );
471         if (!hBrush) /* did the app forget to call defwindowproc ? */
472             hBrush = (HBRUSH)DefWindowProcW(GetParent(hwnd), WM_CTLCOLORSTATIC,
473                                             (WPARAM)hdc, (LPARAM)hwnd);
474         FillRect( hdc, &rc, hBrush );
475     }
476     if (!IsWindowEnabled(hwnd)) SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
477
478     if (!(len = SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 ))) return;
479     if (!(text = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return;
480     SendMessageW( hwnd, WM_GETTEXT, len + 1, (LPARAM)text );
481     DrawTextW( hdc, text, -1, &rc, wFormat );
482     HeapFree( GetProcessHeap(), 0, text );
483 }
484
485 static void STATIC_PaintRectfn( HWND hwnd, HDC hdc, DWORD style )
486 {
487     RECT rc;
488     HBRUSH hBrush;
489
490     GetClientRect( hwnd, &rc);
491
492     switch (style & SS_TYPEMASK)
493     {
494     case SS_BLACKRECT:
495         hBrush = CreateSolidBrush(color_windowframe);
496         FillRect( hdc, &rc, hBrush );
497         break;
498     case SS_GRAYRECT:
499         hBrush = CreateSolidBrush(color_background);
500         FillRect( hdc, &rc, hBrush );
501         break;
502     case SS_WHITERECT:
503         hBrush = CreateSolidBrush(color_window);
504         FillRect( hdc, &rc, hBrush );
505         break;
506     case SS_BLACKFRAME:
507         hBrush = CreateSolidBrush(color_windowframe);
508         FrameRect( hdc, &rc, hBrush );
509         break;
510     case SS_GRAYFRAME:
511         hBrush = CreateSolidBrush(color_background);
512         FrameRect( hdc, &rc, hBrush );
513         break;
514     case SS_WHITEFRAME:
515         hBrush = CreateSolidBrush(color_window);
516         FrameRect( hdc, &rc, hBrush );
517         break;
518     default:
519         return;
520     }
521     DeleteObject( hBrush );
522 }
523
524
525 static void STATIC_PaintIconfn( HWND hwnd, HDC hdc, DWORD style )
526 {
527     RECT rc;
528     HBRUSH hbrush;
529     HICON hIcon;
530
531     GetClientRect( hwnd, &rc );
532     hbrush = (HBRUSH)SendMessageW( GetParent(hwnd), WM_CTLCOLORSTATIC,
533                                    (WPARAM)hdc, (LPARAM)hwnd );
534     FillRect( hdc, &rc, hbrush );
535     if ((hIcon = (HICON)GetWindowLongA( hwnd, HICON_GWL_OFFSET )))
536         DrawIcon( hdc, rc.left, rc.top, hIcon );
537 }
538
539 static void STATIC_PaintBitmapfn(HWND hwnd, HDC hdc, DWORD style )
540 {
541     RECT rc;
542     HBRUSH hbrush;
543     HDC hMemDC;
544     HBITMAP hBitmap, oldbitmap;
545
546     GetClientRect( hwnd, &rc );
547     hbrush = (HBRUSH)SendMessageW( GetParent(hwnd), WM_CTLCOLORSTATIC,
548                                    (WPARAM)hdc, (LPARAM)hwnd );
549     FillRect( hdc, &rc, hbrush );
550
551     if ((hBitmap = (HBITMAP)GetWindowLongA( hwnd, HICON_GWL_OFFSET )))
552     {
553         BITMAP bm;
554         SIZE sz;
555
556         if(GetObjectType(hBitmap) != OBJ_BITMAP) return;
557         if (!(hMemDC = CreateCompatibleDC( hdc ))) return;
558         GetObjectW(hBitmap, sizeof(bm), &bm);
559         GetBitmapDimensionEx(hBitmap, &sz);
560         oldbitmap = SelectObject(hMemDC, hBitmap);
561         BitBlt(hdc, sz.cx, sz.cy, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0,
562                SRCCOPY);
563         SelectObject(hMemDC, oldbitmap);
564         DeleteDC(hMemDC);
565     }
566 }
567
568
569 static void STATIC_PaintEtchedfn( HWND hwnd, HDC hdc, DWORD style )
570 {
571     RECT rc;
572
573     if (TWEAK_WineLook == WIN31_LOOK)
574         return;
575
576     GetClientRect( hwnd, &rc );
577     switch (style & SS_TYPEMASK)
578     {
579         case SS_ETCHEDHORZ:
580             DrawEdge(hdc,&rc,EDGE_ETCHED,BF_TOP|BF_BOTTOM);
581             break;
582         case SS_ETCHEDVERT:
583             DrawEdge(hdc,&rc,EDGE_ETCHED,BF_LEFT|BF_RIGHT);
584             break;
585         case SS_ETCHEDFRAME:
586             DrawEdge (hdc, &rc, EDGE_ETCHED, BF_RECT);
587             break;
588     }
589 }