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