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
; /* unicode flag */
81 BOOL NtfUnicode
; /* notify format */
82 STATUSWINDOWPART part0
; /* simple window */
83 STATUSWINDOWPART
* parts
;
90 * Run tests using Waite Group Windows95 API Bible Vol. 1&2
91 * The second cdrom contains executables drawstat.exe, gettext.exe,
92 * simple.exe, getparts.exe, setparts.exe, statwnd.exe
99 static const WCHAR themeClass
[] = { 'S','t','a','t','u','s',0 };
103 STATUSBAR_SetPartBounds (STATUS_INFO
*infoPtr
);
105 static inline LPCSTR
debugstr_t(LPCWSTR text
, BOOL isW
)
107 return isW
? debugstr_w(text
) : debugstr_a((LPCSTR
)text
);
111 STATUSBAR_DrawSizeGrip (HTHEME theme
, HDC hdc
, LPRECT lpRect
)
113 HPEN hPenFace
, hPenShadow
, hPenHighlight
, hOldPen
;
117 TRACE("draw size grip %d,%d - %d,%d\n", lpRect
->left
, lpRect
->top
, lpRect
->right
, lpRect
->bottom
);
123 gripperRect
= *lpRect
;
124 if (SUCCEEDED (GetThemePartSize (theme
, hdc
, SP_GRIPPER
, 0, lpRect
,
125 TS_DRAW
, &gripperSize
)))
127 gripperRect
.left
= gripperRect
.right
- gripperSize
.cx
;
128 gripperRect
.top
= gripperRect
.bottom
- gripperSize
.cy
;
129 if (SUCCEEDED (DrawThemeBackground(theme
, hdc
, SP_GRIPPER
, 0, &gripperRect
, NULL
)))
134 pt
.x
= lpRect
->right
- 1;
135 pt
.y
= lpRect
->bottom
- 1;
137 hPenFace
= CreatePen( PS_SOLID
, 1, GetSysColor( COLOR_3DFACE
));
138 hOldPen
= SelectObject( hdc
, hPenFace
);
139 MoveToEx (hdc
, pt
.x
- 12, pt
.y
, NULL
);
140 LineTo (hdc
, pt
.x
, pt
.y
);
141 LineTo (hdc
, pt
.x
, pt
.y
- 13);
146 hPenShadow
= CreatePen( PS_SOLID
, 1, GetSysColor( COLOR_3DSHADOW
));
147 SelectObject( hdc
, hPenShadow
);
148 for (i
= 1; i
< 11; i
+= 4) {
149 MoveToEx (hdc
, pt
.x
- i
, pt
.y
, NULL
);
150 LineTo (hdc
, pt
.x
+ 1, pt
.y
- i
- 1);
152 MoveToEx (hdc
, pt
.x
- i
- 1, pt
.y
, NULL
);
153 LineTo (hdc
, pt
.x
+ 1, pt
.y
- i
- 2);
156 hPenHighlight
= CreatePen( PS_SOLID
, 1, GetSysColor( COLOR_3DHIGHLIGHT
));
157 SelectObject( hdc
, hPenHighlight
);
158 for (i
= 3; i
< 13; i
+= 4) {
159 MoveToEx (hdc
, pt
.x
- i
, pt
.y
, NULL
);
160 LineTo (hdc
, pt
.x
+ 1, pt
.y
- i
- 1);
163 SelectObject (hdc
, hOldPen
);
164 DeleteObject( hPenFace
);
165 DeleteObject( hPenShadow
);
166 DeleteObject( hPenHighlight
);
171 STATUSBAR_DrawPart (STATUS_INFO
*infoPtr
, HDC hdc
, STATUSWINDOWPART
*part
, int itemID
)
173 RECT r
= part
->bound
;
174 UINT border
= BDR_SUNKENOUTER
;
175 HTHEME theme
= GetWindowTheme (infoPtr
->Self
);
176 int themePart
= SP_PANE
;
178 TRACE("part bound %d,%d - %d,%d\n", r
.left
, r
.top
, r
.right
, r
.bottom
);
179 if (part
->style
& SBT_POPOUT
)
180 border
= BDR_RAISEDOUTER
;
181 else if (part
->style
& SBT_NOBORDERS
)
186 if ((GetWindowLongW (infoPtr
->Self
, GWL_STYLE
) & SBARS_SIZEGRIP
)
187 && (infoPtr
->simple
|| (itemID
== (infoPtr
->numParts
-1))))
188 themePart
= SP_GRIPPERPANE
;
189 DrawThemeBackground(theme
, hdc
, themePart
, 0, &r
, NULL
);
192 DrawEdge(hdc
, &r
, border
, BF_RECT
|BF_ADJUST
);
194 if (part
->style
& SBT_OWNERDRAW
) {
197 dis
.CtlID
= GetWindowLongPtrW (infoPtr
->Self
, GWLP_ID
);
199 dis
.hwndItem
= infoPtr
->Self
;
202 dis
.itemData
= (ULONG_PTR
)part
->text
;
203 SendMessageW (infoPtr
->Notify
, WM_DRAWITEM
, (WPARAM
)dis
.CtlID
, (LPARAM
)&dis
);
206 INT cy
= r
.bottom
- r
.top
;
209 DrawIconEx (hdc
, r
.left
, r
.top
, part
->hIcon
, cy
, cy
, 0, 0, DI_NORMAL
);
212 DrawStatusTextW (hdc
, &r
, part
->text
, SBT_NOBORDERS
);
218 STATUSBAR_RefreshPart (STATUS_INFO
*infoPtr
, HDC hdc
, STATUSWINDOWPART
*part
, int itemID
)
224 TRACE("item %d\n", itemID
);
225 if (!IsWindowVisible (infoPtr
->Self
))
228 if (part
->bound
.right
< part
->bound
.left
) return;
230 if ((theme
= GetWindowTheme (infoPtr
->Self
)))
233 GetClientRect (infoPtr
->Self
, &cr
);
234 DrawThemeBackground(theme
, hdc
, 0, 0, &cr
, &part
->bound
);
238 if (infoPtr
->clrBk
!= CLR_DEFAULT
)
239 hbrBk
= CreateSolidBrush (infoPtr
->clrBk
);
241 hbrBk
= GetSysColorBrush (COLOR_3DFACE
);
242 FillRect(hdc
, &part
->bound
, hbrBk
);
243 if (infoPtr
->clrBk
!= CLR_DEFAULT
)
244 DeleteObject (hbrBk
);
247 hOldFont
= SelectObject (hdc
, infoPtr
->hFont
? infoPtr
->hFont
: infoPtr
->hDefaultFont
);
249 STATUSBAR_DrawPart (infoPtr
, hdc
, part
, itemID
);
251 SelectObject (hdc
, hOldFont
);
253 if (GetWindowLongW (infoPtr
->Self
, GWL_STYLE
) & SBARS_SIZEGRIP
) {
256 GetClientRect (infoPtr
->Self
, &rect
);
257 STATUSBAR_DrawSizeGrip (theme
, hdc
, &rect
);
263 STATUSBAR_Refresh (STATUS_INFO
*infoPtr
, HDC hdc
)
272 if (!IsWindowVisible(infoPtr
->Self
))
275 STATUSBAR_SetPartBounds(infoPtr
);
277 GetClientRect (infoPtr
->Self
, &rect
);
279 if ((theme
= GetWindowTheme (infoPtr
->Self
)))
281 DrawThemeBackground(theme
, hdc
, 0, 0, &rect
, NULL
);
285 if (infoPtr
->clrBk
!= CLR_DEFAULT
)
286 hbrBk
= CreateSolidBrush (infoPtr
->clrBk
);
288 hbrBk
= GetSysColorBrush (COLOR_3DFACE
);
289 FillRect(hdc
, &rect
, hbrBk
);
290 if (infoPtr
->clrBk
!= CLR_DEFAULT
)
291 DeleteObject (hbrBk
);
294 hOldFont
= SelectObject (hdc
, infoPtr
->hFont
? infoPtr
->hFont
: infoPtr
->hDefaultFont
);
296 if (infoPtr
->simple
) {
297 STATUSBAR_RefreshPart (infoPtr
, hdc
, &infoPtr
->part0
, 0);
299 for (i
= 0; i
< infoPtr
->numParts
; i
++) {
300 STATUSBAR_RefreshPart (infoPtr
, hdc
, &infoPtr
->parts
[i
], i
);
304 SelectObject (hdc
, hOldFont
);
306 if (GetWindowLongW (infoPtr
->Self
, GWL_STYLE
) & SBARS_SIZEGRIP
)
307 STATUSBAR_DrawSizeGrip (theme
, hdc
, &rect
);
314 STATUSBAR_SetPartBounds (STATUS_INFO
*infoPtr
)
316 STATUSWINDOWPART
*part
;
320 /* get our window size */
321 GetClientRect (infoPtr
->Self
, &rect
);
322 TRACE("client wnd size is %d,%d - %d,%d\n", rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
324 rect
.left
+= infoPtr
->horizontalBorder
;
325 rect
.top
+= infoPtr
->verticalBorder
;
327 /* set bounds for simple rectangle */
328 infoPtr
->part0
.bound
= rect
;
330 /* set bounds for non-simple rectangles */
331 for (i
= 0; i
< infoPtr
->numParts
; i
++) {
332 part
= &infoPtr
->parts
[i
];
333 r
= &infoPtr
->parts
[i
].bound
;
335 r
->bottom
= rect
.bottom
;
339 r
->left
= infoPtr
->parts
[i
-1].bound
.right
+ infoPtr
->horizontalGap
;
341 r
->right
= rect
.right
;
345 if (infoPtr
->hwndToolTip
) {
348 ti
.cbSize
= sizeof(TTTOOLINFOW
);
349 ti
.hwnd
= infoPtr
->Self
;
352 SendMessageW (infoPtr
->hwndToolTip
, TTM_NEWTOOLRECTW
,
360 STATUSBAR_Relay2Tip (STATUS_INFO
*infoPtr
, UINT uMsg
,
361 WPARAM wParam
, LPARAM lParam
)
365 msg
.hwnd
= infoPtr
->Self
;
369 msg
.time
= GetMessageTime ();
370 msg
.pt
.x
= (short)LOWORD(GetMessagePos ());
371 msg
.pt
.y
= (short)HIWORD(GetMessagePos ());
373 return SendMessageW (infoPtr
->hwndToolTip
, TTM_RELAYEVENT
, 0, (LPARAM
)&msg
);
378 STATUSBAR_GetBorders (STATUS_INFO
*infoPtr
, INT out
[])
381 out
[0] = infoPtr
->horizontalBorder
;
382 out
[1] = infoPtr
->verticalBorder
;
383 out
[2] = infoPtr
->horizontalGap
;
390 STATUSBAR_SetBorders (STATUS_INFO
*infoPtr
, INT in
[])
393 infoPtr
->horizontalBorder
= in
[0];
394 infoPtr
->verticalBorder
= in
[1];
395 infoPtr
->horizontalGap
= in
[2];
396 InvalidateRect(infoPtr
->Self
, NULL
, FALSE
);
403 STATUSBAR_GetIcon (STATUS_INFO
*infoPtr
, INT nPart
)
405 TRACE("%d\n", nPart
);
406 /* MSDN says: "simple parts are indexed with -1" */
407 if ((nPart
< -1) || (nPart
>= infoPtr
->numParts
))
411 return (infoPtr
->part0
.hIcon
);
413 return (infoPtr
->parts
[nPart
].hIcon
);
418 STATUSBAR_GetParts (STATUS_INFO
*infoPtr
, INT num_parts
, INT parts
[])
422 TRACE("(%d)\n", num_parts
);
424 for (i
= 0; i
< num_parts
; i
++) {
425 parts
[i
] = infoPtr
->parts
[i
].x
;
428 return infoPtr
->numParts
;
433 STATUSBAR_GetRect (STATUS_INFO
*infoPtr
, INT nPart
, LPRECT rect
)
435 TRACE("part %d\n", nPart
);
436 if(nPart
>= infoPtr
->numParts
|| nPart
< 0)
439 *rect
= infoPtr
->part0
.bound
;
441 *rect
= infoPtr
->parts
[nPart
].bound
;
447 STATUSBAR_GetTextA (STATUS_INFO
*infoPtr
, INT nPart
, LPSTR buf
)
449 STATUSWINDOWPART
*part
;
452 TRACE("part %d\n", nPart
);
454 /* MSDN says: "simple parts use index of 0", so this check is ok. */
455 if (nPart
< 0 || nPart
>= infoPtr
->numParts
) return 0;
458 part
= &infoPtr
->part0
;
460 part
= &infoPtr
->parts
[nPart
];
462 if (part
->style
& SBT_OWNERDRAW
)
463 result
= (LRESULT
)part
->text
;
465 DWORD len
= part
->text
? WideCharToMultiByte( CP_ACP
, 0, part
->text
, -1,
466 NULL
, 0, NULL
, NULL
) - 1 : 0;
467 result
= MAKELONG( len
, part
->style
);
468 if (part
->text
&& buf
)
469 WideCharToMultiByte( CP_ACP
, 0, part
->text
, -1, buf
, len
+1, NULL
, NULL
);
476 STATUSBAR_GetTextW (STATUS_INFO
*infoPtr
, INT nPart
, LPWSTR buf
)
478 STATUSWINDOWPART
*part
;
481 TRACE("part %d\n", nPart
);
482 if (nPart
< 0 || nPart
>= infoPtr
->numParts
) return 0;
485 part
= &infoPtr
->part0
;
487 part
= &infoPtr
->parts
[nPart
];
489 if (part
->style
& SBT_OWNERDRAW
)
490 result
= (LRESULT
)part
->text
;
492 result
= part
->text
? strlenW (part
->text
) : 0;
493 result
|= (part
->style
<< 16);
494 if (part
->text
&& buf
)
495 strcpyW (buf
, part
->text
);
502 STATUSBAR_GetTextLength (STATUS_INFO
*infoPtr
, INT nPart
)
504 STATUSWINDOWPART
*part
;
507 TRACE("part %d\n", nPart
);
509 /* MSDN says: "simple parts use index of 0", so this check is ok. */
510 if (nPart
< 0 || nPart
>= infoPtr
->numParts
) return 0;
513 part
= &infoPtr
->part0
;
515 part
= &infoPtr
->parts
[nPart
];
517 if ((~part
->style
& SBT_OWNERDRAW
) && part
->text
)
518 result
= strlenW(part
->text
);
522 result
|= (part
->style
<< 16);
527 STATUSBAR_GetTipTextA (STATUS_INFO
*infoPtr
, INT id
, LPSTR tip
, INT size
)
531 CHAR buf
[INFOTIPSIZE
];
534 if (infoPtr
->hwndToolTip
) {
536 ti
.cbSize
= sizeof(TTTOOLINFOA
);
537 ti
.hwnd
= infoPtr
->Self
;
540 SendMessageA (infoPtr
->hwndToolTip
, TTM_GETTEXTA
, 0, (LPARAM
)&ti
);
542 lstrcpynA (tip
, buf
, size
);
549 STATUSBAR_GetTipTextW (STATUS_INFO
*infoPtr
, INT id
, LPWSTR tip
, INT size
)
553 WCHAR buf
[INFOTIPSIZE
];
556 if (infoPtr
->hwndToolTip
) {
558 ti
.cbSize
= sizeof(TTTOOLINFOW
);
559 ti
.hwnd
= infoPtr
->Self
;
562 SendMessageW(infoPtr
->hwndToolTip
, TTM_GETTEXTW
, 0, (LPARAM
)&ti
);
564 lstrcpynW(tip
, buf
, size
);
572 STATUSBAR_SetBkColor (STATUS_INFO
*infoPtr
, COLORREF color
)
576 oldBkColor
= infoPtr
->clrBk
;
577 infoPtr
->clrBk
= color
;
578 InvalidateRect(infoPtr
->Self
, NULL
, FALSE
);
580 TRACE("CREF: %08x -> %08x\n", oldBkColor
, infoPtr
->clrBk
);
586 STATUSBAR_SetIcon (STATUS_INFO
*infoPtr
, INT nPart
, HICON hIcon
)
588 if ((nPart
< -1) || (nPart
>= infoPtr
->numParts
))
591 TRACE("setting part %d\n", nPart
);
593 /* FIXME: MSDN says "if nPart is -1, the status bar is assumed simple" */
595 if (infoPtr
->part0
.hIcon
== hIcon
) /* same as - no redraw */
597 infoPtr
->part0
.hIcon
= hIcon
;
599 InvalidateRect(infoPtr
->Self
, &infoPtr
->part0
.bound
, FALSE
);
601 if (infoPtr
->parts
[nPart
].hIcon
== hIcon
) /* same as - no redraw */
604 infoPtr
->parts
[nPart
].hIcon
= hIcon
;
605 if (!(infoPtr
->simple
))
606 InvalidateRect(infoPtr
->Self
, &infoPtr
->parts
[nPart
].bound
, FALSE
);
613 STATUSBAR_SetMinHeight (STATUS_INFO
*infoPtr
, INT height
)
616 TRACE("(height=%d)\n", height
);
617 if (IsWindowVisible (infoPtr
->Self
)) {
622 GetClientRect (infoPtr
->Notify
, &parent_rect
);
623 infoPtr
->height
= height
+ infoPtr
->verticalBorder
;
625 if ((theme
= GetWindowTheme (infoPtr
->Self
)))
627 /* Determine bar height from theme such that the content area is
628 * 'height' pixels large */
629 HDC hdc
= GetDC (infoPtr
->Self
);
631 memset (&r
, 0, sizeof (r
));
633 if (SUCCEEDED(GetThemeBackgroundExtent (theme
, hdc
, SP_PANE
, 0, &r
, &r
)))
635 infoPtr
->height
= r
.bottom
- r
.top
;
637 ReleaseDC (infoPtr
->Self
, hdc
);
640 width
= parent_rect
.right
- parent_rect
.left
;
641 x
= parent_rect
.left
;
642 y
= parent_rect
.bottom
- infoPtr
->height
;
643 MoveWindow (infoPtr
->Self
, parent_rect
.left
,
644 parent_rect
.bottom
- infoPtr
->height
,
645 width
, infoPtr
->height
, TRUE
);
646 STATUSBAR_SetPartBounds (infoPtr
);
654 STATUSBAR_SetParts (STATUS_INFO
*infoPtr
, INT count
, LPINT parts
)
656 STATUSWINDOWPART
*tmp
;
659 TRACE("(%d,%p)\n", count
, parts
);
661 oldNumParts
= infoPtr
->numParts
;
662 infoPtr
->numParts
= count
;
663 if (oldNumParts
> infoPtr
->numParts
) {
664 for (i
= infoPtr
->numParts
; i
< oldNumParts
; i
++) {
665 if (infoPtr
->parts
[i
].text
&& !(infoPtr
->parts
[i
].style
& SBT_OWNERDRAW
))
666 Free (infoPtr
->parts
[i
].text
);
668 } else if (oldNumParts
< infoPtr
->numParts
) {
669 tmp
= Alloc (sizeof(STATUSWINDOWPART
) * infoPtr
->numParts
);
670 if (!tmp
) return FALSE
;
671 for (i
= 0; i
< oldNumParts
; i
++) {
672 tmp
[i
] = infoPtr
->parts
[i
];
675 Free (infoPtr
->parts
);
676 infoPtr
->parts
= tmp
;
678 if (oldNumParts
== infoPtr
->numParts
) {
679 for (i
=0; i
< oldNumParts
; i
++)
680 if (infoPtr
->parts
[i
].x
!= parts
[i
])
682 if (i
==oldNumParts
) /* Unchanged? no need to redraw! */
686 for (i
= 0; i
< infoPtr
->numParts
; i
++)
687 infoPtr
->parts
[i
].x
= parts
[i
];
689 if (infoPtr
->hwndToolTip
) {
693 ZeroMemory (&ti
, sizeof(TTTOOLINFOW
));
694 ti
.cbSize
= sizeof(TTTOOLINFOW
);
695 ti
.hwnd
= infoPtr
->Self
;
697 nTipCount
= SendMessageW (infoPtr
->hwndToolTip
, TTM_GETTOOLCOUNT
, 0, 0);
698 if (nTipCount
< infoPtr
->numParts
) {
700 for (i
= nTipCount
; i
< infoPtr
->numParts
; i
++) {
701 TRACE("add tool %d\n", i
);
703 SendMessageW (infoPtr
->hwndToolTip
, TTM_ADDTOOLW
,
707 else if (nTipCount
> infoPtr
->numParts
) {
709 for (i
= nTipCount
- 1; i
>= infoPtr
->numParts
; i
--) {
710 TRACE("delete tool %d\n", i
);
712 SendMessageW (infoPtr
->hwndToolTip
, TTM_DELTOOLW
,
717 STATUSBAR_SetPartBounds (infoPtr
);
718 InvalidateRect(infoPtr
->Self
, NULL
, FALSE
);
724 STATUSBAR_SetTextT (STATUS_INFO
*infoPtr
, INT nPart
, WORD style
,
725 LPCWSTR text
, BOOL isW
)
727 STATUSWINDOWPART
*part
=NULL
;
728 BOOL changed
= FALSE
;
731 if (style
& SBT_OWNERDRAW
) {
732 TRACE("part %d, text %p\n",nPart
,text
);
734 else TRACE("part %d, text %s\n", nPart
, debugstr_t(text
, isW
));
736 /* MSDN says: "If the parameter is set to SB_SIMPLEID (255), the status
737 * window is assumed to be a simple window */
739 if (nPart
== 0x00ff) {
740 part
= &infoPtr
->part0
;
742 if (infoPtr
->parts
&& nPart
>= 0 && nPart
< infoPtr
->numParts
) {
743 part
= &infoPtr
->parts
[nPart
];
746 if (!part
) return FALSE
;
748 if (part
->style
!= style
)
751 oldStyle
= part
->style
;
753 if (style
& SBT_OWNERDRAW
) {
754 if (!(oldStyle
& SBT_OWNERDRAW
)) {
757 } else if (part
->text
== text
)
759 part
->text
= (LPWSTR
)text
;
764 LPCSTR atxt
= (LPCSTR
)text
;
765 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, atxt
, -1, NULL
, 0 );
766 ntext
= Alloc( (len
+ 1)*sizeof(WCHAR
) );
767 if (!ntext
) return FALSE
;
768 MultiByteToWideChar( CP_ACP
, 0, atxt
, -1, ntext
, len
);
770 ntext
= Alloc( (strlenW(text
) + 1)*sizeof(WCHAR
) );
771 if (!ntext
) return FALSE
;
772 strcpyW (ntext
, text
);
775 /* check if text is unchanged -> no need to redraw */
777 if (!changed
&& part
->text
&& !lstrcmpW(ntext
, part
->text
)) {
782 if (!changed
&& !part
->text
)
786 if (part
->text
&& !(oldStyle
& SBT_OWNERDRAW
))
790 InvalidateRect(infoPtr
->Self
, &part
->bound
, FALSE
);
791 UpdateWindow(infoPtr
->Self
);
798 STATUSBAR_SetTipTextA (STATUS_INFO
*infoPtr
, INT id
, LPSTR text
)
800 TRACE("part %d: \"%s\"\n", id
, text
);
801 if (infoPtr
->hwndToolTip
) {
803 ti
.cbSize
= sizeof(TTTOOLINFOA
);
804 ti
.hwnd
= infoPtr
->Self
;
808 SendMessageA (infoPtr
->hwndToolTip
, TTM_UPDATETIPTEXTA
, 0, (LPARAM
)&ti
);
816 STATUSBAR_SetTipTextW (STATUS_INFO
*infoPtr
, INT id
, LPWSTR text
)
818 TRACE("part %d: \"%s\"\n", id
, debugstr_w(text
));
819 if (infoPtr
->hwndToolTip
) {
821 ti
.cbSize
= sizeof(TTTOOLINFOW
);
822 ti
.hwnd
= infoPtr
->Self
;
826 SendMessageW (infoPtr
->hwndToolTip
, TTM_UPDATETIPTEXTW
, 0, (LPARAM
)&ti
);
833 inline static LRESULT
834 STATUSBAR_SetUnicodeFormat (STATUS_INFO
*infoPtr
, BOOL bUnicode
)
836 BOOL bOld
= infoPtr
->bUnicode
;
838 TRACE("(0x%x)\n", bUnicode
);
839 infoPtr
->bUnicode
= bUnicode
;
846 STATUSBAR_Simple (STATUS_INFO
*infoPtr
, BOOL simple
)
850 TRACE("(simple=%d)\n", simple
);
851 if (infoPtr
->simple
== simple
) /* no need to change */
854 infoPtr
->simple
= simple
;
856 /* send notification */
857 nmhdr
.hwndFrom
= infoPtr
->Self
;
858 nmhdr
.idFrom
= GetWindowLongPtrW (infoPtr
->Self
, GWLP_ID
);
859 nmhdr
.code
= SBN_SIMPLEMODECHANGE
;
860 SendMessageW (infoPtr
->Notify
, WM_NOTIFY
, 0, (LPARAM
)&nmhdr
);
861 InvalidateRect(infoPtr
->Self
, NULL
, FALSE
);
867 STATUSBAR_WMDestroy (STATUS_INFO
*infoPtr
)
872 for (i
= 0; i
< infoPtr
->numParts
; i
++) {
873 if (infoPtr
->parts
[i
].text
&& !(infoPtr
->parts
[i
].style
& SBT_OWNERDRAW
))
874 Free (infoPtr
->parts
[i
].text
);
876 if (infoPtr
->part0
.text
&& !(infoPtr
->part0
.style
& SBT_OWNERDRAW
))
877 Free (infoPtr
->part0
.text
);
878 Free (infoPtr
->parts
);
880 /* delete default font */
881 if (infoPtr
->hDefaultFont
)
882 DeleteObject (infoPtr
->hDefaultFont
);
884 /* delete tool tip control */
885 if (infoPtr
->hwndToolTip
)
886 DestroyWindow (infoPtr
->hwndToolTip
);
888 CloseThemeData (GetWindowTheme (infoPtr
->Self
));
890 SetWindowLongPtrW(infoPtr
->Self
, 0, 0);
897 STATUSBAR_WMCreate (HWND hwnd
, LPCREATESTRUCTA lpCreate
)
899 STATUS_INFO
*infoPtr
;
900 NONCLIENTMETRICSW nclm
;
903 int i
, width
, len
, textHeight
= 0;
907 infoPtr
= (STATUS_INFO
*)Alloc (sizeof(STATUS_INFO
));
908 if (!infoPtr
) goto create_fail
;
909 SetWindowLongPtrW (hwnd
, 0, (DWORD_PTR
)infoPtr
);
911 infoPtr
->Self
= hwnd
;
912 infoPtr
->Notify
= lpCreate
->hwndParent
;
913 infoPtr
->numParts
= 1;
915 infoPtr
->simple
= FALSE
;
916 infoPtr
->clrBk
= CLR_DEFAULT
;
918 infoPtr
->horizontalBorder
= HORZ_BORDER
;
919 infoPtr
->verticalBorder
= VERT_BORDER
;
920 infoPtr
->horizontalGap
= HORZ_GAP
;
922 i
= SendMessageW(infoPtr
->Notify
, WM_NOTIFYFORMAT
, (WPARAM
)hwnd
, NF_QUERY
);
923 infoPtr
->NtfUnicode
= (i
== NFR_UNICODE
);
925 GetClientRect (hwnd
, &rect
);
926 InvalidateRect (hwnd
, &rect
, 0);
929 ZeroMemory (&nclm
, sizeof(nclm
));
930 nclm
.cbSize
= sizeof(nclm
);
931 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS
, nclm
.cbSize
, &nclm
, 0);
932 infoPtr
->hDefaultFont
= CreateFontIndirectW (&nclm
.lfStatusFont
);
934 /* initialize simple case */
935 infoPtr
->part0
.bound
= rect
;
936 infoPtr
->part0
.text
= 0;
937 infoPtr
->part0
.x
= 0;
938 infoPtr
->part0
.style
= 0;
939 infoPtr
->part0
.hIcon
= 0;
941 /* initialize first part */
942 infoPtr
->parts
= Alloc (sizeof(STATUSWINDOWPART
));
943 if (!infoPtr
->parts
) goto create_fail
;
944 infoPtr
->parts
[0].bound
= rect
;
945 infoPtr
->parts
[0].text
= 0;
946 infoPtr
->parts
[0].x
= -1;
947 infoPtr
->parts
[0].style
= 0;
948 infoPtr
->parts
[0].hIcon
= 0;
950 OpenThemeData (hwnd
, themeClass
);
952 if (IsWindowUnicode (hwnd
)) {
953 infoPtr
->bUnicode
= TRUE
;
954 if (lpCreate
->lpszName
&&
955 (len
= strlenW ((LPCWSTR
)lpCreate
->lpszName
))) {
956 infoPtr
->parts
[0].text
= Alloc ((len
+ 1)*sizeof(WCHAR
));
957 if (!infoPtr
->parts
[0].text
) goto create_fail
;
958 strcpyW (infoPtr
->parts
[0].text
, (LPCWSTR
)lpCreate
->lpszName
);
962 if (lpCreate
->lpszName
&&
963 (len
= strlen((LPCSTR
)lpCreate
->lpszName
))) {
964 DWORD lenW
= MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)lpCreate
->lpszName
, -1, NULL
, 0 );
965 infoPtr
->parts
[0].text
= Alloc (lenW
*sizeof(WCHAR
));
966 if (!infoPtr
->parts
[0].text
) goto create_fail
;
967 MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)lpCreate
->lpszName
, -1,
968 infoPtr
->parts
[0].text
, lenW
);
972 dwStyle
= GetWindowLongW (hwnd
, GWL_STYLE
);
973 /* native seems to clear WS_BORDER, too */
974 dwStyle
&= ~WS_BORDER
;
976 /* statusbars on managed windows should not have SIZEGRIP style */
977 if ((dwStyle
& SBARS_SIZEGRIP
) && lpCreate
->hwndParent
&&
978 GetPropA( lpCreate
->hwndParent
, "__wine_x11_managed" ))
979 dwStyle
&= ~SBARS_SIZEGRIP
;
981 SetWindowLongW (hwnd
, GWL_STYLE
, dwStyle
);
983 if ((hdc
= GetDC (hwnd
))) {
987 hOldFont
= SelectObject (hdc
, infoPtr
->hDefaultFont
);
988 GetTextMetricsW (hdc
, &tm
);
989 textHeight
= tm
.tmHeight
;
990 SelectObject (hdc
, hOldFont
);
991 ReleaseDC (hwnd
, hdc
);
993 TRACE(" textHeight=%d\n", textHeight
);
995 if (dwStyle
& SBT_TOOLTIPS
) {
996 infoPtr
->hwndToolTip
=
997 CreateWindowExW (0, TOOLTIPS_CLASSW
, NULL
, WS_POPUP
| TTS_ALWAYSTIP
,
998 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
999 CW_USEDEFAULT
, hwnd
, 0,
1000 (HINSTANCE
)GetWindowLongPtrW(hwnd
, GWLP_HINSTANCE
), NULL
);
1002 if (infoPtr
->hwndToolTip
) {
1003 NMTOOLTIPSCREATED nmttc
;
1005 nmttc
.hdr
.hwndFrom
= hwnd
;
1006 nmttc
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
1007 nmttc
.hdr
.code
= NM_TOOLTIPSCREATED
;
1008 nmttc
.hwndToolTips
= infoPtr
->hwndToolTip
;
1010 SendMessageW (lpCreate
->hwndParent
, WM_NOTIFY
,
1011 (WPARAM
)nmttc
.hdr
.idFrom
, (LPARAM
)&nmttc
);
1015 if (!(dwStyle
& CCS_NORESIZE
)) { /* don't resize wnd if it doesn't want it ! */
1017 GetClientRect (infoPtr
->Notify
, &rect
);
1018 width
= rect
.right
- rect
.left
;
1019 infoPtr
->height
= textHeight
+ 4 + infoPtr
->verticalBorder
;
1021 if ((theme
= GetWindowTheme (hwnd
)))
1023 /* Determine bar height from theme such that the content area is
1024 * textHeight pixels large */
1025 HDC hdc
= GetDC (hwnd
);
1027 memset (&r
, 0, sizeof (r
));
1028 r
.bottom
= textHeight
;
1029 if (SUCCEEDED(GetThemeBackgroundExtent (theme
, hdc
, SP_PANE
, 0, &r
, &r
)))
1031 infoPtr
->height
= r
.bottom
- r
.top
;
1033 ReleaseDC (hwnd
, hdc
);
1036 SetWindowPos(hwnd
, 0, lpCreate
->x
, lpCreate
->y
- 1,
1037 width
, infoPtr
->height
, SWP_NOZORDER
);
1038 STATUSBAR_SetPartBounds (infoPtr
);
1044 TRACE(" failed!\n");
1045 if (infoPtr
) STATUSBAR_WMDestroy(infoPtr
);
1050 /* in contrast to SB_GETTEXT*, WM_GETTEXT handles the text
1051 * of the first part only (usual behaviour) */
1053 STATUSBAR_WMGetText (STATUS_INFO
*infoPtr
, INT size
, LPWSTR buf
)
1058 if (!(infoPtr
->parts
[0].text
))
1060 if (infoPtr
->bUnicode
)
1061 len
= strlenW (infoPtr
->parts
[0].text
);
1063 len
= WideCharToMultiByte( CP_ACP
, 0, infoPtr
->parts
[0].text
, -1, NULL
, 0, NULL
, NULL
)-1;
1066 if (infoPtr
->bUnicode
)
1067 strcpyW (buf
, infoPtr
->parts
[0].text
);
1069 WideCharToMultiByte( CP_ACP
, 0, infoPtr
->parts
[0].text
, -1,
1070 (LPSTR
)buf
, len
+1, NULL
, NULL
);
1079 STATUSBAR_WMNCHitTest (STATUS_INFO
*infoPtr
, INT x
, INT y
)
1081 if (GetWindowLongW (infoPtr
->Self
, GWL_STYLE
) & SBARS_SIZEGRIP
) {
1085 GetClientRect (infoPtr
->Self
, &rect
);
1089 ScreenToClient (infoPtr
->Self
, &pt
);
1091 rect
.left
= rect
.right
- 13;
1094 if (PtInRect (&rect
, pt
))
1095 return HTBOTTOMRIGHT
;
1103 STATUSBAR_WMPaint (STATUS_INFO
*infoPtr
, HDC hdc
)
1108 if (hdc
) return STATUSBAR_Refresh (infoPtr
, hdc
);
1109 hdc
= BeginPaint (infoPtr
->Self
, &ps
);
1110 STATUSBAR_Refresh (infoPtr
, hdc
);
1111 EndPaint (infoPtr
->Self
, &ps
);
1118 STATUSBAR_WMSetFont (STATUS_INFO
*infoPtr
, HFONT font
, BOOL redraw
)
1120 infoPtr
->hFont
= font
;
1121 TRACE("%p\n", infoPtr
->hFont
);
1123 InvalidateRect(infoPtr
->Self
, NULL
, FALSE
);
1130 STATUSBAR_WMSetText (STATUS_INFO
*infoPtr
, LPCSTR text
)
1132 STATUSWINDOWPART
*part
;
1136 if (infoPtr
->numParts
== 0)
1139 part
= &infoPtr
->parts
[0];
1140 /* duplicate string */
1144 if (infoPtr
->bUnicode
) {
1145 if (text
&& (len
= strlenW((LPCWSTR
)text
))) {
1146 part
->text
= Alloc ((len
+1)*sizeof(WCHAR
));
1147 if (!part
->text
) return FALSE
;
1148 strcpyW (part
->text
, (LPCWSTR
)text
);
1152 if (text
&& (len
= lstrlenA(text
))) {
1153 DWORD lenW
= MultiByteToWideChar( CP_ACP
, 0, text
, -1, NULL
, 0 );
1154 part
->text
= Alloc (lenW
*sizeof(WCHAR
));
1155 if (!part
->text
) return FALSE
;
1156 MultiByteToWideChar( CP_ACP
, 0, text
, -1, part
->text
, lenW
);
1160 InvalidateRect(infoPtr
->Self
, &part
->bound
, FALSE
);
1167 STATUSBAR_WMSize (STATUS_INFO
*infoPtr
, WORD flags
)
1172 /* Need to resize width to match parent */
1173 TRACE("flags %04x\n", flags
);
1175 if (flags
!= SIZE_RESTORED
&& flags
!= SIZE_MAXIMIZED
) {
1176 WARN("flags MUST be SIZE_RESTORED or SIZE_MAXIMIZED\n");
1180 if (GetWindowLongW(infoPtr
->Self
, GWL_STYLE
) & CCS_NORESIZE
) return FALSE
;
1182 /* width and height don't apply */
1183 GetClientRect (infoPtr
->Notify
, &parent_rect
);
1184 width
= parent_rect
.right
- parent_rect
.left
;
1185 x
= parent_rect
.left
;
1186 y
= parent_rect
.bottom
- infoPtr
->height
;
1187 MoveWindow (infoPtr
->Self
, parent_rect
.left
,
1188 parent_rect
.bottom
- infoPtr
->height
,
1189 width
, infoPtr
->height
, TRUE
);
1190 STATUSBAR_SetPartBounds (infoPtr
);
1195 /* update theme after a WM_THEMECHANGED message */
1196 static LRESULT
theme_changed (STATUS_INFO
* infoPtr
)
1198 HTHEME theme
= GetWindowTheme (infoPtr
->Self
);
1199 CloseThemeData (theme
);
1200 OpenThemeData (infoPtr
->Self
, themeClass
);
1206 STATUSBAR_NotifyFormat (STATUS_INFO
*infoPtr
, HWND from
, INT cmd
)
1208 if (cmd
== NF_REQUERY
) {
1209 INT i
= SendMessageW(from
, WM_NOTIFYFORMAT
, (WPARAM
)infoPtr
->Self
, NF_QUERY
);
1210 infoPtr
->NtfUnicode
= (i
== NFR_UNICODE
);
1212 return infoPtr
->NtfUnicode
? NFR_UNICODE
: NFR_ANSI
;
1217 STATUSBAR_SendNotify (STATUS_INFO
*infoPtr
, UINT code
)
1221 TRACE("code %04x\n", code
);
1222 nmhdr
.hwndFrom
= infoPtr
->Self
;
1223 nmhdr
.idFrom
= GetWindowLongPtrW (infoPtr
->Self
, GWLP_ID
);
1225 SendMessageW (infoPtr
->Notify
, WM_NOTIFY
, 0, (LPARAM
)&nmhdr
);
1231 static LRESULT WINAPI
1232 StatusWindowProc (HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1234 STATUS_INFO
*infoPtr
= (STATUS_INFO
*)GetWindowLongPtrW (hwnd
, 0);
1235 INT nPart
= ((INT
) wParam
) & 0x00ff;
1238 TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hwnd
, msg
, wParam
, lParam
);
1239 if (!infoPtr
&& msg
!= WM_CREATE
)
1240 return DefWindowProcW (hwnd
, msg
, wParam
, lParam
);
1244 return STATUSBAR_GetBorders (infoPtr
, (INT
*)lParam
);
1247 return (LRESULT
)STATUSBAR_GetIcon (infoPtr
, nPart
);
1250 return STATUSBAR_GetParts (infoPtr
, (INT
)wParam
, (INT
*)lParam
);
1253 return STATUSBAR_GetRect (infoPtr
, nPart
, (LPRECT
)lParam
);
1256 return STATUSBAR_GetTextA (infoPtr
, nPart
, (LPSTR
)lParam
);
1259 return STATUSBAR_GetTextW (infoPtr
, nPart
, (LPWSTR
)lParam
);
1261 case SB_GETTEXTLENGTHA
:
1262 case SB_GETTEXTLENGTHW
:
1263 return STATUSBAR_GetTextLength (infoPtr
, nPart
);
1265 case SB_GETTIPTEXTA
:
1266 return STATUSBAR_GetTipTextA (infoPtr
, LOWORD(wParam
), (LPSTR
)lParam
, HIWORD(wParam
));
1268 case SB_GETTIPTEXTW
:
1269 return STATUSBAR_GetTipTextW (infoPtr
, LOWORD(wParam
), (LPWSTR
)lParam
, HIWORD(wParam
));
1271 case SB_GETUNICODEFORMAT
:
1272 return infoPtr
->bUnicode
;
1275 return infoPtr
->simple
;
1278 return STATUSBAR_SetBorders (infoPtr
, (INT
*)lParam
);
1281 return STATUSBAR_SetBkColor (infoPtr
, (COLORREF
)lParam
);
1284 return STATUSBAR_SetIcon (infoPtr
, nPart
, (HICON
)lParam
);
1286 case SB_SETMINHEIGHT
:
1287 return STATUSBAR_SetMinHeight (infoPtr
, (INT
)wParam
);
1290 return STATUSBAR_SetParts (infoPtr
, (INT
)wParam
, (LPINT
)lParam
);
1293 return STATUSBAR_SetTextT (infoPtr
, nPart
, wParam
& 0xff00, (LPCWSTR
)lParam
, FALSE
);
1296 return STATUSBAR_SetTextT (infoPtr
, nPart
, wParam
& 0xff00, (LPCWSTR
)lParam
, TRUE
);
1298 case SB_SETTIPTEXTA
:
1299 return STATUSBAR_SetTipTextA (infoPtr
, (INT
)wParam
, (LPSTR
)lParam
);
1301 case SB_SETTIPTEXTW
:
1302 return STATUSBAR_SetTipTextW (infoPtr
, (INT
)wParam
, (LPWSTR
)lParam
);
1304 case SB_SETUNICODEFORMAT
:
1305 return STATUSBAR_SetUnicodeFormat (infoPtr
, (BOOL
)wParam
);
1308 return STATUSBAR_Simple (infoPtr
, (BOOL
)wParam
);
1311 return STATUSBAR_WMCreate (hwnd
, (LPCREATESTRUCTA
)lParam
);
1314 return STATUSBAR_WMDestroy (infoPtr
);
1317 return (LRESULT
)(infoPtr
->hFont
? infoPtr
->hFont
: infoPtr
->hDefaultFont
);
1320 return STATUSBAR_WMGetText (infoPtr
, (INT
)wParam
, (LPWSTR
)lParam
);
1322 case WM_GETTEXTLENGTH
:
1323 return STATUSBAR_GetTextLength (infoPtr
, 0);
1325 case WM_LBUTTONDBLCLK
:
1326 return STATUSBAR_SendNotify (infoPtr
, NM_DBLCLK
);
1329 return STATUSBAR_SendNotify (infoPtr
, NM_CLICK
);
1332 return STATUSBAR_Relay2Tip (infoPtr
, msg
, wParam
, lParam
);
1335 res
= STATUSBAR_WMNCHitTest(infoPtr
, (short)LOWORD(lParam
),
1336 (short)HIWORD(lParam
));
1337 if (res
!= HTERROR
) return res
;
1338 return DefWindowProcW (hwnd
, msg
, wParam
, lParam
);
1340 case WM_NCLBUTTONUP
:
1341 case WM_NCLBUTTONDOWN
:
1342 PostMessageW (infoPtr
->Notify
, msg
, wParam
, lParam
);
1345 case WM_NOTIFYFORMAT
:
1346 return STATUSBAR_NotifyFormat(infoPtr
, (HWND
)wParam
, (INT
)lParam
);
1348 case WM_PRINTCLIENT
:
1350 return STATUSBAR_WMPaint (infoPtr
, (HDC
)wParam
);
1352 case WM_RBUTTONDBLCLK
:
1353 return STATUSBAR_SendNotify (infoPtr
, NM_RDBLCLK
);
1356 return STATUSBAR_SendNotify (infoPtr
, NM_RCLICK
);
1359 return STATUSBAR_WMSetFont (infoPtr
, (HFONT
)wParam
, LOWORD(lParam
));
1362 return STATUSBAR_WMSetText (infoPtr
, (LPCSTR
)lParam
);
1365 if (STATUSBAR_WMSize (infoPtr
, (WORD
)wParam
)) return 0;
1366 return DefWindowProcW (hwnd
, msg
, wParam
, lParam
);
1368 case WM_THEMECHANGED
:
1369 return theme_changed (infoPtr
);
1372 if ((msg
>= WM_USER
) && (msg
< WM_APP
))
1373 ERR("unknown msg %04x wp=%04x lp=%08lx\n",
1374 msg
, wParam
, lParam
);
1375 return DefWindowProcW (hwnd
, msg
, wParam
, lParam
);
1380 /***********************************************************************
1381 * STATUS_Register [Internal]
1383 * Registers the status window class.
1387 STATUS_Register (void)
1391 ZeroMemory (&wndClass
, sizeof(WNDCLASSW
));
1392 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
| CS_VREDRAW
;
1393 wndClass
.lpfnWndProc
= StatusWindowProc
;
1394 wndClass
.cbClsExtra
= 0;
1395 wndClass
.cbWndExtra
= sizeof(STATUS_INFO
*);
1396 wndClass
.hCursor
= LoadCursorW (0, (LPWSTR
)IDC_ARROW
);
1397 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
1398 wndClass
.lpszClassName
= STATUSCLASSNAMEW
;
1400 RegisterClassW (&wndClass
);
1404 /***********************************************************************
1405 * STATUS_Unregister [Internal]
1407 * Unregisters the status window class.
1411 STATUS_Unregister (void)
1413 UnregisterClassW (STATUSCLASSNAMEW
, NULL
);