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