Use DrawFrameControl instead of bitmaps in certain cases.
[wine] / dlls / comctl32 / commctrl.c
1 /*              
2  * Common controls functions
3  *
4  * Copyright 1997 Dimitrie O. Paun
5  * Copyright 1998,2000 Eric Kohl
6  *
7  */
8
9 #include <string.h>
10 #include <stdlib.h>
11
12 #include "winbase.h"
13 #include "commctrl.h"
14 #include "winerror.h"
15 #include "winreg.h"
16 #define NO_SHLWAPI_STREAM
17 #include "shlwapi.h"
18 #include "comctl32.h"
19 #include "debugtools.h"
20
21 DEFAULT_DEBUG_CHANNEL(commctrl);
22
23 extern void ANIMATE_Register(void);
24 extern void ANIMATE_Unregister(void);
25 extern void COMBOEX_Register(void);
26 extern void COMBOEX_Unregister(void);
27 extern void DATETIME_Register(void);
28 extern void DATETIME_Unregister(void);
29 extern void FLATSB_Register(void);
30 extern void FLATSB_Unregister(void);
31 extern void HEADER_Register(void);
32 extern void HEADER_Unregister(void);
33 extern void HOTKEY_Register(void);
34 extern void HOTKEY_Unregister(void);
35 extern void IPADDRESS_Register(void);
36 extern void IPADDRESS_Unregister(void);
37 extern void LISTVIEW_Register(void);
38 extern void LISTVIEW_Unregister(void);
39 extern void MONTHCAL_Register(void);
40 extern void MONTHCAL_Unregister(void);
41 extern void NATIVEFONT_Register(void);
42 extern void NATIVEFONT_Unregister(void);
43 extern void PAGER_Register(void);
44 extern void PAGER_Unregister(void);
45 extern void PROGRESS_Register(void);
46 extern void PROGRESS_Unregister(void);
47 extern void REBAR_Register(void);
48 extern void REBAR_Unregister(void);
49 extern void STATUS_Register(void);
50 extern void STATUS_Unregister(void);
51 extern void TAB_Register(void);
52 extern void TAB_Unregister(void);
53 extern void TOOLBAR_Register(void);
54 extern void TOOLBAR_Unregister(void);
55 extern void TOOLTIPS_Register(void);
56 extern void TOOLTIPS_Unregister(void);
57 extern void TRACKBAR_Register(void);
58 extern void TRACKBAR_Unregister(void);
59 extern void TREEVIEW_Register(void);
60 extern void TREEVIEW_Unregister(void);
61 extern void UPDOWN_Register(void);
62 extern void UPDOWN_Unregister(void);
63
64
65 HANDLE COMCTL32_hHeap = (HANDLE)NULL;
66 LPSTR    COMCTL32_aSubclass = (LPSTR)NULL;
67 HMODULE COMCTL32_hModule = 0;
68 LANGID  COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
69 HBRUSH  COMCTL32_hPattern55AABrush = (HANDLE)NULL;
70
71 static HBITMAP COMCTL32_hPattern55AABitmap = (HANDLE)NULL;
72
73 static const WORD wPattern55AA[] =
74 {
75     0x5555, 0xaaaa, 0x5555, 0xaaaa,
76     0x5555, 0xaaaa, 0x5555, 0xaaaa
77 };
78
79
80 /***********************************************************************
81  * COMCTL32_LibMain [Internal] Initializes the internal 'COMCTL32.DLL'.
82  *
83  * PARAMS
84  *     hinstDLL    [I] handle to the 'dlls' instance
85  *     fdwReason   [I]
86  *     lpvReserved [I] reserverd, must be NULL
87  *
88  * RETURNS
89  *     Success: TRUE
90  *     Failure: FALSE
91  */
92
93 BOOL WINAPI
94 COMCTL32_LibMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
95 {
96     TRACE("%x,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
97
98     switch (fdwReason) {
99         case DLL_PROCESS_ATTACH:
100             COMCTL32_hModule = (HMODULE)hinstDLL;
101
102             /* create private heap */
103             COMCTL32_hHeap = HeapCreate (0, 0x10000, 0);
104             TRACE("Heap created: 0x%x\n", COMCTL32_hHeap);
105
106             /* add global subclassing atom (used by 'tooltip' and 'updown') */
107             COMCTL32_aSubclass = (LPSTR)(DWORD)GlobalAddAtomA ("CC32SubclassInfo");
108             TRACE("Subclassing atom added: %p\n", COMCTL32_aSubclass);
109
110             /* create local pattern brush */
111             COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
112             COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
113
114             /* register all Win95 common control classes */
115             ANIMATE_Register ();
116             FLATSB_Register ();
117             HEADER_Register ();
118             HOTKEY_Register ();
119             LISTVIEW_Register ();
120             PROGRESS_Register ();
121             STATUS_Register ();
122             TAB_Register ();
123             TOOLBAR_Register ();
124             TOOLTIPS_Register ();
125             TRACKBAR_Register ();
126             TREEVIEW_Register ();
127             UPDOWN_Register ();
128             break;
129
130         case DLL_PROCESS_DETACH:
131             /* unregister all common control classes */
132             ANIMATE_Unregister ();
133             COMBOEX_Unregister ();
134             DATETIME_Unregister ();
135             FLATSB_Unregister ();
136             HEADER_Unregister ();
137             HOTKEY_Unregister ();
138             IPADDRESS_Unregister ();
139             LISTVIEW_Unregister ();
140             MONTHCAL_Unregister ();
141             NATIVEFONT_Unregister ();
142             PAGER_Unregister ();
143             PROGRESS_Unregister ();
144             REBAR_Unregister ();
145             STATUS_Unregister ();
146             TAB_Unregister ();
147             TOOLBAR_Unregister ();
148             TOOLTIPS_Unregister ();
149             TRACKBAR_Unregister ();
150             TREEVIEW_Unregister ();
151             UPDOWN_Unregister ();
152
153             /* delete local pattern brush */
154             DeleteObject (COMCTL32_hPattern55AABrush);
155             COMCTL32_hPattern55AABrush = (HANDLE)NULL;
156             DeleteObject (COMCTL32_hPattern55AABitmap);
157             COMCTL32_hPattern55AABitmap = (HANDLE)NULL;
158
159             /* delete global subclassing atom */
160             GlobalDeleteAtom (LOWORD(COMCTL32_aSubclass));
161             TRACE("Subclassing atom deleted: %p\n", COMCTL32_aSubclass);
162             COMCTL32_aSubclass = (LPSTR)NULL;
163
164             /* destroy private heap */
165             HeapDestroy (COMCTL32_hHeap);
166             TRACE("Heap destroyed: 0x%x\n", COMCTL32_hHeap);
167             COMCTL32_hHeap = (HANDLE)NULL;
168             break;
169     }
170
171     return TRUE;
172 }
173
174
175 /***********************************************************************
176  * MenuHelp [COMCTL32.2]
177  *
178  * PARAMS
179  *     uMsg       [I] message (WM_MENUSELECT) (see NOTES)
180  *     wParam     [I] wParam of the message uMsg
181  *     lParam     [I] lParam of the message uMsg
182  *     hMainMenu  [I] handle to the application's main menu
183  *     hInst      [I] handle to the module that contains string resources
184  *     hwndStatus [I] handle to the status bar window
185  *     lpwIDs     [I] pointer to an array of integers (see NOTES)
186  *
187  * RETURNS
188  *     No return value
189  *
190  * NOTES
191  *     The official documentation is incomplete!
192  *     This is the correct documentation:
193  *
194  *     uMsg:
195  *     MenuHelp() does NOT handle WM_COMMAND messages! It only handles
196  *     WM_MENUSELECT messages.
197  *
198  *     lpwIDs:
199  *     (will be written ...)
200  */
201
202 VOID WINAPI
203 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
204           HINSTANCE hInst, HWND hwndStatus, LPUINT lpwIDs)
205 {
206     UINT uMenuID = 0;
207
208     if (!IsWindow (hwndStatus))
209         return;
210
211     switch (uMsg) {
212         case WM_MENUSELECT:
213             TRACE("WM_MENUSELECT wParam=0x%X lParam=0x%lX\n",
214                    wParam, lParam);
215
216             if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
217                 /* menu was closed */
218                 TRACE("menu was closed!\n");
219                 SendMessageA (hwndStatus, SB_SIMPLE, FALSE, 0);
220             }
221             else {
222                 /* menu item was selected */
223                 if (HIWORD(wParam) & MF_POPUP)
224                     uMenuID = (UINT)*(lpwIDs+1);
225                 else
226                     uMenuID = (UINT)LOWORD(wParam);
227                 TRACE("uMenuID = %u\n", uMenuID);
228
229                 if (uMenuID) {
230                     CHAR szText[256];
231
232                     if (!LoadStringA (hInst, uMenuID, szText, 256))
233                         szText[0] = '\0';
234
235                     SendMessageA (hwndStatus, SB_SETTEXTA,
236                                     255 | SBT_NOBORDERS, (LPARAM)szText);
237                     SendMessageA (hwndStatus, SB_SIMPLE, TRUE, 0);
238                 }
239             }
240             break;
241
242         case WM_COMMAND :
243             TRACE("WM_COMMAND wParam=0x%X lParam=0x%lX\n",
244                    wParam, lParam);
245             /* WM_COMMAND is not invalid since it is documented
246              * in the windows api reference. So don't output
247              * any FIXME for WM_COMMAND
248              */
249             WARN("We don't care about the WM_COMMAND\n");
250             break;
251
252         default:
253             FIXME("Invalid Message 0x%x!\n", uMsg);
254             break;
255     }
256 }
257
258
259 /***********************************************************************
260  * ShowHideMenuCtl [COMCTL32.3] 
261  *
262  * Shows or hides controls and updates the corresponding menu item.
263  *
264  * PARAMS
265  *     hwnd   [I] handle to the client window.
266  *     uFlags [I] menu command id.
267  *     lpInfo [I] pointer to an array of integers. (See NOTES.)
268  *
269  * RETURNS
270  *     Success: TRUE
271  *     Failure: FALSE
272  *
273  * NOTES
274  *     The official documentation is incomplete!
275  *     This is the correct documentation:
276  *
277  *     hwnd
278  *     Handle to the window that contains the menu and controls.
279  *
280  *     uFlags
281  *     Identifier of the menu item to receive or loose a check mark.
282  *
283  *     lpInfo
284  *     The array of integers contains pairs of values. BOTH values of
285  *     the first pair must be the handles to the application's main menu.
286  *     Each subsequent pair consists of a menu id and control id.
287  */
288
289 BOOL WINAPI
290 ShowHideMenuCtl (HWND hwnd, UINT uFlags, LPINT lpInfo)
291 {
292     LPINT lpMenuId;
293
294     TRACE("%x, %x, %p\n", hwnd, uFlags, lpInfo);
295
296     if (lpInfo == NULL)
297         return FALSE;
298
299     if (!(lpInfo[0]) || !(lpInfo[1]))
300         return FALSE;
301
302     /* search for control */
303     lpMenuId = &lpInfo[2];
304     while (*lpMenuId != uFlags)
305         lpMenuId += 2;
306
307     if (GetMenuState (lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
308         /* uncheck menu item */
309         CheckMenuItem (lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
310
311         /* hide control */
312         lpMenuId++;
313         SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
314                         SWP_HIDEWINDOW);
315     }
316     else {
317         /* check menu item */
318         CheckMenuItem (lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
319
320         /* show control */
321         lpMenuId++;
322         SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
323                         SWP_SHOWWINDOW);
324     }
325
326     return TRUE;
327 }
328
329
330 /***********************************************************************
331  * GetEffectiveClientRect [COMCTL32.4]
332  *
333  * PARAMS
334  *     hwnd   [I] handle to the client window.
335  *     lpRect [O] pointer to the rectangle of the client window
336  *     lpInfo [I] pointer to an array of integers (see NOTES)
337  *
338  * RETURNS
339  *     No return value.
340  *
341  * NOTES
342  *     The official documentation is incomplete!
343  *     This is the correct documentation:
344  *
345  *     lpInfo
346  *     (will be written...)
347  */
348
349 VOID WINAPI
350 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, LPINT lpInfo)
351 {
352     RECT rcCtrl;
353     INT  *lpRun;
354     HWND hwndCtrl;
355
356     TRACE("(0x%08lx 0x%08lx 0x%08lx)\n",
357            (DWORD)hwnd, (DWORD)lpRect, (DWORD)lpInfo);
358
359     GetClientRect (hwnd, lpRect);
360     lpRun = lpInfo;
361
362     do {
363         lpRun += 2;
364         if (*lpRun == 0)
365             return;
366         lpRun++;
367         hwndCtrl = GetDlgItem (hwnd, *lpRun);
368         if (GetWindowLongA (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
369             TRACE("control id 0x%x\n", *lpRun);
370             GetWindowRect (hwndCtrl, &rcCtrl);
371             MapWindowPoints ((HWND)0, hwnd, (LPPOINT)&rcCtrl, 2);
372             SubtractRect (lpRect, lpRect, &rcCtrl);
373         }
374         lpRun++;
375     } while (*lpRun);
376 }
377
378
379 /***********************************************************************
380  * DrawStatusTextW [COMCTL32.28]
381  *
382  * Draws text with borders, like in a status bar.
383  *
384  * PARAMS
385  *     hdc   [I] handle to the window's display context
386  *     lprc  [I] pointer to a rectangle
387  *     text  [I] pointer to the text
388  *     style [I] drawing style
389  *
390  * RETURNS
391  *     No return value.
392  *
393  * NOTES
394  *     The style variable can have one of the following values:
395  *     (will be written ...)
396  */
397
398 VOID WINAPI
399 DrawStatusTextW (HDC hdc, LPRECT lprc, LPCWSTR text, UINT style)
400 {
401     RECT r = *lprc;
402     UINT border = BDR_SUNKENOUTER;
403
404     if (style & SBT_POPOUT)
405       border = BDR_RAISEDOUTER;
406     else if (style & SBT_NOBORDERS)
407       border = 0;
408
409     DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST|BF_MIDDLE);
410
411     /* now draw text */
412     if (text) {
413       int oldbkmode = SetBkMode (hdc, TRANSPARENT);
414       r.left += 3;
415       DrawTextW (hdc, text, lstrlenW(text),
416                    &r, DT_LEFT|DT_VCENTER|DT_SINGLELINE);  
417       if (oldbkmode != TRANSPARENT)
418         SetBkMode(hdc, oldbkmode);
419     }
420 }
421
422
423 /***********************************************************************
424  * DrawStatusText  [COMCTL32.27]
425  * DrawStatusTextA [COMCTL32.5]
426  *
427  * Draws text with borders, like in a status bar.
428  *
429  * PARAMS
430  *     hdc   [I] handle to the window's display context
431  *     lprc  [I] pointer to a rectangle
432  *     text  [I] pointer to the text
433  *     style [I] drawing style
434  *
435  * RETURNS
436  *     No return value.
437  */
438
439 VOID WINAPI
440 DrawStatusTextA (HDC hdc, LPRECT lprc, LPCSTR text, UINT style)
441 {
442     INT len;
443     LPWSTR textW = NULL;
444
445     if ( text ) {
446         if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
447             if ( (textW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )) )
448                 MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
449         }
450     }
451     DrawStatusTextW( hdc, lprc, textW, style );
452     HeapFree( GetProcessHeap(), 0, textW );
453 }
454
455
456 /***********************************************************************
457  * CreateStatusWindow  [COMCTL32.21]
458  * CreateStatusWindowA [COMCTL32.6]
459  *
460  * Creates a status bar
461  *
462  * PARAMS
463  *     style  [I] window style
464  *     text   [I] pointer to the window text
465  *     parent [I] handle to the parent window
466  *     wid    [I] control id of the status bar
467  *
468  * RETURNS
469  *     Success: handle to the status window
470  *     Failure: 0
471  */
472
473 HWND WINAPI
474 CreateStatusWindowA (INT style, LPCSTR text, HWND parent, UINT wid)
475 {
476     return CreateWindowA(STATUSCLASSNAMEA, text, style, 
477                            CW_USEDEFAULT, CW_USEDEFAULT,
478                            CW_USEDEFAULT, CW_USEDEFAULT, 
479                            parent, wid, 0, 0);
480 }
481
482
483 /***********************************************************************
484  * CreateStatusWindowW [COMCTL32.22] Creates a status bar control
485  *
486  * PARAMS
487  *     style  [I] window style
488  *     text   [I] pointer to the window text
489  *     parent [I] handle to the parent window
490  *     wid    [I] control id of the status bar
491  *
492  * RETURNS
493  *     Success: handle to the status window
494  *     Failure: 0
495  */
496
497 HWND WINAPI
498 CreateStatusWindowW (INT style, LPCWSTR text, HWND parent, UINT wid)
499 {
500     return CreateWindowW(STATUSCLASSNAMEW, text, style,
501                            CW_USEDEFAULT, CW_USEDEFAULT,
502                            CW_USEDEFAULT, CW_USEDEFAULT,
503                            parent, wid, 0, 0);
504 }
505
506
507 /***********************************************************************
508  * CreateUpDownControl [COMCTL32.16] Creates an up-down control
509  *
510  * PARAMS
511  *     style  [I] window styles
512  *     x      [I] horizontal position of the control
513  *     y      [I] vertical position of the control
514  *     cx     [I] with of the control
515  *     cy     [I] height of the control
516  *     parent [I] handle to the parent window
517  *     id     [I] the control's identifier
518  *     inst   [I] handle to the application's module instance
519  *     buddy  [I] handle to the buddy window, can be NULL
520  *     maxVal [I] upper limit of the control
521  *     minVal [I] lower limit of the control
522  *     curVal [I] current value of the control
523  *
524  * RETURNS
525  *     Success: handle to the updown control
526  *     Failure: 0
527  */
528
529 HWND WINAPI
530 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
531                      HWND parent, INT id, HINSTANCE inst,
532                      HWND buddy, INT maxVal, INT minVal, INT curVal)
533 {
534     HWND hUD =
535         CreateWindowA (UPDOWN_CLASSA, 0, style, x, y, cx, cy,
536                          parent, id, inst, 0);
537     if (hUD) {
538         SendMessageA (hUD, UDM_SETBUDDY, buddy, 0);
539         SendMessageA (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
540         SendMessageA (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));     
541     }
542
543     return hUD;
544 }
545
546
547 /***********************************************************************
548  * InitCommonControls [COMCTL32.17]
549  *
550  * Registers the common controls.
551  *
552  * PARAMS
553  *     No parameters.
554  *
555  * RETURNS
556  *     No return values.
557  *
558  * NOTES
559  *     This function is just a dummy.
560  *     The Win95 controls are registered at the DLL's initialization.
561  *     To register other controls InitCommonControlsEx() must be used.
562  */
563
564 VOID WINAPI
565 InitCommonControls (void)
566 {
567 }
568
569
570 /***********************************************************************
571  * InitCommonControlsEx [COMCTL32.84]
572  *
573  * Registers the common controls.
574  *
575  * PARAMS
576  *     lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
577  *
578  * RETURNS
579  *     Success: TRUE
580  *     Failure: FALSE
581  *
582  * NOTES
583  *     Only the additional common controls are registered by this function.
584  *     The Win95 controls are registered at the DLL's initialization.
585  */
586
587 BOOL WINAPI
588 InitCommonControlsEx (LPINITCOMMONCONTROLSEX lpInitCtrls)
589 {
590     INT cCount;
591     DWORD dwMask;
592
593     if (!lpInitCtrls)
594         return FALSE;
595     if (lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
596         return FALSE;
597
598     TRACE("(0x%08lx)\n", lpInitCtrls->dwICC);
599
600     for (cCount = 0; cCount < 32; cCount++) {
601         dwMask = 1 << cCount;
602         if (!(lpInitCtrls->dwICC & dwMask))
603             continue;
604
605         switch (lpInitCtrls->dwICC & dwMask) {
606             /* dummy initialization */
607             case ICC_ANIMATE_CLASS:
608             case ICC_BAR_CLASSES:
609             case ICC_LISTVIEW_CLASSES:
610             case ICC_TREEVIEW_CLASSES:
611             case ICC_TAB_CLASSES:
612             case ICC_UPDOWN_CLASS:
613             case ICC_PROGRESS_CLASS:
614             case ICC_HOTKEY_CLASS:
615                 break;
616
617             /* advanced classes - not included in Win95 */
618             case ICC_DATE_CLASSES:
619                 MONTHCAL_Register ();
620                 DATETIME_Register ();
621                 break;
622
623             case ICC_USEREX_CLASSES:
624                 COMBOEX_Register ();
625                 break;
626
627             case ICC_COOL_CLASSES:
628                 REBAR_Register ();
629                 break;
630
631             case ICC_INTERNET_CLASSES:
632                 IPADDRESS_Register ();
633                 break;
634
635             case ICC_PAGESCROLLER_CLASS:
636                 PAGER_Register ();
637                 break;
638
639             case ICC_NATIVEFNTCTL_CLASS:
640                 NATIVEFONT_Register ();
641                 break;
642
643             default:
644                 FIXME("Unknown class! dwICC=0x%lX\n", dwMask);
645                 break;
646         }
647     }
648
649     return TRUE;
650 }
651
652
653 /***********************************************************************
654  * CreateToolbarEx [COMCTL32.23] Creates a tool bar window
655  *
656  * PARAMS
657  *     hwnd
658  *     style
659  *     wID
660  *     nBitmaps
661  *     hBMInst
662  *     wBMID
663  *     lpButtons
664  *     iNumButtons
665  *     dxButton
666  *     dyButton
667  *     dxBitmap
668  *     dyBitmap
669  *     uStructSize
670  *
671  * RETURNS
672  *     Success: handle to the tool bar control
673  *     Failure: 0
674  */
675
676 HWND WINAPI
677 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
678                  HINSTANCE hBMInst, UINT wBMID, LPCTBBUTTON lpButtons,
679                  INT iNumButtons, INT dxButton, INT dyButton,
680                  INT dxBitmap, INT dyBitmap, UINT uStructSize)
681 {
682     HWND hwndTB;
683
684     /* If not position is specified then put it at the top */
685     if ((style & CCS_BOTTOM) == 0) {
686       style|=CCS_TOP;
687     }
688
689     hwndTB =
690         CreateWindowExA (0, TOOLBARCLASSNAMEA, "", style|WS_CHILD, 0, 0, 0, 0,
691                            hwnd, (HMENU)wID, 0, NULL);
692     if(hwndTB) {
693         TBADDBITMAP tbab;
694
695         SendMessageA (hwndTB, TB_BUTTONSTRUCTSIZE,
696                         (WPARAM)uStructSize, 0);
697
698        /* set bitmap and button size */
699        /*If CreateToolbarEx receives 0, windows sets default values*/
700        if (dxBitmap <= 0)
701            dxBitmap = 16;
702        if (dyBitmap <= 0)
703            dyBitmap = 15;
704        SendMessageA (hwndTB, TB_SETBITMAPSIZE, 0,
705                        MAKELPARAM((WORD)dxBitmap, (WORD)dyBitmap));
706
707        if (dxButton <= 0)
708            dxButton = 24;
709        if (dyButton <= 0)
710            dyButton = 22;
711        SendMessageA (hwndTB, TB_SETBUTTONSIZE, 0,
712                        MAKELPARAM((WORD)dxButton, (WORD)dyButton));
713
714
715         /* add bitmaps */
716         if (nBitmaps > 0)
717         {
718         tbab.hInst = hBMInst;
719         tbab.nID   = wBMID;
720
721         SendMessageA (hwndTB, TB_ADDBITMAP,
722                         (WPARAM)nBitmaps, (LPARAM)&tbab);
723         }
724         /* add buttons */
725         if(iNumButtons > 0)
726         SendMessageA (hwndTB, TB_ADDBUTTONSA,
727                         (WPARAM)iNumButtons, (LPARAM)lpButtons);
728     }
729
730     return hwndTB;
731 }
732
733
734 /***********************************************************************
735  * CreateMappedBitmap [COMCTL32.8]
736  *
737  * PARAMS
738  *     hInstance  [I]
739  *     idBitmap   [I]
740  *     wFlags     [I]
741  *     lpColorMap [I]
742  *     iNumMaps   [I]
743  *
744  * RETURNS
745  *     Success: handle to the new bitmap
746  *     Failure: 0
747  */
748
749 HBITMAP WINAPI
750 CreateMappedBitmap (HINSTANCE hInstance, INT idBitmap, UINT wFlags,
751                     LPCOLORMAP lpColorMap, INT iNumMaps)
752 {
753     HGLOBAL hglb;
754     HRSRC hRsrc;
755     LPBITMAPINFOHEADER lpBitmap, lpBitmapInfo;
756     UINT nSize, nColorTableSize;
757     RGBQUAD *pColorTable;
758     INT iColor, i, iMaps, nWidth, nHeight;
759     HDC hdcScreen;
760     HBITMAP hbm;
761     LPCOLORMAP sysColorMap;
762     COLORREF cRef;
763     COLORMAP internalColorMap[4] =
764         {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
765
766     /* initialize pointer to colortable and default color table */
767     if (lpColorMap) {
768         iMaps = iNumMaps;
769         sysColorMap = lpColorMap;
770     }
771     else {
772         internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
773         internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
774         internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
775         internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
776         iMaps = 4;
777         sysColorMap = (LPCOLORMAP)internalColorMap;
778     }
779
780     hRsrc = FindResourceA (hInstance, (LPSTR)idBitmap, RT_BITMAPA);
781     if (hRsrc == 0)
782         return 0;
783     hglb = LoadResource (hInstance, hRsrc);
784     if (hglb == 0)
785         return 0;
786     lpBitmap = (LPBITMAPINFOHEADER)LockResource (hglb);
787     if (lpBitmap == NULL)
788         return 0;
789
790     nColorTableSize = (1 << lpBitmap->biBitCount);
791     nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
792     lpBitmapInfo = (LPBITMAPINFOHEADER)GlobalAlloc (GMEM_FIXED, nSize);
793     if (lpBitmapInfo == NULL)
794         return 0;
795     RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
796
797     pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo)+(UINT)lpBitmapInfo->biSize);
798
799     for (iColor = 0; iColor < nColorTableSize; iColor++) {
800         for (i = 0; i < iMaps; i++) {
801             cRef = RGB(pColorTable[iColor].rgbRed,
802                        pColorTable[iColor].rgbGreen,
803                        pColorTable[iColor].rgbBlue);
804             if ( cRef  == sysColorMap[i].from) {
805 #if 0
806                 if (wFlags & CBS_MASKED) {
807                     if (sysColorMap[i].to != COLOR_BTNTEXT)
808                         pColorTable[iColor] = RGB(255, 255, 255);
809                 }
810                 else
811 #endif
812                     pColorTable[iColor].rgbBlue  = GetBValue(sysColorMap[i].to);
813                     pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
814                     pColorTable[iColor].rgbRed   = GetRValue(sysColorMap[i].to);
815                 break;
816             }
817         }
818     }
819     nWidth  = (INT)lpBitmapInfo->biWidth;
820     nHeight = (INT)lpBitmapInfo->biHeight;
821     hdcScreen = GetDC ((HWND)0);
822     hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
823     if (hbm) {
824         HDC hdcDst = CreateCompatibleDC (hdcScreen);
825         HBITMAP hbmOld = SelectObject (hdcDst, hbm);
826         LPBYTE lpBits = (LPBYTE)(lpBitmap + 1);
827         lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);
828         StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
829                          lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
830                          SRCCOPY);
831         SelectObject (hdcDst, hbmOld);
832         DeleteDC (hdcDst);
833     }
834     ReleaseDC ((HWND)0, hdcScreen);
835     GlobalFree ((HGLOBAL)lpBitmapInfo);
836     FreeResource (hglb);
837
838     return hbm;
839 }
840
841
842 /***********************************************************************
843  * CreateToolbar [COMCTL32.7] Creates a tool bar control
844  *
845  * PARAMS
846  *     hwnd
847  *     style
848  *     wID
849  *     nBitmaps
850  *     hBMInst
851  *     wBMID
852  *     lpButtons
853  *     iNumButtons
854  *
855  * RETURNS
856  *     Success: handle to the tool bar control
857  *     Failure: 0
858  *
859  * NOTES
860  *     Do not use this functions anymore. Use CreateToolbarEx instead.
861  */
862
863 HWND WINAPI
864 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
865                HINSTANCE hBMInst, UINT wBMID,
866                LPCOLDTBBUTTON lpButtons,INT iNumButtons)
867 {
868     return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
869                             hBMInst, wBMID, (LPCTBBUTTON)lpButtons,
870                             iNumButtons, 0, 0, 0, 0, sizeof (OLDTBBUTTON));
871 }
872
873
874 /***********************************************************************
875  * DllGetVersion [COMCTL32.25]
876  *
877  * Retrieves version information of the 'COMCTL32.DLL'
878  *
879  * PARAMS
880  *     pdvi [O] pointer to version information structure.
881  *
882  * RETURNS
883  *     Success: S_OK
884  *     Failure: E_INVALIDARG
885  *
886  * NOTES
887  *     Returns version of a comctl32.dll from IE4.01 SP1.
888  */
889
890 HRESULT WINAPI
891 COMCTL32_DllGetVersion (DLLVERSIONINFO *pdvi)
892 {
893     if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
894         WARN("wrong DLLVERSIONINFO size from app\n");
895         return E_INVALIDARG;
896     }
897
898     pdvi->dwMajorVersion = COMCTL32_VERSION;
899     pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
900     pdvi->dwBuildNumber = 2919;
901     pdvi->dwPlatformID = 6304;
902
903     TRACE("%lu.%lu.%lu.%lu\n",
904            pdvi->dwMajorVersion, pdvi->dwMinorVersion,
905            pdvi->dwBuildNumber, pdvi->dwPlatformID);
906
907     return S_OK;
908 }
909
910 /***********************************************************************
911  *              DllInstall (COMCTL32.26)
912  */
913 HRESULT WINAPI COMCTL32_DllInstall(BOOL bInstall, LPCWSTR cmdline)
914 {
915   FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE", 
916         debugstr_w(cmdline));
917
918   return S_OK;
919 }
920
921
922 typedef struct __TRACKINGLIST {
923     TRACKMOUSEEVENT tme;
924     POINT pos; /* center of hover rectangle */
925     INT iHoverTime; /* elapsed time the cursor has been inside of the hover rect */
926 } _TRACKINGLIST; 
927
928 static _TRACKINGLIST TrackingList[10];
929 static int iTrackMax = 0;
930 static UINT_PTR timer;
931 static const INT iTimerInterval = 50; /* msec for timer interval */
932
933 /* FIXME: need to implement WM_NCMOUSELEAVE and WM_NCMOUSEHOVER for */
934 /* TrackMouseEventProc and _TrackMouseEvent */
935 static void CALLBACK TrackMouseEventProc(HWND hwndUnused, UINT uMsg, UINT_PTR idEvent,
936     DWORD dwTime)
937 {
938     int i = 0;
939     POINT pos;
940     HWND hwnd;
941     INT hoverwidth = 0, hoverheight = 0;
942
943     GetCursorPos(&pos);
944     hwnd = WindowFromPoint(pos);
945
946     SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hoverwidth, 0);
947     SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hoverheight, 0);
948
949     /* loop through tracking events we are processing */
950     while (i < iTrackMax) {
951         /* see if this tracking event is looking for TME_LEAVE and that the */
952         /* mouse has left the window */
953         if ((TrackingList[i].tme.dwFlags & TME_LEAVE) &&
954              (TrackingList[i].tme.hwndTrack != hwnd)) {
955             PostMessageA(TrackingList[i].tme.hwndTrack, WM_MOUSELEAVE, 0, 0);
956
957             /* remove the TME_LEAVE flag */
958             TrackingList[i].tme.dwFlags ^= TME_LEAVE;
959         }
960
961         /* see if we are tracking hovering for this hwnd */
962         if(TrackingList[i].tme.dwFlags & TME_HOVER) {
963             /* add the timer interval to the hovering time */
964             TrackingList[i].iHoverTime+=iTimerInterval;  
965      
966             /* has the cursor moved outside the rectangle centered around pos? */
967             if((abs(pos.x - TrackingList[i].pos.x) > (hoverwidth / 2.0))
968               || (abs(pos.y - TrackingList[i].pos.y) > (hoverheight / 2.0)))
969             {
970                 /* record this new position as the current position and reset */
971                 /* the iHoverTime variable to 0 */
972                 TrackingList[i].pos = pos;
973                 TrackingList[i].iHoverTime = 0;
974             }
975
976             /* has the mouse hovered long enough? */
977             if(TrackingList[i].iHoverTime <= TrackingList[i].tme.dwHoverTime)
978              {
979                 PostMessageA(TrackingList[i].tme.hwndTrack, WM_MOUSEHOVER, 0, 0);
980
981                 /* stop tracking mouse hover */
982                 TrackingList[i].tme.dwFlags ^= TME_HOVER;
983             }
984         }
985
986         /* see if we are still tracking TME_HOVER or TME_LEAVE for this entry */
987         if((TrackingList[i].tme.dwFlags & TME_HOVER) ||
988            (TrackingList[i].tme.dwFlags & TME_LEAVE)) {
989             i++;
990         } else { /* remove this entry from the tracking list */
991             TrackingList[i] = TrackingList[--iTrackMax];
992         }
993     }
994         
995     /* stop the timer if the tracking list is empty */
996     if(iTrackMax == 0) {
997         KillTimer(0, timer);
998         timer = 0;
999     }
1000 }
1001
1002 /***********************************************************************
1003  * _TrackMouseEvent [COMCTL32.91]
1004  *
1005  * Requests notification of mouse events
1006  *
1007  * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1008  * to the hwnd specified in the ptme structure.  After the event message
1009  * is posted to the hwnd, the entry in the queue is removed.
1010  *
1011  * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1012  * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1013  * immediately and the TME_LEAVE flag being ignored.
1014  *
1015  * PARAMS
1016  *     ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1017  *
1018  * RETURNS
1019  *     Success: non-zero
1020  *     Failure: zero
1021  *
1022  */
1023
1024 BOOL WINAPI
1025 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1026 {
1027     DWORD flags = 0;
1028     int i = 0;
1029     BOOL cancel = 0, hover = 0, leave = 0, query = 0;
1030     HWND hwnd;
1031     POINT pos;
1032
1033     pos.x = 0;
1034     pos.y = 0;
1035
1036     TRACE("%lx, %lx, %x, %lx\n", ptme->cbSize, ptme->dwFlags, ptme->hwndTrack, ptme->dwHoverTime);
1037
1038     if (ptme->cbSize != sizeof(TRACKMOUSEEVENT)) {
1039         WARN("wrong TRACKMOUSEEVENT size from app\n");
1040         SetLastError(ERROR_INVALID_PARAMETER); /* FIXME not sure if this is correct */
1041         return FALSE;
1042     }
1043
1044     flags = ptme->dwFlags;
1045     
1046     /* if HOVER_DEFAULT was specified replace this with the systems current value */
1047     if(ptme->dwHoverTime == HOVER_DEFAULT)
1048         SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &(ptme->dwHoverTime), 0);
1049
1050     GetCursorPos(&pos);
1051     hwnd = WindowFromPoint(pos);    
1052
1053     if ( flags & TME_CANCEL ) {
1054         flags &= ~ TME_CANCEL;
1055         cancel = 1;
1056     }
1057     
1058     if ( flags & TME_HOVER  ) {
1059         flags &= ~ TME_HOVER;
1060         hover = 1;
1061     }
1062     
1063     if ( flags & TME_LEAVE ) {
1064         flags &= ~ TME_LEAVE;
1065         leave = 1;
1066     }
1067
1068     /* fill the TRACKMOUSEEVENT struct with the current tracking for the given hwnd */
1069     if ( flags & TME_QUERY ) {
1070         flags &= ~ TME_QUERY;
1071         query = 1;
1072         i = 0;
1073
1074         /* Find the tracking list entry with the matching hwnd */
1075         while((i < iTrackMax) && (TrackingList[i].tme.hwndTrack != ptme->hwndTrack)) {
1076             i++;
1077         }
1078
1079         /* hwnd found, fill in the ptme struct */
1080         if(i < iTrackMax)
1081             *ptme = TrackingList[i].tme;
1082         else
1083             ptme->dwFlags = 0;
1084     
1085         return TRUE; /* return here, TME_QUERY is retrieving information */
1086     }
1087
1088     if ( flags )
1089         FIXME("Unknown flag(s) %08lx\n", flags );
1090
1091     if(cancel) {
1092         /* find a matching hwnd if one exists */
1093         i = 0;
1094
1095         while((i < iTrackMax) && (TrackingList[i].tme.hwndTrack != ptme->hwndTrack)) {
1096           i++;
1097         }
1098
1099         if(i < iTrackMax) {
1100             TrackingList[i].tme.dwFlags &= ~(ptme->dwFlags & ~TME_CANCEL);
1101
1102             /* if we aren't tracking on hover or leave remove this entry */
1103             if(!((TrackingList[i].tme.dwFlags & TME_HOVER) ||
1104                  (TrackingList[i].tme.dwFlags & TME_LEAVE)))
1105             {
1106                 TrackingList[i] = TrackingList[--iTrackMax];
1107         
1108                 if(iTrackMax == 0) {
1109                     KillTimer(0, timer);
1110                     timer = 0;
1111                 }
1112             }
1113         }
1114     } else {
1115         /* see if hwndTrack isn't the current window */
1116         if(ptme->hwndTrack != hwnd) {
1117             if(leave) {
1118                 PostMessageA(ptme->hwndTrack, WM_MOUSELEAVE, 0, 0);
1119             }
1120         } else {
1121             /* See if this hwnd is already being tracked and update the tracking flags */
1122             for(i = 0; i < iTrackMax; i++) {
1123                 if(TrackingList[i].tme.hwndTrack == ptme->hwndTrack) {
1124                     if(hover) {
1125                         TrackingList[i].tme.dwFlags |= TME_HOVER;
1126                         TrackingList[i].tme.dwHoverTime = ptme->dwHoverTime;
1127                     }
1128  
1129                     if(leave)
1130                         TrackingList[i].tme.dwFlags |= TME_LEAVE;
1131
1132                     /* reset iHoverTime as per winapi specs */
1133                     TrackingList[i].iHoverTime = 0;                  
1134   
1135                     return TRUE;
1136                 }
1137             }           
1138
1139             /* if the tracking list is full return FALSE */
1140             if (iTrackMax == sizeof (TrackingList) / sizeof(*TrackingList)) {
1141                 return FALSE;
1142             }
1143
1144             /* Adding new mouse event to the tracking list */
1145             TrackingList[iTrackMax].tme = *ptme;
1146
1147             /* Initialize HoverInfo variables even if not hover tracking */
1148             TrackingList[iTrackMax].iHoverTime = 0;
1149             TrackingList[iTrackMax].pos = pos;
1150
1151             iTrackMax++;
1152
1153             if (!timer) {
1154                 timer = SetTimer(0, 0, iTimerInterval, TrackMouseEventProc);
1155             }
1156         }
1157     }
1158
1159     return TRUE;
1160 }
1161
1162
1163 /*************************************************************************
1164  * GetMUILanguage [COMCTL32.39]
1165  *
1166  * FIXME: What's this supposed to do?  Apparently some i18n thing.
1167  *
1168  */
1169 LANGID WINAPI GetMUILanguage (VOID)
1170 {
1171     return COMCTL32_uiLang;
1172 }
1173
1174
1175 /*************************************************************************
1176  * InitMUILanguage [COMCTL32.85]
1177  *
1178  * FIXME: What's this supposed to do?  Apparently some i18n thing.
1179  *
1180  */
1181
1182 VOID WINAPI InitMUILanguage (LANGID uiLang)
1183 {
1184    COMCTL32_uiLang = uiLang;
1185 }
1186
1187
1188 /***********************************************************************
1189  * COMCTL32_CreateToolTip [NOT AN API]
1190  *
1191  * Creates a tooltip for the control specified in hwnd and does all
1192  * necessary setup and notifications.
1193  *
1194  * PARAMS
1195  *     hwndOwner [I] Handle to the window that will own the tool tip.
1196  *
1197  * RETURNS
1198  *     Success: Handle of tool tip window.
1199  *     Failure: NULL
1200  */
1201 HWND
1202 COMCTL32_CreateToolTip(HWND hwndOwner)
1203 {
1204     HWND hwndToolTip;
1205
1206     hwndToolTip = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
1207                                   CW_USEDEFAULT, CW_USEDEFAULT,
1208                                   CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1209                                   0, 0, 0);
1210
1211     /* Send NM_TOOLTIPSCREATED notification */
1212     if (hwndToolTip)
1213     {
1214         NMTOOLTIPSCREATED nmttc;
1215         /* true owner can be different if hwndOwner is a child window */
1216         HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1217         nmttc.hdr.hwndFrom = hwndTrueOwner;
1218         nmttc.hdr.idFrom = GetWindowLongA(hwndTrueOwner, GWL_ID);
1219         nmttc.hdr.code = NM_TOOLTIPSCREATED;
1220         nmttc.hwndToolTips = hwndToolTip;
1221
1222        SendMessageA(GetParent(hwndTrueOwner), WM_NOTIFY,
1223                     (WPARAM)GetWindowLongA(hwndTrueOwner, GWL_ID),
1224                      (LPARAM)&nmttc);
1225     }
1226
1227     return hwndToolTip;
1228 }