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
23 * -- CCS_BOTTOM (default)
28 * -- CCS_NOPARENTALIGN
31 * -- CCS_VERT (defaults to RIGHT)
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(statusbar
);
65 UINT minHeight
; /* at least MIN_PANE_HEIGHT, can be increased by SB_SETMINHEIGHT */
70 COLORREF clrBk
; /* background color */
71 BOOL bUnicode
; /* notify format. TRUE if notifies in Unicode */
72 STATUSWINDOWPART part0
; /* simple window */
73 STATUSWINDOWPART
* parts
;
80 * Run tests using Waite Group Windows95 API Bible Vol. 1&2
81 * The second cdrom contains executables drawstat.exe, gettext.exe,
82 * simple.exe, getparts.exe, setparts.exe, statwnd.exe
89 static const WCHAR themeClass
[] = L
"Status";
93 STATUSBAR_SetPartBounds (STATUS_INFO
*infoPtr
);
95 STATUSBAR_NotifyFormat (STATUS_INFO
*infoPtr
, HWND from
, INT cmd
);
97 static inline LPCSTR
debugstr_t(LPCWSTR text
, BOOL isW
)
99 return isW
? debugstr_w(text
) : debugstr_a((LPCSTR
)text
);
103 STATUSBAR_ComputeHeight(STATUS_INFO
*infoPtr
)
109 COMCTL32_GetFontMetrics(infoPtr
->hFont
? infoPtr
->hFont
: infoPtr
->hDefaultFont
, &tm
);
110 margin
= (tm
.tmInternalLeading
? tm
.tmInternalLeading
: 2);
111 height
= max(tm
.tmHeight
+ margin
+ 2*GetSystemMetrics(SM_CYBORDER
), infoPtr
->minHeight
) + infoPtr
->verticalBorder
;
113 TRACE(" textHeight=%ld+%ld, final height=%d\n", tm
.tmHeight
, tm
.tmInternalLeading
, height
);
118 STATUSBAR_DrawSizeGrip (HTHEME theme
, HDC hdc
, LPRECT lpRect
)
122 TRACE("draw size grip %s\n", wine_dbgstr_rect(lpRect
));
127 if (SUCCEEDED (GetThemePartSize (theme
, hdc
, SP_GRIPPER
, 0, lpRect
,
128 TS_DRAW
, &gripperSize
)))
130 rc
.left
= rc
.right
- gripperSize
.cx
;
131 rc
.top
= rc
.bottom
- gripperSize
.cy
;
132 if (SUCCEEDED (DrawThemeBackground(theme
, hdc
, SP_GRIPPER
, 0, &rc
, NULL
)))
137 rc
.left
= max( rc
.left
, rc
.right
- GetSystemMetrics(SM_CXVSCROLL
) - 1 );
138 rc
.top
= max( rc
.top
, rc
.bottom
- GetSystemMetrics(SM_CYHSCROLL
) - 1 );
139 DrawFrameControl( hdc
, &rc
, DFC_SCROLL
, DFCS_SCROLLSIZEGRIP
);
143 STATUSBAR_DrawPart (const STATUS_INFO
*infoPtr
, HDC hdc
, const STATUSWINDOWPART
*part
, int itemID
)
145 RECT r
= part
->bound
;
147 HTHEME theme
= GetWindowTheme (infoPtr
->Self
);
148 int themePart
= SP_PANE
;
151 TRACE("part bound %s\n", wine_dbgstr_rect(&r
));
155 if ((GetWindowLongW (infoPtr
->Self
, GWL_STYLE
) & SBARS_SIZEGRIP
)
156 && (infoPtr
->simple
|| (itemID
== (infoPtr
->numParts
-1))))
157 themePart
= SP_GRIPPERPANE
;
158 DrawThemeBackground(theme
, hdc
, themePart
, 0, &r
, NULL
);
162 if (part
->style
& SBT_POPOUT
)
163 border
= BDR_RAISEDOUTER
;
164 else if (part
->style
& SBT_NOBORDERS
)
167 border
= BDR_SUNKENOUTER
;
168 DrawEdge(hdc
, &r
, border
, BF_RECT
|BF_ADJUST
);
172 INT cy
= r
.bottom
- r
.top
;
173 DrawIconEx (hdc
, r
.left
+ 2, r
.top
, part
->hIcon
, cy
, cy
, 0, 0, DI_NORMAL
);
177 if (part
->style
& SBT_OWNERDRAW
) {
180 dis
.CtlID
= GetWindowLongPtrW (infoPtr
->Self
, GWLP_ID
);
182 dis
.hwndItem
= infoPtr
->Self
;
185 dis
.itemData
= (ULONG_PTR
)part
->text
;
186 SendMessageW (infoPtr
->Notify
, WM_DRAWITEM
, dis
.CtlID
, (LPARAM
)&dis
);
189 COMCTL32_DrawStatusText(hdc
, &r
, part
->text
, 0, FALSE
);
195 STATUSBAR_RefreshPart (const STATUS_INFO
*infoPtr
, HDC hdc
, const STATUSWINDOWPART
*part
, int itemID
)
197 TRACE("item %d\n", itemID
);
199 if (part
->bound
.right
< part
->bound
.left
) return;
201 if (!RectVisible(hdc
, &part
->bound
))
204 STATUSBAR_DrawPart (infoPtr
, hdc
, part
, itemID
);
209 STATUSBAR_Refresh (STATUS_INFO
*infoPtr
, HDC hdc
)
217 if (!IsWindowVisible(infoPtr
->Self
))
220 STATUSBAR_SetPartBounds(infoPtr
);
222 GetClientRect (infoPtr
->Self
, &rect
);
224 if ((theme
= GetWindowTheme (infoPtr
->Self
)))
226 DrawThemeBackground(theme
, hdc
, 0, 0, &rect
, NULL
);
230 if (infoPtr
->clrBk
!= CLR_DEFAULT
)
231 hbrBk
= CreateSolidBrush (infoPtr
->clrBk
);
233 hbrBk
= GetSysColorBrush (COLOR_3DFACE
);
234 FillRect(hdc
, &rect
, hbrBk
);
235 if (infoPtr
->clrBk
!= CLR_DEFAULT
)
236 DeleteObject (hbrBk
);
239 hOldFont
= SelectObject (hdc
, infoPtr
->hFont
? infoPtr
->hFont
: infoPtr
->hDefaultFont
);
241 if (infoPtr
->simple
) {
242 STATUSBAR_RefreshPart (infoPtr
, hdc
, &infoPtr
->part0
, 0);
246 for (i
= 0; i
< infoPtr
->numParts
; i
++) {
247 STATUSBAR_RefreshPart (infoPtr
, hdc
, &infoPtr
->parts
[i
], i
);
251 SelectObject (hdc
, hOldFont
);
253 if ((GetWindowLongW (infoPtr
->Self
, GWL_STYLE
) & SBARS_SIZEGRIP
)
254 && !(GetWindowLongW (infoPtr
->Notify
, GWL_STYLE
) & WS_MAXIMIZE
))
255 STATUSBAR_DrawSizeGrip (theme
, hdc
, &rect
);
262 STATUSBAR_InternalHitTest(const STATUS_INFO
*infoPtr
, const POINT
*pt
)
269 for (i
= 0; i
< infoPtr
->numParts
; i
++)
270 if (pt
->x
>= infoPtr
->parts
[i
].bound
.left
&& pt
->x
<= infoPtr
->parts
[i
].bound
.right
)
277 STATUSBAR_SetPartBounds (STATUS_INFO
*infoPtr
)
279 STATUSWINDOWPART
*part
;
283 /* get our window size */
284 GetClientRect (infoPtr
->Self
, &rect
);
285 TRACE("client wnd size is %s\n", wine_dbgstr_rect(&rect
));
287 rect
.left
+= infoPtr
->horizontalBorder
;
288 rect
.top
+= infoPtr
->verticalBorder
;
290 /* set bounds for simple rectangle */
291 infoPtr
->part0
.bound
= rect
;
293 /* set bounds for non-simple rectangles */
294 for (i
= 0; i
< infoPtr
->numParts
; i
++) {
295 part
= &infoPtr
->parts
[i
];
296 r
= &infoPtr
->parts
[i
].bound
;
298 r
->bottom
= rect
.bottom
;
302 r
->left
= infoPtr
->parts
[i
-1].bound
.right
+ infoPtr
->horizontalGap
;
304 r
->right
= rect
.right
;
308 if (infoPtr
->hwndToolTip
) {
311 ti
.cbSize
= sizeof(TTTOOLINFOW
);
312 ti
.hwnd
= infoPtr
->Self
;
315 SendMessageW (infoPtr
->hwndToolTip
, TTM_NEWTOOLRECTW
,
323 STATUSBAR_Relay2Tip (const STATUS_INFO
*infoPtr
, UINT uMsg
,
324 WPARAM wParam
, LPARAM lParam
)
328 msg
.hwnd
= infoPtr
->Self
;
332 msg
.time
= GetMessageTime ();
333 msg
.pt
.x
= (short)LOWORD(GetMessagePos ());
334 msg
.pt
.y
= (short)HIWORD(GetMessagePos ());
336 return SendMessageW (infoPtr
->hwndToolTip
, TTM_RELAYEVENT
, 0, (LPARAM
)&msg
);
341 STATUSBAR_GetBorders (const STATUS_INFO
*infoPtr
, INT out
[])
344 out
[0] = infoPtr
->horizontalBorder
;
345 out
[1] = infoPtr
->verticalBorder
;
346 out
[2] = infoPtr
->horizontalGap
;
353 STATUSBAR_SetBorders (STATUS_INFO
*infoPtr
, const INT in
[])
356 infoPtr
->horizontalBorder
= in
[0];
357 infoPtr
->verticalBorder
= in
[1];
358 infoPtr
->horizontalGap
= in
[2];
359 InvalidateRect(infoPtr
->Self
, NULL
, FALSE
);
366 STATUSBAR_GetIcon (const STATUS_INFO
*infoPtr
, INT nPart
)
368 TRACE("%d\n", nPart
);
369 /* MSDN says: "simple parts are indexed with -1" */
370 if ((nPart
< -1) || (nPart
>= infoPtr
->numParts
))
374 return (infoPtr
->part0
.hIcon
);
376 return (infoPtr
->parts
[nPart
].hIcon
);
381 STATUSBAR_GetParts (const STATUS_INFO
*infoPtr
, INT num_parts
, INT parts
[])
385 TRACE("(%d)\n", num_parts
);
387 if (num_parts
> infoPtr
->numParts
)
388 num_parts
= infoPtr
->numParts
;
389 for (i
= 0; i
< num_parts
; i
++) {
390 parts
[i
] = infoPtr
->parts
[i
].x
;
393 return infoPtr
->numParts
;
398 STATUSBAR_GetRect (const STATUS_INFO
*infoPtr
, INT nPart
, LPRECT rect
)
400 TRACE("part %d\n", nPart
);
401 if(nPart
>= infoPtr
->numParts
|| nPart
< 0)
404 *rect
= infoPtr
->part0
.bound
;
406 *rect
= infoPtr
->parts
[nPart
].bound
;
412 STATUSBAR_GetTextA (STATUS_INFO
*infoPtr
, INT nPart
, LPSTR buf
)
414 STATUSWINDOWPART
*part
;
417 TRACE("part %d\n", nPart
);
419 /* MSDN says: "simple parts use index of 0", so this check is ok. */
420 if (nPart
< 0 || nPart
>= infoPtr
->numParts
) return 0;
423 part
= &infoPtr
->part0
;
425 part
= &infoPtr
->parts
[nPart
];
427 if (part
->style
& SBT_OWNERDRAW
)
428 result
= (LRESULT
)part
->text
;
430 DWORD len
= part
->text
? WideCharToMultiByte( CP_ACP
, 0, part
->text
, -1,
431 NULL
, 0, NULL
, NULL
) - 1 : 0;
432 result
= MAKELONG( len
, part
->style
);
433 if (part
->text
&& buf
)
434 WideCharToMultiByte( CP_ACP
, 0, part
->text
, -1, buf
, len
+1, NULL
, NULL
);
441 STATUSBAR_GetTextW (STATUS_INFO
*infoPtr
, INT nPart
, LPWSTR buf
)
443 STATUSWINDOWPART
*part
;
446 TRACE("part %d\n", nPart
);
447 if (nPart
< 0 || nPart
>= infoPtr
->numParts
) return 0;
450 part
= &infoPtr
->part0
;
452 part
= &infoPtr
->parts
[nPart
];
454 if (part
->style
& SBT_OWNERDRAW
)
455 result
= (LRESULT
)part
->text
;
457 result
= part
->text
? lstrlenW (part
->text
) : 0;
458 result
|= (part
->style
<< 16);
459 if (part
->text
&& buf
)
460 lstrcpyW (buf
, part
->text
);
467 STATUSBAR_GetTextLength (STATUS_INFO
*infoPtr
, INT nPart
)
469 STATUSWINDOWPART
*part
;
472 TRACE("part %d\n", nPart
);
474 /* MSDN says: "simple parts use index of 0", so this check is ok. */
475 if (nPart
< 0 || nPart
>= infoPtr
->numParts
) return 0;
478 part
= &infoPtr
->part0
;
480 part
= &infoPtr
->parts
[nPart
];
482 if ((~part
->style
& SBT_OWNERDRAW
) && part
->text
)
483 result
= lstrlenW(part
->text
);
487 result
|= (part
->style
<< 16);
492 STATUSBAR_GetTipTextA (const STATUS_INFO
*infoPtr
, INT id
, LPSTR tip
, INT size
)
496 CHAR buf
[INFOTIPSIZE
];
499 if (infoPtr
->hwndToolTip
) {
501 ti
.cbSize
= sizeof(TTTOOLINFOA
);
502 ti
.hwnd
= infoPtr
->Self
;
505 SendMessageA (infoPtr
->hwndToolTip
, TTM_GETTEXTA
, 0, (LPARAM
)&ti
);
507 lstrcpynA (tip
, buf
, size
);
514 STATUSBAR_GetTipTextW (const STATUS_INFO
*infoPtr
, INT id
, LPWSTR tip
, INT size
)
518 WCHAR buf
[INFOTIPSIZE
];
521 if (infoPtr
->hwndToolTip
) {
523 ti
.cbSize
= sizeof(TTTOOLINFOW
);
524 ti
.hwnd
= infoPtr
->Self
;
527 SendMessageW(infoPtr
->hwndToolTip
, TTM_GETTEXTW
, 0, (LPARAM
)&ti
);
529 lstrcpynW(tip
, buf
, size
);
537 STATUSBAR_SetBkColor (STATUS_INFO
*infoPtr
, COLORREF color
)
541 oldBkColor
= infoPtr
->clrBk
;
542 infoPtr
->clrBk
= color
;
543 InvalidateRect(infoPtr
->Self
, NULL
, FALSE
);
545 TRACE("CREF: %#lx -> %#lx\n", oldBkColor
, infoPtr
->clrBk
);
551 STATUSBAR_SetIcon (STATUS_INFO
*infoPtr
, INT nPart
, HICON hIcon
)
553 if ((nPart
< -1) || (nPart
>= infoPtr
->numParts
))
556 TRACE("setting part %d\n", nPart
);
558 /* FIXME: MSDN says "if nPart is -1, the status bar is assumed simple" */
560 if (infoPtr
->part0
.hIcon
== hIcon
) /* same as - no redraw */
562 infoPtr
->part0
.hIcon
= hIcon
;
564 InvalidateRect(infoPtr
->Self
, &infoPtr
->part0
.bound
, FALSE
);
566 if (infoPtr
->parts
[nPart
].hIcon
== hIcon
) /* same as - no redraw */
569 infoPtr
->parts
[nPart
].hIcon
= hIcon
;
570 if (!(infoPtr
->simple
))
571 InvalidateRect(infoPtr
->Self
, &infoPtr
->parts
[nPart
].bound
, FALSE
);
578 STATUSBAR_SetMinHeight (STATUS_INFO
*infoPtr
, INT height
)
580 DWORD ysize
= GetSystemMetrics(SM_CYSIZE
);
581 if (ysize
& 1) ysize
--;
582 infoPtr
->minHeight
= max(height
, ysize
);
583 infoPtr
->height
= STATUSBAR_ComputeHeight(infoPtr
);
584 /* like native, don't resize the control */
590 STATUSBAR_SetParts (STATUS_INFO
*infoPtr
, INT count
, LPINT parts
)
592 STATUSWINDOWPART
*tmp
;
595 TRACE("(%d,%p)\n", count
, parts
);
597 if(!count
) return FALSE
;
599 oldNumParts
= infoPtr
->numParts
;
600 infoPtr
->numParts
= count
;
601 if (oldNumParts
> infoPtr
->numParts
) {
602 for (i
= infoPtr
->numParts
; i
< oldNumParts
; i
++) {
603 if (!(infoPtr
->parts
[i
].style
& SBT_OWNERDRAW
))
604 Free (infoPtr
->parts
[i
].text
);
606 } else if (oldNumParts
< infoPtr
->numParts
) {
607 tmp
= Alloc (sizeof(STATUSWINDOWPART
) * infoPtr
->numParts
);
608 if (!tmp
) return FALSE
;
609 for (i
= 0; i
< oldNumParts
; i
++) {
610 tmp
[i
] = infoPtr
->parts
[i
];
612 Free (infoPtr
->parts
);
613 infoPtr
->parts
= tmp
;
615 if (oldNumParts
== infoPtr
->numParts
) {
616 for (i
=0; i
< oldNumParts
; i
++)
617 if (infoPtr
->parts
[i
].x
!= parts
[i
])
619 if (i
==oldNumParts
) /* Unchanged? no need to redraw! */
623 for (i
= 0; i
< infoPtr
->numParts
; i
++)
624 infoPtr
->parts
[i
].x
= parts
[i
];
626 if (infoPtr
->hwndToolTip
) {
629 WCHAR wEmpty
[] = L
"";
631 ZeroMemory (&ti
, sizeof(TTTOOLINFOW
));
632 ti
.cbSize
= sizeof(TTTOOLINFOW
);
633 ti
.hwnd
= infoPtr
->Self
;
634 ti
.lpszText
= wEmpty
;
636 nTipCount
= SendMessageW (infoPtr
->hwndToolTip
, TTM_GETTOOLCOUNT
, 0, 0);
637 if (nTipCount
< infoPtr
->numParts
) {
639 for (i
= nTipCount
; i
< infoPtr
->numParts
; i
++) {
640 TRACE("add tool %d\n", i
);
642 SendMessageW (infoPtr
->hwndToolTip
, TTM_ADDTOOLW
,
646 else if (nTipCount
> infoPtr
->numParts
) {
648 for (i
= nTipCount
- 1; i
>= infoPtr
->numParts
; i
--) {
649 TRACE("delete tool %d\n", i
);
651 SendMessageW (infoPtr
->hwndToolTip
, TTM_DELTOOLW
,
656 STATUSBAR_SetPartBounds (infoPtr
);
657 InvalidateRect(infoPtr
->Self
, NULL
, FALSE
);
663 STATUSBAR_SetTextT (STATUS_INFO
*infoPtr
, INT nPart
, WORD style
,
664 LPWSTR text
, BOOL isW
)
666 STATUSWINDOWPART
*part
=NULL
;
667 BOOL changed
= FALSE
;
670 if (style
& SBT_OWNERDRAW
) {
671 TRACE("part %d, text %p\n",nPart
,text
);
673 else TRACE("part %d, text %s\n", nPart
, debugstr_t(text
, isW
));
675 /* MSDN says: "If the parameter is set to SB_SIMPLEID (255), the status
676 * window is assumed to be a simple window */
678 if (nPart
== 0x00ff) {
679 part
= &infoPtr
->part0
;
681 if (infoPtr
->parts
&& nPart
>= 0 && nPart
< infoPtr
->numParts
) {
682 part
= &infoPtr
->parts
[nPart
];
685 if (!part
) return FALSE
;
687 if (part
->style
!= style
)
690 oldStyle
= part
->style
;
692 if (style
& SBT_OWNERDRAW
) {
693 if (!(oldStyle
& SBT_OWNERDRAW
))
701 LPCSTR atxt
= (LPCSTR
)text
;
702 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, atxt
, -1, NULL
, 0 );
703 ntext
= Alloc( (len
+ 1)*sizeof(WCHAR
) );
704 if (!ntext
) return FALSE
;
705 MultiByteToWideChar( CP_ACP
, 0, atxt
, -1, ntext
, len
);
707 ntext
= Alloc( (lstrlenW(text
) + 1)*sizeof(WCHAR
) );
708 if (!ntext
) return FALSE
;
709 lstrcpyW (ntext
, text
);
712 /* replace nonprintable characters with spaces */
716 if(*idx
< ' ' && *idx
!= '\t')
722 /* check if text is unchanged -> no need to redraw */
724 if (!changed
&& part
->text
&& !lstrcmpW(ntext
, part
->text
)) {
729 if (!changed
&& !part
->text
)
733 if (!(oldStyle
& SBT_OWNERDRAW
))
737 InvalidateRect(infoPtr
->Self
, &part
->bound
, FALSE
);
738 UpdateWindow(infoPtr
->Self
);
745 STATUSBAR_SetTipTextA (const STATUS_INFO
*infoPtr
, INT id
, LPSTR text
)
747 TRACE("part %d: \"%s\"\n", id
, text
);
748 if (infoPtr
->hwndToolTip
) {
750 ti
.cbSize
= sizeof(TTTOOLINFOA
);
751 ti
.hwnd
= infoPtr
->Self
;
755 SendMessageA (infoPtr
->hwndToolTip
, TTM_UPDATETIPTEXTA
, 0, (LPARAM
)&ti
);
763 STATUSBAR_SetTipTextW (const STATUS_INFO
*infoPtr
, INT id
, LPWSTR text
)
765 TRACE("part %d: \"%s\"\n", id
, debugstr_w(text
));
766 if (infoPtr
->hwndToolTip
) {
768 ti
.cbSize
= sizeof(TTTOOLINFOW
);
769 ti
.hwnd
= infoPtr
->Self
;
773 SendMessageW (infoPtr
->hwndToolTip
, TTM_UPDATETIPTEXTW
, 0, (LPARAM
)&ti
);
780 static inline LRESULT
781 STATUSBAR_SetUnicodeFormat (STATUS_INFO
*infoPtr
, BOOL bUnicode
)
783 BOOL bOld
= infoPtr
->bUnicode
;
785 TRACE("(0x%x)\n", bUnicode
);
786 infoPtr
->bUnicode
= bUnicode
;
793 STATUSBAR_Simple (STATUS_INFO
*infoPtr
, BOOL simple
)
797 TRACE("(simple=%d)\n", simple
);
798 if (infoPtr
->simple
== simple
) /* no need to change */
801 infoPtr
->simple
= simple
;
803 /* send notification */
804 nmhdr
.hwndFrom
= infoPtr
->Self
;
805 nmhdr
.idFrom
= GetWindowLongPtrW (infoPtr
->Self
, GWLP_ID
);
806 nmhdr
.code
= SBN_SIMPLEMODECHANGE
;
807 SendMessageW (infoPtr
->Notify
, WM_NOTIFY
, 0, (LPARAM
)&nmhdr
);
808 InvalidateRect(infoPtr
->Self
, NULL
, FALSE
);
814 STATUSBAR_WMDestroy (STATUS_INFO
*infoPtr
)
819 for (i
= 0; i
< infoPtr
->numParts
; i
++) {
820 if (!(infoPtr
->parts
[i
].style
& SBT_OWNERDRAW
))
821 Free (infoPtr
->parts
[i
].text
);
823 if (!(infoPtr
->part0
.style
& SBT_OWNERDRAW
))
824 Free (infoPtr
->part0
.text
);
825 Free (infoPtr
->parts
);
827 /* delete default font */
828 if (infoPtr
->hDefaultFont
)
829 DeleteObject (infoPtr
->hDefaultFont
);
831 /* delete tool tip control */
832 if (infoPtr
->hwndToolTip
)
833 DestroyWindow (infoPtr
->hwndToolTip
);
835 CloseThemeData (GetWindowTheme (infoPtr
->Self
));
837 SetWindowLongPtrW(infoPtr
->Self
, 0, 0);
844 STATUSBAR_WMCreate (HWND hwnd
, const CREATESTRUCTA
*lpCreate
)
846 STATUS_INFO
*infoPtr
;
847 NONCLIENTMETRICSW nclm
;
853 infoPtr
= Alloc (sizeof(STATUS_INFO
));
854 if (!infoPtr
) goto create_fail
;
855 SetWindowLongPtrW (hwnd
, 0, (DWORD_PTR
)infoPtr
);
857 infoPtr
->Self
= hwnd
;
858 infoPtr
->Notify
= lpCreate
->hwndParent
;
859 infoPtr
->numParts
= 1;
861 infoPtr
->simple
= FALSE
;
862 infoPtr
->clrBk
= CLR_DEFAULT
;
864 infoPtr
->horizontalBorder
= HORZ_BORDER
;
865 infoPtr
->verticalBorder
= VERT_BORDER
;
866 infoPtr
->horizontalGap
= HORZ_GAP
;
867 infoPtr
->minHeight
= GetSystemMetrics(SM_CYSIZE
);
868 if (infoPtr
->minHeight
& 1) infoPtr
->minHeight
--;
870 STATUSBAR_NotifyFormat(infoPtr
, infoPtr
->Notify
, NF_REQUERY
);
872 ZeroMemory (&nclm
, sizeof(nclm
));
873 nclm
.cbSize
= sizeof(nclm
);
874 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS
, nclm
.cbSize
, &nclm
, 0);
875 infoPtr
->hDefaultFont
= CreateFontIndirectW (&nclm
.lfStatusFont
);
877 GetClientRect (hwnd
, &rect
);
879 /* initialize simple case */
880 infoPtr
->part0
.bound
= rect
;
881 infoPtr
->part0
.text
= 0;
882 infoPtr
->part0
.x
= 0;
883 infoPtr
->part0
.style
= 0;
884 infoPtr
->part0
.hIcon
= 0;
886 /* initialize first part */
887 infoPtr
->parts
= Alloc (sizeof(STATUSWINDOWPART
));
888 if (!infoPtr
->parts
) goto create_fail
;
889 infoPtr
->parts
[0].bound
= rect
;
890 infoPtr
->parts
[0].text
= 0;
891 infoPtr
->parts
[0].x
= -1;
892 infoPtr
->parts
[0].style
= 0;
893 infoPtr
->parts
[0].hIcon
= 0;
895 OpenThemeData (hwnd
, themeClass
);
897 if (lpCreate
->lpszName
&& (len
= lstrlenW ((LPCWSTR
)lpCreate
->lpszName
)))
899 infoPtr
->parts
[0].text
= Alloc ((len
+ 1)*sizeof(WCHAR
));
900 if (!infoPtr
->parts
[0].text
) goto create_fail
;
901 lstrcpyW (infoPtr
->parts
[0].text
, (LPCWSTR
)lpCreate
->lpszName
);
904 dwStyle
= GetWindowLongW (hwnd
, GWL_STYLE
);
905 /* native seems to clear WS_BORDER, too */
906 dwStyle
&= ~WS_BORDER
;
907 SetWindowLongW (hwnd
, GWL_STYLE
, dwStyle
);
909 infoPtr
->height
= STATUSBAR_ComputeHeight(infoPtr
);
911 if (dwStyle
& SBT_TOOLTIPS
) {
912 infoPtr
->hwndToolTip
=
913 CreateWindowExW (0, TOOLTIPS_CLASSW
, NULL
, WS_POPUP
| TTS_ALWAYSTIP
,
914 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
915 CW_USEDEFAULT
, hwnd
, 0,
916 (HINSTANCE
)GetWindowLongPtrW(hwnd
, GWLP_HINSTANCE
), NULL
);
918 if (infoPtr
->hwndToolTip
) {
919 NMTOOLTIPSCREATED nmttc
;
921 nmttc
.hdr
.hwndFrom
= hwnd
;
922 nmttc
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
923 nmttc
.hdr
.code
= NM_TOOLTIPSCREATED
;
924 nmttc
.hwndToolTips
= infoPtr
->hwndToolTip
;
926 SendMessageW (lpCreate
->hwndParent
, WM_NOTIFY
, nmttc
.hdr
.idFrom
, (LPARAM
)&nmttc
);
934 if (infoPtr
) STATUSBAR_WMDestroy(infoPtr
);
939 /* in contrast to SB_GETTEXT*, WM_GETTEXT handles the text
940 * of the first part only (usual behaviour) */
942 STATUSBAR_WMGetText (const STATUS_INFO
*infoPtr
, INT size
, LPWSTR buf
)
947 if (!(infoPtr
->parts
[0].text
))
950 len
= lstrlenW (infoPtr
->parts
[0].text
);
954 else if (size
> len
) {
955 lstrcpyW (buf
, infoPtr
->parts
[0].text
);
959 memcpy (buf
, infoPtr
->parts
[0].text
, (size
- 1) * sizeof(WCHAR
));
967 STATUSBAR_WMNCHitTest (const STATUS_INFO
*infoPtr
, INT x
, INT y
)
969 if ((GetWindowLongW (infoPtr
->Self
, GWL_STYLE
) & SBARS_SIZEGRIP
)
970 && !(GetWindowLongW (infoPtr
->Notify
, GWL_STYLE
) & WS_MAXIMIZE
)) {
974 GetClientRect (infoPtr
->Self
, &rect
);
978 ScreenToClient (infoPtr
->Self
, &pt
);
980 if (pt
.x
>= rect
.right
- GetSystemMetrics(SM_CXVSCROLL
))
982 if (GetWindowLongW( infoPtr
->Self
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
) return HTBOTTOMLEFT
;
983 else return HTBOTTOMRIGHT
;
992 STATUSBAR_WMPaint (STATUS_INFO
*infoPtr
, HDC hdc
)
997 if (hdc
) return STATUSBAR_Refresh (infoPtr
, hdc
);
998 hdc
= BeginPaint (infoPtr
->Self
, &ps
);
999 STATUSBAR_Refresh (infoPtr
, hdc
);
1000 EndPaint (infoPtr
->Self
, &ps
);
1007 STATUSBAR_WMSetFont (STATUS_INFO
*infoPtr
, HFONT font
, BOOL redraw
)
1009 infoPtr
->hFont
= font
;
1010 TRACE("%p\n", infoPtr
->hFont
);
1012 infoPtr
->height
= STATUSBAR_ComputeHeight(infoPtr
);
1013 SendMessageW(infoPtr
->Self
, WM_SIZE
, 0, 0); /* update size */
1015 InvalidateRect(infoPtr
->Self
, NULL
, FALSE
);
1022 STATUSBAR_WMSetText (const STATUS_INFO
*infoPtr
, LPCSTR text
)
1024 STATUSWINDOWPART
*part
;
1028 if (infoPtr
->numParts
== 0)
1031 part
= &infoPtr
->parts
[0];
1032 /* duplicate string */
1036 if (text
&& (len
= lstrlenW((LPCWSTR
)text
))) {
1037 part
->text
= Alloc ((len
+1)*sizeof(WCHAR
));
1038 if (!part
->text
) return FALSE
;
1039 lstrcpyW (part
->text
, (LPCWSTR
)text
);
1042 InvalidateRect(infoPtr
->Self
, &part
->bound
, FALSE
);
1049 STATUSBAR_WMSize (STATUS_INFO
*infoPtr
, WORD flags
)
1054 /* Need to resize width to match parent */
1055 TRACE("flags %04x\n", flags
);
1057 if (flags
!= SIZE_RESTORED
&& flags
!= SIZE_MAXIMIZED
) {
1058 WARN("flags MUST be SIZE_RESTORED or SIZE_MAXIMIZED\n");
1062 if (GetWindowLongW(infoPtr
->Self
, GWL_STYLE
) & CCS_NORESIZE
) return FALSE
;
1064 /* width and height don't apply */
1065 if (!GetClientRect (infoPtr
->Notify
, &parent_rect
))
1068 width
= parent_rect
.right
- parent_rect
.left
;
1069 x
= parent_rect
.left
;
1070 y
= parent_rect
.bottom
- infoPtr
->height
;
1071 MoveWindow (infoPtr
->Self
, x
, y
, width
, infoPtr
->height
, TRUE
);
1072 STATUSBAR_SetPartBounds (infoPtr
);
1077 /* update theme after a WM_THEMECHANGED message */
1078 static LRESULT
theme_changed (const STATUS_INFO
* infoPtr
)
1080 HTHEME theme
= GetWindowTheme (infoPtr
->Self
);
1081 CloseThemeData (theme
);
1082 OpenThemeData (infoPtr
->Self
, themeClass
);
1083 InvalidateRect (infoPtr
->Self
, NULL
, TRUE
);
1089 STATUSBAR_NotifyFormat (STATUS_INFO
*infoPtr
, HWND from
, INT cmd
)
1091 if (cmd
== NF_REQUERY
) {
1092 INT i
= SendMessageW(from
, WM_NOTIFYFORMAT
, (WPARAM
)infoPtr
->Self
, NF_QUERY
);
1093 infoPtr
->bUnicode
= (i
== NFR_UNICODE
);
1095 return infoPtr
->bUnicode
? NFR_UNICODE
: NFR_ANSI
;
1100 STATUSBAR_SendMouseNotify(const STATUS_INFO
*infoPtr
, UINT code
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1104 TRACE("code %04x, lParam %Ix\n", code
, lParam
);
1105 nm
.hdr
.hwndFrom
= infoPtr
->Self
;
1106 nm
.hdr
.idFrom
= GetWindowLongPtrW(infoPtr
->Self
, GWLP_ID
);
1108 nm
.pt
.x
= (short)LOWORD(lParam
);
1109 nm
.pt
.y
= (short)HIWORD(lParam
);
1110 nm
.dwItemSpec
= STATUSBAR_InternalHitTest(infoPtr
, &nm
.pt
);
1112 nm
.dwHitInfo
= 0x30000; /* seems constant */
1114 /* Do default processing if WM_NOTIFY returns zero */
1115 if(!SendMessageW(infoPtr
->Notify
, WM_NOTIFY
, nm
.hdr
.idFrom
, (LPARAM
)&nm
))
1117 return DefWindowProcW(infoPtr
->Self
, msg
, wParam
, lParam
);
1124 static LRESULT WINAPI
1125 StatusWindowProc (HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1127 STATUS_INFO
*infoPtr
= (STATUS_INFO
*)GetWindowLongPtrW (hwnd
, 0);
1128 INT nPart
= ((INT
) wParam
) & 0x00ff;
1131 TRACE("hwnd %p, msg %x, wparam %Ix, lparam %Ix\n", hwnd
, msg
, wParam
, lParam
);
1133 if (!infoPtr
&& msg
!= WM_CREATE
)
1134 return DefWindowProcW (hwnd
, msg
, wParam
, lParam
);
1138 return STATUSBAR_GetBorders (infoPtr
, (INT
*)lParam
);
1141 return (LRESULT
)STATUSBAR_GetIcon (infoPtr
, nPart
);
1144 return STATUSBAR_GetParts (infoPtr
, (INT
)wParam
, (INT
*)lParam
);
1147 return STATUSBAR_GetRect (infoPtr
, nPart
, (LPRECT
)lParam
);
1150 return STATUSBAR_GetTextA (infoPtr
, nPart
, (LPSTR
)lParam
);
1153 return STATUSBAR_GetTextW (infoPtr
, nPart
, (LPWSTR
)lParam
);
1155 case SB_GETTEXTLENGTHA
:
1156 case SB_GETTEXTLENGTHW
:
1157 return STATUSBAR_GetTextLength (infoPtr
, nPart
);
1159 case SB_GETTIPTEXTA
:
1160 return STATUSBAR_GetTipTextA (infoPtr
, LOWORD(wParam
), (LPSTR
)lParam
, HIWORD(wParam
));
1162 case SB_GETTIPTEXTW
:
1163 return STATUSBAR_GetTipTextW (infoPtr
, LOWORD(wParam
), (LPWSTR
)lParam
, HIWORD(wParam
));
1165 case SB_GETUNICODEFORMAT
:
1166 return infoPtr
->bUnicode
;
1169 return infoPtr
->simple
;
1172 return STATUSBAR_SetBorders (infoPtr
, (INT
*)lParam
);
1175 return STATUSBAR_SetBkColor (infoPtr
, (COLORREF
)lParam
);
1178 return STATUSBAR_SetIcon (infoPtr
, nPart
, (HICON
)lParam
);
1180 case SB_SETMINHEIGHT
:
1181 return STATUSBAR_SetMinHeight (infoPtr
, (INT
)wParam
);
1184 return STATUSBAR_SetParts (infoPtr
, (INT
)wParam
, (LPINT
)lParam
);
1187 return STATUSBAR_SetTextT (infoPtr
, nPart
, wParam
& 0xff00, (LPWSTR
)lParam
, FALSE
);
1190 return STATUSBAR_SetTextT (infoPtr
, nPart
, wParam
& 0xff00, (LPWSTR
)lParam
, TRUE
);
1192 case SB_SETTIPTEXTA
:
1193 return STATUSBAR_SetTipTextA (infoPtr
, (INT
)wParam
, (LPSTR
)lParam
);
1195 case SB_SETTIPTEXTW
:
1196 return STATUSBAR_SetTipTextW (infoPtr
, (INT
)wParam
, (LPWSTR
)lParam
);
1198 case SB_SETUNICODEFORMAT
:
1199 return STATUSBAR_SetUnicodeFormat (infoPtr
, (BOOL
)wParam
);
1202 return STATUSBAR_Simple (infoPtr
, (BOOL
)wParam
);
1205 return STATUSBAR_WMCreate (hwnd
, (LPCREATESTRUCTA
)lParam
);
1208 return STATUSBAR_WMDestroy (infoPtr
);
1211 return (LRESULT
)(infoPtr
->hFont
? infoPtr
->hFont
: infoPtr
->hDefaultFont
);
1214 return STATUSBAR_WMGetText (infoPtr
, (INT
)wParam
, (LPWSTR
)lParam
);
1216 case WM_GETTEXTLENGTH
:
1217 return LOWORD(STATUSBAR_GetTextLength (infoPtr
, 0));
1219 case WM_LBUTTONDBLCLK
:
1220 return STATUSBAR_SendMouseNotify(infoPtr
, NM_DBLCLK
, msg
, wParam
, lParam
);
1223 return STATUSBAR_SendMouseNotify(infoPtr
, NM_CLICK
, msg
, wParam
, lParam
);
1226 return STATUSBAR_Relay2Tip (infoPtr
, msg
, wParam
, lParam
);
1229 res
= STATUSBAR_WMNCHitTest(infoPtr
, (short)LOWORD(lParam
),
1230 (short)HIWORD(lParam
));
1231 if (res
!= HTERROR
) return res
;
1232 return DefWindowProcW (hwnd
, msg
, wParam
, lParam
);
1234 case WM_NCLBUTTONUP
:
1235 case WM_NCLBUTTONDOWN
:
1236 PostMessageW (infoPtr
->Notify
, msg
, wParam
, lParam
);
1239 case WM_NOTIFYFORMAT
:
1240 return STATUSBAR_NotifyFormat(infoPtr
, (HWND
)wParam
, (INT
)lParam
);
1242 case WM_PRINTCLIENT
:
1244 return STATUSBAR_WMPaint (infoPtr
, (HDC
)wParam
);
1246 case WM_RBUTTONDBLCLK
:
1247 return STATUSBAR_SendMouseNotify(infoPtr
, NM_RDBLCLK
, msg
, wParam
, lParam
);
1250 return STATUSBAR_SendMouseNotify(infoPtr
, NM_RCLICK
, msg
, wParam
, lParam
);
1253 return STATUSBAR_WMSetFont (infoPtr
, (HFONT
)wParam
, LOWORD(lParam
));
1256 return STATUSBAR_WMSetText (infoPtr
, (LPCSTR
)lParam
);
1259 if (STATUSBAR_WMSize (infoPtr
, (WORD
)wParam
)) return 0;
1260 return DefWindowProcW (hwnd
, msg
, wParam
, lParam
);
1262 case WM_SYSCOLORCHANGE
:
1263 COMCTL32_RefreshSysColors();
1266 case WM_THEMECHANGED
:
1267 return theme_changed (infoPtr
);
1270 if ((msg
>= WM_USER
) && (msg
< WM_APP
) && !COMCTL32_IsReflectedMessage(msg
))
1271 ERR("unknown msg %04x wp=%Ix lp=%Ix\n", msg
, wParam
, lParam
);
1272 return DefWindowProcW (hwnd
, msg
, wParam
, lParam
);
1277 /***********************************************************************
1278 * STATUS_Register [Internal]
1280 * Registers the status window class.
1284 STATUS_Register (void)
1288 ZeroMemory (&wndClass
, sizeof(WNDCLASSW
));
1289 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
| CS_VREDRAW
;
1290 wndClass
.lpfnWndProc
= StatusWindowProc
;
1291 wndClass
.cbClsExtra
= 0;
1292 wndClass
.cbWndExtra
= sizeof(STATUS_INFO
*);
1293 wndClass
.hCursor
= LoadCursorW (0, (LPWSTR
)IDC_ARROW
);
1294 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
1295 wndClass
.lpszClassName
= STATUSCLASSNAMEW
;
1297 RegisterClassW (&wndClass
);
1301 /***********************************************************************
1302 * STATUS_Unregister [Internal]
1304 * Unregisters the status window class.
1308 STATUS_Unregister (void)
1310 UnregisterClassW (STATUSCLASSNAMEW
, NULL
);