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 LinearSpec* linearSpec = fGroup->GetLinearSpec(); 381 382 linearSpec->RemoveConstraint(fMinWidthConstraint, true); 383 linearSpec->RemoveConstraint(fMinHeightConstraint, true); 384 linearSpec->RemoveConstraint(fMaxWidthConstraint, true); 385 linearSpec->RemoveConstraint(fMaxHeightConstraint, true); 386 linearSpec->RemoveConstraint(fWidthConstraint, true); 387 linearSpec->RemoveConstraint(fHeightConstraint, true); 388 389 fMinWidthConstraint = NULL; 390 fMinHeightConstraint = NULL; 391 fMaxWidthConstraint = NULL; 392 fMaxHeightConstraint = NULL; 393 fWidthConstraint = NULL; 394 fHeightConstraint = NULL; 395 } 396 397 398 BReference<Crossing> 399 WindowArea::_CrossingByPosition(Crossing* crossing, SATGroup* group) 400 { 401 BReference<Crossing> crossRef = NULL; 402 403 Tab* oldHTab = crossing->HorizontalTab(); 404 BReference<Tab> hTab = group->FindHorizontalTab(oldHTab->Position()); 405 if (!hTab) 406 hTab = group->_AddHorizontalTab(oldHTab->Position()); 407 if (!hTab) 408 return crossRef; 409 410 Tab* oldVTab = crossing->VerticalTab(); 411 crossRef = hTab->FindCrossing(oldVTab->Position()); 412 if (crossRef) 413 return crossRef; 414 415 BReference<Tab> vTab = group->FindVerticalTab(oldVTab->Position()); 416 if (!vTab) 417 vTab = group->_AddVerticalTab(oldVTab->Position()); 418 if (!vTab) 419 return crossRef; 420 421 return hTab->AddCrossing(vTab); 422 } 423 424 425 void 426 WindowArea::_InitCorners() 427 { 428 _SetToWindowCorner(fLeftTopCrossing->RightBottomCorner()); 429 _SetToNeighbourCorner(fLeftTopCrossing->LeftBottomCorner()); 430 _SetToNeighbourCorner(fLeftTopCrossing->RightTopCorner()); 431 432 _SetToWindowCorner(fRightTopCrossing->LeftBottomCorner()); 433 _SetToNeighbourCorner(fRightTopCrossing->LeftTopCorner()); 434 _SetToNeighbourCorner(fRightTopCrossing->RightBottomCorner()); 435 436 _SetToWindowCorner(fLeftBottomCrossing->RightTopCorner()); 437 _SetToNeighbourCorner(fLeftBottomCrossing->LeftTopCorner()); 438 _SetToNeighbourCorner(fLeftBottomCrossing->RightBottomCorner()); 439 440 _SetToWindowCorner(fRightBottomCrossing->LeftTopCorner()); 441 _SetToNeighbourCorner(fRightBottomCrossing->LeftBottomCorner()); 442 _SetToNeighbourCorner(fRightBottomCrossing->RightTopCorner()); 443 } 444 445 446 void 447 WindowArea::_CleanupCorners() 448 { 449 _UnsetWindowCorner(fLeftTopCrossing->RightBottomCorner()); 450 _UnsetNeighbourCorner(fLeftTopCrossing->LeftBottomCorner(), 451 fLeftBottomCrossing->LeftTopCorner()); 452 _UnsetNeighbourCorner(fLeftTopCrossing->RightTopCorner(), 453 fLeftBottomCrossing->LeftTopCorner()); 454 455 _UnsetWindowCorner(fRightTopCrossing->LeftBottomCorner()); 456 _UnsetNeighbourCorner(fRightTopCrossing->LeftTopCorner(), 457 fLeftBottomCrossing->RightTopCorner()); 458 _UnsetNeighbourCorner(fRightTopCrossing->RightBottomCorner(), 459 fLeftBottomCrossing->RightTopCorner()); 460 461 _UnsetWindowCorner(fLeftBottomCrossing->RightTopCorner()); 462 _UnsetNeighbourCorner(fLeftBottomCrossing->LeftTopCorner(), 463 fLeftBottomCrossing->LeftBottomCorner()); 464 _UnsetNeighbourCorner(fLeftBottomCrossing->RightBottomCorner(), 465 fLeftBottomCrossing->LeftBottomCorner()); 466 467 _UnsetWindowCorner(fRightBottomCrossing->LeftTopCorner()); 468 _UnsetNeighbourCorner(fRightBottomCrossing->LeftBottomCorner(), 469 fRightBottomCrossing->RightBottomCorner()); 470 _UnsetNeighbourCorner(fRightBottomCrossing->RightTopCorner(), 471 fRightBottomCrossing->RightBottomCorner()); 472 } 473 474 475 void 476 WindowArea::_SetToWindowCorner(Corner* corner) 477 { 478 corner->status = Corner::kUsed; 479 corner->windowArea = this; 480 } 481 482 483 void 484 WindowArea::_SetToNeighbourCorner(Corner* neighbour) 485 { 486 if (neighbour->status == Corner::kNotDockable) 487 neighbour->status = Corner::kFree; 488 } 489 490 491 void 492 WindowArea::_UnsetWindowCorner(Corner* corner) 493 { 494 corner->status = Corner::kFree; 495 corner->windowArea = NULL; 496 } 497 498 499 void 500 WindowArea::_UnsetNeighbourCorner(Corner* neighbour, Corner* opponent) 501 { 502 if (neighbour->status == Corner::kFree && opponent->status != Corner::kUsed) 503 neighbour->status = Corner::kNotDockable; 504 } 505 506 507 void 508 WindowArea::_MoveToSAT(SATWindow* triggerWindow) 509 { 510 SATWindow* topWindow = TopWindow(); 511 // if there is no window in the group we are done 512 if (topWindow == NULL) 513 return; 514 515 BRect frameSAT(LeftVar()->Value() - kMakePositiveOffset, 516 TopVar()->Value() - kMakePositiveOffset, 517 RightVar()->Value() - kMakePositiveOffset, 518 BottomVar()->Value() - kMakePositiveOffset); 519 topWindow->AdjustSizeLimits(frameSAT); 520 521 BRect frame = topWindow->CompleteWindowFrame(); 522 float deltaToX = round(frameSAT.left - frame.left); 523 float deltaToY = round(frameSAT.top - frame.top); 524 frame.OffsetBy(deltaToX, deltaToY); 525 float deltaByX = round(frameSAT.right - frame.right); 526 float deltaByY = round(frameSAT.bottom - frame.bottom); 527 528 int32 workspace = triggerWindow->GetWindow()->CurrentWorkspace(); 529 Desktop* desktop = triggerWindow->GetWindow()->Desktop(); 530 desktop->MoveWindowBy(topWindow->GetWindow(), deltaToX, deltaToY, 531 workspace); 532 // Update frame to the new position 533 desktop->ResizeWindowBy(topWindow->GetWindow(), deltaByX, deltaByY); 534 535 UpdateSizeConstaints(frameSAT); 536 } 537 538 539 Corner::Corner() 540 : 541 status(kNotDockable), 542 windowArea(NULL) 543 { 544 545 } 546 547 548 void 549 Corner::Trace() const 550 { 551 switch (status) { 552 case kFree: 553 debug_printf("free corner\n"); 554 break; 555 556 case kUsed: 557 { 558 debug_printf("attached windows:\n"); 559 const SATWindowList& list = windowArea->WindowList(); 560 for (int i = 0; i < list.CountItems(); i++) { 561 debug_printf("- %s\n", list.ItemAt(i)->GetWindow()->Title()); 562 } 563 break; 564 } 565 566 case kNotDockable: 567 debug_printf("not dockable\n"); 568 break; 569 }; 570 } 571 572 573 Crossing::Crossing(Tab* vertical, Tab* horizontal) 574 : 575 fVerticalTab(vertical), 576 fHorizontalTab(horizontal) 577 { 578 } 579 580 581 Crossing::~Crossing() 582 { 583 fVerticalTab->RemoveCrossing(this); 584 fHorizontalTab->RemoveCrossing(this); 585 } 586 587 588 Corner* 589 Crossing::GetCorner(Corner::position_t corner) const 590 { 591 return &const_cast<Corner*>(fCorners)[corner]; 592 } 593 594 595 Corner* 596 Crossing::GetOppositeCorner(Corner::position_t corner) const 597 { 598 return &const_cast<Corner*>(fCorners)[3 - corner]; 599 } 600 601 602 Tab* 603 Crossing::VerticalTab() const 604 { 605 return fVerticalTab; 606 } 607 608 609 Tab* 610 Crossing::HorizontalTab() const 611 { 612 return fHorizontalTab; 613 } 614 615 616 void 617 Crossing::Trace() const 618 { 619 debug_printf("left-top corner: "); 620 fCorners[Corner::kLeftTop].Trace(); 621 debug_printf("right-top corner: "); 622 fCorners[Corner::kRightTop].Trace(); 623 debug_printf("left-bottom corner: "); 624 fCorners[Corner::kLeftBottom].Trace(); 625 debug_printf("right-bottom corner: "); 626 fCorners[Corner::kRightBottom].Trace(); 627 } 628 629 630 Tab::Tab(SATGroup* group, Variable* variable, orientation_t orientation) 631 : 632 fGroup(group), 633 fVariable(variable), 634 fOrientation(orientation) 635 { 636 637 } 638 639 640 Tab::~Tab() 641 { 642 if (fOrientation == kVertical) 643 fGroup->_RemoveVerticalTab(this); 644 else 645 fGroup->_RemoveHorizontalTab(this); 646 647 delete fVariable; 648 } 649 650 651 float 652 Tab::Position() const 653 { 654 return (float)fVariable->Value() - kMakePositiveOffset; 655 } 656 657 658 void 659 Tab::SetPosition(float position) 660 { 661 fVariable->SetValue(position + kMakePositiveOffset); 662 } 663 664 665 Tab::orientation_t 666 Tab::Orientation() const 667 { 668 return fOrientation; 669 } 670 671 672 Constraint* 673 Tab::Connect(Variable* variable) 674 { 675 return fVariable->IsEqual(variable); 676 } 677 678 679 BReference<Crossing> 680 Tab::AddCrossing(Tab* tab) 681 { 682 if (tab->Orientation() == fOrientation) 683 return NULL; 684 685 Tab* vTab = (fOrientation == kVertical) ? this : tab; 686 Tab* hTab = (fOrientation == kHorizontal) ? this : tab; 687 688 Crossing* crossing = new (std::nothrow)Crossing(vTab, hTab); 689 if (!crossing) 690 return NULL; 691 692 if (!fCrossingList.AddItem(crossing)) { 693 return NULL; 694 } 695 if (!tab->fCrossingList.AddItem(crossing)) { 696 fCrossingList.RemoveItem(crossing); 697 return NULL; 698 } 699 700 BReference<Crossing> crossingRef(crossing, true); 701 return crossingRef; 702 } 703 704 705 bool 706 Tab::RemoveCrossing(Crossing* crossing) 707 { 708 Tab* vTab = crossing->VerticalTab(); 709 Tab* hTab = crossing->HorizontalTab(); 710 711 if (vTab != this && hTab != this) 712 return false; 713 fCrossingList.RemoveItem(crossing); 714 715 return true; 716 } 717 718 719 int32 720 Tab::FindCrossingIndex(Tab* tab) 721 { 722 if (fOrientation == kVertical) { 723 for (int32 i = 0; i < fCrossingList.CountItems(); i++) { 724 if (fCrossingList.ItemAt(i)->HorizontalTab() == tab) 725 return i; 726 } 727 } else { 728 for (int32 i = 0; i < fCrossingList.CountItems(); i++) { 729 if (fCrossingList.ItemAt(i)->VerticalTab() == tab) 730 return i; 731 } 732 } 733 return -1; 734 } 735 736 737 int32 738 Tab::FindCrossingIndex(float pos) 739 { 740 if (fOrientation == kVertical) { 741 for (int32 i = 0; i < fCrossingList.CountItems(); i++) { 742 if (fabs(fCrossingList.ItemAt(i)->HorizontalTab()->Position() - pos) 743 < 0.0001) 744 return i; 745 } 746 } else { 747 for (int32 i = 0; i < fCrossingList.CountItems(); i++) { 748 if (fabs(fCrossingList.ItemAt(i)->VerticalTab()->Position() - pos) 749 < 0.0001) 750 return i; 751 } 752 } 753 return -1; 754 } 755 756 757 Crossing* 758 Tab::FindCrossing(Tab* tab) 759 { 760 return fCrossingList.ItemAt(FindCrossingIndex(tab)); 761 } 762 763 764 Crossing* 765 Tab::FindCrossing(float tabPosition) 766 { 767 return fCrossingList.ItemAt(FindCrossingIndex(tabPosition)); 768 } 769 770 771 const CrossingList* 772 Tab::GetCrossingList() const 773 { 774 return &fCrossingList; 775 } 776 777 778 int 779 Tab::CompareFunction(const Tab* tab1, const Tab* tab2) 780 { 781 if (tab1->Position() < tab2->Position()) 782 return -1; 783 784 return 1; 785 } 786 787 788 SATGroup::SATGroup() 789 : 790 fHorizontalTabsSorted(false), 791 fVerticalTabsSorted(false), 792 fActiveWindow(NULL) 793 { 794 } 795 796 797 SATGroup::~SATGroup() 798 { 799 // Should be empty 800 //while (fSATWindowList.CountItems() > 0) 801 // RemoveWindow(fSATWindowList.ItemAt(0)); 802 } 803 804 805 bool 806 SATGroup::AddWindow(SATWindow* window, Tab* left, Tab* top, Tab* right, 807 Tab* bottom) 808 { 809 STRACE_SAT("SATGroup::AddWindow\n"); 810 811 // first check if we have to create tabs and missing corners. 812 BReference<Tab> leftRef, rightRef, topRef, bottomRef; 813 BReference<Crossing> leftTopRef, rightTopRef, leftBottomRef, rightBottomRef; 814 815 if (left && top) 816 leftTopRef = left->FindCrossing(top); 817 if (right && top) 818 rightTopRef = right->FindCrossing(top); 819 if (left && bottom) 820 leftBottomRef = left->FindCrossing(bottom); 821 if (right && bottom) 822 rightBottomRef = right->FindCrossing(bottom); 823 824 if (!left) { 825 leftRef = _AddVerticalTab(); 826 left = leftRef.Get(); 827 } 828 if (!top) { 829 topRef = _AddHorizontalTab(); 830 top = topRef.Get(); 831 } 832 if (!right) { 833 rightRef = _AddVerticalTab(); 834 right = rightRef.Get(); 835 } 836 if (!bottom) { 837 bottomRef = _AddHorizontalTab(); 838 bottom = bottomRef.Get(); 839 } 840 if (!left || !top || !right || !bottom) 841 return false; 842 843 if (!leftTopRef) { 844 leftTopRef = left->AddCrossing(top); 845 if (!leftTopRef) 846 return false; 847 } 848 if (!rightTopRef) { 849 rightTopRef = right->AddCrossing(top); 850 if (!rightTopRef) 851 return false; 852 } 853 if (!leftBottomRef) { 854 leftBottomRef = left->AddCrossing(bottom); 855 if (!leftBottomRef) 856 return false; 857 } 858 if (!rightBottomRef) { 859 rightBottomRef = right->AddCrossing(bottom); 860 if (!rightBottomRef) 861 return false; 862 } 863 864 WindowArea* area = new(std::nothrow) WindowArea(leftTopRef, rightTopRef, 865 leftBottomRef, rightBottomRef); 866 if (!area) 867 return false; 868 // the area register itself in our area list 869 if (area->Init(this) == false) { 870 delete area; 871 return false; 872 } 873 // delete the area if AddWindow failed / release our reference on it 874 BReference<WindowArea> areaRef(area, true); 875 876 return AddWindow(window, area); 877 } 878 879 880 bool 881 SATGroup::AddWindow(SATWindow* window, WindowArea* area, SATWindow* after) 882 { 883 if (!area->_AddWindow(window, after)) 884 return false; 885 886 if (!fSATWindowList.AddItem(window)) { 887 area->_RemoveWindow(window); 888 return false; 889 } 890 891 if (!window->AddedToGroup(this, area)) { 892 area->_RemoveWindow(window); 893 fSATWindowList.RemoveItem(window); 894 return false; 895 } 896 897 return true; 898 } 899 900 901 bool 902 SATGroup::RemoveWindow(SATWindow* window, bool stayBelowMouse) 903 { 904 if (!fSATWindowList.RemoveItem(window)) 905 return false; 906 907 // We need the area a little bit longer because the area could hold the 908 // last reference to the group. 909 BReference<WindowArea> area = window->GetWindowArea(); 910 if (area.Get() != NULL) 911 area->_RemoveWindow(window); 912 913 window->RemovedFromGroup(this, stayBelowMouse); 914 915 if (CountItems() >= 2) 916 WindowAt(0)->DoGroupLayout(); 917 918 return true; 919 } 920 921 922 int32 923 SATGroup::CountItems() 924 { 925 return fSATWindowList.CountItems(); 926 }; 927 928 929 SATWindow* 930 SATGroup::WindowAt(int32 index) 931 { 932 return fSATWindowList.ItemAt(index); 933 } 934 935 936 SATWindow* 937 SATGroup::ActiveWindow() const 938 { 939 return fActiveWindow; 940 } 941 942 943 void 944 SATGroup::SetActiveWindow(SATWindow* window) 945 { 946 fActiveWindow = window; 947 } 948 949 950 const TabList* 951 SATGroup::HorizontalTabs() 952 { 953 if (!fHorizontalTabsSorted) { 954 fHorizontalTabs.SortItems(Tab::CompareFunction); 955 fHorizontalTabsSorted = true; 956 } 957 return &fHorizontalTabs; 958 } 959 960 961 const TabList* 962 SATGroup::VerticalTabs() 963 { 964 if (!fVerticalTabsSorted) { 965 fVerticalTabs.SortItems(Tab::CompareFunction); 966 fVerticalTabsSorted = true; 967 } 968 return &fVerticalTabs; 969 } 970 971 972 Tab* 973 SATGroup::FindHorizontalTab(float position) 974 { 975 return _FindTab(fHorizontalTabs, position); 976 } 977 978 979 Tab* 980 SATGroup::FindVerticalTab(float position) 981 { 982 return _FindTab(fVerticalTabs, position); 983 } 984 985 986 void 987 SATGroup::WindowAreaRemoved(WindowArea* area) 988 { 989 _SplitGroupIfNecessary(area); 990 } 991 992 993 status_t 994 SATGroup::RestoreGroup(const BMessage& archive, StackAndTile* sat) 995 { 996 // create new group 997 SATGroup* group = new (std::nothrow)SATGroup; 998 if (!group) 999 return B_NO_MEMORY; 1000 BReference<SATGroup> groupRef; 1001 groupRef.SetTo(group, true); 1002 1003 int32 nHTabs, nVTabs; 1004 status_t status; 1005 status = archive.FindInt32("htab_count", &nHTabs); 1006 if (status != B_OK) 1007 return status; 1008 status = archive.FindInt32("vtab_count", &nVTabs); 1009 if (status != B_OK) 1010 return status; 1011 1012 vector<BReference<Tab> > tempHTabs; 1013 for (int i = 0; i < nHTabs; i++) { 1014 BReference<Tab> tab = group->_AddHorizontalTab(); 1015 if (!tab) 1016 return B_NO_MEMORY; 1017 tempHTabs.push_back(tab); 1018 } 1019 vector<BReference<Tab> > tempVTabs; 1020 for (int i = 0; i < nVTabs; i++) { 1021 BReference<Tab> tab = group->_AddVerticalTab(); 1022 if (!tab) 1023 return B_NO_MEMORY; 1024 tempVTabs.push_back(tab); 1025 } 1026 1027 BMessage areaArchive; 1028 for (int32 i = 0; archive.FindMessage("area", i, &areaArchive) == B_OK; 1029 i++) { 1030 uint32 leftTab, rightTab, topTab, bottomTab; 1031 if (areaArchive.FindInt32("left_tab", (int32*)&leftTab) != B_OK 1032 || areaArchive.FindInt32("right_tab", (int32*)&rightTab) != B_OK 1033 || areaArchive.FindInt32("top_tab", (int32*)&topTab) != B_OK 1034 || areaArchive.FindInt32("bottom_tab", (int32*)&bottomTab) != B_OK) 1035 return B_ERROR; 1036 1037 if (leftTab >= tempVTabs.size() || rightTab >= tempVTabs.size()) 1038 return B_BAD_VALUE; 1039 if (topTab >= tempHTabs.size() || bottomTab >= tempHTabs.size()) 1040 return B_BAD_VALUE; 1041 1042 Tab* left = tempVTabs[leftTab]; 1043 Tab* right = tempVTabs[rightTab]; 1044 Tab* top = tempHTabs[topTab]; 1045 Tab* bottom = tempHTabs[bottomTab]; 1046 1047 // adding windows to area 1048 uint64 windowId; 1049 SATWindow* prevWindow = NULL; 1050 for (int32 i = 0; areaArchive.FindInt64("window", i, 1051 (int64*)&windowId) == B_OK; i++) { 1052 SATWindow* window = sat->FindSATWindow(windowId); 1053 if (!window) 1054 continue; 1055 1056 if (prevWindow == NULL) { 1057 if (!group->AddWindow(window, left, top, right, bottom)) 1058 continue; 1059 prevWindow = window; 1060 } else { 1061 if (!prevWindow->StackWindow(window)) 1062 continue; 1063 prevWindow = window; 1064 } 1065 } 1066 } 1067 return B_OK; 1068 } 1069 1070 1071 status_t 1072 SATGroup::ArchiveGroup(BMessage& archive) 1073 { 1074 archive.AddInt32("htab_count", fHorizontalTabs.CountItems()); 1075 archive.AddInt32("vtab_count", fVerticalTabs.CountItems()); 1076 1077 for (int i = 0; i < fWindowAreaList.CountItems(); i++) { 1078 WindowArea* area = fWindowAreaList.ItemAt(i); 1079 int32 leftTab = fVerticalTabs.IndexOf(area->LeftTab()); 1080 int32 rightTab = fVerticalTabs.IndexOf(area->RightTab()); 1081 int32 topTab = fHorizontalTabs.IndexOf(area->TopTab()); 1082 int32 bottomTab = fHorizontalTabs.IndexOf(area->BottomTab()); 1083 1084 BMessage areaMessage; 1085 areaMessage.AddInt32("left_tab", leftTab); 1086 areaMessage.AddInt32("right_tab", rightTab); 1087 areaMessage.AddInt32("top_tab", topTab); 1088 areaMessage.AddInt32("bottom_tab", bottomTab); 1089 1090 const SATWindowList& windowList = area->WindowList(); 1091 for (int a = 0; a < windowList.CountItems(); a++) 1092 areaMessage.AddInt64("window", windowList.ItemAt(a)->Id()); 1093 1094 archive.AddMessage("area", &areaMessage); 1095 } 1096 return B_OK; 1097 } 1098 1099 1100 BReference<Tab> 1101 SATGroup::_AddHorizontalTab(float position) 1102 { 1103 Variable* variable = fLinearSpec.AddVariable(); 1104 if (!variable) 1105 return NULL; 1106 1107 Tab* tab = new (std::nothrow)Tab(this, variable, Tab::kHorizontal); 1108 if (!tab) 1109 return NULL; 1110 BReference<Tab> tabRef(tab, true); 1111 1112 if (!fHorizontalTabs.AddItem(tab)) 1113 return NULL; 1114 1115 fHorizontalTabsSorted = false; 1116 tabRef->SetPosition(position); 1117 return tabRef; 1118 } 1119 1120 1121 BReference<Tab> 1122 SATGroup::_AddVerticalTab(float position) 1123 { 1124 Variable* variable = fLinearSpec.AddVariable(); 1125 if (!variable) 1126 return NULL; 1127 1128 Tab* tab = new (std::nothrow)Tab(this, variable, Tab::kVertical); 1129 if (!tab) 1130 return NULL; 1131 BReference<Tab> tabRef(tab, true); 1132 1133 if (!fVerticalTabs.AddItem(tab)) 1134 return NULL; 1135 1136 fVerticalTabsSorted = false; 1137 tabRef->SetPosition(position); 1138 return tabRef; 1139 } 1140 1141 1142 bool 1143 SATGroup::_RemoveHorizontalTab(Tab* tab) 1144 { 1145 if (!fHorizontalTabs.RemoveItem(tab)) 1146 return false; 1147 fHorizontalTabsSorted = false; 1148 // don't delete the tab it is reference counted 1149 return true; 1150 } 1151 1152 1153 bool 1154 SATGroup::_RemoveVerticalTab(Tab* tab) 1155 { 1156 if (!fVerticalTabs.RemoveItem(tab)) 1157 return false; 1158 fVerticalTabsSorted = false; 1159 // don't delete the tab it is reference counted 1160 return true; 1161 } 1162 1163 1164 Tab* 1165 SATGroup::_FindTab(const TabList& list, float position) 1166 { 1167 for (int i = 0; i < list.CountItems(); i++) 1168 if (fabs(list.ItemAt(i)->Position() - position) < 0.00001) 1169 return list.ItemAt(i); 1170 1171 return NULL; 1172 } 1173 1174 1175 void 1176 SATGroup::_SplitGroupIfNecessary(WindowArea* removedArea) 1177 { 1178 // if there are windows stacked in the area we don't need to split 1179 if (!removedArea || removedArea->WindowList().CountItems() > 1) 1180 return; 1181 1182 WindowAreaList neighbourWindows; 1183 1184 _FillNeighbourList(neighbourWindows, removedArea); 1185 1186 bool ownGroupProcessed = false; 1187 WindowAreaList newGroup; 1188 while (_FindConnectedGroup(neighbourWindows, removedArea, newGroup)) { 1189 STRACE_SAT("Connected group found; %i window(s)\n", 1190 (int)newGroup.CountItems()); 1191 if (newGroup.CountItems() == 1 1192 && newGroup.ItemAt(0)->WindowList().CountItems() == 1) { 1193 SATWindow* window = newGroup.ItemAt(0)->WindowList().ItemAt(0); 1194 RemoveWindow(window); 1195 _EnsureGroupIsOnScreen(window->GetGroup()); 1196 } else if (ownGroupProcessed) 1197 _SpawnNewGroup(newGroup); 1198 else { 1199 _EnsureGroupIsOnScreen(this); 1200 ownGroupProcessed = true; 1201 } 1202 1203 newGroup.MakeEmpty(); 1204 } 1205 } 1206 1207 1208 void 1209 SATGroup::_FillNeighbourList(WindowAreaList& neighbourWindows, 1210 WindowArea* area) 1211 { 1212 _LeftNeighbours(neighbourWindows, area); 1213 _RightNeighbours(neighbourWindows, area); 1214 _TopNeighbours(neighbourWindows, area); 1215 _BottomNeighbours(neighbourWindows, area); 1216 } 1217 1218 1219 void 1220 SATGroup::_LeftNeighbours(WindowAreaList& neighbourWindows, WindowArea* parent) 1221 { 1222 float startPos = parent->LeftTopCrossing()->HorizontalTab()->Position(); 1223 float endPos = parent->LeftBottomCrossing()->HorizontalTab()->Position(); 1224 1225 Tab* tab = parent->LeftTopCrossing()->VerticalTab(); 1226 const CrossingList* crossingList = tab->GetCrossingList(); 1227 for (int i = 0; i < crossingList->CountItems(); i++) { 1228 Corner* corner = crossingList->ItemAt(i)->LeftTopCorner(); 1229 if (corner->status != Corner::kUsed) 1230 continue; 1231 1232 WindowArea* area = corner->windowArea; 1233 float pos1 = area->LeftTopCrossing()->HorizontalTab()->Position(); 1234 float pos2 = area->LeftBottomCrossing()->HorizontalTab()->Position(); 1235 1236 if (pos1 < endPos && pos2 > startPos) 1237 neighbourWindows.AddItem(area); 1238 1239 if (pos2 > endPos) 1240 break; 1241 } 1242 } 1243 1244 1245 void 1246 SATGroup::_TopNeighbours(WindowAreaList& neighbourWindows, WindowArea* parent) 1247 { 1248 float startPos = parent->LeftTopCrossing()->VerticalTab()->Position(); 1249 float endPos = parent->RightTopCrossing()->VerticalTab()->Position(); 1250 1251 Tab* tab = parent->LeftTopCrossing()->HorizontalTab(); 1252 const CrossingList* crossingList = tab->GetCrossingList(); 1253 for (int i = 0; i < crossingList->CountItems(); i++) { 1254 Corner* corner = crossingList->ItemAt(i)->LeftTopCorner(); 1255 if (corner->status != Corner::kUsed) 1256 continue; 1257 1258 WindowArea* area = corner->windowArea; 1259 float pos1 = area->LeftTopCrossing()->VerticalTab()->Position(); 1260 float pos2 = area->RightTopCrossing()->VerticalTab()->Position(); 1261 1262 if (pos1 < endPos && pos2 > startPos) 1263 neighbourWindows.AddItem(area); 1264 1265 if (pos2 > endPos) 1266 break; 1267 } 1268 } 1269 1270 1271 void 1272 SATGroup::_RightNeighbours(WindowAreaList& neighbourWindows, WindowArea* parent) 1273 { 1274 float startPos = parent->RightTopCrossing()->HorizontalTab()->Position(); 1275 float endPos = parent->RightBottomCrossing()->HorizontalTab()->Position(); 1276 1277 Tab* tab = parent->RightTopCrossing()->VerticalTab(); 1278 const CrossingList* crossingList = tab->GetCrossingList(); 1279 for (int i = 0; i < crossingList->CountItems(); i++) { 1280 Corner* corner = crossingList->ItemAt(i)->RightTopCorner(); 1281 if (corner->status != Corner::kUsed) 1282 continue; 1283 1284 WindowArea* area = corner->windowArea; 1285 float pos1 = area->RightTopCrossing()->HorizontalTab()->Position(); 1286 float pos2 = area->RightBottomCrossing()->HorizontalTab()->Position(); 1287 1288 if (pos1 < endPos && pos2 > startPos) 1289 neighbourWindows.AddItem(area); 1290 1291 if (pos2 > endPos) 1292 break; 1293 } 1294 } 1295 1296 1297 void 1298 SATGroup::_BottomNeighbours(WindowAreaList& neighbourWindows, 1299 WindowArea* parent) 1300 { 1301 float startPos = parent->LeftBottomCrossing()->VerticalTab()->Position(); 1302 float endPos = parent->RightBottomCrossing()->VerticalTab()->Position(); 1303 1304 Tab* tab = parent->LeftBottomCrossing()->HorizontalTab(); 1305 const CrossingList* crossingList = tab->GetCrossingList(); 1306 for (int i = 0; i < crossingList->CountItems(); i++) { 1307 Corner* corner = crossingList->ItemAt(i)->LeftBottomCorner(); 1308 if (corner->status != Corner::kUsed) 1309 continue; 1310 1311 WindowArea* area = corner->windowArea; 1312 float pos1 = area->LeftBottomCrossing()->VerticalTab()->Position(); 1313 float pos2 = area->RightBottomCrossing()->VerticalTab()->Position(); 1314 1315 if (pos1 < endPos && pos2 > startPos) 1316 neighbourWindows.AddItem(area); 1317 1318 if (pos2 > endPos) 1319 break; 1320 } 1321 } 1322 1323 1324 bool 1325 SATGroup::_FindConnectedGroup(WindowAreaList& seedList, WindowArea* removedArea, 1326 WindowAreaList& newGroup) 1327 { 1328 if (seedList.CountItems() == 0) 1329 return false; 1330 1331 WindowArea* area = seedList.RemoveItemAt(0); 1332 newGroup.AddItem(area); 1333 1334 _FollowSeed(area, removedArea, seedList, newGroup); 1335 return true; 1336 } 1337 1338 1339 void 1340 SATGroup::_FollowSeed(WindowArea* area, WindowArea* veto, 1341 WindowAreaList& seedList, WindowAreaList& newGroup) 1342 { 1343 WindowAreaList neighbours; 1344 _FillNeighbourList(neighbours, area); 1345 for (int i = 0; i < neighbours.CountItems(); i++) { 1346 WindowArea* currentArea = neighbours.ItemAt(i); 1347 if (currentArea != veto && !newGroup.HasItem(currentArea)) { 1348 newGroup.AddItem(currentArea); 1349 // if we get a area from the seed list it is not a seed any more 1350 seedList.RemoveItem(currentArea); 1351 } 1352 else { 1353 // don't _FollowSeed of invalid areas 1354 neighbours.RemoveItemAt(i); 1355 i--; 1356 } 1357 } 1358 1359 for (int i = 0; i < neighbours.CountItems(); i++) 1360 _FollowSeed(neighbours.ItemAt(i), veto, seedList, newGroup); 1361 } 1362 1363 1364 void 1365 SATGroup::_SpawnNewGroup(const WindowAreaList& newGroup) 1366 { 1367 STRACE_SAT("SATGroup::_SpawnNewGroup\n"); 1368 SATGroup* group = new (std::nothrow)SATGroup; 1369 if (!group) 1370 return; 1371 BReference<SATGroup> groupRef; 1372 groupRef.SetTo(group, true); 1373 1374 for (int i = 0; i < newGroup.CountItems(); i++) 1375 newGroup.ItemAt(i)->PropagateToGroup(group); 1376 1377 _EnsureGroupIsOnScreen(group); 1378 } 1379 1380 1381 const float kMinOverlap = 50; 1382 const float kMoveToScreen = 75; 1383 1384 1385 void 1386 SATGroup::_EnsureGroupIsOnScreen(SATGroup* group) 1387 { 1388 STRACE_SAT("SATGroup::_EnsureGroupIsOnScreen\n"); 1389 if (!group) 1390 return; 1391 1392 if (group->CountItems() < 1) 1393 return; 1394 1395 SATWindow* window = group->WindowAt(0); 1396 Desktop* desktop = window->GetWindow()->Desktop(); 1397 if (!desktop) 1398 return; 1399 1400 const float kBigDistance = 1E+10; 1401 1402 float minLeftDistance = kBigDistance; 1403 BRect leftRect; 1404 float minTopDistance = kBigDistance; 1405 BRect topRect; 1406 float minRightDistance = kBigDistance; 1407 BRect rightRect; 1408 float minBottomDistance = kBigDistance; 1409 BRect bottomRect; 1410 1411 BRect screen = window->GetWindow()->Screen()->Frame(); 1412 BRect reducedScreen = screen; 1413 reducedScreen.InsetBy(kMinOverlap, kMinOverlap); 1414 1415 for (int i = 0; i < group->CountItems(); i++) { 1416 SATWindow* window = group->WindowAt(i); 1417 BRect frame = window->CompleteWindowFrame(); 1418 if (reducedScreen.Intersects(frame)) 1419 return; 1420 1421 if (frame.right < screen.left + kMinOverlap) { 1422 float dist = fabs(screen.left - frame.right); 1423 if (dist < minLeftDistance) { 1424 minLeftDistance = dist; 1425 leftRect = frame; 1426 } 1427 else if (dist == minLeftDistance) 1428 leftRect = leftRect | frame; 1429 } 1430 if (frame.top > screen.bottom - kMinOverlap) { 1431 float dist = fabs(frame.top - screen.bottom); 1432 if (dist < minBottomDistance) { 1433 minBottomDistance = dist; 1434 bottomRect = frame; 1435 } 1436 else if (dist == minBottomDistance) 1437 bottomRect = bottomRect | frame; 1438 } 1439 if (frame.left > screen.right - kMinOverlap) { 1440 float dist = fabs(frame.left - screen.right); 1441 if (dist < minRightDistance) { 1442 minRightDistance = dist; 1443 rightRect = frame; 1444 } 1445 else if (dist == minRightDistance) 1446 rightRect = rightRect | frame; 1447 } 1448 if (frame.bottom < screen.top + kMinOverlap) { 1449 float dist = fabs(frame.bottom - screen.top); 1450 if (dist < minTopDistance) { 1451 minTopDistance = dist; 1452 topRect = frame; 1453 } 1454 else if (dist == minTopDistance) 1455 topRect = topRect | frame; 1456 } 1457 } 1458 1459 BPoint offset; 1460 if (minLeftDistance < kBigDistance) { 1461 offset.x = screen.left - leftRect.right + kMoveToScreen; 1462 _CallculateYOffset(offset, leftRect, screen); 1463 } 1464 else if (minTopDistance < kBigDistance) { 1465 offset.y = screen.top - topRect.bottom + kMoveToScreen; 1466 _CallculateXOffset(offset, topRect, screen); 1467 } 1468 else if (minRightDistance < kBigDistance) { 1469 offset.x = screen.right - rightRect.left - kMoveToScreen; 1470 _CallculateYOffset(offset, rightRect, screen); 1471 } 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