1 /* 2 * Copyright 2001-2005, 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 <BeBuild.h> 13 #include <InterfaceDefs.h> 14 #include <PropertyInfo.h> 15 #include <Handler.h> 16 #include <Looper.h> 17 #include <Application.h> 18 #include <Window.h> 19 #include <View.h> 20 #include <MenuBar.h> 21 #include <MenuItem.h> 22 #include <String.h> 23 #include <Screen.h> 24 #include <Button.h> 25 #include <MessageQueue.h> 26 #include <MessageRunner.h> 27 #include <Roster.h> 28 #include <Autolock.h> 29 30 #include <ApplicationPrivate.h> 31 #include <AppMisc.h> 32 #include <PortLink.h> 33 #include <ServerProtocol.h> 34 #include <TokenSpace.h> 35 #include <MessageUtils.h> 36 #include <WindowAux.h> 37 38 #include <stdio.h> 39 #include <math.h> 40 41 42 //#define DEBUG_WIN 43 #ifdef DEBUG_WIN 44 # include <stdio.h> 45 # define STRACE(x) printf x 46 #else 47 # define STRACE(x) ; 48 #endif 49 50 using BPrivate::gDefaultTokens; 51 52 static property_info sWindowPropInfo[] = { 53 { 54 "Feel", { B_GET_PROPERTY, B_SET_PROPERTY }, 55 { B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE } 56 }, 57 58 { 59 "Flags", { B_GET_PROPERTY, B_SET_PROPERTY }, 60 { B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE } 61 }, 62 63 { 64 "Frame", { B_GET_PROPERTY, B_SET_PROPERTY }, 65 { B_DIRECT_SPECIFIER }, NULL, 0, { B_RECT_TYPE } 66 }, 67 68 { 69 "Hidden", { B_GET_PROPERTY, B_SET_PROPERTY }, 70 { B_DIRECT_SPECIFIER }, NULL, 0, { B_BOOL_TYPE } 71 }, 72 73 { 74 "Look", { B_GET_PROPERTY, B_SET_PROPERTY }, 75 { B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE } 76 }, 77 78 { 79 "Title", { B_GET_PROPERTY, B_SET_PROPERTY }, 80 { B_DIRECT_SPECIFIER }, NULL, 0, { B_STRING_TYPE } 81 }, 82 83 { 84 "Workspaces", { B_GET_PROPERTY, B_SET_PROPERTY }, 85 { B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE} 86 }, 87 88 { 89 "MenuBar", {}, 90 { B_DIRECT_SPECIFIER }, NULL, 0, {} 91 }, 92 93 { 94 "View", {}, {}, NULL, 0, {} 95 }, 96 97 { 98 "Minimize", { B_GET_PROPERTY, B_SET_PROPERTY }, 99 { B_DIRECT_SPECIFIER }, NULL, 0, { B_BOOL_TYPE } 100 }, 101 102 {} 103 }; 104 105 106 void 107 _set_menu_sem_(BWindow *window, sem_id sem) 108 { 109 if (window != NULL) 110 window->fMenuSem = sem; 111 } 112 113 114 // #pragma mark - 115 116 117 BWindow::BWindow(BRect frame, const char* title, window_type type, 118 uint32 flags, uint32 workspace) 119 : BLooper(title) 120 { 121 #ifdef DEBUG_WIN 122 printf("BWindow::BWindow()\n"); 123 #endif 124 window_look look; 125 window_feel feel; 126 127 decomposeType(type, &look, &feel); 128 129 InitData(frame, title, look, feel, flags, workspace); 130 } 131 132 133 BWindow::BWindow(BRect frame, const char* title, window_look look, window_feel feel, 134 uint32 flags, uint32 workspace) 135 : BLooper(title) 136 { 137 InitData(frame, title, look, feel, flags, workspace); 138 } 139 140 141 BWindow::BWindow(BMessage* data) 142 : BLooper(data) 143 { 144 data->FindRect("_frame", &fFrame); 145 146 const char *title; 147 data->FindString("_title", &title); 148 149 window_look look; 150 data->FindInt32("_wlook", (int32 *)&look); 151 152 window_feel feel; 153 data->FindInt32("_wfeel", (int32 *)&feel); 154 155 if (data->FindInt32("_flags", (int32 *)&fFlags) != B_OK) 156 fFlags = 0; 157 158 uint32 workspaces; 159 data->FindInt32("_wspace", (int32 *)&workspaces); 160 161 uint32 type; 162 if (data->FindInt32("_type", (int32*)&type) == B_OK) 163 decomposeType((window_type)type, &fLook, &fFeel); 164 165 // connect to app_server and initialize data 166 InitData(fFrame, title, look, feel, fFlags, workspaces); 167 168 if (data->FindFloat("_zoom", 0, &fMaxZoomWidth) == B_OK 169 && data->FindFloat("_zoom", 1, &fMaxZoomHeight) == B_OK) 170 SetZoomLimits(fMaxZoomWidth, fMaxZoomHeight); 171 172 if (data->FindFloat("_sizel", 0, &fMinWidth) == B_OK 173 && data->FindFloat("_sizel", 1, &fMinHeight) == B_OK 174 && data->FindFloat("_sizel", 2, &fMaxWidth) == B_OK 175 && data->FindFloat("_sizel", 3, &fMaxHeight) == B_OK) 176 SetSizeLimits(fMinWidth, fMaxWidth, 177 fMinHeight, fMaxHeight); 178 179 if (data->FindInt64("_pulse", &fPulseRate) == B_OK) 180 SetPulseRate(fPulseRate); 181 182 BMessage msg; 183 int32 i = 0; 184 while ( data->FindMessage("_views", i++, &msg) == B_OK){ 185 BArchivable *obj = instantiate_object(&msg); 186 BView *child = dynamic_cast<BView *>(obj); 187 if (child) 188 AddChild(child); 189 } 190 } 191 192 193 BWindow::BWindow(BRect frame, int32 bitmapToken) 194 : BLooper("offscreen bitmap") 195 { 196 // TODO: Implement for real 197 decomposeType(B_UNTYPED_WINDOW, &fLook, &fFeel); 198 InitData(frame, "offscreen", fLook, fFeel, 0, 0, bitmapToken); 199 } 200 201 202 BWindow::~BWindow() 203 { 204 // the following lines, remove all existing shortcuts and delete accelList 205 int32 noOfItems = accelList.CountItems(); 206 for (int index = noOfItems-1; index >= 0; index--) { 207 delete (_BCmdKey*)accelList.ItemAt(index); 208 } 209 210 // TODO: release other dynamically-allocated objects 211 212 // Deleting this semaphore will tell open menus to quit. 213 if (fMenuSem > 0) 214 delete_sem(fMenuSem); 215 216 // disable pulsing 217 SetPulseRate(0); 218 219 // tell app_server about our demise 220 fLink->StartMessage(AS_DELETE_WINDOW); 221 fLink->Flush(); 222 223 // the sender port belongs to the app_server 224 delete_port(fLink->ReceiverPort()); 225 delete fLink; 226 } 227 228 229 BArchivable * 230 BWindow::Instantiate(BMessage *data) 231 { 232 if (!validate_instantiation(data , "BWindow")) 233 return NULL; 234 235 return new BWindow(data); 236 } 237 238 239 status_t 240 BWindow::Archive(BMessage* data, bool deep) const 241 { 242 status_t retval = BLooper::Archive(data, deep); 243 if (retval != B_OK) 244 return retval; 245 246 data->AddRect("_frame", fFrame); 247 data->AddString("_title", fTitle); 248 data->AddInt32("_wlook", fLook); 249 data->AddInt32("_wfeel", fFeel); 250 if (fFlags) 251 data->AddInt32("_flags", fFlags); 252 data->AddInt32("_wspace", (uint32)Workspaces()); 253 254 if (!composeType(fLook, fFeel)) 255 data->AddInt32("_type", (uint32)Type()); 256 257 if (fMaxZoomWidth != 32768.0 || fMaxZoomHeight != 32768.0) { 258 data->AddFloat("_zoom", fMaxZoomWidth); 259 data->AddFloat("_zoom", fMaxZoomHeight); 260 } 261 262 if (fMinWidth != 0.0 || fMinHeight != 0.0 263 || fMaxWidth != 32768.0 || fMaxHeight != 32768.0) { 264 data->AddFloat("_sizel", fMinWidth); 265 data->AddFloat("_sizel", fMinHeight); 266 data->AddFloat("_sizel", fMaxWidth); 267 data->AddFloat("_sizel", fMaxHeight); 268 } 269 270 if (fPulseRate != 500000) 271 data->AddInt64("_pulse", fPulseRate); 272 273 if (deep) { 274 int32 noOfViews = CountChildren(); 275 for (int32 i = 0; i < noOfViews; i++){ 276 BMessage childArchive; 277 if (ChildAt(i)->Archive(&childArchive, deep) == B_OK) 278 data->AddMessage("_views", &childArchive); 279 } 280 } 281 282 return B_OK; 283 } 284 285 286 void 287 BWindow::Quit() 288 { 289 if (!IsLocked()) { 290 const char *name = Name(); 291 if (!name) 292 name = "no-name"; 293 294 printf("ERROR - you must Lock a looper before calling Quit(), " 295 "team=%ld, looper=%s\n", Team(), name); 296 } 297 298 // Try to lock 299 if (!Lock()){ 300 // We're toast already 301 return; 302 } 303 304 while (!IsHidden()) { 305 Hide(); 306 } 307 308 // ... also its children 309 //detachTopView(); 310 311 if (fFlags & B_QUIT_ON_WINDOW_CLOSE) 312 be_app->PostMessage(B_QUIT_REQUESTED); 313 314 BLooper::Quit(); 315 } 316 317 318 void 319 BWindow::AddChild(BView *child, BView *before) 320 { 321 top_view->AddChild(child, before); 322 } 323 324 325 bool 326 BWindow::RemoveChild(BView *child) 327 { 328 return top_view->RemoveChild(child); 329 } 330 331 332 int32 333 BWindow::CountChildren() const 334 { 335 return top_view->CountChildren(); 336 } 337 338 339 BView * 340 BWindow::ChildAt(int32 index) const 341 { 342 return top_view->ChildAt(index); 343 } 344 345 346 void 347 BWindow::Minimize(bool minimize) 348 { 349 if (IsModal()) 350 return; 351 352 if (IsFloating()) 353 return; 354 355 if (fMinimized == minimize) 356 return; 357 358 fMinimized = minimize; 359 360 Lock(); 361 fLink->StartMessage(AS_WINDOW_MINIMIZE); 362 fLink->Attach<bool>(minimize); 363 fLink->Flush(); 364 Unlock(); 365 } 366 367 368 status_t 369 BWindow::SendBehind(const BWindow *window) 370 { 371 if (!window) 372 return B_ERROR; 373 374 Lock(); 375 fLink->StartMessage(AS_SEND_BEHIND); 376 fLink->Attach<int32>(_get_object_token_(window)); 377 fLink->Attach<team_id>(Team()); 378 379 int32 code = B_OK; 380 fLink->FlushWithReply(code); 381 382 Unlock(); 383 384 return code; 385 } 386 387 388 void 389 BWindow::Flush() const 390 { 391 const_cast<BWindow *>(this)->Lock(); 392 fLink->Flush(); 393 const_cast<BWindow *>(this)->Unlock(); 394 } 395 396 397 void 398 BWindow::Sync() const 399 { 400 const_cast<BWindow*>(this)->Lock(); 401 fLink->StartMessage(AS_SYNC); 402 403 // ToDo: why with reply? 404 int32 code; 405 fLink->FlushWithReply(code); 406 407 const_cast<BWindow*>(this)->Unlock(); 408 } 409 410 411 void 412 BWindow::DisableUpdates() 413 { 414 Lock(); 415 fLink->StartMessage(AS_DISABLE_UPDATES); 416 fLink->Flush(); 417 Unlock(); 418 } 419 420 421 void 422 BWindow::EnableUpdates() 423 { 424 Lock(); 425 fLink->StartMessage(AS_ENABLE_UPDATES); 426 fLink->Flush(); 427 Unlock(); 428 } 429 430 431 void 432 BWindow::BeginViewTransaction() 433 { 434 if (!fInTransaction) { 435 Lock(); 436 fLink->StartMessage(AS_BEGIN_TRANSACTION); 437 Unlock(); 438 439 fInTransaction = true; 440 } 441 } 442 443 444 void 445 BWindow::EndViewTransaction() 446 { 447 if (fInTransaction) { 448 Lock(); 449 fLink->StartMessage(AS_END_TRANSACTION); 450 fLink->Flush(); 451 Unlock(); 452 453 fInTransaction = false; 454 } 455 } 456 457 458 bool 459 BWindow::IsFront() const 460 { 461 if (IsActive()) 462 return true; 463 464 if (IsModal()) 465 return true; 466 467 return false; 468 } 469 470 471 void 472 BWindow::MessageReceived(BMessage *msg) 473 { 474 if (!msg->HasSpecifiers()) 475 return BLooper::MessageReceived(msg); 476 477 BMessage replyMsg(B_REPLY); 478 bool handled = false; 479 480 switch (msg->what) { 481 case B_GET_PROPERTY: 482 case B_SET_PROPERTY: { 483 BMessage specifier; 484 int32 what; 485 const char *prop; 486 int32 index; 487 488 if (msg->GetCurrentSpecifier(&index, &specifier, &what, &prop) != B_OK) 489 break; 490 491 if (!strcmp(prop, "Feel")) { 492 if (msg->what == B_GET_PROPERTY) { 493 replyMsg.AddInt32("result", (uint32)Feel()); 494 handled = true; 495 } else { 496 uint32 newFeel; 497 if (msg->FindInt32("data", (int32 *)&newFeel) == B_OK) { 498 SetFeel((window_feel)newFeel); 499 handled = true; 500 } 501 } 502 } else if (!strcmp(prop, "Flags")) { 503 if (msg->what == B_GET_PROPERTY) { 504 replyMsg.AddInt32("result", Flags()); 505 handled = true; 506 } else { 507 uint32 newFlags; 508 if (msg->FindInt32("data", (int32 *)&newFlags) == B_OK) { 509 SetFlags(newFlags); 510 handled = true; 511 } 512 } 513 } else if (!strcmp(prop, "Frame")) { 514 if (msg->what == B_GET_PROPERTY) { 515 replyMsg.AddRect("result", Frame()); 516 handled = true; 517 } else { 518 BRect newFrame; 519 if (msg->FindRect("data", &newFrame) == B_OK) { 520 MoveTo(newFrame.LeftTop()); 521 ResizeTo(newFrame.Width(), newFrame.Height()); 522 handled = true; 523 } 524 } 525 } else if (!strcmp(prop, "Hidden")) { 526 if (msg->what == B_GET_PROPERTY) { 527 replyMsg.AddBool("result", IsHidden()); 528 handled = true; 529 } else { 530 bool hide; 531 if (msg->FindBool("data", &hide) == B_OK) { 532 if (hide) { 533 if (!IsHidden()) 534 Hide(); 535 } else if (IsHidden()) 536 Show(); 537 538 handled = true; 539 } 540 } 541 } else if (!strcmp(prop, "Look")) { 542 if (msg->what == B_GET_PROPERTY) { 543 replyMsg.AddInt32("result", (uint32)Look()); 544 handled = true; 545 } else { 546 uint32 newLook; 547 if (msg->FindInt32("data", (int32 *)&newLook) == B_OK) { 548 SetLook((window_look)newLook); 549 handled = true; 550 } 551 } 552 } else if (!strcmp(prop, "Title")) { 553 if (msg->what == B_GET_PROPERTY) { 554 replyMsg.AddString("result", Title()); 555 handled = true; 556 } else { 557 const char *newTitle = NULL; 558 if (msg->FindString("data", &newTitle) == B_OK) { 559 SetTitle(newTitle); 560 handled = true; 561 } 562 } 563 } else if (!strcmp(prop, "Workspaces")) { 564 if (msg->what == B_GET_PROPERTY) { 565 replyMsg.AddInt32( "result", Workspaces()); 566 handled = true; 567 } else { 568 uint32 newWorkspaces; 569 if (msg->FindInt32("data", (int32 *)&newWorkspaces) == B_OK) { 570 SetWorkspaces(newWorkspaces); 571 handled = true; 572 } 573 } 574 } else if (!strcmp(prop, "Minimize")) { 575 if (msg->what == B_GET_PROPERTY) { 576 replyMsg.AddBool("result", IsMinimized()); 577 handled = true; 578 } else { 579 bool minimize; 580 if (msg->FindBool("data", &minimize) == B_OK) { 581 Minimize(minimize); 582 handled = true; 583 } 584 } 585 } 586 break; 587 } 588 } 589 590 if (handled) { 591 if (msg->what == B_SET_PROPERTY) 592 replyMsg.AddInt32("error", B_OK); 593 } else { 594 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD; 595 replyMsg.AddInt32("error", B_BAD_SCRIPT_SYNTAX); 596 replyMsg.AddString("message", "Didn't understand the specifier(s)"); 597 } 598 msg->SendReply(&replyMsg); 599 } 600 601 602 void 603 BWindow::DispatchMessage(BMessage *msg, BHandler *target) 604 { 605 if (!msg) 606 return; 607 608 switch (msg->what) { 609 case B_ZOOM: 610 Zoom(); 611 break; 612 613 case B_MINIMIZE: 614 { 615 bool minimize; 616 if (msg->FindBool("minimize", &minimize) == B_OK) 617 Minimize(minimize); 618 break; 619 } 620 621 case B_WINDOW_RESIZED: 622 { 623 int32 width, height; 624 if (msg->FindInt32("width", &width) == B_OK 625 && msg->FindInt32("height", &height) == B_OK) { 626 fFrame.right = fFrame.left + width; 627 fFrame.bottom = fFrame.top + height; 628 629 FrameResized(width, height); 630 } 631 break; 632 } 633 634 case B_WINDOW_MOVED: 635 { 636 BPoint origin; 637 if (msg->FindPoint("where", &origin) == B_OK) { 638 fFrame.OffsetTo(origin); 639 640 FrameMoved(origin); 641 } 642 break; 643 } 644 645 case B_WINDOW_ACTIVATED: 646 { 647 bool active; 648 if (msg->FindBool("active", &active) == B_OK) { 649 fActive = active; 650 handleActivation(active); 651 } 652 break; 653 } 654 655 case B_SCREEN_CHANGED: 656 { 657 BRect frame; 658 uint32 mode; 659 if (msg->FindRect("frame", &frame) == B_OK 660 && msg->FindInt32("mode", (int32 *)&mode) == B_OK) 661 ScreenChanged(frame, (color_space)mode); 662 break; 663 } 664 665 case B_WORKSPACE_ACTIVATED: 666 { 667 uint32 workspace; 668 bool active; 669 if (msg->FindInt32("workspace", (int32 *)&workspace) == B_OK 670 && msg->FindBool("active", &active) == B_OK) 671 WorkspaceActivated(workspace, active); 672 break; 673 } 674 675 case B_WORKSPACES_CHANGED: 676 { 677 uint32 oldWorkspace, newWorkspace; 678 if (msg->FindInt32("old", (int32 *)&oldWorkspace) == B_OK 679 && msg->FindInt32("new", (int32 *)&newWorkspace) == B_OK) 680 WorkspacesChanged(oldWorkspace, newWorkspace); 681 break; 682 } 683 684 case B_KEY_DOWN: 685 { 686 uint32 modifiers; 687 int32 rawChar; 688 const char *string = NULL; 689 msg->FindInt32("modifiers", (int32*)&modifiers); 690 msg->FindInt32("raw_char", &rawChar); 691 msg->FindString("bytes", &string); 692 693 // TODO: USE target !!!! 694 if (!_HandleKeyDown(string[0], (uint32)modifiers)) { 695 if (fFocus) 696 fFocus->KeyDown(string, strlen(string)); 697 else 698 printf("Adi: No Focus\n"); 699 } 700 break; 701 } 702 703 case B_KEY_UP: 704 { 705 const char *string = NULL; 706 msg->FindString("bytes", &string); 707 708 // TODO: USE target !!!! 709 if (fFocus) 710 fFocus->KeyUp(string, strlen(string)); 711 break; 712 } 713 714 case B_UNMAPPED_KEY_DOWN: 715 case B_UNMAPPED_KEY_UP: 716 case B_MODIFIERS_CHANGED: 717 if (target != this && target != top_view) 718 target->MessageReceived(msg); 719 break; 720 721 case B_MOUSE_WHEEL_CHANGED: 722 if (target != this && target != top_view) 723 target->MessageReceived(msg); 724 break; 725 726 case B_MOUSE_DOWN: 727 { 728 BPoint where; 729 uint32 modifiers; 730 uint32 buttons; 731 int32 clicks; 732 msg->FindPoint("where", &where); 733 msg->FindInt32("modifiers", (int32 *)&modifiers); 734 msg->FindInt32("buttons", (int32 *)&buttons); 735 msg->FindInt32("clicks", &clicks); 736 737 if (target && target != this && target != top_view) { 738 if (BView *view = dynamic_cast<BView *>(target)) { 739 view->ConvertFromScreen(&where); 740 view->MouseDown(where); 741 } else 742 target->MessageReceived(msg); 743 } 744 break; 745 } 746 747 case B_MOUSE_UP: 748 { 749 BPoint where; 750 uint32 modifiers; 751 msg->FindPoint("where", &where); 752 msg->FindInt32("modifiers", (int32 *)&modifiers); 753 754 if (target && target != this && target != top_view) { 755 if (BView *view = dynamic_cast<BView *>(target)) { 756 view->ConvertFromScreen(&where); 757 view->MouseUp(where); 758 } else 759 target->MessageReceived(msg); 760 } 761 break; 762 } 763 764 case B_MOUSE_MOVED: 765 { 766 BPoint where; 767 uint32 buttons; 768 uint32 transit; 769 msg->FindPoint("where", &where); 770 msg->FindInt32("buttons", (int32 *)&buttons); 771 msg->FindInt32("transit", (int32 *)&transit); 772 if (target && target != this && target != top_view) { 773 if (BView *view = dynamic_cast<BView *>(target)) { 774 fLastMouseMovedView = view; 775 view->ConvertFromScreen(&where); 776 view->MouseMoved(where, transit, NULL); 777 } else 778 target->MessageReceived(msg); 779 } 780 break; 781 } 782 783 case B_PULSE: 784 if (fPulseEnabled) { 785 top_view->_Pulse(); 786 fLink->Flush(); 787 } 788 break; 789 790 case B_QUIT_REQUESTED: 791 if (QuitRequested()) 792 Quit(); 793 break; 794 795 case _UPDATE_: 796 { 797 STRACE(("info:BWindow handling _UPDATE_.\n")); 798 BRect updateRect; 799 int32 token; 800 msg->FindRect("_rect", &updateRect); 801 msg->FindInt32("_token", &token); 802 803 fLink->StartMessage(AS_BEGIN_UPDATE); 804 DoUpdate(top_view, updateRect); 805 fLink->StartMessage(AS_END_UPDATE); 806 fLink->Flush(); 807 break; 808 } 809 810 case B_VIEW_RESIZED: 811 case B_VIEW_MOVED: 812 { 813 // NOTE: The problem with this implementation is that BView::Window()->CurrentMessage() 814 // will show this message, and not what it used to be on R5. This might break apps and 815 // we need to fix this here or change the way this feature is implemented. However, this 816 // implementation shows what has to be done when Layers are moved or resized inside the 817 // app_server. This message is generated from Layer::move_by() and resize_by() in 818 // Layer::AddToViewsWithInvalidCoords(). 819 int32 token; 820 BPoint frameLeftTop; 821 float width; 822 float height; 823 BView *view; 824 for (int32 i = 0; CurrentMessage() && msg->FindInt32("_token", i, &token) >= B_OK; i++) { 825 if (token >= 0) { 826 msg->FindPoint("where", i, &frameLeftTop); 827 msg->FindFloat("width", i, &width); 828 msg->FindFloat("height", i, &height); 829 if ((view = findView(top_view, token))) { 830 // update the views offset in parent 831 if (view->LeftTop() != frameLeftTop) { 832 //printf("updating position (%.1f, %.1f): %s\n", frameLeftTop.x, frameLeftTop.y, view->Name()); 833 view->fParentOffset = frameLeftTop; 834 835 // optionally call FrameMoved 836 if (view->fFlags & B_FRAME_EVENTS) { 837 STRACE(("Calling BView(%s)::FrameMoved( %.1f, %.1f )\n", view->Name(), 838 frameLeftTop.x, frameLeftTop.y)); 839 view->FrameMoved(frameLeftTop); 840 } 841 } 842 // update the views width and height 843 if (view->fBounds.Width() != width || view->fBounds.Height() != height) { 844 //printf("updating size (%.1f, %.1f): %s\n", width, height, view->Name()); 845 // TODO: does this work when a views left/top side is resized? 846 view->fBounds.right = view->fBounds.left + width; 847 view->fBounds.bottom = view->fBounds.top + height; 848 // optionally call FrameResized 849 if (view->fFlags & B_FRAME_EVENTS) { 850 STRACE(("Calling BView(%s)::FrameResized( %f, %f )\n", view->Name(), width, height)); 851 view->FrameResized(width, height); 852 } 853 } 854 } else { 855 fprintf(stderr, "***PANIC: BW: Can't find view with ID: %ld !***\n", token); 856 } 857 } 858 } 859 break; 860 } 861 862 case _MENUS_DONE_: 863 MenusEnded(); 864 break; 865 866 // These two are obviously some kind of old scripting messages 867 // this is NOT an app_server message and we have to be cautious 868 case B_WINDOW_MOVE_BY: 869 { 870 BPoint offset; 871 if (msg->FindPoint("data", &offset) == B_OK) 872 MoveBy(offset.x, offset.y); 873 else 874 msg->SendReply(B_MESSAGE_NOT_UNDERSTOOD); 875 break; 876 } 877 878 // this is NOT an app_server message and we have to be cautious 879 case B_WINDOW_MOVE_TO: 880 { 881 BPoint origin; 882 if (msg->FindPoint("data", &origin) == B_OK) 883 MoveTo(origin); 884 else 885 msg->SendReply(B_MESSAGE_NOT_UNDERSTOOD); 886 break; 887 } 888 889 default: 890 BLooper::DispatchMessage(msg, target); 891 break; 892 } 893 } 894 895 896 void 897 BWindow::FrameMoved(BPoint new_position) 898 { 899 // does nothing 900 // Hook function 901 } 902 903 904 void 905 BWindow::FrameResized(float new_width, float new_height) 906 { 907 // does nothing 908 // Hook function 909 } 910 911 912 void 913 BWindow::WorkspacesChanged(uint32 old_ws, uint32 new_ws) 914 { 915 // does nothing 916 // Hook function 917 } 918 919 920 void 921 BWindow::WorkspaceActivated(int32 ws, bool state) 922 { 923 // does nothing 924 // Hook function 925 } 926 927 928 void 929 BWindow::MenusBeginning() 930 { 931 // does nothing 932 // Hook function 933 } 934 935 936 void 937 BWindow::MenusEnded() 938 { 939 // does nothing 940 // Hook function 941 } 942 943 944 void 945 BWindow::SetSizeLimits(float minWidth, float maxWidth, 946 float minHeight, float maxHeight) 947 { 948 if (minWidth > maxWidth || minHeight > maxHeight) 949 return; 950 951 if (Lock()) { 952 fLink->StartMessage(AS_SET_SIZE_LIMITS); 953 fLink->Attach<float>(minWidth); 954 fLink->Attach<float>(maxWidth); 955 fLink->Attach<float>(minHeight); 956 fLink->Attach<float>(maxHeight); 957 958 int32 code; 959 if (fLink->FlushWithReply(code) == B_OK 960 && code == SERVER_TRUE) { 961 // read the values that were really enforced on 962 // the server side (the window frame could have 963 // been changed, too) 964 fLink->Read<BRect>(&fFrame); 965 fLink->Read<float>(&fMinWidth); 966 fLink->Read<float>(&fMaxWidth); 967 fLink->Read<float>(&fMinHeight); 968 fLink->Read<float>(&fMaxHeight); 969 } 970 Unlock(); 971 } 972 } 973 974 975 void 976 BWindow::GetSizeLimits(float *minWidth, float *maxWidth, 977 float *minHeight, float *maxHeight) 978 { 979 // TODO: What about locking?!? 980 *minHeight = fMinHeight; 981 *minWidth = fMinWidth; 982 *maxHeight = fMaxHeight; 983 *maxWidth = fMaxWidth; 984 } 985 986 987 void 988 BWindow::SetZoomLimits(float maxWidth, float maxHeight) 989 { 990 // TODO: What about locking?!? 991 if (maxWidth > fMaxWidth) 992 maxWidth = fMaxWidth; 993 else 994 fMaxZoomWidth = maxWidth; 995 996 if (maxHeight > fMaxHeight) 997 maxHeight = fMaxHeight; 998 else 999 fMaxZoomHeight = maxHeight; 1000 } 1001 1002 1003 void 1004 BWindow::Zoom(BPoint rec_position, float rec_width, float rec_height) 1005 { 1006 // this is also a Hook function! 1007 1008 MoveTo(rec_position); 1009 ResizeTo(rec_width, rec_height); 1010 } 1011 1012 1013 void 1014 BWindow::Zoom() 1015 { 1016 // TODO: broken. 1017 // TODO: What about locking?!? 1018 float minWidth, minHeight; 1019 BScreen screen; 1020 1021 /* 1022 from BeBook: 1023 However, if the window's rectangle already matches these "zoom" dimensions 1024 (give or take a few pixels), Zoom() passes the window's previous 1025 ("non-zoomed") size and location. (??????) 1026 */ 1027 1028 if (Frame().Width() == fMaxZoomWidth && Frame().Height() == fMaxZoomHeight) { 1029 BPoint position( Frame().left, Frame().top); 1030 Zoom(position, fMaxZoomWidth, fMaxZoomHeight); 1031 return; 1032 } 1033 1034 /* From BeBook: 1035 The dimensions that non-virtual Zoom() passes to hook Zoom() are deduced from 1036 the smallest of three rectangles: 1037 */ 1038 1039 // 1) the rectangle defined by SetZoomLimits(), 1040 minHeight = fMaxZoomHeight; 1041 minWidth = fMaxZoomWidth; 1042 1043 // 2) the rectangle defined by SetSizeLimits() 1044 if (fMaxHeight < minHeight) 1045 minHeight = fMaxHeight; 1046 if (fMaxWidth < minWidth) 1047 minWidth = fMaxWidth; 1048 1049 // 3) the screen rectangle 1050 if (screen.Frame().Width() < minWidth) 1051 minWidth = screen.Frame().Width(); 1052 if (screen.Frame().Height() < minHeight) 1053 minHeight = screen.Frame().Height(); 1054 1055 Zoom(Frame().LeftTop(), minWidth, minHeight); 1056 } 1057 1058 1059 void 1060 BWindow::ScreenChanged(BRect screen_size, color_space depth) 1061 { 1062 // Hook function 1063 // does nothing 1064 } 1065 1066 1067 void 1068 BWindow::SetPulseRate(bigtime_t rate) 1069 { 1070 // TODO: What about locking?!? 1071 if (rate < 0) 1072 return; 1073 1074 // ToDo: isn't fPulseRunner enough? Why fPulseEnabled? 1075 if (fPulseRate == 0 && !fPulseEnabled) { 1076 fPulseRunner = new BMessageRunner(BMessenger(this), 1077 new BMessage(B_PULSE), rate); 1078 fPulseRate = rate; 1079 fPulseEnabled = true; 1080 return; 1081 } 1082 1083 if (rate == 0 && fPulseEnabled) { 1084 delete fPulseRunner; 1085 fPulseRunner = NULL; 1086 1087 fPulseRate = rate; 1088 fPulseEnabled = false; 1089 return; 1090 } 1091 1092 fPulseRunner->SetInterval(rate); 1093 } 1094 1095 1096 bigtime_t 1097 BWindow::PulseRate() const 1098 { 1099 // TODO: What about locking?!? 1100 return fPulseRate; 1101 } 1102 1103 1104 void 1105 BWindow::AddShortcut(uint32 key, uint32 modifiers, BMenuItem *item) 1106 { 1107 if (item->Message()) 1108 AddShortcut(key, modifiers, new BMessage(*item->Message()), this); 1109 } 1110 1111 1112 void 1113 BWindow::AddShortcut(uint32 key, uint32 modifiers, BMessage *msg) 1114 { 1115 AddShortcut(key, modifiers, msg, this); 1116 } 1117 1118 1119 void 1120 BWindow::AddShortcut(uint32 key, uint32 modifiers, BMessage *msg, BHandler *target) 1121 { 1122 // NOTE: I'm not sure if it is OK to use 'key' 1123 // TODO: What about locking?!? 1124 1125 if (msg == NULL) 1126 return; 1127 1128 int64 when = real_time_clock_usecs(); 1129 msg->AddInt64("when", when); 1130 1131 // TODO: make sure key is a lowercase char !!! 1132 1133 modifiers = modifiers | B_COMMAND_KEY; 1134 1135 _BCmdKey *cmdKey = new _BCmdKey(key, modifiers, msg); 1136 1137 if (target) 1138 cmdKey->targetToken = _get_object_token_(target); 1139 1140 // removes the shortcut from accelList if it exists! 1141 RemoveShortcut(key, modifiers); 1142 1143 accelList.AddItem((void*)cmdKey); 1144 } 1145 1146 1147 void 1148 BWindow::RemoveShortcut(uint32 key, uint32 modifiers) 1149 { 1150 // TODO: What about locking?!? 1151 int32 index = findShortcut(key, modifiers | B_COMMAND_KEY); 1152 if (index >=0) { 1153 _BCmdKey *cmdKey = (_BCmdKey *)accelList.ItemAt(index); 1154 1155 accelList.RemoveItem(index); 1156 delete cmdKey; 1157 } 1158 } 1159 1160 1161 BButton * 1162 BWindow::DefaultButton() const 1163 { 1164 // TODO: What about locking?!? 1165 return fDefaultButton; 1166 } 1167 1168 1169 void 1170 BWindow::SetDefaultButton(BButton *button) 1171 { 1172 // TODO: What about locking?!? 1173 if (fDefaultButton == button) 1174 return; 1175 1176 if (fDefaultButton != NULL) { 1177 // tell old button it's no longer the default one 1178 BButton *oldDefault = fDefaultButton; 1179 oldDefault->MakeDefault(false); 1180 oldDefault->Invalidate(); 1181 } 1182 1183 fDefaultButton = button; 1184 1185 if (button != NULL) { 1186 // notify new default button 1187 fDefaultButton->MakeDefault(true); 1188 fDefaultButton->Invalidate(); 1189 } 1190 } 1191 1192 1193 bool 1194 BWindow::NeedsUpdate() const 1195 { 1196 // TODO: What about locking?!? 1197 1198 const_cast<BWindow *>(this)->Lock(); 1199 fLink->StartMessage(AS_NEEDS_UPDATE); 1200 1201 int32 code = B_ERROR; 1202 fLink->FlushWithReply(code); 1203 1204 const_cast<BWindow *>(this)->Unlock(); 1205 1206 return code == B_OK; 1207 } 1208 1209 1210 void 1211 BWindow::UpdateIfNeeded() 1212 { 1213 // TODO: What about locking?!? 1214 // works only from this thread 1215 if (find_thread(NULL) != Thread()) 1216 return; 1217 1218 // Since we're blocking the event loop, we need to retrieve 1219 // all messages that are pending on the port. 1220 DequeueAll(); 1221 1222 BMessageQueue *queue = MessageQueue(); 1223 queue->Lock(); 1224 1225 // First process and remove any _UPDATE_ message in the queue 1226 // According to Adi, there can only be one at a time 1227 1228 BMessage *msg; 1229 for (int32 i = 0; (msg = queue->FindMessage(i)) != NULL; i++) { 1230 if (msg->what == _UPDATE_) { 1231 BWindow::DispatchMessage(msg, this); 1232 // we need to make sure that no overridden method is called 1233 // here; for BWindow::DispatchMessage() we now exactly what 1234 // will happen 1235 queue->RemoveMessage(msg); 1236 delete msg; 1237 break; 1238 } 1239 } 1240 1241 queue->Unlock(); 1242 } 1243 1244 1245 BView * 1246 BWindow::FindView(const char *viewName) const 1247 { 1248 // TODO: What about locking?!? 1249 return findView(top_view, viewName); 1250 } 1251 1252 1253 BView * 1254 BWindow::FindView(BPoint point) const 1255 { 1256 // TODO: What about locking?!? 1257 return findView(top_view, point); 1258 } 1259 1260 1261 BView *BWindow::CurrentFocus() const 1262 { 1263 // TODO: What about locking?!? 1264 return fFocus; 1265 } 1266 1267 1268 void 1269 BWindow::Activate(bool active) 1270 { 1271 // TODO: What about locking?!? 1272 if (IsHidden()) 1273 return; 1274 1275 Lock(); 1276 fLink->StartMessage(AS_ACTIVATE_WINDOW); 1277 fLink->Attach<bool>(active); 1278 fLink->Flush(); 1279 Unlock(); 1280 } 1281 1282 1283 void 1284 BWindow::WindowActivated(bool state) 1285 { 1286 // hook function 1287 // does nothing 1288 } 1289 1290 1291 void 1292 BWindow::ConvertToScreen(BPoint *point) const 1293 { 1294 point->x += fFrame.left; 1295 point->y += fFrame.top; 1296 } 1297 1298 1299 BPoint 1300 BWindow::ConvertToScreen(BPoint point) const 1301 { 1302 return point + fFrame.LeftTop(); 1303 } 1304 1305 1306 void 1307 BWindow::ConvertFromScreen(BPoint *point) const 1308 { 1309 point->x -= fFrame.left; 1310 point->y -= fFrame.top; 1311 } 1312 1313 1314 BPoint 1315 BWindow::ConvertFromScreen(BPoint point) const 1316 { 1317 return point - fFrame.LeftTop(); 1318 } 1319 1320 1321 void 1322 BWindow::ConvertToScreen(BRect *rect) const 1323 { 1324 rect->OffsetBy(fFrame.LeftTop()); 1325 } 1326 1327 1328 BRect 1329 BWindow::ConvertToScreen(BRect rect) const 1330 { 1331 return rect.OffsetByCopy(fFrame.LeftTop()); 1332 } 1333 1334 1335 void 1336 BWindow::ConvertFromScreen(BRect* rect) const 1337 { 1338 rect->OffsetBy(-fFrame.left, -fFrame.top); 1339 } 1340 1341 1342 BRect 1343 BWindow::ConvertFromScreen(BRect rect) const 1344 { 1345 return rect.OffsetByCopy(-fFrame.left, -fFrame.top); 1346 } 1347 1348 1349 bool 1350 BWindow::IsMinimized() const 1351 { 1352 // Hiding takes precendence over minimization!!! 1353 if (IsHidden()) 1354 return false; 1355 1356 return fMinimized; 1357 } 1358 1359 1360 BRect 1361 BWindow::Bounds() const 1362 { 1363 return BRect(0, 0, fFrame.Width(), fFrame.Height()); 1364 } 1365 1366 1367 BRect 1368 BWindow::Frame() const 1369 { 1370 return fFrame; 1371 } 1372 1373 1374 const char * 1375 BWindow::Title() const 1376 { 1377 return fTitle; 1378 } 1379 1380 1381 void 1382 BWindow::SetTitle(const char *title) 1383 { 1384 if (title == NULL) 1385 title = ""; 1386 1387 free(fTitle); 1388 fTitle = strdup(title); 1389 1390 // we will change BWindow's thread name to "w>window title" 1391 1392 char threadName[B_OS_NAME_LENGTH]; 1393 strcpy(threadName, "w>"); 1394 #ifdef __HAIKU__ 1395 strlcat(threadName, title, B_OS_NAME_LENGTH); 1396 #else 1397 int32 length = strlen(title); 1398 length = min_c(length, B_OS_NAME_LENGTH - 3); 1399 memcpy(threadName + 2, title, length); 1400 threadName[length + 2] = '\0'; 1401 #endif 1402 1403 // change the handler's name 1404 SetName(threadName); 1405 1406 // if the message loop has been started... 1407 if (Thread() >= B_OK) { 1408 rename_thread(Thread(), threadName); 1409 1410 // we notify the app_server so we can actually see the change 1411 if (Lock()) { 1412 fLink->StartMessage(AS_SET_WINDOW_TITLE); 1413 fLink->AttachString(fTitle); 1414 fLink->Flush(); 1415 Unlock(); 1416 } 1417 } 1418 } 1419 1420 1421 bool 1422 BWindow::IsActive() const 1423 { 1424 return fActive; 1425 } 1426 1427 1428 void 1429 BWindow::SetKeyMenuBar(BMenuBar *bar) 1430 { 1431 fKeyMenuBar = bar; 1432 } 1433 1434 1435 BMenuBar * 1436 BWindow::KeyMenuBar() const 1437 { 1438 return fKeyMenuBar; 1439 } 1440 1441 1442 bool 1443 BWindow::IsModal() const 1444 { 1445 return fFeel == B_MODAL_SUBSET_WINDOW_FEEL 1446 || fFeel == B_MODAL_APP_WINDOW_FEEL 1447 || fFeel == B_MODAL_ALL_WINDOW_FEEL; 1448 } 1449 1450 1451 bool 1452 BWindow::IsFloating() const 1453 { 1454 return fFeel == B_FLOATING_SUBSET_WINDOW_FEEL 1455 || fFeel == B_FLOATING_APP_WINDOW_FEEL 1456 || fFeel == B_FLOATING_ALL_WINDOW_FEEL; 1457 } 1458 1459 1460 status_t 1461 BWindow::AddToSubset(BWindow *window) 1462 { 1463 if (window == NULL || window->Feel() != B_NORMAL_WINDOW_FEEL 1464 || (fFeel != B_MODAL_SUBSET_WINDOW_FEEL 1465 && fFeel != B_FLOATING_SUBSET_WINDOW_FEEL)) 1466 return B_BAD_VALUE; 1467 1468 team_id team = Team(); 1469 1470 Lock(); 1471 fLink->StartMessage(AS_ADD_TO_SUBSET); 1472 fLink->Attach<int32>(_get_object_token_(window)); 1473 fLink->Attach<team_id>(team); 1474 1475 int32 code = SERVER_FALSE; 1476 fLink->FlushWithReply(code); 1477 1478 Unlock(); 1479 1480 return code == SERVER_TRUE ? B_OK : B_ERROR; 1481 } 1482 1483 1484 status_t 1485 BWindow::RemoveFromSubset(BWindow *window) 1486 { 1487 if (window == NULL || window->Feel() != B_NORMAL_WINDOW_FEEL 1488 || (fFeel != B_MODAL_SUBSET_WINDOW_FEEL 1489 && fFeel != B_FLOATING_SUBSET_WINDOW_FEEL)) 1490 return B_BAD_VALUE; 1491 1492 team_id team = Team(); 1493 1494 Lock(); 1495 fLink->StartMessage(AS_REM_FROM_SUBSET); 1496 fLink->Attach<int32>(_get_object_token_(window)); 1497 fLink->Attach<team_id>(team); 1498 1499 int32 code; 1500 fLink->FlushWithReply(code); 1501 Unlock(); 1502 1503 return code == SERVER_TRUE ? B_OK : B_ERROR; 1504 } 1505 1506 1507 status_t 1508 BWindow::Perform(perform_code d, void *arg) 1509 { 1510 return BLooper::Perform(d, arg); 1511 } 1512 1513 1514 status_t 1515 BWindow::SetType(window_type type) 1516 { 1517 window_look look; 1518 window_feel feel; 1519 decomposeType(type, &look, &feel); 1520 1521 status_t status = SetLook(look); 1522 if (status == B_OK) 1523 status = SetFeel(feel); 1524 1525 return status; 1526 } 1527 1528 1529 window_type 1530 BWindow::Type() const 1531 { 1532 return composeType(fLook, fFeel); 1533 } 1534 1535 1536 status_t 1537 BWindow::SetLook(window_look look) 1538 { 1539 BAutolock locker(this); 1540 1541 fLink->StartMessage(AS_SET_LOOK); 1542 fLink->Attach<int32>((int32)look); 1543 1544 int32 code; 1545 status_t status = fLink->FlushWithReply(code); 1546 1547 // ToDo: the server should probably return something more meaningful, anyway 1548 if (status == B_OK && code == SERVER_TRUE) { 1549 fLook = look; 1550 return B_OK; 1551 } 1552 1553 return B_ERROR; 1554 } 1555 1556 1557 window_look 1558 BWindow::Look() const 1559 { 1560 return fLook; 1561 } 1562 1563 1564 status_t 1565 BWindow::SetFeel(window_feel feel) 1566 { 1567 // ToDo: that should probably be done by the server, not the window 1568 if (feel != B_NORMAL_WINDOW_FEEL 1569 && feel != B_MODAL_SUBSET_WINDOW_FEEL 1570 && feel != B_MODAL_APP_WINDOW_FEEL 1571 && feel != B_MODAL_ALL_WINDOW_FEEL 1572 && feel != B_FLOATING_SUBSET_WINDOW_FEEL 1573 && feel != B_FLOATING_APP_WINDOW_FEEL 1574 && feel != B_FLOATING_ALL_WINDOW_FEEL) 1575 return B_BAD_VALUE; 1576 1577 Lock(); 1578 fLink->StartMessage(AS_SET_FEEL); 1579 fLink->Attach<int32>((int32)feel); 1580 fLink->Flush(); 1581 Unlock(); 1582 1583 // ToDo: return code from server? 1584 fFeel = feel; 1585 1586 return B_OK; 1587 } 1588 1589 1590 window_feel 1591 BWindow::Feel() const 1592 { 1593 return fFeel; 1594 } 1595 1596 1597 status_t 1598 BWindow::SetFlags(uint32 flags) 1599 { 1600 1601 Lock(); 1602 fLink->StartMessage(AS_SET_FLAGS); 1603 fLink->Attach<uint32>(flags); 1604 1605 int32 code = SERVER_FALSE; 1606 fLink->FlushWithReply(code); 1607 1608 Unlock(); 1609 1610 if (code == SERVER_TRUE) { 1611 fFlags = flags; 1612 return B_OK; 1613 } 1614 1615 return B_ERROR; 1616 } 1617 1618 1619 uint32 1620 BWindow::Flags() const 1621 { 1622 return fFlags; 1623 } 1624 1625 1626 status_t 1627 BWindow::SetWindowAlignment(window_alignment mode, 1628 int32 h, int32 hOffset, int32 width, int32 widthOffset, 1629 int32 v, int32 vOffset, int32 height, int32 heightOffset) 1630 { 1631 if ((mode & (B_BYTE_ALIGNMENT | B_PIXEL_ALIGNMENT)) == 0 1632 || (hOffset >= 0 && hOffset <= h) 1633 || (vOffset >= 0 && vOffset <= v) 1634 || (widthOffset >= 0 && widthOffset <= width) 1635 || (heightOffset >= 0 && heightOffset <= height)) 1636 return B_BAD_VALUE; 1637 1638 // TODO: test if hOffset = 0 and set it to 1 if true. 1639 1640 Lock(); 1641 fLink->StartMessage(AS_SET_ALIGNMENT); 1642 fLink->Attach<int32>((int32)mode); 1643 fLink->Attach<int32>(h); 1644 fLink->Attach<int32>(hOffset); 1645 fLink->Attach<int32>(width); 1646 fLink->Attach<int32>(widthOffset); 1647 fLink->Attach<int32>(v); 1648 fLink->Attach<int32>(vOffset); 1649 fLink->Attach<int32>(height); 1650 fLink->Attach<int32>(heightOffset); 1651 1652 int32 code = SERVER_FALSE; 1653 fLink->FlushWithReply(code); 1654 1655 Unlock(); 1656 1657 if (code == SERVER_TRUE) 1658 return B_OK; 1659 1660 return B_ERROR; 1661 } 1662 1663 1664 status_t 1665 BWindow::GetWindowAlignment(window_alignment *mode, 1666 int32 *h, int32 *hOffset, int32 *width, int32 *widthOffset, 1667 int32 *v, int32 *vOffset, int32 *height, int32 *heightOffset) const 1668 { 1669 const_cast<BWindow *>(this)->Lock(); 1670 fLink->StartMessage(AS_GET_ALIGNMENT); 1671 1672 int32 code = SERVER_FALSE; 1673 if (fLink->FlushWithReply(code) == B_OK 1674 && code == SERVER_TRUE) { 1675 fLink->Read<int32>((int32 *)mode); 1676 fLink->Read<int32>(h); 1677 fLink->Read<int32>(hOffset); 1678 fLink->Read<int32>(width); 1679 fLink->Read<int32>(widthOffset); 1680 fLink->Read<int32>(v); 1681 fLink->Read<int32>(hOffset); 1682 fLink->Read<int32>(height); 1683 fLink->Read<int32>(heightOffset); 1684 } 1685 1686 const_cast<BWindow *>(this)->Unlock(); 1687 1688 if (code != SERVER_TRUE) 1689 return B_ERROR; 1690 1691 return B_OK; 1692 } 1693 1694 1695 uint32 1696 BWindow::Workspaces() const 1697 { 1698 uint32 workspaces = 0; 1699 1700 const_cast<BWindow *>(this)->Lock(); 1701 fLink->StartMessage(AS_GET_WORKSPACES); 1702 1703 int32 code; 1704 if (fLink->FlushWithReply(code) == B_OK 1705 && code == SERVER_TRUE) 1706 fLink->Read<uint32>(&workspaces); 1707 1708 const_cast<BWindow *>(this)->Unlock(); 1709 1710 // TODO: shouldn't we cache? 1711 return workspaces; 1712 } 1713 1714 1715 void 1716 BWindow::SetWorkspaces(uint32 workspaces) 1717 { 1718 // TODO: don't forget about Tracker's background window. 1719 if (fFeel != B_NORMAL_WINDOW_FEEL) 1720 return; 1721 1722 Lock(); 1723 fLink->StartMessage(AS_SET_WORKSPACES); 1724 fLink->Attach<uint32>(workspaces); 1725 fLink->Flush(); 1726 Unlock(); 1727 } 1728 1729 1730 BView * 1731 BWindow::LastMouseMovedView() const 1732 { 1733 return fLastMouseMovedView; 1734 } 1735 1736 1737 void 1738 BWindow::MoveBy(float dx, float dy) 1739 { 1740 if (dx == 0.0 && dy == 0.0) 1741 return; 1742 1743 Lock(); 1744 1745 fLink->StartMessage(AS_WINDOW_MOVE); 1746 fLink->Attach<float>(dx); 1747 fLink->Attach<float>(dy); 1748 fLink->Flush(); 1749 1750 fFrame.OffsetBy(dx, dy); 1751 1752 Unlock(); 1753 } 1754 1755 1756 void 1757 BWindow::MoveTo(BPoint point) 1758 { 1759 Lock(); 1760 1761 if (fFrame.left != point.x || fFrame.top != point.y) { 1762 float xOffset = point.x - fFrame.left; 1763 float yOffset = point.y - fFrame.top; 1764 1765 MoveBy(xOffset, yOffset); 1766 } 1767 1768 Unlock(); 1769 } 1770 1771 1772 void 1773 BWindow::MoveTo(float x, float y) 1774 { 1775 MoveTo(BPoint(x, y)); 1776 } 1777 1778 1779 void 1780 BWindow::ResizeBy(float dx, float dy) 1781 { 1782 Lock(); 1783 // stay in minimum & maximum frame limits 1784 if (fFrame.Width() + dx < fMinWidth) 1785 dx = fMinWidth - fFrame.Width(); 1786 if (fFrame.Width() + dx > fMaxWidth) 1787 dx = fMaxWidth - fFrame.Width(); 1788 if (fFrame.Height() + dy < fMinHeight) 1789 dy = fMinHeight - fFrame.Height(); 1790 if (fFrame.Height() + dy > fMaxHeight) 1791 dy = fMaxHeight - fFrame.Height(); 1792 1793 if (dx != 0.0 || dy != 0.0) { 1794 fLink->StartMessage(AS_WINDOW_RESIZE); 1795 fLink->Attach<float>(dx); 1796 fLink->Attach<float>(dy); 1797 fLink->Flush(); 1798 1799 fFrame.SetRightBottom(fFrame.RightBottom() + BPoint(dx, dy)); 1800 } 1801 Unlock(); 1802 } 1803 1804 1805 void 1806 BWindow::ResizeTo(float width, float height) 1807 { 1808 Lock(); 1809 ResizeBy(width - fFrame.Width(), height - fFrame.Height()); 1810 Unlock(); 1811 } 1812 1813 1814 void 1815 BWindow::Show() 1816 { 1817 bool isLocked = this->IsLocked(); 1818 1819 fShowLevel--; 1820 1821 if (fShowLevel == 0) { 1822 STRACE(("BWindow(%s): sending AS_SHOW_WINDOW message...\n", Name())); 1823 if (Lock()) { 1824 fLink->StartMessage(AS_SHOW_WINDOW); 1825 fLink->Flush(); 1826 Unlock(); 1827 } 1828 } 1829 1830 // if it's the fist time Show() is called... start the Looper thread. 1831 if (Thread() == B_ERROR) { 1832 // normally this won't happen, but I want to be sure! 1833 if (!isLocked) 1834 Lock(); 1835 Run(); 1836 } 1837 } 1838 1839 1840 void 1841 BWindow::Hide() 1842 { 1843 if (fShowLevel == 0 && Lock()) { 1844 fLink->StartMessage(AS_HIDE_WINDOW); 1845 fLink->Flush(); 1846 Unlock(); 1847 } 1848 fShowLevel++; 1849 } 1850 1851 1852 bool 1853 BWindow::IsHidden() const 1854 { 1855 return fShowLevel > 0; 1856 } 1857 1858 1859 bool 1860 BWindow::QuitRequested() 1861 { 1862 return BLooper::QuitRequested(); 1863 } 1864 1865 1866 thread_id 1867 BWindow::Run() 1868 { 1869 return BLooper::Run(); 1870 } 1871 1872 1873 status_t 1874 BWindow::GetSupportedSuites(BMessage *data) 1875 { 1876 if (data == NULL) 1877 return B_BAD_VALUE; 1878 1879 status_t status = data->AddString("Suites", "suite/vnd.Be-window"); 1880 if (status == B_OK) { 1881 BPropertyInfo propertyInfo(sWindowPropInfo); 1882 1883 status = data->AddFlat("message", &propertyInfo); 1884 if (status == B_OK) 1885 status = BLooper::GetSupportedSuites(data); 1886 } 1887 1888 return status; 1889 } 1890 1891 1892 BHandler * 1893 BWindow::ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier, 1894 int32 what, const char *property) 1895 { 1896 if (msg->what == B_WINDOW_MOVE_BY 1897 || msg->what == B_WINDOW_MOVE_TO) 1898 return this; 1899 1900 BPropertyInfo propertyInfo(sWindowPropInfo); 1901 if (propertyInfo.FindMatch(msg, index, specifier, what, property) >= 0) { 1902 if (!strcmp(property, "View")) { 1903 // we will NOT pop the current specifier 1904 return top_view; 1905 } else if (!strcmp(property, "MenuBar")) { 1906 if (fKeyMenuBar) { 1907 msg->PopSpecifier(); 1908 return fKeyMenuBar; 1909 } else { 1910 BMessage replyMsg(B_MESSAGE_NOT_UNDERSTOOD); 1911 replyMsg.AddInt32("error", B_NAME_NOT_FOUND); 1912 replyMsg.AddString("message", "This window doesn't have a main MenuBar"); 1913 msg->SendReply(&replyMsg); 1914 return NULL; 1915 } 1916 } else 1917 return this; 1918 } 1919 1920 return BLooper::ResolveSpecifier(msg, index, specifier, what, property); 1921 } 1922 1923 1924 // #pragma mark - 1925 //--------------------Private Methods------------------------------------------- 1926 1927 1928 void 1929 BWindow::InitData(BRect frame, const char* title, window_look look, 1930 window_feel feel, uint32 flags, uint32 workspace, int32 bitmapToken) 1931 { 1932 STRACE(("BWindow::InitData()\n")); 1933 1934 fTitle = NULL; 1935 1936 if (be_app == NULL) { 1937 debugger("You need a valid BApplication object before interacting with the app_server"); 1938 return; 1939 } 1940 1941 fFrame = frame; 1942 1943 // ToDo: that looks wrong... 1944 SetTitle(title ? title : "no_name_window"); 1945 1946 fFeel = feel; 1947 fLook = look; 1948 fFlags = flags; 1949 1950 fInTransaction = false; 1951 fActive = false; 1952 fShowLevel = 1; 1953 1954 top_view = NULL; 1955 fFocus = NULL; 1956 fLastMouseMovedView = NULL; 1957 fKeyMenuBar = NULL; 1958 fDefaultButton = NULL; 1959 1960 AddShortcut('X', B_COMMAND_KEY, new BMessage(B_CUT), NULL); 1961 AddShortcut('C', B_COMMAND_KEY, new BMessage(B_COPY), NULL); 1962 AddShortcut('V', B_COMMAND_KEY, new BMessage(B_PASTE), NULL); 1963 AddShortcut('A', B_COMMAND_KEY, new BMessage(B_SELECT_ALL), NULL); 1964 AddShortcut('W', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED)); 1965 1966 fPulseEnabled = false; 1967 fPulseRate = 0; 1968 fPulseRunner = NULL; 1969 1970 // TODO: is this correct??? should the thread loop be started??? 1971 //SetPulseRate( 500000 ); 1972 1973 // TODO: see if you can use 'fViewsNeedPulse' 1974 1975 fIsFilePanel = false; 1976 1977 // TODO: see WHEN is this used! 1978 fMaskActivated = false; 1979 1980 // TODO: see WHEN is this used! 1981 fWaitingForMenu = false; 1982 fMenuSem = -1; 1983 1984 fMinimized = false; 1985 1986 fMaxZoomHeight = 32768.0; 1987 fMaxZoomWidth = 32768.0; 1988 fMinHeight = 0.0; 1989 fMinWidth = 0.0; 1990 fMaxHeight = 32768.0; 1991 fMaxWidth = 32768.0; 1992 1993 fLastViewToken = B_NULL_TOKEN; 1994 1995 // TODO: other initializations! 1996 1997 // Create the server-side window 1998 1999 port_id receivePort = create_port(B_LOOPER_PORT_DEFAULT_CAPACITY, "w_rcv_port"); 2000 if (receivePort < B_OK) { 2001 debugger("Could not create BWindow's receive port, used for interacting with the app_server!"); 2002 delete this; 2003 return; 2004 } 2005 2006 STRACE(("BWindow::InitData(): contacting app_server...\n")); 2007 2008 // HERE we are in BApplication's thread, so for locking we use be_app variable 2009 // we'll lock the be_app to be sure we're the only one writing at BApplication's server port 2010 bool locked = false; 2011 if (!be_app->IsLocked()) { 2012 be_app->Lock(); 2013 locked = true; 2014 } 2015 2016 // let app_server know that a window has been created. 2017 fLink = new BPrivate::PortLink( 2018 BApplication::Private::ServerLink()->SenderPort(), receivePort); 2019 2020 if (bitmapToken < 0) { 2021 fLink->StartMessage(AS_CREATE_WINDOW); 2022 } else { 2023 fLink->StartMessage(AS_CREATE_OFFSCREEN_WINDOW); 2024 fLink->Attach<int32>(bitmapToken); 2025 } 2026 2027 fLink->Attach<BRect>(fFrame); 2028 fLink->Attach<uint32>((uint32)fLook); 2029 fLink->Attach<uint32>((uint32)fFeel); 2030 fLink->Attach<uint32>(fFlags); 2031 fLink->Attach<uint32>(workspace); 2032 fLink->Attach<int32>(_get_object_token_(this)); 2033 fLink->Attach<port_id>(receivePort); 2034 fLink->Attach<port_id>(fMsgPort); 2035 fLink->AttachString(title); 2036 2037 port_id sendPort; 2038 int32 code; 2039 if (fLink->FlushWithReply(code) == B_OK 2040 && code == SERVER_TRUE 2041 && fLink->Read<port_id>(&sendPort) == B_OK) { 2042 fLink->SetSenderPort(sendPort); 2043 2044 // read the frame size and its limits that were really 2045 // enforced on the server side 2046 2047 fLink->Read<BRect>(&fFrame); 2048 fLink->Read<float>(&fMinWidth); 2049 fLink->Read<float>(&fMaxWidth); 2050 fLink->Read<float>(&fMinHeight); 2051 fLink->Read<float>(&fMaxHeight); 2052 2053 fMaxZoomWidth = fMaxWidth; 2054 fMaxZoomHeight = fMaxHeight; 2055 } else 2056 sendPort = -1; 2057 2058 if (locked) 2059 be_app->Unlock(); 2060 2061 STRACE(("Server says that our send port is %ld\n", sendPort)); 2062 STRACE(("Window locked?: %s\n", IsLocked() ? "True" : "False")); 2063 2064 // build and register top_view with app_server 2065 BuildTopView(); 2066 } 2067 2068 2069 /** Reads all pending messages from the window port and put them into the queue. 2070 */ 2071 2072 void 2073 BWindow::DequeueAll() 2074 { 2075 // Get message count from port 2076 int32 count = port_count(fMsgPort); 2077 2078 for (int32 i = 0; i < count; i++) { 2079 BMessage *message = MessageFromPort(0); 2080 if (message != NULL) 2081 fQueue->AddMessage(message); 2082 } 2083 } 2084 2085 2086 // TODO: This here is a nearly full code duplication to BLooper::task_loop 2087 // but with one little difference: It uses the determine_target function 2088 // to tell what the later target of a message will be, if no explicit target 2089 // is supplied. This is important because we need to call the right targets 2090 // MessageFilter. For B_KEY_DOWN messages for example, not the BWindow but the 2091 // focus view will be the target of the message. This means that also the 2092 // focus views MessageFilters have to be checked before DispatchMessage and 2093 // not the ones of this BWindow. 2094 2095 void 2096 BWindow::task_looper() 2097 { 2098 STRACE(("info: BWindow::task_looper() started.\n")); 2099 2100 // Check that looper is locked (should be) 2101 AssertLocked(); 2102 // Unlock the looper 2103 Unlock(); 2104 2105 if (IsLocked()) 2106 debugger("window must not be locked!"); 2107 2108 // loop: As long as we are not terminating. 2109 while (!fTerminating) { 2110 // TODO: timeout determination algo 2111 // Read from message port (how do we determine what the timeout is?) 2112 BMessage* msg = MessageFromPort(); 2113 2114 // Did we get a message? 2115 if (msg) { 2116 // Add to queue 2117 fQueue->AddMessage(msg); 2118 } else 2119 continue; 2120 2121 // Get message count from port 2122 int32 msgCount = port_count(fMsgPort); 2123 for (int32 i = 0; i < msgCount; ++i) { 2124 // Read 'count' messages from port (so we will not block) 2125 // We use zero as our timeout since we know there is stuff there 2126 msg = MessageFromPort(0); 2127 // Add messages to queue 2128 if (msg) 2129 fQueue->AddMessage(msg); 2130 } 2131 2132 // loop: As long as there are messages in the queue and the port is 2133 // empty... and we are not terminating, of course. 2134 bool dispatchNextMessage = true; 2135 while (!fTerminating && dispatchNextMessage) { 2136 // Get next message from queue (assign to fLastMessage) 2137 fLastMessage = fQueue->NextMessage(); 2138 2139 // Lock the looper 2140 Lock(); 2141 if (!fLastMessage) { 2142 // No more messages: Unlock the looper and terminate the 2143 // dispatch loop. 2144 dispatchNextMessage = false; 2145 } else { 2146 // Get the target handler 2147 // Use BMessage friend functions to determine if we are using the 2148 // preferred handler, or if a target has been specified 2149 BHandler* handler; 2150 if (_use_preferred_target_(fLastMessage)) { 2151 handler = fPreferred; 2152 } else { 2153 /** 2154 @note Here is where all the token stuff starts to 2155 make sense. How, exactly, do we determine 2156 what the target BHandler is? If we look at 2157 BMessage, we see an int32 field, fTarget. 2158 Amazingly, we happen to have a global mapping 2159 of BHandler pointers to int32s! 2160 */ 2161 gDefaultTokens.GetToken(_get_message_target_(fLastMessage), 2162 B_HANDLER_TOKEN, (void **)&handler); 2163 } 2164 2165 if (!handler) { 2166 handler = determine_target(fLastMessage, handler, false); 2167 if (!handler) 2168 handler = this; 2169 } 2170 2171 // Is this a scripting message? (BMessage::HasSpecifiers()) 2172 if (fLastMessage->HasSpecifiers()) { 2173 int32 index = 0; 2174 // Make sure the current specifier is kosher 2175 if (fLastMessage->GetCurrentSpecifier(&index) == B_OK) 2176 handler = resolve_specifier(handler, fLastMessage); 2177 } 2178 2179 if (handler) { 2180 // Do filtering 2181 handler = top_level_filter(fLastMessage, handler); 2182 if (handler && handler->Looper() == this) 2183 DispatchMessage(fLastMessage, handler); 2184 } 2185 } 2186 2187 Unlock(); 2188 2189 // Delete the current message (fLastMessage) 2190 delete fLastMessage; 2191 fLastMessage = NULL; 2192 2193 // Are any messages on the port? 2194 if (port_count(fMsgPort) > 0) { 2195 // Do outer loop 2196 dispatchNextMessage = false; 2197 } 2198 } 2199 } 2200 } 2201 2202 2203 window_type 2204 BWindow::composeType(window_look look, 2205 window_feel feel) const 2206 { 2207 switch (feel) { 2208 case B_NORMAL_WINDOW_FEEL: 2209 switch (look) { 2210 case B_TITLED_WINDOW_LOOK: 2211 return B_TITLED_WINDOW; 2212 2213 case B_DOCUMENT_WINDOW_LOOK: 2214 return B_DOCUMENT_WINDOW; 2215 2216 case B_BORDERED_WINDOW_LOOK: 2217 return B_BORDERED_WINDOW; 2218 2219 default: 2220 return B_UNTYPED_WINDOW; 2221 } 2222 break; 2223 2224 case B_MODAL_APP_WINDOW_FEEL: 2225 if (look == B_MODAL_WINDOW_LOOK) 2226 return B_MODAL_WINDOW; 2227 break; 2228 2229 case B_FLOATING_APP_WINDOW_FEEL: 2230 if (look == B_FLOATING_WINDOW_LOOK) 2231 return B_FLOATING_WINDOW; 2232 break; 2233 2234 default: 2235 return B_UNTYPED_WINDOW; 2236 } 2237 2238 return B_UNTYPED_WINDOW; 2239 } 2240 2241 2242 void 2243 BWindow::decomposeType(window_type type, window_look *look, 2244 window_feel *feel) const 2245 { 2246 switch (type) { 2247 case B_TITLED_WINDOW: 2248 { 2249 *look = B_TITLED_WINDOW_LOOK; 2250 *feel = B_NORMAL_WINDOW_FEEL; 2251 break; 2252 } 2253 case B_DOCUMENT_WINDOW: 2254 { 2255 *look = B_DOCUMENT_WINDOW_LOOK; 2256 *feel = B_NORMAL_WINDOW_FEEL; 2257 break; 2258 } 2259 case B_MODAL_WINDOW: 2260 { 2261 *look = B_MODAL_WINDOW_LOOK; 2262 *feel = B_MODAL_APP_WINDOW_FEEL; 2263 break; 2264 } 2265 case B_FLOATING_WINDOW: 2266 { 2267 *look = B_FLOATING_WINDOW_LOOK; 2268 *feel = B_FLOATING_APP_WINDOW_FEEL; 2269 break; 2270 } 2271 case B_BORDERED_WINDOW: 2272 { 2273 *look = B_BORDERED_WINDOW_LOOK; 2274 *feel = B_NORMAL_WINDOW_FEEL; 2275 break; 2276 } 2277 case B_UNTYPED_WINDOW: 2278 { 2279 *look = B_TITLED_WINDOW_LOOK; 2280 *feel = B_NORMAL_WINDOW_FEEL; 2281 break; 2282 } 2283 default: 2284 { 2285 *look = B_TITLED_WINDOW_LOOK; 2286 *feel = B_NORMAL_WINDOW_FEEL; 2287 break; 2288 } 2289 } 2290 } 2291 2292 2293 void 2294 BWindow::BuildTopView() 2295 { 2296 STRACE(("BuildTopView(): enter\n")); 2297 2298 BRect frame = fFrame.OffsetToCopy(B_ORIGIN); 2299 top_view = new BView(frame, "top_view", 2300 B_FOLLOW_ALL, B_WILL_DRAW); 2301 top_view->top_level_view = true; 2302 2303 //inhibit check_lock() 2304 fLastViewToken = _get_object_token_(top_view); 2305 2306 // set top_view's owner, add it to window's eligible handler list 2307 // and also set its next handler to be this window. 2308 2309 STRACE(("Calling setowner top_view = %p this = %p.\n", 2310 top_view, this)); 2311 2312 top_view->_SetOwner(this); 2313 2314 //we can't use AddChild() because this is the top_view 2315 top_view->attachView(top_view); 2316 2317 STRACE(("BuildTopView ended\n")); 2318 } 2319 2320 2321 void 2322 BWindow::prepareView(BView *view) 2323 { 2324 // TODO: implement 2325 } 2326 2327 2328 void 2329 BWindow::attachView(BView *view) 2330 { 2331 // TODO: implement 2332 } 2333 2334 2335 void 2336 BWindow::detachView(BView *view) 2337 { 2338 // TODO: implement 2339 } 2340 2341 2342 void 2343 BWindow::setFocus(BView *focusView, bool notifyInputServer) 2344 { 2345 if (fFocus == focusView) 2346 return; 2347 2348 if (focusView) 2349 focusView->MakeFocus(true); 2350 2351 // TODO: Notify the input server if we are passing focus 2352 // from a view which has the B_INPUT_METHOD_AWARE to a one 2353 // which does not, or vice-versa 2354 if (notifyInputServer) { 2355 // TODO: Send a message to input server using 2356 // control_input_server() 2357 } 2358 } 2359 2360 2361 void 2362 BWindow::handleActivation(bool active) 2363 { 2364 WindowActivated(active); 2365 2366 // recursively call hook function 'WindowActivated(bool)' 2367 // for all views attached to this window. 2368 top_view->_Activate(active); 2369 } 2370 2371 2372 BHandler * 2373 BWindow::determine_target(BMessage *msg, BHandler *target, bool pref) 2374 { 2375 // TODO: this is mostly guessed; check for correctness. 2376 // I think this function is used to determine if a BView will be 2377 // the target of a message. This is used in the BLooper::task_loop 2378 // to determine what BHandler will dispatch the message and what filters 2379 // should be checked before doing so. 2380 2381 switch (msg->what) { 2382 case B_KEY_DOWN: 2383 case B_KEY_UP: 2384 case B_UNMAPPED_KEY_DOWN: 2385 case B_UNMAPPED_KEY_UP: 2386 case B_MODIFIERS_CHANGED: 2387 case B_MOUSE_WHEEL_CHANGED: 2388 // these messages will be dispatched by the focus view later 2389 return fFocus; 2390 2391 case B_MOUSE_DOWN: 2392 case B_MOUSE_UP: 2393 case B_MOUSE_MOVED: 2394 // TODO: find out how to determine the target for these 2395 break; 2396 2397 case B_PULSE: 2398 case B_QUIT_REQUESTED: 2399 // TODO: test wether R5 will let BView dispatch these messages 2400 break; 2401 2402 case B_VIEW_RESIZED: 2403 case B_VIEW_MOVED: { 2404 int32 token = B_NULL_TOKEN; 2405 msg->FindInt32("_token", &token); 2406 BView *view = findView(top_view, token); 2407 if (view) 2408 return view; 2409 break; 2410 } 2411 default: 2412 break; 2413 } 2414 2415 return target; 2416 } 2417 2418 2419 bool 2420 BWindow::_HandleKeyDown(char key, uint32 modifiers) 2421 { 2422 // TODO: ask people if using 'raw_char' is OK ? 2423 2424 // handle BMenuBar key 2425 if (key == B_ESCAPE && (modifiers & B_COMMAND_KEY) != 0 2426 && fKeyMenuBar) { 2427 // TODO: ask Marc about 'fWaitingForMenu' member! 2428 2429 // fWaitingForMenu = true; 2430 fKeyMenuBar->StartMenuBar(0, true, false, NULL); 2431 return true; 2432 } 2433 2434 // Command+q has been pressed, so, we will quit 2435 if ((key == 'Q' || key == 'q') && (modifiers & B_COMMAND_KEY) != 0) { 2436 be_app->PostMessage(B_QUIT_REQUESTED); 2437 return true; 2438 } 2439 2440 // Keyboard navigation through views 2441 // (B_OPTION_KEY makes BTextViews and friends navigable, even in editing mode) 2442 if (key == B_TAB && (modifiers & (B_COMMAND_KEY | B_OPTION_KEY)) != 0) { 2443 _KeyboardNavigation(); 2444 return true; 2445 } 2446 2447 // Handle shortcuts 2448 int index; 2449 if ((index = findShortcut(key, modifiers)) >= 0) { 2450 _BCmdKey *cmdKey = (_BCmdKey*)accelList.ItemAt(index); 2451 2452 // we'll give the message to the focus view 2453 if (cmdKey->targetToken == B_ANY_TOKEN) { 2454 fFocus->MessageReceived(cmdKey->message); 2455 return true; 2456 } else { 2457 BHandler *target = NULL; 2458 int32 count = CountHandlers(); 2459 2460 // ToDo: this looks wrong: why not just send a message to the 2461 // target? Only if the target is a handler of this looper we 2462 // can do what is done below. 2463 2464 // search for a match through BLooper's list of eligible handlers 2465 for (int32 i = 0; i < count; i++) { 2466 BHandler *handler = HandlerAt(i); 2467 2468 // do we have a match? 2469 if (_get_object_token_(handler) == cmdKey->targetToken) { 2470 // yes, we do. 2471 target = handler; 2472 break; 2473 } 2474 } 2475 2476 if (target) 2477 target->MessageReceived(cmdKey->message); 2478 else { 2479 // if no handler was found, BWindow will handle the message 2480 MessageReceived(cmdKey->message); 2481 } 2482 } 2483 return true; 2484 } 2485 2486 // if <ENTER> is pressed and we have a default button 2487 if (DefaultButton() && key == B_ENTER) { 2488 const char *chars; 2489 CurrentMessage()->FindString("bytes", &chars); 2490 2491 DefaultButton()->KeyDown(chars, strlen(chars)); 2492 return true; 2493 } 2494 2495 return false; 2496 } 2497 2498 2499 void 2500 BWindow::_KeyboardNavigation() 2501 { 2502 BMessage *message = CurrentMessage(); 2503 if (message == NULL) 2504 return; 2505 2506 const char *bytes; 2507 uint32 modifiers; 2508 if (message->FindString("bytes", &bytes) != B_OK 2509 || bytes[0] != B_TAB) 2510 return; 2511 2512 message->FindInt32("modifiers", (int32*)&modifiers); 2513 2514 BView *nextFocus; 2515 int32 jumpGroups = modifiers & B_CONTROL_KEY ? B_NAVIGABLE_JUMP : B_NAVIGABLE; 2516 if (modifiers & B_SHIFT_KEY) 2517 nextFocus = _FindPreviousNavigable(fFocus, jumpGroups); 2518 else 2519 nextFocus = _FindNextNavigable(fFocus, jumpGroups); 2520 2521 if (nextFocus && nextFocus != fFocus) 2522 setFocus(nextFocus, false); 2523 } 2524 2525 2526 BMessage * 2527 BWindow::ConvertToMessage(void *raw, int32 code) 2528 { 2529 return BLooper::ConvertToMessage(raw, code); 2530 } 2531 2532 2533 int32 2534 BWindow::findShortcut(uint32 key, uint32 modifiers) 2535 { 2536 int32 count = accelList.CountItems(); 2537 2538 for (int32 index = 0; index < count; index++) { 2539 _BCmdKey *cmdKey = (_BCmdKey *)accelList.ItemAt(index); 2540 2541 if (cmdKey->key == key && cmdKey->modifiers == modifiers) 2542 return index; 2543 } 2544 2545 return -1; 2546 } 2547 2548 2549 BView * 2550 BWindow::findView(BView *view, int32 token) 2551 { 2552 if (_get_object_token_(view) == token) 2553 return view; 2554 2555 BView *child = view->fFirstChild; 2556 2557 while (child != NULL) { 2558 if ((view = findView(child, token)) != NULL) 2559 return view; 2560 2561 child = child->fNextSibling; 2562 } 2563 2564 return NULL; 2565 } 2566 2567 2568 BView * 2569 BWindow::findView(BView *view, const char *name) const 2570 { 2571 if (!strcmp(name, view->Name())) 2572 return view; 2573 2574 BView *child = view->fFirstChild; 2575 2576 while (child != NULL) { 2577 if ((view = findView(child, name)) != NULL) 2578 return view; 2579 2580 child = child->fNextSibling; 2581 } 2582 2583 return NULL; 2584 } 2585 2586 2587 BView * 2588 BWindow::findView(BView *view, BPoint point) const 2589 { 2590 if (view->Bounds().Contains(point) && !view->fFirstChild) 2591 return view; 2592 2593 BView *child = view->fFirstChild; 2594 2595 while (child != NULL) { 2596 if ((view = findView(child, point)) != NULL) 2597 return view; 2598 2599 child = child->fNextSibling; 2600 } 2601 2602 return NULL; 2603 } 2604 2605 2606 BView * 2607 BWindow::_FindNextNavigable(BView *focus, uint32 flags) 2608 { 2609 if (focus == NULL) 2610 focus = top_view; 2611 2612 BView *nextFocus = focus; 2613 2614 // Search the tree for views that accept focus 2615 while (true) { 2616 if (nextFocus->fFirstChild) 2617 nextFocus = nextFocus->fFirstChild; 2618 else if (nextFocus->fNextSibling) 2619 nextFocus = nextFocus->fNextSibling; 2620 else { 2621 while (!nextFocus->fNextSibling && nextFocus->fParent) 2622 nextFocus = nextFocus->fParent; 2623 2624 if (nextFocus == top_view) 2625 nextFocus = nextFocus->fFirstChild; 2626 else 2627 nextFocus = nextFocus->fNextSibling; 2628 } 2629 2630 // It means that the hole tree has been searched and there is no 2631 // view with B_NAVIGABLE_JUMP flag set! 2632 if (nextFocus == focus) 2633 return NULL; 2634 2635 if (nextFocus->Flags() & flags) 2636 return nextFocus; 2637 } 2638 } 2639 2640 2641 BView * 2642 BWindow::_FindPreviousNavigable(BView *focus, uint32 flags) 2643 { 2644 BView *prevFocus = focus; 2645 2646 // Search the tree for views that accept focus 2647 while (true) { 2648 BView *view; 2649 if ((view = findLastChild(prevFocus)) != NULL) 2650 prevFocus = view; 2651 else if (prevFocus->fPreviousSibling) 2652 prevFocus = prevFocus->fPreviousSibling; 2653 else { 2654 while (!prevFocus->fPreviousSibling && prevFocus->fParent) 2655 prevFocus = prevFocus->fParent; 2656 2657 if (prevFocus == top_view) 2658 prevFocus = findLastChild(prevFocus); 2659 else 2660 prevFocus = prevFocus->fPreviousSibling; 2661 } 2662 2663 // It means that the hole tree has been searched and there is no 2664 // view with B_NAVIGABLE_JUMP flag set! 2665 if (prevFocus == focus) 2666 return NULL; 2667 2668 if (prevFocus->Flags() & flags) 2669 return prevFocus; 2670 } 2671 } 2672 2673 2674 BView * 2675 BWindow::findLastChild(BView *parent) 2676 { 2677 BView *last = parent->fFirstChild; 2678 if (last == NULL) 2679 return NULL; 2680 2681 while (last->fNextSibling) 2682 last = last->fNextSibling; 2683 2684 return last; 2685 } 2686 2687 2688 void 2689 BWindow::drawAllViews(BView* aView) 2690 { 2691 if (Lock()) { 2692 top_view->Invalidate(); 2693 Unlock(); 2694 } 2695 Sync(); 2696 } 2697 2698 2699 void 2700 BWindow::DoUpdate(BView *view, BRect &area) 2701 { 2702 STRACE(("info: BWindow::DoUpdate() BRect(%f,%f,%f,%f) called.\n", 2703 area.left, area.top, area.right, area.bottom)); 2704 2705 // don't draw hidden views or their children 2706 if (view->IsHidden(view)) 2707 return; 2708 2709 view->check_lock(); 2710 2711 if (view->Flags() & B_WILL_DRAW) { 2712 // ToDo: make states robust 2713 view->PushState(); 2714 view->Draw(area); 2715 view->PopState(); 2716 } else { 2717 // The code below is certainly not correct, because 2718 // it redoes what the app_server already did 2719 // Find out what happens on R5 if a view has ViewColor() = 2720 // B_TRANSPARENT_COLOR but not B_WILL_DRAW 2721 /* rgb_color c = aView->HighColor(); 2722 aView->SetHighColor(aView->ViewColor()); 2723 aView->FillRect(aView->Bounds(), B_SOLID_HIGH); 2724 aView->SetHighColor(c);*/ 2725 } 2726 2727 BView *child = view->fFirstChild; 2728 while (child) { 2729 if (area.Intersects(child->Frame())) { 2730 BRect newArea = area & child->Frame(); 2731 child->ConvertFromParent(&newArea); 2732 2733 DoUpdate(child, newArea); 2734 } 2735 child = child->fNextSibling; 2736 } 2737 2738 if (view->Flags() & B_WILL_DRAW) { 2739 view->PushState(); 2740 view->DrawAfterChildren(area); 2741 view->PopState(); 2742 } 2743 } 2744 2745 2746 void 2747 BWindow::SetIsFilePanel(bool yes) 2748 { 2749 // TODO: is this not enough? 2750 fIsFilePanel = yes; 2751 } 2752 2753 2754 bool 2755 BWindow::IsFilePanel() const 2756 { 2757 return fIsFilePanel; 2758 } 2759 2760 2761 //------------------------------------------------------------------------------ 2762 // Virtual reserved Functions 2763 2764 void BWindow::_ReservedWindow1() {} 2765 void BWindow::_ReservedWindow2() {} 2766 void BWindow::_ReservedWindow3() {} 2767 void BWindow::_ReservedWindow4() {} 2768 void BWindow::_ReservedWindow5() {} 2769 void BWindow::_ReservedWindow6() {} 2770 void BWindow::_ReservedWindow7() {} 2771 void BWindow::_ReservedWindow8() {} 2772 2773 void 2774 BWindow::PrintToStream() const 2775 { 2776 printf("BWindow '%s' data:\ 2777 Title = %s\ 2778 Token = %ld\ 2779 InTransaction = %s\ 2780 Active = %s\ 2781 fShowLevel = %d\ 2782 Flags = %lx\ 2783 send_port = %ld\ 2784 receive_port = %ld\ 2785 top_view name = %s\ 2786 focus view name = %s\ 2787 lastMouseMoved = %s\ 2788 fLink = %p\ 2789 KeyMenuBar name = %s\ 2790 DefaultButton = %s\ 2791 # of shortcuts = %ld", 2792 Name(), fTitle, 2793 _get_object_token_(this), 2794 fInTransaction == true ? "yes" : "no", 2795 fActive == true ? "yes" : "no", 2796 fShowLevel, 2797 fFlags, 2798 fLink->SenderPort(), 2799 fLink->ReceiverPort(), 2800 top_view != NULL ? top_view->Name() : "NULL", 2801 fFocus != NULL ? fFocus->Name() : "NULL", 2802 fLastMouseMovedView != NULL ? fLastMouseMovedView->Name() : "NULL", 2803 fLink, 2804 fKeyMenuBar != NULL ? fKeyMenuBar->Name() : "NULL", 2805 fDefaultButton != NULL ? fDefaultButton->Name() : "NULL", 2806 accelList.CountItems()); 2807 /* 2808 for( int32 i=0; i<accelList.CountItems(); i++){ 2809 _BCmdKey *key = (_BCmdKey*)accelList.ItemAt(i); 2810 printf("\tShortCut %ld: char %s\n\t\t message: \n", i, (key->key > 127)?"ASCII":"UNICODE"); 2811 key->message->PrintToStream(); 2812 } 2813 */ 2814 printf("\ 2815 topViewToken = %ld\ 2816 pluseEnabled = %s\ 2817 isFilePanel = %s\ 2818 MaskActivated = %s\ 2819 pulseRate = %lld\ 2820 waitingForMenu = %s\ 2821 minimized = %s\ 2822 Menu semaphore = %ld\ 2823 maxZoomHeight = %f\ 2824 maxZoomWidth = %f\ 2825 minWindHeight = %f\ 2826 minWindWidth = %f\ 2827 maxWindHeight = %f\ 2828 maxWindWidth = %f\ 2829 frame = ( %f, %f, %f, %f )\ 2830 look = %d\ 2831 feel = %d\ 2832 lastViewToken = %ld\ 2833 pulseRUNNER = %s\n", 2834 fTopViewToken, 2835 fPulseEnabled==true?"Yes":"No", 2836 fIsFilePanel==true?"Yes":"No", 2837 fMaskActivated==true?"Yes":"No", 2838 fPulseRate, 2839 fWaitingForMenu==true?"Yes":"No", 2840 fMinimized==true?"Yes":"No", 2841 fMenuSem, 2842 fMaxZoomHeight, 2843 fMaxZoomWidth, 2844 fMinHeight, 2845 fMinWidth, 2846 fMaxHeight, 2847 fMaxWidth, 2848 fFrame.left, fFrame.top, fFrame.right, fFrame.bottom, 2849 (int16)fLook, 2850 (int16)fFeel, 2851 fLastViewToken, 2852 fPulseRunner!=NULL?"In place":"NULL"); 2853 } 2854 2855 /* 2856 TODO list: 2857 2858 *) take care of temporarely events mask!!! 2859 *) what's with this flag B_ASYNCHRONOUS_CONTROLS ? 2860 *) test arguments for SetWindowAligment 2861 *) call hook functions: MenusBeginning, MenusEnded. Add menu activation code. 2862 */ 2863 2864