1 /* 2 * Interface code to StatusWindow widget/control 3 * 4 * Copyright 1996 Bruce Milner 5 * Copyright 1998, 1999 Eric Kohl 6 * Copyright 2002 Dimitrie O. Paun 7 * 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. 12 * 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. 17 * 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 21 * 22 * NOTE 23 * 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. 26 * 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. 30 * 31 * TODO: 32 * -- CCS_BOTTOM (default) 33 * -- CCS_LEFT 34 * -- CCS_NODIVIDER 35 * -- CCS_NOMOVEX 36 * -- CCS_NOMOVEY 37 * -- CCS_NOPARENTALIGN 38 * -- CCS_RIGHT 39 * -- CCS_TOP 40 * -- CCS_VERT (defaults to RIGHT) 41 */ 42 43 #include <stdarg.h> 44 #include <string.h> 45 46 #include "windef.h" 47 #include "winbase.h" 48 #include "wine/unicode.h" 49 #include "wingdi.h" 50 #include "winuser.h" 51 #include "winnls.h" 52 #include "commctrl.h" 53 #include "comctl32.h" 54 #include "uxtheme.h" 55 #include "tmschema.h" 56 #include "wine/debug.h" 57 58 WINE_DEFAULT_DEBUG_CHANNEL(statusbar); 59 60 typedef struct 61 { 62 INT x; 63 INT style; 64 RECT bound; 65 LPWSTR text; 66 HICON hIcon; 67 } STATUSWINDOWPART; 68 69 typedef struct 70 { 71 HWND Self; 72 HWND Notify; 73 WORD numParts; 74 UINT height; 75 UINT minHeight; /* at least MIN_PANE_HEIGHT, can be increased by SB_SETMINHEIGHT */ 76 BOOL simple; 77 HWND hwndToolTip; 78 HFONT hFont; 79 HFONT hDefaultFont; 80 COLORREF clrBk; /* background color */ 81 BOOL bUnicode; /* notify format. TRUE if notifies in Unicode */ 82 STATUSWINDOWPART part0; /* simple window */ 83 STATUSWINDOWPART* parts; 84 INT horizontalBorder; 85 INT verticalBorder; 86 INT horizontalGap; 87 } STATUS_INFO; 88 89 /* 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 93 */ 94 95 #define HORZ_BORDER 0 96 #define VERT_BORDER 2 97 #define HORZ_GAP 2 98 99 static const WCHAR themeClass[] = { 'S','t','a','t','u','s',0 }; 100 101 /* prototype */ 102 static void 103 STATUSBAR_SetPartBounds (STATUS_INFO *infoPtr); 104 static LRESULT 105 STATUSBAR_NotifyFormat (STATUS_INFO *infoPtr, HWND from, INT cmd); 106 107 static inline LPCSTR debugstr_t(LPCWSTR text, BOOL isW) 108 { 109 return isW ? debugstr_w(text) : debugstr_a((LPCSTR)text); 110 } 111 112 static UINT 113 STATUSBAR_ComputeHeight(STATUS_INFO *infoPtr) 114 { 115 HTHEME theme; 116 UINT height; 117 TEXTMETRICW tm; 118 int margin; 119 120 COMCTL32_GetFontMetrics(infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont, &tm); 121 margin = (tm.tmInternalLeading ? tm.tmInternalLeading : 2); 122 height = max(tm.tmHeight + margin + 2*GetSystemMetrics(SM_CYBORDER), infoPtr->minHeight) + infoPtr->verticalBorder; 123 124 if ((theme = GetWindowTheme(infoPtr->Self))) 125 { 126 /* Determine bar height from theme such that the content area is 127 * textHeight pixels large */ 128 HDC hdc = GetDC(infoPtr->Self); 129 RECT r; 130 memset (&r, 0, sizeof (r)); 131 r.bottom = max(infoPtr->minHeight, tm.tmHeight); 132 if (SUCCEEDED(GetThemeBackgroundExtent(theme, hdc, SP_PANE, 0, &r, &r))) 133 { 134 height = r.bottom - r.top; 135 } 136 ReleaseDC(infoPtr->Self, hdc); 137 } 138 139 TRACE(" textHeight=%d+%d, final height=%d\n", tm.tmHeight, tm.tmInternalLeading, height); 140 return height; 141 } 142 143 static void 144 STATUSBAR_DrawSizeGrip (HTHEME theme, HDC hdc, LPRECT lpRect) 145 { 146 HPEN hPenFace, hPenShadow, hPenHighlight, hOldPen; 147 POINT pt; 148 INT i; 149 150 TRACE("draw size grip %s\n", wine_dbgstr_rect(lpRect)); 151 152 if (theme) 153 { 154 RECT gripperRect; 155 SIZE gripperSize; 156 gripperRect = *lpRect; 157 if (SUCCEEDED (GetThemePartSize (theme, hdc, SP_GRIPPER, 0, lpRect, 158 TS_DRAW, &gripperSize))) 159 { 160 gripperRect.left = gripperRect.right - gripperSize.cx; 161 gripperRect.top = gripperRect.bottom - gripperSize.cy; 162 if (SUCCEEDED (DrawThemeBackground(theme, hdc, SP_GRIPPER, 0, &gripperRect, NULL))) 163 return; 164 } 165 } 166 167 pt.x = lpRect->right - 1; 168 pt.y = lpRect->bottom - 1; 169 170 hPenFace = CreatePen( PS_SOLID, 1, comctl32_color.clr3dFace); 171 hOldPen = SelectObject( hdc, hPenFace ); 172 MoveToEx (hdc, pt.x - 12, pt.y, NULL); 173 LineTo (hdc, pt.x, pt.y); 174 LineTo (hdc, pt.x, pt.y - 13); 175 176 pt.x--; 177 pt.y--; 178 179 hPenShadow = CreatePen( PS_SOLID, 1, comctl32_color.clr3dShadow); 180 SelectObject( hdc, hPenShadow ); 181 for (i = 1; i < 11; i += 4) { 182 MoveToEx (hdc, pt.x - i, pt.y, NULL); 183 LineTo (hdc, pt.x + 1, pt.y - i - 1); 184 185 MoveToEx (hdc, pt.x - i - 1, pt.y, NULL); 186 LineTo (hdc, pt.x + 1, pt.y - i - 2); 187 } 188 189 hPenHighlight = CreatePen( PS_SOLID, 1, comctl32_color.clr3dHilight); 190 SelectObject( hdc, hPenHighlight ); 191 for (i = 3; i < 13; i += 4) { 192 MoveToEx (hdc, pt.x - i, pt.y, NULL); 193 LineTo (hdc, pt.x + 1, pt.y - i - 1); 194 } 195 196 SelectObject (hdc, hOldPen); 197 DeleteObject( hPenFace ); 198 DeleteObject( hPenShadow ); 199 DeleteObject( hPenHighlight ); 200 } 201 202 203 static void 204 STATUSBAR_DrawPart (const STATUS_INFO *infoPtr, HDC hdc, const STATUSWINDOWPART *part, int itemID) 205 { 206 RECT r = part->bound; 207 UINT border = BDR_SUNKENOUTER; 208 HTHEME theme = GetWindowTheme (infoPtr->Self); 209 int themePart = SP_PANE; 210 211 TRACE("part bound %s\n", wine_dbgstr_rect(&r)); 212 if (part->style & SBT_POPOUT) 213 border = BDR_RAISEDOUTER; 214 else if (part->style & SBT_NOBORDERS) 215 border = 0; 216 217 if (theme) 218 { 219 if ((GetWindowLongW (infoPtr->Self, GWL_STYLE) & SBARS_SIZEGRIP) 220 && (infoPtr->simple || (itemID == (infoPtr->numParts-1)))) 221 themePart = SP_GRIPPERPANE; 222 DrawThemeBackground(theme, hdc, themePart, 0, &r, NULL); 223 } 224 else 225 DrawEdge(hdc, &r, border, BF_RECT|BF_ADJUST); 226 227 if (part->style & SBT_OWNERDRAW) { 228 DRAWITEMSTRUCT dis; 229 230 dis.CtlID = GetWindowLongPtrW (infoPtr->Self, GWLP_ID); 231 dis.itemID = itemID; 232 dis.hwndItem = infoPtr->Self; 233 dis.hDC = hdc; 234 dis.rcItem = r; 235 dis.itemData = (ULONG_PTR)part->text; 236 SendMessageW (infoPtr->Notify, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis); 237 } else { 238 if (part->hIcon) { 239 INT cy = r.bottom - r.top; 240 241 r.left += 2; 242 DrawIconEx (hdc, r.left, r.top, part->hIcon, cy, cy, 0, 0, DI_NORMAL); 243 r.left += cy; 244 } 245 DrawStatusTextW (hdc, &r, part->text, SBT_NOBORDERS); 246 } 247 } 248 249 250 static void 251 STATUSBAR_RefreshPart (const STATUS_INFO *infoPtr, HDC hdc, const STATUSWINDOWPART *part, int itemID) 252 { 253 HBRUSH hbrBk; 254 HTHEME theme; 255 256 TRACE("item %d\n", itemID); 257 258 if (part->bound.right < part->bound.left) return; 259 260 if (!RectVisible(hdc, &part->bound)) 261 return; 262 263 if ((theme = GetWindowTheme (infoPtr->Self))) 264 { 265 RECT cr; 266 GetClientRect (infoPtr->Self, &cr); 267 DrawThemeBackground(theme, hdc, 0, 0, &cr, &part->bound); 268 } 269 else 270 { 271 if (infoPtr->clrBk != CLR_DEFAULT) 272 hbrBk = CreateSolidBrush (infoPtr->clrBk); 273 else 274 hbrBk = GetSysColorBrush (COLOR_3DFACE); 275 FillRect(hdc, &part->bound, hbrBk); 276 if (infoPtr->clrBk != CLR_DEFAULT) 277 DeleteObject (hbrBk); 278 } 279 280 STATUSBAR_DrawPart (infoPtr, hdc, part, itemID); 281 } 282 283 284 static LRESULT 285 STATUSBAR_Refresh (STATUS_INFO *infoPtr, HDC hdc) 286 { 287 int i; 288 RECT rect; 289 HBRUSH hbrBk; 290 HFONT hOldFont; 291 HTHEME theme; 292 293 TRACE("\n"); 294 if (!IsWindowVisible(infoPtr->Self)) 295 return 0; 296 297 STATUSBAR_SetPartBounds(infoPtr); 298 299 GetClientRect (infoPtr->Self, &rect); 300 301 if ((theme = GetWindowTheme (infoPtr->Self))) 302 { 303 DrawThemeBackground(theme, hdc, 0, 0, &rect, NULL); 304 } 305 else 306 { 307 if (infoPtr->clrBk != CLR_DEFAULT) 308 hbrBk = CreateSolidBrush (infoPtr->clrBk); 309 else 310 hbrBk = GetSysColorBrush (COLOR_3DFACE); 311 FillRect(hdc, &rect, hbrBk); 312 if (infoPtr->clrBk != CLR_DEFAULT) 313 DeleteObject (hbrBk); 314 } 315 316 hOldFont = SelectObject (hdc, infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont); 317 318 if (infoPtr->simple) { 319 STATUSBAR_RefreshPart (infoPtr, hdc, &infoPtr->part0, 0); 320 } else { 321 for (i = 0; i < infoPtr->numParts; i++) { 322 STATUSBAR_RefreshPart (infoPtr, hdc, &infoPtr->parts[i], i); 323 } 324 } 325 326 SelectObject (hdc, hOldFont); 327 328 if (GetWindowLongW (infoPtr->Self, GWL_STYLE) & SBARS_SIZEGRIP) 329 STATUSBAR_DrawSizeGrip (theme, hdc, &rect); 330 331 return 0; 332 } 333 334 335 static int 336 STATUSBAR_InternalHitTest(const STATUS_INFO *infoPtr, const POINT *pt) 337 { 338 int i; 339 if (infoPtr->simple) 340 return 255; 341 342 for (i = 0; i < infoPtr->numParts; i++) 343 if (pt->x >= infoPtr->parts[i].bound.left && pt->x <= infoPtr->parts[i].bound.right) 344 return i; 345 return -2; 346 } 347 348 349 static void 350 STATUSBAR_SetPartBounds (STATUS_INFO *infoPtr) 351 { 352 STATUSWINDOWPART *part; 353 RECT rect, *r; 354 int i; 355 356 /* get our window size */ 357 GetClientRect (infoPtr->Self, &rect); 358 TRACE("client wnd size is %s\n", wine_dbgstr_rect(&rect)); 359 360 rect.left += infoPtr->horizontalBorder; 361 rect.top += infoPtr->verticalBorder; 362 363 /* set bounds for simple rectangle */ 364 infoPtr->part0.bound = rect; 365 366 /* set bounds for non-simple rectangles */ 367 for (i = 0; i < infoPtr->numParts; i++) { 368 part = &infoPtr->parts[i]; 369 r = &infoPtr->parts[i].bound; 370 r->top = rect.top; 371 r->bottom = rect.bottom; 372 if (i == 0) 373 r->left = 0; 374 else 375 r->left = infoPtr->parts[i-1].bound.right + infoPtr->horizontalGap; 376 if (part->x == -1) 377 r->right = rect.right; 378 else 379 r->right = part->x; 380 381 if (infoPtr->hwndToolTip) { 382 TTTOOLINFOW ti; 383 384 ti.cbSize = sizeof(TTTOOLINFOW); 385 ti.hwnd = infoPtr->Self; 386 ti.uId = i; 387 ti.rect = *r; 388 SendMessageW (infoPtr->hwndToolTip, TTM_NEWTOOLRECTW, 389 0, (LPARAM)&ti); 390 } 391 } 392 } 393 394 395 static LRESULT 396 STATUSBAR_Relay2Tip (const STATUS_INFO *infoPtr, UINT uMsg, 397 WPARAM wParam, LPARAM lParam) 398 { 399 MSG msg; 400 401 msg.hwnd = infoPtr->Self; 402 msg.message = uMsg; 403 msg.wParam = wParam; 404 msg.lParam = lParam; 405 msg.time = GetMessageTime (); 406 msg.pt.x = (short)LOWORD(GetMessagePos ()); 407 msg.pt.y = (short)HIWORD(GetMessagePos ()); 408 409 return SendMessageW (infoPtr->hwndToolTip, TTM_RELAYEVENT, 0, (LPARAM)&msg); 410 } 411 412 413 static BOOL 414 STATUSBAR_GetBorders (const STATUS_INFO *infoPtr, INT out[]) 415 { 416 TRACE("\n"); 417 out[0] = infoPtr->horizontalBorder; 418 out[1] = infoPtr->verticalBorder; 419 out[2] = infoPtr->horizontalGap; 420 421 return TRUE; 422 } 423 424 425 static BOOL 426 STATUSBAR_SetBorders (STATUS_INFO *infoPtr, const INT in[]) 427 { 428 TRACE("\n"); 429 infoPtr->horizontalBorder = in[0]; 430 infoPtr->verticalBorder = in[1]; 431 infoPtr->horizontalGap = in[2]; 432 InvalidateRect(infoPtr->Self, NULL, FALSE); 433 434 return TRUE; 435 } 436 437 438 static HICON 439 STATUSBAR_GetIcon (const STATUS_INFO *infoPtr, INT nPart) 440 { 441 TRACE("%d\n", nPart); 442 /* MSDN says: "simple parts are indexed with -1" */ 443 if ((nPart < -1) || (nPart >= infoPtr->numParts)) 444 return 0; 445 446 if (nPart == -1) 447 return (infoPtr->part0.hIcon); 448 else 449 return (infoPtr->parts[nPart].hIcon); 450 } 451 452 453 static INT 454 STATUSBAR_GetParts (const STATUS_INFO *infoPtr, INT num_parts, INT parts[]) 455 { 456 INT i; 457 458 TRACE("(%d)\n", num_parts); 459 if (parts) { 460 for (i = 0; i < num_parts; i++) { 461 parts[i] = infoPtr->parts[i].x; 462 } 463 } 464 return infoPtr->numParts; 465 } 466 467 468 static BOOL 469 STATUSBAR_GetRect (const STATUS_INFO *infoPtr, INT nPart, LPRECT rect) 470 { 471 TRACE("part %d\n", nPart); 472 if(nPart >= infoPtr->numParts || nPart < 0) 473 return FALSE; 474 if (infoPtr->simple) 475 *rect = infoPtr->part0.bound; 476 else 477 *rect = infoPtr->parts[nPart].bound; 478 return TRUE; 479 } 480 481 482 static LRESULT 483 STATUSBAR_GetTextA (STATUS_INFO *infoPtr, INT nPart, LPSTR buf) 484 { 485 STATUSWINDOWPART *part; 486 LRESULT result; 487 488 TRACE("part %d\n", nPart); 489 490 /* MSDN says: "simple parts use index of 0", so this check is ok. */ 491 if (nPart < 0 || nPart >= infoPtr->numParts) return 0; 492 493 if (infoPtr->simple) 494 part = &infoPtr->part0; 495 else 496 part = &infoPtr->parts[nPart]; 497 498 if (part->style & SBT_OWNERDRAW) 499 result = (LRESULT)part->text; 500 else { 501 DWORD len = part->text ? WideCharToMultiByte( CP_ACP, 0, part->text, -1, 502 NULL, 0, NULL, NULL ) - 1 : 0; 503 result = MAKELONG( len, part->style ); 504 if (part->text && buf) 505 WideCharToMultiByte( CP_ACP, 0, part->text, -1, buf, len+1, NULL, NULL ); 506 } 507 return result; 508 } 509 510 511 static LRESULT 512 STATUSBAR_GetTextW (STATUS_INFO *infoPtr, INT nPart, LPWSTR buf) 513 { 514 STATUSWINDOWPART *part; 515 LRESULT result; 516 517 TRACE("part %d\n", nPart); 518 if (nPart < 0 || nPart >= infoPtr->numParts) return 0; 519 520 if (infoPtr->simple) 521 part = &infoPtr->part0; 522 else 523 part = &infoPtr->parts[nPart]; 524 525 if (part->style & SBT_OWNERDRAW) 526 result = (LRESULT)part->text; 527 else { 528 result = part->text ? strlenW (part->text) : 0; 529 result |= (part->style << 16); 530 if (part->text && buf) 531 strcpyW (buf, part->text); 532 } 533 return result; 534 } 535 536 537 static LRESULT 538 STATUSBAR_GetTextLength (STATUS_INFO *infoPtr, INT nPart) 539 { 540 STATUSWINDOWPART *part; 541 DWORD result; 542 543 TRACE("part %d\n", nPart); 544 545 /* MSDN says: "simple parts use index of 0", so this check is ok. */ 546 if (nPart < 0 || nPart >= infoPtr->numParts) return 0; 547 548 if (infoPtr->simple) 549 part = &infoPtr->part0; 550 else 551 part = &infoPtr->parts[nPart]; 552 553 if ((~part->style & SBT_OWNERDRAW) && part->text) 554 result = strlenW(part->text); 555 else 556 result = 0; 557 558 result |= (part->style << 16); 559 return result; 560 } 561 562 static LRESULT 563 STATUSBAR_GetTipTextA (const STATUS_INFO *infoPtr, INT id, LPSTR tip, INT size) 564 { 565 TRACE("\n"); 566 if (tip) { 567 CHAR buf[INFOTIPSIZE]; 568 buf[0]='\0'; 569 570 if (infoPtr->hwndToolTip) { 571 TTTOOLINFOA ti; 572 ti.cbSize = sizeof(TTTOOLINFOA); 573 ti.hwnd = infoPtr->Self; 574 ti.uId = id; 575 ti.lpszText = buf; 576 SendMessageA (infoPtr->hwndToolTip, TTM_GETTEXTA, 0, (LPARAM)&ti); 577 } 578 lstrcpynA (tip, buf, size); 579 } 580 return 0; 581 } 582 583 584 static LRESULT 585 STATUSBAR_GetTipTextW (const STATUS_INFO *infoPtr, INT id, LPWSTR tip, INT size) 586 { 587 TRACE("\n"); 588 if (tip) { 589 WCHAR buf[INFOTIPSIZE]; 590 buf[0]=0; 591 592 if (infoPtr->hwndToolTip) { 593 TTTOOLINFOW ti; 594 ti.cbSize = sizeof(TTTOOLINFOW); 595 ti.hwnd = infoPtr->Self; 596 ti.uId = id; 597 ti.lpszText = buf; 598 SendMessageW(infoPtr->hwndToolTip, TTM_GETTEXTW, 0, (LPARAM)&ti); 599 } 600 lstrcpynW(tip, buf, size); 601 } 602 603 return 0; 604 } 605 606 607 static COLORREF 608 STATUSBAR_SetBkColor (STATUS_INFO *infoPtr, COLORREF color) 609 { 610 COLORREF oldBkColor; 611 612 oldBkColor = infoPtr->clrBk; 613 infoPtr->clrBk = color; 614 InvalidateRect(infoPtr->Self, NULL, FALSE); 615 616 TRACE("CREF: %08x -> %08x\n", oldBkColor, infoPtr->clrBk); 617 return oldBkColor; 618 } 619 620 621 static BOOL 622 STATUSBAR_SetIcon (STATUS_INFO *infoPtr, INT nPart, HICON hIcon) 623 { 624 if ((nPart < -1) || (nPart >= infoPtr->numParts)) 625 return FALSE; 626 627 TRACE("setting part %d\n", nPart); 628 629 /* FIXME: MSDN says "if nPart is -1, the status bar is assumed simple" */ 630 if (nPart == -1) { 631 if (infoPtr->part0.hIcon == hIcon) /* same as - no redraw */ 632 return TRUE; 633 infoPtr->part0.hIcon = hIcon; 634 if (infoPtr->simple) 635 InvalidateRect(infoPtr->Self, &infoPtr->part0.bound, FALSE); 636 } else { 637 if (infoPtr->parts[nPart].hIcon == hIcon) /* same as - no redraw */ 638 return TRUE; 639 640 infoPtr->parts[nPart].hIcon = hIcon; 641 if (!(infoPtr->simple)) 642 InvalidateRect(infoPtr->Self, &infoPtr->parts[nPart].bound, FALSE); 643 } 644 return TRUE; 645 } 646 647 648 static BOOL 649 STATUSBAR_SetMinHeight (STATUS_INFO *infoPtr, INT height) 650 { 651 DWORD ysize = GetSystemMetrics(SM_CYSIZE); 652 if (ysize & 1) ysize--; 653 infoPtr->minHeight = max(height, ysize); 654 infoPtr->height = STATUSBAR_ComputeHeight(infoPtr); 655 /* like native, don't resize the control */ 656 return TRUE; 657 } 658 659 660 static BOOL 661 STATUSBAR_SetParts (STATUS_INFO *infoPtr, INT count, LPINT parts) 662 { 663 STATUSWINDOWPART *tmp; 664 UINT i, oldNumParts; 665 666 TRACE("(%d,%p)\n", count, parts); 667 668 oldNumParts = infoPtr->numParts; 669 infoPtr->numParts = count; 670 if (oldNumParts > infoPtr->numParts) { 671 for (i = infoPtr->numParts ; i < oldNumParts; i++) { 672 if (!(infoPtr->parts[i].style & SBT_OWNERDRAW)) 673 Free (infoPtr->parts[i].text); 674 } 675 } else if (oldNumParts < infoPtr->numParts) { 676 tmp = Alloc (sizeof(STATUSWINDOWPART) * infoPtr->numParts); 677 if (!tmp) return FALSE; 678 for (i = 0; i < oldNumParts; i++) { 679 tmp[i] = infoPtr->parts[i]; 680 } 681 Free (infoPtr->parts); 682 infoPtr->parts = tmp; 683 } 684 if (oldNumParts == infoPtr->numParts) { 685 for (i=0; i < oldNumParts; i++) 686 if (infoPtr->parts[i].x != parts[i]) 687 break; 688 if (i==oldNumParts) /* Unchanged? no need to redraw! */ 689 return TRUE; 690 } 691 692 for (i = 0; i < infoPtr->numParts; i++) 693 infoPtr->parts[i].x = parts[i]; 694 695 if (infoPtr->hwndToolTip) { 696 UINT nTipCount; 697 TTTOOLINFOW ti; 698 699 ZeroMemory (&ti, sizeof(TTTOOLINFOW)); 700 ti.cbSize = sizeof(TTTOOLINFOW); 701 ti.hwnd = infoPtr->Self; 702 703 nTipCount = SendMessageW (infoPtr->hwndToolTip, TTM_GETTOOLCOUNT, 0, 0); 704 if (nTipCount < infoPtr->numParts) { 705 /* add tools */ 706 for (i = nTipCount; i < infoPtr->numParts; i++) { 707 TRACE("add tool %d\n", i); 708 ti.uId = i; 709 SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, 710 0, (LPARAM)&ti); 711 } 712 } 713 else if (nTipCount > infoPtr->numParts) { 714 /* delete tools */ 715 for (i = nTipCount - 1; i >= infoPtr->numParts; i--) { 716 TRACE("delete tool %d\n", i); 717 ti.uId = i; 718 SendMessageW (infoPtr->hwndToolTip, TTM_DELTOOLW, 719 0, (LPARAM)&ti); 720 } 721 } 722 } 723 STATUSBAR_SetPartBounds (infoPtr); 724 InvalidateRect(infoPtr->Self, NULL, FALSE); 725 return TRUE; 726 } 727 728 729 static BOOL 730 STATUSBAR_SetTextT (STATUS_INFO *infoPtr, INT nPart, WORD style, 731 LPWSTR text, BOOL isW) 732 { 733 STATUSWINDOWPART *part=NULL; 734 BOOL changed = FALSE; 735 INT oldStyle; 736 737 if (style & SBT_OWNERDRAW) { 738 TRACE("part %d, text %p\n",nPart,text); 739 } 740 else TRACE("part %d, text %s\n", nPart, debugstr_t(text, isW)); 741 742 /* MSDN says: "If the parameter is set to SB_SIMPLEID (255), the status 743 * window is assumed to be a simple window */ 744 745 if (nPart == 0x00ff) { 746 part = &infoPtr->part0; 747 } else { 748 if (infoPtr->parts && nPart >= 0 && nPart < infoPtr->numParts) { 749 part = &infoPtr->parts[nPart]; 750 } 751 } 752 if (!part) return FALSE; 753 754 if (part->style != style) 755 changed = TRUE; 756 757 oldStyle = part->style; 758 part->style = style; 759 if (style & SBT_OWNERDRAW) { 760 if (!(oldStyle & SBT_OWNERDRAW)) 761 Free (part->text); 762 part->text = text; 763 } else { 764 LPWSTR ntext; 765 WCHAR *idx; 766 767 if (text && !isW) { 768 LPCSTR atxt = (LPCSTR)text; 769 DWORD len = MultiByteToWideChar( CP_ACP, 0, atxt, -1, NULL, 0 ); 770 ntext = Alloc( (len + 1)*sizeof(WCHAR) ); 771 if (!ntext) return FALSE; 772 MultiByteToWideChar( CP_ACP, 0, atxt, -1, ntext, len ); 773 } else if (text) { 774 ntext = Alloc( (strlenW(text) + 1)*sizeof(WCHAR) ); 775 if (!ntext) return FALSE; 776 strcpyW (ntext, text); 777 } else ntext = 0; 778 779 /* replace nonprintable characters with spaces */ 780 if (ntext) { 781 idx = ntext; 782 while (*idx) { 783 if(!isprintW(*idx)) 784 *idx = ' '; 785 idx++; 786 } 787 } 788 789 /* check if text is unchanged -> no need to redraw */ 790 if (text) { 791 if (!changed && part->text && !lstrcmpW(ntext, part->text)) { 792 Free(ntext); 793 return TRUE; 794 } 795 } else { 796 if (!changed && !part->text) 797 return TRUE; 798 } 799 800 if (!(oldStyle & SBT_OWNERDRAW)) 801 Free (part->text); 802 part->text = ntext; 803 } 804 InvalidateRect(infoPtr->Self, &part->bound, FALSE); 805 UpdateWindow(infoPtr->Self); 806 807 return TRUE; 808 } 809 810 811 static LRESULT 812 STATUSBAR_SetTipTextA (const STATUS_INFO *infoPtr, INT id, LPSTR text) 813 { 814 TRACE("part %d: \"%s\"\n", id, text); 815 if (infoPtr->hwndToolTip) { 816 TTTOOLINFOA ti; 817 ti.cbSize = sizeof(TTTOOLINFOA); 818 ti.hwnd = infoPtr->Self; 819 ti.uId = id; 820 ti.hinst = 0; 821 ti.lpszText = text; 822 SendMessageA (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTA, 0, (LPARAM)&ti); 823 } 824 825 return 0; 826 } 827 828 829 static LRESULT 830 STATUSBAR_SetTipTextW (const STATUS_INFO *infoPtr, INT id, LPWSTR text) 831 { 832 TRACE("part %d: \"%s\"\n", id, debugstr_w(text)); 833 if (infoPtr->hwndToolTip) { 834 TTTOOLINFOW ti; 835 ti.cbSize = sizeof(TTTOOLINFOW); 836 ti.hwnd = infoPtr->Self; 837 ti.uId = id; 838 ti.hinst = 0; 839 ti.lpszText = text; 840 SendMessageW (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTW, 0, (LPARAM)&ti); 841 } 842 843 return 0; 844 } 845 846 847 static inline LRESULT 848 STATUSBAR_SetUnicodeFormat (STATUS_INFO *infoPtr, BOOL bUnicode) 849 { 850 BOOL bOld = infoPtr->bUnicode; 851 852 TRACE("(0x%x)\n", bUnicode); 853 infoPtr->bUnicode = bUnicode; 854 855 return bOld; 856 } 857 858 859 static BOOL 860 STATUSBAR_Simple (STATUS_INFO *infoPtr, BOOL simple) 861 { 862 NMHDR nmhdr; 863 864 TRACE("(simple=%d)\n", simple); 865 if (infoPtr->simple == simple) /* no need to change */ 866 return TRUE; 867 868 infoPtr->simple = simple; 869 870 /* send notification */ 871 nmhdr.hwndFrom = infoPtr->Self; 872 nmhdr.idFrom = GetWindowLongPtrW (infoPtr->Self, GWLP_ID); 873 nmhdr.code = SBN_SIMPLEMODECHANGE; 874 SendMessageW (infoPtr->Notify, WM_NOTIFY, 0, (LPARAM)&nmhdr); 875 InvalidateRect(infoPtr->Self, NULL, FALSE); 876 return TRUE; 877 } 878 879 880 static LRESULT 881 STATUSBAR_WMDestroy (STATUS_INFO *infoPtr) 882 { 883 int i; 884 885 TRACE("\n"); 886 for (i = 0; i < infoPtr->numParts; i++) { 887 if (!(infoPtr->parts[i].style & SBT_OWNERDRAW)) 888 Free (infoPtr->parts[i].text); 889 } 890 if (!(infoPtr->part0.style & SBT_OWNERDRAW)) 891 Free (infoPtr->part0.text); 892 Free (infoPtr->parts); 893 894 /* delete default font */ 895 if (infoPtr->hDefaultFont) 896 DeleteObject (infoPtr->hDefaultFont); 897 898 /* delete tool tip control */ 899 if (infoPtr->hwndToolTip) 900 DestroyWindow (infoPtr->hwndToolTip); 901 902 CloseThemeData (GetWindowTheme (infoPtr->Self)); 903 904 SetWindowLongPtrW(infoPtr->Self, 0, 0); 905 Free (infoPtr); 906 return 0; 907 } 908 909 910 static LRESULT 911 STATUSBAR_WMCreate (HWND hwnd, const CREATESTRUCTA *lpCreate) 912 { 913 STATUS_INFO *infoPtr; 914 NONCLIENTMETRICSW nclm; 915 DWORD dwStyle; 916 RECT rect; 917 int len; 918 919 TRACE("\n"); 920 infoPtr = Alloc (sizeof(STATUS_INFO)); 921 if (!infoPtr) goto create_fail; 922 SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); 923 924 infoPtr->Self = hwnd; 925 infoPtr->Notify = lpCreate->hwndParent; 926 infoPtr->numParts = 1; 927 infoPtr->parts = 0; 928 infoPtr->simple = FALSE; 929 infoPtr->clrBk = CLR_DEFAULT; 930 infoPtr->hFont = 0; 931 infoPtr->horizontalBorder = HORZ_BORDER; 932 infoPtr->verticalBorder = VERT_BORDER; 933 infoPtr->horizontalGap = HORZ_GAP; 934 infoPtr->minHeight = GetSystemMetrics(SM_CYSIZE); 935 if (infoPtr->minHeight & 1) infoPtr->minHeight--; 936 937 STATUSBAR_NotifyFormat(infoPtr, infoPtr->Notify, NF_REQUERY); 938 939 ZeroMemory (&nclm, sizeof(nclm)); 940 nclm.cbSize = sizeof(nclm); 941 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, nclm.cbSize, &nclm, 0); 942 infoPtr->hDefaultFont = CreateFontIndirectW (&nclm.lfStatusFont); 943 944 GetClientRect (hwnd, &rect); 945 946 /* initialize simple case */ 947 infoPtr->part0.bound = rect; 948 infoPtr->part0.text = 0; 949 infoPtr->part0.x = 0; 950 infoPtr->part0.style = 0; 951 infoPtr->part0.hIcon = 0; 952 953 /* initialize first part */ 954 infoPtr->parts = Alloc (sizeof(STATUSWINDOWPART)); 955 if (!infoPtr->parts) goto create_fail; 956 infoPtr->parts[0].bound = rect; 957 infoPtr->parts[0].text = 0; 958 infoPtr->parts[0].x = -1; 959 infoPtr->parts[0].style = 0; 960 infoPtr->parts[0].hIcon = 0; 961 962 OpenThemeData (hwnd, themeClass); 963 964 if (lpCreate->lpszName && (len = strlenW ((LPCWSTR)lpCreate->lpszName))) 965 { 966 infoPtr->parts[0].text = Alloc ((len + 1)*sizeof(WCHAR)); 967 if (!infoPtr->parts[0].text) goto create_fail; 968 strcpyW (infoPtr->parts[0].text, (LPCWSTR)lpCreate->lpszName); 969 } 970 971 dwStyle = GetWindowLongW (hwnd, GWL_STYLE); 972 /* native seems to clear WS_BORDER, too */ 973 dwStyle &= ~WS_BORDER; 974 SetWindowLongW (hwnd, GWL_STYLE, dwStyle); 975 976 infoPtr->height = STATUSBAR_ComputeHeight(infoPtr); 977 978 if (dwStyle & SBT_TOOLTIPS) { 979 infoPtr->hwndToolTip = 980 CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, WS_POPUP | TTS_ALWAYSTIP, 981 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 982 CW_USEDEFAULT, hwnd, 0, 983 (HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE), NULL); 984 985 if (infoPtr->hwndToolTip) { 986 NMTOOLTIPSCREATED nmttc; 987 988 nmttc.hdr.hwndFrom = hwnd; 989 nmttc.hdr.idFrom = GetWindowLongPtrW (hwnd, GWLP_ID); 990 nmttc.hdr.code = NM_TOOLTIPSCREATED; 991 nmttc.hwndToolTips = infoPtr->hwndToolTip; 992 993 SendMessageW (lpCreate->hwndParent, WM_NOTIFY, nmttc.hdr.idFrom, (LPARAM)&nmttc); 994 } 995 } 996 997 return 0; 998 999 create_fail: 1000 TRACE(" failed!\n"); 1001 if (infoPtr) STATUSBAR_WMDestroy(infoPtr); 1002 return -1; 1003 } 1004 1005 1006 /* in contrast to SB_GETTEXT*, WM_GETTEXT handles the text 1007 * of the first part only (usual behaviour) */ 1008 static INT 1009 STATUSBAR_WMGetText (const STATUS_INFO *infoPtr, INT size, LPWSTR buf) 1010 { 1011 INT len; 1012 1013 TRACE("\n"); 1014 if (!(infoPtr->parts[0].text)) 1015 return 0; 1016 1017 len = strlenW (infoPtr->parts[0].text); 1018 1019 if (!size) 1020 return len; 1021 else if (size > len) { 1022 strcpyW (buf, infoPtr->parts[0].text); 1023 return len; 1024 } 1025 else { 1026 memcpy (buf, infoPtr->parts[0].text, (size - 1) * sizeof(WCHAR)); 1027 buf[size - 1] = 0; 1028 return size - 1; 1029 } 1030 } 1031 1032 1033 static BOOL 1034 STATUSBAR_WMNCHitTest (const STATUS_INFO *infoPtr, INT x, INT y) 1035 { 1036 if (GetWindowLongW (infoPtr->Self, GWL_STYLE) & SBARS_SIZEGRIP) { 1037 RECT rect; 1038 POINT pt; 1039 1040 GetClientRect (infoPtr->Self, &rect); 1041 1042 pt.x = x; 1043 pt.y = y; 1044 ScreenToClient (infoPtr->Self, &pt); 1045 1046 rect.left = rect.right - 13; 1047 rect.top += 2; 1048 1049 if (PtInRect (&rect, pt)) 1050 { 1051 if (GetWindowLongW( infoPtr->Self, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL) return HTBOTTOMLEFT; 1052 else return HTBOTTOMRIGHT; 1053 } 1054 } 1055 1056 return HTERROR; 1057 } 1058 1059 1060 static LRESULT 1061 STATUSBAR_WMPaint (STATUS_INFO *infoPtr, HDC hdc) 1062 { 1063 PAINTSTRUCT ps; 1064 1065 TRACE("\n"); 1066 if (hdc) return STATUSBAR_Refresh (infoPtr, hdc); 1067 hdc = BeginPaint (infoPtr->Self, &ps); 1068 STATUSBAR_Refresh (infoPtr, hdc); 1069 EndPaint (infoPtr->Self, &ps); 1070 1071 return 0; 1072 } 1073 1074 1075 static LRESULT 1076 STATUSBAR_WMSetFont (STATUS_INFO *infoPtr, HFONT font, BOOL redraw) 1077 { 1078 infoPtr->hFont = font; 1079 TRACE("%p\n", infoPtr->hFont); 1080 1081 infoPtr->height = STATUSBAR_ComputeHeight(infoPtr); 1082 SendMessageW(infoPtr->Self, WM_SIZE, 0, 0); /* update size */ 1083 if (redraw) 1084 InvalidateRect(infoPtr->Self, NULL, FALSE); 1085 1086 return 0; 1087 } 1088 1089 1090 static BOOL 1091 STATUSBAR_WMSetText (const STATUS_INFO *infoPtr, LPCSTR text) 1092 { 1093 STATUSWINDOWPART *part; 1094 int len; 1095 1096 TRACE("\n"); 1097 if (infoPtr->numParts == 0) 1098 return FALSE; 1099 1100 part = &infoPtr->parts[0]; 1101 /* duplicate string */ 1102 Free (part->text); 1103 part->text = 0; 1104 1105 if (text && (len = strlenW((LPCWSTR)text))) { 1106 part->text = Alloc ((len+1)*sizeof(WCHAR)); 1107 if (!part->text) return FALSE; 1108 strcpyW (part->text, (LPCWSTR)text); 1109 } 1110 1111 InvalidateRect(infoPtr->Self, &part->bound, FALSE); 1112 1113 return TRUE; 1114 } 1115 1116 1117 static BOOL 1118 STATUSBAR_WMSize (STATUS_INFO *infoPtr, WORD flags) 1119 { 1120 INT width, x, y; 1121 RECT parent_rect; 1122 1123 /* Need to resize width to match parent */ 1124 TRACE("flags %04x\n", flags); 1125 1126 if (flags != SIZE_RESTORED && flags != SIZE_MAXIMIZED) { 1127 WARN("flags MUST be SIZE_RESTORED or SIZE_MAXIMIZED\n"); 1128 return FALSE; 1129 } 1130 1131 if (GetWindowLongW(infoPtr->Self, GWL_STYLE) & CCS_NORESIZE) return FALSE; 1132 1133 /* width and height don't apply */ 1134 if (!GetClientRect (infoPtr->Notify, &parent_rect)) 1135 return FALSE; 1136 1137 width = parent_rect.right - parent_rect.left; 1138 x = parent_rect.left; 1139 y = parent_rect.bottom - infoPtr->height; 1140 MoveWindow (infoPtr->Self, x, y, width, infoPtr->height, TRUE); 1141 STATUSBAR_SetPartBounds (infoPtr); 1142 return TRUE; 1143 } 1144 1145 1146 /* update theme after a WM_THEMECHANGED message */ 1147 static LRESULT theme_changed (const STATUS_INFO* infoPtr) 1148 { 1149 HTHEME theme = GetWindowTheme (infoPtr->Self); 1150 CloseThemeData (theme); 1151 OpenThemeData (infoPtr->Self, themeClass); 1152 return 0; 1153 } 1154 1155 1156 static LRESULT 1157 STATUSBAR_NotifyFormat (STATUS_INFO *infoPtr, HWND from, INT cmd) 1158 { 1159 if (cmd == NF_REQUERY) { 1160 INT i = SendMessageW(from, WM_NOTIFYFORMAT, (WPARAM)infoPtr->Self, NF_QUERY); 1161 infoPtr->bUnicode = (i == NFR_UNICODE); 1162 } 1163 return infoPtr->bUnicode ? NFR_UNICODE : NFR_ANSI; 1164 } 1165 1166 1167 static LRESULT 1168 STATUSBAR_SendMouseNotify(const STATUS_INFO *infoPtr, UINT code, UINT msg, WPARAM wParam, LPARAM lParam) 1169 { 1170 NMMOUSE nm; 1171 1172 TRACE("code %04x, lParam=%lx\n", code, lParam); 1173 nm.hdr.hwndFrom = infoPtr->Self; 1174 nm.hdr.idFrom = GetWindowLongPtrW(infoPtr->Self, GWLP_ID); 1175 nm.hdr.code = code; 1176 nm.pt.x = (short)LOWORD(lParam); 1177 nm.pt.y = (short)HIWORD(lParam); 1178 nm.dwItemSpec = STATUSBAR_InternalHitTest(infoPtr, &nm.pt); 1179 nm.dwItemData = 0; 1180 nm.dwHitInfo = 0x30000; /* seems constant */ 1181 1182 /* Do default processing if WM_NOTIFY returns zero */ 1183 if(!SendMessageW(infoPtr->Notify, WM_NOTIFY, nm.hdr.idFrom, (LPARAM)&nm)) 1184 { 1185 return DefWindowProcW(infoPtr->Self, msg, wParam, lParam); 1186 } 1187 return 0; 1188 } 1189 1190 1191 1192 static LRESULT WINAPI 1193 StatusWindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 1194 { 1195 STATUS_INFO *infoPtr = (STATUS_INFO *)GetWindowLongPtrW (hwnd, 0); 1196 INT nPart = ((INT) wParam) & 0x00ff; 1197 LRESULT res; 1198 1199 TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", hwnd, msg, wParam, lParam); 1200 if (!infoPtr && msg != WM_CREATE) 1201 return DefWindowProcW (hwnd, msg, wParam, lParam); 1202 1203 switch (msg) { 1204 case SB_GETBORDERS: 1205 return STATUSBAR_GetBorders (infoPtr, (INT *)lParam); 1206 1207 case SB_GETICON: 1208 return (LRESULT)STATUSBAR_GetIcon (infoPtr, nPart); 1209 1210 case SB_GETPARTS: 1211 return STATUSBAR_GetParts (infoPtr, (INT)wParam, (INT *)lParam); 1212 1213 case SB_GETRECT: 1214 return STATUSBAR_GetRect (infoPtr, nPart, (LPRECT)lParam); 1215 1216 case SB_GETTEXTA: 1217 return STATUSBAR_GetTextA (infoPtr, nPart, (LPSTR)lParam); 1218 1219 case SB_GETTEXTW: 1220 return STATUSBAR_GetTextW (infoPtr, nPart, (LPWSTR)lParam); 1221 1222 case SB_GETTEXTLENGTHA: 1223 case SB_GETTEXTLENGTHW: 1224 return STATUSBAR_GetTextLength (infoPtr, nPart); 1225 1226 case SB_GETTIPTEXTA: 1227 return STATUSBAR_GetTipTextA (infoPtr, LOWORD(wParam), (LPSTR)lParam, HIWORD(wParam)); 1228 1229 case SB_GETTIPTEXTW: 1230 return STATUSBAR_GetTipTextW (infoPtr, LOWORD(wParam), (LPWSTR)lParam, HIWORD(wParam)); 1231 1232 case SB_GETUNICODEFORMAT: 1233 return infoPtr->bUnicode; 1234 1235 case SB_ISSIMPLE: 1236 return infoPtr->simple; 1237 1238 case SB_SETBORDERS: 1239 return STATUSBAR_SetBorders (infoPtr, (INT *)lParam); 1240 1241 case SB_SETBKCOLOR: 1242 return STATUSBAR_SetBkColor (infoPtr, (COLORREF)lParam); 1243 1244 case SB_SETICON: 1245 return STATUSBAR_SetIcon (infoPtr, nPart, (HICON)lParam); 1246 1247 case SB_SETMINHEIGHT: 1248 return STATUSBAR_SetMinHeight (infoPtr, (INT)wParam); 1249 1250 case SB_SETPARTS: 1251 return STATUSBAR_SetParts (infoPtr, (INT)wParam, (LPINT)lParam); 1252 1253 case SB_SETTEXTA: 1254 return STATUSBAR_SetTextT (infoPtr, nPart, wParam & 0xff00, (LPWSTR)lParam, FALSE); 1255 1256 case SB_SETTEXTW: 1257 return STATUSBAR_SetTextT (infoPtr, nPart, wParam & 0xff00, (LPWSTR)lParam, TRUE); 1258 1259 case SB_SETTIPTEXTA: 1260 return STATUSBAR_SetTipTextA (infoPtr, (INT)wParam, (LPSTR)lParam); 1261 1262 case SB_SETTIPTEXTW: 1263 return STATUSBAR_SetTipTextW (infoPtr, (INT)wParam, (LPWSTR)lParam); 1264 1265 case SB_SETUNICODEFORMAT: 1266 return STATUSBAR_SetUnicodeFormat (infoPtr, (BOOL)wParam); 1267 1268 case SB_SIMPLE: 1269 return STATUSBAR_Simple (infoPtr, (BOOL)wParam); 1270 1271 case WM_CREATE: 1272 return STATUSBAR_WMCreate (hwnd, (LPCREATESTRUCTA)lParam); 1273 1274 case WM_DESTROY: 1275 return STATUSBAR_WMDestroy (infoPtr); 1276 1277 case WM_GETFONT: 1278 return (LRESULT)(infoPtr->hFont? infoPtr->hFont : infoPtr->hDefaultFont); 1279 1280 case WM_GETTEXT: 1281 return STATUSBAR_WMGetText (infoPtr, (INT)wParam, (LPWSTR)lParam); 1282 1283 case WM_GETTEXTLENGTH: 1284 return STATUSBAR_GetTextLength (infoPtr, 0); 1285 1286 case WM_LBUTTONDBLCLK: 1287 return STATUSBAR_SendMouseNotify(infoPtr, NM_DBLCLK, msg, wParam, lParam); 1288 1289 case WM_LBUTTONUP: 1290 return STATUSBAR_SendMouseNotify(infoPtr, NM_CLICK, msg, wParam, lParam); 1291 1292 case WM_MOUSEMOVE: 1293 return STATUSBAR_Relay2Tip (infoPtr, msg, wParam, lParam); 1294 1295 case WM_NCHITTEST: 1296 res = STATUSBAR_WMNCHitTest(infoPtr, (short)LOWORD(lParam), 1297 (short)HIWORD(lParam)); 1298 if (res != HTERROR) return res; 1299 return DefWindowProcW (hwnd, msg, wParam, lParam); 1300 1301 case WM_NCLBUTTONUP: 1302 case WM_NCLBUTTONDOWN: 1303 PostMessageW (infoPtr->Notify, msg, wParam, lParam); 1304 return 0; 1305 1306 case WM_NOTIFYFORMAT: 1307 return STATUSBAR_NotifyFormat(infoPtr, (HWND)wParam, (INT)lParam); 1308 1309 case WM_PRINTCLIENT: 1310 case WM_PAINT: 1311 return STATUSBAR_WMPaint (infoPtr, (HDC)wParam); 1312 1313 case WM_RBUTTONDBLCLK: 1314 return STATUSBAR_SendMouseNotify(infoPtr, NM_RDBLCLK, msg, wParam, lParam); 1315 1316 case WM_RBUTTONUP: 1317 return STATUSBAR_SendMouseNotify(infoPtr, NM_RCLICK, msg, wParam, lParam); 1318 1319 case WM_SETFONT: 1320 return STATUSBAR_WMSetFont (infoPtr, (HFONT)wParam, LOWORD(lParam)); 1321 1322 case WM_SETTEXT: 1323 return STATUSBAR_WMSetText (infoPtr, (LPCSTR)lParam); 1324 1325 case WM_SIZE: 1326 if (STATUSBAR_WMSize (infoPtr, (WORD)wParam)) return 0; 1327 return DefWindowProcW (hwnd, msg, wParam, lParam); 1328 1329 case WM_SYSCOLORCHANGE: 1330 COMCTL32_RefreshSysColors(); 1331 return 0; 1332 1333 case WM_THEMECHANGED: 1334 return theme_changed (infoPtr); 1335 1336 default: 1337 if ((msg >= WM_USER) && (msg < WM_APP) && !COMCTL32_IsReflectedMessage(msg)) 1338 ERR("unknown msg %04x wp=%04lx lp=%08lx\n", 1339 msg, wParam, lParam); 1340 return DefWindowProcW (hwnd, msg, wParam, lParam); 1341 } 1342 } 1343 1344 1345 /*********************************************************************** 1346 * STATUS_Register [Internal] 1347 * 1348 * Registers the status window class. 1349 */ 1350 1351 void 1352 STATUS_Register (void) 1353 { 1354 WNDCLASSW wndClass; 1355 1356 ZeroMemory (&wndClass, sizeof(WNDCLASSW)); 1357 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW; 1358 wndClass.lpfnWndProc = StatusWindowProc; 1359 wndClass.cbClsExtra = 0; 1360 wndClass.cbWndExtra = sizeof(STATUS_INFO *); 1361 wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); 1362 wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 1363 wndClass.lpszClassName = STATUSCLASSNAMEW; 1364 1365 RegisterClassW (&wndClass); 1366 } 1367 1368 1369 /*********************************************************************** 1370 * STATUS_Unregister [Internal] 1371 * 1372 * Unregisters the status window class. 1373 */ 1374 1375 void 1376 STATUS_Unregister (void) 1377 { 1378 UnregisterClassW (STATUSCLASSNAMEW, NULL); 1379 } 1380