1 /* 2 * Copyright 2010-2014 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * John Scipione, jscipione@gmail.com 7 * Clemens Zeidler, haiku@clemens-zeidler.de 8 */ 9 10 11 #include "SATGroup.h" 12 13 #include <vector> 14 15 #include <Debug.h> 16 #include <Message.h> 17 18 #include "Desktop.h" 19 20 #include "SATWindow.h" 21 #include "StackAndTile.h" 22 #include "Window.h" 23 24 25 using namespace std; 26 using namespace LinearProgramming; 27 28 29 const float kExtentPenalty = 1; 30 const float kHighPenalty = 100; 31 const float kInequalityPenalty = 10000; 32 33 34 WindowArea::WindowArea(Crossing* leftTop, Crossing* rightTop, 35 Crossing* leftBottom, Crossing* rightBottom) 36 : 37 fGroup(NULL), 38 39 fLeftTopCrossing(leftTop), 40 fRightTopCrossing(rightTop), 41 fLeftBottomCrossing(leftBottom), 42 fRightBottomCrossing(rightBottom), 43 44 fMinWidthConstraint(NULL), 45 fMinHeightConstraint(NULL), 46 fMaxWidthConstraint(NULL), 47 fMaxHeightConstraint(NULL), 48 fWidthConstraint(NULL), 49 fHeightConstraint(NULL) 50 { 51 } 52 53 54 WindowArea::~WindowArea() 55 { 56 if (fGroup) 57 fGroup->WindowAreaRemoved(this); 58 59 _CleanupCorners(); 60 fGroup->fWindowAreaList.RemoveItem(this); 61 62 _UninitConstraints(); 63 } 64 65 66 bool 67 WindowArea::Init(SATGroup* group) 68 { 69 _UninitConstraints(); 70 71 if (group == NULL || group->fWindowAreaList.AddItem(this) == false) 72 return false; 73 74 fGroup = group; 75 76 LinearSpec* linearSpec = fGroup->GetLinearSpec(); 77 78 fMinWidthConstraint = linearSpec->AddConstraint(1.0, RightVar(), -1.0, 79 LeftVar(), kGE, 0); 80 fMinHeightConstraint = linearSpec->AddConstraint(1.0, BottomVar(), -1.0, 81 TopVar(), kGE, 0); 82 83 fMaxWidthConstraint = linearSpec->AddConstraint(1.0, RightVar(), -1.0, 84 LeftVar(), kLE, 0, kInequalityPenalty, kInequalityPenalty); 85 fMaxHeightConstraint = linearSpec->AddConstraint(1.0, BottomVar(), -1.0, 86 TopVar(), kLE, 0, kInequalityPenalty, kInequalityPenalty); 87 88 // Width and height have soft constraints 89 fWidthConstraint = linearSpec->AddConstraint(1.0, RightVar(), -1.0, 90 LeftVar(), kEQ, 0, kExtentPenalty, 91 kExtentPenalty); 92 fHeightConstraint = linearSpec->AddConstraint(-1.0, TopVar(), 1.0, 93 BottomVar(), kEQ, 0, kExtentPenalty, 94 kExtentPenalty); 95 96 if (!fMinWidthConstraint || !fMinHeightConstraint || !fWidthConstraint 97 || !fHeightConstraint || !fMaxWidthConstraint 98 || !fMaxHeightConstraint) 99 return false; 100 101 return true; 102 } 103 104 105 void 106 WindowArea::DoGroupLayout() 107 { 108 SATWindow* parentWindow = fWindowLayerOrder.ItemAt(0); 109 if (parentWindow == NULL) 110 return; 111 112 BRect frame = parentWindow->CompleteWindowFrame(); 113 // Make it also work for solver which don't support negative variables 114 frame.OffsetBy(kMakePositiveOffset, kMakePositiveOffset); 115 116 // adjust window size soft constraints 117 fWidthConstraint->SetRightSide(frame.Width()); 118 fHeightConstraint->SetRightSide(frame.Height()); 119 120 LinearSpec* linearSpec = fGroup->GetLinearSpec(); 121 Constraint* leftConstraint = linearSpec->AddConstraint(1.0, LeftVar(), 122 kEQ, frame.left); 123 Constraint* topConstraint = linearSpec->AddConstraint(1.0, TopVar(), kEQ, 124 frame.top); 125 126 // give soft constraints a high penalty 127 fWidthConstraint->SetPenaltyNeg(kHighPenalty); 128 fWidthConstraint->SetPenaltyPos(kHighPenalty); 129 fHeightConstraint->SetPenaltyNeg(kHighPenalty); 130 fHeightConstraint->SetPenaltyPos(kHighPenalty); 131 132 // After we set the new parameter solve and apply the new layout. 133 ResultType result; 134 for (int32 tries = 0; tries < 15; tries++) { 135 result = fGroup->GetLinearSpec()->Solve(); 136 if (result == kInfeasible) { 137 debug_printf("can't solve constraints!\n"); 138 break; 139 } 140 if (result == kOptimal) { 141 const WindowAreaList& areas = fGroup->GetAreaList(); 142 for (int32 i = 0; i < areas.CountItems(); i++) { 143 WindowArea* area = areas.ItemAt(i); 144 area->_MoveToSAT(parentWindow); 145 } 146 break; 147 } 148 } 149 150 // set penalties back to normal 151 fWidthConstraint->SetPenaltyNeg(kExtentPenalty); 152 fWidthConstraint->SetPenaltyPos(kExtentPenalty); 153 fHeightConstraint->SetPenaltyNeg(kExtentPenalty); 154 fHeightConstraint->SetPenaltyPos(kExtentPenalty); 155 156 linearSpec->RemoveConstraint(leftConstraint); 157 linearSpec->RemoveConstraint(topConstraint); 158 } 159 160 161 void 162 WindowArea::UpdateSizeLimits() 163 { 164 _UpdateConstraintValues(); 165 } 166 167 168 void 169 WindowArea::UpdateSizeConstaints(const BRect& frame) 170 { 171 // adjust window size soft constraints 172 fWidthConstraint->SetRightSide(frame.Width()); 173 fHeightConstraint->SetRightSide(frame.Height()); 174 } 175 176 177 bool 178 WindowArea::MoveWindowToPosition(SATWindow* window, int32 index) 179 { 180 int32 oldIndex = fWindowList.IndexOf(window); 181 ASSERT(oldIndex != index); 182 return fWindowList.MoveItem(oldIndex, index); 183 } 184 185 186 SATWindow* 187 WindowArea::TopWindow() 188 { 189 return fWindowLayerOrder.ItemAt(fWindowLayerOrder.CountItems() - 1); 190 } 191 192 193 void 194 WindowArea::_UpdateConstraintValues() 195 { 196 SATWindow* topWindow = TopWindow(); 197 if (topWindow == NULL) 198 return; 199 200 int32 minWidth, maxWidth; 201 int32 minHeight, maxHeight; 202 SATWindow* window = fWindowList.ItemAt(0); 203 window->GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight); 204 for (int32 i = 1; i < fWindowList.CountItems(); i++) { 205 window = fWindowList.ItemAt(i); 206 // size limit constraints 207 int32 minW, maxW; 208 int32 minH, maxH; 209 window->GetSizeLimits(&minW, &maxW, &minH, &maxH); 210 if (minWidth < minW) 211 minWidth = minW; 212 if (minHeight < minH) 213 minHeight = minH; 214 if (maxWidth < maxW) 215 maxWidth = maxW; 216 if (maxHeight < maxH) 217 maxHeight = maxH; 218 } 219 // the current solver don't like big values 220 const int32 kMaxSolverValue = 5000; 221 if (minWidth > kMaxSolverValue) 222 minWidth = kMaxSolverValue; 223 if (minHeight > kMaxSolverValue) 224 minHeight = kMaxSolverValue; 225 if (maxWidth > kMaxSolverValue) 226 maxWidth = kMaxSolverValue; 227 if (maxHeight > kMaxSolverValue) 228 maxHeight = kMaxSolverValue; 229 230 topWindow->AddDecorator(&minWidth, &maxWidth, &minHeight, &maxHeight); 231 fMinWidthConstraint->SetRightSide(minWidth); 232 fMinHeightConstraint->SetRightSide(minHeight); 233 234 fMaxWidthConstraint->SetRightSide(maxWidth); 235 fMaxHeightConstraint->SetRightSide(maxHeight); 236 237 BRect frame = topWindow->CompleteWindowFrame(); 238 fWidthConstraint->SetRightSide(frame.Width()); 239 fHeightConstraint->SetRightSide(frame.Height()); 240 } 241 242 243 bool 244 WindowArea::_AddWindow(SATWindow* window, SATWindow* after) 245 { 246 if (after) { 247 int32 indexAfter = fWindowList.IndexOf(after); 248 if (!fWindowList.AddItem(window, indexAfter + 1)) 249 return false; 250 } else if (fWindowList.AddItem(window) == false) 251 return false; 252 253 AcquireReference(); 254 255 if (fWindowList.CountItems() <= 1) 256 _InitCorners(); 257 258 fWindowLayerOrder.AddItem(window); 259 260 _UpdateConstraintValues(); 261 return true; 262 } 263 264 265 bool 266 WindowArea::_RemoveWindow(SATWindow* window) 267 { 268 if (!fWindowList.RemoveItem(window)) 269 return false; 270 271 fWindowLayerOrder.RemoveItem(window); 272 _UpdateConstraintValues(); 273 274 window->RemovedFromArea(this); 275 ReleaseReference(); 276 return true; 277 } 278 279 280 Tab* 281 WindowArea::LeftTab() 282 { 283 return fLeftTopCrossing->VerticalTab(); 284 } 285 286 287 Tab* 288 WindowArea::RightTab() 289 { 290 return fRightBottomCrossing->VerticalTab(); 291 } 292 293 294 Tab* 295 WindowArea::TopTab() 296 { 297 return fLeftTopCrossing->HorizontalTab(); 298 } 299 300 301 Tab* 302 WindowArea::BottomTab() 303 { 304 return fRightBottomCrossing->HorizontalTab(); 305 } 306 307 308 BRect 309 WindowArea::Frame() 310 { 311 return BRect(fLeftTopCrossing->VerticalTab()->Position(), 312 fLeftTopCrossing->HorizontalTab()->Position(), 313 fRightBottomCrossing->VerticalTab()->Position(), 314 fRightBottomCrossing->HorizontalTab()->Position()); 315 } 316 317 318 bool 319 WindowArea::PropagateToGroup(SATGroup* group) 320 { 321 BReference<Crossing> newLeftTop = _CrossingByPosition(fLeftTopCrossing, 322 group); 323 BReference<Crossing> newRightTop = _CrossingByPosition(fRightTopCrossing, 324 group); 325 BReference<Crossing> newLeftBottom = _CrossingByPosition( 326 fLeftBottomCrossing, group); 327 BReference<Crossing> newRightBottom = _CrossingByPosition( 328 fRightBottomCrossing, group); 329 330 if (!newLeftTop || !newRightTop || !newLeftBottom || !newRightBottom) 331 return false; 332 333 // hold a ref to the crossings till we cleaned up everything 334 BReference<Crossing> oldLeftTop = fLeftTopCrossing; 335 BReference<Crossing> oldRightTop = fRightTopCrossing; 336 BReference<Crossing> oldLeftBottom = fLeftBottomCrossing; 337 BReference<Crossing> oldRightBottom = fRightBottomCrossing; 338 339 fLeftTopCrossing = newLeftTop; 340 fRightTopCrossing = newRightTop; 341 fLeftBottomCrossing = newLeftBottom; 342 fRightBottomCrossing = newRightBottom; 343 344 _InitCorners(); 345 346 BReference<SATGroup> oldGroup = fGroup; 347 // manage constraints 348 if (Init(group) == false) 349 return false; 350 351 oldGroup->fWindowAreaList.RemoveItem(this); 352 for (int32 i = 0; i < fWindowList.CountItems(); i++) { 353 SATWindow* window = fWindowList.ItemAt(i); 354 if (oldGroup->fSATWindowList.RemoveItem(window) == false) 355 return false; 356 if (group->fSATWindowList.AddItem(window) == false) { 357 _UninitConstraints(); 358 return false; 359 } 360 } 361 362 _UpdateConstraintValues(); 363 364 return true; 365 } 366 367 368 bool 369 WindowArea::MoveToTopLayer(SATWindow* window) 370 { 371 if (!fWindowLayerOrder.RemoveItem(window)) 372 return false; 373 return fWindowLayerOrder.AddItem(window); 374 } 375 376 377 void 378 WindowArea::_UninitConstraints() 379 { 380 if (fGroup != NULL) { 381 LinearSpec* linearSpec = fGroup->GetLinearSpec(); 382 383 if (linearSpec != NULL) { 384 linearSpec->RemoveConstraint(fMinWidthConstraint, true); 385 linearSpec->RemoveConstraint(fMinHeightConstraint, true); 386 linearSpec->RemoveConstraint(fMaxWidthConstraint, true); 387 linearSpec->RemoveConstraint(fMaxHeightConstraint, true); 388 linearSpec->RemoveConstraint(fWidthConstraint, true); 389 linearSpec->RemoveConstraint(fHeightConstraint, true); 390 } 391 } 392 393 fMinWidthConstraint = NULL; 394 fMinHeightConstraint = NULL; 395 fMaxWidthConstraint = NULL; 396 fMaxHeightConstraint = NULL; 397 fWidthConstraint = NULL; 398 fHeightConstraint = NULL; 399 } 400 401 402 BReference<Crossing> 403 WindowArea::_CrossingByPosition(Crossing* crossing, SATGroup* group) 404 { 405 BReference<Crossing> crossRef = NULL; 406 407 Tab* oldHTab = crossing->HorizontalTab(); 408 BReference<Tab> hTab = group->FindHorizontalTab(oldHTab->Position()); 409 if (!hTab) 410 hTab = group->_AddHorizontalTab(oldHTab->Position()); 411 if (!hTab) 412 return crossRef; 413 414 Tab* oldVTab = crossing->VerticalTab(); 415 crossRef = hTab->FindCrossing(oldVTab->Position()); 416 if (crossRef) 417 return crossRef; 418 419 BReference<Tab> vTab = group->FindVerticalTab(oldVTab->Position()); 420 if (!vTab) 421 vTab = group->_AddVerticalTab(oldVTab->Position()); 422 if (!vTab) 423 return crossRef; 424 425 return hTab->AddCrossing(vTab); 426 } 427 428 429 void 430 WindowArea::_InitCorners() 431 { 432 _SetToWindowCorner(fLeftTopCrossing->RightBottomCorner()); 433 _SetToNeighbourCorner(fLeftTopCrossing->LeftBottomCorner()); 434 _SetToNeighbourCorner(fLeftTopCrossing->RightTopCorner()); 435 436 _SetToWindowCorner(fRightTopCrossing->LeftBottomCorner()); 437 _SetToNeighbourCorner(fRightTopCrossing->LeftTopCorner()); 438 _SetToNeighbourCorner(fRightTopCrossing->RightBottomCorner()); 439 440 _SetToWindowCorner(fLeftBottomCrossing->RightTopCorner()); 441 _SetToNeighbourCorner(fLeftBottomCrossing->LeftTopCorner()); 442 _SetToNeighbourCorner(fLeftBottomCrossing->RightBottomCorner()); 443 444 _SetToWindowCorner(fRightBottomCrossing->LeftTopCorner()); 445 _SetToNeighbourCorner(fRightBottomCrossing->LeftBottomCorner()); 446 _SetToNeighbourCorner(fRightBottomCrossing->RightTopCorner()); 447 } 448 449 450 void 451 WindowArea::_CleanupCorners() 452 { 453 _UnsetWindowCorner(fLeftTopCrossing->RightBottomCorner()); 454 _UnsetNeighbourCorner(fLeftTopCrossing->LeftBottomCorner(), 455 fLeftBottomCrossing->LeftTopCorner()); 456 _UnsetNeighbourCorner(fLeftTopCrossing->RightTopCorner(), 457 fLeftBottomCrossing->LeftTopCorner()); 458 459 _UnsetWindowCorner(fRightTopCrossing->LeftBottomCorner()); 460 _UnsetNeighbourCorner(fRightTopCrossing->LeftTopCorner(), 461 fLeftBottomCrossing->RightTopCorner()); 462 _UnsetNeighbourCorner(fRightTopCrossing->RightBottomCorner(), 463 fLeftBottomCrossing->RightTopCorner()); 464 465 _UnsetWindowCorner(fLeftBottomCrossing->RightTopCorner()); 466 _UnsetNeighbourCorner(fLeftBottomCrossing->LeftTopCorner(), 467 fLeftBottomCrossing->LeftBottomCorner()); 468 _UnsetNeighbourCorner(fLeftBottomCrossing->RightBottomCorner(), 469 fLeftBottomCrossing->LeftBottomCorner()); 470 471 _UnsetWindowCorner(fRightBottomCrossing->LeftTopCorner()); 472 _UnsetNeighbourCorner(fRightBottomCrossing->LeftBottomCorner(), 473 fRightBottomCrossing->RightBottomCorner()); 474 _UnsetNeighbourCorner(fRightBottomCrossing->RightTopCorner(), 475 fRightBottomCrossing->RightBottomCorner()); 476 } 477 478 479 void 480 WindowArea::_SetToWindowCorner(Corner* corner) 481 { 482 corner->status = Corner::kUsed; 483 corner->windowArea = this; 484 } 485 486 487 void 488 WindowArea::_SetToNeighbourCorner(Corner* neighbour) 489 { 490 if (neighbour->status == Corner::kNotDockable) 491 neighbour->status = Corner::kFree; 492 } 493 494 495 void 496 WindowArea::_UnsetWindowCorner(Corner* corner) 497 { 498 corner->status = Corner::kFree; 499 corner->windowArea = NULL; 500 } 501 502 503 void 504 WindowArea::_UnsetNeighbourCorner(Corner* neighbour, Corner* opponent) 505 { 506 if (neighbour->status == Corner::kFree && opponent->status != Corner::kUsed) 507 neighbour->status = Corner::kNotDockable; 508 } 509 510 511 void 512 WindowArea::_MoveToSAT(SATWindow* triggerWindow) 513 { 514 SATWindow* topWindow = TopWindow(); 515 // if there is no window in the group we are done 516 if (topWindow == NULL) 517 return; 518 519 BRect frameSAT(LeftVar()->Value() - kMakePositiveOffset, 520 TopVar()->Value() - kMakePositiveOffset, 521 RightVar()->Value() - kMakePositiveOffset, 522 BottomVar()->Value() - kMakePositiveOffset); 523 topWindow->AdjustSizeLimits(frameSAT); 524 525 BRect frame = topWindow->CompleteWindowFrame(); 526 float deltaToX = round(frameSAT.left - frame.left); 527 float deltaToY = round(frameSAT.top - frame.top); 528 frame.OffsetBy(deltaToX, deltaToY); 529 float deltaByX = round(frameSAT.right - frame.right); 530 float deltaByY = round(frameSAT.bottom - frame.bottom); 531 532 int32 workspace = triggerWindow->GetWindow()->CurrentWorkspace(); 533 Desktop* desktop = triggerWindow->GetWindow()->Desktop(); 534 desktop->MoveWindowBy(topWindow->GetWindow(), deltaToX, deltaToY, 535 workspace); 536 // Update frame to the new position 537 desktop->ResizeWindowBy(topWindow->GetWindow(), deltaByX, deltaByY); 538 539 UpdateSizeConstaints(frameSAT); 540 } 541 542 543 Corner::Corner() 544 : 545 status(kNotDockable), 546 windowArea(NULL) 547 { 548 549 } 550 551 552 void 553 Corner::Trace() const 554 { 555 switch (status) { 556 case kFree: 557 debug_printf("free corner\n"); 558 break; 559 560 case kUsed: 561 { 562 debug_printf("attached windows:\n"); 563 const SATWindowList& list = windowArea->WindowList(); 564 for (int i = 0; i < list.CountItems(); i++) { 565 debug_printf("- %s\n", list.ItemAt(i)->GetWindow()->Title()); 566 } 567 break; 568 } 569 570 case kNotDockable: 571 debug_printf("not dockable\n"); 572 break; 573 }; 574 } 575 576 577 Crossing::Crossing(Tab* vertical, Tab* horizontal) 578 : 579 fVerticalTab(vertical), 580 fHorizontalTab(horizontal) 581 { 582 } 583 584 585 Crossing::~Crossing() 586 { 587 fVerticalTab->RemoveCrossing(this); 588 fHorizontalTab->RemoveCrossing(this); 589 } 590 591 592 Corner* 593 Crossing::GetCorner(Corner::position_t corner) const 594 { 595 return &const_cast<Corner*>(fCorners)[corner]; 596 } 597 598 599 Corner* 600 Crossing::GetOppositeCorner(Corner::position_t corner) const 601 { 602 return &const_cast<Corner*>(fCorners)[3 - corner]; 603 } 604 605 606 Tab* 607 Crossing::VerticalTab() const 608 { 609 return fVerticalTab; 610 } 611 612 613 Tab* 614 Crossing::HorizontalTab() const 615 { 616 return fHorizontalTab; 617 } 618 619 620 void 621 Crossing::Trace() const 622 { 623 debug_printf("left-top corner: "); 624 fCorners[Corner::kLeftTop].Trace(); 625 debug_printf("right-top corner: "); 626 fCorners[Corner::kRightTop].Trace(); 627 debug_printf("left-bottom corner: "); 628 fCorners[Corner::kLeftBottom].Trace(); 629 debug_printf("right-bottom corner: "); 630 fCorners[Corner::kRightBottom].Trace(); 631 } 632 633 634 Tab::Tab(SATGroup* group, Variable* variable, orientation_t orientation) 635 : 636 fGroup(group), 637 fVariable(variable), 638 fOrientation(orientation) 639 { 640 641 } 642 643 644 Tab::~Tab() 645 { 646 if (fOrientation == kVertical) 647 fGroup->_RemoveVerticalTab(this); 648 else 649 fGroup->_RemoveHorizontalTab(this); 650 651 delete fVariable; 652 } 653 654 655 float 656 Tab::Position() const 657 { 658 return (float)fVariable->Value() - kMakePositiveOffset; 659 } 660 661 662 void 663 Tab::SetPosition(float position) 664 { 665 fVariable->SetValue(position + kMakePositiveOffset); 666 } 667 668 669 Tab::orientation_t 670 Tab::Orientation() const 671 { 672 return fOrientation; 673 } 674 675 676 Constraint* 677 Tab::Connect(Variable* variable) 678 { 679 return fVariable->IsEqual(variable); 680 } 681 682 683 BReference<Crossing> 684 Tab::AddCrossing(Tab* tab) 685 { 686 if (tab->Orientation() == fOrientation) 687 return NULL; 688 689 Tab* vTab = (fOrientation == kVertical) ? this : tab; 690 Tab* hTab = (fOrientation == kHorizontal) ? this : tab; 691 692 Crossing* crossing = new (std::nothrow)Crossing(vTab, hTab); 693 if (!crossing) 694 return NULL; 695 696 if (!fCrossingList.AddItem(crossing)) { 697 return NULL; 698 } 699 if (!tab->fCrossingList.AddItem(crossing)) { 700 fCrossingList.RemoveItem(crossing); 701 return NULL; 702 } 703 704 BReference<Crossing> crossingRef(crossing, true); 705 return crossingRef; 706 } 707 708 709 bool 710 Tab::RemoveCrossing(Crossing* crossing) 711 { 712 Tab* vTab = crossing->VerticalTab(); 713 Tab* hTab = crossing->HorizontalTab(); 714 715 if (vTab != this && hTab != this) 716 return false; 717 fCrossingList.RemoveItem(crossing); 718 719 return true; 720 } 721 722 723 int32 724 Tab::FindCrossingIndex(Tab* tab) 725 { 726 if (fOrientation == kVertical) { 727 for (int32 i = 0; i < fCrossingList.CountItems(); i++) { 728 if (fCrossingList.ItemAt(i)->HorizontalTab() == tab) 729 return i; 730 } 731 } else { 732 for (int32 i = 0; i < fCrossingList.CountItems(); i++) { 733 if (fCrossingList.ItemAt(i)->VerticalTab() == tab) 734 return i; 735 } 736 } 737 return -1; 738 } 739 740 741 int32 742 Tab::FindCrossingIndex(float pos) 743 { 744 if (fOrientation == kVertical) { 745 for (int32 i = 0; i < fCrossingList.CountItems(); i++) { 746 if (fabs(fCrossingList.ItemAt(i)->HorizontalTab()->Position() - pos) 747 < 0.0001) 748 return i; 749 } 750 } else { 751 for (int32 i = 0; i < fCrossingList.CountItems(); i++) { 752 if (fabs(fCrossingList.ItemAt(i)->VerticalTab()->Position() - pos) 753 < 0.0001) 754 return i; 755 } 756 } 757 return -1; 758 } 759 760 761 Crossing* 762 Tab::FindCrossing(Tab* tab) 763 { 764 return fCrossingList.ItemAt(FindCrossingIndex(tab)); 765 } 766 767 768 Crossing* 769 Tab::FindCrossing(float tabPosition) 770 { 771 return fCrossingList.ItemAt(FindCrossingIndex(tabPosition)); 772 } 773 774 775 const CrossingList* 776 Tab::GetCrossingList() const 777 { 778 return &fCrossingList; 779 } 780 781 782 int 783 Tab::CompareFunction(const Tab* tab1, const Tab* tab2) 784 { 785 if (tab1->Position() < tab2->Position()) 786 return -1; 787 788 return 1; 789 } 790 791 792 SATGroup::SATGroup() 793 : 794 fLinearSpec(new(std::nothrow) LinearSpec()), 795 fHorizontalTabsSorted(false), 796 fVerticalTabsSorted(false), 797 fActiveWindow(NULL) 798 { 799 } 800 801 802 SATGroup::~SATGroup() 803 { 804 // Should be empty 805 if (fSATWindowList.CountItems() > 0) 806 debugger("Deleting a SATGroup which is not empty"); 807 //while (fSATWindowList.CountItems() > 0) 808 // RemoveWindow(fSATWindowList.ItemAt(0)); 809 810 fLinearSpec->ReleaseReference(); 811 } 812 813 814 bool 815 SATGroup::AddWindow(SATWindow* window, Tab* left, Tab* top, Tab* right, 816 Tab* bottom) 817 { 818 STRACE_SAT("SATGroup::AddWindow\n"); 819 820 // first check if we have to create tabs and missing corners. 821 BReference<Tab> leftRef, rightRef, topRef, bottomRef; 822 BReference<Crossing> leftTopRef, rightTopRef, leftBottomRef, rightBottomRef; 823 824 if (left != NULL && top != NULL) 825 leftTopRef = left->FindCrossing(top); 826 if (right != NULL && top != NULL) 827 rightTopRef = right->FindCrossing(top); 828 if (left != NULL && bottom != NULL) 829 leftBottomRef = left->FindCrossing(bottom); 830 if (right != NULL && bottom != NULL) 831 rightBottomRef = right->FindCrossing(bottom); 832 833 if (left == NULL) { 834 leftRef = _AddVerticalTab(); 835 left = leftRef.Get(); 836 } 837 if (top == NULL) { 838 topRef = _AddHorizontalTab(); 839 top = topRef.Get(); 840 } 841 if (right == NULL) { 842 rightRef = _AddVerticalTab(); 843 right = rightRef.Get(); 844 } 845 if (bottom == NULL) { 846 bottomRef = _AddHorizontalTab(); 847 bottom = bottomRef.Get(); 848 } 849 if (left == NULL || top == NULL || right == NULL || bottom == NULL) 850 return false; 851 852 if (leftTopRef == NULL) { 853 leftTopRef = left->AddCrossing(top); 854 if (leftTopRef == NULL) 855 return false; 856 } 857 if (!rightTopRef) { 858 rightTopRef = right->AddCrossing(top); 859 if (!rightTopRef) 860 return false; 861 } 862 if (!leftBottomRef) { 863 leftBottomRef = left->AddCrossing(bottom); 864 if (!leftBottomRef) 865 return false; 866 } 867 if (!rightBottomRef) { 868 rightBottomRef = right->AddCrossing(bottom); 869 if (!rightBottomRef) 870 return false; 871 } 872 873 WindowArea* area = new(std::nothrow) WindowArea(leftTopRef, rightTopRef, 874 leftBottomRef, rightBottomRef); 875 if (area == NULL) 876 return false; 877 // the area register itself in our area list 878 if (area->Init(this) == false) { 879 delete area; 880 return false; 881 } 882 // delete the area if AddWindow failed / release our reference on it 883 BReference<WindowArea> areaRef(area, true); 884 885 return AddWindow(window, area); 886 } 887 888 889 bool 890 SATGroup::AddWindow(SATWindow* window, WindowArea* area, SATWindow* after) 891 { 892 if (!area->_AddWindow(window, after)) 893 return false; 894 895 if (!fSATWindowList.AddItem(window)) { 896 area->_RemoveWindow(window); 897 return false; 898 } 899 900 if (!window->AddedToGroup(this, area)) { 901 area->_RemoveWindow(window); 902 fSATWindowList.RemoveItem(window); 903 return false; 904 } 905 906 return true; 907 } 908 909 910 bool 911 SATGroup::RemoveWindow(SATWindow* window, bool stayBelowMouse) 912 { 913 if (!fSATWindowList.RemoveItem(window)) 914 return false; 915 916 // We need the area a little bit longer because the area could hold the 917 // last reference to the group. 918 BReference<WindowArea> area = window->GetWindowArea(); 919 if (area.Get() != NULL) 920 area->_RemoveWindow(window); 921 922 window->RemovedFromGroup(this, stayBelowMouse); 923 924 if (CountItems() >= 2) 925 WindowAt(0)->DoGroupLayout(); 926 927 return true; 928 } 929 930 931 int32 932 SATGroup::CountItems() 933 { 934 return fSATWindowList.CountItems(); 935 } 936 937 938 SATWindow* 939 SATGroup::WindowAt(int32 index) 940 { 941 return fSATWindowList.ItemAt(index); 942 } 943 944 945 SATWindow* 946 SATGroup::ActiveWindow() const 947 { 948 return fActiveWindow; 949 } 950 951 952 void 953 SATGroup::SetActiveWindow(SATWindow* window) 954 { 955 fActiveWindow = window; 956 } 957 958 959 const TabList* 960 SATGroup::HorizontalTabs() 961 { 962 if (!fHorizontalTabsSorted) { 963 fHorizontalTabs.SortItems(Tab::CompareFunction); 964 fHorizontalTabsSorted = true; 965 } 966 return &fHorizontalTabs; 967 } 968 969 970 const TabList* 971 SATGroup::VerticalTabs() 972 { 973 if (!fVerticalTabsSorted) { 974 fVerticalTabs.SortItems(Tab::CompareFunction); 975 fVerticalTabsSorted = true; 976 } 977 return &fVerticalTabs; 978 } 979 980 981 Tab* 982 SATGroup::FindHorizontalTab(float position) 983 { 984 return _FindTab(fHorizontalTabs, position); 985 } 986 987 988 Tab* 989 SATGroup::FindVerticalTab(float position) 990 { 991 return _FindTab(fVerticalTabs, position); 992 } 993 994 995 void 996 SATGroup::WindowAreaRemoved(WindowArea* area) 997 { 998 _SplitGroupIfNecessary(area); 999 } 1000 1001 1002 status_t 1003 SATGroup::RestoreGroup(const BMessage& archive, StackAndTile* sat) 1004 { 1005 // create new group 1006 SATGroup* group = new (std::nothrow)SATGroup; 1007 if (group == NULL) 1008 return B_NO_MEMORY; 1009 BReference<SATGroup> groupRef; 1010 groupRef.SetTo(group, true); 1011 1012 int32 nHTabs, nVTabs; 1013 status_t status; 1014 status = archive.FindInt32("htab_count", &nHTabs); 1015 if (status != B_OK) 1016 return status; 1017 status = archive.FindInt32("vtab_count", &nVTabs); 1018 if (status != B_OK) 1019 return status; 1020 1021 vector<BReference<Tab> > tempHTabs; 1022 for (int i = 0; i < nHTabs; i++) { 1023 BReference<Tab> tab = group->_AddHorizontalTab(); 1024 if (!tab) 1025 return B_NO_MEMORY; 1026 tempHTabs.push_back(tab); 1027 } 1028 vector<BReference<Tab> > tempVTabs; 1029 for (int i = 0; i < nVTabs; i++) { 1030 BReference<Tab> tab = group->_AddVerticalTab(); 1031 if (!tab) 1032 return B_NO_MEMORY; 1033 tempVTabs.push_back(tab); 1034 } 1035 1036 BMessage areaArchive; 1037 for (int32 i = 0; archive.FindMessage("area", i, &areaArchive) == B_OK; 1038 i++) { 1039 uint32 leftTab, rightTab, topTab, bottomTab; 1040 if (areaArchive.FindInt32("left_tab", (int32*)&leftTab) != B_OK 1041 || areaArchive.FindInt32("right_tab", (int32*)&rightTab) != B_OK 1042 || areaArchive.FindInt32("top_tab", (int32*)&topTab) != B_OK 1043 || areaArchive.FindInt32("bottom_tab", (int32*)&bottomTab) != B_OK) 1044 return B_ERROR; 1045 1046 if (leftTab >= tempVTabs.size() || rightTab >= tempVTabs.size()) 1047 return B_BAD_VALUE; 1048 if (topTab >= tempHTabs.size() || bottomTab >= tempHTabs.size()) 1049 return B_BAD_VALUE; 1050 1051 Tab* left = tempVTabs[leftTab]; 1052 Tab* right = tempVTabs[rightTab]; 1053 Tab* top = tempHTabs[topTab]; 1054 Tab* bottom = tempHTabs[bottomTab]; 1055 1056 // adding windows to area 1057 uint64 windowId; 1058 SATWindow* prevWindow = NULL; 1059 for (int32 i = 0; areaArchive.FindInt64("window", i, 1060 (int64*)&windowId) == B_OK; i++) { 1061 SATWindow* window = sat->FindSATWindow(windowId); 1062 if (!window) 1063 continue; 1064 1065 if (prevWindow == NULL) { 1066 if (!group->AddWindow(window, left, top, right, bottom)) 1067 continue; 1068 prevWindow = window; 1069 } else { 1070 if (!prevWindow->StackWindow(window)) 1071 continue; 1072 prevWindow = window; 1073 } 1074 } 1075 } 1076 return B_OK; 1077 } 1078 1079 1080 status_t 1081 SATGroup::ArchiveGroup(BMessage& archive) 1082 { 1083 archive.AddInt32("htab_count", fHorizontalTabs.CountItems()); 1084 archive.AddInt32("vtab_count", fVerticalTabs.CountItems()); 1085 1086 for (int i = 0; i < fWindowAreaList.CountItems(); i++) { 1087 WindowArea* area = fWindowAreaList.ItemAt(i); 1088 int32 leftTab = fVerticalTabs.IndexOf(area->LeftTab()); 1089 int32 rightTab = fVerticalTabs.IndexOf(area->RightTab()); 1090 int32 topTab = fHorizontalTabs.IndexOf(area->TopTab()); 1091 int32 bottomTab = fHorizontalTabs.IndexOf(area->BottomTab()); 1092 1093 BMessage areaMessage; 1094 areaMessage.AddInt32("left_tab", leftTab); 1095 areaMessage.AddInt32("right_tab", rightTab); 1096 areaMessage.AddInt32("top_tab", topTab); 1097 areaMessage.AddInt32("bottom_tab", bottomTab); 1098 1099 const SATWindowList& windowList = area->WindowList(); 1100 for (int a = 0; a < windowList.CountItems(); a++) 1101 areaMessage.AddInt64("window", windowList.ItemAt(a)->Id()); 1102 1103 archive.AddMessage("area", &areaMessage); 1104 } 1105 return B_OK; 1106 } 1107 1108 1109 BReference<Tab> 1110 SATGroup::_AddHorizontalTab(float position) 1111 { 1112 if (fLinearSpec == NULL) 1113 return NULL; 1114 Variable* variable = fLinearSpec->AddVariable(); 1115 if (variable == NULL) 1116 return NULL; 1117 1118 Tab* tab = new (std::nothrow)Tab(this, variable, Tab::kHorizontal); 1119 if (tab == NULL) 1120 return NULL; 1121 BReference<Tab> tabRef(tab, true); 1122 1123 if (!fHorizontalTabs.AddItem(tab)) 1124 return NULL; 1125 1126 fHorizontalTabsSorted = false; 1127 tabRef->SetPosition(position); 1128 return tabRef; 1129 } 1130 1131 1132 BReference<Tab> 1133 SATGroup::_AddVerticalTab(float position) 1134 { 1135 if (fLinearSpec == NULL) 1136 return NULL; 1137 Variable* variable = fLinearSpec->AddVariable(); 1138 if (variable == NULL) 1139 return NULL; 1140 1141 Tab* tab = new (std::nothrow)Tab(this, variable, Tab::kVertical); 1142 if (tab == NULL) 1143 return NULL; 1144 BReference<Tab> tabRef(tab, true); 1145 1146 if (!fVerticalTabs.AddItem(tab)) 1147 return NULL; 1148 1149 fVerticalTabsSorted = false; 1150 tabRef->SetPosition(position); 1151 return tabRef; 1152 } 1153 1154 1155 bool 1156 SATGroup::_RemoveHorizontalTab(Tab* tab) 1157 { 1158 if (!fHorizontalTabs.RemoveItem(tab)) 1159 return false; 1160 fHorizontalTabsSorted = false; 1161 // don't delete the tab it is reference counted 1162 return true; 1163 } 1164 1165 1166 bool 1167 SATGroup::_RemoveVerticalTab(Tab* tab) 1168 { 1169 if (!fVerticalTabs.RemoveItem(tab)) 1170 return false; 1171 fVerticalTabsSorted = false; 1172 // don't delete the tab it is reference counted 1173 return true; 1174 } 1175 1176 1177 Tab* 1178 SATGroup::_FindTab(const TabList& list, float position) 1179 { 1180 for (int i = 0; i < list.CountItems(); i++) 1181 if (fabs(list.ItemAt(i)->Position() - position) < 0.00001) 1182 return list.ItemAt(i); 1183 1184 return NULL; 1185 } 1186 1187 1188 void 1189 SATGroup::_SplitGroupIfNecessary(WindowArea* removedArea) 1190 { 1191 // if there are windows stacked in the area we don't need to split 1192 if (removedArea == NULL || removedArea->WindowList().CountItems() > 1) 1193 return; 1194 1195 WindowAreaList neighbourWindows; 1196 1197 _FillNeighbourList(neighbourWindows, removedArea); 1198 1199 bool ownGroupProcessed = false; 1200 WindowAreaList newGroup; 1201 while (_FindConnectedGroup(neighbourWindows, removedArea, newGroup)) { 1202 STRACE_SAT("Connected group found; %i window(s)\n", 1203 (int)newGroup.CountItems()); 1204 if (newGroup.CountItems() == 1 1205 && newGroup.ItemAt(0)->WindowList().CountItems() == 1) { 1206 SATWindow* window = newGroup.ItemAt(0)->WindowList().ItemAt(0); 1207 RemoveWindow(window); 1208 _EnsureGroupIsOnScreen(window->GetGroup()); 1209 } else if (ownGroupProcessed) 1210 _SpawnNewGroup(newGroup); 1211 else { 1212 _EnsureGroupIsOnScreen(this); 1213 ownGroupProcessed = true; 1214 } 1215 1216 newGroup.MakeEmpty(); 1217 } 1218 } 1219 1220 1221 void 1222 SATGroup::_FillNeighbourList(WindowAreaList& neighbourWindows, 1223 WindowArea* area) 1224 { 1225 _LeftNeighbours(neighbourWindows, area); 1226 _RightNeighbours(neighbourWindows, area); 1227 _TopNeighbours(neighbourWindows, area); 1228 _BottomNeighbours(neighbourWindows, area); 1229 } 1230 1231 1232 void 1233 SATGroup::_LeftNeighbours(WindowAreaList& neighbourWindows, WindowArea* parent) 1234 { 1235 float startPos = parent->LeftTopCrossing()->HorizontalTab()->Position(); 1236 float endPos = parent->LeftBottomCrossing()->HorizontalTab()->Position(); 1237 1238 Tab* tab = parent->LeftTopCrossing()->VerticalTab(); 1239 const CrossingList* crossingList = tab->GetCrossingList(); 1240 for (int i = 0; i < crossingList->CountItems(); i++) { 1241 Corner* corner = crossingList->ItemAt(i)->LeftTopCorner(); 1242 if (corner->status != Corner::kUsed) 1243 continue; 1244 1245 WindowArea* area = corner->windowArea; 1246 float pos1 = area->LeftTopCrossing()->HorizontalTab()->Position(); 1247 float pos2 = area->LeftBottomCrossing()->HorizontalTab()->Position(); 1248 1249 if (pos1 < endPos && pos2 > startPos) 1250 neighbourWindows.AddItem(area); 1251 1252 if (pos2 > endPos) 1253 break; 1254 } 1255 } 1256 1257 1258 void 1259 SATGroup::_TopNeighbours(WindowAreaList& neighbourWindows, WindowArea* parent) 1260 { 1261 float startPos = parent->LeftTopCrossing()->VerticalTab()->Position(); 1262 float endPos = parent->RightTopCrossing()->VerticalTab()->Position(); 1263 1264 Tab* tab = parent->LeftTopCrossing()->HorizontalTab(); 1265 const CrossingList* crossingList = tab->GetCrossingList(); 1266 for (int i = 0; i < crossingList->CountItems(); i++) { 1267 Corner* corner = crossingList->ItemAt(i)->LeftTopCorner(); 1268 if (corner->status != Corner::kUsed) 1269 continue; 1270 1271 WindowArea* area = corner->windowArea; 1272 float pos1 = area->LeftTopCrossing()->VerticalTab()->Position(); 1273 float pos2 = area->RightTopCrossing()->VerticalTab()->Position(); 1274 1275 if (pos1 < endPos && pos2 > startPos) 1276 neighbourWindows.AddItem(area); 1277 1278 if (pos2 > endPos) 1279 break; 1280 } 1281 } 1282 1283 1284 void 1285 SATGroup::_RightNeighbours(WindowAreaList& neighbourWindows, WindowArea* parent) 1286 { 1287 float startPos = parent->RightTopCrossing()->HorizontalTab()->Position(); 1288 float endPos = parent->RightBottomCrossing()->HorizontalTab()->Position(); 1289 1290 Tab* tab = parent->RightTopCrossing()->VerticalTab(); 1291 const CrossingList* crossingList = tab->GetCrossingList(); 1292 for (int i = 0; i < crossingList->CountItems(); i++) { 1293 Corner* corner = crossingList->ItemAt(i)->RightTopCorner(); 1294 if (corner->status != Corner::kUsed) 1295 continue; 1296 1297 WindowArea* area = corner->windowArea; 1298 float pos1 = area->RightTopCrossing()->HorizontalTab()->Position(); 1299 float pos2 = area->RightBottomCrossing()->HorizontalTab()->Position(); 1300 1301 if (pos1 < endPos && pos2 > startPos) 1302 neighbourWindows.AddItem(area); 1303 1304 if (pos2 > endPos) 1305 break; 1306 } 1307 } 1308 1309 1310 void 1311 SATGroup::_BottomNeighbours(WindowAreaList& neighbourWindows, 1312 WindowArea* parent) 1313 { 1314 float startPos = parent->LeftBottomCrossing()->VerticalTab()->Position(); 1315 float endPos = parent->RightBottomCrossing()->VerticalTab()->Position(); 1316 1317 Tab* tab = parent->LeftBottomCrossing()->HorizontalTab(); 1318 const CrossingList* crossingList = tab->GetCrossingList(); 1319 for (int i = 0; i < crossingList->CountItems(); i++) { 1320 Corner* corner = crossingList->ItemAt(i)->LeftBottomCorner(); 1321 if (corner->status != Corner::kUsed) 1322 continue; 1323 1324 WindowArea* area = corner->windowArea; 1325 float pos1 = area->LeftBottomCrossing()->VerticalTab()->Position(); 1326 float pos2 = area->RightBottomCrossing()->VerticalTab()->Position(); 1327 1328 if (pos1 < endPos && pos2 > startPos) 1329 neighbourWindows.AddItem(area); 1330 1331 if (pos2 > endPos) 1332 break; 1333 } 1334 } 1335 1336 1337 bool 1338 SATGroup::_FindConnectedGroup(WindowAreaList& seedList, WindowArea* removedArea, 1339 WindowAreaList& newGroup) 1340 { 1341 if (seedList.CountItems() == 0) 1342 return false; 1343 1344 WindowArea* area = seedList.RemoveItemAt(0); 1345 newGroup.AddItem(area); 1346 1347 _FollowSeed(area, removedArea, seedList, newGroup); 1348 return true; 1349 } 1350 1351 1352 void 1353 SATGroup::_FollowSeed(WindowArea* area, WindowArea* veto, 1354 WindowAreaList& seedList, WindowAreaList& newGroup) 1355 { 1356 WindowAreaList neighbours; 1357 _FillNeighbourList(neighbours, area); 1358 for (int i = 0; i < neighbours.CountItems(); i++) { 1359 WindowArea* currentArea = neighbours.ItemAt(i); 1360 if (currentArea != veto && !newGroup.HasItem(currentArea)) { 1361 newGroup.AddItem(currentArea); 1362 // if we get a area from the seed list it is not a seed any more 1363 seedList.RemoveItem(currentArea); 1364 } else { 1365 // don't _FollowSeed of invalid areas 1366 neighbours.RemoveItemAt(i); 1367 i--; 1368 } 1369 } 1370 1371 for (int i = 0; i < neighbours.CountItems(); i++) 1372 _FollowSeed(neighbours.ItemAt(i), veto, seedList, newGroup); 1373 } 1374 1375 1376 void 1377 SATGroup::_SpawnNewGroup(const WindowAreaList& newGroup) 1378 { 1379 STRACE_SAT("SATGroup::_SpawnNewGroup\n"); 1380 SATGroup* group = new (std::nothrow)SATGroup; 1381 if (group == NULL) 1382 return; 1383 BReference<SATGroup> groupRef; 1384 groupRef.SetTo(group, true); 1385 1386 for (int i = 0; i < newGroup.CountItems(); i++) 1387 newGroup.ItemAt(i)->PropagateToGroup(group); 1388 1389 _EnsureGroupIsOnScreen(group); 1390 } 1391 1392 1393 const float kMinOverlap = 50; 1394 const float kMoveToScreen = 75; 1395 1396 1397 void 1398 SATGroup::_EnsureGroupIsOnScreen(SATGroup* group) 1399 { 1400 STRACE_SAT("SATGroup::_EnsureGroupIsOnScreen\n"); 1401 if (group == NULL || group->CountItems() < 1) 1402 return; 1403 1404 SATWindow* window = group->WindowAt(0); 1405 Desktop* desktop = window->GetWindow()->Desktop(); 1406 if (desktop == NULL) 1407 return; 1408 1409 const float kBigDistance = 1E+10; 1410 1411 float minLeftDistance = kBigDistance; 1412 BRect leftRect; 1413 float minTopDistance = kBigDistance; 1414 BRect topRect; 1415 float minRightDistance = kBigDistance; 1416 BRect rightRect; 1417 float minBottomDistance = kBigDistance; 1418 BRect bottomRect; 1419 1420 BRect screen = window->GetWindow()->Screen()->Frame(); 1421 BRect reducedScreen = screen; 1422 reducedScreen.InsetBy(kMinOverlap, kMinOverlap); 1423 1424 for (int i = 0; i < group->CountItems(); i++) { 1425 SATWindow* window = group->WindowAt(i); 1426 BRect frame = window->CompleteWindowFrame(); 1427 if (reducedScreen.Intersects(frame)) 1428 return; 1429 1430 if (frame.right < screen.left + kMinOverlap) { 1431 float dist = fabs(screen.left - frame.right); 1432 if (dist < minLeftDistance) { 1433 minLeftDistance = dist; 1434 leftRect = frame; 1435 } else if (dist == minLeftDistance) 1436 leftRect = leftRect | frame; 1437 } 1438 if (frame.top > screen.bottom - kMinOverlap) { 1439 float dist = fabs(frame.top - screen.bottom); 1440 if (dist < minBottomDistance) { 1441 minBottomDistance = dist; 1442 bottomRect = frame; 1443 } else if (dist == minBottomDistance) 1444 bottomRect = bottomRect | frame; 1445 } 1446 if (frame.left > screen.right - kMinOverlap) { 1447 float dist = fabs(frame.left - screen.right); 1448 if (dist < minRightDistance) { 1449 minRightDistance = dist; 1450 rightRect = frame; 1451 } else if (dist == minRightDistance) 1452 rightRect = rightRect | frame; 1453 } 1454 if (frame.bottom < screen.top + kMinOverlap) { 1455 float dist = fabs(frame.bottom - screen.top); 1456 if (dist < minTopDistance) { 1457 minTopDistance = dist; 1458 topRect = frame; 1459 } else if (dist == minTopDistance) 1460 topRect = topRect | frame; 1461 } 1462 } 1463 1464 BPoint offset; 1465 if (minLeftDistance < kBigDistance) { 1466 offset.x = screen.left - leftRect.right + kMoveToScreen; 1467 _CallculateYOffset(offset, leftRect, screen); 1468 } else if (minTopDistance < kBigDistance) { 1469 offset.y = screen.top - topRect.bottom + kMoveToScreen; 1470 _CallculateXOffset(offset, topRect, screen); 1471 } else if (minRightDistance < kBigDistance) { 1472 offset.x = screen.right - rightRect.left - kMoveToScreen; 1473 _CallculateYOffset(offset, rightRect, screen); 1474 } else if (minBottomDistance < kBigDistance) { 1475 offset.y = screen.bottom - bottomRect.top - kMoveToScreen; 1476 _CallculateXOffset(offset, bottomRect, screen); 1477 } 1478 1479 if (offset.x == 0. && offset.y == 0.) 1480 return; 1481 STRACE_SAT("move group back to screen: offset x: %f offset y: %f\n", 1482 offset.x, offset.y); 1483 1484 desktop->MoveWindowBy(window->GetWindow(), offset.x, offset.y); 1485 window->DoGroupLayout(); 1486 } 1487 1488 1489 void 1490 SATGroup::_CallculateXOffset(BPoint& offset, BRect& frame, BRect& screen) 1491 { 1492 if (frame.right < screen.left + kMinOverlap) 1493 offset.x = screen.left - frame.right + kMoveToScreen; 1494 else if (frame.left > screen.right - kMinOverlap) 1495 offset.x = screen.right - frame.left - kMoveToScreen; 1496 } 1497 1498 1499 void 1500 SATGroup::_CallculateYOffset(BPoint& offset, BRect& frame, BRect& screen) 1501 { 1502 if (frame.top > screen.bottom - kMinOverlap) 1503 offset.y = screen.bottom - frame.top - kMoveToScreen; 1504 else if (frame.bottom < screen.top + kMinOverlap) 1505 offset.y = screen.top - frame.bottom + kMoveToScreen; 1506 } 1507