2 * Interface code to StatusWindow widget/control
4 * Copyright 1996 Bruce Milner
5 * Copyright 1998, 1999 Eric Kohl
6 * Copyright 2002 Dimitrie O. Paun
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 * This code was audited for completeness against the documented features
25 * of Comctl32.dll version 6.0 on Sep. 24, 2002, by Dimitrie O. Paun.
27 * Unless otherwise noted, we believe this code to be complete, as per
28 * the specification mentioned above.
29 * If you discover missing features, or bugs, please note them below.
32 * -- CCS_BOTTOM (default)
37 * -- CCS_NOPARENTALIGN
40 * -- CCS_VERT (defaults to RIGHT)
48 #include "wine/unicode.h"
56 #include "wine/debug.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(statusbar);
79 COLORREF clrBk; /* background color */
80 BOOL bUnicode; /* notify format. TRUE if notifies in Unicode */
81 STATUSWINDOWPART part0; /* simple window */
82 STATUSWINDOWPART* parts;
89 * Run tests using Waite Group Windows95 API Bible Vol. 1&2
90 * The second cdrom contains executables drawstat.exe, gettext.exe,
91 * simple.exe, getparts.exe, setparts.exe, statwnd.exe
98 static const WCHAR themeClass[] = { 'S','t','a','t','u','s',0 };
102 STATUSBAR_SetPartBounds (STATUS_INFO *infoPtr);
104 STATUSBAR_NotifyFormat (STATUS_INFO *infoPtr, HWND from, INT cmd);
106 static inline LPCSTR debugstr_t(LPCWSTR text, BOOL isW)
108 return isW ? debugstr_w(text) : debugstr_a((LPCSTR)text);
112 STATUSBAR_ComputeHeight(STATUS_INFO *infoPtr)
118 COMCTL32_GetFontMetrics(infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont, &tm);
119 height = tm.tmHeight + 4 + infoPtr->verticalBorder;
121 if ((theme = GetWindowTheme(infoPtr->Self)))
123 /* Determine bar height from theme such that the content area is
124 * textHeight pixels large */
125 HDC hdc = GetDC(infoPtr->Self);
127 memset (&r, 0, sizeof (r));
128 r.bottom = tm.tmHeight;
129 if (SUCCEEDED(GetThemeBackgroundExtent(theme, hdc, SP_PANE, 0, &r, &r)))
131 height = r.bottom - r.top;
133 ReleaseDC(infoPtr->Self, hdc);
136 TRACE(" textHeight=%d+%d, final height=%d\n", tm.tmHeight, tm.tmInternalLeading, height);
141 STATUSBAR_DrawSizeGrip (HTHEME theme, HDC hdc, LPRECT lpRect)
143 HPEN hPenFace, hPenShadow, hPenHighlight, hOldPen;
147 TRACE("draw size grip %s\n", wine_dbgstr_rect(lpRect));
153 gripperRect = *lpRect;
154 if (SUCCEEDED (GetThemePartSize (theme, hdc, SP_GRIPPER, 0, lpRect,
155 TS_DRAW, &gripperSize)))
157 gripperRect.left = gripperRect.right - gripperSize.cx;
158 gripperRect.top = gripperRect.bottom - gripperSize.cy;
159 if (SUCCEEDED (DrawThemeBackground(theme, hdc, SP_GRIPPER, 0, &gripperRect, NULL)))
164 pt.x = lpRect->right - 1;
165 pt.y = lpRect->bottom - 1;
167 hPenFace = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_3DFACE ));
168 hOldPen = SelectObject( hdc, hPenFace );
169 MoveToEx (hdc, pt.x - 12, pt.y, NULL);
170 LineTo (hdc, pt.x, pt.y);
171 LineTo (hdc, pt.x, pt.y - 13);
176 hPenShadow = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_3DSHADOW ));
177 SelectObject( hdc, hPenShadow );
178 for (i = 1; i < 11; i += 4) {
179 MoveToEx (hdc, pt.x - i, pt.y, NULL);
180 LineTo (hdc, pt.x + 1, pt.y - i - 1);
182 MoveToEx (hdc, pt.x - i - 1, pt.y, NULL);
183 LineTo (hdc, pt.x + 1, pt.y - i - 2);
186 hPenHighlight = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_3DHIGHLIGHT ));
187 SelectObject( hdc, hPenHighlight );
188 for (i = 3; i < 13; i += 4) {
189 MoveToEx (hdc, pt.x - i, pt.y, NULL);
190 LineTo (hdc, pt.x + 1, pt.y - i - 1);
193 SelectObject (hdc, hOldPen);
194 DeleteObject( hPenFace );
195 DeleteObject( hPenShadow );
196 DeleteObject( hPenHighlight );
201 STATUSBAR_DrawPart (const STATUS_INFO *infoPtr, HDC hdc, const STATUSWINDOWPART *part, int itemID)
203 RECT r = part->bound;
204 UINT border = BDR_SUNKENOUTER;
205 HTHEME theme = GetWindowTheme (infoPtr->Self);
206 int themePart = SP_PANE;
208 TRACE("part bound %s\n", wine_dbgstr_rect(&r));
209 if (part->style & SBT_POPOUT)
210 border = BDR_RAISEDOUTER;
211 else if (part->style & SBT_NOBORDERS)
216 if ((GetWindowLongW (infoPtr->Self, GWL_STYLE) & SBARS_SIZEGRIP)
217 && (infoPtr->simple || (itemID == (infoPtr->numParts-1))))
218 themePart = SP_GRIPPERPANE;
219 DrawThemeBackground(theme, hdc, themePart, 0, &r, NULL);
222 DrawEdge(hdc, &r, border, BF_RECT|BF_ADJUST);
224 if (part->style & SBT_OWNERDRAW) {
227 dis.CtlID = GetWindowLongPtrW (infoPtr->Self, GWLP_ID);
229 dis.hwndItem = infoPtr->Self;
232 dis.itemData = (ULONG_PTR)part->text;
233 SendMessageW (infoPtr->Notify, WM_DRAWITEM, (WPARAM)dis.CtlID, (LPARAM)&dis);
236 INT cy = r.bottom - r.top;
239 DrawIconEx (hdc, r.left, r.top, part->hIcon, cy, cy, 0, 0, DI_NORMAL);
242 DrawStatusTextW (hdc, &r, part->text, SBT_NOBORDERS);
248 STATUSBAR_RefreshPart (const STATUS_INFO *infoPtr, HDC hdc, const STATUSWINDOWPART *part, int itemID)
254 TRACE("item %d\n", itemID);
255 if (!IsWindowVisible (infoPtr->Self))
258 if (part->bound.right < part->bound.left) return;
260 if ((theme = GetWindowTheme (infoPtr->Self)))
263 GetClientRect (infoPtr->Self, &cr);
264 DrawThemeBackground(theme, hdc, 0, 0, &cr, &part->bound);
268 if (infoPtr->clrBk != CLR_DEFAULT)
269 hbrBk = CreateSolidBrush (infoPtr->clrBk);
271 hbrBk = GetSysColorBrush (COLOR_3DFACE);
272 FillRect(hdc, &part->bound, hbrBk);
273 if (infoPtr->clrBk != CLR_DEFAULT)
274 DeleteObject (hbrBk);
277 hOldFont = SelectObject (hdc, infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont);
279 STATUSBAR_DrawPart (infoPtr, hdc, part, itemID);
281 SelectObject (hdc, hOldFont);
283 if (GetWindowLongW (infoPtr->Self, GWL_STYLE) & SBARS_SIZEGRIP) {
286 GetClientRect (infoPtr->Self, &rect);
287 STATUSBAR_DrawSizeGrip (theme, hdc, &rect);
293 STATUSBAR_Refresh (STATUS_INFO *infoPtr, HDC hdc)
302 if (!IsWindowVisible(infoPtr->Self))
305 STATUSBAR_SetPartBounds(infoPtr);
307 GetClientRect (infoPtr->Self, &rect);
309 if ((theme = GetWindowTheme (infoPtr->Self)))
311 DrawThemeBackground(theme, hdc, 0, 0, &rect, NULL);
315 if (infoPtr->clrBk != CLR_DEFAULT)
316 hbrBk = CreateSolidBrush (infoPtr->clrBk);
318 hbrBk = GetSysColorBrush (COLOR_3DFACE);
319 FillRect(hdc, &rect, hbrBk);
320 if (infoPtr->clrBk != CLR_DEFAULT)
321 DeleteObject (hbrBk);
324 hOldFont = SelectObject (hdc, infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont);
326 if (infoPtr->simple) {
327 STATUSBAR_RefreshPart (infoPtr, hdc, &infoPtr->part0, 0);
329 for (i = 0; i < infoPtr->numParts; i++) {
330 STATUSBAR_RefreshPart (infoPtr, hdc, &infoPtr->parts[i], i);
334 SelectObject (hdc, hOldFont);
336 if (GetWindowLongW (infoPtr->Self, GWL_STYLE) & SBARS_SIZEGRIP)
337 STATUSBAR_DrawSizeGrip (theme, hdc, &rect);
344 STATUSBAR_InternalHitTest(const STATUS_INFO *infoPtr, const LPPOINT pt)
350 for (i = 0; i < infoPtr->numParts; i++)
351 if (pt->x >= infoPtr->parts[i].bound.left && pt->x <= infoPtr->parts[i].bound.right)
358 STATUSBAR_SetPartBounds (STATUS_INFO *infoPtr)
360 STATUSWINDOWPART *part;
364 /* get our window size */
365 GetClientRect (infoPtr->Self, &rect);
366 TRACE("client wnd size is %s\n", wine_dbgstr_rect(&rect));
368 rect.left += infoPtr->horizontalBorder;
369 rect.top += infoPtr->verticalBorder;
371 /* set bounds for simple rectangle */
372 infoPtr->part0.bound = rect;
374 /* set bounds for non-simple rectangles */
375 for (i = 0; i < infoPtr->numParts; i++) {
376 part = &infoPtr->parts[i];
377 r = &infoPtr->parts[i].bound;
379 r->bottom = rect.bottom;
383 r->left = infoPtr->parts[i-1].bound.right + infoPtr->horizontalGap;
385 r->right = rect.right;
389 if (infoPtr->hwndToolTip) {
392 ti.cbSize = sizeof(TTTOOLINFOW);
393 ti.hwnd = infoPtr->Self;
396 SendMessageW (infoPtr->hwndToolTip, TTM_NEWTOOLRECTW,
404 STATUSBAR_Relay2Tip (const STATUS_INFO *infoPtr, UINT uMsg,
405 WPARAM wParam, LPARAM lParam)
409 msg.hwnd = infoPtr->Self;
413 msg.time = GetMessageTime ();
414 msg.pt.x = (short)LOWORD(GetMessagePos ());
415 msg.pt.y = (short)HIWORD(GetMessagePos ());
417 return SendMessageW (infoPtr->hwndToolTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
422 STATUSBAR_GetBorders (const STATUS_INFO *infoPtr, INT out[])
425 out[0] = infoPtr->horizontalBorder;
426 out[1] = infoPtr->verticalBorder;
427 out[2] = infoPtr->horizontalGap;
434 STATUSBAR_SetBorders (STATUS_INFO *infoPtr, const INT in[])
437 infoPtr->horizontalBorder = in[0];
438 infoPtr->verticalBorder = in[1];
439 infoPtr->horizontalGap = in[2];
440 InvalidateRect(infoPtr->Self, NULL, FALSE);
447 STATUSBAR_GetIcon (const STATUS_INFO *infoPtr, INT nPart)
449 TRACE("%d\n", nPart);
450 /* MSDN says: "simple parts are indexed with -1" */
451 if ((nPart < -1) || (nPart >= infoPtr->numParts))
455 return (infoPtr->part0.hIcon);
457 return (infoPtr->parts[nPart].hIcon);
462 STATUSBAR_GetParts (const STATUS_INFO *infoPtr, INT num_parts, INT parts[])
466 TRACE("(%d)\n", num_parts);
468 for (i = 0; i < num_parts; i++) {
469 parts[i] = infoPtr->parts[i].x;
472 return infoPtr->numParts;
477 STATUSBAR_GetRect (const STATUS_INFO *infoPtr, INT nPart, LPRECT rect)
479 TRACE("part %d\n", nPart);
480 if(nPart >= infoPtr->numParts || nPart < 0)
483 *rect = infoPtr->part0.bound;
485 *rect = infoPtr->parts[nPart].bound;
491 STATUSBAR_GetTextA (STATUS_INFO *infoPtr, INT nPart, LPSTR buf)
493 STATUSWINDOWPART *part;
496 TRACE("part %d\n", nPart);
498 /* MSDN says: "simple parts use index of 0", so this check is ok. */
499 if (nPart < 0 || nPart >= infoPtr->numParts) return 0;
502 part = &infoPtr->part0;
504 part = &infoPtr->parts[nPart];
506 if (part->style & SBT_OWNERDRAW)
507 result = (LRESULT)part->text;
509 DWORD len = part->text ? WideCharToMultiByte( CP_ACP, 0, part->text, -1,
510 NULL, 0, NULL, NULL ) - 1 : 0;
511 result = MAKELONG( len, part->style );
512 if (part->text && buf)
513 WideCharToMultiByte( CP_ACP, 0, part->text, -1, buf, len+1, NULL, NULL );
520 STATUSBAR_GetTextW (STATUS_INFO *infoPtr, INT nPart, LPWSTR buf)
522 STATUSWINDOWPART *part;
525 TRACE("part %d\n", nPart);
526 if (nPart < 0 || nPart >= infoPtr->numParts) return 0;
529 part = &infoPtr->part0;
531 part = &infoPtr->parts[nPart];
533 if (part->style & SBT_OWNERDRAW)
534 result = (LRESULT)part->text;
536 result = part->text ? strlenW (part->text) : 0;
537 result |= (part->style << 16);
538 if (part->text && buf)
539 strcpyW (buf, part->text);
546 STATUSBAR_GetTextLength (STATUS_INFO *infoPtr, INT nPart)
548 STATUSWINDOWPART *part;
551 TRACE("part %d\n", nPart);
553 /* MSDN says: "simple parts use index of 0", so this check is ok. */
554 if (nPart < 0 || nPart >= infoPtr->numParts) return 0;
557 part = &infoPtr->part0;
559 part = &infoPtr->parts[nPart];
561 if ((~part->style & SBT_OWNERDRAW) && part->text)
562 result = strlenW(part->text);
566 result |= (part->style << 16);
571 STATUSBAR_GetTipTextA (const STATUS_INFO *infoPtr, INT id, LPSTR tip, INT size)
575 CHAR buf[INFOTIPSIZE];
578 if (infoPtr->hwndToolTip) {
580 ti.cbSize = sizeof(TTTOOLINFOA);
581 ti.hwnd = infoPtr->Self;
584 SendMessageA (infoPtr->hwndToolTip, TTM_GETTEXTA, 0, (LPARAM)&ti);
586 lstrcpynA (tip, buf, size);
593 STATUSBAR_GetTipTextW (const STATUS_INFO *infoPtr, INT id, LPWSTR tip, INT size)
597 WCHAR buf[INFOTIPSIZE];
600 if (infoPtr->hwndToolTip) {
602 ti.cbSize = sizeof(TTTOOLINFOW);
603 ti.hwnd = infoPtr->Self;
606 SendMessageW(infoPtr->hwndToolTip, TTM_GETTEXTW, 0, (LPARAM)&ti);
608 lstrcpynW(tip, buf, size);
616 STATUSBAR_SetBkColor (STATUS_INFO *infoPtr, COLORREF color)
620 oldBkColor = infoPtr->clrBk;
621 infoPtr->clrBk = color;
622 InvalidateRect(infoPtr->Self, NULL, FALSE);
624 TRACE("CREF: %08x -> %08x\n", oldBkColor, infoPtr->clrBk);
630 STATUSBAR_SetIcon (STATUS_INFO *infoPtr, INT nPart, HICON hIcon)
632 if ((nPart < -1) || (nPart >= infoPtr->numParts))
635 TRACE("setting part %d\n", nPart);
637 /* FIXME: MSDN says "if nPart is -1, the status bar is assumed simple" */
639 if (infoPtr->part0.hIcon == hIcon) /* same as - no redraw */
641 infoPtr->part0.hIcon = hIcon;
643 InvalidateRect(infoPtr->Self, &infoPtr->part0.bound, FALSE);
645 if (infoPtr->parts[nPart].hIcon == hIcon) /* same as - no redraw */
648 infoPtr->parts[nPart].hIcon = hIcon;
649 if (!(infoPtr->simple))
650 InvalidateRect(infoPtr->Self, &infoPtr->parts[nPart].bound, FALSE);
657 STATUSBAR_SetMinHeight (STATUS_INFO *infoPtr, INT height)
660 TRACE("(height=%d)\n", height);
661 if (IsWindowVisible (infoPtr->Self)) {
666 infoPtr->height = height + infoPtr->verticalBorder;
668 if ((theme = GetWindowTheme (infoPtr->Self)))
670 /* Determine bar height from theme such that the content area is
671 * 'height' pixels large */
672 HDC hdc = GetDC (infoPtr->Self);
674 memset (&r, 0, sizeof (r));
676 if (SUCCEEDED(GetThemeBackgroundExtent (theme, hdc, SP_PANE, 0, &r, &r)))
678 infoPtr->height = r.bottom - r.top;
680 ReleaseDC (infoPtr->Self, hdc);
683 if (GetClientRect (infoPtr->Notify, &parent_rect))
685 width = parent_rect.right - parent_rect.left;
686 x = parent_rect.left;
687 y = parent_rect.bottom - infoPtr->height;
688 MoveWindow (infoPtr->Self, x, y, width, infoPtr->height, TRUE);
689 STATUSBAR_SetPartBounds (infoPtr);
698 STATUSBAR_SetParts (STATUS_INFO *infoPtr, INT count, LPINT parts)
700 STATUSWINDOWPART *tmp;
703 TRACE("(%d,%p)\n", count, parts);
705 oldNumParts = infoPtr->numParts;
706 infoPtr->numParts = count;
707 if (oldNumParts > infoPtr->numParts) {
708 for (i = infoPtr->numParts ; i < oldNumParts; i++) {
709 if (!(infoPtr->parts[i].style & SBT_OWNERDRAW))
710 Free (infoPtr->parts[i].text);
712 } else if (oldNumParts < infoPtr->numParts) {
713 tmp = Alloc (sizeof(STATUSWINDOWPART) * infoPtr->numParts);
714 if (!tmp) return FALSE;
715 for (i = 0; i < oldNumParts; i++) {
716 tmp[i] = infoPtr->parts[i];
718 Free (infoPtr->parts);
719 infoPtr->parts = tmp;
721 if (oldNumParts == infoPtr->numParts) {
722 for (i=0; i < oldNumParts; i++)
723 if (infoPtr->parts[i].x != parts[i])
725 if (i==oldNumParts) /* Unchanged? no need to redraw! */
729 for (i = 0; i < infoPtr->numParts; i++)
730 infoPtr->parts[i].x = parts[i];
732 if (infoPtr->hwndToolTip) {
736 ZeroMemory (&ti, sizeof(TTTOOLINFOW));
737 ti.cbSize = sizeof(TTTOOLINFOW);
738 ti.hwnd = infoPtr->Self;
740 nTipCount = SendMessageW (infoPtr->hwndToolTip, TTM_GETTOOLCOUNT, 0, 0);
741 if (nTipCount < infoPtr->numParts) {
743 for (i = nTipCount; i < infoPtr->numParts; i++) {
744 TRACE("add tool %d\n", i);
746 SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW,
750 else if (nTipCount > infoPtr->numParts) {
752 for (i = nTipCount - 1; i >= infoPtr->numParts; i--) {
753 TRACE("delete tool %d\n", i);
755 SendMessageW (infoPtr->hwndToolTip, TTM_DELTOOLW,
760 STATUSBAR_SetPartBounds (infoPtr);
761 InvalidateRect(infoPtr->Self, NULL, FALSE);
767 STATUSBAR_SetTextT (STATUS_INFO *infoPtr, INT nPart, WORD style,
768 LPCWSTR text, BOOL isW)
770 STATUSWINDOWPART *part=NULL;
771 BOOL changed = FALSE;
774 if (style & SBT_OWNERDRAW) {
775 TRACE("part %d, text %p\n",nPart,text);
777 else TRACE("part %d, text %s\n", nPart, debugstr_t(text, isW));
779 /* MSDN says: "If the parameter is set to SB_SIMPLEID (255), the status
780 * window is assumed to be a simple window */
782 if (nPart == 0x00ff) {
783 part = &infoPtr->part0;
785 if (infoPtr->parts && nPart >= 0 && nPart < infoPtr->numParts) {
786 part = &infoPtr->parts[nPart];
789 if (!part) return FALSE;
791 if (part->style != style)
794 oldStyle = part->style;
796 if (style & SBT_OWNERDRAW) {
797 if (!(oldStyle & SBT_OWNERDRAW))
799 else if (part->text == text)
801 part->text = (LPWSTR)text;
806 LPCSTR atxt = (LPCSTR)text;
807 DWORD len = MultiByteToWideChar( CP_ACP, 0, atxt, -1, NULL, 0 );
808 ntext = Alloc( (len + 1)*sizeof(WCHAR) );
809 if (!ntext) return FALSE;
810 MultiByteToWideChar( CP_ACP, 0, atxt, -1, ntext, len );
812 ntext = Alloc( (strlenW(text) + 1)*sizeof(WCHAR) );
813 if (!ntext) return FALSE;
814 strcpyW (ntext, text);
817 /* check if text is unchanged -> no need to redraw */
819 if (!changed && part->text && !lstrcmpW(ntext, part->text)) {
824 if (!changed && !part->text)
828 if (!(oldStyle & SBT_OWNERDRAW))
832 InvalidateRect(infoPtr->Self, &part->bound, FALSE);
833 UpdateWindow(infoPtr->Self);
840 STATUSBAR_SetTipTextA (const STATUS_INFO *infoPtr, INT id, LPSTR text)
842 TRACE("part %d: \"%s\"\n", id, text);
843 if (infoPtr->hwndToolTip) {
845 ti.cbSize = sizeof(TTTOOLINFOA);
846 ti.hwnd = infoPtr->Self;
850 SendMessageA (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTA, 0, (LPARAM)&ti);
858 STATUSBAR_SetTipTextW (const STATUS_INFO *infoPtr, INT id, LPWSTR text)
860 TRACE("part %d: \"%s\"\n", id, debugstr_w(text));
861 if (infoPtr->hwndToolTip) {
863 ti.cbSize = sizeof(TTTOOLINFOW);
864 ti.hwnd = infoPtr->Self;
868 SendMessageW (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTW, 0, (LPARAM)&ti);
875 static inline LRESULT
876 STATUSBAR_SetUnicodeFormat (STATUS_INFO *infoPtr, BOOL bUnicode)
878 BOOL bOld = infoPtr->bUnicode;
880 TRACE("(0x%x)\n", bUnicode);
881 infoPtr->bUnicode = bUnicode;
888 STATUSBAR_Simple (STATUS_INFO *infoPtr, BOOL simple)
892 TRACE("(simple=%d)\n", simple);
893 if (infoPtr->simple == simple) /* no need to change */
896 infoPtr->simple = simple;
898 /* send notification */
899 nmhdr.hwndFrom = infoPtr->Self;
900 nmhdr.idFrom = GetWindowLongPtrW (infoPtr->Self, GWLP_ID);
901 nmhdr.code = SBN_SIMPLEMODECHANGE;
902 SendMessageW (infoPtr->Notify, WM_NOTIFY, 0, (LPARAM)&nmhdr);
903 InvalidateRect(infoPtr->Self, NULL, FALSE);
909 STATUSBAR_WMDestroy (STATUS_INFO *infoPtr)
914 for (i = 0; i < infoPtr->numParts; i++) {
915 if (!(infoPtr->parts[i].style & SBT_OWNERDRAW))
916 Free (infoPtr->parts[i].text);
918 if (!(infoPtr->part0.style & SBT_OWNERDRAW))
919 Free (infoPtr->part0.text);
920 Free (infoPtr->parts);
922 /* delete default font */
923 if (infoPtr->hDefaultFont)
924 DeleteObject (infoPtr->hDefaultFont);
926 /* delete tool tip control */
927 if (infoPtr->hwndToolTip)
928 DestroyWindow (infoPtr->hwndToolTip);
930 CloseThemeData (GetWindowTheme (infoPtr->Self));
932 SetWindowLongPtrW(infoPtr->Self, 0, 0);
939 STATUSBAR_WMCreate (HWND hwnd, const CREATESTRUCTA *lpCreate)
941 STATUS_INFO *infoPtr;
942 NONCLIENTMETRICSW nclm;
948 infoPtr = (STATUS_INFO*)Alloc (sizeof(STATUS_INFO));
949 if (!infoPtr) goto create_fail;
950 SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
952 infoPtr->Self = hwnd;
953 infoPtr->Notify = lpCreate->hwndParent;
954 infoPtr->numParts = 1;
956 infoPtr->simple = FALSE;
957 infoPtr->clrBk = CLR_DEFAULT;
959 infoPtr->horizontalBorder = HORZ_BORDER;
960 infoPtr->verticalBorder = VERT_BORDER;
961 infoPtr->horizontalGap = HORZ_GAP;
963 STATUSBAR_NotifyFormat(infoPtr, infoPtr->Notify, NF_REQUERY);
965 ZeroMemory (&nclm, sizeof(nclm));
966 nclm.cbSize = sizeof(nclm);
967 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, nclm.cbSize, &nclm, 0);
968 infoPtr->hDefaultFont = CreateFontIndirectW (&nclm.lfStatusFont);
970 GetClientRect (hwnd, &rect);
972 /* initialize simple case */
973 infoPtr->part0.bound = rect;
974 infoPtr->part0.text = 0;
975 infoPtr->part0.x = 0;
976 infoPtr->part0.style = 0;
977 infoPtr->part0.hIcon = 0;
979 /* initialize first part */
980 infoPtr->parts = Alloc (sizeof(STATUSWINDOWPART));
981 if (!infoPtr->parts) goto create_fail;
982 infoPtr->parts[0].bound = rect;
983 infoPtr->parts[0].text = 0;
984 infoPtr->parts[0].x = -1;
985 infoPtr->parts[0].style = 0;
986 infoPtr->parts[0].hIcon = 0;
988 OpenThemeData (hwnd, themeClass);
990 if (lpCreate->lpszName && (len = strlenW ((LPCWSTR)lpCreate->lpszName)))
992 infoPtr->parts[0].text = Alloc ((len + 1)*sizeof(WCHAR));
993 if (!infoPtr->parts[0].text) goto create_fail;
994 strcpyW (infoPtr->parts[0].text, (LPCWSTR)lpCreate->lpszName);
997 dwStyle = GetWindowLongW (hwnd, GWL_STYLE);
998 /* native seems to clear WS_BORDER, too */
999 dwStyle &= ~WS_BORDER;
1000 SetWindowLongW (hwnd, GWL_STYLE, dwStyle);
1002 infoPtr->height = STATUSBAR_ComputeHeight(infoPtr);
1004 if (dwStyle & SBT_TOOLTIPS) {
1005 infoPtr->hwndToolTip =
1006 CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, WS_POPUP | TTS_ALWAYSTIP,
1007 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1008 CW_USEDEFAULT, hwnd, 0,
1009 (HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE), NULL);
1011 if (infoPtr->hwndToolTip) {
1012 NMTOOLTIPSCREATED nmttc;
1014 nmttc.hdr.hwndFrom = hwnd;
1015 nmttc.hdr.idFrom = GetWindowLongPtrW (hwnd, GWLP_ID);
1016 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1017 nmttc.hwndToolTips = infoPtr->hwndToolTip;
1019 SendMessageW (lpCreate->hwndParent, WM_NOTIFY, nmttc.hdr.idFrom, (LPARAM)&nmttc);
1026 TRACE(" failed!\n");
1027 if (infoPtr) STATUSBAR_WMDestroy(infoPtr);
1032 /* in contrast to SB_GETTEXT*, WM_GETTEXT handles the text
1033 * of the first part only (usual behaviour) */
1035 STATUSBAR_WMGetText (const STATUS_INFO *infoPtr, INT size, LPWSTR buf)
1040 if (!(infoPtr->parts[0].text))
1043 len = strlenW (infoPtr->parts[0].text);
1046 strcpyW (buf, infoPtr->parts[0].text);
1055 STATUSBAR_WMNCHitTest (const STATUS_INFO *infoPtr, INT x, INT y)
1057 if (GetWindowLongW (infoPtr->Self, GWL_STYLE) & SBARS_SIZEGRIP) {
1061 GetClientRect (infoPtr->Self, &rect);
1065 ScreenToClient (infoPtr->Self, &pt);
1067 rect.left = rect.right - 13;
1070 if (PtInRect (&rect, pt))
1071 return HTBOTTOMRIGHT;
1079 STATUSBAR_WMPaint (STATUS_INFO *infoPtr, HDC hdc)
1084 if (hdc) return STATUSBAR_Refresh (infoPtr, hdc);
1085 hdc = BeginPaint (infoPtr->Self, &ps);
1086 STATUSBAR_Refresh (infoPtr, hdc);
1087 EndPaint (infoPtr->Self, &ps);
1094 STATUSBAR_WMSetFont (STATUS_INFO *infoPtr, HFONT font, BOOL redraw)
1096 infoPtr->hFont = font;
1097 TRACE("%p\n", infoPtr->hFont);
1099 infoPtr->height = STATUSBAR_ComputeHeight(infoPtr);
1100 SendMessageW(infoPtr->Self, WM_SIZE, 0, 0); /* update size */
1102 InvalidateRect(infoPtr->Self, NULL, FALSE);
1109 STATUSBAR_WMSetText (const STATUS_INFO *infoPtr, LPCSTR text)
1111 STATUSWINDOWPART *part;
1115 if (infoPtr->numParts == 0)
1118 part = &infoPtr->parts[0];
1119 /* duplicate string */
1123 if (text && (len = strlenW((LPCWSTR)text))) {
1124 part->text = Alloc ((len+1)*sizeof(WCHAR));
1125 if (!part->text) return FALSE;
1126 strcpyW (part->text, (LPCWSTR)text);
1129 InvalidateRect(infoPtr->Self, &part->bound, FALSE);
1136 STATUSBAR_WMSize (STATUS_INFO *infoPtr, WORD flags)
1141 /* Need to resize width to match parent */
1142 TRACE("flags %04x\n", flags);
1144 if (flags != SIZE_RESTORED && flags != SIZE_MAXIMIZED) {
1145 WARN("flags MUST be SIZE_RESTORED or SIZE_MAXIMIZED\n");
1149 if (GetWindowLongW(infoPtr->Self, GWL_STYLE) & CCS_NORESIZE) return FALSE;
1151 /* width and height don't apply */
1152 if (!GetClientRect (infoPtr->Notify, &parent_rect))
1155 width = parent_rect.right - parent_rect.left;
1156 x = parent_rect.left;
1157 y = parent_rect.bottom - infoPtr->height;
1158 MoveWindow (infoPtr->Self, x, y, width, infoPtr->height, TRUE);
1159 STATUSBAR_SetPartBounds (infoPtr);
1164 /* update theme after a WM_THEMECHANGED message */
1165 static LRESULT theme_changed (const STATUS_INFO* infoPtr)
1167 HTHEME theme = GetWindowTheme (infoPtr->Self);
1168 CloseThemeData (theme);
1169 OpenThemeData (infoPtr->Self, themeClass);
1175 STATUSBAR_NotifyFormat (STATUS_INFO *infoPtr, HWND from, INT cmd)
1177 if (cmd == NF_REQUERY) {
1178 INT i = SendMessageW(from, WM_NOTIFYFORMAT, (WPARAM)infoPtr->Self, NF_QUERY);
1179 infoPtr->bUnicode = (i == NFR_UNICODE);
1181 return infoPtr->bUnicode ? NFR_UNICODE : NFR_ANSI;
1186 STATUSBAR_SendMouseNotify(const STATUS_INFO *infoPtr, UINT code, LPARAM lParam)
1190 TRACE("code %04x, lParam=%lx\n", code, lParam);
1191 nm.hdr.hwndFrom = infoPtr->Self;
1192 nm.hdr.idFrom = GetWindowLongPtrW(infoPtr->Self, GWLP_ID);
1194 nm.pt.x = (short)LOWORD(lParam);
1195 nm.pt.y = (short)HIWORD(lParam);
1196 nm.dwItemSpec = STATUSBAR_InternalHitTest(infoPtr, &nm.pt);
1198 nm.dwHitInfo = 0x30000; /* seems constant */
1199 SendMessageW(infoPtr->Notify, WM_NOTIFY, 0, (LPARAM)&nm);
1205 static LRESULT WINAPI
1206 StatusWindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1208 STATUS_INFO *infoPtr = (STATUS_INFO *)GetWindowLongPtrW (hwnd, 0);
1209 INT nPart = ((INT) wParam) & 0x00ff;
1212 TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", hwnd, msg, wParam, lParam);
1213 if (!infoPtr && msg != WM_CREATE)
1214 return DefWindowProcW (hwnd, msg, wParam, lParam);
1218 return STATUSBAR_GetBorders (infoPtr, (INT *)lParam);
1221 return (LRESULT)STATUSBAR_GetIcon (infoPtr, nPart);
1224 return STATUSBAR_GetParts (infoPtr, (INT)wParam, (INT *)lParam);
1227 return STATUSBAR_GetRect (infoPtr, nPart, (LPRECT)lParam);
1230 return STATUSBAR_GetTextA (infoPtr, nPart, (LPSTR)lParam);
1233 return STATUSBAR_GetTextW (infoPtr, nPart, (LPWSTR)lParam);
1235 case SB_GETTEXTLENGTHA:
1236 case SB_GETTEXTLENGTHW:
1237 return STATUSBAR_GetTextLength (infoPtr, nPart);
1239 case SB_GETTIPTEXTA:
1240 return STATUSBAR_GetTipTextA (infoPtr, LOWORD(wParam), (LPSTR)lParam, HIWORD(wParam));
1242 case SB_GETTIPTEXTW:
1243 return STATUSBAR_GetTipTextW (infoPtr, LOWORD(wParam), (LPWSTR)lParam, HIWORD(wParam));
1245 case SB_GETUNICODEFORMAT:
1246 return infoPtr->bUnicode;
1249 return infoPtr->simple;
1252 return STATUSBAR_SetBorders (infoPtr, (INT *)lParam);
1255 return STATUSBAR_SetBkColor (infoPtr, (COLORREF)lParam);
1258 return STATUSBAR_SetIcon (infoPtr, nPart, (HICON)lParam);
1260 case SB_SETMINHEIGHT:
1261 return STATUSBAR_SetMinHeight (infoPtr, (INT)wParam);
1264 return STATUSBAR_SetParts (infoPtr, (INT)wParam, (LPINT)lParam);
1267 return STATUSBAR_SetTextT (infoPtr, nPart, wParam & 0xff00, (LPCWSTR)lParam, FALSE);
1270 return STATUSBAR_SetTextT (infoPtr, nPart, wParam & 0xff00, (LPCWSTR)lParam, TRUE);
1272 case SB_SETTIPTEXTA:
1273 return STATUSBAR_SetTipTextA (infoPtr, (INT)wParam, (LPSTR)lParam);
1275 case SB_SETTIPTEXTW:
1276 return STATUSBAR_SetTipTextW (infoPtr, (INT)wParam, (LPWSTR)lParam);
1278 case SB_SETUNICODEFORMAT:
1279 return STATUSBAR_SetUnicodeFormat (infoPtr, (BOOL)wParam);
1282 return STATUSBAR_Simple (infoPtr, (BOOL)wParam);
1285 return STATUSBAR_WMCreate (hwnd, (LPCREATESTRUCTA)lParam);
1288 return STATUSBAR_WMDestroy (infoPtr);
1291 return (LRESULT)(infoPtr->hFont? infoPtr->hFont : infoPtr->hDefaultFont);
1294 return STATUSBAR_WMGetText (infoPtr, (INT)wParam, (LPWSTR)lParam);
1296 case WM_GETTEXTLENGTH:
1297 return STATUSBAR_GetTextLength (infoPtr, 0);
1299 case WM_LBUTTONDBLCLK:
1300 return STATUSBAR_SendMouseNotify(infoPtr, NM_DBLCLK, lParam);
1303 return STATUSBAR_SendMouseNotify(infoPtr, NM_CLICK, lParam);
1306 return STATUSBAR_Relay2Tip (infoPtr, msg, wParam, lParam);
1309 res = STATUSBAR_WMNCHitTest(infoPtr, (short)LOWORD(lParam),
1310 (short)HIWORD(lParam));
1311 if (res != HTERROR) return res;
1312 return DefWindowProcW (hwnd, msg, wParam, lParam);
1314 case WM_NCLBUTTONUP:
1315 case WM_NCLBUTTONDOWN:
1316 PostMessageW (infoPtr->Notify, msg, wParam, lParam);
1319 case WM_NOTIFYFORMAT:
1320 return STATUSBAR_NotifyFormat(infoPtr, (HWND)wParam, (INT)lParam);
1322 case WM_PRINTCLIENT:
1324 return STATUSBAR_WMPaint (infoPtr, (HDC)wParam);
1326 case WM_RBUTTONDBLCLK:
1327 return STATUSBAR_SendMouseNotify(infoPtr, NM_RDBLCLK, lParam);
1330 return STATUSBAR_SendMouseNotify(infoPtr, NM_RCLICK, lParam);
1333 return STATUSBAR_WMSetFont (infoPtr, (HFONT)wParam, LOWORD(lParam));
1336 return STATUSBAR_WMSetText (infoPtr, (LPCSTR)lParam);
1339 if (STATUSBAR_WMSize (infoPtr, (WORD)wParam)) return 0;
1340 return DefWindowProcW (hwnd, msg, wParam, lParam);
1342 case WM_THEMECHANGED:
1343 return theme_changed (infoPtr);
1346 if ((msg >= WM_USER) && (msg < WM_APP))
1347 ERR("unknown msg %04x wp=%04lx lp=%08lx\n",
1348 msg, wParam, lParam);
1349 return DefWindowProcW (hwnd, msg, wParam, lParam);
1354 /***********************************************************************
1355 * STATUS_Register [Internal]
1357 * Registers the status window class.
1361 STATUS_Register (void)
1365 ZeroMemory (&wndClass, sizeof(WNDCLASSW));
1366 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW;
1367 wndClass.lpfnWndProc = StatusWindowProc;
1368 wndClass.cbClsExtra = 0;
1369 wndClass.cbWndExtra = sizeof(STATUS_INFO *);
1370 wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW);
1371 wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1372 wndClass.lpszClassName = STATUSCLASSNAMEW;
1374 RegisterClassW (&wndClass);
1378 /***********************************************************************
1379 * STATUS_Unregister [Internal]
1381 * Unregisters the status window class.
1385 STATUS_Unregister (void)
1387 UnregisterClassW (STATUSCLASSNAMEW, NULL);