2 * Common controls functions
4 * Copyright 1997 Dimitrie O. Paun
5 * Copyright 1998,2000 Eric Kohl
14 #include "debugtools.h"
18 DEFAULT_DEBUG_CHANNEL(commctrl);
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);
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 HBRUSH COMCTL32_hPattern55AABrush = (HANDLE)NULL;
69 static HBITMAP COMCTL32_hPattern55AABitmap = (HANDLE)NULL;
71 static const WORD wPattern55AA[] =
73 0x5555, 0xaaaa, 0x5555, 0xaaaa,
74 0x5555, 0xaaaa, 0x5555, 0xaaaa
78 /***********************************************************************
79 * COMCTL32_LibMain [Internal] Initializes the internal 'COMCTL32.DLL'.
82 * hinstDLL [I] handle to the 'dlls' instance
84 * lpvReserved [I] reserverd, must be NULL
92 COMCTL32_LibMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
94 TRACE("%x,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
97 case DLL_PROCESS_ATTACH:
98 if (COMCTL32_dwProcessesAttached == 0) {
100 /* This will be wrong for any other process attching in this address-space! */
101 COMCTL32_hModule = (HMODULE)hinstDLL;
103 /* create private heap */
104 COMCTL32_hHeap = HeapCreate (0, 0x10000, 0);
105 TRACE("Heap created: 0x%x\n", COMCTL32_hHeap);
107 /* add global subclassing atom (used by 'tooltip' and 'updown') */
108 COMCTL32_aSubclass = (LPSTR)(DWORD)GlobalAddAtomA ("CC32SubclassInfo");
109 TRACE("Subclassing atom added: %p\n",
112 /* create local pattern brush */
113 COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
114 COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
116 /* register all Win95 common control classes */
121 LISTVIEW_Register ();
122 PROGRESS_Register ();
126 TOOLTIPS_Register ();
127 TRACKBAR_Register ();
128 TREEVIEW_Register ();
131 COMCTL32_dwProcessesAttached++;
134 case DLL_PROCESS_DETACH:
135 COMCTL32_dwProcessesAttached--;
136 if (COMCTL32_dwProcessesAttached == 0) {
137 /* unregister all common control classes */
138 ANIMATE_Unregister ();
139 COMBOEX_Unregister ();
140 DATETIME_Unregister ();
141 FLATSB_Unregister ();
142 HEADER_Unregister ();
143 HOTKEY_Unregister ();
144 IPADDRESS_Unregister ();
145 LISTVIEW_Unregister ();
146 MONTHCAL_Unregister ();
147 NATIVEFONT_Unregister ();
149 PROGRESS_Unregister ();
151 STATUS_Unregister ();
153 TOOLBAR_Unregister ();
154 TOOLTIPS_Unregister ();
155 TRACKBAR_Unregister ();
156 TREEVIEW_Unregister ();
157 UPDOWN_Unregister ();
159 /* delete local pattern brush */
160 DeleteObject (COMCTL32_hPattern55AABrush);
161 COMCTL32_hPattern55AABrush = (HANDLE)NULL;
162 DeleteObject (COMCTL32_hPattern55AABitmap);
163 COMCTL32_hPattern55AABitmap = (HANDLE)NULL;
165 /* delete global subclassing atom */
166 GlobalDeleteAtom (LOWORD(COMCTL32_aSubclass));
167 TRACE("Subclassing atom deleted: %p\n",
169 COMCTL32_aSubclass = (LPSTR)NULL;
171 /* destroy private heap */
172 HeapDestroy (COMCTL32_hHeap);
173 TRACE("Heap destroyed: 0x%x\n", COMCTL32_hHeap);
174 COMCTL32_hHeap = (HANDLE)NULL;
183 /***********************************************************************
184 * MenuHelp [COMCTL32.2]
187 * uMsg [I] message (WM_MENUSELECT) (see NOTES)
188 * wParam [I] wParam of the message uMsg
189 * lParam [I] lParam of the message uMsg
190 * hMainMenu [I] handle to the application's main menu
191 * hInst [I] handle to the module that contains string resources
192 * hwndStatus [I] handle to the status bar window
193 * lpwIDs [I] pointer to an array of integers (see NOTES)
199 * The official documentation is incomplete!
200 * This is the correct documentation:
203 * MenuHelp() does NOT handle WM_COMMAND messages! It only handles
204 * WM_MENUSELECT messages.
207 * (will be written ...)
211 MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
212 HINSTANCE hInst, HWND hwndStatus, LPUINT lpwIDs)
216 if (!IsWindow (hwndStatus))
221 TRACE("WM_MENUSELECT wParam=0x%X lParam=0x%lX\n",
224 if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
225 /* menu was closed */
226 TRACE("menu was closed!\n");
227 SendMessageA (hwndStatus, SB_SIMPLE, FALSE, 0);
230 /* menu item was selected */
231 if (HIWORD(wParam) & MF_POPUP)
232 uMenuID = (UINT)*(lpwIDs+1);
234 uMenuID = (UINT)LOWORD(wParam);
235 TRACE("uMenuID = %u\n", uMenuID);
240 if (!LoadStringA (hInst, uMenuID, szText, 256))
243 SendMessageA (hwndStatus, SB_SETTEXTA,
244 255 | SBT_NOBORDERS, (LPARAM)szText);
245 SendMessageA (hwndStatus, SB_SIMPLE, TRUE, 0);
251 TRACE("WM_COMMAND wParam=0x%X lParam=0x%lX\n",
253 /* WM_COMMAND is not invalid since it is documented
254 * in the windows api reference. So don't output
255 * any FIXME for WM_COMMAND
257 WARN("We don't care about the WM_COMMAND\n");
261 FIXME("Invalid Message 0x%x!\n", uMsg);
267 /***********************************************************************
268 * ShowHideMenuCtl [COMCTL32.3]
270 * Shows or hides controls and updates the corresponding menu item.
273 * hwnd [I] handle to the client window.
274 * uFlags [I] menu command id.
275 * lpInfo [I] pointer to an array of integers. (See NOTES.)
282 * The official documentation is incomplete!
283 * This is the correct documentation:
286 * Handle to the window that contains the menu and controls.
289 * Identifier of the menu item to receive or loose a check mark.
292 * The array of integers contains pairs of values. BOTH values of
293 * the first pair must be the handles to the application's main menu.
294 * Each subsequent pair consists of a menu id and control id.
298 ShowHideMenuCtl (HWND hwnd, UINT uFlags, LPINT lpInfo)
302 TRACE("%x, %x, %p\n", hwnd, uFlags, lpInfo);
307 if (!(lpInfo[0]) || !(lpInfo[1]))
310 /* search for control */
311 lpMenuId = &lpInfo[2];
312 while (*lpMenuId != uFlags)
315 if (GetMenuState (lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
316 /* uncheck menu item */
317 CheckMenuItem (lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
321 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
325 /* check menu item */
326 CheckMenuItem (lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
330 SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
338 /***********************************************************************
339 * GetEffectiveClientRect [COMCTL32.4]
342 * hwnd [I] handle to the client window.
343 * lpRect [O] pointer to the rectangle of the client window
344 * lpInfo [I] pointer to an array of integers (see NOTES)
350 * The official documentation is incomplete!
351 * This is the correct documentation:
354 * (will be written...)
358 GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, LPINT lpInfo)
364 TRACE("(0x%08lx 0x%08lx 0x%08lx)\n",
365 (DWORD)hwnd, (DWORD)lpRect, (DWORD)lpInfo);
367 GetClientRect (hwnd, lpRect);
375 hwndCtrl = GetDlgItem (hwnd, *lpRun);
376 if (GetWindowLongA (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
377 TRACE("control id 0x%x\n", *lpRun);
378 GetWindowRect (hwndCtrl, &rcCtrl);
379 MapWindowPoints ((HWND)0, hwnd, (LPPOINT)&rcCtrl, 2);
380 SubtractRect (lpRect, lpRect, &rcCtrl);
387 /***********************************************************************
388 * DrawStatusTextA [COMCTL32.5][COMCTL32.27]
390 * Draws text with borders, like in a status bar.
393 * hdc [I] handle to the window's display context
394 * lprc [I] pointer to a rectangle
395 * text [I] pointer to the text
396 * style [I] drawing style
402 * The style variable can have one of the following values:
403 * (will be written ...)
407 DrawStatusTextA (HDC hdc, LPRECT lprc, LPCSTR text, UINT style)
410 UINT border = BDR_SUNKENOUTER;
412 if (style & SBT_POPOUT)
413 border = BDR_RAISEDOUTER;
414 else if (style & SBT_NOBORDERS)
417 DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST|BF_MIDDLE);
421 int oldbkmode = SetBkMode (hdc, TRANSPARENT);
423 DrawTextA (hdc, text, lstrlenA(text),
424 &r, DT_LEFT|DT_VCENTER|DT_SINGLELINE);
425 if (oldbkmode != TRANSPARENT)
426 SetBkMode(hdc, oldbkmode);
431 /***********************************************************************
432 * DrawStatusTextW [COMCTL32.28]
434 * Draws text with borders, like in a status bar.
437 * hdc [I] handle to the window's display context
438 * lprc [I] pointer to a rectangle
439 * text [I] pointer to the text
440 * style [I] drawing style
447 DrawStatusTextW (HDC hdc, LPRECT lprc, LPCWSTR text, UINT style)
449 LPSTR p = HEAP_strdupWtoA (GetProcessHeap (), 0, text);
450 DrawStatusTextA (hdc, lprc, p, style);
451 HeapFree (GetProcessHeap (), 0, p );
455 /***********************************************************************
456 * CreateStatusWindowA [COMCTL32.6][COMCTL32.21]
458 * Creates a status bar
461 * style [I] window style
462 * text [I] pointer to the window text
463 * parent [I] handle to the parent window
464 * wid [I] control id of the status bar
467 * Success: handle to the status window
472 CreateStatusWindowA (INT style, LPCSTR text, HWND parent, UINT wid)
474 return CreateWindowA(STATUSCLASSNAMEA, text, style,
475 CW_USEDEFAULT, CW_USEDEFAULT,
476 CW_USEDEFAULT, CW_USEDEFAULT,
481 /***********************************************************************
482 * CreateStatusWindowW [COMCTL32.22] Creates a status bar control
485 * style [I] window style
486 * text [I] pointer to the window text
487 * parent [I] handle to the parent window
488 * wid [I] control id of the status bar
491 * Success: handle to the status window
496 CreateStatusWindowW (INT style, LPCWSTR text, HWND parent, UINT wid)
498 return CreateWindowW(STATUSCLASSNAMEW, text, style,
499 CW_USEDEFAULT, CW_USEDEFAULT,
500 CW_USEDEFAULT, CW_USEDEFAULT,
505 /***********************************************************************
506 * CreateUpDownControl [COMCTL32.16] Creates an up-down control
509 * style [I] window styles
510 * x [I] horizontal position of the control
511 * y [I] vertical position of the control
512 * cx [I] with of the control
513 * cy [I] height of the control
514 * parent [I] handle to the parent window
515 * id [I] the control's identifier
516 * inst [I] handle to the application's module instance
517 * buddy [I] handle to the buddy window, can be NULL
518 * maxVal [I] upper limit of the control
519 * minVal [I] lower limit of the control
520 * curVal [I] current value of the control
523 * Success: handle to the updown control
528 CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
529 HWND parent, INT id, HINSTANCE inst,
530 HWND buddy, INT maxVal, INT minVal, INT curVal)
533 CreateWindowA (UPDOWN_CLASSA, 0, style, x, y, cx, cy,
534 parent, id, inst, 0);
536 SendMessageA (hUD, UDM_SETBUDDY, buddy, 0);
537 SendMessageA (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
538 SendMessageA (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
545 /***********************************************************************
546 * InitCommonControls [COMCTL32.17]
548 * Registers the common controls.
557 * This function is just a dummy.
558 * The Win95 controls are registered at the DLL's initialization.
559 * To register other controls InitCommonControlsEx() must be used.
563 InitCommonControls (void)
568 /***********************************************************************
569 * InitCommonControlsEx [COMCTL32.81]
571 * Registers the common controls.
574 * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
581 * Only the additional common controls are registered by this function.
582 * The Win95 controls are registered at the DLL's initialization.
586 InitCommonControlsEx (LPINITCOMMONCONTROLSEX lpInitCtrls)
593 if (lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
596 TRACE("(0x%08lx)\n", lpInitCtrls->dwICC);
598 for (cCount = 0; cCount < 32; cCount++) {
599 dwMask = 1 << cCount;
600 if (!(lpInitCtrls->dwICC & dwMask))
603 switch (lpInitCtrls->dwICC & dwMask) {
604 /* dummy initialization */
605 case ICC_ANIMATE_CLASS:
606 case ICC_BAR_CLASSES:
607 case ICC_LISTVIEW_CLASSES:
608 case ICC_TREEVIEW_CLASSES:
609 case ICC_TAB_CLASSES:
610 case ICC_UPDOWN_CLASS:
611 case ICC_PROGRESS_CLASS:
612 case ICC_HOTKEY_CLASS:
615 /* advanced classes - not included in Win95 */
616 case ICC_DATE_CLASSES:
617 MONTHCAL_Register ();
618 DATETIME_Register ();
621 case ICC_USEREX_CLASSES:
625 case ICC_COOL_CLASSES:
629 case ICC_INTERNET_CLASSES:
630 IPADDRESS_Register ();
633 case ICC_PAGESCROLLER_CLASS:
637 case ICC_NATIVEFNTCTL_CLASS:
638 NATIVEFONT_Register ();
642 FIXME("Unknown class! dwICC=0x%lX\n", dwMask);
651 /***********************************************************************
652 * CreateToolbarEx [COMCTL32.32] Creates a tool bar window
670 * Success: handle to the tool bar control
675 CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
676 HINSTANCE hBMInst, UINT wBMID, LPCTBBUTTON lpButtons,
677 INT iNumButtons, INT dxButton, INT dyButton,
678 INT dxBitmap, INT dyBitmap, UINT uStructSize)
682 /* If not position is specified then put it at the top */
683 if ((style & CCS_BOTTOM) == 0) {
688 CreateWindowExA (0, TOOLBARCLASSNAMEA, "", style|WS_CHILD, 0, 0, 0, 0,
689 hwnd, (HMENU)wID, 0, NULL);
693 SendMessageA (hwndTB, TB_BUTTONSTRUCTSIZE,
694 (WPARAM)uStructSize, 0);
696 /* set bitmap and button size */
697 /*If CreateToolbarEx receives 0, windows sets default values*/
702 SendMessageA (hwndTB, TB_SETBITMAPSIZE, 0,
703 MAKELPARAM((WORD)dxBitmap, (WORD)dyBitmap));
709 SendMessageA (hwndTB, TB_SETBUTTONSIZE, 0,
710 MAKELPARAM((WORD)dxButton, (WORD)dyButton));
716 tbab.hInst = hBMInst;
719 SendMessageA (hwndTB, TB_ADDBITMAP,
720 (WPARAM)nBitmaps, (LPARAM)&tbab);
724 SendMessageA (hwndTB, TB_ADDBUTTONSA,
725 (WPARAM)iNumButtons, (LPARAM)lpButtons);
732 /***********************************************************************
733 * CreateMappedBitmap [COMCTL32.8]
743 * Success: handle to the new bitmap
748 CreateMappedBitmap (HINSTANCE hInstance, INT idBitmap, UINT wFlags,
749 LPCOLORMAP lpColorMap, INT iNumMaps)
753 LPBITMAPINFOHEADER lpBitmap, lpBitmapInfo;
754 UINT nSize, nColorTableSize;
755 RGBQUAD *pColorTable;
756 INT iColor, i, iMaps, nWidth, nHeight;
759 LPCOLORMAP sysColorMap;
761 COLORMAP internalColorMap[4] =
762 {{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
764 /* initialize pointer to colortable and default color table */
767 sysColorMap = lpColorMap;
770 internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
771 internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
772 internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
773 internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
775 sysColorMap = (LPCOLORMAP)internalColorMap;
778 hRsrc = FindResourceA (hInstance, (LPSTR)idBitmap, RT_BITMAPA);
781 hglb = LoadResource (hInstance, hRsrc);
784 lpBitmap = (LPBITMAPINFOHEADER)LockResource (hglb);
785 if (lpBitmap == NULL)
788 nColorTableSize = (1 << lpBitmap->biBitCount);
789 nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
790 lpBitmapInfo = (LPBITMAPINFOHEADER)GlobalAlloc (GMEM_FIXED, nSize);
791 if (lpBitmapInfo == NULL)
793 RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
795 pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo)+(UINT)lpBitmapInfo->biSize);
797 for (iColor = 0; iColor < nColorTableSize; iColor++) {
798 for (i = 0; i < iMaps; i++) {
799 cRef = RGB(pColorTable[iColor].rgbRed,
800 pColorTable[iColor].rgbGreen,
801 pColorTable[iColor].rgbBlue);
802 if ( cRef == sysColorMap[i].from) {
804 if (wFlags & CBS_MASKED) {
805 if (sysColorMap[i].to != COLOR_BTNTEXT)
806 pColorTable[iColor] = RGB(255, 255, 255);
810 pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
811 pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
812 pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
817 nWidth = (INT)lpBitmapInfo->biWidth;
818 nHeight = (INT)lpBitmapInfo->biHeight;
819 hdcScreen = GetDC ((HWND)0);
820 hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
822 HDC hdcDst = CreateCompatibleDC (hdcScreen);
823 HBITMAP hbmOld = SelectObject (hdcDst, hbm);
824 LPBYTE lpBits = (LPBYTE)(lpBitmap + 1);
825 lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);
826 StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
827 lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
829 SelectObject (hdcDst, hbmOld);
832 ReleaseDC ((HWND)0, hdcScreen);
833 GlobalFree ((HGLOBAL)lpBitmapInfo);
840 /***********************************************************************
841 * CreateToolbar [COMCTL32.7] Creates a tool bar control
854 * Success: handle to the tool bar control
858 * Do not use this functions anymore. Use CreateToolbarEx instead.
862 CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
863 HINSTANCE hBMInst, UINT wBMID,
864 LPCOLDTBBUTTON lpButtons,INT iNumButtons)
866 return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
867 hBMInst, wBMID, (LPCTBBUTTON)lpButtons,
868 iNumButtons, 0, 0, 0, 0, sizeof (OLDTBBUTTON));
872 /***********************************************************************
873 * DllGetVersion [COMCTL32.25]
875 * Retrieves version information of the 'COMCTL32.DLL'
878 * pdvi [O] pointer to version information structure.
882 * Failure: E_INVALIDARG
885 * Returns version of a comctl32.dll from IE4.01 SP1.
889 COMCTL32_DllGetVersion (DLLVERSIONINFO *pdvi)
891 if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
892 WARN("wrong DLLVERSIONINFO size from app");
896 pdvi->dwMajorVersion = 5;
897 pdvi->dwMinorVersion = 0;
898 pdvi->dwBuildNumber = 2919;
899 pdvi->dwPlatformID = 6304;
901 TRACE("%lu.%lu.%lu.%lu\n",
902 pdvi->dwMajorVersion, pdvi->dwMinorVersion,
903 pdvi->dwBuildNumber, pdvi->dwPlatformID);
908 /***********************************************************************
909 * DllInstall (COMCTL32.@)
911 HRESULT WINAPI COMCTL32_DllInstall(BOOL bInstall, LPCWSTR cmdline)
913 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
914 debugstr_w(cmdline));
920 typedef struct __TRACKINGLIST {
922 POINT pos; /* center of hover rectangle */
923 INT iHoverTime; /* elapsed time the cursor has been inside of the hover rect */
926 static _TRACKINGLIST TrackingList[10];
927 static int iTrackMax = 0;
928 static UINT_PTR timer;
929 static const INT iTimerInterval = 50; /* msec for timer interval */
931 /* FIXME: need to implement WM_NCMOUSELEAVE and WM_NCMOUSEHOVER for */
932 /* TrackMouseEventProc and _TrackMouseEvent */
933 static void CALLBACK TrackMouseEventProc(HWND hwndUnused, UINT uMsg, UINT_PTR idEvent,
939 INT hoverwidth = 0, hoverheight = 0;
942 hwnd = WindowFromPoint(pos);
944 SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hoverwidth, 0);
945 SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hoverheight, 0);
947 /* loop through tracking events we are processing */
948 while (i < iTrackMax) {
949 /* see if this tracking event is looking for TME_LEAVE and that the */
950 /* mouse has left the window */
951 if ((TrackingList[i].tme.dwFlags & TME_LEAVE) &&
952 (TrackingList[i].tme.hwndTrack != hwnd)) {
953 PostMessageA(TrackingList[i].tme.hwndTrack, WM_MOUSELEAVE, 0, 0);
955 /* remove the TME_LEAVE flag */
956 TrackingList[i].tme.dwFlags ^= TME_LEAVE;
959 /* see if we are tracking hovering for this hwnd */
960 if(TrackingList[i].tme.dwFlags & TME_HOVER) {
961 /* add the timer interval to the hovering time */
962 TrackingList[i].iHoverTime+=iTimerInterval;
964 /* has the cursor moved outside the rectangle centered around pos? */
965 if((abs(pos.x - TrackingList[i].pos.x) > (hoverwidth / 2.0))
966 || (abs(pos.y - TrackingList[i].pos.y) > (hoverheight / 2.0)))
968 /* record this new position as the current position and reset */
969 /* the iHoverTime variable to 0 */
970 TrackingList[i].pos = pos;
971 TrackingList[i].iHoverTime = 0;
974 /* has the mouse hovered long enough? */
975 if(TrackingList[i].iHoverTime <= TrackingList[i].tme.dwHoverTime)
977 PostMessageA(TrackingList[i].tme.hwndTrack, WM_MOUSEHOVER, 0, 0);
979 /* stop tracking mouse hover */
980 TrackingList[i].tme.dwFlags ^= TME_HOVER;
984 /* see if we are still tracking TME_HOVER or TME_LEAVE for this entry */
985 if((TrackingList[i].tme.dwFlags & TME_HOVER) ||
986 (TrackingList[i].tme.dwFlags & TME_LEAVE)) {
988 } else { /* remove this entry from the tracking list */
989 TrackingList[i] = TrackingList[--iTrackMax];
993 /* stop the timer if the tracking list is empty */
1000 /***********************************************************************
1001 * _TrackMouseEvent [COMCTL32.25]
1003 * Requests notification of mouse events
1005 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1006 * to the hwnd specified in the ptme structure. After the event message
1007 * is posted to the hwnd, the entry in the queue is removed.
1009 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1010 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1011 * immediately and the TME_LEAVE flag being ignored.
1014 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1023 _TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1027 BOOL cancel = 0, hover = 0, leave = 0, query = 0;
1034 TRACE("%lx, %lx, %x, %lx\n", ptme->cbSize, ptme->dwFlags, ptme->hwndTrack, ptme->dwHoverTime);
1036 if (ptme->cbSize != sizeof(TRACKMOUSEEVENT)) {
1037 WARN("wrong TRACKMOUSEEVENT size from app");
1038 SetLastError(ERROR_INVALID_PARAMETER); /* FIXME not sure if this is correct */
1042 flags = ptme->dwFlags;
1044 /* if HOVER_DEFAULT was specified replace this with the systems current value */
1045 if(ptme->dwHoverTime == HOVER_DEFAULT)
1046 SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &(ptme->dwHoverTime), 0);
1049 hwnd = WindowFromPoint(pos);
1051 if ( flags & TME_CANCEL ) {
1052 flags &= ~ TME_CANCEL;
1056 if ( flags & TME_HOVER ) {
1057 flags &= ~ TME_HOVER;
1061 if ( flags & TME_LEAVE ) {
1062 flags &= ~ TME_LEAVE;
1066 /* fill the TRACKMOUSEEVENT struct with the current tracking for the given hwnd */
1067 if ( flags & TME_QUERY ) {
1068 flags &= ~ TME_QUERY;
1072 /* Find the tracking list entry with the matching hwnd */
1073 while((i < iTrackMax) && (TrackingList[i].tme.hwndTrack != ptme->hwndTrack)) {
1077 /* hwnd found, fill in the ptme struct */
1079 *ptme = TrackingList[i].tme;
1083 return TRUE; /* return here, TME_QUERY is retrieving information */
1087 FIXME("Unknown flag(s) %08lx\n", flags );
1090 /* find a matching hwnd if one exists */
1093 while((i < iTrackMax) && (TrackingList[i].tme.hwndTrack != ptme->hwndTrack)) {
1098 TrackingList[i].tme.dwFlags &= ~(ptme->dwFlags & ~TME_CANCEL);
1100 /* if we aren't tracking on hover or leave remove this entry */
1101 if(!((TrackingList[i].tme.dwFlags & TME_HOVER) ||
1102 (TrackingList[i].tme.dwFlags & TME_LEAVE)))
1104 TrackingList[i] = TrackingList[--iTrackMax];
1106 if(iTrackMax == 0) {
1107 KillTimer(0, timer);
1113 /* see if hwndTrack isn't the current window */
1114 if(ptme->hwndTrack != hwnd) {
1116 PostMessageA(ptme->hwndTrack, WM_MOUSELEAVE, 0, 0);
1119 /* See if this hwnd is already being tracked and update the tracking flags */
1120 for(i = 0; i < iTrackMax; i++) {
1121 if(TrackingList[i].tme.hwndTrack == ptme->hwndTrack) {
1123 TrackingList[i].tme.dwFlags |= TME_HOVER;
1124 TrackingList[i].tme.dwHoverTime = ptme->dwHoverTime;
1128 TrackingList[i].tme.dwFlags |= TME_LEAVE;
1130 /* reset iHoverTime as per winapi specs */
1131 TrackingList[i].iHoverTime = 0;
1137 /* if the tracking list is full return FALSE */
1138 if (iTrackMax == sizeof (TrackingList) / sizeof(*TrackingList)) {
1142 /* Adding new mouse event to the tracking list */
1143 TrackingList[iTrackMax].tme = *ptme;
1145 /* Initialize HoverInfo variables even if not hover tracking */
1146 TrackingList[iTrackMax].iHoverTime = 0;
1147 TrackingList[iTrackMax].pos = pos;
1152 timer = SetTimer(0, 0, iTimerInterval, TrackMouseEventProc);
1161 /*************************************************************************
1162 * GetMUILanguage [COMCTL32.39]
1164 * FIXME: What's this supposed to do? Apparently some i18n thing.
1167 LANGID WINAPI GetMUILanguage (VOID)
1169 return COMCTL32_uiLang;
1173 /*************************************************************************
1174 * InitMUILanguage [COMCTL32.85]
1176 * FIXME: What's this supposed to do? Apparently some i18n thing.
1180 VOID WINAPI InitMUILanguage (LANGID uiLang)
1182 COMCTL32_uiLang = uiLang;
1186 /***********************************************************************
1187 * COMCTL32_CreateToolTip [NOT AN API]
1189 * Creates a tooltip for the control specified in hwnd and does all
1190 * necessary setup and notifications.
1193 * hwndOwner [I] Handle to the window that will own the tool tip.
1196 * Success: Handle of tool tip window.
1200 COMCTL32_CreateToolTip(HWND hwndOwner)
1204 hwndToolTip = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
1205 CW_USEDEFAULT, CW_USEDEFAULT,
1206 CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
1209 /* Send NM_TOOLTIPSCREATED notification */
1212 NMTOOLTIPSCREATED nmttc;
1213 /* true owner can be different if hwndOwner is a child window */
1214 HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
1215 nmttc.hdr.hwndFrom = hwndTrueOwner;
1216 nmttc.hdr.idFrom = GetWindowLongA(hwndTrueOwner, GWL_ID);
1217 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1218 nmttc.hwndToolTips = hwndToolTip;
1220 SendMessageA(GetParent(hwndTrueOwner), WM_NOTIFY,
1221 (WPARAM)GetWindowLongA(hwndTrueOwner, GWL_ID),