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