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