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