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