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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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"
54 #include "wine/debug.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(statusbar
);
77 COLORREF clrBk
; /* background color */
78 BOOL bUnicode
; /* unicode flag */
79 BOOL NtfUnicode
; /* notify format */
80 STATUSWINDOWPART part0
; /* simple window */
81 STATUSWINDOWPART
* parts
;
85 * Run tests using Waite Group Windows95 API Bible Vol. 1&2
86 * The second cdrom contains executables drawstat.exe, gettext.exe,
87 * simple.exe, getparts.exe, setparts.exe, statwnd.exe
96 STATUSBAR_SetPartBounds (STATUS_INFO
*infoPtr
);
98 static inline LPCSTR
debugstr_t(LPCWSTR text
, BOOL isW
)
100 return isW
? debugstr_w(text
) : debugstr_a((LPCSTR
)text
);
104 STATUSBAR_DrawSizeGrip (HDC hdc
, LPRECT lpRect
)
106 HPEN hPenFace
, hPenShadow
, hPenHighlight
, hOldPen
;
110 TRACE("draw size grip %ld,%ld - %ld,%ld\n", lpRect
->left
, lpRect
->top
, lpRect
->right
, lpRect
->bottom
);
112 pt
.x
= lpRect
->right
- 1;
113 pt
.y
= lpRect
->bottom
- 1;
115 hPenFace
= CreatePen( PS_SOLID
, 1, GetSysColor( COLOR_3DFACE
));
116 hOldPen
= SelectObject( hdc
, hPenFace
);
117 MoveToEx (hdc
, pt
.x
- 12, pt
.y
, NULL
);
118 LineTo (hdc
, pt
.x
, pt
.y
);
119 LineTo (hdc
, pt
.x
, pt
.y
- 13);
124 hPenShadow
= CreatePen( PS_SOLID
, 1, GetSysColor( COLOR_3DSHADOW
));
125 SelectObject( hdc
, hPenShadow
);
126 for (i
= 1; i
< 11; i
+= 4) {
127 MoveToEx (hdc
, pt
.x
- i
, pt
.y
, NULL
);
128 LineTo (hdc
, pt
.x
+ 1, pt
.y
- i
- 1);
130 MoveToEx (hdc
, pt
.x
- i
- 1, pt
.y
, NULL
);
131 LineTo (hdc
, pt
.x
+ 1, pt
.y
- i
- 2);
134 hPenHighlight
= CreatePen( PS_SOLID
, 1, GetSysColor( COLOR_3DHIGHLIGHT
));
135 SelectObject( hdc
, hPenHighlight
);
136 for (i
= 3; i
< 13; i
+= 4) {
137 MoveToEx (hdc
, pt
.x
- i
, pt
.y
, NULL
);
138 LineTo (hdc
, pt
.x
+ 1, pt
.y
- i
- 1);
141 SelectObject (hdc
, hOldPen
);
142 DeleteObject( hPenFace
);
143 DeleteObject( hPenShadow
);
144 DeleteObject( hPenHighlight
);
149 STATUSBAR_DrawPart (STATUS_INFO
*infoPtr
, HDC hdc
, STATUSWINDOWPART
*part
, int itemID
)
151 RECT r
= part
->bound
;
152 UINT border
= BDR_SUNKENOUTER
;
154 TRACE("part bound %ld,%ld - %ld,%ld\n", r
.left
, r
.top
, r
.right
, r
.bottom
);
155 if (part
->style
& SBT_POPOUT
)
156 border
= BDR_RAISEDOUTER
;
157 else if (part
->style
& SBT_NOBORDERS
)
160 DrawEdge(hdc
, &r
, border
, BF_RECT
|BF_ADJUST
);
162 if (part
->style
& SBT_OWNERDRAW
)
166 dis
.CtlID
= GetWindowLongPtrW (infoPtr
->Self
, GWLP_ID
);
168 dis
.hwndItem
= infoPtr
->Self
;
171 dis
.itemData
= (INT
)part
->text
;
172 SendMessageW (infoPtr
->Notify
, WM_DRAWITEM
, (WPARAM
)dis
.CtlID
, (LPARAM
)&dis
);
178 INT cy
= r
.bottom
- r
.top
;
181 DrawIconEx (hdc
, r
.left
, r
.top
, part
->hIcon
, cy
, cy
, 0, 0, DI_NORMAL
);
184 DrawStatusTextW (hdc
, &r
, part
->text
, SBT_NOBORDERS
);
190 STATUSBAR_RefreshPart (STATUS_INFO
*infoPtr
, HDC hdc
, STATUSWINDOWPART
*part
, int itemID
)
195 TRACE("item %d\n", itemID
);
196 if (!IsWindowVisible (infoPtr
->Self
))
199 if (part
->bound
.right
< part
->bound
.left
) return;
201 if (infoPtr
->clrBk
!= CLR_DEFAULT
)
202 hbrBk
= CreateSolidBrush (infoPtr
->clrBk
);
204 hbrBk
= GetSysColorBrush (COLOR_3DFACE
);
205 FillRect(hdc
, &part
->bound
, hbrBk
);
207 hOldFont
= SelectObject (hdc
, infoPtr
->hFont
? infoPtr
->hFont
: infoPtr
->hDefaultFont
);
209 STATUSBAR_DrawPart (infoPtr
, hdc
, part
, itemID
);
211 SelectObject (hdc
, hOldFont
);
213 if (infoPtr
->clrBk
!= CLR_DEFAULT
)
214 DeleteObject (hbrBk
);
216 if (GetWindowLongW (infoPtr
->Self
, GWL_STYLE
) & SBARS_SIZEGRIP
)
220 GetClientRect (infoPtr
->Self
, &rect
);
221 STATUSBAR_DrawSizeGrip (hdc
, &rect
);
227 STATUSBAR_Refresh (STATUS_INFO
*infoPtr
, HDC hdc
)
235 if (!IsWindowVisible(infoPtr
->Self
))
238 STATUSBAR_SetPartBounds(infoPtr
);
240 GetClientRect (infoPtr
->Self
, &rect
);
242 if (infoPtr
->clrBk
!= CLR_DEFAULT
)
243 hbrBk
= CreateSolidBrush (infoPtr
->clrBk
);
245 hbrBk
= GetSysColorBrush (COLOR_3DFACE
);
246 FillRect(hdc
, &rect
, hbrBk
);
248 hOldFont
= SelectObject (hdc
, infoPtr
->hFont
? infoPtr
->hFont
: infoPtr
->hDefaultFont
);
250 if (infoPtr
->simple
) {
251 STATUSBAR_RefreshPart (infoPtr
, hdc
, &infoPtr
->part0
, 0);
253 for (i
= 0; i
< infoPtr
->numParts
; i
++) {
254 STATUSBAR_RefreshPart (infoPtr
, hdc
, &infoPtr
->parts
[i
], i
);
258 SelectObject (hdc
, hOldFont
);
260 if (infoPtr
->clrBk
!= CLR_DEFAULT
)
261 DeleteObject (hbrBk
);
263 if (GetWindowLongW (infoPtr
->Self
, GWL_STYLE
) & SBARS_SIZEGRIP
)
264 STATUSBAR_DrawSizeGrip (hdc
, &rect
);
271 STATUSBAR_SetPartBounds (STATUS_INFO
*infoPtr
)
273 STATUSWINDOWPART
*part
;
277 /* get our window size */
278 GetClientRect (infoPtr
->Self
, &rect
);
279 TRACE("client wnd size is %ld,%ld - %ld,%ld\n", rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
281 rect
.top
+= VERT_BORDER
;
283 /* set bounds for simple rectangle */
284 infoPtr
->part0
.bound
= rect
;
286 /* set bounds for non-simple rectangles */
287 for (i
= 0; i
< infoPtr
->numParts
; i
++) {
288 part
= &infoPtr
->parts
[i
];
289 r
= &infoPtr
->parts
[i
].bound
;
291 r
->bottom
= rect
.bottom
;
295 r
->left
= infoPtr
->parts
[i
-1].bound
.right
+ HORZ_GAP
;
297 r
->right
= rect
.right
;
301 if (infoPtr
->hwndToolTip
) {
304 ti
.cbSize
= sizeof(TTTOOLINFOW
);
305 ti
.hwnd
= infoPtr
->Self
;
308 SendMessageW (infoPtr
->hwndToolTip
, TTM_NEWTOOLRECTW
,
316 STATUSBAR_Relay2Tip (STATUS_INFO
*infoPtr
, UINT uMsg
,
317 WPARAM wParam
, LPARAM lParam
)
321 msg
.hwnd
= infoPtr
->Self
;
325 msg
.time
= GetMessageTime ();
326 msg
.pt
.x
= LOWORD(GetMessagePos ());
327 msg
.pt
.y
= HIWORD(GetMessagePos ());
329 return SendMessageW (infoPtr
->hwndToolTip
, TTM_RELAYEVENT
, 0, (LPARAM
)&msg
);
334 STATUSBAR_GetBorders (INT out
[])
337 out
[0] = HORZ_BORDER
; /* horizontal border width */
338 out
[1] = VERT_BORDER
; /* vertical border width */
339 out
[2] = HORZ_GAP
; /* width of border between rectangles */
346 STATUSBAR_GetIcon (STATUS_INFO
*infoPtr
, INT nPart
)
348 TRACE("%d\n", nPart
);
349 /* MSDN says: "simple parts are indexed with -1" */
350 if ((nPart
< -1) || (nPart
>= infoPtr
->numParts
))
354 return (infoPtr
->part0
.hIcon
);
356 return (infoPtr
->parts
[nPart
].hIcon
);
361 STATUSBAR_GetParts (STATUS_INFO
*infoPtr
, INT num_parts
, INT parts
[])
365 TRACE("(%d)\n", num_parts
);
367 for (i
= 0; i
< num_parts
; i
++) {
368 parts
[i
] = infoPtr
->parts
[i
].x
;
371 return infoPtr
->numParts
;
376 STATUSBAR_GetRect (STATUS_INFO
*infoPtr
, INT nPart
, LPRECT rect
)
378 TRACE("part %d\n", nPart
);
380 *rect
= infoPtr
->part0
.bound
;
382 *rect
= infoPtr
->parts
[nPart
].bound
;
388 STATUSBAR_GetTextA (STATUS_INFO
*infoPtr
, INT nPart
, LPSTR buf
)
390 STATUSWINDOWPART
*part
;
393 TRACE("part %d\n", nPart
);
395 /* MSDN says: "simple parts use index of 0", so this check is ok. */
396 if (nPart
< 0 || nPart
>= infoPtr
->numParts
) return 0;
399 part
= &infoPtr
->part0
;
401 part
= &infoPtr
->parts
[nPart
];
403 if (part
->style
& SBT_OWNERDRAW
)
404 result
= (LRESULT
)part
->text
;
406 DWORD len
= part
->text
? WideCharToMultiByte( CP_ACP
, 0, part
->text
, -1,
407 NULL
, 0, NULL
, NULL
) - 1 : 0;
408 result
= MAKELONG( len
, part
->style
);
409 if (part
->text
&& buf
)
410 WideCharToMultiByte( CP_ACP
, 0, part
->text
, -1, buf
, len
+1, NULL
, NULL
);
417 STATUSBAR_GetTextW (STATUS_INFO
*infoPtr
, INT nPart
, LPWSTR buf
)
419 STATUSWINDOWPART
*part
;
422 TRACE("part %d\n", nPart
);
423 if (nPart
< 0 || nPart
>= infoPtr
->numParts
) return 0;
426 part
= &infoPtr
->part0
;
428 part
= &infoPtr
->parts
[nPart
];
430 if (part
->style
& SBT_OWNERDRAW
)
431 result
= (LRESULT
)part
->text
;
433 result
= part
->text
? strlenW (part
->text
) : 0;
434 result
|= (part
->style
<< 16);
435 if (part
->text
&& buf
)
436 strcpyW (buf
, part
->text
);
443 STATUSBAR_GetTextLength (STATUS_INFO
*infoPtr
, INT nPart
)
445 STATUSWINDOWPART
*part
;
448 TRACE("part %d\n", nPart
);
450 /* MSDN says: "simple parts use index of 0", so this check is ok. */
451 if (nPart
< 0 || nPart
>= infoPtr
->numParts
) return 0;
454 part
= &infoPtr
->part0
;
456 part
= &infoPtr
->parts
[nPart
];
458 if ((~part
->style
& SBT_OWNERDRAW
) && part
->text
)
459 result
= strlenW(part
->text
);
463 result
|= (part
->style
<< 16);
468 STATUSBAR_GetTipTextA (STATUS_INFO
*infoPtr
, INT id
, LPSTR tip
, INT size
)
472 CHAR buf
[INFOTIPSIZE
];
475 if (infoPtr
->hwndToolTip
) {
477 ti
.cbSize
= sizeof(TTTOOLINFOA
);
478 ti
.hwnd
= infoPtr
->Self
;
481 SendMessageA (infoPtr
->hwndToolTip
, TTM_GETTEXTA
, 0, (LPARAM
)&ti
);
483 lstrcpynA (tip
, buf
, size
);
490 STATUSBAR_GetTipTextW (STATUS_INFO
*infoPtr
, INT id
, LPWSTR tip
, INT size
)
494 WCHAR buf
[INFOTIPSIZE
];
497 if (infoPtr
->hwndToolTip
) {
499 ti
.cbSize
= sizeof(TTTOOLINFOW
);
500 ti
.hwnd
= infoPtr
->Self
;
503 SendMessageW(infoPtr
->hwndToolTip
, TTM_GETTEXTW
, 0, (LPARAM
)&ti
);
505 lstrcpynW(tip
, buf
, size
);
513 STATUSBAR_SetBkColor (STATUS_INFO
*infoPtr
, COLORREF color
)
517 oldBkColor
= infoPtr
->clrBk
;
518 infoPtr
->clrBk
= color
;
519 InvalidateRect(infoPtr
->Self
, NULL
, FALSE
);
521 TRACE("CREF: %08lx -> %08lx\n", oldBkColor
, infoPtr
->clrBk
);
527 STATUSBAR_SetIcon (STATUS_INFO
*infoPtr
, INT nPart
, HICON hIcon
)
529 if ((nPart
< -1) || (nPart
>= infoPtr
->numParts
))
532 TRACE("setting part %d\n", nPart
);
534 /* FIXME: MSDN says "if nPart is -1, the status bar is assumed simple" */
536 if (infoPtr
->part0
.hIcon
== hIcon
) /* same as - no redraw */
538 infoPtr
->part0
.hIcon
= hIcon
;
540 InvalidateRect(infoPtr
->Self
, &infoPtr
->part0
.bound
, FALSE
);
542 if (infoPtr
->parts
[nPart
].hIcon
== hIcon
) /* same as - no redraw */
545 infoPtr
->parts
[nPart
].hIcon
= hIcon
;
546 if (!(infoPtr
->simple
))
547 InvalidateRect(infoPtr
->Self
, &infoPtr
->parts
[nPart
].bound
, FALSE
);
554 STATUSBAR_SetMinHeight (STATUS_INFO
*infoPtr
, INT height
)
557 TRACE("(height=%d)\n", height
);
558 if (IsWindowVisible (infoPtr
->Self
)) {
562 GetClientRect (infoPtr
->Notify
, &parent_rect
);
563 infoPtr
->height
= height
+ VERT_BORDER
;
564 width
= parent_rect
.right
- parent_rect
.left
;
565 x
= parent_rect
.left
;
566 y
= parent_rect
.bottom
- infoPtr
->height
;
567 MoveWindow (infoPtr
->Self
, parent_rect
.left
,
568 parent_rect
.bottom
- infoPtr
->height
,
569 width
, infoPtr
->height
, TRUE
);
570 STATUSBAR_SetPartBounds (infoPtr
);
578 STATUSBAR_SetParts (STATUS_INFO
*infoPtr
, INT count
, LPINT parts
)
580 STATUSWINDOWPART
*tmp
;
583 TRACE("(%d,%p)\n", count
, parts
);
585 oldNumParts
= infoPtr
->numParts
;
586 infoPtr
->numParts
= count
;
587 if (oldNumParts
> infoPtr
->numParts
) {
588 for (i
= infoPtr
->numParts
; i
< oldNumParts
; i
++) {
589 if (infoPtr
->parts
[i
].text
&& !(infoPtr
->parts
[i
].style
& SBT_OWNERDRAW
))
590 Free (infoPtr
->parts
[i
].text
);
592 } else if (oldNumParts
< infoPtr
->numParts
) {
593 tmp
= Alloc (sizeof(STATUSWINDOWPART
) * infoPtr
->numParts
);
594 if (!tmp
) return FALSE
;
595 for (i
= 0; i
< oldNumParts
; i
++) {
596 tmp
[i
] = infoPtr
->parts
[i
];
599 Free (infoPtr
->parts
);
600 infoPtr
->parts
= tmp
;
602 if (oldNumParts
== infoPtr
->numParts
) {
603 for (i
=0; i
< oldNumParts
; i
++)
604 if (infoPtr
->parts
[i
].x
!= parts
[i
])
606 if (i
==oldNumParts
) /* Unchanged? no need to redraw! */
610 for (i
= 0; i
< infoPtr
->numParts
; i
++)
611 infoPtr
->parts
[i
].x
= parts
[i
];
613 if (infoPtr
->hwndToolTip
) {
617 ZeroMemory (&ti
, sizeof(TTTOOLINFOW
));
618 ti
.cbSize
= sizeof(TTTOOLINFOW
);
619 ti
.hwnd
= infoPtr
->Self
;
621 nTipCount
= SendMessageW (infoPtr
->hwndToolTip
, TTM_GETTOOLCOUNT
, 0, 0);
622 if (nTipCount
< infoPtr
->numParts
) {
624 for (i
= nTipCount
; i
< infoPtr
->numParts
; i
++) {
625 TRACE("add tool %d\n", i
);
627 SendMessageW (infoPtr
->hwndToolTip
, TTM_ADDTOOLW
,
631 else if (nTipCount
> infoPtr
->numParts
) {
633 for (i
= nTipCount
- 1; i
>= infoPtr
->numParts
; i
--) {
634 TRACE("delete tool %d\n", i
);
636 SendMessageW (infoPtr
->hwndToolTip
, TTM_DELTOOLW
,
641 STATUSBAR_SetPartBounds (infoPtr
);
642 InvalidateRect(infoPtr
->Self
, NULL
, FALSE
);
648 STATUSBAR_SetTextT (STATUS_INFO
*infoPtr
, INT nPart
, WORD style
,
649 LPCWSTR text
, BOOL isW
)
651 STATUSWINDOWPART
*part
=NULL
;
652 BOOL changed
= FALSE
;
655 if (style
& SBT_OWNERDRAW
) {
656 TRACE("part %d, text %p\n",nPart
,text
);
658 else TRACE("part %d, text %s\n", nPart
, debugstr_t(text
, isW
));
660 /* MSDN says: "If the parameter is set to SB_SIMPLEID (255), the status
661 * window is assumed to be a simple window */
663 if (nPart
== 0x00ff) {
664 part
= &infoPtr
->part0
;
666 if (infoPtr
->parts
&& nPart
>= 0 && nPart
< infoPtr
->numParts
) {
667 part
= &infoPtr
->parts
[nPart
];
670 if (!part
) return FALSE
;
672 if (part
->style
!= style
)
675 oldStyle
= part
->style
;
677 if (style
& SBT_OWNERDRAW
) {
678 if (!(oldStyle
& SBT_OWNERDRAW
)) {
681 } else if (part
->text
== text
)
683 part
->text
= (LPWSTR
)text
;
688 LPCSTR atxt
= (LPCSTR
)text
;
689 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, atxt
, -1, NULL
, 0 );
690 ntext
= Alloc( (len
+ 1)*sizeof(WCHAR
) );
691 if (!ntext
) return FALSE
;
692 MultiByteToWideChar( CP_ACP
, 0, atxt
, -1, ntext
, len
);
694 ntext
= Alloc( (strlenW(text
) + 1)*sizeof(WCHAR
) );
695 if (!ntext
) return FALSE
;
696 strcpyW (ntext
, text
);
699 /* check if text is unchanged -> no need to redraw */
701 if (!changed
&& part
->text
&& !lstrcmpW(ntext
, part
->text
)) {
706 if (!changed
&& !part
->text
)
710 if (part
->text
&& !(oldStyle
& SBT_OWNERDRAW
))
714 InvalidateRect(infoPtr
->Self
, &part
->bound
, FALSE
);
721 STATUSBAR_SetTipTextA (STATUS_INFO
*infoPtr
, INT id
, LPSTR text
)
723 TRACE("part %d: \"%s\"\n", id
, text
);
724 if (infoPtr
->hwndToolTip
) {
726 ti
.cbSize
= sizeof(TTTOOLINFOA
);
727 ti
.hwnd
= infoPtr
->Self
;
731 SendMessageA (infoPtr
->hwndToolTip
, TTM_UPDATETIPTEXTA
,
740 STATUSBAR_SetTipTextW (STATUS_INFO
*infoPtr
, INT id
, LPWSTR text
)
742 TRACE("part %d: \"%s\"\n", id
, debugstr_w(text
));
743 if (infoPtr
->hwndToolTip
) {
745 ti
.cbSize
= sizeof(TTTOOLINFOW
);
746 ti
.hwnd
= infoPtr
->Self
;
750 SendMessageW (infoPtr
->hwndToolTip
, TTM_UPDATETIPTEXTW
,
758 inline static LRESULT
759 STATUSBAR_SetUnicodeFormat (STATUS_INFO
*infoPtr
, BOOL bUnicode
)
761 BOOL bOld
= infoPtr
->bUnicode
;
763 TRACE("(0x%x)\n", bUnicode
);
764 infoPtr
->bUnicode
= bUnicode
;
771 STATUSBAR_Simple (STATUS_INFO
*infoPtr
, BOOL simple
)
775 TRACE("(simple=%d)\n", simple
);
776 if (infoPtr
->simple
== simple
) /* no need to change */
779 infoPtr
->simple
= simple
;
781 /* send notification */
782 nmhdr
.hwndFrom
= infoPtr
->Self
;
783 nmhdr
.idFrom
= GetWindowLongPtrW (infoPtr
->Self
, GWLP_ID
);
784 nmhdr
.code
= SBN_SIMPLEMODECHANGE
;
785 SendMessageW (infoPtr
->Notify
, WM_NOTIFY
, 0, (LPARAM
)&nmhdr
);
786 InvalidateRect(infoPtr
->Self
, NULL
, FALSE
);
792 STATUSBAR_WMDestroy (STATUS_INFO
*infoPtr
)
797 for (i
= 0; i
< infoPtr
->numParts
; i
++) {
798 if (infoPtr
->parts
[i
].text
&& !(infoPtr
->parts
[i
].style
& SBT_OWNERDRAW
))
799 Free (infoPtr
->parts
[i
].text
);
801 if (infoPtr
->part0
.text
&& !(infoPtr
->part0
.style
& SBT_OWNERDRAW
))
802 Free (infoPtr
->part0
.text
);
803 Free (infoPtr
->parts
);
805 /* delete default font */
806 if (infoPtr
->hDefaultFont
)
807 DeleteObject (infoPtr
->hDefaultFont
);
809 /* delete tool tip control */
810 if (infoPtr
->hwndToolTip
)
811 DestroyWindow (infoPtr
->hwndToolTip
);
813 SetWindowLongPtrW(infoPtr
->Self
, 0, 0);
820 STATUSBAR_WMCreate (HWND hwnd
, LPCREATESTRUCTA lpCreate
)
822 STATUS_INFO
*infoPtr
;
823 NONCLIENTMETRICSW nclm
;
826 int i
, width
, len
, textHeight
= 0;
830 infoPtr
= (STATUS_INFO
*)Alloc (sizeof(STATUS_INFO
));
831 if (!infoPtr
) goto create_fail
;
832 SetWindowLongPtrW (hwnd
, 0, (DWORD_PTR
)infoPtr
);
834 infoPtr
->Self
= hwnd
;
835 infoPtr
->Notify
= lpCreate
->hwndParent
;
836 infoPtr
->numParts
= 1;
838 infoPtr
->simple
= FALSE
;
839 infoPtr
->clrBk
= CLR_DEFAULT
;
842 i
= SendMessageW(infoPtr
->Notify
, WM_NOTIFYFORMAT
, (WPARAM
)hwnd
, NF_QUERY
);
843 infoPtr
->NtfUnicode
= (i
== NFR_UNICODE
);
845 GetClientRect (hwnd
, &rect
);
846 InvalidateRect (hwnd
, &rect
, 0);
849 ZeroMemory (&nclm
, sizeof(nclm
));
850 nclm
.cbSize
= sizeof(nclm
);
851 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS
, nclm
.cbSize
, &nclm
, 0);
852 infoPtr
->hDefaultFont
= CreateFontIndirectW (&nclm
.lfStatusFont
);
854 /* initialize simple case */
855 infoPtr
->part0
.bound
= rect
;
856 infoPtr
->part0
.text
= 0;
857 infoPtr
->part0
.x
= 0;
858 infoPtr
->part0
.style
= 0;
859 infoPtr
->part0
.hIcon
= 0;
861 /* initialize first part */
862 infoPtr
->parts
= Alloc (sizeof(STATUSWINDOWPART
));
863 if (!infoPtr
->parts
) goto create_fail
;
864 infoPtr
->parts
[0].bound
= rect
;
865 infoPtr
->parts
[0].text
= 0;
866 infoPtr
->parts
[0].x
= -1;
867 infoPtr
->parts
[0].style
= 0;
868 infoPtr
->parts
[0].hIcon
= 0;
870 if (IsWindowUnicode (hwnd
)) {
871 infoPtr
->bUnicode
= TRUE
;
872 if (lpCreate
->lpszName
&&
873 (len
= strlenW ((LPCWSTR
)lpCreate
->lpszName
))) {
874 infoPtr
->parts
[0].text
= Alloc ((len
+ 1)*sizeof(WCHAR
));
875 if (!infoPtr
->parts
[0].text
) goto create_fail
;
876 strcpyW (infoPtr
->parts
[0].text
, (LPCWSTR
)lpCreate
->lpszName
);
880 if (lpCreate
->lpszName
&&
881 (len
= strlen((LPCSTR
)lpCreate
->lpszName
))) {
882 DWORD lenW
= MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)lpCreate
->lpszName
, -1, NULL
, 0 );
883 infoPtr
->parts
[0].text
= Alloc (lenW
*sizeof(WCHAR
));
884 if (!infoPtr
->parts
[0].text
) goto create_fail
;
885 MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)lpCreate
->lpszName
, -1,
886 infoPtr
->parts
[0].text
, lenW
);
890 dwStyle
= GetWindowLongW (hwnd
, GWL_STYLE
);
892 /* statusbars on managed windows should not have SIZEGRIP style */
893 if ((dwStyle
& SBARS_SIZEGRIP
) && lpCreate
->hwndParent
)
894 if (GetWindowLongW (lpCreate
->hwndParent
, GWL_EXSTYLE
) & WS_EX_MANAGED
)
895 SetWindowLongW (hwnd
, GWL_STYLE
, dwStyle
& ~SBARS_SIZEGRIP
);
897 if ((hdc
= GetDC (hwnd
))) {
901 hOldFont
= SelectObject (hdc
, infoPtr
->hDefaultFont
);
902 GetTextMetricsW (hdc
, &tm
);
903 textHeight
= tm
.tmHeight
;
904 SelectObject (hdc
, hOldFont
);
905 ReleaseDC (hwnd
, hdc
);
907 TRACE(" textHeight=%d\n", textHeight
);
909 if (dwStyle
& SBT_TOOLTIPS
) {
910 infoPtr
->hwndToolTip
=
911 CreateWindowExW (0, TOOLTIPS_CLASSW
, NULL
, 0,
912 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
913 CW_USEDEFAULT
, hwnd
, 0,
914 (HINSTANCE
)GetWindowLongPtrW(hwnd
, GWLP_HINSTANCE
), NULL
);
916 if (infoPtr
->hwndToolTip
) {
917 NMTOOLTIPSCREATED nmttc
;
919 nmttc
.hdr
.hwndFrom
= hwnd
;
920 nmttc
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
921 nmttc
.hdr
.code
= NM_TOOLTIPSCREATED
;
922 nmttc
.hwndToolTips
= infoPtr
->hwndToolTip
;
924 SendMessageW (lpCreate
->hwndParent
, WM_NOTIFY
,
925 (WPARAM
)nmttc
.hdr
.idFrom
, (LPARAM
)&nmttc
);
929 if (!(dwStyle
& CCS_NORESIZE
)) { /* don't resize wnd if it doesn't want it ! */
930 GetClientRect (infoPtr
->Notify
, &rect
);
931 width
= rect
.right
- rect
.left
;
932 infoPtr
->height
= textHeight
+ 4 + VERT_BORDER
;
933 SetWindowPos(hwnd
, 0, lpCreate
->x
, lpCreate
->y
- 1,
934 width
, infoPtr
->height
, SWP_NOZORDER
);
935 STATUSBAR_SetPartBounds (infoPtr
);
942 if (infoPtr
) STATUSBAR_WMDestroy(infoPtr
);
947 /* in contrast to SB_GETTEXT*, WM_GETTEXT handles the text
948 * of the first part only (usual behaviour) */
950 STATUSBAR_WMGetText (STATUS_INFO
*infoPtr
, INT size
, LPWSTR buf
)
955 if (!(infoPtr
->parts
[0].text
))
957 if (infoPtr
->bUnicode
)
958 len
= strlenW (infoPtr
->parts
[0].text
);
960 len
= WideCharToMultiByte( CP_ACP
, 0, infoPtr
->parts
[0].text
, -1, NULL
, 0, NULL
, NULL
)-1;
963 if (infoPtr
->bUnicode
)
964 strcpyW (buf
, infoPtr
->parts
[0].text
);
966 WideCharToMultiByte( CP_ACP
, 0, infoPtr
->parts
[0].text
, -1,
967 (LPSTR
)buf
, len
+1, NULL
, NULL
);
976 STATUSBAR_WMNCHitTest (STATUS_INFO
*infoPtr
, INT x
, INT y
)
978 if (GetWindowLongW (infoPtr
->Self
, GWL_STYLE
) & SBARS_SIZEGRIP
) {
982 GetClientRect (infoPtr
->Self
, &rect
);
986 ScreenToClient (infoPtr
->Self
, &pt
);
988 rect
.left
= rect
.right
- 13;
991 if (PtInRect (&rect
, pt
))
992 return HTBOTTOMRIGHT
;
1000 STATUSBAR_WMPaint (STATUS_INFO
*infoPtr
, HDC hdc
)
1005 if (hdc
) return STATUSBAR_Refresh (infoPtr
, hdc
);
1006 hdc
= BeginPaint (infoPtr
->Self
, &ps
);
1007 STATUSBAR_Refresh (infoPtr
, hdc
);
1008 EndPaint (infoPtr
->Self
, &ps
);
1015 STATUSBAR_WMSetFont (STATUS_INFO
*infoPtr
, HFONT font
, BOOL redraw
)
1017 infoPtr
->hFont
= font
;
1018 TRACE("%p\n", infoPtr
->hFont
);
1020 InvalidateRect(infoPtr
->Self
, NULL
, FALSE
);
1027 STATUSBAR_WMSetText (STATUS_INFO
*infoPtr
, LPCSTR text
)
1029 STATUSWINDOWPART
*part
;
1033 if (infoPtr
->numParts
== 0)
1036 part
= &infoPtr
->parts
[0];
1037 /* duplicate string */
1041 if (infoPtr
->bUnicode
) {
1042 if (text
&& (len
= strlenW((LPCWSTR
)text
))) {
1043 part
->text
= Alloc ((len
+1)*sizeof(WCHAR
));
1044 if (!part
->text
) return FALSE
;
1045 strcpyW (part
->text
, (LPCWSTR
)text
);
1049 if (text
&& (len
= lstrlenA(text
))) {
1050 DWORD lenW
= MultiByteToWideChar( CP_ACP
, 0, text
, -1, NULL
, 0 );
1051 part
->text
= Alloc (lenW
*sizeof(WCHAR
));
1052 if (!part
->text
) return FALSE
;
1053 MultiByteToWideChar( CP_ACP
, 0, text
, -1, part
->text
, lenW
);
1057 InvalidateRect(infoPtr
->Self
, &part
->bound
, FALSE
);
1064 STATUSBAR_WMSize (STATUS_INFO
*infoPtr
, WORD flags
)
1069 /* Need to resize width to match parent */
1070 TRACE("flags %04x\n", flags
);
1072 if (flags
!= SIZE_RESTORED
&& flags
!= SIZE_MAXIMIZED
)
1074 WARN("flags MUST be SIZE_RESTORED or SIZE_MAXIMIZED\n");
1078 if (GetWindowLongW(infoPtr
->Self
, GWL_STYLE
) & CCS_NORESIZE
) return FALSE
;
1080 /* width and height don't apply */
1081 GetClientRect (infoPtr
->Notify
, &parent_rect
);
1082 width
= parent_rect
.right
- parent_rect
.left
;
1083 x
= parent_rect
.left
;
1084 y
= parent_rect
.bottom
- infoPtr
->height
;
1085 MoveWindow (infoPtr
->Self
, parent_rect
.left
,
1086 parent_rect
.bottom
- infoPtr
->height
,
1087 width
, infoPtr
->height
, TRUE
);
1088 STATUSBAR_SetPartBounds (infoPtr
);
1094 STATUSBAR_NotifyFormat (STATUS_INFO
*infoPtr
, HWND from
, INT cmd
)
1096 if (cmd
== NF_REQUERY
) {
1097 INT i
= SendMessageW(from
, WM_NOTIFYFORMAT
, (WPARAM
)infoPtr
->Self
, NF_QUERY
);
1098 infoPtr
->NtfUnicode
= (i
== NFR_UNICODE
);
1100 return infoPtr
->NtfUnicode
? NFR_UNICODE
: NFR_ANSI
;
1105 STATUSBAR_SendNotify (STATUS_INFO
*infoPtr
, UINT code
)
1109 TRACE("code %04x\n", code
);
1110 nmhdr
.hwndFrom
= infoPtr
->Self
;
1111 nmhdr
.idFrom
= GetWindowLongPtrW (infoPtr
->Self
, GWLP_ID
);
1113 SendMessageW (infoPtr
->Notify
, WM_NOTIFY
, 0, (LPARAM
)&nmhdr
);
1119 static LRESULT WINAPI
1120 StatusWindowProc (HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1122 STATUS_INFO
*infoPtr
= (STATUS_INFO
*)GetWindowLongPtrW (hwnd
, 0);
1123 INT nPart
= ((INT
) wParam
) & 0x00ff;
1126 TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hwnd
, msg
, wParam
, lParam
);
1127 if (!infoPtr
&& msg
!= WM_CREATE
)
1128 return DefWindowProcW (hwnd
, msg
, wParam
, lParam
);
1132 return STATUSBAR_GetBorders ((INT
*)lParam
);
1135 return (LRESULT
)STATUSBAR_GetIcon (infoPtr
, nPart
);
1138 return STATUSBAR_GetParts (infoPtr
, (INT
)wParam
, (INT
*)lParam
);
1141 return STATUSBAR_GetRect (infoPtr
, nPart
, (LPRECT
)lParam
);
1144 return STATUSBAR_GetTextA (infoPtr
, nPart
, (LPSTR
)lParam
);
1147 return STATUSBAR_GetTextW (infoPtr
, nPart
, (LPWSTR
)lParam
);
1149 case SB_GETTEXTLENGTHA
:
1150 case SB_GETTEXTLENGTHW
:
1151 return STATUSBAR_GetTextLength (infoPtr
, nPart
);
1153 case SB_GETTIPTEXTA
:
1154 return STATUSBAR_GetTipTextA (infoPtr
, LOWORD(wParam
), (LPSTR
)lParam
, HIWORD(wParam
));
1156 case SB_GETTIPTEXTW
:
1157 return STATUSBAR_GetTipTextW (infoPtr
, LOWORD(wParam
), (LPWSTR
)lParam
, HIWORD(wParam
));
1159 case SB_GETUNICODEFORMAT
:
1160 return infoPtr
->bUnicode
;
1163 return infoPtr
->simple
;
1166 return STATUSBAR_SetBkColor (infoPtr
, (COLORREF
)lParam
);
1169 return STATUSBAR_SetIcon (infoPtr
, nPart
, (HICON
)lParam
);
1171 case SB_SETMINHEIGHT
:
1172 return STATUSBAR_SetMinHeight (infoPtr
, (INT
)wParam
);
1175 return STATUSBAR_SetParts (infoPtr
, (INT
)wParam
, (LPINT
)lParam
);
1178 return STATUSBAR_SetTextT (infoPtr
, nPart
, wParam
& 0xff00, (LPCWSTR
)lParam
, FALSE
);
1181 return STATUSBAR_SetTextT (infoPtr
, nPart
, wParam
& 0xff00, (LPCWSTR
)lParam
, TRUE
);
1183 case SB_SETTIPTEXTA
:
1184 return STATUSBAR_SetTipTextA (infoPtr
, (INT
)wParam
, (LPSTR
)lParam
);
1186 case SB_SETTIPTEXTW
:
1187 return STATUSBAR_SetTipTextW (infoPtr
, (INT
)wParam
, (LPWSTR
)lParam
);
1189 case SB_SETUNICODEFORMAT
:
1190 return STATUSBAR_SetUnicodeFormat (infoPtr
, (BOOL
)wParam
);
1193 return STATUSBAR_Simple (infoPtr
, (BOOL
)wParam
);
1196 return STATUSBAR_WMCreate (hwnd
, (LPCREATESTRUCTA
)lParam
);
1199 return STATUSBAR_WMDestroy (infoPtr
);
1202 return (LRESULT
)(infoPtr
->hFont
? infoPtr
->hFont
: infoPtr
->hDefaultFont
);
1205 return STATUSBAR_WMGetText (infoPtr
, (INT
)wParam
, (LPWSTR
)lParam
);
1207 case WM_GETTEXTLENGTH
:
1208 return STATUSBAR_GetTextLength (infoPtr
, 0);
1210 case WM_LBUTTONDBLCLK
:
1211 return STATUSBAR_SendNotify (infoPtr
, NM_DBLCLK
);
1214 return STATUSBAR_SendNotify (infoPtr
, NM_CLICK
);
1217 return STATUSBAR_Relay2Tip (infoPtr
, msg
, wParam
, lParam
);
1220 res
= STATUSBAR_WMNCHitTest(infoPtr
, (INT
)LOWORD(lParam
),
1221 (INT
)HIWORD(lParam
));
1222 if (res
!= HTERROR
) return res
;
1223 return DefWindowProcW (hwnd
, msg
, wParam
, lParam
);
1225 case WM_NCLBUTTONUP
:
1226 case WM_NCLBUTTONDOWN
:
1227 PostMessageW (infoPtr
->Notify
, msg
, wParam
, lParam
);
1230 case WM_NOTIFYFORMAT
:
1231 return STATUSBAR_NotifyFormat(infoPtr
, (HWND
)wParam
, (INT
)lParam
);
1234 return STATUSBAR_WMPaint (infoPtr
, (HDC
)wParam
);
1236 case WM_RBUTTONDBLCLK
:
1237 return STATUSBAR_SendNotify (infoPtr
, NM_RDBLCLK
);
1240 return STATUSBAR_SendNotify (infoPtr
, NM_RCLICK
);
1243 return STATUSBAR_WMSetFont (infoPtr
, (HFONT
)wParam
, LOWORD(lParam
));
1246 return STATUSBAR_WMSetText (infoPtr
, (LPCSTR
)lParam
);
1249 if (STATUSBAR_WMSize (infoPtr
, (WORD
)wParam
)) return 0;
1250 return DefWindowProcW (hwnd
, msg
, wParam
, lParam
);
1253 if ((msg
>= WM_USER
) && (msg
< WM_APP
))
1254 ERR("unknown msg %04x wp=%04x lp=%08lx\n",
1255 msg
, wParam
, lParam
);
1256 return DefWindowProcW (hwnd
, msg
, wParam
, lParam
);
1261 /***********************************************************************
1262 * STATUS_Register [Internal]
1264 * Registers the status window class.
1268 STATUS_Register (void)
1272 ZeroMemory (&wndClass
, sizeof(WNDCLASSW
));
1273 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
| CS_VREDRAW
;
1274 wndClass
.lpfnWndProc
= StatusWindowProc
;
1275 wndClass
.cbClsExtra
= 0;
1276 wndClass
.cbWndExtra
= sizeof(STATUS_INFO
*);
1277 wndClass
.hCursor
= LoadCursorW (0, (LPWSTR
)IDC_ARROW
);
1278 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
1279 wndClass
.lpszClassName
= STATUSCLASSNAMEW
;
1281 RegisterClassW (&wndClass
);
1285 /***********************************************************************
1286 * STATUS_Unregister [Internal]
1288 * Unregisters the status window class.
1292 STATUS_Unregister (void)
1294 UnregisterClassW (STATUSCLASSNAMEW
, NULL
);