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