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