1 /* 2 * Copyright 2001-2006, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Adrian Oanca <adioanca@cotty.iren.ro> 7 * Axel Dörfler, axeld@pinc-software.de 8 * Stephan Aßmus, <superstippi@gmx.de> 9 */ 10 11 12 #include <Application.h> 13 #include <Autolock.h> 14 #include <Button.h> 15 #include <MenuBar.h> 16 #include <MenuItem.h> 17 #include <MessageQueue.h> 18 #include <MessageRunner.h> 19 #include <PropertyInfo.h> 20 #include <Roster.h> 21 #include <Screen.h> 22 #include <String.h> 23 #include <Window.h> 24 25 #include <input_globals.h> 26 #include <AppMisc.h> 27 #include <ApplicationPrivate.h> 28 #include <InputServerTypes.h> 29 #include <MenuPrivate.h> 30 #include <MessagePrivate.h> 31 #include <PortLink.h> 32 #include <ServerProtocol.h> 33 #include <TokenSpace.h> 34 #include <tracker_private.h> 35 36 #include <ctype.h> 37 #include <stdio.h> 38 #include <math.h> 39 40 41 //#define DEBUG_WIN 42 #ifdef DEBUG_WIN 43 # include <stdio.h> 44 # define STRACE(x) printf x 45 #else 46 # define STRACE(x) ; 47 #endif 48 49 50 struct BWindow::unpack_cookie { 51 unpack_cookie(); 52 53 BMessage* message; 54 int32 index; 55 BHandler* focus; 56 int32 focus_token; 57 int32 last_view_token; 58 bool found_focus; 59 bool tokens_scanned; 60 }; 61 62 class BWindow::Shortcut { 63 public: 64 Shortcut(uint32 key, uint32 modifiers, BMenuItem* item); 65 Shortcut(uint32 key, uint32 modifiers, BMessage* message, BHandler* target); 66 ~Shortcut(); 67 68 bool Matches(uint32 key, uint32 modifiers) const; 69 70 BMenuItem* MenuItem() const { return fMenuItem; } 71 BMessage* Message() const { return fMessage; } 72 BHandler* Target() const { return fTarget; } 73 74 static uint32 AllowedModifiers(); 75 static uint32 PrepareKey(uint32 key); 76 static uint32 PrepareModifiers(uint32 modifiers); 77 78 private: 79 uint32 fKey; 80 uint32 fModifiers; 81 BMenuItem* fMenuItem; 82 BMessage* fMessage; 83 BHandler* fTarget; 84 }; 85 86 87 using BPrivate::gDefaultTokens; 88 89 static property_info sWindowPropInfo[] = { 90 { 91 "Feel", { B_GET_PROPERTY, B_SET_PROPERTY }, 92 { B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE } 93 }, 94 95 { 96 "Flags", { B_GET_PROPERTY, B_SET_PROPERTY }, 97 { B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE } 98 }, 99 100 { 101 "Frame", { B_GET_PROPERTY, B_SET_PROPERTY }, 102 { B_DIRECT_SPECIFIER }, NULL, 0, { B_RECT_TYPE } 103 }, 104 105 { 106 "Hidden", { B_GET_PROPERTY, B_SET_PROPERTY }, 107 { B_DIRECT_SPECIFIER }, NULL, 0, { B_BOOL_TYPE } 108 }, 109 110 { 111 "Look", { B_GET_PROPERTY, B_SET_PROPERTY }, 112 { B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE } 113 }, 114 115 { 116 "Title", { B_GET_PROPERTY, B_SET_PROPERTY }, 117 { B_DIRECT_SPECIFIER }, NULL, 0, { B_STRING_TYPE } 118 }, 119 120 { 121 "Workspaces", { B_GET_PROPERTY, B_SET_PROPERTY }, 122 { B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE} 123 }, 124 125 { 126 "MenuBar", {}, 127 { B_DIRECT_SPECIFIER }, NULL, 0, {} 128 }, 129 130 { 131 "View", {}, {}, NULL, 0, {} 132 }, 133 134 { 135 "Minimize", { B_GET_PROPERTY, B_SET_PROPERTY }, 136 { B_DIRECT_SPECIFIER }, NULL, 0, { B_BOOL_TYPE } 137 }, 138 139 {} 140 }; 141 142 143 void 144 _set_menu_sem_(BWindow *window, sem_id sem) 145 { 146 if (window != NULL) 147 window->fMenuSem = sem; 148 } 149 150 151 // #pragma mark - 152 153 154 BWindow::unpack_cookie::unpack_cookie() 155 : 156 message((BMessage*)~0UL), 157 // message == NULL is our exit condition 158 index(0), 159 focus_token(B_NULL_TOKEN), 160 last_view_token(B_NULL_TOKEN), 161 found_focus(false), 162 tokens_scanned(false) 163 { 164 } 165 166 167 // #pragma mark - 168 169 170 BWindow::Shortcut::Shortcut(uint32 key, uint32 modifiers, BMenuItem* item) 171 : 172 fKey(PrepareKey(key)), 173 fModifiers(PrepareModifiers(modifiers)), 174 fMenuItem(item), 175 fMessage(NULL), 176 fTarget(NULL) 177 { 178 } 179 180 181 BWindow::Shortcut::Shortcut(uint32 key, uint32 modifiers, BMessage* message, 182 BHandler* target) 183 : 184 fKey(PrepareKey(key)), 185 fModifiers(PrepareModifiers(modifiers)), 186 fMenuItem(NULL), 187 fMessage(message), 188 fTarget(target) 189 { 190 } 191 192 193 BWindow::Shortcut::~Shortcut() 194 { 195 // we own the message, if any 196 delete fMessage; 197 } 198 199 200 bool 201 BWindow::Shortcut::Matches(uint32 key, uint32 modifiers) const 202 { 203 return fKey == key && fModifiers == modifiers; 204 } 205 206 207 /*static*/ 208 uint32 209 BWindow::Shortcut::AllowedModifiers() 210 { 211 return B_COMMAND_KEY | B_OPTION_KEY | B_SHIFT_KEY 212 | B_CONTROL_KEY | B_MENU_KEY; 213 } 214 215 216 /*static*/ 217 uint32 218 BWindow::Shortcut::PrepareModifiers(uint32 modifiers) 219 { 220 return (modifiers & AllowedModifiers()) | B_COMMAND_KEY; 221 } 222 223 224 /*static*/ 225 uint32 226 BWindow::Shortcut::PrepareKey(uint32 key) 227 { 228 return tolower(key); 229 // TODO: support unicode and/or more intelligent key mapping 230 } 231 232 233 // #pragma mark - 234 235 236 BWindow::BWindow(BRect frame, const char* title, window_type type, 237 uint32 flags, uint32 workspace) 238 : BLooper(title) 239 { 240 window_look look; 241 window_feel feel; 242 _DecomposeType(type, &look, &feel); 243 244 _InitData(frame, title, look, feel, flags, workspace); 245 } 246 247 248 BWindow::BWindow(BRect frame, const char* title, window_look look, window_feel feel, 249 uint32 flags, uint32 workspace) 250 : BLooper(title) 251 { 252 _InitData(frame, title, look, feel, flags, workspace); 253 } 254 255 256 BWindow::BWindow(BMessage* data) 257 : BLooper(data) 258 { 259 data->FindRect("_frame", &fFrame); 260 261 const char *title; 262 data->FindString("_title", &title); 263 264 window_look look; 265 data->FindInt32("_wlook", (int32 *)&look); 266 267 window_feel feel; 268 data->FindInt32("_wfeel", (int32 *)&feel); 269 270 if (data->FindInt32("_flags", (int32 *)&fFlags) != B_OK) 271 fFlags = 0; 272 273 uint32 workspaces; 274 data->FindInt32("_wspace", (int32 *)&workspaces); 275 276 uint32 type; 277 if (data->FindInt32("_type", (int32*)&type) == B_OK) 278 _DecomposeType((window_type)type, &fLook, &fFeel); 279 280 // connect to app_server and initialize data 281 _InitData(fFrame, title, look, feel, fFlags, workspaces); 282 283 if (data->FindFloat("_zoom", 0, &fMaxZoomWidth) == B_OK 284 && data->FindFloat("_zoom", 1, &fMaxZoomHeight) == B_OK) 285 SetZoomLimits(fMaxZoomWidth, fMaxZoomHeight); 286 287 if (data->FindFloat("_sizel", 0, &fMinWidth) == B_OK 288 && data->FindFloat("_sizel", 1, &fMinHeight) == B_OK 289 && data->FindFloat("_sizel", 2, &fMaxWidth) == B_OK 290 && data->FindFloat("_sizel", 3, &fMaxHeight) == B_OK) 291 SetSizeLimits(fMinWidth, fMaxWidth, 292 fMinHeight, fMaxHeight); 293 294 if (data->FindInt64("_pulse", &fPulseRate) == B_OK) 295 SetPulseRate(fPulseRate); 296 297 BMessage msg; 298 int32 i = 0; 299 while (data->FindMessage("_views", i++, &msg) == B_OK) { 300 BArchivable *obj = instantiate_object(&msg); 301 BView *child = dynamic_cast<BView *>(obj); 302 if (child) 303 AddChild(child); 304 } 305 } 306 307 308 BWindow::BWindow(BRect frame, int32 bitmapToken) 309 : BLooper("offscreen bitmap") 310 { 311 // TODO: Implement for real 312 _DecomposeType(B_UNTYPED_WINDOW, &fLook, &fFeel); 313 _InitData(frame, "offscreen", fLook, fFeel, 0, 0, bitmapToken); 314 } 315 316 317 BWindow::~BWindow() 318 { 319 Lock(); 320 321 if (BMenu *menu = dynamic_cast<BMenu *>(fFocus)) { 322 menu->QuitTracking(); 323 } 324 325 // Wait if a menu is still tracking 326 if (fMenuSem > 0) { 327 while (acquire_sem(fMenuSem) == B_INTERRUPTED) 328 ; 329 } 330 331 fTopView->RemoveSelf(); 332 delete fTopView; 333 334 // remove all remaining shortcuts 335 int32 shortCutCount = fShortcuts.CountItems(); 336 for (int32 i = 0; i < shortCutCount; i++) { 337 delete (Shortcut*)fShortcuts.ItemAtFast(i); 338 } 339 340 // TODO: release other dynamically-allocated objects 341 free(fTitle); 342 343 // disable pulsing 344 SetPulseRate(0); 345 346 // tell app_server about our demise 347 fLink->StartMessage(AS_DELETE_WINDOW); 348 // sync with the server so that for example 349 // a BBitmap can be sure that there are no 350 // more pending messages that are executed 351 // after the bitmap is deleted (which uses 352 // a different link and server side thread) 353 int32 code; 354 fLink->FlushWithReply(code); 355 356 // the sender port belongs to the app_server 357 delete_port(fLink->ReceiverPort()); 358 delete fLink; 359 } 360 361 362 BArchivable * 363 BWindow::Instantiate(BMessage *data) 364 { 365 if (!validate_instantiation(data , "BWindow")) 366 return NULL; 367 368 return new BWindow(data); 369 } 370 371 372 status_t 373 BWindow::Archive(BMessage* data, bool deep) const 374 { 375 status_t ret = BLooper::Archive(data, deep); 376 377 if (ret == B_OK) 378 ret = data->AddRect("_frame", fFrame); 379 if (ret == B_OK) 380 ret = data->AddString("_title", fTitle); 381 if (ret == B_OK) 382 ret = data->AddInt32("_wlook", fLook); 383 if (ret == B_OK) 384 ret = data->AddInt32("_wfeel", fFeel); 385 if (ret == B_OK && fFlags != 0) 386 ret = data->AddInt32("_flags", fFlags); 387 if (ret == B_OK) 388 ret = data->AddInt32("_wspace", (uint32)Workspaces()); 389 390 if (ret == B_OK && !_ComposeType(fLook, fFeel)) 391 ret = data->AddInt32("_type", (uint32)Type()); 392 393 if (fMaxZoomWidth != 32768.0 || fMaxZoomHeight != 32768.0) { 394 if (ret == B_OK) 395 ret = data->AddFloat("_zoom", fMaxZoomWidth); 396 if (ret == B_OK) 397 ret = data->AddFloat("_zoom", fMaxZoomHeight); 398 } 399 400 if (fMinWidth != 0.0 || fMinHeight != 0.0 401 || fMaxWidth != 32768.0 || fMaxHeight != 32768.0) { 402 if (ret == B_OK) 403 ret = data->AddFloat("_sizel", fMinWidth); 404 if (ret == B_OK) 405 ret = data->AddFloat("_sizel", fMinHeight); 406 if (ret == B_OK) 407 ret = data->AddFloat("_sizel", fMaxWidth); 408 if (ret == B_OK) 409 ret = data->AddFloat("_sizel", fMaxHeight); 410 } 411 412 if (ret == B_OK && fPulseRate != 500000) 413 data->AddInt64("_pulse", fPulseRate); 414 415 if (ret == B_OK && deep) { 416 int32 noOfViews = CountChildren(); 417 for (int32 i = 0; i < noOfViews; i++){ 418 BMessage childArchive; 419 ret = ChildAt(i)->Archive(&childArchive, true); 420 if (ret == B_OK) 421 ret = data->AddMessage("_views", &childArchive); 422 if (ret != B_OK) 423 break; 424 } 425 } 426 427 if (ret == B_OK) 428 ret = data->AddString("class", "BWindow"); 429 430 return ret; 431 } 432 433 434 void 435 BWindow::Quit() 436 { 437 if (!IsLocked()) { 438 const char *name = Name(); 439 if (!name) 440 name = "no-name"; 441 442 printf("ERROR - you must Lock a looper before calling Quit(), " 443 "team=%ld, looper=%s\n", Team(), name); 444 } 445 446 // Try to lock 447 if (!Lock()){ 448 // We're toast already 449 return; 450 } 451 452 while (!IsHidden()) { 453 Hide(); 454 } 455 456 if (fFlags & B_QUIT_ON_WINDOW_CLOSE) 457 be_app->PostMessage(B_QUIT_REQUESTED); 458 459 BLooper::Quit(); 460 } 461 462 463 void 464 BWindow::AddChild(BView *child, BView *before) 465 { 466 BAutolock locker(this); 467 fTopView->AddChild(child, before); 468 } 469 470 471 bool 472 BWindow::RemoveChild(BView *child) 473 { 474 BAutolock locker(this); 475 return fTopView->RemoveChild(child); 476 } 477 478 479 int32 480 BWindow::CountChildren() const 481 { 482 BAutolock _(const_cast<BWindow*>(this)); 483 return fTopView->CountChildren(); 484 } 485 486 487 BView * 488 BWindow::ChildAt(int32 index) const 489 { 490 BAutolock _(const_cast<BWindow*>(this)); 491 return fTopView->ChildAt(index); 492 } 493 494 495 void 496 BWindow::Minimize(bool minimize) 497 { 498 if (IsModal() || IsFloating() || fMinimized == minimize || !Lock()) 499 return; 500 501 fMinimized = minimize; 502 503 fLink->StartMessage(AS_MINIMIZE_WINDOW); 504 fLink->Attach<bool>(minimize); 505 fLink->Attach<int32>(fShowLevel); 506 fLink->Flush(); 507 508 Unlock(); 509 } 510 511 512 status_t 513 BWindow::SendBehind(const BWindow *window) 514 { 515 if (!window || !Lock()) 516 return B_ERROR; 517 518 fLink->StartMessage(AS_SEND_BEHIND); 519 fLink->Attach<int32>(_get_object_token_(window)); 520 fLink->Attach<team_id>(Team()); 521 522 status_t status = B_ERROR; 523 fLink->FlushWithReply(status); 524 525 Unlock(); 526 527 return status; 528 } 529 530 531 void 532 BWindow::Flush() const 533 { 534 if (const_cast<BWindow *>(this)->Lock()) { 535 fLink->Flush(); 536 const_cast<BWindow *>(this)->Unlock(); 537 } 538 } 539 540 541 void 542 BWindow::Sync() const 543 { 544 if (!const_cast<BWindow*>(this)->Lock()) 545 return; 546 547 fLink->StartMessage(AS_SYNC); 548 549 // waiting for the reply is the actual syncing 550 int32 code; 551 fLink->FlushWithReply(code); 552 553 const_cast<BWindow*>(this)->Unlock(); 554 } 555 556 557 void 558 BWindow::DisableUpdates() 559 { 560 if (Lock()) { 561 fLink->StartMessage(AS_DISABLE_UPDATES); 562 fLink->Flush(); 563 Unlock(); 564 } 565 } 566 567 568 void 569 BWindow::EnableUpdates() 570 { 571 if (Lock()) { 572 fLink->StartMessage(AS_ENABLE_UPDATES); 573 fLink->Flush(); 574 Unlock(); 575 } 576 } 577 578 579 void 580 BWindow::BeginViewTransaction() 581 { 582 if (Lock()) { 583 if (fInTransaction) { 584 Unlock(); 585 return; 586 } 587 fInTransaction = true; 588 589 Unlock(); 590 } 591 } 592 593 594 void 595 BWindow::EndViewTransaction() 596 { 597 if (Lock()) { 598 if (!fInTransaction) { 599 Unlock(); 600 return; 601 } 602 fLink->Flush(); 603 fInTransaction = false; 604 605 Unlock(); 606 } 607 } 608 609 610 bool 611 BWindow::IsFront() const 612 { 613 if (IsActive()) 614 return true; 615 616 if (IsModal()) 617 return true; 618 619 return false; 620 } 621 622 623 void 624 BWindow::MessageReceived(BMessage *msg) 625 { 626 if (!msg->HasSpecifiers()) { 627 if (msg->what == B_KEY_DOWN) 628 _KeyboardNavigation(); 629 630 return BLooper::MessageReceived(msg); 631 } 632 633 BMessage replyMsg(B_REPLY); 634 bool handled = false; 635 636 switch (msg->what) { 637 case B_GET_PROPERTY: 638 case B_SET_PROPERTY: { 639 BMessage specifier; 640 int32 what; 641 const char *prop; 642 int32 index; 643 644 if (msg->GetCurrentSpecifier(&index, &specifier, &what, &prop) != B_OK) 645 break; 646 647 if (!strcmp(prop, "Feel")) { 648 if (msg->what == B_GET_PROPERTY) { 649 replyMsg.AddInt32("result", (uint32)Feel()); 650 handled = true; 651 } else { 652 uint32 newFeel; 653 if (msg->FindInt32("data", (int32 *)&newFeel) == B_OK) { 654 SetFeel((window_feel)newFeel); 655 handled = true; 656 } 657 } 658 } else if (!strcmp(prop, "Flags")) { 659 if (msg->what == B_GET_PROPERTY) { 660 replyMsg.AddInt32("result", Flags()); 661 handled = true; 662 } else { 663 uint32 newFlags; 664 if (msg->FindInt32("data", (int32 *)&newFlags) == B_OK) { 665 SetFlags(newFlags); 666 handled = true; 667 } 668 } 669 } else if (!strcmp(prop, "Frame")) { 670 if (msg->what == B_GET_PROPERTY) { 671 replyMsg.AddRect("result", Frame()); 672 handled = true; 673 } else { 674 BRect newFrame; 675 if (msg->FindRect("data", &newFrame) == B_OK) { 676 MoveTo(newFrame.LeftTop()); 677 ResizeTo(newFrame.Width(), newFrame.Height()); 678 handled = true; 679 } 680 } 681 } else if (!strcmp(prop, "Hidden")) { 682 if (msg->what == B_GET_PROPERTY) { 683 replyMsg.AddBool("result", IsHidden()); 684 handled = true; 685 } else { 686 bool hide; 687 if (msg->FindBool("data", &hide) == B_OK) { 688 if (hide) { 689 if (!IsHidden()) 690 Hide(); 691 } else if (IsHidden()) 692 Show(); 693 694 handled = true; 695 } 696 } 697 } else if (!strcmp(prop, "Look")) { 698 if (msg->what == B_GET_PROPERTY) { 699 replyMsg.AddInt32("result", (uint32)Look()); 700 handled = true; 701 } else { 702 uint32 newLook; 703 if (msg->FindInt32("data", (int32 *)&newLook) == B_OK) { 704 SetLook((window_look)newLook); 705 handled = true; 706 } 707 } 708 } else if (!strcmp(prop, "Title")) { 709 if (msg->what == B_GET_PROPERTY) { 710 replyMsg.AddString("result", Title()); 711 handled = true; 712 } else { 713 const char *newTitle = NULL; 714 if (msg->FindString("data", &newTitle) == B_OK) { 715 SetTitle(newTitle); 716 handled = true; 717 } 718 } 719 } else if (!strcmp(prop, "Workspaces")) { 720 if (msg->what == B_GET_PROPERTY) { 721 replyMsg.AddInt32( "result", Workspaces()); 722 handled = true; 723 } else { 724 uint32 newWorkspaces; 725 if (msg->FindInt32("data", (int32 *)&newWorkspaces) == B_OK) { 726 SetWorkspaces(newWorkspaces); 727 handled = true; 728 } 729 } 730 } else if (!strcmp(prop, "Minimize")) { 731 if (msg->what == B_GET_PROPERTY) { 732 replyMsg.AddBool("result", IsMinimized()); 733 handled = true; 734 } else { 735 bool minimize; 736 if (msg->FindBool("data", &minimize) == B_OK) { 737 Minimize(minimize); 738 handled = true; 739 } 740 } 741 } 742 break; 743 } 744 } 745 746 if (handled) { 747 if (msg->what == B_SET_PROPERTY) 748 replyMsg.AddInt32("error", B_OK); 749 } else { 750 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD; 751 replyMsg.AddInt32("error", B_BAD_SCRIPT_SYNTAX); 752 replyMsg.AddString("message", "Didn't understand the specifier(s)"); 753 } 754 msg->SendReply(&replyMsg); 755 } 756 757 758 void 759 BWindow::DispatchMessage(BMessage *msg, BHandler *target) 760 { 761 if (!msg) 762 return; 763 764 switch (msg->what) { 765 case B_ZOOM: 766 Zoom(); 767 break; 768 769 case B_MINIMIZE: 770 { 771 bool minimize; 772 if (msg->FindBool("minimize", &minimize) == B_OK) 773 Minimize(minimize); 774 break; 775 } 776 777 case B_WINDOW_RESIZED: 778 { 779 int32 width, height; 780 if (msg->FindInt32("width", &width) == B_OK 781 && msg->FindInt32("height", &height) == B_OK) { 782 // combine with pending resize notifications 783 BMessage* pendingMessage; 784 while ((pendingMessage = MessageQueue()->FindMessage(B_WINDOW_RESIZED, 0))) { 785 if (pendingMessage != msg) { 786 int32 nextWidth; 787 if (pendingMessage->FindInt32("width", &nextWidth) == B_OK) 788 width = nextWidth; 789 790 int32 nextHeight; 791 if (pendingMessage->FindInt32("height", &nextHeight) == B_OK) 792 height = nextHeight; 793 794 MessageQueue()->RemoveMessage(pendingMessage); 795 // TODO: the BeBook says that MessageQueue::RemoveMessage() deletes the message! 796 delete pendingMessage; 797 // this deletes the first *additional* message 798 // fCurrentMessage is safe 799 } else { 800 MessageQueue()->RemoveMessage(pendingMessage); 801 } 802 } 803 if (width != fFrame.Width() || height != fFrame.Height()) { 804 // NOTE: we might have already handled the resize 805 // in an _UPDATE_ message 806 fFrame.right = fFrame.left + width; 807 fFrame.bottom = fFrame.top + height; 808 809 _AdoptResize(); 810 // FrameResized(width, height); 811 } 812 // call hook function anyways 813 // TODO: When a window is resized programmatically, 814 // it receives this message, and maybe it is wise to 815 // keep the asynchronous nature of this process to 816 // not risk breaking any apps. 817 FrameResized(width, height); 818 } 819 break; 820 } 821 822 case B_WINDOW_MOVED: 823 { 824 BPoint origin; 825 if (msg->FindPoint("where", &origin) == B_OK) { 826 if (fFrame.LeftTop() != origin) { 827 // NOTE: we might have already handled the move 828 // in an _UPDATE_ message 829 fFrame.OffsetTo(origin); 830 831 // FrameMoved(origin); 832 } 833 // call hook function anyways 834 // TODO: When a window is moved programmatically, 835 // it receives this message, and maybe it is wise to 836 // keep the asynchronous nature of this process to 837 // not risk breaking any apps. 838 FrameMoved(origin); 839 } 840 break; 841 } 842 843 case B_WINDOW_ACTIVATED: 844 if (target == this) { 845 bool active; 846 if (msg->FindBool("active", &active) == B_OK 847 && active != fActive) { 848 fActive = active; 849 WindowActivated(active); 850 851 // call hook function 'WindowActivated(bool)' for all 852 // views attached to this window. 853 fTopView->_Activate(active); 854 } 855 } else 856 target->MessageReceived(msg); 857 break; 858 859 case B_SCREEN_CHANGED: 860 if (target == this) { 861 BRect frame; 862 uint32 mode; 863 if (msg->FindRect("frame", &frame) == B_OK 864 && msg->FindInt32("mode", (int32 *)&mode) == B_OK) 865 ScreenChanged(frame, (color_space)mode); 866 } else 867 target->MessageReceived(msg); 868 break; 869 870 case B_WORKSPACE_ACTIVATED: 871 if (target == this) { 872 uint32 workspace; 873 bool active; 874 if (msg->FindInt32("workspace", (int32 *)&workspace) == B_OK 875 && msg->FindBool("active", &active) == B_OK) 876 WorkspaceActivated(workspace, active); 877 } else 878 target->MessageReceived(msg); 879 break; 880 881 case B_WORKSPACES_CHANGED: 882 if (target == this) { 883 uint32 oldWorkspace, newWorkspace; 884 if (msg->FindInt32("old", (int32 *)&oldWorkspace) == B_OK 885 && msg->FindInt32("new", (int32 *)&newWorkspace) == B_OK) 886 WorkspacesChanged(oldWorkspace, newWorkspace); 887 } else 888 target->MessageReceived(msg); 889 break; 890 891 case B_KEY_DOWN: 892 { 893 uint32 modifiers; 894 int32 rawChar; 895 const char *string = NULL; 896 msg->FindInt32("modifiers", (int32*)&modifiers); 897 msg->FindInt32("raw_char", &rawChar); 898 msg->FindString("bytes", &string); 899 900 // TODO: cannot use "string" here if we support having different 901 // font encoding per view (it's supposed to be converted by 902 // _HandleKeyDown() one day) 903 if (!_HandleKeyDown(string[0], (uint32)modifiers)) { 904 if (BView* view = dynamic_cast<BView*>(target)) 905 view->KeyDown(string, strlen(string)); 906 else 907 target->MessageReceived(msg); 908 } 909 break; 910 } 911 912 case B_KEY_UP: 913 { 914 const char *string = NULL; 915 msg->FindString("bytes", &string); 916 917 // TODO: same as above 918 if (BView* view = dynamic_cast<BView*>(target)) 919 view->KeyUp(string, strlen(string)); 920 else 921 target->MessageReceived(msg); 922 break; 923 } 924 925 case B_MOUSE_DOWN: 926 { 927 BView *view = dynamic_cast<BView *>(target); 928 929 // Close an eventually opened menu, unless the target is the menu itself 930 BMenu *menu = dynamic_cast<BMenu *>(fFocus); 931 if (menu != NULL && menu != view) 932 menu->QuitTracking(); 933 934 if (view != NULL) { 935 BPoint where; 936 msg->FindPoint("be:view_where", &where); 937 view->MouseDown(where); 938 } else 939 target->MessageReceived(msg); 940 941 break; 942 } 943 944 case B_MOUSE_UP: 945 { 946 if (BView *view = dynamic_cast<BView *>(target)) { 947 BPoint where; 948 msg->FindPoint("be:view_where", &where); 949 view->MouseUp(where); 950 } else 951 target->MessageReceived(msg); 952 953 break; 954 } 955 956 case B_MOUSE_MOVED: 957 { 958 if (BView *view = dynamic_cast<BView *>(target)) { 959 BPoint where; 960 uint32 buttons; 961 uint32 transit; 962 msg->FindPoint("be:view_where", &where); 963 msg->FindInt32("buttons", (int32*)&buttons); 964 msg->FindInt32("be:transit", (int32*)&transit); 965 966 #if 0 967 bigtime_t when; 968 if (msg->FindInt64("when", (int64*)&when) < B_OK) 969 printf("BWindow B_MOUSE_MOVED no when\n"); 970 else if (system_time() - when > 5000) 971 printf("BWindow B_MOUSE_MOVED lagging behind\n"); 972 #endif 973 974 BMessage* dragMessage = NULL; 975 if (msg->HasMessage("be:drag_message")) { 976 dragMessage = new BMessage(); 977 if (msg->FindMessage("be:drag_message", dragMessage) != B_OK) { 978 delete dragMessage; 979 dragMessage = NULL; 980 } 981 } 982 983 view->MouseMoved(where, transit, dragMessage); 984 delete dragMessage; 985 } else 986 target->MessageReceived(msg); 987 988 break; 989 } 990 991 case B_PULSE: 992 if (target == this && fPulseRunner) { 993 fTopView->_Pulse(); 994 fLink->Flush(); 995 } else 996 target->MessageReceived(msg); 997 break; 998 999 case _UPDATE_: 1000 { 1001 //bigtime_t now = system_time(); 1002 STRACE(("info:BWindow handling _UPDATE_.\n")); 1003 BRect updateRect; 1004 1005 fLink->StartMessage(AS_BEGIN_UPDATE); 1006 fInTransaction = true; 1007 1008 int32 code; 1009 if (fLink->FlushWithReply(code) == B_OK 1010 && code == B_OK) { 1011 // read current window position and size first, 1012 // the update rect is in screen coordinates... 1013 // so we need to be up to date 1014 BPoint origin; 1015 fLink->Read<BPoint>(&origin); 1016 float width; 1017 float height; 1018 fLink->Read<float>(&width); 1019 fLink->Read<float>(&height); 1020 if (origin != fFrame.LeftTop()) { 1021 // TODO: remove code duplicatation with 1022 // B_WINDOW_MOVED case... 1023 //printf("window position was not up to date\n"); 1024 fFrame.OffsetTo(origin); 1025 FrameMoved(origin); 1026 } 1027 if (width != fFrame.Width() || height != fFrame.Height()) { 1028 // TODO: remove code duplicatation with 1029 // B_WINDOW_RESIZED case... 1030 //printf("window size was not up to date\n"); 1031 fFrame.right = fFrame.left + width; 1032 fFrame.bottom = fFrame.top + height; 1033 1034 _AdoptResize(); 1035 FrameResized(width, height); 1036 } 1037 1038 // read culmulated update rect (is in screen coords) 1039 fLink->Read<BRect>(&updateRect); 1040 1041 // read tokens for views that need to be drawn 1042 // NOTE: we need to read the tokens completely 1043 // first, or other calls would likely mess up the 1044 // data in the link. 1045 BList tokens(20); 1046 int32 token; 1047 status_t error = fLink->Read<int32>(&token); 1048 while (error >= B_OK && token != B_NULL_TOKEN) { 1049 tokens.AddItem((void*)token); 1050 error = fLink->Read<int32>(&token); 1051 } 1052 // draw 1053 int32 count = tokens.CountItems(); 1054 for (int32 i = 0; i < count; i++) { 1055 if (BView* view = _FindView((int32)tokens.ItemAtFast(i))) 1056 view->_Draw(updateRect); 1057 else 1058 printf("_UPDATE_ - didn't find view by token: %ld\n", (int32)tokens.ItemAtFast(i)); 1059 } 1060 // TODO: the tokens are actually hirachically sorted, 1061 // so traversing the list in revers and calling 1062 // child->DrawAfterChildren would actually work correctly, 1063 // only that drawing outside a view is not yet supported 1064 // in the app_server. 1065 } 1066 1067 fLink->StartMessage(AS_END_UPDATE); 1068 fLink->Flush(); 1069 fInTransaction = false; 1070 1071 //printf("BWindow(%s) - UPDATE took %lld usecs\n", Title(), system_time() - now); 1072 break; 1073 } 1074 1075 case _MENUS_DONE_: 1076 MenusEnded(); 1077 break; 1078 1079 // These two are obviously some kind of old scripting messages 1080 // this is NOT an app_server message and we have to be cautious 1081 case B_WINDOW_MOVE_BY: 1082 { 1083 BPoint offset; 1084 if (msg->FindPoint("data", &offset) == B_OK) 1085 MoveBy(offset.x, offset.y); 1086 else 1087 msg->SendReply(B_MESSAGE_NOT_UNDERSTOOD); 1088 break; 1089 } 1090 1091 // this is NOT an app_server message and we have to be cautious 1092 case B_WINDOW_MOVE_TO: 1093 { 1094 BPoint origin; 1095 if (msg->FindPoint("data", &origin) == B_OK) 1096 MoveTo(origin); 1097 else 1098 msg->SendReply(B_MESSAGE_NOT_UNDERSTOOD); 1099 break; 1100 } 1101 case _MESSAGE_DROPPED_: 1102 { 1103 if (fLastMouseMovedView) 1104 target = fLastMouseMovedView; 1105 1106 uint32 originalWhat; 1107 if (msg->FindInt32("_original_what", (int32*)&originalWhat) == B_OK) { 1108 msg->what = originalWhat; 1109 msg->RemoveName("_original_what"); 1110 } 1111 1112 BLooper::DispatchMessage(msg, target); 1113 break; 1114 } 1115 1116 default: 1117 BLooper::DispatchMessage(msg, target); 1118 break; 1119 } 1120 } 1121 1122 1123 void 1124 BWindow::FrameMoved(BPoint new_position) 1125 { 1126 // does nothing 1127 // Hook function 1128 } 1129 1130 1131 void 1132 BWindow::FrameResized(float new_width, float new_height) 1133 { 1134 // does nothing 1135 // Hook function 1136 } 1137 1138 1139 void 1140 BWindow::WorkspacesChanged(uint32 old_ws, uint32 new_ws) 1141 { 1142 // does nothing 1143 // Hook function 1144 } 1145 1146 1147 void 1148 BWindow::WorkspaceActivated(int32 ws, bool state) 1149 { 1150 // does nothing 1151 // Hook function 1152 } 1153 1154 1155 void 1156 BWindow::MenusBeginning() 1157 { 1158 // does nothing 1159 // Hook function 1160 } 1161 1162 1163 void 1164 BWindow::MenusEnded() 1165 { 1166 // does nothing 1167 // Hook function 1168 } 1169 1170 1171 void 1172 BWindow::SetSizeLimits(float minWidth, float maxWidth, 1173 float minHeight, float maxHeight) 1174 { 1175 if (minWidth > maxWidth || minHeight > maxHeight) 1176 return; 1177 1178 if (!Lock()) 1179 return; 1180 1181 fLink->StartMessage(AS_SET_SIZE_LIMITS); 1182 fLink->Attach<float>(minWidth); 1183 fLink->Attach<float>(maxWidth); 1184 fLink->Attach<float>(minHeight); 1185 fLink->Attach<float>(maxHeight); 1186 1187 int32 code; 1188 if (fLink->FlushWithReply(code) == B_OK 1189 && code == B_OK) { 1190 // read the values that were really enforced on 1191 // the server side (the window frame could have 1192 // been changed, too) 1193 fLink->Read<BRect>(&fFrame); 1194 fLink->Read<float>(&fMinWidth); 1195 fLink->Read<float>(&fMaxWidth); 1196 fLink->Read<float>(&fMinHeight); 1197 fLink->Read<float>(&fMaxHeight); 1198 1199 _AdoptResize(); 1200 // TODO: the same has to be done for SetLook() (that can alter 1201 // the size limits, and hence, the size of the window 1202 } 1203 Unlock(); 1204 } 1205 1206 1207 void 1208 BWindow::GetSizeLimits(float *minWidth, float *maxWidth, 1209 float *minHeight, float *maxHeight) 1210 { 1211 // TODO: What about locking?!? 1212 *minHeight = fMinHeight; 1213 *minWidth = fMinWidth; 1214 *maxHeight = fMaxHeight; 1215 *maxWidth = fMaxWidth; 1216 } 1217 1218 1219 status_t 1220 BWindow::SetDecoratorSettings(const BMessage& settings) 1221 { 1222 // flatten the given settings into a buffer and send 1223 // it to the app_server to apply the settings to the 1224 // decorator 1225 1226 int32 size = settings.FlattenedSize(); 1227 char buffer[size]; 1228 status_t ret = settings.Flatten(buffer, size); 1229 1230 if (ret < B_OK) 1231 return ret; 1232 1233 if (!Lock()) 1234 return B_ERROR; 1235 1236 ret = fLink->StartMessage(AS_SET_DECORATOR_SETTINGS); 1237 1238 if (ret == B_OK) 1239 ret = fLink->Attach<int32>(size); 1240 1241 if (ret == B_OK) 1242 ret = fLink->Attach(buffer, size); 1243 1244 if (ret == B_OK) 1245 ret = fLink->Flush(); 1246 1247 Unlock(); 1248 1249 return ret; 1250 } 1251 1252 1253 status_t 1254 BWindow::GetDecoratorSettings(BMessage* settings) const 1255 { 1256 // read a flattened settings message from the app_server 1257 // and put it into settings 1258 1259 if (!const_cast<BWindow*>(this)->Lock()) 1260 return B_ERROR; 1261 1262 status_t ret = fLink->StartMessage(AS_GET_DECORATOR_SETTINGS); 1263 1264 if (ret == B_OK) { 1265 int32 code; 1266 ret = fLink->FlushWithReply(code); 1267 if (ret == B_OK && code != B_OK) 1268 ret = code; 1269 } 1270 1271 if (ret == B_OK) { 1272 int32 size; 1273 ret = fLink->Read<int32>(&size); 1274 if (ret == B_OK) { 1275 char buffer[size]; 1276 ret = fLink->Read(buffer, size); 1277 if (ret == B_OK) { 1278 ret = settings->Unflatten(buffer); 1279 } 1280 } 1281 } 1282 1283 const_cast<BWindow*>(this)->Unlock(); 1284 1285 return ret; 1286 } 1287 1288 1289 void 1290 BWindow::SetZoomLimits(float maxWidth, float maxHeight) 1291 { 1292 // TODO: What about locking?!? 1293 if (maxWidth > fMaxWidth) 1294 maxWidth = fMaxWidth; 1295 else 1296 fMaxZoomWidth = maxWidth; 1297 1298 if (maxHeight > fMaxHeight) 1299 maxHeight = fMaxHeight; 1300 else 1301 fMaxZoomHeight = maxHeight; 1302 } 1303 1304 1305 void 1306 BWindow::Zoom(BPoint leftTop, float width, float height) 1307 { 1308 // the default implementation of this hook function 1309 // just does the obvious: 1310 MoveTo(leftTop); 1311 ResizeTo(width, height); 1312 } 1313 1314 1315 void 1316 BWindow::Zoom() 1317 { 1318 // TODO: What about locking?!? 1319 /* 1320 from BeBook: 1321 However, if the window's rectangle already matches these "zoom" dimensions 1322 (give or take a few pixels), Zoom() passes the window's previous 1323 ("non-zoomed") size and location. (??????) 1324 */ 1325 1326 /* From BeBook: 1327 The dimensions that non-virtual Zoom() passes to hook Zoom() are deduced from 1328 the smallest of three rectangles: 1329 */ 1330 1331 // TODO: make more elaborate (figure out this window's 1332 // tab height and border width... maybe ask app_server) 1333 float borderWidth = 5.0; 1334 float tabHeight = 26.0; 1335 1336 // 1) the rectangle defined by SetZoomLimits(), 1337 float zoomedWidth = fMaxZoomWidth; 1338 float zoomedHeight = fMaxZoomHeight; 1339 1340 // 2) the rectangle defined by SetSizeLimits() 1341 if (fMaxWidth < zoomedWidth) 1342 zoomedWidth = fMaxWidth; 1343 if (fMaxHeight < zoomedHeight) 1344 zoomedHeight = fMaxHeight; 1345 1346 // 3) the screen rectangle 1347 BScreen screen(this); 1348 float screenWidth = screen.Frame().Width() - 2 * borderWidth; 1349 float screenHeight = screen.Frame().Height() - (borderWidth + tabHeight); 1350 if (screenWidth < zoomedWidth) 1351 zoomedWidth = screenWidth; 1352 if (screenHeight < zoomedHeight) 1353 zoomedHeight = screenHeight; 1354 1355 BPoint zoomedLeftTop = screen.Frame().LeftTop() + BPoint(borderWidth, tabHeight); 1356 1357 // UN-ZOOM: 1358 if (fPreviousFrame.IsValid() 1359 // NOTE: don't check for fFrame.LeftTop() == zoomedLeftTop 1360 // -> makes it easier on the user to get a window back into place 1361 && fFrame.Width() == zoomedWidth 1362 && fFrame.Height() == zoomedHeight) { 1363 // already zoomed! 1364 Zoom(fPreviousFrame.LeftTop(), fPreviousFrame.Width(), fPreviousFrame.Height()); 1365 return; 1366 } 1367 1368 // ZOOM: 1369 1370 // remember fFrame for later "unzooming" 1371 fPreviousFrame = fFrame; 1372 1373 Zoom(zoomedLeftTop, zoomedWidth, zoomedHeight); 1374 } 1375 1376 1377 void 1378 BWindow::ScreenChanged(BRect screen_size, color_space depth) 1379 { 1380 // Hook function 1381 // does nothing 1382 } 1383 1384 1385 void 1386 BWindow::SetPulseRate(bigtime_t rate) 1387 { 1388 // TODO: What about locking?!? 1389 if (rate < 0 || rate == fPulseRate) 1390 return; 1391 1392 fPulseRate = rate; 1393 1394 if (rate > 0) { 1395 if (fPulseRunner == NULL) { 1396 BMessage message(B_PULSE); 1397 fPulseRunner = new BMessageRunner(BMessenger(this), 1398 &message, rate); 1399 } else { 1400 fPulseRunner->SetInterval(rate); 1401 } 1402 } else { 1403 // rate == 0 1404 delete fPulseRunner; 1405 fPulseRunner = NULL; 1406 } 1407 } 1408 1409 1410 bigtime_t 1411 BWindow::PulseRate() const 1412 { 1413 // TODO: What about locking?!? 1414 return fPulseRate; 1415 } 1416 1417 1418 void 1419 BWindow::AddShortcut(uint32 key, uint32 modifiers, BMenuItem *item) 1420 { 1421 Shortcut* shortcut = new Shortcut(key, modifiers, item); 1422 1423 // removes the shortcut if it already exists! 1424 RemoveShortcut(key, modifiers); 1425 1426 fShortcuts.AddItem(shortcut); 1427 } 1428 1429 1430 void 1431 BWindow::AddShortcut(uint32 key, uint32 modifiers, BMessage *message) 1432 { 1433 AddShortcut(key, modifiers, message, this); 1434 } 1435 1436 1437 void 1438 BWindow::AddShortcut(uint32 key, uint32 modifiers, BMessage *message, BHandler *target) 1439 { 1440 if (message == NULL) 1441 return; 1442 1443 Shortcut* shortcut = new Shortcut(key, modifiers, message, target); 1444 1445 // removes the shortcut if it already exists! 1446 RemoveShortcut(key, modifiers); 1447 1448 fShortcuts.AddItem(shortcut); 1449 } 1450 1451 1452 void 1453 BWindow::RemoveShortcut(uint32 key, uint32 modifiers) 1454 { 1455 Shortcut* shortcut = _FindShortcut(key, modifiers); 1456 if (shortcut != NULL) { 1457 fShortcuts.RemoveItem(shortcut); 1458 delete shortcut; 1459 } else if ((key == 'q' || key == 'Q') && modifiers == B_COMMAND_KEY) { 1460 // the quit shortcut is a fake shortcut 1461 fNoQuitShortcut = true; 1462 } 1463 } 1464 1465 1466 BButton * 1467 BWindow::DefaultButton() const 1468 { 1469 // TODO: What about locking?!? 1470 return fDefaultButton; 1471 } 1472 1473 1474 void 1475 BWindow::SetDefaultButton(BButton *button) 1476 { 1477 // TODO: What about locking?!? 1478 if (fDefaultButton == button) 1479 return; 1480 1481 if (fDefaultButton != NULL) { 1482 // tell old button it's no longer the default one 1483 BButton *oldDefault = fDefaultButton; 1484 oldDefault->MakeDefault(false); 1485 oldDefault->Invalidate(); 1486 } 1487 1488 fDefaultButton = button; 1489 1490 if (button != NULL) { 1491 // notify new default button 1492 fDefaultButton->MakeDefault(true); 1493 fDefaultButton->Invalidate(); 1494 } 1495 } 1496 1497 1498 bool 1499 BWindow::NeedsUpdate() const 1500 { 1501 if (!const_cast<BWindow *>(this)->Lock()) 1502 return false; 1503 1504 fLink->StartMessage(AS_NEEDS_UPDATE); 1505 1506 int32 code = B_ERROR; 1507 fLink->FlushWithReply(code); 1508 1509 const_cast<BWindow *>(this)->Unlock(); 1510 1511 return code == B_OK; 1512 } 1513 1514 1515 void 1516 BWindow::UpdateIfNeeded() 1517 { 1518 // works only from the window thread 1519 if (find_thread(NULL) != Thread()) 1520 return; 1521 1522 // if the queue is already locked we are called recursivly 1523 // from our own dispatched update message 1524 if (((const BMessageQueue *)MessageQueue())->IsLocked()) 1525 return; 1526 1527 // make sure all requests that would cause an update have 1528 // arrived at the server 1529 Sync(); 1530 1531 // Since we're blocking the event loop, we need to retrieve 1532 // all messages that are pending on the port. 1533 _DequeueAll(); 1534 1535 BMessageQueue *queue = MessageQueue(); 1536 queue->Lock(); 1537 1538 // First process and remove any _UPDATE_ message in the queue 1539 // With the current design, there can only be one at a time 1540 1541 BMessage *msg; 1542 for (int32 i = 0; (msg = queue->FindMessage(i)) != NULL; i++) { 1543 if (msg->what == _UPDATE_) { 1544 BWindow::DispatchMessage(msg, this); 1545 // we need to make sure that no overridden method is called 1546 // here; for BWindow::DispatchMessage() we now exactly what 1547 // will happen 1548 queue->RemoveMessage(msg); 1549 delete msg; 1550 break; 1551 // NOTE: "i" would have to be decreased if there were 1552 // multiple _UPDATE_ messages and we would not break! 1553 } 1554 } 1555 1556 queue->Unlock(); 1557 } 1558 1559 1560 BView * 1561 BWindow::FindView(const char *viewName) const 1562 { 1563 BAutolock _(const_cast<BWindow*>(this)); 1564 return fTopView->FindView(viewName); 1565 } 1566 1567 1568 BView * 1569 BWindow::FindView(BPoint point) const 1570 { 1571 BAutolock _(const_cast<BWindow*>(this)); 1572 return _FindView(fTopView, point); 1573 } 1574 1575 1576 BView * 1577 BWindow::CurrentFocus() const 1578 { 1579 return fFocus; 1580 } 1581 1582 1583 void 1584 BWindow::Activate(bool active) 1585 { 1586 if (!Lock()) 1587 return; 1588 1589 if (!IsHidden()) { 1590 fLink->StartMessage(AS_ACTIVATE_WINDOW); 1591 fLink->Attach<bool>(active); 1592 fLink->Flush(); 1593 } 1594 1595 Unlock(); 1596 } 1597 1598 1599 void 1600 BWindow::WindowActivated(bool state) 1601 { 1602 // hook function 1603 // does nothing 1604 } 1605 1606 1607 void 1608 BWindow::ConvertToScreen(BPoint *point) const 1609 { 1610 point->x += fFrame.left; 1611 point->y += fFrame.top; 1612 } 1613 1614 1615 BPoint 1616 BWindow::ConvertToScreen(BPoint point) const 1617 { 1618 return point + fFrame.LeftTop(); 1619 } 1620 1621 1622 void 1623 BWindow::ConvertFromScreen(BPoint *point) const 1624 { 1625 point->x -= fFrame.left; 1626 point->y -= fFrame.top; 1627 } 1628 1629 1630 BPoint 1631 BWindow::ConvertFromScreen(BPoint point) const 1632 { 1633 return point - fFrame.LeftTop(); 1634 } 1635 1636 1637 void 1638 BWindow::ConvertToScreen(BRect *rect) const 1639 { 1640 rect->OffsetBy(fFrame.LeftTop()); 1641 } 1642 1643 1644 BRect 1645 BWindow::ConvertToScreen(BRect rect) const 1646 { 1647 return rect.OffsetByCopy(fFrame.LeftTop()); 1648 } 1649 1650 1651 void 1652 BWindow::ConvertFromScreen(BRect* rect) const 1653 { 1654 rect->OffsetBy(-fFrame.left, -fFrame.top); 1655 } 1656 1657 1658 BRect 1659 BWindow::ConvertFromScreen(BRect rect) const 1660 { 1661 return rect.OffsetByCopy(-fFrame.left, -fFrame.top); 1662 } 1663 1664 1665 bool 1666 BWindow::IsMinimized() const 1667 { 1668 // Hiding takes precendence over minimization!!! 1669 if (IsHidden()) 1670 return false; 1671 1672 return fMinimized; 1673 } 1674 1675 1676 BRect 1677 BWindow::Bounds() const 1678 { 1679 return BRect(0, 0, fFrame.Width(), fFrame.Height()); 1680 } 1681 1682 1683 BRect 1684 BWindow::Frame() const 1685 { 1686 return fFrame; 1687 } 1688 1689 1690 const char * 1691 BWindow::Title() const 1692 { 1693 return fTitle; 1694 } 1695 1696 1697 void 1698 BWindow::SetTitle(const char *title) 1699 { 1700 if (title == NULL) 1701 title = ""; 1702 1703 free(fTitle); 1704 fTitle = strdup(title); 1705 1706 // we will change BWindow's thread name to "w>window title" 1707 1708 char threadName[B_OS_NAME_LENGTH]; 1709 strcpy(threadName, "w>"); 1710 #ifdef __HAIKU__ 1711 strlcat(threadName, title, B_OS_NAME_LENGTH); 1712 #else 1713 int32 length = strlen(title); 1714 length = min_c(length, B_OS_NAME_LENGTH - 3); 1715 memcpy(threadName + 2, title, length); 1716 threadName[length + 2] = '\0'; 1717 #endif 1718 1719 // change the handler's name 1720 SetName(threadName); 1721 1722 // if the message loop has been started... 1723 if (Thread() >= B_OK) 1724 rename_thread(Thread(), threadName); 1725 1726 // we notify the app_server so we can actually see the change 1727 if (Lock()) { 1728 fLink->StartMessage(AS_SET_WINDOW_TITLE); 1729 fLink->AttachString(fTitle); 1730 fLink->Flush(); 1731 Unlock(); 1732 } 1733 } 1734 1735 1736 bool 1737 BWindow::IsActive() const 1738 { 1739 return fActive; 1740 } 1741 1742 1743 void 1744 BWindow::SetKeyMenuBar(BMenuBar *bar) 1745 { 1746 fKeyMenuBar = bar; 1747 } 1748 1749 1750 BMenuBar * 1751 BWindow::KeyMenuBar() const 1752 { 1753 return fKeyMenuBar; 1754 } 1755 1756 1757 bool 1758 BWindow::IsModal() const 1759 { 1760 return fFeel == B_MODAL_SUBSET_WINDOW_FEEL 1761 || fFeel == B_MODAL_APP_WINDOW_FEEL 1762 || fFeel == B_MODAL_ALL_WINDOW_FEEL; 1763 } 1764 1765 1766 bool 1767 BWindow::IsFloating() const 1768 { 1769 return fFeel == B_FLOATING_SUBSET_WINDOW_FEEL 1770 || fFeel == B_FLOATING_APP_WINDOW_FEEL 1771 || fFeel == B_FLOATING_ALL_WINDOW_FEEL; 1772 } 1773 1774 1775 status_t 1776 BWindow::AddToSubset(BWindow *window) 1777 { 1778 if (window == NULL || window->Feel() != B_NORMAL_WINDOW_FEEL 1779 || (fFeel != B_MODAL_SUBSET_WINDOW_FEEL 1780 && fFeel != B_FLOATING_SUBSET_WINDOW_FEEL)) 1781 return B_BAD_VALUE; 1782 1783 if (!Lock()) 1784 return B_ERROR; 1785 1786 status_t status = B_ERROR; 1787 fLink->StartMessage(AS_ADD_TO_SUBSET); 1788 fLink->Attach<int32>(_get_object_token_(window)); 1789 fLink->FlushWithReply(status); 1790 1791 Unlock(); 1792 1793 return status; 1794 } 1795 1796 1797 status_t 1798 BWindow::RemoveFromSubset(BWindow *window) 1799 { 1800 if (window == NULL || window->Feel() != B_NORMAL_WINDOW_FEEL 1801 || (fFeel != B_MODAL_SUBSET_WINDOW_FEEL 1802 && fFeel != B_FLOATING_SUBSET_WINDOW_FEEL)) 1803 return B_BAD_VALUE; 1804 1805 if (!Lock()) 1806 return B_ERROR; 1807 1808 status_t status = B_ERROR; 1809 fLink->StartMessage(AS_REMOVE_FROM_SUBSET); 1810 fLink->Attach<int32>(_get_object_token_(window)); 1811 fLink->FlushWithReply(status); 1812 1813 Unlock(); 1814 1815 return status; 1816 } 1817 1818 1819 status_t 1820 BWindow::Perform(perform_code d, void *arg) 1821 { 1822 return BLooper::Perform(d, arg); 1823 } 1824 1825 1826 status_t 1827 BWindow::SetType(window_type type) 1828 { 1829 window_look look; 1830 window_feel feel; 1831 _DecomposeType(type, &look, &feel); 1832 1833 status_t status = SetLook(look); 1834 if (status == B_OK) 1835 status = SetFeel(feel); 1836 1837 return status; 1838 } 1839 1840 1841 window_type 1842 BWindow::Type() const 1843 { 1844 return _ComposeType(fLook, fFeel); 1845 } 1846 1847 1848 status_t 1849 BWindow::SetLook(window_look look) 1850 { 1851 BAutolock locker(this); 1852 1853 fLink->StartMessage(AS_SET_LOOK); 1854 fLink->Attach<int32>((int32)look); 1855 1856 status_t status = B_ERROR; 1857 if (fLink->FlushWithReply(status) == B_OK && status == B_OK) 1858 fLook = look; 1859 1860 // TODO: this could have changed the window size, and thus, we 1861 // need to get it from the server (and call _AdoptResize()). 1862 1863 return status; 1864 } 1865 1866 1867 window_look 1868 BWindow::Look() const 1869 { 1870 return fLook; 1871 } 1872 1873 1874 status_t 1875 BWindow::SetFeel(window_feel feel) 1876 { 1877 BAutolock locker(this); 1878 1879 fLink->StartMessage(AS_SET_FEEL); 1880 fLink->Attach<int32>((int32)feel); 1881 1882 status_t status = B_ERROR; 1883 if (fLink->FlushWithReply(status) == B_OK && status == B_OK) 1884 fFeel = feel; 1885 1886 return status; 1887 } 1888 1889 1890 window_feel 1891 BWindow::Feel() const 1892 { 1893 return fFeel; 1894 } 1895 1896 1897 status_t 1898 BWindow::SetFlags(uint32 flags) 1899 { 1900 BAutolock locker(this); 1901 1902 fLink->StartMessage(AS_SET_FLAGS); 1903 fLink->Attach<uint32>(flags); 1904 1905 int32 status = B_ERROR; 1906 if (fLink->FlushWithReply(status) == B_OK && status == B_OK) 1907 fFlags = flags; 1908 1909 return status; 1910 } 1911 1912 1913 uint32 1914 BWindow::Flags() const 1915 { 1916 return fFlags; 1917 } 1918 1919 1920 status_t 1921 BWindow::SetWindowAlignment(window_alignment mode, 1922 int32 h, int32 hOffset, int32 width, int32 widthOffset, 1923 int32 v, int32 vOffset, int32 height, int32 heightOffset) 1924 { 1925 if ((mode & (B_BYTE_ALIGNMENT | B_PIXEL_ALIGNMENT)) == 0 1926 || (hOffset >= 0 && hOffset <= h) 1927 || (vOffset >= 0 && vOffset <= v) 1928 || (widthOffset >= 0 && widthOffset <= width) 1929 || (heightOffset >= 0 && heightOffset <= height)) 1930 return B_BAD_VALUE; 1931 1932 // TODO: test if hOffset = 0 and set it to 1 if true. 1933 1934 if (!Lock()) 1935 return B_ERROR; 1936 1937 fLink->StartMessage(AS_SET_ALIGNMENT); 1938 fLink->Attach<int32>((int32)mode); 1939 fLink->Attach<int32>(h); 1940 fLink->Attach<int32>(hOffset); 1941 fLink->Attach<int32>(width); 1942 fLink->Attach<int32>(widthOffset); 1943 fLink->Attach<int32>(v); 1944 fLink->Attach<int32>(vOffset); 1945 fLink->Attach<int32>(height); 1946 fLink->Attach<int32>(heightOffset); 1947 1948 status_t status = B_ERROR; 1949 fLink->FlushWithReply(status); 1950 1951 Unlock(); 1952 1953 return status; 1954 } 1955 1956 1957 status_t 1958 BWindow::GetWindowAlignment(window_alignment *mode, 1959 int32 *h, int32 *hOffset, int32 *width, int32 *widthOffset, 1960 int32 *v, int32 *vOffset, int32 *height, int32 *heightOffset) const 1961 { 1962 if (!const_cast<BWindow *>(this)->Lock()) 1963 return B_ERROR; 1964 1965 fLink->StartMessage(AS_GET_ALIGNMENT); 1966 1967 status_t status; 1968 if (fLink->FlushWithReply(status) == B_OK && status == B_OK) { 1969 fLink->Read<int32>((int32 *)mode); 1970 fLink->Read<int32>(h); 1971 fLink->Read<int32>(hOffset); 1972 fLink->Read<int32>(width); 1973 fLink->Read<int32>(widthOffset); 1974 fLink->Read<int32>(v); 1975 fLink->Read<int32>(hOffset); 1976 fLink->Read<int32>(height); 1977 fLink->Read<int32>(heightOffset); 1978 } 1979 1980 const_cast<BWindow *>(this)->Unlock(); 1981 return status; 1982 } 1983 1984 1985 uint32 1986 BWindow::Workspaces() const 1987 { 1988 if (!const_cast<BWindow *>(this)->Lock()) 1989 return 0; 1990 1991 uint32 workspaces = 0; 1992 1993 fLink->StartMessage(AS_GET_WORKSPACES); 1994 1995 status_t status; 1996 if (fLink->FlushWithReply(status) == B_OK && status == B_OK) 1997 fLink->Read<uint32>(&workspaces); 1998 1999 const_cast<BWindow *>(this)->Unlock(); 2000 return workspaces; 2001 } 2002 2003 2004 void 2005 BWindow::SetWorkspaces(uint32 workspaces) 2006 { 2007 // TODO: don't forget about Tracker's background window. 2008 if (fFeel != B_NORMAL_WINDOW_FEEL) 2009 return; 2010 2011 if (Lock()) { 2012 fLink->StartMessage(AS_SET_WORKSPACES); 2013 fLink->Attach<uint32>(workspaces); 2014 fLink->Flush(); 2015 Unlock(); 2016 } 2017 } 2018 2019 2020 BView * 2021 BWindow::LastMouseMovedView() const 2022 { 2023 return fLastMouseMovedView; 2024 } 2025 2026 2027 void 2028 BWindow::MoveBy(float dx, float dy) 2029 { 2030 if ((dx == 0.0 && dy == 0.0) || !Lock()) 2031 return; 2032 2033 fLink->StartMessage(AS_WINDOW_MOVE); 2034 fLink->Attach<float>(dx); 2035 fLink->Attach<float>(dy); 2036 2037 status_t status; 2038 if (fLink->FlushWithReply(status) == B_OK && status == B_OK) 2039 fFrame.OffsetBy(dx, dy); 2040 2041 Unlock(); 2042 } 2043 2044 2045 void 2046 BWindow::MoveTo(BPoint point) 2047 { 2048 if (!Lock()) 2049 return; 2050 2051 point.x = roundf(point.x); 2052 point.y = roundf(point.y); 2053 2054 if (fFrame.left != point.x || fFrame.top != point.y) { 2055 float xOffset = point.x - fFrame.left; 2056 float yOffset = point.y - fFrame.top; 2057 2058 MoveBy(xOffset, yOffset); 2059 } 2060 2061 Unlock(); 2062 } 2063 2064 2065 void 2066 BWindow::MoveTo(float x, float y) 2067 { 2068 MoveTo(BPoint(x, y)); 2069 } 2070 2071 2072 void 2073 BWindow::ResizeBy(float dx, float dy) 2074 { 2075 if (!Lock()) 2076 return; 2077 2078 dx = roundf(dx); 2079 dy = roundf(dy); 2080 2081 // stay in minimum & maximum frame limits 2082 if (fFrame.Width() + dx < fMinWidth) 2083 dx = fMinWidth - fFrame.Width(); 2084 if (fFrame.Width() + dx > fMaxWidth) 2085 dx = fMaxWidth - fFrame.Width(); 2086 if (fFrame.Height() + dy < fMinHeight) 2087 dy = fMinHeight - fFrame.Height(); 2088 if (fFrame.Height() + dy > fMaxHeight) 2089 dy = fMaxHeight - fFrame.Height(); 2090 2091 if (dx != 0.0 || dy != 0.0) { 2092 fLink->StartMessage(AS_WINDOW_RESIZE); 2093 fLink->Attach<float>(dx); 2094 fLink->Attach<float>(dy); 2095 2096 status_t status; 2097 if (fLink->FlushWithReply(status) == B_OK && status == B_OK) { 2098 fFrame.SetRightBottom(fFrame.RightBottom() + BPoint(dx, dy)); 2099 _AdoptResize(); 2100 } 2101 } 2102 Unlock(); 2103 } 2104 2105 2106 void 2107 BWindow::ResizeTo(float width, float height) 2108 { 2109 if (Lock()) { 2110 ResizeBy(width - fFrame.Width(), height - fFrame.Height()); 2111 Unlock(); 2112 } 2113 } 2114 2115 2116 void 2117 BWindow::Show() 2118 { 2119 if (!fRunCalled) { 2120 // this is the fist time Show() is called, which implicetly runs the looper 2121 if (fLink->SenderPort() < B_OK) { 2122 // We don't have valid app_server connection; there is no point 2123 // in starting our looper 2124 fTaskID = B_ERROR; 2125 return; 2126 } else 2127 Run(); 2128 } 2129 2130 if (Lock()) { 2131 fShowLevel++; 2132 2133 if (fShowLevel == 1) { 2134 STRACE(("BWindow(%s): sending AS_SHOW_WINDOW message...\n", Name())); 2135 fLink->StartMessage(AS_SHOW_WINDOW); 2136 fLink->Flush(); 2137 } 2138 2139 Unlock(); 2140 } 2141 } 2142 2143 2144 void 2145 BWindow::Hide() 2146 { 2147 if (!Lock()) 2148 return; 2149 2150 if (--fShowLevel == 0) { 2151 fLink->StartMessage(AS_HIDE_WINDOW); 2152 fLink->Flush(); 2153 } 2154 2155 Unlock(); 2156 } 2157 2158 2159 bool 2160 BWindow::IsHidden() const 2161 { 2162 return fShowLevel <= 0; 2163 } 2164 2165 2166 bool 2167 BWindow::QuitRequested() 2168 { 2169 return BLooper::QuitRequested(); 2170 } 2171 2172 2173 thread_id 2174 BWindow::Run() 2175 { 2176 return BLooper::Run(); 2177 } 2178 2179 2180 status_t 2181 BWindow::GetSupportedSuites(BMessage *data) 2182 { 2183 if (data == NULL) 2184 return B_BAD_VALUE; 2185 2186 status_t status = data->AddString("Suites", "suite/vnd.Be-window"); 2187 if (status == B_OK) { 2188 BPropertyInfo propertyInfo(sWindowPropInfo); 2189 2190 status = data->AddFlat("message", &propertyInfo); 2191 if (status == B_OK) 2192 status = BLooper::GetSupportedSuites(data); 2193 } 2194 2195 return status; 2196 } 2197 2198 2199 BHandler * 2200 BWindow::ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier, 2201 int32 what, const char *property) 2202 { 2203 if (msg->what == B_WINDOW_MOVE_BY 2204 || msg->what == B_WINDOW_MOVE_TO) 2205 return this; 2206 2207 BPropertyInfo propertyInfo(sWindowPropInfo); 2208 if (propertyInfo.FindMatch(msg, index, specifier, what, property) >= 0) { 2209 if (!strcmp(property, "View")) { 2210 // we will NOT pop the current specifier 2211 return fTopView; 2212 } else if (!strcmp(property, "MenuBar")) { 2213 if (fKeyMenuBar) { 2214 msg->PopSpecifier(); 2215 return fKeyMenuBar; 2216 } else { 2217 BMessage replyMsg(B_MESSAGE_NOT_UNDERSTOOD); 2218 replyMsg.AddInt32("error", B_NAME_NOT_FOUND); 2219 replyMsg.AddString("message", "This window doesn't have a main MenuBar"); 2220 msg->SendReply(&replyMsg); 2221 return NULL; 2222 } 2223 } else 2224 return this; 2225 } 2226 2227 return BLooper::ResolveSpecifier(msg, index, specifier, what, property); 2228 } 2229 2230 2231 // #pragma mark - Private Methods 2232 2233 2234 void 2235 BWindow::_InitData(BRect frame, const char* title, window_look look, 2236 window_feel feel, uint32 flags, uint32 workspace, int32 bitmapToken) 2237 { 2238 STRACE(("BWindow::InitData()\n")); 2239 2240 if (be_app == NULL) { 2241 debugger("You need a valid BApplication object before interacting with the app_server"); 2242 return; 2243 } 2244 2245 frame.left = roundf(frame.left); 2246 frame.top = roundf(frame.top); 2247 frame.right = roundf(frame.right); 2248 frame.bottom = roundf(frame.bottom); 2249 2250 fFrame = frame; 2251 2252 if (title == NULL) 2253 title = ""; 2254 fTitle = strdup(title); 2255 SetName(title); 2256 2257 fFeel = feel; 2258 fLook = look; 2259 fFlags = flags; 2260 2261 fInTransaction = false; 2262 fActive = false; 2263 fShowLevel = 0; 2264 2265 fTopView = NULL; 2266 fFocus = NULL; 2267 fLastMouseMovedView = NULL; 2268 fKeyMenuBar = NULL; 2269 fDefaultButton = NULL; 2270 2271 // Shortcut 'Q' is handled in _HandleKeyDown() directly, as its message 2272 // get sent to the application, and not one of our handlers 2273 fNoQuitShortcut = false; 2274 2275 if ((fFlags & B_NOT_CLOSABLE) == 0) 2276 AddShortcut('W', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED)); 2277 2278 AddShortcut('X', B_COMMAND_KEY, new BMessage(B_CUT), NULL); 2279 AddShortcut('C', B_COMMAND_KEY, new BMessage(B_COPY), NULL); 2280 AddShortcut('V', B_COMMAND_KEY, new BMessage(B_PASTE), NULL); 2281 AddShortcut('A', B_COMMAND_KEY, new BMessage(B_SELECT_ALL), NULL); 2282 2283 fPulseRate = 0; 2284 fPulseRunner = NULL; 2285 2286 // TODO: is this correct??? should the thread loop be started??? 2287 //SetPulseRate( 500000 ); 2288 2289 // TODO: see if you can use 'fViewsNeedPulse' 2290 2291 fIsFilePanel = false; 2292 2293 // TODO: see WHEN is this used! 2294 fMaskActivated = false; 2295 2296 // TODO: see WHEN is this used! 2297 fWaitingForMenu = false; 2298 fMenuSem = -1; 2299 2300 fMinimized = false; 2301 2302 fMaxZoomHeight = 32768.0; 2303 fMaxZoomWidth = 32768.0; 2304 fMinHeight = 0.0; 2305 fMinWidth = 0.0; 2306 fMaxHeight = 32768.0; 2307 fMaxWidth = 32768.0; 2308 2309 fLastViewToken = B_NULL_TOKEN; 2310 2311 // TODO: other initializations! 2312 2313 // Create the server-side window 2314 2315 port_id receivePort = create_port(B_LOOPER_PORT_DEFAULT_CAPACITY, "w<app_server"); 2316 if (receivePort < B_OK) { 2317 // TODO: huh? 2318 debugger("Could not create BWindow's receive port, used for interacting with the app_server!"); 2319 delete this; 2320 return; 2321 } 2322 2323 STRACE(("BWindow::InitData(): contacting app_server...\n")); 2324 2325 // HERE we are in BApplication's thread, so for locking we use be_app variable 2326 // we'll lock the be_app to be sure we're the only one writing at BApplication's server port 2327 bool locked = false; 2328 if (!be_app->IsLocked()) { 2329 be_app->Lock(); 2330 locked = true; 2331 } 2332 2333 // let app_server know that a window has been created. 2334 fLink = new BPrivate::PortLink( 2335 BApplication::Private::ServerLink()->SenderPort(), receivePort); 2336 2337 if (bitmapToken < 0) { 2338 fLink->StartMessage(AS_CREATE_WINDOW); 2339 } else { 2340 fLink->StartMessage(AS_CREATE_OFFSCREEN_WINDOW); 2341 fLink->Attach<int32>(bitmapToken); 2342 } 2343 2344 fLink->Attach<BRect>(fFrame); 2345 fLink->Attach<uint32>((uint32)fLook); 2346 fLink->Attach<uint32>((uint32)fFeel); 2347 fLink->Attach<uint32>(fFlags); 2348 fLink->Attach<uint32>(workspace); 2349 fLink->Attach<int32>(_get_object_token_(this)); 2350 fLink->Attach<port_id>(receivePort); 2351 fLink->Attach<port_id>(fMsgPort); 2352 fLink->AttachString(title); 2353 2354 port_id sendPort; 2355 int32 code; 2356 if (fLink->FlushWithReply(code) == B_OK 2357 && code == B_OK 2358 && fLink->Read<port_id>(&sendPort) == B_OK) { 2359 // read the frame size and its limits that were really 2360 // enforced on the server side 2361 2362 fLink->Read<BRect>(&fFrame); 2363 fLink->Read<float>(&fMinWidth); 2364 fLink->Read<float>(&fMaxWidth); 2365 fLink->Read<float>(&fMinHeight); 2366 fLink->Read<float>(&fMaxHeight); 2367 2368 fMaxZoomWidth = fMaxWidth; 2369 fMaxZoomHeight = fMaxHeight; 2370 } else 2371 sendPort = -1; 2372 2373 // Redirect our link to the new window connection 2374 fLink->SetSenderPort(sendPort); 2375 2376 if (locked) 2377 be_app->Unlock(); 2378 2379 STRACE(("Server says that our send port is %ld\n", sendPort)); 2380 STRACE(("Window locked?: %s\n", IsLocked() ? "True" : "False")); 2381 2382 _CreateTopView(); 2383 } 2384 2385 2386 //! Reads all pending messages from the window port and put them into the queue. 2387 void 2388 BWindow::_DequeueAll() 2389 { 2390 // Get message count from port 2391 int32 count = port_count(fMsgPort); 2392 2393 for (int32 i = 0; i < count; i++) { 2394 BMessage *message = MessageFromPort(0); 2395 if (message != NULL) 2396 fQueue->AddMessage(message); 2397 } 2398 } 2399 2400 2401 /*! This here is an almost complete code duplication to BLooper::task_looper() 2402 but with some important differences: 2403 a) it uses the _DetermineTarget() method to tell what the later target of 2404 a message will be, if no explicit target is supplied. 2405 b) it calls _UnpackMessage() and _SanitizeMessage() to duplicate the message 2406 to all of its intended targets, and to add all fields the target would 2407 expect in such a message. 2408 2409 This is important because the app_server sends all input events to the 2410 preferred handler, and expects them to be correctly distributed to their 2411 intended targets. 2412 */ 2413 void 2414 BWindow::task_looper() 2415 { 2416 STRACE(("info: BWindow::task_looper() started.\n")); 2417 2418 // Check that looper is locked (should be) 2419 AssertLocked(); 2420 Unlock(); 2421 2422 if (IsLocked()) 2423 debugger("window must not be locked!"); 2424 2425 // loop: As long as we are not terminating. 2426 while (!fTerminating) { 2427 // TODO: timeout determination algo 2428 // Read from message port (how do we determine what the timeout is?) 2429 BMessage* msg = MessageFromPort(); 2430 2431 // Did we get a message? 2432 if (msg) { 2433 // Add to queue 2434 fQueue->AddMessage(msg); 2435 } else 2436 continue; 2437 2438 // Get message count from port 2439 int32 msgCount = port_count(fMsgPort); 2440 for (int32 i = 0; i < msgCount; ++i) { 2441 // Read 'count' messages from port (so we will not block) 2442 // We use zero as our timeout since we know there is stuff there 2443 msg = MessageFromPort(0); 2444 // Add messages to queue 2445 if (msg) 2446 fQueue->AddMessage(msg); 2447 } 2448 2449 // loop: As long as there are messages in the queue and the port is 2450 // empty... and we are not terminating, of course. 2451 bool dispatchNextMessage = true; 2452 while (!fTerminating && dispatchNextMessage) { 2453 // Get next message from queue (assign to fLastMessage) 2454 fLastMessage = fQueue->NextMessage(); 2455 2456 // Lock the looper 2457 if (!Lock()) 2458 break; 2459 2460 if (!fLastMessage) { 2461 // No more messages: Unlock the looper and terminate the 2462 // dispatch loop. 2463 dispatchNextMessage = false; 2464 } else { 2465 // Get the target handler 2466 BMessage::Private messagePrivate(fLastMessage); 2467 bool usePreferred = messagePrivate.UsePreferredTarget(); 2468 BHandler *handler = NULL; 2469 bool dropMessage = false; 2470 2471 if (usePreferred) { 2472 handler = PreferredHandler(); 2473 if (handler == NULL) 2474 handler = this; 2475 } else { 2476 gDefaultTokens.GetToken(messagePrivate.GetTarget(), 2477 B_HANDLER_TOKEN, (void **)&handler); 2478 2479 // if this handler doesn't belong to us, we drop the message 2480 if (handler != NULL && handler->Looper() != this) { 2481 dropMessage = true; 2482 handler = NULL; 2483 } 2484 } 2485 2486 if ((handler == NULL && !dropMessage) || usePreferred) 2487 handler = _DetermineTarget(fLastMessage, handler); 2488 2489 unpack_cookie cookie; 2490 while (_UnpackMessage(cookie, &fLastMessage, &handler, &usePreferred)) { 2491 // if there is no target handler, the message is dropped 2492 if (handler != NULL) { 2493 // Is this a scripting message? 2494 if (fLastMessage->HasSpecifiers()) { 2495 int32 index = 0; 2496 // Make sure the current specifier is kosher 2497 if (fLastMessage->GetCurrentSpecifier(&index) == B_OK) 2498 handler = resolve_specifier(handler, fLastMessage); 2499 } 2500 2501 if (handler != NULL) 2502 handler = _TopLevelFilter(fLastMessage, handler); 2503 2504 if (handler != NULL) { 2505 _SanitizeMessage(fLastMessage, handler, usePreferred); 2506 DispatchMessage(fLastMessage, handler); 2507 } 2508 } 2509 2510 // Delete the current message 2511 delete fLastMessage; 2512 fLastMessage = NULL; 2513 } 2514 } 2515 2516 if (fTerminating) { 2517 // we leave the looper locked when we quit 2518 return; 2519 } 2520 2521 Unlock(); 2522 2523 // Are any messages on the port? 2524 if (port_count(fMsgPort) > 0) { 2525 // Do outer loop 2526 dispatchNextMessage = false; 2527 } 2528 } 2529 } 2530 } 2531 2532 2533 window_type 2534 BWindow::_ComposeType(window_look look, window_feel feel) const 2535 { 2536 switch (feel) { 2537 case B_NORMAL_WINDOW_FEEL: 2538 switch (look) { 2539 case B_TITLED_WINDOW_LOOK: 2540 return B_TITLED_WINDOW; 2541 2542 case B_DOCUMENT_WINDOW_LOOK: 2543 return B_DOCUMENT_WINDOW; 2544 2545 case B_BORDERED_WINDOW_LOOK: 2546 return B_BORDERED_WINDOW; 2547 2548 default: 2549 return B_UNTYPED_WINDOW; 2550 } 2551 break; 2552 2553 case B_MODAL_APP_WINDOW_FEEL: 2554 if (look == B_MODAL_WINDOW_LOOK) 2555 return B_MODAL_WINDOW; 2556 break; 2557 2558 case B_FLOATING_APP_WINDOW_FEEL: 2559 if (look == B_FLOATING_WINDOW_LOOK) 2560 return B_FLOATING_WINDOW; 2561 break; 2562 2563 default: 2564 return B_UNTYPED_WINDOW; 2565 } 2566 2567 return B_UNTYPED_WINDOW; 2568 } 2569 2570 2571 void 2572 BWindow::_DecomposeType(window_type type, window_look *_look, 2573 window_feel *_feel) const 2574 { 2575 switch (type) { 2576 case B_DOCUMENT_WINDOW: 2577 *_look = B_DOCUMENT_WINDOW_LOOK; 2578 *_feel = B_NORMAL_WINDOW_FEEL; 2579 break; 2580 2581 case B_MODAL_WINDOW: 2582 *_look = B_MODAL_WINDOW_LOOK; 2583 *_feel = B_MODAL_APP_WINDOW_FEEL; 2584 break; 2585 2586 case B_FLOATING_WINDOW: 2587 *_look = B_FLOATING_WINDOW_LOOK; 2588 *_feel = B_FLOATING_APP_WINDOW_FEEL; 2589 break; 2590 2591 case B_BORDERED_WINDOW: 2592 *_look = B_BORDERED_WINDOW_LOOK; 2593 *_feel = B_NORMAL_WINDOW_FEEL; 2594 break; 2595 2596 case B_TITLED_WINDOW: 2597 case B_UNTYPED_WINDOW: 2598 default: 2599 *_look = B_TITLED_WINDOW_LOOK; 2600 *_feel = B_NORMAL_WINDOW_FEEL; 2601 break; 2602 } 2603 } 2604 2605 2606 void 2607 BWindow::_CreateTopView() 2608 { 2609 STRACE(("_CreateTopView(): enter\n")); 2610 2611 BRect frame = fFrame.OffsetToCopy(B_ORIGIN); 2612 fTopView = new BView(frame, "fTopView", 2613 B_FOLLOW_ALL, B_WILL_DRAW); 2614 fTopView->fTopLevelView = true; 2615 2616 //inhibit check_lock() 2617 fLastViewToken = _get_object_token_(fTopView); 2618 2619 // set fTopView's owner, add it to window's eligible handler list 2620 // and also set its next handler to be this window. 2621 2622 STRACE(("Calling setowner fTopView = %p this = %p.\n", 2623 fTopView, this)); 2624 2625 fTopView->_SetOwner(this); 2626 2627 // we can't use AddChild() because this is the top view 2628 fTopView->_CreateSelf(); 2629 2630 STRACE(("BuildTopView ended\n")); 2631 } 2632 2633 2634 /*! 2635 Resizes the top view to match the window size. This will also 2636 adapt the size of all its child views as needed. 2637 This method has to be called whenever the frame of the window 2638 changes. 2639 */ 2640 void 2641 BWindow::_AdoptResize() 2642 { 2643 // Resize views according to their resize modes - this 2644 // saves us some server communication, as the server 2645 // does the same with our views on its side. 2646 2647 int32 deltaWidth = (int32)(fFrame.Width() - fTopView->Bounds().Width()); 2648 int32 deltaHeight = (int32)(fFrame.Height() - fTopView->Bounds().Height()); 2649 if (deltaWidth == 0 && deltaHeight == 0) 2650 return; 2651 2652 fTopView->_ResizeBy(deltaWidth, deltaHeight); 2653 } 2654 2655 2656 void 2657 BWindow::_SetFocus(BView *focusView, bool notifyInputServer) 2658 { 2659 if (fFocus == focusView) 2660 return; 2661 2662 if (focusView) 2663 focusView->MakeFocus(true); 2664 2665 // we notify the input server if we are passing focus 2666 // from a view which has the B_INPUT_METHOD_AWARE to a one 2667 // which does not, or vice-versa 2668 if (notifyInputServer) { 2669 bool oldIMAware = false, newIMAware = false; 2670 if (focusView) 2671 newIMAware = focusView->Flags() & B_INPUT_METHOD_AWARE; 2672 if (fFocus) 2673 oldIMAware = fFocus->Flags() & B_INPUT_METHOD_AWARE; 2674 if (newIMAware ^ oldIMAware) { 2675 BMessage msg(newIMAware ? IS_FOCUS_IM_AWARE_VIEW : IS_UNFOCUS_IM_AWARE_VIEW); 2676 BMessage reply; 2677 _control_input_server_(&msg, &reply); 2678 // do we care return code ? 2679 } 2680 } 2681 2682 fFocus = focusView; 2683 } 2684 2685 2686 /*! 2687 \brief Determines the target of a message received for the 2688 focus view. 2689 */ 2690 BHandler * 2691 BWindow::_DetermineTarget(BMessage *message, BHandler *target) 2692 { 2693 if (target == NULL) 2694 target = this; 2695 2696 switch (message->what) { 2697 case B_KEY_DOWN: 2698 case B_KEY_UP: 2699 { 2700 // if we have a default button, it might want to hear 2701 // about pressing the <enter> key 2702 int32 rawChar; 2703 if (DefaultButton() != NULL 2704 && message->FindInt32("raw_char", &rawChar) == B_OK 2705 && rawChar == B_ENTER) 2706 return DefaultButton(); 2707 2708 // supposed to fall through 2709 } 2710 case B_UNMAPPED_KEY_DOWN: 2711 case B_UNMAPPED_KEY_UP: 2712 case B_MODIFIERS_CHANGED: 2713 // these messages should be dispatched by the focus view 2714 if (CurrentFocus() != NULL) 2715 return CurrentFocus(); 2716 break; 2717 2718 case B_MOUSE_DOWN: 2719 case B_MOUSE_UP: 2720 case B_MOUSE_MOVED: 2721 case B_MOUSE_WHEEL_CHANGED: 2722 // is there a token of the view that is currently under the mouse? 2723 int32 token; 2724 if (message->FindInt32("_view_token", &token) == B_OK) { 2725 BView* view = _FindView(token); 2726 if (view != NULL) 2727 return view; 2728 } 2729 2730 // if there is no valid token in the message, we try our 2731 // luck with the last target, if available 2732 if (fLastMouseMovedView != NULL) 2733 return fLastMouseMovedView; 2734 break; 2735 2736 case B_PULSE: 2737 case B_QUIT_REQUESTED: 2738 // TODO: test wether R5 will let BView dispatch these messages 2739 return this; 2740 2741 default: 2742 break; 2743 } 2744 2745 return target; 2746 } 2747 2748 2749 /*! 2750 \brief Distributes the message to its intended targets. This is done for 2751 all messages that should go to the preferred handler. 2752 2753 Returns \c true in case the message should still be dispatched 2754 */ 2755 bool 2756 BWindow::_UnpackMessage(unpack_cookie& cookie, BMessage** _message, BHandler** _target, 2757 bool* _usePreferred) 2758 { 2759 if (cookie.message == NULL) 2760 return false; 2761 2762 if (cookie.index == 0 && !cookie.tokens_scanned) { 2763 if (!*_usePreferred) { 2764 // we only consider messages targeted at the preferred handler 2765 cookie.message = NULL; 2766 return true; 2767 } 2768 2769 // initialize our cookie 2770 cookie.message = *_message; 2771 cookie.focus = *_target; 2772 2773 if (cookie.focus != NULL) 2774 cookie.focus_token = _get_object_token_(*_target); 2775 2776 if (fLastMouseMovedView != NULL && cookie.message->what == B_MOUSE_MOVED) 2777 cookie.last_view_token = _get_object_token_(fLastMouseMovedView); 2778 2779 *_usePreferred = false; 2780 } 2781 2782 _DequeueAll(); 2783 2784 // distribute the message to all targets specified in the 2785 // message directly (but not to the focus view) 2786 2787 for (int32 token; !cookie.tokens_scanned 2788 && cookie.message->FindInt32("_token", cookie.index, &token) == B_OK; 2789 cookie.index++) { 2790 // focus view is preferred and should get its message directly 2791 if (token == cookie.focus_token) { 2792 cookie.found_focus = true; 2793 continue; 2794 } 2795 if (token == cookie.last_view_token) 2796 continue; 2797 2798 BView* target = _FindView(token); 2799 if (target == NULL) 2800 continue; 2801 2802 *_message = new BMessage(*cookie.message); 2803 *_target = target; 2804 cookie.index++; 2805 return true; 2806 } 2807 2808 cookie.tokens_scanned = true; 2809 2810 // if there is a last mouse moved view, and the new focus is 2811 // different, the previous view wants to get its B_EXITED_VIEW 2812 // message 2813 if (cookie.last_view_token != B_NULL_TOKEN && fLastMouseMovedView != NULL 2814 && fLastMouseMovedView != cookie.focus) { 2815 *_message = new BMessage(*cookie.message); 2816 *_target = fLastMouseMovedView; 2817 cookie.last_view_token = B_NULL_TOKEN; 2818 return true; 2819 } 2820 2821 bool dispatchToFocus = true; 2822 2823 // check if the focus token is still valid (could have been removed in the mean time) 2824 BHandler* handler; 2825 if (gDefaultTokens.GetToken(cookie.focus_token, B_HANDLER_TOKEN, (void**)&handler) != B_OK 2826 || handler->Looper() != this) 2827 dispatchToFocus = false; 2828 2829 if (dispatchToFocus && cookie.index > 0) { 2830 // should this message still be dispatched by the focus view? 2831 bool feedFocus; 2832 if (!cookie.found_focus 2833 && (cookie.message->FindBool("_feed_focus", &feedFocus) != B_OK 2834 || feedFocus == false)) 2835 dispatchToFocus = false; 2836 } 2837 2838 if (!dispatchToFocus) { 2839 delete cookie.message; 2840 cookie.message = NULL; 2841 return false; 2842 } 2843 2844 *_message = cookie.message; 2845 *_target = cookie.focus; 2846 *_usePreferred = true; 2847 cookie.message = NULL; 2848 return true; 2849 } 2850 2851 2852 void 2853 BWindow::_SanitizeMessage(BMessage* message, BHandler* target, bool usePreferred) 2854 { 2855 if (target == NULL) 2856 return; 2857 2858 switch (message->what) { 2859 case B_MOUSE_MOVED: 2860 case B_MOUSE_UP: 2861 case B_MOUSE_DOWN: 2862 BPoint where; 2863 if (message->FindPoint("screen_where", &where) != B_OK) 2864 break; 2865 2866 // add local window coordinates 2867 message->AddPoint("where", ConvertFromScreen(where)); 2868 2869 BView* view = dynamic_cast<BView*>(target); 2870 if (view != NULL) { 2871 // add local view coordinates 2872 message->AddPoint("be:view_where", view->ConvertFromScreen(where)); 2873 2874 if (message->what == B_MOUSE_MOVED) { 2875 // is there a token of the view that is currently under the mouse? 2876 BView* viewUnderMouse = NULL; 2877 int32 token; 2878 if (message->FindInt32("_view_token", &token) == B_OK) 2879 viewUnderMouse = _FindView(token); 2880 2881 // add transit information 2882 int32 transit; 2883 if (viewUnderMouse == view) { 2884 // the mouse is over the target view 2885 if (fLastMouseMovedView != view) 2886 transit = B_ENTERED_VIEW; 2887 else 2888 transit = B_INSIDE_VIEW; 2889 } else { 2890 // the mouse is not over the target view 2891 if (view == fLastMouseMovedView) 2892 transit = B_EXITED_VIEW; 2893 else 2894 transit = B_OUTSIDE_VIEW; 2895 } 2896 2897 message->AddInt32("be:transit", transit); 2898 2899 if (usePreferred || viewUnderMouse == NULL) 2900 fLastMouseMovedView = viewUnderMouse; 2901 } 2902 } 2903 break; 2904 } 2905 } 2906 2907 2908 bool 2909 BWindow::_HandleKeyDown(char key, uint32 modifiers) 2910 { 2911 // TODO: ask people if using 'raw_char' is OK ? 2912 2913 // handle BMenuBar key 2914 if (key == B_ESCAPE && (modifiers & B_COMMAND_KEY) != 0 2915 && fKeyMenuBar) { 2916 // TODO: ask Marc about 'fWaitingForMenu' member! 2917 2918 // fWaitingForMenu = true; 2919 fKeyMenuBar->StartMenuBar(0, true, false, NULL); 2920 return true; 2921 } 2922 2923 // Keyboard navigation through views 2924 // (B_OPTION_KEY makes BTextViews and friends navigable, even in editing mode) 2925 if (key == B_TAB && (modifiers & (B_COMMAND_KEY | B_OPTION_KEY)) != 0) { 2926 _KeyboardNavigation(); 2927 return true; 2928 } 2929 2930 // Deskbar's Switcher 2931 if (key == B_TAB && (modifiers & B_CONTROL_KEY) != 0) { 2932 BMessenger deskbar(kDeskbarSignature); 2933 if (deskbar.IsValid()) { 2934 BMessage message('TASK'); 2935 message.AddInt32("key", B_TAB); 2936 message.AddInt32("modifiers", modifiers); 2937 message.AddInt64("when", system_time()); 2938 message.AddInt32("team", Team()); 2939 deskbar.SendMessage(&message); 2940 } 2941 return true; 2942 } 2943 2944 // Handle shortcuts 2945 if ((modifiers & B_COMMAND_KEY) != 0) { 2946 // Command+q has been pressed, so, we will quit 2947 // the shortcut mechanism doesn't allow handlers outside the window 2948 if (!fNoQuitShortcut && (key == 'Q' || key == 'q')) { 2949 BMessage message(B_QUIT_REQUESTED); 2950 message.AddBool("shortcut", true); 2951 2952 be_app->PostMessage(&message); 2953 return true; 2954 } 2955 2956 Shortcut* shortcut = _FindShortcut(key, modifiers); 2957 if (shortcut != NULL) { 2958 // TODO: would be nice to move this functionality to 2959 // a Shortcut::Invoke() method - but since BMenu::InvokeItem() 2960 // (and BMenuItem::Invoke()) are private, I didn't want 2961 // to mess with them (BMenuItem::Invoke() is public in 2962 // Dano/Zeta, though, maybe we should just follow their 2963 // example) 2964 if (shortcut->MenuItem() != NULL) { 2965 BMenu* menu = shortcut->MenuItem()->Menu(); 2966 if (menu != NULL) 2967 menu->InvokeItem(shortcut->MenuItem(), true); 2968 } else { 2969 BHandler* target = shortcut->Target(); 2970 if (target == NULL) 2971 target = CurrentFocus(); 2972 2973 if (shortcut->Message() != NULL) { 2974 BMessage message(*shortcut->Message()); 2975 2976 if (message.ReplaceInt64("when", system_time()) != B_OK) 2977 message.AddInt64("when", system_time()); 2978 if (message.ReplaceBool("shortcut", true) != B_OK) 2979 message.AddBool("shortcut", true); 2980 2981 PostMessage(&message, target); 2982 } 2983 } 2984 2985 return true; 2986 } 2987 } 2988 2989 // TODO: convert keys to the encoding of the target view 2990 2991 return false; 2992 } 2993 2994 2995 void 2996 BWindow::_KeyboardNavigation() 2997 { 2998 BMessage *message = CurrentMessage(); 2999 if (message == NULL) 3000 return; 3001 3002 const char *bytes; 3003 uint32 modifiers; 3004 if (message->FindString("bytes", &bytes) != B_OK 3005 || bytes[0] != B_TAB) 3006 return; 3007 3008 message->FindInt32("modifiers", (int32*)&modifiers); 3009 3010 BView *nextFocus; 3011 int32 jumpGroups = modifiers & B_CONTROL_KEY ? B_NAVIGABLE_JUMP : B_NAVIGABLE; 3012 if (modifiers & B_SHIFT_KEY) 3013 nextFocus = _FindPreviousNavigable(fFocus, jumpGroups); 3014 else 3015 nextFocus = _FindNextNavigable(fFocus, jumpGroups); 3016 3017 if (nextFocus && nextFocus != fFocus) 3018 _SetFocus(nextFocus, false); 3019 } 3020 3021 3022 BMessage * 3023 BWindow::ConvertToMessage(void *raw, int32 code) 3024 { 3025 return BLooper::ConvertToMessage(raw, code); 3026 } 3027 3028 3029 BWindow::Shortcut * 3030 BWindow::_FindShortcut(uint32 key, uint32 modifiers) 3031 { 3032 int32 count = fShortcuts.CountItems(); 3033 3034 key = Shortcut::PrepareKey(key); 3035 modifiers = Shortcut::PrepareModifiers(modifiers); 3036 3037 for (int32 index = 0; index < count; index++) { 3038 Shortcut *shortcut = (Shortcut *)fShortcuts.ItemAt(index); 3039 3040 if (shortcut->Matches(key, modifiers)) 3041 return shortcut; 3042 } 3043 3044 return NULL; 3045 } 3046 3047 3048 BView * 3049 BWindow::_FindView(int32 token) 3050 { 3051 BHandler* handler; 3052 if (gDefaultTokens.GetToken(token, B_HANDLER_TOKEN, (void**)&handler) != B_OK) 3053 return NULL; 3054 3055 // the view must belong to us in order to be found by this method 3056 BView* view = dynamic_cast<BView*>(handler); 3057 if (view != NULL && view->Window() == this) 3058 return view; 3059 3060 return NULL; 3061 } 3062 3063 3064 BView * 3065 BWindow::_FindView(BView *view, BPoint point) const 3066 { 3067 // TODO: this is totally broken (bounds vs. frame) - since 3068 // BView::Bounds() potentially queries the app_server 3069 // anyway, we could just let the app_server answer this 3070 // query directly. 3071 if (view->Bounds().Contains(point) && !view->fFirstChild) 3072 return view; 3073 3074 BView *child = view->fFirstChild; 3075 3076 while (child != NULL) { 3077 if ((view = _FindView(child, point)) != NULL) 3078 return view; 3079 3080 child = child->fNextSibling; 3081 } 3082 3083 return NULL; 3084 } 3085 3086 3087 BView * 3088 BWindow::_FindNextNavigable(BView* focus, uint32 flags) 3089 { 3090 if (focus == NULL) 3091 focus = fTopView; 3092 3093 BView* nextFocus = focus; 3094 3095 // Search the tree for views that accept focus (depth search) 3096 while (true) { 3097 if (nextFocus->fFirstChild) 3098 nextFocus = nextFocus->fFirstChild; 3099 else if (nextFocus->fNextSibling) 3100 nextFocus = nextFocus->fNextSibling; 3101 else { 3102 // go to the nearest parent with a next sibling 3103 while (!nextFocus->fNextSibling && nextFocus->fParent) { 3104 nextFocus = nextFocus->fParent; 3105 } 3106 3107 if (nextFocus == fTopView) { 3108 // if we started with the top view, we traversed the whole tree already 3109 if (nextFocus == focus) 3110 return NULL; 3111 3112 nextFocus = nextFocus->fFirstChild; 3113 } else 3114 nextFocus = nextFocus->fNextSibling; 3115 } 3116 3117 if (nextFocus == focus || nextFocus == NULL) { 3118 // When we get here it means that the hole tree has been 3119 // searched and there is no view with B_NAVIGABLE(_JUMP) flag set! 3120 return NULL; 3121 } 3122 3123 if (!nextFocus->IsHidden() && (nextFocus->Flags() & flags) != 0) 3124 return nextFocus; 3125 } 3126 } 3127 3128 3129 BView * 3130 BWindow::_FindPreviousNavigable(BView* focus, uint32 flags) 3131 { 3132 if (focus == NULL) 3133 focus = fTopView; 3134 3135 BView* previousFocus = focus; 3136 3137 // Search the tree for the previous view that accept focus 3138 while (true) { 3139 if (previousFocus->fPreviousSibling) { 3140 // find the last child in the previous sibling 3141 previousFocus = _LastViewChild(previousFocus->fPreviousSibling); 3142 } else { 3143 previousFocus = previousFocus->fParent; 3144 if (previousFocus == fTopView) 3145 previousFocus = _LastViewChild(fTopView); 3146 } 3147 3148 if (previousFocus == focus || previousFocus == NULL) { 3149 // When we get here it means that the hole tree has been 3150 // searched and there is no view with B_NAVIGABLE(_JUMP) flag set! 3151 return NULL; 3152 } 3153 3154 if (!previousFocus->IsHidden() && (previousFocus->Flags() & flags) != 0) 3155 return previousFocus; 3156 } 3157 } 3158 3159 3160 /*! 3161 Returns the last child in a view hierarchy. 3162 Needed only by _FindPreviousNavigable(). 3163 */ 3164 BView * 3165 BWindow::_LastViewChild(BView *parent) 3166 { 3167 while (true) { 3168 BView *last = parent->fFirstChild; 3169 if (last == NULL) 3170 return parent; 3171 3172 while (last->fNextSibling) { 3173 last = last->fNextSibling; 3174 } 3175 3176 parent = last; 3177 } 3178 } 3179 3180 3181 void 3182 BWindow::SetIsFilePanel(bool isFilePanel) 3183 { 3184 fIsFilePanel = isFilePanel; 3185 } 3186 3187 3188 bool 3189 BWindow::IsFilePanel() const 3190 { 3191 return fIsFilePanel; 3192 } 3193 3194 3195 //------------------------------------------------------------------------------ 3196 // Virtual reserved Functions 3197 3198 void BWindow::_ReservedWindow1() {} 3199 void BWindow::_ReservedWindow2() {} 3200 void BWindow::_ReservedWindow3() {} 3201 void BWindow::_ReservedWindow4() {} 3202 void BWindow::_ReservedWindow5() {} 3203 void BWindow::_ReservedWindow6() {} 3204 void BWindow::_ReservedWindow7() {} 3205 void BWindow::_ReservedWindow8() {} 3206 3207 void 3208 BWindow::PrintToStream() const 3209 { 3210 printf("BWindow '%s' data:\ 3211 Title = %s\ 3212 Token = %ld\ 3213 InTransaction = %s\ 3214 Active = %s\ 3215 fShowLevel = %d\ 3216 Flags = %lx\ 3217 send_port = %ld\ 3218 receive_port = %ld\ 3219 fTopView name = %s\ 3220 focus view name = %s\ 3221 lastMouseMoved = %s\ 3222 fLink = %p\ 3223 KeyMenuBar name = %s\ 3224 DefaultButton = %s\ 3225 # of shortcuts = %ld", 3226 Name(), fTitle, 3227 _get_object_token_(this), 3228 fInTransaction == true ? "yes" : "no", 3229 fActive == true ? "yes" : "no", 3230 fShowLevel, 3231 fFlags, 3232 fLink->SenderPort(), 3233 fLink->ReceiverPort(), 3234 fTopView != NULL ? fTopView->Name() : "NULL", 3235 fFocus != NULL ? fFocus->Name() : "NULL", 3236 fLastMouseMovedView != NULL ? fLastMouseMovedView->Name() : "NULL", 3237 fLink, 3238 fKeyMenuBar != NULL ? fKeyMenuBar->Name() : "NULL", 3239 fDefaultButton != NULL ? fDefaultButton->Name() : "NULL", 3240 fShortcuts.CountItems()); 3241 /* 3242 for( int32 i=0; i<accelList.CountItems(); i++){ 3243 _BCmdKey *key = (_BCmdKey*)accelList.ItemAt(i); 3244 printf("\tShortCut %ld: char %s\n\t\t message: \n", i, (key->key > 127)?"ASCII":"UNICODE"); 3245 key->message->PrintToStream(); 3246 } 3247 */ 3248 printf("\ 3249 topViewToken = %ld\ 3250 isFilePanel = %s\ 3251 MaskActivated = %s\ 3252 pulseRate = %lld\ 3253 waitingForMenu = %s\ 3254 minimized = %s\ 3255 Menu semaphore = %ld\ 3256 maxZoomHeight = %f\ 3257 maxZoomWidth = %f\ 3258 minWindHeight = %f\ 3259 minWindWidth = %f\ 3260 maxWindHeight = %f\ 3261 maxWindWidth = %f\ 3262 frame = ( %f, %f, %f, %f )\ 3263 look = %d\ 3264 feel = %d\ 3265 lastViewToken = %ld\ 3266 pulseRunner = %s\n", 3267 fTopViewToken, 3268 fIsFilePanel==true?"Yes":"No", 3269 fMaskActivated==true?"Yes":"No", 3270 fPulseRate, 3271 fWaitingForMenu==true?"Yes":"No", 3272 fMinimized==true?"Yes":"No", 3273 fMenuSem, 3274 fMaxZoomHeight, 3275 fMaxZoomWidth, 3276 fMinHeight, 3277 fMinWidth, 3278 fMaxHeight, 3279 fMaxWidth, 3280 fFrame.left, fFrame.top, fFrame.right, fFrame.bottom, 3281 (int16)fLook, 3282 (int16)fFeel, 3283 fLastViewToken, 3284 fPulseRunner != NULL ? "In place" : "NULL"); 3285 } 3286 3287 /* 3288 TODO list: 3289 *) test arguments for SetWindowAligment 3290 *) call hook functions: MenusBeginning, MenusEnded. Add menu activation code. 3291 */ 3292 3293