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 652 653 float 654 Tab::Position() const 655 { 656 return (float)fVariable->Value() - kMakePositiveOffset; 657 } 658 659 660 void 661 Tab::SetPosition(float position) 662 { 663 fVariable->SetValue(position + kMakePositiveOffset); 664 } 665 666 667 Tab::orientation_t 668 Tab::Orientation() const 669 { 670 return fOrientation; 671 } 672 673 674 Constraint* 675 Tab::Connect(Variable* variable) 676 { 677 return fVariable->IsEqual(variable); 678 } 679 680 681 BReference<Crossing> 682 Tab::AddCrossing(Tab* tab) 683 { 684 if (tab->Orientation() == fOrientation) 685 return NULL; 686 687 Tab* vTab = (fOrientation == kVertical) ? this : tab; 688 Tab* hTab = (fOrientation == kHorizontal) ? this : tab; 689 690 Crossing* crossing = new (std::nothrow)Crossing(vTab, hTab); 691 if (!crossing) 692 return NULL; 693 694 if (!fCrossingList.AddItem(crossing)) { 695 return NULL; 696 } 697 if (!tab->fCrossingList.AddItem(crossing)) { 698 fCrossingList.RemoveItem(crossing); 699 return NULL; 700 } 701 702 BReference<Crossing> crossingRef(crossing, true); 703 return crossingRef; 704 } 705 706 707 bool 708 Tab::RemoveCrossing(Crossing* crossing) 709 { 710 Tab* vTab = crossing->VerticalTab(); 711 Tab* hTab = crossing->HorizontalTab(); 712 713 if (vTab != this && hTab != this) 714 return false; 715 fCrossingList.RemoveItem(crossing); 716 717 return true; 718 } 719 720 721 int32 722 Tab::FindCrossingIndex(Tab* tab) 723 { 724 if (fOrientation == kVertical) { 725 for (int32 i = 0; i < fCrossingList.CountItems(); i++) { 726 if (fCrossingList.ItemAt(i)->HorizontalTab() == tab) 727 return i; 728 } 729 } else { 730 for (int32 i = 0; i < fCrossingList.CountItems(); i++) { 731 if (fCrossingList.ItemAt(i)->VerticalTab() == tab) 732 return i; 733 } 734 } 735 return -1; 736 } 737 738 739 int32 740 Tab::FindCrossingIndex(float pos) 741 { 742 if (fOrientation == kVertical) { 743 for (int32 i = 0; i < fCrossingList.CountItems(); i++) { 744 if (fabs(fCrossingList.ItemAt(i)->HorizontalTab()->Position() - pos) 745 < 0.0001) 746 return i; 747 } 748 } else { 749 for (int32 i = 0; i < fCrossingList.CountItems(); i++) { 750 if (fabs(fCrossingList.ItemAt(i)->VerticalTab()->Position() - pos) 751 < 0.0001) 752 return i; 753 } 754 } 755 return -1; 756 } 757 758 759 Crossing* 760 Tab::FindCrossing(Tab* tab) 761 { 762 return fCrossingList.ItemAt(FindCrossingIndex(tab)); 763 } 764 765 766 Crossing* 767 Tab::FindCrossing(float tabPosition) 768 { 769 return fCrossingList.ItemAt(FindCrossingIndex(tabPosition)); 770 } 771 772 773 const CrossingList* 774 Tab::GetCrossingList() const 775 { 776 return &fCrossingList; 777 } 778 779 780 int 781 Tab::CompareFunction(const Tab* tab1, const Tab* tab2) 782 { 783 if (tab1->Position() < tab2->Position()) 784 return -1; 785 786 return 1; 787 } 788 789 790 SATGroup::SATGroup() 791 : 792 fLinearSpec(new(std::nothrow) LinearSpec()), 793 fHorizontalTabsSorted(false), 794 fVerticalTabsSorted(false), 795 fActiveWindow(NULL) 796 { 797 } 798 799 800 SATGroup::~SATGroup() 801 { 802 // Should be empty 803 if (fSATWindowList.CountItems() > 0) 804 debugger("Deleting a SATGroup which is not empty"); 805 //while (fSATWindowList.CountItems() > 0) 806 // RemoveWindow(fSATWindowList.ItemAt(0)); 807 808 fLinearSpec->ReleaseReference(); 809 } 810 811 812 bool 813 SATGroup::AddWindow(SATWindow* window, Tab* left, Tab* top, Tab* right, 814 Tab* bottom) 815 { 816 STRACE_SAT("SATGroup::AddWindow\n"); 817 818 // first check if we have to create tabs and missing corners. 819 BReference<Tab> leftRef, rightRef, topRef, bottomRef; 820 BReference<Crossing> leftTopRef, rightTopRef, leftBottomRef, rightBottomRef; 821 822 if (left != NULL && top != NULL) 823 leftTopRef = left->FindCrossing(top); 824 if (right != NULL && top != NULL) 825 rightTopRef = right->FindCrossing(top); 826 if (left != NULL && bottom != NULL) 827 leftBottomRef = left->FindCrossing(bottom); 828 if (right != NULL && bottom != NULL) 829 rightBottomRef = right->FindCrossing(bottom); 830 831 if (left == NULL) { 832 leftRef = _AddVerticalTab(); 833 left = leftRef.Get(); 834 } 835 if (top == NULL) { 836 topRef = _AddHorizontalTab(); 837 top = topRef.Get(); 838 } 839 if (right == NULL) { 840 rightRef = _AddVerticalTab(); 841 right = rightRef.Get(); 842 } 843 if (bottom == NULL) { 844 bottomRef = _AddHorizontalTab(); 845 bottom = bottomRef.Get(); 846 } 847 if (left == NULL || top == NULL || right == NULL || bottom == NULL) 848 return false; 849 850 if (leftTopRef == NULL) { 851 leftTopRef = left->AddCrossing(top); 852 if (leftTopRef == NULL) 853 return false; 854 } 855 if (!rightTopRef) { 856 rightTopRef = right->AddCrossing(top); 857 if (!rightTopRef) 858 return false; 859 } 860 if (!leftBottomRef) { 861 leftBottomRef = left->AddCrossing(bottom); 862 if (!leftBottomRef) 863 return false; 864 } 865 if (!rightBottomRef) { 866 rightBottomRef = right->AddCrossing(bottom); 867 if (!rightBottomRef) 868 return false; 869 } 870 871 WindowArea* area = new(std::nothrow) WindowArea(leftTopRef, rightTopRef, 872 leftBottomRef, rightBottomRef); 873 if (area == NULL) 874 return false; 875 // the area register itself in our area list 876 if (area->Init(this) == false) { 877 delete area; 878 return false; 879 } 880 // delete the area if AddWindow failed / release our reference on it 881 BReference<WindowArea> areaRef(area, true); 882 883 return AddWindow(window, area); 884 } 885 886 887 bool 888 SATGroup::AddWindow(SATWindow* window, WindowArea* area, SATWindow* after) 889 { 890 if (!area->_AddWindow(window, after)) 891 return false; 892 893 if (!fSATWindowList.AddItem(window)) { 894 area->_RemoveWindow(window); 895 return false; 896 } 897 898 if (!window->AddedToGroup(this, area)) { 899 area->_RemoveWindow(window); 900 fSATWindowList.RemoveItem(window); 901 return false; 902 } 903 904 return true; 905 } 906 907 908 bool 909 SATGroup::RemoveWindow(SATWindow* window, bool stayBelowMouse) 910 { 911 if (!fSATWindowList.RemoveItem(window)) 912 return false; 913 914 // We need the area a little bit longer because the area could hold the 915 // last reference to the group. 916 BReference<WindowArea> area = window->GetWindowArea(); 917 if (area.IsSet()) 918 area->_RemoveWindow(window); 919 920 window->RemovedFromGroup(this, stayBelowMouse); 921 922 if (CountItems() >= 2) 923 WindowAt(0)->DoGroupLayout(); 924 925 return true; 926 } 927 928 929 int32 930 SATGroup::CountItems() 931 { 932 return fSATWindowList.CountItems(); 933 } 934 935 936 SATWindow* 937 SATGroup::WindowAt(int32 index) 938 { 939 return fSATWindowList.ItemAt(index); 940 } 941 942 943 SATWindow* 944 SATGroup::ActiveWindow() const 945 { 946 return fActiveWindow; 947 } 948 949 950 void 951 SATGroup::SetActiveWindow(SATWindow* window) 952 { 953 fActiveWindow = window; 954 } 955 956 957 const TabList* 958 SATGroup::HorizontalTabs() 959 { 960 if (!fHorizontalTabsSorted) { 961 fHorizontalTabs.SortItems(Tab::CompareFunction); 962 fHorizontalTabsSorted = true; 963 } 964 return &fHorizontalTabs; 965 } 966 967 968 const TabList* 969 SATGroup::VerticalTabs() 970 { 971 if (!fVerticalTabsSorted) { 972 fVerticalTabs.SortItems(Tab::CompareFunction); 973 fVerticalTabsSorted = true; 974 } 975 return &fVerticalTabs; 976 } 977 978 979 Tab* 980 SATGroup::FindHorizontalTab(float position) 981 { 982 return _FindTab(fHorizontalTabs, position); 983 } 984 985 986 Tab* 987 SATGroup::FindVerticalTab(float position) 988 { 989 return _FindTab(fVerticalTabs, position); 990 } 991 992 993 void 994 SATGroup::WindowAreaRemoved(WindowArea* area) 995 { 996 _SplitGroupIfNecessary(area); 997 } 998 999 1000 status_t 1001 SATGroup::RestoreGroup(const BMessage& archive, StackAndTile* sat) 1002 { 1003 // create new group 1004 SATGroup* group = new (std::nothrow)SATGroup; 1005 if (group == NULL) 1006 return B_NO_MEMORY; 1007 BReference<SATGroup> groupRef; 1008 groupRef.SetTo(group, true); 1009 1010 int32 nHTabs, nVTabs; 1011 status_t status; 1012 status = archive.FindInt32("htab_count", &nHTabs); 1013 if (status != B_OK) 1014 return status; 1015 status = archive.FindInt32("vtab_count", &nVTabs); 1016 if (status != B_OK) 1017 return status; 1018 1019 vector<BReference<Tab> > tempHTabs; 1020 for (int i = 0; i < nHTabs; i++) { 1021 BReference<Tab> tab = group->_AddHorizontalTab(); 1022 if (!tab) 1023 return B_NO_MEMORY; 1024 tempHTabs.push_back(tab); 1025 } 1026 vector<BReference<Tab> > tempVTabs; 1027 for (int i = 0; i < nVTabs; i++) { 1028 BReference<Tab> tab = group->_AddVerticalTab(); 1029 if (!tab) 1030 return B_NO_MEMORY; 1031 tempVTabs.push_back(tab); 1032 } 1033 1034 BMessage areaArchive; 1035 for (int32 i = 0; archive.FindMessage("area", i, &areaArchive) == B_OK; 1036 i++) { 1037 uint32 leftTab, rightTab, topTab, bottomTab; 1038 if (areaArchive.FindInt32("left_tab", (int32*)&leftTab) != B_OK 1039 || areaArchive.FindInt32("right_tab", (int32*)&rightTab) != B_OK 1040 || areaArchive.FindInt32("top_tab", (int32*)&topTab) != B_OK 1041 || areaArchive.FindInt32("bottom_tab", (int32*)&bottomTab) != B_OK) 1042 return B_ERROR; 1043 1044 if (leftTab >= tempVTabs.size() || rightTab >= tempVTabs.size()) 1045 return B_BAD_VALUE; 1046 if (topTab >= tempHTabs.size() || bottomTab >= tempHTabs.size()) 1047 return B_BAD_VALUE; 1048 1049 Tab* left = tempVTabs[leftTab]; 1050 Tab* right = tempVTabs[rightTab]; 1051 Tab* top = tempHTabs[topTab]; 1052 Tab* bottom = tempHTabs[bottomTab]; 1053 1054 // adding windows to area 1055 uint64 windowId; 1056 SATWindow* prevWindow = NULL; 1057 for (int32 i = 0; areaArchive.FindInt64("window", i, 1058 (int64*)&windowId) == B_OK; i++) { 1059 SATWindow* window = sat->FindSATWindow(windowId); 1060 if (!window) 1061 continue; 1062 1063 if (prevWindow == NULL) { 1064 if (!group->AddWindow(window, left, top, right, bottom)) 1065 continue; 1066 prevWindow = window; 1067 } else { 1068 if (!prevWindow->StackWindow(window)) 1069 continue; 1070 prevWindow = window; 1071 } 1072 } 1073 } 1074 return B_OK; 1075 } 1076 1077 1078 status_t 1079 SATGroup::ArchiveGroup(BMessage& archive) 1080 { 1081 archive.AddInt32("htab_count", fHorizontalTabs.CountItems()); 1082 archive.AddInt32("vtab_count", fVerticalTabs.CountItems()); 1083 1084 for (int i = 0; i < fWindowAreaList.CountItems(); i++) { 1085 WindowArea* area = fWindowAreaList.ItemAt(i); 1086 int32 leftTab = fVerticalTabs.IndexOf(area->LeftTab()); 1087 int32 rightTab = fVerticalTabs.IndexOf(area->RightTab()); 1088 int32 topTab = fHorizontalTabs.IndexOf(area->TopTab()); 1089 int32 bottomTab = fHorizontalTabs.IndexOf(area->BottomTab()); 1090 1091 BMessage areaMessage; 1092 areaMessage.AddInt32("left_tab", leftTab); 1093 areaMessage.AddInt32("right_tab", rightTab); 1094 areaMessage.AddInt32("top_tab", topTab); 1095 areaMessage.AddInt32("bottom_tab", bottomTab); 1096 1097 const SATWindowList& windowList = area->WindowList(); 1098 for (int a = 0; a < windowList.CountItems(); a++) 1099 areaMessage.AddInt64("window", windowList.ItemAt(a)->Id()); 1100 1101 archive.AddMessage("area", &areaMessage); 1102 } 1103 return B_OK; 1104 } 1105 1106 1107 BReference<Tab> 1108 SATGroup::_AddHorizontalTab(float position) 1109 { 1110 if (fLinearSpec == NULL) 1111 return NULL; 1112 Variable* variable = fLinearSpec->AddVariable(); 1113 if (variable == NULL) 1114 return NULL; 1115 1116 Tab* tab = new (std::nothrow)Tab(this, variable, Tab::kHorizontal); 1117 if (tab == NULL) 1118 return NULL; 1119 BReference<Tab> tabRef(tab, true); 1120 1121 if (!fHorizontalTabs.AddItem(tab)) 1122 return NULL; 1123 1124 fHorizontalTabsSorted = false; 1125 tabRef->SetPosition(position); 1126 return tabRef; 1127 } 1128 1129 1130 BReference<Tab> 1131 SATGroup::_AddVerticalTab(float position) 1132 { 1133 if (fLinearSpec == NULL) 1134 return NULL; 1135 Variable* variable = fLinearSpec->AddVariable(); 1136 if (variable == NULL) 1137 return NULL; 1138 1139 Tab* tab = new (std::nothrow)Tab(this, variable, Tab::kVertical); 1140 if (tab == NULL) 1141 return NULL; 1142 BReference<Tab> tabRef(tab, true); 1143 1144 if (!fVerticalTabs.AddItem(tab)) 1145 return NULL; 1146 1147 fVerticalTabsSorted = false; 1148 tabRef->SetPosition(position); 1149 return tabRef; 1150 } 1151 1152 1153 bool 1154 SATGroup::_RemoveHorizontalTab(Tab* tab) 1155 { 1156 if (!fHorizontalTabs.RemoveItem(tab)) 1157 return false; 1158 fHorizontalTabsSorted = false; 1159 // don't delete the tab it is reference counted 1160 return true; 1161 } 1162 1163 1164 bool 1165 SATGroup::_RemoveVerticalTab(Tab* tab) 1166 { 1167 if (!fVerticalTabs.RemoveItem(tab)) 1168 return false; 1169 fVerticalTabsSorted = false; 1170 // don't delete the tab it is reference counted 1171 return true; 1172 } 1173 1174 1175 Tab* 1176 SATGroup::_FindTab(const TabList& list, float position) 1177 { 1178 for (int i = 0; i < list.CountItems(); i++) 1179 if (fabs(list.ItemAt(i)->Position() - position) < 0.00001) 1180 return list.ItemAt(i); 1181 1182 return NULL; 1183 } 1184 1185 1186 void 1187 SATGroup::_SplitGroupIfNecessary(WindowArea* removedArea) 1188 { 1189 // if there are windows stacked in the area we don't need to split 1190 if (removedArea == NULL || removedArea->WindowList().CountItems() > 1) 1191 return; 1192 1193 WindowAreaList neighbourWindows; 1194 1195 _FillNeighbourList(neighbourWindows, removedArea); 1196 1197 bool ownGroupProcessed = false; 1198 WindowAreaList newGroup; 1199 while (_FindConnectedGroup(neighbourWindows, removedArea, newGroup)) { 1200 STRACE_SAT("Connected group found; %i window(s)\n", 1201 (int)newGroup.CountItems()); 1202 if (newGroup.CountItems() == 1 1203 && newGroup.ItemAt(0)->WindowList().CountItems() == 1) { 1204 SATWindow* window = newGroup.ItemAt(0)->WindowList().ItemAt(0); 1205 RemoveWindow(window); 1206 _EnsureGroupIsOnScreen(window->GetGroup()); 1207 } else if (ownGroupProcessed) 1208 _SpawnNewGroup(newGroup); 1209 else { 1210 _EnsureGroupIsOnScreen(this); 1211 ownGroupProcessed = true; 1212 } 1213 1214 newGroup.MakeEmpty(); 1215 } 1216 } 1217 1218 1219 void 1220 SATGroup::_FillNeighbourList(WindowAreaList& neighbourWindows, 1221 WindowArea* area) 1222 { 1223 _LeftNeighbours(neighbourWindows, area); 1224 _RightNeighbours(neighbourWindows, area); 1225 _TopNeighbours(neighbourWindows, area); 1226 _BottomNeighbours(neighbourWindows, area); 1227 } 1228 1229 1230 void 1231 SATGroup::_LeftNeighbours(WindowAreaList& neighbourWindows, WindowArea* parent) 1232 { 1233 float startPos = parent->LeftTopCrossing()->HorizontalTab()->Position(); 1234 float endPos = parent->LeftBottomCrossing()->HorizontalTab()->Position(); 1235 1236 Tab* tab = parent->LeftTopCrossing()->VerticalTab(); 1237 const CrossingList* crossingList = tab->GetCrossingList(); 1238 for (int i = 0; i < crossingList->CountItems(); i++) { 1239 Corner* corner = crossingList->ItemAt(i)->LeftTopCorner(); 1240 if (corner->status != Corner::kUsed) 1241 continue; 1242 1243 WindowArea* area = corner->windowArea; 1244 float pos1 = area->LeftTopCrossing()->HorizontalTab()->Position(); 1245 float pos2 = area->LeftBottomCrossing()->HorizontalTab()->Position(); 1246 1247 if (pos1 < endPos && pos2 > startPos) 1248 neighbourWindows.AddItem(area); 1249 1250 if (pos2 > endPos) 1251 break; 1252 } 1253 } 1254 1255 1256 void 1257 SATGroup::_TopNeighbours(WindowAreaList& neighbourWindows, WindowArea* parent) 1258 { 1259 float startPos = parent->LeftTopCrossing()->VerticalTab()->Position(); 1260 float endPos = parent->RightTopCrossing()->VerticalTab()->Position(); 1261 1262 Tab* tab = parent->LeftTopCrossing()->HorizontalTab(); 1263 const CrossingList* crossingList = tab->GetCrossingList(); 1264 for (int i = 0; i < crossingList->CountItems(); i++) { 1265 Corner* corner = crossingList->ItemAt(i)->LeftTopCorner(); 1266 if (corner->status != Corner::kUsed) 1267 continue; 1268 1269 WindowArea* area = corner->windowArea; 1270 float pos1 = area->LeftTopCrossing()->VerticalTab()->Position(); 1271 float pos2 = area->RightTopCrossing()->VerticalTab()->Position(); 1272 1273 if (pos1 < endPos && pos2 > startPos) 1274 neighbourWindows.AddItem(area); 1275 1276 if (pos2 > endPos) 1277 break; 1278 } 1279 } 1280 1281 1282 void 1283 SATGroup::_RightNeighbours(WindowAreaList& neighbourWindows, WindowArea* parent) 1284 { 1285 float startPos = parent->RightTopCrossing()->HorizontalTab()->Position(); 1286 float endPos = parent->RightBottomCrossing()->HorizontalTab()->Position(); 1287 1288 Tab* tab = parent->RightTopCrossing()->VerticalTab(); 1289 const CrossingList* crossingList = tab->GetCrossingList(); 1290 for (int i = 0; i < crossingList->CountItems(); i++) { 1291 Corner* corner = crossingList->ItemAt(i)->RightTopCorner(); 1292 if (corner->status != Corner::kUsed) 1293 continue; 1294 1295 WindowArea* area = corner->windowArea; 1296 float pos1 = area->RightTopCrossing()->HorizontalTab()->Position(); 1297 float pos2 = area->RightBottomCrossing()->HorizontalTab()->Position(); 1298 1299 if (pos1 < endPos && pos2 > startPos) 1300 neighbourWindows.AddItem(area); 1301 1302 if (pos2 > endPos) 1303 break; 1304 } 1305 } 1306 1307 1308 void 1309 SATGroup::_BottomNeighbours(WindowAreaList& neighbourWindows, 1310 WindowArea* parent) 1311 { 1312 float startPos = parent->LeftBottomCrossing()->VerticalTab()->Position(); 1313 float endPos = parent->RightBottomCrossing()->VerticalTab()->Position(); 1314 1315 Tab* tab = parent->LeftBottomCrossing()->HorizontalTab(); 1316 const CrossingList* crossingList = tab->GetCrossingList(); 1317 for (int i = 0; i < crossingList->CountItems(); i++) { 1318 Corner* corner = crossingList->ItemAt(i)->LeftBottomCorner(); 1319 if (corner->status != Corner::kUsed) 1320 continue; 1321 1322 WindowArea* area = corner->windowArea; 1323 float pos1 = area->LeftBottomCrossing()->VerticalTab()->Position(); 1324 float pos2 = area->RightBottomCrossing()->VerticalTab()->Position(); 1325 1326 if (pos1 < endPos && pos2 > startPos) 1327 neighbourWindows.AddItem(area); 1328 1329 if (pos2 > endPos) 1330 break; 1331 } 1332 } 1333 1334 1335 bool 1336 SATGroup::_FindConnectedGroup(WindowAreaList& seedList, WindowArea* removedArea, 1337 WindowAreaList& newGroup) 1338 { 1339 if (seedList.CountItems() == 0) 1340 return false; 1341 1342 WindowArea* area = seedList.RemoveItemAt(0); 1343 newGroup.AddItem(area); 1344 1345 _FollowSeed(area, removedArea, seedList, newGroup); 1346 return true; 1347 } 1348 1349 1350 void 1351 SATGroup::_FollowSeed(WindowArea* area, WindowArea* veto, 1352 WindowAreaList& seedList, WindowAreaList& newGroup) 1353 { 1354 WindowAreaList neighbours; 1355 _FillNeighbourList(neighbours, area); 1356 for (int i = 0; i < neighbours.CountItems(); i++) { 1357 WindowArea* currentArea = neighbours.ItemAt(i); 1358 if (currentArea != veto && !newGroup.HasItem(currentArea)) { 1359 newGroup.AddItem(currentArea); 1360 // if we get a area from the seed list it is not a seed any more 1361 seedList.RemoveItem(currentArea); 1362 } else { 1363 // don't _FollowSeed of invalid areas 1364 neighbours.RemoveItemAt(i); 1365 i--; 1366 } 1367 } 1368 1369 for (int i = 0; i < neighbours.CountItems(); i++) 1370 _FollowSeed(neighbours.ItemAt(i), veto, seedList, newGroup); 1371 } 1372 1373 1374 void 1375 SATGroup::_SpawnNewGroup(const WindowAreaList& newGroup) 1376 { 1377 STRACE_SAT("SATGroup::_SpawnNewGroup\n"); 1378 SATGroup* group = new (std::nothrow)SATGroup; 1379 if (group == NULL) 1380 return; 1381 BReference<SATGroup> groupRef; 1382 groupRef.SetTo(group, true); 1383 1384 for (int i = 0; i < newGroup.CountItems(); i++) 1385 newGroup.ItemAt(i)->PropagateToGroup(group); 1386 1387 _EnsureGroupIsOnScreen(group); 1388 } 1389 1390 1391 const float kMinOverlap = 50; 1392 const float kMoveToScreen = 75; 1393 1394 1395 void 1396 SATGroup::_EnsureGroupIsOnScreen(SATGroup* group) 1397 { 1398 STRACE_SAT("SATGroup::_EnsureGroupIsOnScreen\n"); 1399 if (group == NULL || group->CountItems() < 1) 1400 return; 1401 1402 SATWindow* window = group->WindowAt(0); 1403 Desktop* desktop = window->GetWindow()->Desktop(); 1404 if (desktop == NULL) 1405 return; 1406 1407 const float kBigDistance = 1E+10; 1408 1409 float minLeftDistance = kBigDistance; 1410 BRect leftRect; 1411 float minTopDistance = kBigDistance; 1412 BRect topRect; 1413 float minRightDistance = kBigDistance; 1414 BRect rightRect; 1415 float minBottomDistance = kBigDistance; 1416 BRect bottomRect; 1417 1418 BRect screen = window->GetWindow()->Screen()->Frame(); 1419 BRect reducedScreen = screen; 1420 reducedScreen.InsetBy(kMinOverlap, kMinOverlap); 1421 1422 for (int i = 0; i < group->CountItems(); i++) { 1423 SATWindow* window = group->WindowAt(i); 1424 BRect frame = window->CompleteWindowFrame(); 1425 if (reducedScreen.Intersects(frame)) 1426 return; 1427 1428 if (frame.right < screen.left + kMinOverlap) { 1429 float dist = fabs(screen.left - frame.right); 1430 if (dist < minLeftDistance) { 1431 minLeftDistance = dist; 1432 leftRect = frame; 1433 } else if (dist == minLeftDistance) 1434 leftRect = leftRect | frame; 1435 } 1436 if (frame.top > screen.bottom - kMinOverlap) { 1437 float dist = fabs(frame.top - screen.bottom); 1438 if (dist < minBottomDistance) { 1439 minBottomDistance = dist; 1440 bottomRect = frame; 1441 } else if (dist == minBottomDistance) 1442 bottomRect = bottomRect | frame; 1443 } 1444 if (frame.left > screen.right - kMinOverlap) { 1445 float dist = fabs(frame.left - screen.right); 1446 if (dist < minRightDistance) { 1447 minRightDistance = dist; 1448 rightRect = frame; 1449 } else if (dist == minRightDistance) 1450 rightRect = rightRect | frame; 1451 } 1452 if (frame.bottom < screen.top + kMinOverlap) { 1453 float dist = fabs(frame.bottom - screen.top); 1454 if (dist < minTopDistance) { 1455 minTopDistance = dist; 1456 topRect = frame; 1457 } else if (dist == minTopDistance) 1458 topRect = topRect | frame; 1459 } 1460 } 1461 1462 BPoint offset; 1463 if (minLeftDistance < kBigDistance) { 1464 offset.x = screen.left - leftRect.right + kMoveToScreen; 1465 _CallculateYOffset(offset, leftRect, screen); 1466 } else if (minTopDistance < kBigDistance) { 1467 offset.y = screen.top - topRect.bottom + kMoveToScreen; 1468 _CallculateXOffset(offset, topRect, screen); 1469 } else if (minRightDistance < kBigDistance) { 1470 offset.x = screen.right - rightRect.left - kMoveToScreen; 1471 _CallculateYOffset(offset, rightRect, screen); 1472 } else if (minBottomDistance < kBigDistance) { 1473 offset.y = screen.bottom - bottomRect.top - kMoveToScreen; 1474 _CallculateXOffset(offset, bottomRect, screen); 1475 } 1476 1477 if (offset.x == 0. && offset.y == 0.) 1478 return; 1479 STRACE_SAT("move group back to screen: offset x: %f offset y: %f\n", 1480 offset.x, offset.y); 1481 1482 desktop->MoveWindowBy(window->GetWindow(), offset.x, offset.y); 1483 window->DoGroupLayout(); 1484 } 1485 1486 1487 void 1488 SATGroup::_CallculateXOffset(BPoint& offset, BRect& frame, BRect& screen) 1489 { 1490 if (frame.right < screen.left + kMinOverlap) 1491 offset.x = screen.left - frame.right + kMoveToScreen; 1492 else if (frame.left > screen.right - kMinOverlap) 1493 offset.x = screen.right - frame.left - kMoveToScreen; 1494 } 1495 1496 1497 void 1498 SATGroup::_CallculateYOffset(BPoint& offset, BRect& frame, BRect& screen) 1499 { 1500 if (frame.top > screen.bottom - kMinOverlap) 1501 offset.y = screen.bottom - frame.top - kMoveToScreen; 1502 else if (frame.bottom < screen.top + kMinOverlap) 1503 offset.y = screen.top - frame.bottom + kMoveToScreen; 1504 } 1505