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