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 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 (find_directory(B_USER_SETTINGS_DIRECTORY, &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 = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true)) 1263 == B_OK) { 1264 path.Append(kReplicantSettingsFile); 1265 1266 BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); 1267 if ((result = file.InitCheck()) == B_OK) 1268 result = fAddOnSettings.Flatten(&file); 1269 } 1270 1271 return result; 1272 } 1273 1274 1275 void 1276 TReplicantTray::SaveTimeSettings() 1277 { 1278 if (fTime == NULL) 1279 return; 1280 1281 clock_settings* settings = ((TBarApp*)be_app)->ClockSettings(); 1282 settings->showSeconds = fTime->ShowSeconds(); 1283 settings->showDayOfWeek = fTime->ShowDayOfWeek(); 1284 settings->showTimeZone = fTime->ShowTimeZone(); 1285 } 1286 1287 1288 // #pragma mark - 1289 1290 1291 /*! Draggable region that is asynchronous so that dragging does not block 1292 other activities. 1293 */ 1294 TDragRegion::TDragRegion(TBarView* parent, BView* child) 1295 : 1296 BControl(BRect(0, 0, 0, 0), "", "", NULL, B_FOLLOW_NONE, 1297 B_WILL_DRAW | B_FRAME_EVENTS), 1298 fBarView(parent), 1299 fChild(child), 1300 fDragLocation(kAutoPlaceDragRegion) 1301 { 1302 } 1303 1304 1305 void 1306 TDragRegion::AttachedToWindow() 1307 { 1308 BView::AttachedToWindow(); 1309 if (be_control_look != NULL) 1310 SetViewColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), 1.1)); 1311 else 1312 SetViewColor(ui_color(B_MENU_BACKGROUND_COLOR)); 1313 ResizeToPreferred(); 1314 } 1315 1316 1317 void 1318 TDragRegion::GetPreferredSize(float* width, float* height) 1319 { 1320 fChild->ResizeToPreferred(); 1321 *width = fChild->Bounds().Width(); 1322 *height = fChild->Bounds().Height(); 1323 1324 if (fDragLocation != kNoDragRegion) 1325 *width += 7; 1326 else 1327 *width += 6; 1328 1329 *height += 3; 1330 } 1331 1332 1333 void 1334 TDragRegion::FrameMoved(BPoint) 1335 { 1336 if (fBarView->Left() && fBarView->Vertical() 1337 && fDragLocation != kNoDragRegion) 1338 fChild->MoveTo(5, 2); 1339 else 1340 fChild->MoveTo(2, 2); 1341 } 1342 1343 1344 void 1345 TDragRegion::Draw(BRect) 1346 { 1347 rgb_color menuColor = ViewColor(); 1348 rgb_color hilite = tint_color(menuColor, B_DARKEN_1_TINT); 1349 rgb_color ldark = tint_color(menuColor, 1.02); 1350 rgb_color dark = tint_color(menuColor, B_DARKEN_2_TINT); 1351 rgb_color vvdark = tint_color(menuColor, B_DARKEN_4_TINT); 1352 rgb_color light = tint_color(menuColor, B_LIGHTEN_2_TINT); 1353 1354 BRect frame(Bounds()); 1355 BeginLineArray(4); 1356 1357 if (be_control_look != NULL) { 1358 if (fBarView->Vertical()) { 1359 AddLine(frame.LeftTop(), frame.RightTop(), dark); 1360 AddLine(BPoint(frame.left, frame.top + 1), 1361 BPoint(frame.right, frame.top + 1), ldark); 1362 AddLine(frame.LeftBottom(), frame.RightBottom(), hilite); 1363 } else if (fBarView->AcrossTop() || fBarView->AcrossBottom()) { 1364 AddLine(frame.LeftTop(), 1365 BPoint(frame.left, frame.bottom), dark); 1366 AddLine(BPoint(frame.left + 1, frame.top + 1), 1367 BPoint(frame.right - 1, frame.top + 1), light); 1368 AddLine(BPoint(frame.right, frame.top + 2), 1369 BPoint(frame.right, frame.bottom), hilite); 1370 AddLine(BPoint(frame.left + 1, frame.bottom), 1371 BPoint(frame.right - 1, frame.bottom), hilite); 1372 } 1373 } else { 1374 if (fBarView->Vertical()) { 1375 AddLine(frame.LeftTop(), frame.RightTop(), light); 1376 AddLine(frame.LeftTop(), frame.LeftBottom(), light); 1377 AddLine(frame.RightBottom(), frame.RightTop(), hilite); 1378 } else if (fBarView->AcrossTop()) { 1379 AddLine(BPoint(frame.left, frame.top + 1), 1380 BPoint(frame.right - 1, frame.top + 1), light); 1381 AddLine(frame.RightTop(), frame.RightBottom(), vvdark); 1382 AddLine(BPoint(frame.right - 1, frame.top + 2), 1383 BPoint(frame.right - 1, frame.bottom - 1), hilite); 1384 AddLine(frame.LeftBottom(), 1385 BPoint(frame.right - 1, frame.bottom), hilite); 1386 } else if (fBarView->AcrossBottom()) { 1387 AddLine(BPoint(frame.left, frame.top + 1), 1388 BPoint(frame.right - 1, frame.top + 1), light); 1389 AddLine(frame.LeftBottom(), frame.RightBottom(), hilite); 1390 AddLine(frame.RightTop(), frame.RightBottom(), vvdark); 1391 AddLine(BPoint(frame.right - 1, frame.top + 1), 1392 BPoint(frame.right - 1, frame.bottom - 1), hilite); 1393 } 1394 } 1395 1396 EndLineArray(); 1397 1398 if (fDragLocation != kDontDrawDragRegion || fDragLocation != kNoDragRegion) 1399 DrawDragRegion(); 1400 } 1401 1402 1403 void 1404 TDragRegion::DrawDragRegion() 1405 { 1406 BRect dragRegion(DragRegion()); 1407 1408 rgb_color menuColor = ViewColor(); 1409 rgb_color menuHilite = menuColor; 1410 if (IsTracking()) { 1411 // Draw drag region highlighted if tracking mouse 1412 menuHilite = tint_color(menuColor, B_HIGHLIGHT_BACKGROUND_TINT); 1413 SetHighColor(menuHilite); 1414 FillRect(dragRegion); 1415 } 1416 rgb_color vdark = tint_color(menuHilite, B_DARKEN_3_TINT); 1417 rgb_color light = tint_color(menuHilite, B_LIGHTEN_2_TINT); 1418 1419 BeginLineArray(dragRegion.IntegerHeight()); 1420 BPoint pt; 1421 pt.x = floorf((dragRegion.left + dragRegion.right) / 2 + 0.5) - 1; 1422 pt.y = dragRegion.top + 2; 1423 1424 while (pt.y + 1 <= dragRegion.bottom) { 1425 AddLine(pt, pt, vdark); 1426 AddLine(pt + BPoint(1, 1), pt + BPoint(1, 1), light); 1427 1428 pt.y += 3; 1429 } 1430 EndLineArray(); 1431 } 1432 1433 1434 BRect 1435 TDragRegion::DragRegion() const 1436 { 1437 float kTopBottomInset = 2; 1438 float kLeftRightInset = 1; 1439 float kDragWidth = 3; 1440 if (be_control_look != NULL) { 1441 kTopBottomInset = 1; 1442 kLeftRightInset = 0; 1443 kDragWidth = 4; 1444 } 1445 1446 BRect dragRegion(Bounds()); 1447 dragRegion.top += kTopBottomInset; 1448 dragRegion.bottom -= kTopBottomInset; 1449 1450 bool placeOnLeft = false; 1451 if (fDragLocation == kAutoPlaceDragRegion) { 1452 if (fBarView->Vertical() && fBarView->Left()) 1453 placeOnLeft = true; 1454 else 1455 placeOnLeft = false; 1456 } else if (fDragLocation == kDragRegionLeft) 1457 placeOnLeft = true; 1458 else if (fDragLocation == kDragRegionRight) 1459 placeOnLeft = false; 1460 1461 if (placeOnLeft) { 1462 dragRegion.left += kLeftRightInset; 1463 dragRegion.right = dragRegion.left + kDragWidth; 1464 } else { 1465 dragRegion.right -= kLeftRightInset; 1466 dragRegion.left = dragRegion.right - kDragWidth; 1467 } 1468 1469 return dragRegion; 1470 } 1471 1472 1473 void 1474 TDragRegion::MouseDown(BPoint thePoint) 1475 { 1476 uint32 buttons; 1477 BPoint where; 1478 BRect dragRegion(DragRegion()); 1479 1480 dragRegion.InsetBy(-2.0f, -2.0f); 1481 // DragRegion() is designed for drawing, not clicking 1482 1483 if (!dragRegion.Contains(thePoint)) 1484 return; 1485 1486 while (true) { 1487 GetMouse(&where, &buttons); 1488 if (!buttons) 1489 break; 1490 1491 if ((Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) != 0) { 1492 fPreviousPosition = thePoint; 1493 SetTracking(true); 1494 SetMouseEventMask(B_POINTER_EVENTS, 1495 B_NO_POINTER_HISTORY | B_LOCK_WINDOW_FOCUS); 1496 Invalidate(DragRegion()); 1497 break; 1498 } 1499 1500 snooze(25000); 1501 } 1502 } 1503 1504 1505 void 1506 TDragRegion::MouseUp(BPoint pt) 1507 { 1508 if (IsTracking()) { 1509 SetTracking(false); 1510 Invalidate(DragRegion()); 1511 } else 1512 BControl::MouseUp(pt); 1513 } 1514 1515 1516 bool 1517 TDragRegion::SwitchModeForRect(BPoint mouse, BRect rect, 1518 bool newVertical, bool newLeft, bool newTop, int32 newState) 1519 { 1520 if (!rect.Contains(mouse)) { 1521 // not our rect 1522 return false; 1523 } 1524 1525 if (newVertical == fBarView->Vertical() && newLeft == fBarView->Left() 1526 && newTop == fBarView->Top() && newState == fBarView->State()) { 1527 // already in the correct mode 1528 return true; 1529 } 1530 1531 fBarView->ChangeState(newState, newVertical, newLeft, newTop, true); 1532 return true; 1533 } 1534 1535 1536 void 1537 TDragRegion::MouseMoved(BPoint where, uint32 code, const BMessage* message) 1538 { 1539 if (IsTracking()) { 1540 BScreen screen; 1541 BRect frame = screen.Frame(); 1542 1543 float hDivider = frame.Width() / 6; 1544 hDivider = (hDivider < sMinimumWindowWidth + 10.0f) 1545 ? sMinimumWindowWidth + 10.0f : hDivider; 1546 float miniDivider = frame.top + kMiniHeight + 10.0f; 1547 float vDivider = frame.Height() / 2; 1548 #ifdef FULL_MODE 1549 float thirdScreen = frame.Height() / 3; 1550 #endif 1551 BRect topLeft(frame.left, frame.top, frame.left + hDivider, 1552 miniDivider); 1553 BRect topMiddle(frame.left + hDivider, frame.top, frame.right 1554 - hDivider, vDivider); 1555 BRect topRight(frame.right - hDivider, frame.top, frame.right, 1556 miniDivider); 1557 1558 #ifdef FULL_MODE 1559 vDivider = miniDivider + thirdScreen; 1560 #endif 1561 BRect middleLeft(frame.left, miniDivider, frame.left + hDivider, 1562 vDivider); 1563 BRect middleRight(frame.right - hDivider, miniDivider, frame.right, 1564 vDivider); 1565 1566 #ifdef FULL_MODE 1567 BRect leftSide(frame.left, vDivider, frame.left + hDivider, 1568 frame.bottom - thirdScreen); 1569 BRect rightSide(frame.right - hDivider, vDivider, frame.right, 1570 frame.bottom - thirdScreen); 1571 1572 vDivider = frame.bottom - thirdScreen; 1573 #endif 1574 BRect bottomLeft(frame.left, vDivider, frame.left + hDivider, 1575 frame.bottom); 1576 BRect bottomMiddle(frame.left + hDivider, vDivider, frame.right 1577 - hDivider, frame.bottom); 1578 BRect bottomRight(frame.right - hDivider, vDivider, frame.right, 1579 frame.bottom); 1580 1581 if (where != fPreviousPosition) { 1582 fPreviousPosition = where; 1583 ConvertToScreen(&where); 1584 1585 // use short circuit evaluation for convenience 1586 if (SwitchModeForRect(where, topLeft, true, true, true, kMiniState) 1587 || SwitchModeForRect(where, topMiddle, false, true, true, 1588 kExpandoState) 1589 || SwitchModeForRect(where, topRight, true, false, true, 1590 kMiniState) 1591 || SwitchModeForRect(where, middleLeft, true, true, true, 1592 kExpandoState) 1593 || SwitchModeForRect(where, middleRight, true, false, true, 1594 kExpandoState) 1595 1596 #ifdef FULL_MODE 1597 || SwitchModeForRect(where, leftSide, true, true, true, 1598 kFullState) 1599 || SwitchModeForRect(where, rightSide, true, false, true, 1600 kFullState) 1601 #endif 1602 || SwitchModeForRect(where, bottomLeft, true, true, false, 1603 kMiniState) 1604 || SwitchModeForRect(where, bottomMiddle, false, true, false, 1605 kExpandoState) 1606 || SwitchModeForRect(where, bottomRight, true, false, false, 1607 kMiniState)) 1608 ; 1609 } 1610 } else 1611 BControl::MouseMoved(where, code, message); 1612 } 1613 1614 1615 int32 1616 TDragRegion::DragRegionLocation() const 1617 { 1618 return fDragLocation; 1619 } 1620 1621 1622 void 1623 TDragRegion::SetDragRegionLocation(int32 location) 1624 { 1625 if (location == fDragLocation) 1626 return; 1627 1628 fDragLocation = location; 1629 Invalidate(); 1630 } 1631