1 /* 2 Open Tracker License 3 4 Terms and Conditions 5 6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy of 9 this software and associated documentation files (the "Software"), to deal in 10 the Software without restriction, including without limitation the rights to 11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12 of the Software, and to permit persons to whom the Software is furnished to do 13 so, subject to the following conditions: 14 15 The above copyright notice and this permission notice applies to all licensees 16 and shall be included in all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION 23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25 Except as contained in this notice, the name of Be Incorporated shall not be 26 used in advertising or otherwise to promote the sale, use or other dealings in 27 this Software without prior written authorization from Be Incorporated. 28 29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered 30 trademarks of Be Incorporated in the United States and other countries. Other 31 brand product names are registered trademarks or trademarks of their respective 32 holders. 33 All rights reserved. 34 */ 35 36 37 #include "StatusView.h" 38 39 #include <errno.h> 40 #include <stdio.h> 41 #include <string.h> 42 #include <time.h> 43 #include <unistd.h> 44 #include <algorithm> 45 46 #include <fs_index.h> 47 #include <fs_info.h> 48 49 #include <Application.h> 50 #include <Beep.h> 51 #include <Bitmap.h> 52 #include <Catalog.h> 53 #include <ControlLook.h> 54 #include <Debug.h> 55 #include <Directory.h> 56 #include <FindDirectory.h> 57 #include <Locale.h> 58 #include <MenuItem.h> 59 #include <NodeInfo.h> 60 #include <NodeMonitor.h> 61 #include <Path.h> 62 #include <PopUpMenu.h> 63 #include <Roster.h> 64 #include <Screen.h> 65 #include <Volume.h> 66 #include <VolumeRoster.h> 67 #include <Window.h> 68 69 #include "icons.h" 70 71 #include "BarApp.h" 72 #include "DeskbarUtils.h" 73 #include "ResourceSet.h" 74 #include "StatusViewShelf.h" 75 #include "TimeView.h" 76 77 78 using std::max; 79 80 #ifdef DB_ADDONS 81 // Add-on support 82 // 83 // Item - internal item list (node, eref, etc) 84 // Icon - physical replicant handed to the DeskbarClass class 85 // AddOn - attribute based add-on 86 87 const char* const kInstantiateItemCFunctionName = "instantiate_deskbar_item"; 88 const char* const kInstantiateEntryCFunctionName = "instantiate_deskbar_entry"; 89 const char* const kReplicantSettingsFile = "Deskbar_replicants"; 90 const char* const kReplicantPathField = "replicant_path"; 91 92 float sMinimumWindowWidth = kGutter + kMinimumTrayWidth + kDragRegionWidth; 93 94 95 static void 96 DumpItem(DeskbarItemInfo* item) 97 { 98 printf("is addon: %i, id: %" B_PRId32 "\n", item->isAddOn, item->id); 99 printf("entry_ref: %" B_PRIdDEV ", %" B_PRIdINO ", %s\n", 100 item->entryRef.device, item->entryRef.directory, item->entryRef.name); 101 printf("node_ref: %" B_PRIdDEV ", %" B_PRIdINO "\n", item->nodeRef.device, 102 item->nodeRef.node); 103 } 104 105 106 static void 107 DumpList(BList* itemlist) 108 { 109 int32 count = itemlist->CountItems() - 1; 110 if (count < 0) { 111 printf("no items in list\n"); 112 return; 113 } 114 for (int32 i = count; i >= 0; i--) { 115 DeskbarItemInfo* item = (DeskbarItemInfo*)itemlist->ItemAt(i); 116 if (!item) 117 continue; 118 119 DumpItem(item); 120 } 121 } 122 #endif /* DB_ADDONS */ 123 124 125 #undef B_TRANSLATION_CONTEXT 126 #define B_TRANSLATION_CONTEXT "Tray" 127 128 // don't change the name of this view to anything other than "Status"! 129 130 TReplicantTray::TReplicantTray(TBarView* parent, bool vertical) 131 : 132 BView(BRect(0, 0, 1, 1), "Status", B_FOLLOW_LEFT | B_FOLLOW_TOP, 133 B_WILL_DRAW | B_FRAME_EVENTS), 134 fTime(NULL), 135 fBarView(parent), 136 fShelf(new TReplicantShelf(this)), 137 fMultiRowMode(vertical), 138 fMinimumTrayWidth(kMinimumTrayWidth), 139 fAlignmentSupport(false) 140 { 141 // init the minimum window width according to the logo. 142 const BBitmap* logoBitmap = AppResSet()->FindBitmap(B_MESSAGE_TYPE, 143 R_LeafLogoBitmap); 144 if (logoBitmap != NULL) { 145 sMinimumWindowWidth = max_c(sMinimumWindowWidth, 146 2 * (logoBitmap->Bounds().Width() + 8)); 147 fMinimumTrayWidth = sMinimumWindowWidth - kGutter - kDragRegionWidth; 148 } 149 150 // Create the time view 151 fTime = new TTimeView(fMinimumTrayWidth, kMaxReplicantHeight - 1.0); 152 } 153 154 155 TReplicantTray::~TReplicantTray() 156 { 157 delete fShelf; 158 delete fTime; 159 } 160 161 162 void 163 TReplicantTray::AttachedToWindow() 164 { 165 BView::AttachedToWindow(); 166 167 if (be_control_look != NULL) { 168 SetViewColor(Parent()->ViewColor()); 169 } else { 170 SetViewColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), 171 B_DARKEN_1_TINT)); 172 } 173 SetDrawingMode(B_OP_COPY); 174 175 Window()->SetPulseRate(1000000); 176 177 // Set clock settings 178 clock_settings* settings = ((TBarApp*)be_app)->ClockSettings(); 179 fTime->SetShowSeconds(settings->showSeconds); 180 fTime->SetShowDayOfWeek(settings->showDayOfWeek); 181 fTime->SetShowTimeZone(settings->showTimeZone); 182 183 AddChild(fTime); 184 fTime->MoveTo(Bounds().right - fTime->Bounds().Width() - 1, 2); 185 186 #ifdef DB_ADDONS 187 // load addons and rehydrate archives 188 #if !defined(HAIKU_TARGET_PLATFORM_LIBBE_TEST) 189 InitAddOnSupport(); 190 #endif 191 #endif 192 ResizeToPreferred(); 193 } 194 195 196 void 197 TReplicantTray::DetachedFromWindow() 198 { 199 #ifdef DB_ADDONS 200 // clean up add-on support 201 #if !defined(HAIKU_TARGET_PLATFORM_LIBBE_TEST) 202 DeleteAddOnSupport(); 203 #endif 204 #endif 205 BView::DetachedFromWindow(); 206 } 207 208 209 /*! Width is set to a minimum of kMinimumReplicantCount by kMaxReplicantWidth 210 if not in multirowmode and greater than kMinimumReplicantCount 211 the width should be calculated based on the actual replicant widths 212 */ 213 void 214 TReplicantTray::GetPreferredSize(float* preferredWidth, float* preferredHeight) 215 { 216 float width = 0, height = kMinimumTrayHeight; 217 218 if (fMultiRowMode) { 219 if (fShelf->CountReplicants() > 0) 220 height = fRightBottomReplicant.bottom; 221 222 // the height will be uniform for the number of rows necessary to show 223 // all the reps + any gutters necessary for spacing 224 int32 rowCount = (int32)(height / kMaxReplicantHeight); 225 height = kGutter + (rowCount * kMaxReplicantHeight) 226 + ((rowCount - 1) * kIconGap) + kGutter; 227 height = max(kMinimumTrayHeight, height); 228 width = fMinimumTrayWidth; 229 } else { 230 // if last replicant overruns clock then resize to accomodate 231 if (fShelf->CountReplicants() > 0) { 232 if (!fTime->IsHidden() && fTime->Frame().left 233 < fRightBottomReplicant.right + 6) { 234 width = fRightBottomReplicant.right + 6 235 + fTime->Frame().Width(); 236 } else 237 width = fRightBottomReplicant.right + 3; 238 } 239 240 // this view has a fixed minimum width 241 width = max(fMinimumTrayWidth, width); 242 height = kGutter + static_cast<TBarApp*>(be_app)->IconSize() + kGutter; 243 } 244 245 *preferredWidth = width; 246 // add 1 for the border 247 *preferredHeight = height + 1; 248 } 249 250 251 void 252 TReplicantTray::AdjustPlacement() 253 { 254 // called when an add-on has been added or removed 255 // need to resize the parent of this accordingly 256 257 BRect bounds = Bounds(); 258 float width, height; 259 GetPreferredSize(&width, &height); 260 261 if (width == bounds.Width() && height == bounds.Height()) { 262 // no need to change anything 263 return; 264 } 265 266 Parent()->ResizeToPreferred(); 267 fBarView->UpdatePlacement(); 268 Parent()->Invalidate(); 269 Invalidate(); 270 } 271 272 273 void 274 TReplicantTray::MessageReceived(BMessage* message) 275 { 276 switch (message->what) { 277 case B_LOCALE_CHANGED: 278 { 279 if (fTime == NULL) 280 return; 281 282 fTime->Update(); 283 284 // time string reformat -> realign 285 RealignReplicants(); 286 AdjustPlacement(); 287 break; 288 } 289 290 case kShowHideTime: 291 // from context menu in clock and in this view 292 ShowHideTime(); 293 break; 294 295 case kShowSeconds: 296 if (fTime == NULL) 297 return; 298 299 fTime->SetShowSeconds(!fTime->ShowSeconds()); 300 301 // time string reformat -> realign 302 RealignReplicants(); 303 AdjustPlacement(); 304 break; 305 306 case kShowDayOfWeek: 307 if (fTime == NULL) 308 return; 309 310 fTime->SetShowDayOfWeek(!fTime->ShowDayOfWeek()); 311 312 // time string reformat -> realign 313 RealignReplicants(); 314 AdjustPlacement(); 315 break; 316 317 case kShowTimeZone: 318 if (fTime == NULL) 319 return; 320 321 fTime->SetShowTimeZone(!fTime->ShowTimeZone()); 322 323 // time string reformat -> realign 324 RealignReplicants(); 325 AdjustPlacement(); 326 break; 327 328 case kGetClockSettings: 329 { 330 if (fTime == NULL) 331 return; 332 333 bool showClock = !fTime->IsHidden(); 334 bool showSeconds = fTime->ShowSeconds(); 335 bool showDayOfWeek = fTime->ShowDayOfWeek(); 336 bool showTimeZone = fTime->ShowTimeZone(); 337 338 BMessage* reply = new BMessage(kGetClockSettings); 339 reply->AddBool("showClock", showClock); 340 reply->AddBool("showSeconds", showSeconds); 341 reply->AddBool("showDayOfWeek", showDayOfWeek); 342 reply->AddBool("showTimeZone", showTimeZone); 343 message->SendReply(reply); 344 break; 345 } 346 347 #ifdef DB_ADDONS 348 case B_NODE_MONITOR: 349 HandleEntryUpdate(message); 350 break; 351 #endif 352 353 default: 354 BView::MessageReceived(message); 355 break; 356 } 357 } 358 359 360 void 361 TReplicantTray::MouseDown(BPoint where) 362 { 363 #ifdef DB_ADDONS 364 if (modifiers() & B_CONTROL_KEY) 365 DumpList(fItemList); 366 #endif 367 368 uint32 buttons; 369 370 Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons); 371 if (buttons == B_SECONDARY_MOUSE_BUTTON) { 372 ShowReplicantMenu(where); 373 } else { 374 BPoint save = where; 375 bigtime_t doubleClickSpeed; 376 bigtime_t start = system_time(); 377 uint32 buttons; 378 379 get_click_speed(&doubleClickSpeed); 380 381 do { 382 if (fabs(where.x - save.x) > 4 || fabs(where.y - save.y) > 4) 383 // user moved out of bounds of click area 384 break; 385 386 if ((system_time() - start) > (2 * doubleClickSpeed)) { 387 ShowReplicantMenu(where); 388 break; 389 } 390 391 snooze(50000); 392 GetMouse(&where, &buttons); 393 } while (buttons); 394 } 395 BView::MouseDown(where); 396 } 397 398 399 void 400 TReplicantTray::ShowReplicantMenu(BPoint point) 401 { 402 BPopUpMenu* menu = new BPopUpMenu("", false, false); 403 menu->SetFont(be_plain_font); 404 405 // If clock is visible show the extended menu, otherwise show "Show clock" 406 407 if (!fTime->IsHidden()) 408 fTime->ShowTimeOptions(ConvertToScreen(point)); 409 else { 410 BMenuItem* item = new BMenuItem(B_TRANSLATE("Show clock"), 411 new BMessage(kShowHideTime)); 412 menu->AddItem(item); 413 menu->SetTargetForItems(this); 414 BPoint where = ConvertToScreen(point); 415 menu->Go(where, true, true, BRect(where - BPoint(4, 4), 416 where + BPoint(4, 4)), true); 417 } 418 } 419 420 421 void 422 TReplicantTray::SetMultiRow(bool state) 423 { 424 fMultiRowMode = state; 425 } 426 427 428 void 429 TReplicantTray::ShowHideTime() 430 { 431 if (fTime == NULL) 432 return; 433 434 if (fTime->IsHidden()) 435 fTime->Show(); 436 else 437 fTime->Hide(); 438 439 RealignReplicants(); 440 AdjustPlacement(); 441 442 // message Time preferences to update it's show time setting 443 BMessenger messenger("application/x-vnd.Haiku-Time"); 444 BMessage* message = new BMessage(kShowHideTime); 445 message->AddBool("showClock", !fTime->IsHidden()); 446 messenger.SendMessage(message); 447 } 448 449 450 #ifdef DB_ADDONS 451 452 453 void 454 TReplicantTray::InitAddOnSupport() 455 { 456 // list to maintain refs to each rep added/deleted 457 fItemList = new BList(); 458 BPath path; 459 460 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path, true) == B_OK) { 461 path.Append(kReplicantSettingsFile); 462 463 BFile file(path.Path(), B_READ_ONLY); 464 if (file.InitCheck() == B_OK) { 465 status_t result; 466 BEntry entry; 467 int32 id; 468 BString path; 469 if (fAddOnSettings.Unflatten(&file) == B_OK) { 470 for (int32 i = 0; fAddOnSettings.FindString(kReplicantPathField, 471 i, &path) == B_OK; i++) { 472 if (entry.SetTo(path.String()) == B_OK && entry.Exists()) { 473 result = LoadAddOn(&entry, &id, false); 474 } else 475 result = B_ENTRY_NOT_FOUND; 476 477 if (result != B_OK) { 478 fAddOnSettings.RemoveData(kReplicantPathField, i); 479 --i; 480 } 481 } 482 } 483 } 484 } 485 } 486 487 488 void 489 TReplicantTray::DeleteAddOnSupport() 490 { 491 _SaveSettings(); 492 493 for (int32 i = fItemList->CountItems(); i-- > 0 ;) { 494 DeskbarItemInfo* item = (DeskbarItemInfo*)fItemList->RemoveItem(i); 495 if (item) { 496 if (item->isAddOn) 497 watch_node(&(item->nodeRef), B_STOP_WATCHING, this, Window()); 498 499 delete item; 500 } 501 } 502 delete fItemList; 503 504 // stop the volume mount/unmount watch 505 stop_watching(this, Window()); 506 } 507 508 509 DeskbarItemInfo* 510 TReplicantTray::DeskbarItemFor(node_ref& nodeRef) 511 { 512 for (int32 i = fItemList->CountItems(); i-- > 0 ;) { 513 DeskbarItemInfo* item = (DeskbarItemInfo*)fItemList->ItemAt(i); 514 if (item == NULL) 515 continue; 516 517 if (item->nodeRef == nodeRef) 518 return item; 519 } 520 521 return NULL; 522 } 523 524 525 DeskbarItemInfo* 526 TReplicantTray::DeskbarItemFor(int32 id) 527 { 528 for (int32 i = fItemList->CountItems(); i-- > 0 ;) { 529 DeskbarItemInfo* item = (DeskbarItemInfo*)fItemList->ItemAt(i); 530 if (item == NULL) 531 continue; 532 533 if (item->id == id) 534 return item; 535 } 536 537 return NULL; 538 } 539 540 541 bool 542 TReplicantTray::NodeExists(node_ref& nodeRef) 543 { 544 return DeskbarItemFor(nodeRef) != NULL; 545 } 546 547 548 /*! This handles B_NODE_MONITOR & B_QUERY_UPDATE messages received 549 for the registered add-ons. 550 */ 551 void 552 TReplicantTray::HandleEntryUpdate(BMessage* message) 553 { 554 int32 opcode; 555 if (message->FindInt32("opcode", &opcode) != B_OK) 556 return; 557 558 BPath path; 559 switch (opcode) { 560 case B_ENTRY_MOVED: 561 { 562 entry_ref ref; 563 ino_t todirectory; 564 ino_t node; 565 const char* name; 566 if (message->FindString("name", &name) == B_OK 567 && message->FindInt64("from directory", &(ref.directory)) 568 == B_OK 569 && message->FindInt64("to directory", &todirectory) == B_OK 570 && message->FindInt32("device", &(ref.device)) == B_OK 571 && message->FindInt64("node", &node) == B_OK ) { 572 573 if (!name) 574 break; 575 576 ref.set_name(name); 577 // change the directory reference to 578 // the new directory 579 MoveItem(&ref, todirectory); 580 } 581 break; 582 } 583 584 case B_ENTRY_REMOVED: 585 { 586 // entry was rm'd from the device 587 node_ref nodeRef; 588 if (message->FindInt32("device", &(nodeRef.device)) == B_OK 589 && message->FindInt64("node", &(nodeRef.node)) == B_OK) { 590 DeskbarItemInfo* item = DeskbarItemFor(nodeRef); 591 if (item == NULL) 592 break; 593 594 // If there is a team running where the add-on comes from, 595 // we don't want to remove the icon yet. 596 if (be_roster->IsRunning(&item->entryRef)) 597 break; 598 599 UnloadAddOn(&nodeRef, NULL, true, false); 600 } 601 break; 602 } 603 } 604 } 605 606 607 /*! The add-ons must support the exported C function API 608 if they do, they will be loaded and added to deskbar 609 primary function is the Instantiate function 610 */ 611 status_t 612 TReplicantTray::LoadAddOn(BEntry* entry, int32* id, bool addToSettings) 613 { 614 if (!entry) 615 return B_ERROR; 616 617 node_ref nodeRef; 618 entry->GetNodeRef(&nodeRef); 619 // no duplicates 620 if (NodeExists(nodeRef)) 621 return B_ERROR; 622 623 BNode node(entry); 624 BPath path; 625 status_t status = entry->GetPath(&path); 626 if (status < B_OK) 627 return status; 628 629 // load the add-on 630 image_id image = load_add_on(path.Path()); 631 if (image < B_OK) 632 return image; 633 634 // get the view loading function symbol 635 // we first look for a symbol that takes an image_id 636 // and entry_ref pointer, if not found, go with normal 637 // instantiate function 638 BView* (*entryFunction)(image_id, const entry_ref*); 639 BView* (*itemFunction)(void); 640 BView* view = NULL; 641 642 entry_ref ref; 643 entry->GetRef(&ref); 644 645 if (get_image_symbol(image, kInstantiateEntryCFunctionName, 646 B_SYMBOL_TYPE_TEXT, (void**)&entryFunction) >= B_OK) { 647 view = (*entryFunction)(image, &ref); 648 } else if (get_image_symbol(image, kInstantiateItemCFunctionName, 649 B_SYMBOL_TYPE_TEXT, (void**)&itemFunction) >= B_OK) { 650 view = (*itemFunction)(); 651 } else { 652 unload_add_on(image); 653 return B_ERROR; 654 } 655 656 if (view == NULL || IconExists(view->Name())) { 657 delete view; 658 unload_add_on(image); 659 return B_ERROR; 660 } 661 662 BMessage* data = new BMessage; 663 view->Archive(data); 664 delete view; 665 666 AddIcon(data, id, &ref); 667 // add the rep; adds info to list 668 669 if (addToSettings) { 670 fAddOnSettings.AddString(kReplicantPathField, path.Path()); 671 _SaveSettings(); 672 } 673 674 return B_OK; 675 } 676 677 678 status_t 679 TReplicantTray::AddItem(int32 id, node_ref nodeRef, BEntry& entry, bool isAddOn) 680 { 681 DeskbarItemInfo* item = new DeskbarItemInfo; 682 if (item == NULL) 683 return B_NO_MEMORY; 684 685 item->id = id; 686 item->isAddOn = isAddOn; 687 688 if (entry.GetRef(&item->entryRef) < B_OK) { 689 item->entryRef.device = -1; 690 item->entryRef.directory = -1; 691 item->entryRef.name = NULL; 692 } 693 item->nodeRef = nodeRef; 694 695 fItemList->AddItem(item); 696 697 if (isAddOn) 698 watch_node(&nodeRef, B_WATCH_NAME | B_WATCH_ATTR, this, Window()); 699 700 return B_OK; 701 } 702 703 704 /** from entry_removed message, when attribute removed 705 * or when a device is unmounted (use removeall, by device) 706 */ 707 708 void 709 TReplicantTray::UnloadAddOn(node_ref* nodeRef, dev_t* device, 710 bool which, bool removeAll) 711 { 712 for (int32 i = fItemList->CountItems(); i-- > 0 ;) { 713 DeskbarItemInfo* item = (DeskbarItemInfo*)fItemList->ItemAt(i); 714 if (!item) 715 continue; 716 717 if ((which && nodeRef && item->nodeRef == *nodeRef) 718 || (device && item->nodeRef.device == *device)) { 719 720 if (device && be_roster->IsRunning(&item->entryRef)) 721 continue; 722 723 RemoveIcon(item->id); 724 725 if (!removeAll) 726 break; 727 } 728 } 729 } 730 731 732 void 733 TReplicantTray::RemoveItem(int32 id) 734 { 735 DeskbarItemInfo* item = DeskbarItemFor(id); 736 if (item == NULL) 737 return; 738 739 // attribute was added via Deskbar API (AddItem(entry_ref*, int32*) 740 if (item->isAddOn) { 741 BPath path(&item->entryRef); 742 BString storedPath; 743 for (int32 i = 0; 744 fAddOnSettings.FindString(kReplicantPathField, i, &storedPath) 745 == B_OK; i++) { 746 if (storedPath == path.Path()) { 747 fAddOnSettings.RemoveData(kReplicantPathField, i); 748 break; 749 } 750 } 751 _SaveSettings(); 752 753 BNode node(&item->entryRef); 754 watch_node(&item->nodeRef, B_STOP_WATCHING, this, Window()); 755 } 756 757 fItemList->RemoveItem(item); 758 delete item; 759 } 760 761 762 /** ENTRY_MOVED message, moving only occurs on a device 763 * copying will occur (ENTRY_CREATED) between devices 764 */ 765 766 void 767 TReplicantTray::MoveItem(entry_ref* ref, ino_t toDirectory) 768 { 769 if (!ref) 770 return; 771 772 // scan for a matching entry_ref and update it 773 // 774 // don't need to change node info as it does not change 775 776 for (int32 i = fItemList->CountItems(); i-- > 0 ;) { 777 DeskbarItemInfo* item = (DeskbarItemInfo*)fItemList->ItemAt(i); 778 if (!item) 779 continue; 780 781 if (!strcmp(item->entryRef.name, ref->name) 782 && item->entryRef.device == ref->device 783 && item->entryRef.directory == ref->directory) { 784 item->entryRef.directory = toDirectory; 785 break; 786 } 787 } 788 } 789 790 #endif // add-on support 791 792 // external add-on API routines 793 // called using the new BDeskbar class 794 795 // existence of icon/replicant by name or ID 796 // returns opposite 797 // note: name and id are semi-private limiting 798 // the ability of non-host apps to remove 799 // icons without a little bit of work 800 801 /** for a specific id 802 * return the name of the replicant (name of view) 803 */ 804 805 status_t 806 TReplicantTray::ItemInfo(int32 id, const char** name) 807 { 808 if (id < 0) 809 return B_ERROR; 810 811 int32 index, temp; 812 BView* view = ViewAt(&index, &temp, id, false); 813 if (view) { 814 *name = view->Name(); 815 return B_OK; 816 } 817 818 return B_ERROR; 819 } 820 821 822 /** for a specific name 823 * return the id (internal to Deskbar) 824 */ 825 826 status_t 827 TReplicantTray::ItemInfo(const char* name, int32* id) 828 { 829 if (!name || strlen(name) <= 0) 830 return B_ERROR; 831 832 int32 index; 833 BView* view = ViewAt(&index, id, name); 834 if (view) 835 return B_OK; 836 837 return B_ERROR; 838 } 839 840 841 /** at a specific index 842 * return both the name and the id of the replicant 843 */ 844 845 status_t 846 TReplicantTray::ItemInfo(int32 index, const char** name, int32* id) 847 { 848 if (index < 0) 849 return B_ERROR; 850 851 BView* view; 852 fShelf->ReplicantAt(index, &view, (uint32*)id, NULL); 853 if (view) { 854 *name = view->Name(); 855 return B_OK; 856 } 857 858 return B_ERROR; 859 } 860 861 862 /** replicant exists, by id/index */ 863 864 bool 865 TReplicantTray::IconExists(int32 target, bool byIndex) 866 { 867 int32 index, id; 868 BView* view = ViewAt(&index, &id, target, byIndex); 869 870 return view && index >= 0; 871 } 872 873 874 /** replicant exists, by name */ 875 876 bool 877 TReplicantTray::IconExists(const char* name) 878 { 879 if (!name || strlen(name) == 0) 880 return false; 881 882 int32 index, id; 883 BView* view = ViewAt(&index, &id, name); 884 885 return view && index >= 0; 886 } 887 888 889 int32 890 TReplicantTray::IconCount() const 891 { 892 return fShelf->CountReplicants(); 893 } 894 895 896 /*! Message must contain an archivable view for later rehydration. 897 This function takes over ownership of the provided message on success 898 only. 899 Returns the current replicant ID. 900 */ 901 status_t 902 TReplicantTray::AddIcon(BMessage* archive, int32* id, const entry_ref* addOn) 903 { 904 if (archive == NULL || id == NULL) 905 return B_ERROR; 906 907 // find entry_ref 908 909 entry_ref ref; 910 if (addOn) { 911 // Use it if we got it 912 ref = *addOn; 913 } else { 914 const char* signature; 915 916 status_t status = archive->FindString("add_on", &signature); 917 if (status == B_OK) { 918 BRoster roster; 919 status = roster.FindApp(signature, &ref); 920 } 921 if (status < B_OK) 922 return status; 923 } 924 925 BFile file; 926 status_t status = file.SetTo(&ref, B_READ_ONLY); 927 if (status < B_OK) 928 return status; 929 930 node_ref nodeRef; 931 status = file.GetNodeRef(&nodeRef); 932 if (status < B_OK) 933 return status; 934 935 BEntry entry(&ref, true); 936 // TODO: this resolves an eventual link for the item being added - this 937 // is okay for now, but in multi-user environments, one might want to 938 // have links that carry the be:deskbar_item_status attribute 939 status = entry.InitCheck(); 940 if (status != B_OK) 941 return status; 942 943 *id = 999; 944 if (archive->what == B_ARCHIVED_OBJECT) 945 archive->what = 0; 946 947 BRect originalBounds = archive->FindRect("_frame"); 948 // this is a work-around for buggy replicants that change their size in 949 // AttachedToWindow() (such as "SVM") 950 951 // TODO: check for name collisions? 952 status = fShelf->AddReplicant(archive, BPoint(1, 1)); 953 if (status != B_OK) 954 return status; 955 956 int32 count = fShelf->CountReplicants(); 957 BView* view; 958 fShelf->ReplicantAt(count - 1, &view, (uint32*)id, NULL); 959 960 if (originalBounds != view->Bounds()) { 961 // The replicant changed its size when added to the window, so we need 962 // to recompute all over again (it's already done once via 963 // BShelf::AddReplicant() and TReplicantShelf::CanAcceptReplicantView()) 964 RealignReplicants(); 965 } 966 967 float oldWidth = Bounds().Width(); 968 float oldHeight = Bounds().Height(); 969 float width, height; 970 GetPreferredSize(&width, &height); 971 if (oldWidth != width || oldHeight != height) 972 AdjustPlacement(); 973 974 // add the item to the add-on list 975 976 AddItem(*id, nodeRef, entry, addOn != NULL); 977 return B_OK; 978 } 979 980 981 void 982 TReplicantTray::RemoveIcon(int32 target, bool byIndex) 983 { 984 if (target < 0) 985 return; 986 987 int32 index, id; 988 BView* view = ViewAt(&index, &id, target, byIndex); 989 if (view && index >= 0) { 990 // remove the reference from the item list & the shelf 991 RemoveItem(id); 992 fShelf->DeleteReplicant(index); 993 994 // force a placement update, !! need to fix BShelf 995 RealReplicantAdjustment(index); 996 } 997 } 998 999 1000 void 1001 TReplicantTray::RemoveIcon(const char* name) 1002 { 1003 if (!name || strlen(name) <= 0) 1004 return; 1005 1006 int32 id, index; 1007 BView* view = ViewAt(&index, &id, name); 1008 if (view && index >= 0) { 1009 // remove the reference from the item list & shelf 1010 RemoveItem(id); 1011 fShelf->DeleteReplicant(index); 1012 1013 // force a placement update, !! need to fix BShelf 1014 RealReplicantAdjustment(index); 1015 } 1016 } 1017 1018 1019 void 1020 TReplicantTray::RealReplicantAdjustment(int32 startIndex) 1021 { 1022 if (startIndex < 0) 1023 return; 1024 1025 if (startIndex == fLastReplicant) 1026 startIndex = 0; 1027 1028 // reset the locations of all replicants after the one deleted 1029 RealignReplicants(startIndex); 1030 1031 float oldWidth = Bounds().Width(); 1032 float oldHeight = Bounds().Height(); 1033 float width, height; 1034 GetPreferredSize(&width, &height); 1035 if (oldWidth != width || oldHeight != height) { 1036 // resize view to accomodate the replicants, redraw as necessary 1037 AdjustPlacement(); 1038 } 1039 } 1040 1041 1042 /** looking for a replicant by id/index 1043 * return the view and index 1044 */ 1045 1046 BView* 1047 TReplicantTray::ViewAt(int32* index, int32* id, int32 target, bool byIndex) 1048 { 1049 *index = -1; 1050 1051 BView* view; 1052 if (byIndex) { 1053 if (fShelf->ReplicantAt(target, &view, (uint32*)id)) { 1054 if (view) { 1055 *index = target; 1056 return view; 1057 } 1058 } 1059 } else { 1060 int32 count = fShelf->CountReplicants() - 1; 1061 int32 localid; 1062 for (int32 repIndex = count ; repIndex >= 0 ; repIndex--) { 1063 fShelf->ReplicantAt(repIndex, &view, (uint32*)&localid); 1064 if (localid == target && view) { 1065 *index = repIndex; 1066 *id = localid; 1067 return view; 1068 } 1069 } 1070 } 1071 return NULL; 1072 } 1073 1074 1075 /** looking for a replicant with a view by name 1076 * return the view, index and the id of the replicant 1077 */ 1078 1079 BView* 1080 TReplicantTray::ViewAt(int32* index, int32* id, const char* name) 1081 { 1082 *index = -1; 1083 *id = -1; 1084 1085 BView* view; 1086 int32 count = fShelf->CountReplicants()-1; 1087 for (int32 repIndex = count ; repIndex >= 0 ; repIndex--) { 1088 fShelf->ReplicantAt(repIndex, &view, (uint32*)id); 1089 if (view && view->Name() && strcmp(name, view->Name()) == 0) { 1090 *index = repIndex; 1091 return view; 1092 } 1093 } 1094 return NULL; 1095 } 1096 1097 1098 /** Shelf will call to determine where and if 1099 * the replicant is to be added 1100 */ 1101 1102 bool 1103 TReplicantTray::AcceptAddon(BRect replicantFrame, BMessage* message) 1104 { 1105 if (!message) 1106 return false; 1107 1108 if (replicantFrame.Height() > kMaxReplicantHeight) 1109 return false; 1110 1111 alignment align = B_ALIGN_LEFT; 1112 if (fAlignmentSupport && message->HasBool("deskbar:dynamic_align")) { 1113 if (!fBarView->Vertical()) 1114 align = B_ALIGN_RIGHT; 1115 else 1116 align = fBarView->Left() ? B_ALIGN_LEFT : B_ALIGN_RIGHT; 1117 } else if (message->HasInt32("deskbar:align")) 1118 message->FindInt32("deskbar:align", (int32*)&align); 1119 1120 if (message->HasInt32("deskbar:private_align")) 1121 message->FindInt32("deskbar:private_align", (int32*)&align); 1122 else 1123 align = B_ALIGN_LEFT; 1124 1125 BPoint loc = LocationForReplicant(fShelf->CountReplicants(), 1126 replicantFrame.Width()); 1127 1128 message->AddPoint("_pjp_loc", loc); 1129 return true; 1130 } 1131 1132 1133 /** based on the previous (index - 1) replicant in the list 1134 * calculate where the left point should be for this 1135 * replicant. replicant will flow to the right on its own 1136 */ 1137 1138 BPoint 1139 TReplicantTray::LocationForReplicant(int32 index, float width) 1140 { 1141 BPoint loc(kIconGap + 1, kGutter + 1); 1142 1143 if (fMultiRowMode) { 1144 // try to find free space in every row 1145 for (int32 row = 0; ; loc.y += kMaxReplicantHeight + kIconGap, row++) { 1146 // determine free space in this row 1147 BRect rect(loc.x, loc.y, loc.x + fMinimumTrayWidth - kIconGap 1148 - 2.0, loc.y + kMaxReplicantHeight); 1149 if (row == 0 && !fTime->IsHidden()) 1150 rect.right -= fTime->Frame().Width() + kIconGap; 1151 1152 for (int32 i = 0; i < index; i++) { 1153 BView* view = NULL; 1154 fShelf->ReplicantAt(i, &view); 1155 if (view == NULL || view->Frame().top != rect.top) 1156 continue; 1157 1158 rect.left = view->Frame().right + kIconGap + 1; 1159 } 1160 1161 if (rect.Width() >= width) { 1162 // the icon fits in this row 1163 loc = rect.LeftTop(); 1164 break; 1165 } 1166 } 1167 } else { 1168 if (index > 0) { 1169 // get the last replicant added for placement reference 1170 BView* view = NULL; 1171 fShelf->ReplicantAt(index - 1, &view); 1172 if (view) { 1173 // push this rep placement past the last one 1174 loc.x = view->Frame().right + kIconGap + 1; 1175 loc.y = view->Frame().top; 1176 } 1177 } 1178 } 1179 1180 if ((loc.y == fRightBottomReplicant.top && loc.x 1181 > fRightBottomReplicant.left) || loc.y > fRightBottomReplicant.top) { 1182 fRightBottomReplicant.Set(loc.x, loc.y, loc.x + width, loc.y 1183 + kMaxReplicantHeight); 1184 fLastReplicant = index; 1185 } 1186 1187 return loc; 1188 } 1189 1190 1191 BRect 1192 TReplicantTray::IconFrame(int32 target, bool byIndex) 1193 { 1194 int32 index, id; 1195 BView* view = ViewAt(&index, &id, target, byIndex); 1196 if (view) 1197 return view->Frame(); 1198 1199 return BRect(0, 0, 0, 0); 1200 } 1201 1202 1203 BRect 1204 TReplicantTray::IconFrame(const char* name) 1205 { 1206 if (!name) 1207 return BRect(0, 0, 0, 0); 1208 1209 int32 id, index; 1210 BView* view = ViewAt(&index, &id, name); 1211 if (view) 1212 return view->Frame(); 1213 1214 return BRect(0, 0, 0, 0); 1215 } 1216 1217 1218 /** Scan from the startIndex and reset the location 1219 * as defined in LocationForReplicant() 1220 */ 1221 1222 void 1223 TReplicantTray::RealignReplicants(int32 startIndex) 1224 { 1225 if (startIndex < 0) 1226 startIndex = 0; 1227 1228 int32 count = fShelf->CountReplicants(); 1229 if (count <= 0) 1230 return; 1231 1232 if (startIndex == 0) 1233 fRightBottomReplicant.Set(0, 0, 0, 0); 1234 1235 BView* view = NULL; 1236 for (int32 i = startIndex ; i < count ; i++) { 1237 fShelf->ReplicantAt(i, &view); 1238 if (view != NULL) { 1239 BPoint loc = LocationForReplicant(i, view->Frame().Width()); 1240 if (view->Frame().LeftTop() != loc) 1241 view->MoveTo(loc); 1242 } 1243 } 1244 } 1245 1246 1247 status_t 1248 TReplicantTray::_SaveSettings() 1249 { 1250 status_t result; 1251 BPath path; 1252 if ((result = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true)) 1253 == B_OK) { 1254 path.Append(kReplicantSettingsFile); 1255 1256 BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); 1257 if ((result = file.InitCheck()) == B_OK) 1258 result = fAddOnSettings.Flatten(&file); 1259 } 1260 1261 return result; 1262 } 1263 1264 1265 void 1266 TReplicantTray::SaveTimeSettings() 1267 { 1268 if (fTime == NULL) 1269 return; 1270 1271 clock_settings* settings = ((TBarApp*)be_app)->ClockSettings(); 1272 settings->showSeconds = fTime->ShowSeconds(); 1273 settings->showDayOfWeek = fTime->ShowDayOfWeek(); 1274 settings->showTimeZone = fTime->ShowTimeZone(); 1275 } 1276 1277 1278 // #pragma mark - 1279 1280 1281 /*! Draggable region that is asynchronous so that dragging does not block 1282 other activities. 1283 */ 1284 TDragRegion::TDragRegion(TBarView* parent, BView* child) 1285 : 1286 BControl(BRect(0, 0, 0, 0), "", "", NULL, B_FOLLOW_NONE, 1287 B_WILL_DRAW | B_FRAME_EVENTS), 1288 fBarView(parent), 1289 fChild(child), 1290 fDragLocation(kAutoPlaceDragRegion) 1291 { 1292 } 1293 1294 1295 void 1296 TDragRegion::AttachedToWindow() 1297 { 1298 BView::AttachedToWindow(); 1299 if (be_control_look != NULL) 1300 SetViewColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), 1.1)); 1301 else 1302 SetViewColor(ui_color(B_MENU_BACKGROUND_COLOR)); 1303 ResizeToPreferred(); 1304 } 1305 1306 1307 void 1308 TDragRegion::GetPreferredSize(float* width, float* height) 1309 { 1310 fChild->ResizeToPreferred(); 1311 *width = fChild->Bounds().Width(); 1312 *height = fChild->Bounds().Height(); 1313 1314 if (fDragLocation != kNoDragRegion) 1315 *width += 7; 1316 else 1317 *width += 6; 1318 1319 *height += 3; 1320 } 1321 1322 1323 void 1324 TDragRegion::FrameMoved(BPoint) 1325 { 1326 if (fBarView->Left() && fBarView->Vertical() 1327 && fDragLocation != kNoDragRegion) 1328 fChild->MoveTo(5, 2); 1329 else 1330 fChild->MoveTo(2, 2); 1331 } 1332 1333 1334 void 1335 TDragRegion::Draw(BRect) 1336 { 1337 rgb_color menuColor = ViewColor(); 1338 rgb_color hilite = tint_color(menuColor, B_DARKEN_1_TINT); 1339 rgb_color ldark = tint_color(menuColor, 1.02); 1340 rgb_color dark = tint_color(menuColor, B_DARKEN_2_TINT); 1341 rgb_color vvdark = tint_color(menuColor, B_DARKEN_4_TINT); 1342 rgb_color light = tint_color(menuColor, B_LIGHTEN_2_TINT); 1343 1344 BRect frame(Bounds()); 1345 BeginLineArray(4); 1346 1347 if (be_control_look != NULL) { 1348 if (fBarView->Vertical()) { 1349 AddLine(frame.LeftTop(), frame.RightTop(), dark); 1350 AddLine(BPoint(frame.left, frame.top + 1), 1351 BPoint(frame.right, frame.top + 1), ldark); 1352 AddLine(frame.LeftBottom(), frame.RightBottom(), hilite); 1353 } else if (fBarView->AcrossTop() || fBarView->AcrossBottom()) { 1354 AddLine(frame.LeftTop(), 1355 BPoint(frame.left, frame.bottom), dark); 1356 AddLine(BPoint(frame.left + 1, frame.top + 1), 1357 BPoint(frame.right - 1, frame.top + 1), light); 1358 AddLine(BPoint(frame.right, frame.top + 2), 1359 BPoint(frame.right, frame.bottom), hilite); 1360 AddLine(BPoint(frame.left + 1, frame.bottom), 1361 BPoint(frame.right - 1, frame.bottom), hilite); 1362 } 1363 } else { 1364 if (fBarView->Vertical()) { 1365 AddLine(frame.LeftTop(), frame.RightTop(), light); 1366 AddLine(frame.LeftTop(), frame.LeftBottom(), light); 1367 AddLine(frame.RightBottom(), frame.RightTop(), hilite); 1368 } else if (fBarView->AcrossTop()) { 1369 AddLine(BPoint(frame.left, frame.top + 1), 1370 BPoint(frame.right - 1, frame.top + 1), light); 1371 AddLine(frame.RightTop(), frame.RightBottom(), vvdark); 1372 AddLine(BPoint(frame.right - 1, frame.top + 2), 1373 BPoint(frame.right - 1, frame.bottom - 1), hilite); 1374 AddLine(frame.LeftBottom(), 1375 BPoint(frame.right - 1, frame.bottom), hilite); 1376 } else if (fBarView->AcrossBottom()) { 1377 AddLine(BPoint(frame.left, frame.top + 1), 1378 BPoint(frame.right - 1, frame.top + 1), light); 1379 AddLine(frame.LeftBottom(), frame.RightBottom(), hilite); 1380 AddLine(frame.RightTop(), frame.RightBottom(), vvdark); 1381 AddLine(BPoint(frame.right - 1, frame.top + 1), 1382 BPoint(frame.right - 1, frame.bottom - 1), hilite); 1383 } 1384 } 1385 1386 EndLineArray(); 1387 1388 if (fDragLocation != kDontDrawDragRegion || fDragLocation != kNoDragRegion) 1389 DrawDragRegion(); 1390 } 1391 1392 1393 void 1394 TDragRegion::DrawDragRegion() 1395 { 1396 BRect dragRegion(DragRegion()); 1397 1398 rgb_color menuColor = ViewColor(); 1399 rgb_color menuHilite = menuColor; 1400 if (IsTracking()) { 1401 // Draw drag region highlighted if tracking mouse 1402 menuHilite = tint_color(menuColor, B_HIGHLIGHT_BACKGROUND_TINT); 1403 SetHighColor(menuHilite); 1404 FillRect(dragRegion); 1405 } 1406 rgb_color vdark = tint_color(menuHilite, B_DARKEN_3_TINT); 1407 rgb_color light = tint_color(menuHilite, B_LIGHTEN_2_TINT); 1408 1409 BeginLineArray(dragRegion.IntegerHeight()); 1410 BPoint pt; 1411 pt.x = floorf((dragRegion.left + dragRegion.right) / 2 + 0.5) - 1; 1412 pt.y = dragRegion.top + 2; 1413 1414 while (pt.y + 1 <= dragRegion.bottom) { 1415 AddLine(pt, pt, vdark); 1416 AddLine(pt + BPoint(1, 1), pt + BPoint(1, 1), light); 1417 1418 pt.y += 3; 1419 } 1420 EndLineArray(); 1421 } 1422 1423 1424 BRect 1425 TDragRegion::DragRegion() const 1426 { 1427 float kTopBottomInset = 2; 1428 float kLeftRightInset = 1; 1429 float kDragWidth = 3; 1430 if (be_control_look != NULL) { 1431 kTopBottomInset = 1; 1432 kLeftRightInset = 0; 1433 kDragWidth = 4; 1434 } 1435 1436 BRect dragRegion(Bounds()); 1437 dragRegion.top += kTopBottomInset; 1438 dragRegion.bottom -= kTopBottomInset; 1439 1440 bool placeOnLeft = false; 1441 if (fDragLocation == kAutoPlaceDragRegion) { 1442 if (fBarView->Vertical() && fBarView->Left()) 1443 placeOnLeft = true; 1444 else 1445 placeOnLeft = false; 1446 } else if (fDragLocation == kDragRegionLeft) 1447 placeOnLeft = true; 1448 else if (fDragLocation == kDragRegionRight) 1449 placeOnLeft = false; 1450 1451 if (placeOnLeft) { 1452 dragRegion.left += kLeftRightInset; 1453 dragRegion.right = dragRegion.left + kDragWidth; 1454 } else { 1455 dragRegion.right -= kLeftRightInset; 1456 dragRegion.left = dragRegion.right - kDragWidth; 1457 } 1458 1459 return dragRegion; 1460 } 1461 1462 1463 void 1464 TDragRegion::MouseDown(BPoint thePoint) 1465 { 1466 uint32 buttons; 1467 BPoint where; 1468 BRect dragRegion(DragRegion()); 1469 1470 dragRegion.InsetBy(-2.0f, -2.0f); 1471 // DragRegion() is designed for drawing, not clicking 1472 1473 if (!dragRegion.Contains(thePoint)) 1474 return; 1475 1476 while (true) { 1477 GetMouse(&where, &buttons); 1478 if (!buttons) 1479 break; 1480 1481 if ((Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) != 0) { 1482 fPreviousPosition = thePoint; 1483 SetTracking(true); 1484 SetMouseEventMask(B_POINTER_EVENTS, 1485 B_NO_POINTER_HISTORY | B_LOCK_WINDOW_FOCUS); 1486 Invalidate(DragRegion()); 1487 break; 1488 } 1489 1490 snooze(25000); 1491 } 1492 } 1493 1494 1495 void 1496 TDragRegion::MouseUp(BPoint pt) 1497 { 1498 if (IsTracking()) { 1499 SetTracking(false); 1500 Invalidate(DragRegion()); 1501 } else 1502 BControl::MouseUp(pt); 1503 } 1504 1505 1506 bool 1507 TDragRegion::SwitchModeForRect(BPoint mouse, BRect rect, 1508 bool newVertical, bool newLeft, bool newTop, int32 newState) 1509 { 1510 if (!rect.Contains(mouse)) { 1511 // not our rect 1512 return false; 1513 } 1514 1515 if (newVertical == fBarView->Vertical() && newLeft == fBarView->Left() 1516 && newTop == fBarView->Top() && newState == fBarView->State()) { 1517 // already in the correct mode 1518 return true; 1519 } 1520 1521 fBarView->ChangeState(newState, newVertical, newLeft, newTop, true); 1522 return true; 1523 } 1524 1525 1526 void 1527 TDragRegion::MouseMoved(BPoint where, uint32 code, const BMessage* message) 1528 { 1529 if (IsTracking()) { 1530 BScreen screen; 1531 BRect frame = screen.Frame(); 1532 1533 float hDivider = frame.Width() / 6; 1534 hDivider = (hDivider < sMinimumWindowWidth + 10.0f) 1535 ? sMinimumWindowWidth + 10.0f : hDivider; 1536 float miniDivider = frame.top + kMiniHeight + 10.0f; 1537 float vDivider = frame.Height() / 2; 1538 #ifdef FULL_MODE 1539 float thirdScreen = frame.Height() / 3; 1540 #endif 1541 BRect topLeft(frame.left, frame.top, frame.left + hDivider, 1542 miniDivider); 1543 BRect topMiddle(frame.left + hDivider, frame.top, frame.right 1544 - hDivider, vDivider); 1545 BRect topRight(frame.right - hDivider, frame.top, frame.right, 1546 miniDivider); 1547 1548 #ifdef FULL_MODE 1549 vDivider = miniDivider + thirdScreen; 1550 #endif 1551 BRect middleLeft(frame.left, miniDivider, frame.left + hDivider, 1552 vDivider); 1553 BRect middleRight(frame.right - hDivider, miniDivider, frame.right, 1554 vDivider); 1555 1556 #ifdef FULL_MODE 1557 BRect leftSide(frame.left, vDivider, frame.left + hDivider, 1558 frame.bottom - thirdScreen); 1559 BRect rightSide(frame.right - hDivider, vDivider, frame.right, 1560 frame.bottom - thirdScreen); 1561 1562 vDivider = frame.bottom - thirdScreen; 1563 #endif 1564 BRect bottomLeft(frame.left, vDivider, frame.left + hDivider, 1565 frame.bottom); 1566 BRect bottomMiddle(frame.left + hDivider, vDivider, frame.right 1567 - hDivider, frame.bottom); 1568 BRect bottomRight(frame.right - hDivider, vDivider, frame.right, 1569 frame.bottom); 1570 1571 if (where != fPreviousPosition) { 1572 fPreviousPosition = where; 1573 ConvertToScreen(&where); 1574 1575 // use short circuit evaluation for convenience 1576 if (SwitchModeForRect(where, topLeft, true, true, true, kMiniState) 1577 || SwitchModeForRect(where, topMiddle, false, true, true, 1578 kExpandoState) 1579 || SwitchModeForRect(where, topRight, true, false, true, 1580 kMiniState) 1581 || SwitchModeForRect(where, middleLeft, true, true, true, 1582 kExpandoState) 1583 || SwitchModeForRect(where, middleRight, true, false, true, 1584 kExpandoState) 1585 1586 #ifdef FULL_MODE 1587 || SwitchModeForRect(where, leftSide, true, true, true, 1588 kFullState) 1589 || SwitchModeForRect(where, rightSide, true, false, true, 1590 kFullState) 1591 #endif 1592 || SwitchModeForRect(where, bottomLeft, true, true, false, 1593 kMiniState) 1594 || SwitchModeForRect(where, bottomMiddle, false, true, false, 1595 kExpandoState) 1596 || SwitchModeForRect(where, bottomRight, true, false, false, 1597 kMiniState)) 1598 ; 1599 } 1600 } else 1601 BControl::MouseMoved(where, code, message); 1602 } 1603 1604 1605 int32 1606 TDragRegion::DragRegionLocation() const 1607 { 1608 return fDragLocation; 1609 } 1610 1611 1612 void 1613 TDragRegion::SetDragRegionLocation(int32 location) 1614 { 1615 if (location == fDragLocation) 1616 return; 1617 1618 fDragLocation = location; 1619 Invalidate(); 1620 } 1621