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 gMinimumWindowWidth = 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 gMinimumWindowWidth = std::max(gMinimumWindowWidth, 146 2 * (logoBitmap->Bounds().Width() + 8)); 147 fMinimumTrayWidth = gMinimumWindowWidth - 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(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(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 // add the rep; adds info to list 677 if (AddIcon(data, id, &ref) != B_OK) 678 delete data; 679 680 if (addToSettings) { 681 fAddOnSettings.AddString(kReplicantPathField, path.Path()); 682 _SaveSettings(); 683 } 684 685 return B_OK; 686 } 687 688 689 status_t 690 TReplicantTray::AddItem(int32 id, node_ref nodeRef, BEntry& entry, bool isAddOn) 691 { 692 DeskbarItemInfo* item = new DeskbarItemInfo; 693 if (item == NULL) 694 return B_NO_MEMORY; 695 696 item->id = id; 697 item->isAddOn = isAddOn; 698 699 if (entry.GetRef(&item->entryRef) < B_OK) { 700 item->entryRef.device = -1; 701 item->entryRef.directory = -1; 702 item->entryRef.name = NULL; 703 } 704 item->nodeRef = nodeRef; 705 706 fItemList->AddItem(item); 707 708 if (isAddOn) 709 watch_node(&nodeRef, B_WATCH_NAME | B_WATCH_ATTR, this, Window()); 710 711 return B_OK; 712 } 713 714 715 /** from entry_removed message, when attribute removed 716 * or when a device is unmounted (use removeall, by device) 717 */ 718 719 void 720 TReplicantTray::UnloadAddOn(node_ref* nodeRef, dev_t* device, 721 bool which, bool removeAll) 722 { 723 for (int32 i = fItemList->CountItems() - 1; i >= 0; i--) { 724 DeskbarItemInfo* item = (DeskbarItemInfo*)fItemList->ItemAt(i); 725 if (!item) 726 continue; 727 728 if ((which && nodeRef && item->nodeRef == *nodeRef) 729 || (device && item->nodeRef.device == *device)) { 730 731 if (device && be_roster->IsRunning(&item->entryRef)) 732 continue; 733 734 RemoveIcon(item->id); 735 736 if (!removeAll) 737 break; 738 } 739 } 740 } 741 742 743 void 744 TReplicantTray::RemoveItem(int32 id) 745 { 746 DeskbarItemInfo* item = DeskbarItemFor(id); 747 if (item == NULL) 748 return; 749 750 // attribute was added via Deskbar API (AddItem(entry_ref*, int32*) 751 if (item->isAddOn) { 752 BPath path(&item->entryRef); 753 BString storedPath; 754 for (int32 i = 0; 755 fAddOnSettings.FindString(kReplicantPathField, i, &storedPath) 756 == B_OK; i++) { 757 if (storedPath == path.Path()) { 758 fAddOnSettings.RemoveData(kReplicantPathField, i); 759 break; 760 } 761 } 762 _SaveSettings(); 763 764 BNode node(&item->entryRef); 765 watch_node(&item->nodeRef, B_STOP_WATCHING, this, Window()); 766 } 767 768 fItemList->RemoveItem(item); 769 delete item; 770 } 771 772 773 /** ENTRY_MOVED message, moving only occurs on a device 774 * copying will occur (ENTRY_CREATED) between devices 775 */ 776 777 void 778 TReplicantTray::MoveItem(entry_ref* ref, ino_t toDirectory) 779 { 780 if (!ref) 781 return; 782 783 // scan for a matching entry_ref and update it 784 // 785 // don't need to change node info as it does not change 786 787 for (int32 i = fItemList->CountItems() - 1; i >= 0; i--) { 788 DeskbarItemInfo* item = (DeskbarItemInfo*)fItemList->ItemAt(i); 789 if (!item) 790 continue; 791 792 if (!strcmp(item->entryRef.name, ref->name) 793 && item->entryRef.device == ref->device 794 && item->entryRef.directory == ref->directory) { 795 item->entryRef.directory = toDirectory; 796 break; 797 } 798 } 799 } 800 801 #endif // add-on support 802 803 // external add-on API routines 804 // called using the new BDeskbar class 805 806 // existence of icon/replicant by name or ID 807 // returns opposite 808 // note: name and id are semi-private limiting 809 // the ability of non-host apps to remove 810 // icons without a little bit of work 811 812 /** for a specific id 813 * return the name of the replicant (name of view) 814 */ 815 816 status_t 817 TReplicantTray::ItemInfo(int32 id, const char** name) 818 { 819 if (id < 0) 820 return B_ERROR; 821 822 int32 index, temp; 823 BView* view = ViewAt(&index, &temp, id, false); 824 if (view) { 825 *name = view->Name(); 826 return B_OK; 827 } 828 829 return B_ERROR; 830 } 831 832 833 /** for a specific name 834 * return the id (internal to Deskbar) 835 */ 836 837 status_t 838 TReplicantTray::ItemInfo(const char* name, int32* id) 839 { 840 if (!name || strlen(name) <= 0) 841 return B_ERROR; 842 843 int32 index; 844 BView* view = ViewAt(&index, id, name); 845 if (view) 846 return B_OK; 847 848 return B_ERROR; 849 } 850 851 852 /** at a specific index 853 * return both the name and the id of the replicant 854 */ 855 856 status_t 857 TReplicantTray::ItemInfo(int32 index, const char** name, int32* id) 858 { 859 if (index < 0) 860 return B_ERROR; 861 862 BView* view; 863 fShelf->ReplicantAt(index, &view, (uint32*)id, NULL); 864 if (view) { 865 *name = view->Name(); 866 return B_OK; 867 } 868 869 return B_ERROR; 870 } 871 872 873 /** replicant exists, by id/index */ 874 875 bool 876 TReplicantTray::IconExists(int32 target, bool byIndex) 877 { 878 int32 index, id; 879 BView* view = ViewAt(&index, &id, target, byIndex); 880 881 return view && index >= 0; 882 } 883 884 885 /** replicant exists, by name */ 886 887 bool 888 TReplicantTray::IconExists(const char* name) 889 { 890 if (!name || strlen(name) == 0) 891 return false; 892 893 int32 index, id; 894 BView* view = ViewAt(&index, &id, name); 895 896 return view && index >= 0; 897 } 898 899 900 int32 901 TReplicantTray::IconCount() const 902 { 903 return fShelf->CountReplicants(); 904 } 905 906 907 /*! Message must contain an archivable view for later rehydration. 908 This function takes over ownership of the provided message on success 909 only. 910 Returns the current replicant ID. 911 */ 912 status_t 913 TReplicantTray::AddIcon(BMessage* archive, int32* id, const entry_ref* addOn) 914 { 915 if (archive == NULL || id == NULL) 916 return B_ERROR; 917 918 // find entry_ref 919 920 entry_ref ref; 921 if (addOn) { 922 // Use it if we got it 923 ref = *addOn; 924 } else { 925 const char* signature; 926 927 status_t status = archive->FindString("add_on", &signature); 928 if (status == B_OK) { 929 BRoster roster; 930 status = roster.FindApp(signature, &ref); 931 } 932 if (status < B_OK) 933 return status; 934 } 935 936 BFile file; 937 status_t status = file.SetTo(&ref, B_READ_ONLY); 938 if (status < B_OK) 939 return status; 940 941 node_ref nodeRef; 942 status = file.GetNodeRef(&nodeRef); 943 if (status < B_OK) 944 return status; 945 946 BEntry entry(&ref, true); 947 // TODO: this resolves an eventual link for the item being added - this 948 // is okay for now, but in multi-user environments, one might want to 949 // have links that carry the be:deskbar_item_status attribute 950 status = entry.InitCheck(); 951 if (status != B_OK) 952 return status; 953 954 *id = 999; 955 if (archive->what == B_ARCHIVED_OBJECT) 956 archive->what = 0; 957 958 BRect originalBounds = archive->FindRect("_frame"); 959 // this is a work-around for buggy replicants that change their size in 960 // AttachedToWindow() (such as "SVM") 961 962 // TODO: check for name collisions? 963 status = fShelf->AddReplicant(archive, BPoint(1, 1)); 964 if (status != B_OK) 965 return status; 966 967 int32 count = fShelf->CountReplicants(); 968 BView* view; 969 fShelf->ReplicantAt(count - 1, &view, (uint32*)id, NULL); 970 971 if (originalBounds != view->Bounds()) { 972 // The replicant changed its size when added to the window, so we need 973 // to recompute all over again (it's already done once via 974 // BShelf::AddReplicant() and TReplicantShelf::CanAcceptReplicantView()) 975 RealignReplicants(); 976 } 977 978 float oldWidth = Bounds().Width(); 979 float oldHeight = Bounds().Height(); 980 float width, height; 981 GetPreferredSize(&width, &height); 982 if (oldWidth != width || oldHeight != height) 983 AdjustPlacement(); 984 985 // add the item to the add-on list 986 987 AddItem(*id, nodeRef, entry, addOn != NULL); 988 return B_OK; 989 } 990 991 992 void 993 TReplicantTray::RemoveIcon(int32 target, bool byIndex) 994 { 995 if (target < 0) 996 return; 997 998 int32 index, id; 999 BView* view = ViewAt(&index, &id, target, byIndex); 1000 if (view && index >= 0) { 1001 // remove the reference from the item list & the shelf 1002 RemoveItem(id); 1003 fShelf->DeleteReplicant(index); 1004 1005 // force a placement update, !! need to fix BShelf 1006 RealReplicantAdjustment(index); 1007 } 1008 } 1009 1010 1011 void 1012 TReplicantTray::RemoveIcon(const char* name) 1013 { 1014 if (!name || strlen(name) <= 0) 1015 return; 1016 1017 int32 id, index; 1018 BView* view = ViewAt(&index, &id, name); 1019 if (view && index >= 0) { 1020 // remove the reference from the item list & shelf 1021 RemoveItem(id); 1022 fShelf->DeleteReplicant(index); 1023 1024 // force a placement update, !! need to fix BShelf 1025 RealReplicantAdjustment(index); 1026 } 1027 } 1028 1029 1030 void 1031 TReplicantTray::RealReplicantAdjustment(int32 startIndex) 1032 { 1033 if (startIndex < 0) 1034 return; 1035 1036 if (startIndex == fLastReplicant) 1037 startIndex = 0; 1038 1039 // reset the locations of all replicants after the one deleted 1040 RealignReplicants(startIndex); 1041 1042 float oldWidth = Bounds().Width(); 1043 float oldHeight = Bounds().Height(); 1044 float width, height; 1045 GetPreferredSize(&width, &height); 1046 if (oldWidth != width || oldHeight != height) { 1047 // resize view to accomodate the replicants, redraw as necessary 1048 AdjustPlacement(); 1049 } 1050 } 1051 1052 1053 /** looking for a replicant by id/index 1054 * return the view and index 1055 */ 1056 1057 BView* 1058 TReplicantTray::ViewAt(int32* index, int32* id, int32 target, bool byIndex) 1059 { 1060 *index = -1; 1061 1062 BView* view; 1063 if (byIndex) { 1064 if (fShelf->ReplicantAt(target, &view, (uint32*)id)) { 1065 if (view) { 1066 *index = target; 1067 return view; 1068 } 1069 } 1070 } else { 1071 int32 count = fShelf->CountReplicants() - 1; 1072 int32 localid; 1073 for (int32 repIndex = count ; repIndex >= 0 ; repIndex--) { 1074 fShelf->ReplicantAt(repIndex, &view, (uint32*)&localid); 1075 if (localid == target && view) { 1076 *index = repIndex; 1077 *id = localid; 1078 return view; 1079 } 1080 } 1081 } 1082 return NULL; 1083 } 1084 1085 1086 /** looking for a replicant with a view by name 1087 * return the view, index and the id of the replicant 1088 */ 1089 1090 BView* 1091 TReplicantTray::ViewAt(int32* index, int32* id, const char* name) 1092 { 1093 *index = -1; 1094 *id = -1; 1095 1096 BView* view; 1097 int32 count = fShelf->CountReplicants()-1; 1098 for (int32 repIndex = count ; repIndex >= 0 ; repIndex--) { 1099 fShelf->ReplicantAt(repIndex, &view, (uint32*)id); 1100 if (view && view->Name() && strcmp(name, view->Name()) == 0) { 1101 *index = repIndex; 1102 return view; 1103 } 1104 } 1105 return NULL; 1106 } 1107 1108 1109 /** Shelf will call to determine where and if 1110 * the replicant is to be added 1111 */ 1112 1113 bool 1114 TReplicantTray::AcceptAddon(BRect replicantFrame, BMessage* message) 1115 { 1116 if (!message) 1117 return false; 1118 1119 if (replicantFrame.Height() > kMaxReplicantHeight) 1120 return false; 1121 1122 alignment align = B_ALIGN_LEFT; 1123 if (fAlignmentSupport && message->HasBool("deskbar:dynamic_align")) { 1124 if (!fBarView->Vertical()) 1125 align = B_ALIGN_RIGHT; 1126 else 1127 align = fBarView->Left() ? B_ALIGN_LEFT : B_ALIGN_RIGHT; 1128 } else if (message->HasInt32("deskbar:align")) 1129 message->FindInt32("deskbar:align", (int32*)&align); 1130 1131 if (message->HasInt32("deskbar:private_align")) 1132 message->FindInt32("deskbar:private_align", (int32*)&align); 1133 else 1134 align = B_ALIGN_LEFT; 1135 1136 BPoint loc = LocationForReplicant(fShelf->CountReplicants(), 1137 replicantFrame.Width()); 1138 1139 message->AddPoint("_pjp_loc", loc); 1140 return true; 1141 } 1142 1143 1144 /** based on the previous (index - 1) replicant in the list 1145 * calculate where the left point should be for this 1146 * replicant. replicant will flow to the right on its own 1147 */ 1148 1149 BPoint 1150 TReplicantTray::LocationForReplicant(int32 index, float width) 1151 { 1152 BPoint loc(kIconGap + 1, kGutter + 1); 1153 1154 if (fMultiRowMode) { 1155 // try to find free space in every row 1156 for (int32 row = 0; ; loc.y += kMaxReplicantHeight + kIconGap, row++) { 1157 // determine free space in this row 1158 BRect rect(loc.x, loc.y, loc.x + fMinimumTrayWidth - kIconGap 1159 - 2.0, loc.y + kMaxReplicantHeight); 1160 if (row == 0 && !fTime->IsHidden()) 1161 rect.right -= fTime->Frame().Width() + kIconGap; 1162 1163 for (int32 i = 0; i < index; i++) { 1164 BView* view = NULL; 1165 fShelf->ReplicantAt(i, &view); 1166 if (view == NULL || view->Frame().top != rect.top) 1167 continue; 1168 1169 rect.left = view->Frame().right + kIconGap + 1; 1170 } 1171 1172 if (rect.Width() >= width) { 1173 // the icon fits in this row 1174 loc = rect.LeftTop(); 1175 break; 1176 } 1177 } 1178 } else { 1179 if (index > 0) { 1180 // get the last replicant added for placement reference 1181 BView* view = NULL; 1182 fShelf->ReplicantAt(index - 1, &view); 1183 if (view) { 1184 // push this rep placement past the last one 1185 loc.x = view->Frame().right + kIconGap + 1; 1186 loc.y = view->Frame().top; 1187 } 1188 } 1189 } 1190 1191 if ((loc.y == fRightBottomReplicant.top && loc.x 1192 > fRightBottomReplicant.left) || loc.y > fRightBottomReplicant.top) { 1193 fRightBottomReplicant.Set(loc.x, loc.y, loc.x + width, loc.y 1194 + kMaxReplicantHeight); 1195 fLastReplicant = index; 1196 } 1197 1198 return loc; 1199 } 1200 1201 1202 BRect 1203 TReplicantTray::IconFrame(int32 target, bool byIndex) 1204 { 1205 int32 index, id; 1206 BView* view = ViewAt(&index, &id, target, byIndex); 1207 if (view) 1208 return view->Frame(); 1209 1210 return BRect(0, 0, 0, 0); 1211 } 1212 1213 1214 BRect 1215 TReplicantTray::IconFrame(const char* name) 1216 { 1217 if (!name) 1218 return BRect(0, 0, 0, 0); 1219 1220 int32 id, index; 1221 BView* view = ViewAt(&index, &id, name); 1222 if (view) 1223 return view->Frame(); 1224 1225 return BRect(0, 0, 0, 0); 1226 } 1227 1228 1229 /** Scan from the startIndex and reset the location 1230 * as defined in LocationForReplicant() 1231 */ 1232 1233 void 1234 TReplicantTray::RealignReplicants(int32 startIndex) 1235 { 1236 if (startIndex < 0) 1237 startIndex = 0; 1238 1239 int32 count = fShelf->CountReplicants(); 1240 if (count <= 0) 1241 return; 1242 1243 if (startIndex == 0) 1244 fRightBottomReplicant.Set(0, 0, 0, 0); 1245 1246 BView* view = NULL; 1247 for (int32 i = startIndex ; i < count ; i++) { 1248 fShelf->ReplicantAt(i, &view); 1249 if (view != NULL) { 1250 BPoint loc = LocationForReplicant(i, view->Frame().Width()); 1251 if (view->Frame().LeftTop() != loc) 1252 view->MoveTo(loc); 1253 } 1254 } 1255 } 1256 1257 1258 status_t 1259 TReplicantTray::_SaveSettings() 1260 { 1261 status_t result; 1262 BPath path; 1263 if ((result = GetDeskbarSettingsDirectory(path, true)) == 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 < gMinimumWindowWidth + 10.0f) 1545 ? gMinimumWindowWidth + 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