1 //------------------------------------------------------------------------------ 2 // Copyright (c) 2001-2005, Haiku, Inc. 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a 5 // copy of this software and associated documentation files (the "Software"), 6 // to deal in the Software without restriction, including without limitation 7 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 // and/or sell copies of the Software, and to permit persons to whom the 9 // Software is furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 // DEALINGS IN THE SOFTWARE. 21 // 22 // File Name: Workspace.cpp 23 // Author: Adi Oanca <adioanca@cotty.iren.ro> 24 // Description: Tracks windows inside one workspace 25 // 26 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 27 // Notes: IMPORTANT WARNING 28 // This object does not use any locking mechanism. It is designed 29 // to be used by RootLayer class ONLY. DO NOT USE from elsewhere! 30 // 31 // Design Spec: 32 // The purpose of this class it to have visible windows appear in the 33 // correct order as defined by GUI guidelines. Those define 3 main type of windows: 34 // normal windows, modal and floating windows. Aditionally there must be support 35 // for another 2 types of windows which will be used in special cases. We're talking 36 // about system front windows which always will be the front-most and have focus, and 37 // system last windows which will always be behind all other kind of windows. 38 // 39 // Normal windows will always be in Workspace's list, be it they are hidden 40 // or not. They are added by hand (AddWindowLayer()) only. Same goes for system last 41 // windows, system first, modall all and floating all windows. Those remaining 42 // are: modal subset, modal app, floating subset and floating app. Those will be 43 // added and removed on-the-fly as they are needed. 44 // 45 // To keep correct track of modal subset/app and floating subset/app windows 46 // we need to have them in a list. Also, we want every normal window to 47 // maintain its floating windows order. For that we define a list for every normal 48 // window in which we'll add floating subset & app windows alongside with subset 49 // modals. Application modals go in a separate list which is hold for every 50 // application (ServerApp) object. For normal window's list: when a floating win 51 // is need (when normal window becomes front) it is always removed and automaticaly 52 // added to workspace's list. When that normal looses front state, it reinserts 53 // all floating windows it has used back into its list, thus saving the exact order 54 // of floating windows. Modal windows are never removed from normal or application's 55 // list, but they are automaticaly added and removed from workspace's list as needed. 56 // (ex: a modal app won't appear until a normal window from the same app is visible) 57 // 58 // Front status is a bit hard to explain. It's a state which helps keep 59 // the wanted order. For example, if a modal window is set to have front status, 60 // an automatic search is made to see if another modal was created after this 61 // one and thus needs to have front state (read: thus have to be in front this). 62 // Another use is to have floating windows pop up in front of a normal window when 63 // no modal exist to steal front state. 64 //------------------------------------------------------------------------------ 65 #include <stdio.h> 66 #include <stdlib.h> 67 #include <Window.h> 68 #include <TypeConstants.h> 69 70 #include "Workspace.h" 71 #include "Layer.h" 72 #include "WindowLayer.h" 73 #include "ServerWindow.h" 74 #include "ServerApp.h" 75 #include "RGBColor.h" 76 #include "SubWindowList.h" 77 78 //#define DEBUG_WORKSPACE 79 80 #ifdef DEBUG_WORKSPACE 81 # include <stdio.h> 82 # define STRACE(x) printf x 83 #else 84 # define STRACE(x) ; 85 #endif 86 87 #ifdef DEBUG_WORKSPACE 88 # include <stdio.h> 89 # define STRACESTREAM() PrintToStream() 90 #else 91 # define STRACESTREAM() ; 92 #endif 93 94 void 95 Workspace::State::PrintToStream() 96 { 97 printf("WS::State - Front: %s\n", Front? Front->Name(): "NULL"); 98 printf("WS::State - Focus: %s\n", Focus? Focus->Name(): "NULL"); 99 100 for (int32 i = 0; i < WindowList.CountItems(); ++i) { 101 Layer *l = (Layer*)WindowList.ItemAt(i); 102 if (l) 103 printf("\t %ld - %s\n", i, l->Name()); 104 } 105 } 106 107 //---------------------------------------------------------------------------------- 108 /*! 109 \brief Creates a new Workspace object which has its own resolution and background color. 110 */ 111 Workspace::Workspace(const int32 ID, const uint32 colorspace, const RGBColor& BGColor) 112 : fBGColor(BGColor) 113 { 114 STRACE(("New Workspace(%ld)\n", fID)); 115 fID = ID; 116 117 fBottomItem = NULL; 118 fTopItem = NULL; 119 fFocusItem = NULL; 120 fFrontItem = NULL; 121 122 memset(&fDisplayMode, 0, sizeof(fDisplayMode)); 123 fDisplayMode.space = colorspace; 124 } 125 126 //---------------------------------------------------------------------------------- 127 /*! 128 \brief Frees internal data. 129 */ 130 Workspace::~Workspace(void) 131 { 132 STRACE(("~Workspace(%ld) - say bye bye\n", fID)); 133 fFocusItem = NULL; 134 fFrontItem = NULL; 135 136 ListData *toast; 137 while(fBottomItem) 138 { 139 toast = fBottomItem; 140 fBottomItem = fBottomItem->upperItem; 141 142 fPool.ReleaseMemory(toast); 143 } 144 fBottomItem = NULL; 145 fTopItem = NULL; 146 } 147 148 149 /*! 150 \brief Adds layer ptr to workspace's list of WindowLayers. 151 */ 152 void 153 Workspace::AddWindowLayer(WindowLayer *winBorder) 154 { 155 STRACE(("W(%ld)::AddWindowLayer(%s)\n", fID, winBorder?winBorder->Name():"NULL")); 156 if (winBorder->Level() == B_FLOATING_APP) { 157 // floating windows are automaticaly added when needed 158 // you cannot add one by hand. 159 return; 160 } 161 162 if (HasItem(winBorder)) { 163 // NOTE: you may remove 'debugger' at Release Candidate time 164 debugger("WindowLayer ALREADY in Workspace's list\n"); 165 return; 166 } 167 168 // allocate a new item 169 ListData* item = fPool.GetCleanMemory(winBorder); 170 171 // place this winBorder in what seems the most appropriate location. 172 // Do not change front window 173 placeInFront(item, false); 174 } 175 176 177 /* 178 \brief Removes a WindowLayer from workspace's list. 179 */ 180 void 181 Workspace::RemoveWindowLayer(WindowLayer *winBorder) 182 { 183 STRACE(("W(%ld)::RemoveWindowLayer(%s)\n", fID, winBorder?winBorder->Name():"NULL")); 184 ListData* item = HasItem(winBorder); 185 186 if (item) { 187 RemoveItem(item); 188 fPool.ReleaseMemory(item); 189 } 190 } 191 192 193 bool 194 Workspace::HasWindowLayer(const WindowLayer* winBorder) const 195 { 196 return HasItem(winBorder) ? true: false; 197 } 198 199 200 WindowLayer * 201 Workspace::Focus() const 202 { 203 return fFocusItem ? fFocusItem->layerPtr : NULL; 204 } 205 206 207 WindowLayer * 208 Workspace::Front() const 209 { 210 return fFrontItem ? fFrontItem->layerPtr: NULL; 211 } 212 213 214 WindowLayer * 215 Workspace::Active() const 216 { 217 return fFocusItem ? fFocusItem->layerPtr : NULL; 218 } 219 220 221 /*! 222 \brief Method that returns the state of window manager. 223 \param state - a pointer to a valid Workspace::State structure 224 \return void 225 226 Fills the state structure with the most important window manager attibutes: 227 front window, focus window, active window and the list of windows starting from 228 the backmost one at position 0 and ending with the most visible window. 229 */ 230 void 231 Workspace::GetState(Workspace::State *state) const 232 { 233 state->Front = Front(); 234 state->Focus = Focus(); 235 236 ListData *cursor = fTopItem; 237 while (cursor) { 238 if (!cursor->layerPtr->IsHidden()) 239 state->WindowList.AddItem(cursor->layerPtr); 240 cursor = cursor->lowerItem; 241 } 242 } 243 244 245 bool 246 Workspace::AttemptToSetFront(WindowLayer *newFront) 247 { 248 return MoveToFront(newFront); 249 } 250 251 252 int32 253 Workspace::AttemptToSetFocus(WindowLayer *newFocus) 254 { 255 ListData* newFocusItem = HasItem(newFocus); 256 257 return _SetFocus(newFocusItem); 258 } 259 260 bool 261 Workspace::AttemptToMoveToBack(WindowLayer *newBack) 262 { 263 return MoveToBack(newBack); 264 } 265 266 bool 267 Workspace::AttemptToActivate(WindowLayer *toActivate) 268 { 269 MoveToFront(toActivate); 270 AttemptToSetFocus(toActivate); 271 return Active() == toActivate; 272 } 273 /* 274 \brief This method provides you the list of visible windows in this workspace. 275 \param list The list of visible WindowLayers found in this workspace. 276 \param itemCount Number of WindowLayer pointers found in the list. 277 */ 278 bool 279 Workspace::GetWindowLayerList(void **list, int32 *itemCount ) const 280 { 281 int32 count = 0; 282 ListData* cursor; 283 284 cursor = fBottomItem; 285 while (cursor) { 286 if (!cursor->layerPtr->IsHidden()) 287 count++; 288 cursor = cursor->upperItem; 289 } 290 291 if (*itemCount < count) { 292 // buffer not big enough. buffer must be count high 293 *itemCount = count; 294 return false; 295 } 296 297 if (list) { 298 *itemCount = count; 299 300 cursor = fBottomItem; 301 while (cursor) { 302 if (!cursor->layerPtr->IsHidden()) { 303 *list = cursor->layerPtr; 304 list++; 305 } 306 cursor = cursor->upperItem; 307 } 308 } 309 310 return true; 311 } 312 313 /*! 314 \brief Makes the specified WindowLayer the focus one. 315 \param newFocus WindowLayer which will try to take focus state. 316 \return 0 - setting focus failed, focus did not change. 317 1 - the new focus WindowLayer is \a winBorder 318 2 - focus changed but not to \a winBorder because in front of it there 319 are other modal windows. 320 321 Set a new focus WindowLayer if possible. 322 */ 323 324 int32 325 Workspace::_SetFocus(ListData *newFocusItem) 326 { 327 if (!newFocusItem || newFocusItem == fFocusItem 328 || (newFocusItem && !newFocusItem->layerPtr->IsHidden() 329 && newFocusItem->layerPtr->WindowFlags() & B_AVOID_FOCUS)) 330 return 0L; 331 332 WindowLayer *newFocus = newFocusItem->layerPtr; 333 bool rv = 1; 334 335 switch(newFocus->Level()) { 336 case B_MODAL_APP: 337 case B_NORMAL: { 338 ListData *item = newFocusItem->upperItem; 339 while ( item && 340 !item->layerPtr->IsHidden() && 341 ((item->layerPtr->Level() == B_MODAL_APP && 342 item->layerPtr->App()->ClientTeam() == newFocus->App()->ClientTeam()) || 343 item->layerPtr->Level() >= B_MODAL_ALL)) 344 { 345 if (item->layerPtr->WindowFlags() & B_AVOID_FOCUS) 346 newFocusItem = NULL; 347 else 348 newFocusItem = item; 349 rv = 2; 350 } 351 } 352 break; 353 354 case B_SYSTEM_FIRST: 355 case B_MODAL_ALL: { 356 ListData *item = newFocusItem->upperItem; 357 while ( item && 358 !item->layerPtr->IsHidden() && 359 item->layerPtr->Level() >= newFocus->Level()) 360 { 361 if (item->layerPtr->WindowFlags() & B_AVOID_FOCUS) 362 newFocusItem = NULL; 363 else 364 newFocusItem = item; 365 rv = 2; 366 } 367 } 368 break; 369 370 default: 371 break; 372 } 373 374 fFocusItem = newFocusItem; 375 376 return rv; 377 } 378 379 /*! 380 \brief Makes the specified WindowLayer the front one. 381 \param newFront WindowLayer which will try to take front state. 382 \param doNotDisturb In case user is busy typing something, don't bring \a newFront 383 in front stealing front&focus, but place imediately after. 384 \return True if the list of WindowLayers has changed, false otherwise. 385 386 This method tries to make \a newFront the new front WindowLayer. "It tries" because 387 if this a B_NORMAL window with subset or application modals those will be displayed 388 in front and get the front state. If no subset or application modals exist, then this 389 B_NORMAL window will get front (and focus) state and subset and application floating 390 window will be shown in front. 391 Note that floating windows cannot get/have front state. 392 */ 393 bool 394 Workspace::MoveToFront(WindowLayer *newFront, bool doNotDisturb) 395 { 396 STRACE(("\nWks(%ld)::MoveToFront ~%s~ \n", fID, newFront?newFront->Name():"NULL")); 397 if (!newFront) 398 return false; 399 400 if (newFront->IsHidden() || newFront->Level() == B_SYSTEM_LAST) 401 return false; 402 403 if (fFrontItem && newFront == fFrontItem->layerPtr) { 404 // we didn't change windows order 405 return false; 406 } 407 408 return ShowWindowLayer(newFront); 409 } 410 411 412 /*! 413 \brief Moves the specified WindowLayer in the back as it is possible. 414 \param newLast WindowLayer which will be placed in the back. 415 \return True if the list of WindowLayers has changed, false otherwise. 416 417 WindowLayer \a newLast will go in the back as much as possible. Note that this 418 action is tricky. While normal windows will always go into the back, front modal windows 419 won't go into the back if the next front window will be a B_NORMAL or B_MODAL_APP part 420 of the same team which was previously created. If it were possible it would 421 undermine the role of modal windows in the system. Another example regards B_FLOATING_APP 422 windows. These will ge in the back as possible, but never farther than the front 423 B_NORMAL window in front of which they appear. 424 */ 425 bool 426 Workspace::MoveToBack(WindowLayer *newLast) 427 { 428 STRACE(("Wks(%ld)::MoveToBack(%s) \n", fID, newLast? newLast->Name(): "NULL")); 429 if (newLast->IsHidden()) 430 return false; 431 432 ListData *newLastItem; 433 newLastItem = HasItem(newLast); 434 if (!newLastItem) 435 return false; 436 437 ListData *previous = newLastItem->upperItem; 438 bool returnValue = false; 439 bool changeFront = false; 440 int32 level = newLast->Level(); 441 if (level > B_SYSTEM_FIRST) 442 level = B_SYSTEM_FIRST; 443 444 if (fFrontItem && fFrontItem == newLastItem) 445 changeFront = true; 446 447 switch(newLast->Level()) 448 { 449 case B_MODAL_ALL: 450 case B_SYSTEM_FIRST: 451 case B_SYSTEM_LAST: 452 { 453 // these kind of windows do not change position 454 return false; 455 } 456 break; 457 case B_NORMAL: 458 { 459 ListData *cursor = newLastItem->upperItem; 460 461 // we are already the back-most window. 462 if (!cursor || cursor->layerPtr->Level() == B_SYSTEM_LAST ) 463 return false; 464 465 if (changeFront) 466 saveFloatingWindows(fFrontItem); 467 } 468 // NOTE: no 'break;' here... 469 case B_FLOATING_APP: 470 case B_FLOATING_ALL: 471 { 472 returnValue = placeToBack(newLastItem); 473 } 474 break; 475 case B_MODAL_APP: 476 { 477 ListData *cursor = newLastItem->upperItem; 478 479 // we are already the back-most window. 480 if (!cursor || cursor->layerPtr->Level() == B_SYSTEM_LAST ) 481 return false; 482 483 // this is a modal app 484 if (newLast->App()->fAppSubWindowList.HasItem(newLast)) { 485 ListData* before; 486 487 // remove now to properly place later 488 RemoveItem(newLastItem); 489 490 while (cursor) { 491 if (!cursor->layerPtr->IsHidden() 492 && cursor->layerPtr->Level() > B_SYSTEM_LAST 493 && cursor->layerPtr->App()->ClientTeam() == newLast->App()->ClientTeam()) 494 break; 495 496 cursor = cursor->upperItem; 497 } 498 499 if (cursor) 500 before = cursor->lowerItem; 501 else 502 before = fTopItem; 503 504 InsertItem(newLastItem, before); 505 } else { 506 // this is a modal subset 507 // this subset modal is visible, it means its main window must be visible. search for it. 508 ListData *mainWindowItem, *before; 509 int32 indexThis = 0, indexCursor; 510 511 // search by going deep 512 while (cursor) { 513 if (cursor->layerPtr->Level() == B_NORMAL && !cursor->layerPtr->IsHidden() 514 && (indexThis = cursor->layerPtr->fSubWindowList.IndexOf(newLast)) >= 0) 515 break; 516 cursor = cursor->upperItem; 517 } 518 519 if (!cursor) 520 debugger("MoveToBack: SubsetWindow: can't find main Window!\n"); 521 522 RemoveItem(newLastItem); 523 524 // good. found our main window. now go up and properly place. 525 mainWindowItem = cursor; 526 before = cursor->lowerItem; 527 528 cursor = cursor->lowerItem; 529 while (cursor) { 530 if (cursor->layerPtr->Level() == B_MODAL_APP && !cursor->layerPtr->IsHidden() 531 && cursor->layerPtr->App()->ClientTeam() == newLast->App()->ClientTeam()) 532 { 533 indexCursor = mainWindowItem->layerPtr->fSubWindowList.IndexOf(cursor->layerPtr); 534 if (indexCursor >= 0) 535 { 536 if (indexThis < indexCursor) 537 { 538 before = cursor; 539 break; 540 } 541 else 542 { 543 before = cursor->lowerItem; 544 } 545 } 546 } 547 cursor = cursor->lowerItem; 548 } 549 550 InsertItem(newLastItem, before); 551 } 552 returnValue = true; 553 } 554 break; 555 default: 556 { 557 debugger("MoveToBack: unknown window feel\n"); 558 return false; 559 } 560 } 561 562 if (previous == newLastItem->upperItem) 563 returnValue = false; 564 565 // The following applies ONLY to B_NORMAL and B_MODAL_APP windows. 566 567 if (changeFront) 568 { 569 ListData *newFront; 570 newFront = findNextFront(); 571 if (newFront) 572 returnValue |= MoveToFront(newFront->layerPtr); 573 else 574 debugger("MoveToBack: can't find new front! We should find one!\n"); 575 } 576 577 return returnValue; 578 } 579 580 581 /*! 582 \brief Hides a WindowLayer. 583 \param winBorder WindowLayer to be hidden. 584 \return True if the list of WindowLayers has changed, false otherwise. 585 586 WindowLayer \a winBorder will be hidden. Some, like floating or subset modals 587 may also be removed from Workspace's list. 588 If \a winBorder if the front WindowLayer, another one (or none) will be automaticaly 589 chosen. Same goes for focus. 590 */ 591 bool 592 Workspace::HideWindowLayer(WindowLayer *winBorder) 593 { 594 STRACE(("W(%ld)::HideWindowLayer(%s) \n", fID, winBorder? winBorder->Name(): "NULL")); 595 bool returnValue = false; 596 int32 level = winBorder->Level(); 597 bool changeFront = false; 598 bool changeFocus = false; 599 ListData* nextFocus = NULL; 600 601 if (fFrontItem && fFrontItem->layerPtr == winBorder) 602 changeFront = true; 603 604 if (fFocusItem && fFocusItem->layerPtr == winBorder) { 605 changeFocus = true; 606 nextFocus = fFocusItem->lowerItem; 607 } 608 609 if (level > B_SYSTEM_FIRST) 610 level = B_SYSTEM_FIRST; 611 612 switch (level) { 613 case B_MODAL_ALL: 614 case B_SYSTEM_FIRST: 615 case B_SYSTEM_LAST: 616 case B_FLOATING_ALL: 617 // window is just hidden. do nothing. its position is OK as it is now. 618 returnValue = true; 619 break; 620 621 case B_FLOATING_APP: 622 if (fFrontItem && fFrontItem->layerPtr->Level() == B_NORMAL) { 623 ListData* item = HasItem(winBorder); 624 if (item) { 625 fFrontItem->layerPtr->fSubWindowList.AddWindowLayer(winBorder); 626 627 RemoveItem(item); 628 fPool.ReleaseMemory(item); 629 630 returnValue = true; 631 } 632 } 633 break; 634 635 case B_NORMAL: 636 { 637 if (fFrontItem && fFrontItem->layerPtr == winBorder) 638 saveFloatingWindows(fFrontItem); 639 640 // remove B_MODAL_SUBSET windows present before this window. 641 ListData* itemThis = HasItem(winBorder); 642 ListData* toast; 643 ListData* item = itemThis->lowerItem; 644 while (item) { 645 // if this modal subset is in our list ONLY (not in other visible normal window's one), 646 // then remove from Workspace's list. 647 if (item->layerPtr->Level() == B_MODAL_APP) { 648 if (winBorder->fSubWindowList.HasItem(item->layerPtr)) { 649 if (!searchFirstMainWindow(item->layerPtr)) { 650 // if this modal subset has front state, make sure another window will get that status. 651 if (fFrontItem == item) 652 changeFront = true; 653 654 toast = item; 655 item = item->lowerItem; 656 RemoveItem(toast); 657 fPool.ReleaseMemory(toast); 658 } 659 } else if (!searchANormalWindow(item->layerPtr) 660 && !(item->layerPtr->Workspaces() & (0x00000001 << fID))) { 661 // if this modal subset has front state, make sure another window will get that status. 662 if (fFrontItem == item) 663 changeFront = true; 664 665 toast = item; 666 item = item->lowerItem; 667 RemoveItem(toast); 668 fPool.ReleaseMemory(toast); 669 } else 670 item = item->lowerItem; 671 } else 672 item = item->lowerItem; 673 } 674 675 returnValue = true; 676 break; 677 } 678 679 case B_MODAL_APP: 680 { 681 // if a subset modal, then remove from Workspace's list. 682 if (winBorder->App()->fAppSubWindowList.HasItem(winBorder)) { 683 ListData* toast = HasItem(winBorder); 684 if (toast) { 685 RemoveItem(toast); 686 fPool.ReleaseMemory(toast); 687 688 returnValue = true; 689 } 690 } 691 break; 692 } 693 694 default: 695 debugger("HideWindowLayer: what kind of window is this?\n"); 696 } 697 698 // select a new Front if needed 699 if (changeFront) { 700 fFrontItem = NULL; 701 702 ListData* newFront = findNextFront(); 703 if (newFront) 704 MoveToFront(newFront->layerPtr); 705 } 706 707 if (!HasItem(fFocusItem)) 708 fFocusItem = NULL; 709 710 // floating windows can have focus state. what if this removed window is 711 // the focus window? There will be no focus anymore. 712 // So, start a search to set the new focus 713 if (!fFocusItem || changeFocus) { 714 if (!HasItem(nextFocus)) 715 nextFocus = NULL; 716 717 if (nextFocus == NULL) { 718 nextFocus = fBottomItem; 719 720 while (nextFocus) { 721 if (!nextFocus->layerPtr->IsHidden() 722 && !(nextFocus->layerPtr->WindowFlags() & B_AVOID_FOCUS)) 723 break; 724 else 725 nextFocus = nextFocus->upperItem; 726 } 727 } 728 729 fFocusItem = nextFocus; 730 } 731 732 return returnValue; 733 } 734 735 /*! 736 \brief Shows a WindowLayer. 737 \param winBorder WindowLayer to be show. 738 \return True if the list of WindowLayers has changed, false otherwise. 739 740 WindowLayer \a winBorder will be shown. Other windows like floating or modal 741 ones will be placed in front if needed. Front & Focus state will be given to \a winBorder 742 unless a modal windows steals both. 743 */ 744 bool 745 Workspace::ShowWindowLayer(WindowLayer *winBorder, bool userBusy) 746 { 747 STRACE(("W(%ld)::ShowWindowLayer(%s) \n", fID, winBorder? winBorder->Name(): "NULL")); 748 bool returnValue = false; 749 int32 level = winBorder->Level(); 750 if (level > B_SYSTEM_FIRST) 751 level = B_SYSTEM_FIRST; 752 753 // Before you go understand this method, please note that 'placeInFront' MUST be 754 // called of EVERY window except B_FLOATING_APP when 755 // ADDING a new window to Workspace's list!!! 756 757 switch (level) { 758 // B_MODAL_ALL, B_FLOATNG_ALL, B_SYSTEM_FIRST & B_SYSTEM_LAST 759 // will be removed ONLY when are deleted! 760 // ALSO, they will ALWAYS be the first/last windows in hierarchy, no matter 761 // if they are hidden or not - they keep their order. 762 763 case B_MODAL_ALL: 764 case B_SYSTEM_FIRST: 765 case B_SYSTEM_LAST: 766 { 767 // nothing special to be done. just compare indexes to see if front state will change. 768 if (fFrontItem) { 769 int32 reverseIndexThis, reverseIndexFront; 770 ListData* itemThis = HasItem(winBorder, &reverseIndexThis); 771 772 HasItem(fFrontItem->layerPtr, &reverseIndexFront); 773 774 if (reverseIndexThis < reverseIndexFront) { 775 if (fFrontItem->layerPtr->Level() == B_NORMAL) 776 saveFloatingWindows(fFrontItem); 777 778 fFrontItem = itemThis; 779 } 780 } else { 781 // of course, if there is no front item, then set this one. 782 fFrontItem = HasItem(winBorder); 783 } 784 returnValue = true; 785 break; 786 } 787 788 case B_FLOATING_ALL: 789 { 790 // simply relocate. A floating window can't have front state. 791 ListData* itemThis = HasItem(winBorder); 792 RemoveItem(itemThis); 793 placeInFront(itemThis, userBusy); 794 795 returnValue = true; 796 break; 797 } 798 799 // FLOATING windows are always removed from Workspace's list when changing to a new front window. 800 801 case B_FLOATING_APP: 802 { 803 // see if we have a front window which is a B_NORMAL window and who's list of floating 804 // and modal windows contains our window. 805 if (fFrontItem && fFrontItem->layerPtr->Level() == B_NORMAL) { 806 // if this winBorder is the focus it is already the first among floating app windows. 807 if (fFocusItem && fFocusItem->layerPtr == winBorder) 808 break; 809 810 ListData* itemThis = NULL; 811 // remove from B_NORMAL's list. 812 if (fFrontItem->layerPtr->fSubWindowList.RemoveItem(winBorder)) { 813 // we need to add this window 814 itemThis = fPool.GetCleanMemory(winBorder); 815 } else { 816 itemThis = HasItem(winBorder); 817 // window is already in Workspace's list. Find and temporarly remove. 818 if (itemThis) 819 RemoveItem(itemThis); 820 } 821 822 if (itemThis) { 823 // insert in front of other B_FLOATING_APP windows. 824 ListData* item = fFrontItem->lowerItem; 825 while (item && item->layerPtr->Level() == B_FLOATING_APP) 826 item = item->lowerItem; 827 828 InsertItem(itemThis, item); 829 830 returnValue = true; 831 } 832 } 833 break; 834 } 835 836 case B_NORMAL: 837 { 838 ListData* itemThis = HasItem(winBorder); 839 840 if (!itemThis) { 841 debugger("ShowWindowLayer: B_NORMAL window - cannot find specified window in workspace's list\n"); 842 return false; 843 } 844 845 // front status will change. if a normal window has front state, 846 // remove and save floating windows order that may be above it. 847 if (fFrontItem && fFrontItem->layerPtr->Level() == B_NORMAL) 848 saveFloatingWindows(fFrontItem); 849 850 RemoveItem(itemThis); 851 852 placeInFront(itemThis, userBusy); 853 854 ListData* newFront = itemThis; 855 856 if (windowHasVisibleModals(winBorder)) 857 newFront = putModalsInFront(itemThis); 858 859 if (fFrontItem) { 860 if (!userBusy) { 861 int32 revFrontItemIndex, revNewFrontIndex; 862 863 HasItem(fFrontItem, &revFrontItemIndex); 864 HasItem(newFront, &revNewFrontIndex); 865 if (revNewFrontIndex < revFrontItemIndex) 866 fFrontItem = newFront; 867 } 868 } else { 869 fFrontItem = newFront; 870 } 871 872 if (fFrontItem->layerPtr->Level() == B_NORMAL) 873 putFloatingInFront(fFrontItem); 874 875 returnValue = true; 876 break; 877 } 878 879 // MODAL windows usualy stay in Workspace's list, but they are scatered, so we must gather them 880 // when needed. 881 882 case B_MODAL_APP: 883 { 884 // build a list of modal windows to know what windows should be placed before this one. 885 BList tempList; 886 887 // APP modal 888 if (winBorder->App()->fAppSubWindowList.HasItem(winBorder)) { 889 // take only application's modals 890 tempList.AddList(&winBorder->App()->fAppSubWindowList); 891 if (fFrontItem 892 && fFrontItem->layerPtr->App()->ClientTeam() == winBorder->App()->ClientTeam()) 893 userBusy = false; 894 } else { 895 // SUBSET modal 896 WindowLayer *mainWindow = searchFirstMainWindow(winBorder); 897 if (mainWindow) { 898 // add both mainWindow's subset modals and application's modals 899 tempList.AddList(&mainWindow->fSubWindowList); 900 tempList.AddList(&winBorder->App()->fAppSubWindowList); 901 if (fFrontItem && fFrontItem->layerPtr == mainWindow) 902 userBusy = false; 903 } else { 904 // none of the unhiden normal windows havs this window as part of its subset. 905 // as a result this window won't be added to Workspace's list for it to be shown. 906 return false; 907 } 908 } 909 910 // === list ready === 911 912 // front status will change. if a normal window has front state, 913 // remove and save floating windows order that may be above it. 914 if (fFrontItem && fFrontItem->layerPtr->Level() == B_NORMAL) 915 saveFloatingWindows(fFrontItem); 916 917 // find and remove the Workspace's entry for this WindowLayer. 918 ListData *itemThis; 919 itemThis = HasItem(winBorder); 920 if (itemThis) { 921 RemoveItem(itemThis); 922 } else { 923 // not found? no problem. create a new entry. 924 itemThis = fPool.GetCleanMemory(winBorder); 925 } 926 927 placeInFront(itemThis, userBusy); 928 929 // now place other modals windows above 930 int32 revIndexThis, revIndexItem; 931 ListData *newFront = itemThis; 932 933 // find the index of this window in Workspace's list. It will be used to place higher 934 // indexed windows above, if it's the case. 935 HasItem(itemThis, &revIndexThis); 936 937 { 938 ListData* before = itemThis->lowerItem; 939 int32 i, count; 940 WindowLayer** wbList; 941 ListData* itemX; 942 int32 indexThisInTempList; 943 944 indexThisInTempList = tempList.IndexOf(winBorder); 945 if (indexThisInTempList < 0) 946 debugger("ShowWindowLayer: modal window: design flaw!!!\n"); 947 948 count = tempList.CountItems(); 949 wbList = (WindowLayer**)tempList.Items(); 950 for (i = indexThisInTempList; i < count; i++) { 951 if (!wbList[i]->IsHidden()) { 952 itemX = HasItem(wbList[i], &revIndexItem); 953 if (itemX && revIndexItem > revIndexThis) { 954 removeAndPlaceBefore(itemX, before); 955 newFront = itemX; 956 } 957 } 958 } 959 } 960 961 if (fFrontItem) { 962 if (!userBusy) { 963 int32 revFrontItemIndex, revNewFrontIndex; 964 965 HasItem(fFrontItem, &revFrontItemIndex); 966 HasItem(newFront, &revNewFrontIndex); 967 if (revNewFrontIndex < revFrontItemIndex) 968 fFrontItem = newFront; 969 } 970 971 if (fFrontItem->layerPtr->Level() == B_NORMAL) 972 putFloatingInFront(fFrontItem); 973 } else { 974 fFrontItem = newFront; 975 } 976 977 returnValue = true; 978 break; 979 } 980 981 default: 982 debugger("What kind of window is this???\n"); 983 } 984 985 if (!HasItem(fFocusItem)) 986 fFocusItem = NULL; 987 988 // set new Focus if needed 989 if (Focus() == NULL) { 990 ListData* cursor = fBottomItem; 991 992 fFocusItem = NULL; 993 while (cursor != NULL && fFocusItem == NULL) { 994 if (!cursor->layerPtr->IsHidden() 995 && !(cursor->layerPtr->WindowFlags() & B_AVOID_FOCUS)) { 996 if (cursor->layerPtr->Level() == B_FLOATING_APP 997 || cursor->layerPtr->Level() == B_FLOATING_ALL) { 998 // set focus to floating windows only if directly targeted 999 if (cursor->layerPtr == winBorder) { 1000 fFocusItem = cursor; 1001 } else 1002 cursor = cursor->upperItem; 1003 } else 1004 fFocusItem = cursor; 1005 } else 1006 cursor = cursor->upperItem; 1007 } 1008 } 1009 1010 return returnValue; 1011 } 1012 1013 1014 status_t 1015 Workspace::SetDisplayMode(const display_mode &mode) 1016 { 1017 fDisplayMode = mode; 1018 return B_OK; 1019 } 1020 1021 1022 status_t 1023 Workspace::GetDisplayMode(display_mode &mode) const 1024 { 1025 mode = fDisplayMode; 1026 return B_OK; 1027 } 1028 1029 1030 void 1031 Workspace::SetBGColor(const RGBColor &c) 1032 { 1033 fBGColor = c; 1034 } 1035 1036 1037 RGBColor 1038 Workspace::BGColor(void) const 1039 { 1040 return fBGColor; 1041 } 1042 1043 1044 /*! 1045 \brief Retrieves settings from a container message passed to PutSettings 1046 \param A BMessage containing data from a PutSettings() call 1047 1048 This function will place default values whenever a particular setting cannot 1049 be found. 1050 */ 1051 void 1052 Workspace::GetSettings(const BMessage &msg) 1053 { 1054 BMessage container; 1055 rgb_color *color; 1056 ssize_t size; 1057 1058 char fieldname[4]; 1059 sprintf(fieldname,"%d",(uint8)fID); 1060 1061 // First, find the container message corresponding to the workspace's index 1062 if(msg.FindMessage(fieldname,&container)!=B_OK) 1063 { 1064 GetDefaultSettings(); 1065 return; 1066 } 1067 1068 if(container.FindInt32("timing_pixel_clock",(int32*)&fDisplayMode.timing.pixel_clock) != B_OK) 1069 fDisplayMode.timing.pixel_clock=25175; 1070 if(container.FindInt16("timing_h_display",(int16*)&fDisplayMode.timing.h_display)!=B_OK) 1071 fDisplayMode.timing.h_display=640; 1072 if(container.FindInt16("timing_h_sync_start",(int16*)&fDisplayMode.timing.h_sync_start)!=B_OK) 1073 fDisplayMode.timing.h_sync_start=656; 1074 if(container.FindInt16("timing_h_sync_end",(int16*)&fDisplayMode.timing.h_sync_end)!=B_OK) 1075 fDisplayMode.timing.h_sync_end=752; 1076 if(container.FindInt16("timing_h_total",(int16*)&fDisplayMode.timing.h_total)!=B_OK) 1077 fDisplayMode.timing.h_total=800; 1078 if(container.FindInt16("timing_v_display",(int16*)&fDisplayMode.timing.v_display)!=B_OK) 1079 fDisplayMode.timing.v_display=480; 1080 if(container.FindInt16("timing_v_sync_start",(int16*)&fDisplayMode.timing.v_sync_start)!=B_OK) 1081 fDisplayMode.timing.v_sync_start=490; 1082 if(container.FindInt16("timing_v_sync_end",(int16*)&fDisplayMode.timing.v_sync_end)!=B_OK) 1083 fDisplayMode.timing.v_sync_end=492; 1084 if(container.FindInt16("timing_v_total",(int16*)&fDisplayMode.timing.v_total)!=B_OK) 1085 fDisplayMode.timing.v_total=525; 1086 if(container.FindInt32("timing_flags",(int32*)&fDisplayMode.timing.flags)!=B_OK) 1087 fDisplayMode.timing.flags=0; 1088 1089 if(container.FindInt32("color_space", (int32*)&fDisplayMode.space) != B_OK) 1090 fDisplayMode.space = B_CMAP8; 1091 1092 if(container.FindData("bgcolor",B_RGB_COLOR_TYPE,(const void **)&color,&size)==B_OK) 1093 fBGColor.SetColor(*color); 1094 else 1095 fBGColor.SetColor(0,0,0); 1096 1097 if(container.FindInt16("virtual_width", (int16 *)&fDisplayMode.virtual_width) != B_OK) 1098 fDisplayMode.virtual_width = 640; 1099 if(container.FindInt16("virtual_height", (int16 *)&fDisplayMode.virtual_height) != B_OK) 1100 fDisplayMode.virtual_height = 480; 1101 } 1102 1103 //---------------------------------------------------------------------------------- 1104 //! Sets workspace settings to defaults 1105 void Workspace::GetDefaultSettings(void) 1106 { 1107 fBGColor.SetColor(0,0,0); 1108 1109 fDisplayMode.timing.pixel_clock = 25175; 1110 fDisplayMode.timing.h_display = 640; 1111 fDisplayMode.timing.h_sync_start = 656; 1112 fDisplayMode.timing.h_sync_end = 752; 1113 fDisplayMode.timing.h_total = 800; 1114 fDisplayMode.timing.v_display = 480; 1115 fDisplayMode.timing.v_sync_start = 490; 1116 fDisplayMode.timing.v_sync_end = 492; 1117 fDisplayMode.timing.v_total = 525; 1118 fDisplayMode.timing.flags = 0; 1119 fDisplayMode.space = B_CMAP8; 1120 1121 fDisplayMode.virtual_width = 640; 1122 fDisplayMode.virtual_height = 480; 1123 } 1124 1125 //---------------------------------------------------------------------------------- 1126 /*! 1127 \brief Places the screen settings for the workspace in the passed BMessage 1128 \param msg BMessage pointer to receive the settings 1129 \param index The index number of the workspace in the desktop 1130 1131 This function will fail if passed a NULL pointer. The settings for the workspace are 1132 saved in a BMessage in a BMessage. 1133 1134 The message itself is placed in a field string based on its index - "1", "2", etc. 1135 1136 The format is as follows: 1137 display_timing "timing_XXX" -> fDisplayTiming members (see Accelerant.h) 1138 uint32 "color_space" -> color space of the workspace 1139 rgb_color "bgcolor" -> background color of the workspace 1140 int16 "virtual_width" -> virtual width of the workspace 1141 int16 "virtual_height" -> virtual height of the workspace 1142 */ 1143 void Workspace::PutSettings(BMessage *msg, const uint8 &index) const 1144 { 1145 if(!msg) 1146 return; 1147 1148 BMessage container; 1149 rgb_color color=fBGColor.GetColor32(); 1150 1151 // a little longer than we need in case someone tries to pass index=255 or something 1152 char fieldname[4]; 1153 1154 container.AddInt32("timing_pixel_clock",fDisplayMode.timing.pixel_clock); 1155 container.AddInt16("timing_h_display",fDisplayMode.timing.h_display); 1156 container.AddInt16("timing_h_sync_start",fDisplayMode.timing.h_sync_start); 1157 container.AddInt16("timing_h_sync_end",fDisplayMode.timing.h_sync_end); 1158 container.AddInt16("timing_h_total",fDisplayMode.timing.h_total); 1159 container.AddInt16("timing_v_display",fDisplayMode.timing.v_display); 1160 container.AddInt16("timing_v_sync_start",fDisplayMode.timing.v_sync_start); 1161 container.AddInt16("timing_v_sync_end",fDisplayMode.timing.v_sync_end); 1162 container.AddInt16("timing_v_total",fDisplayMode.timing.v_total); 1163 container.AddInt32("timing_flags",fDisplayMode.timing.flags); 1164 1165 container.AddInt32("color_space", fDisplayMode.space); 1166 container.AddData("bgcolor", B_RGB_COLOR_TYPE, &color, sizeof(rgb_color)); 1167 1168 container.AddInt16("virtual_width", fDisplayMode.virtual_width); 1169 container.AddInt16("virtual_height", fDisplayMode.virtual_height); 1170 1171 sprintf(fieldname,"%d",index); 1172 1173 // Just in case... 1174 msg->RemoveName(fieldname); 1175 1176 msg->AddMessage(fieldname,&container); 1177 } 1178 1179 //---------------------------------------------------------------------------------- 1180 /*! 1181 \brief Places default settings for the workspace in the passed BMessage 1182 \param msg BMessage pointer to receive the settings 1183 \param index The index number of the workspace in the desktop 1184 */ 1185 void Workspace::PutDefaultSettings(BMessage *msg, const uint8 &index) 1186 { 1187 if(!msg) 1188 return; 1189 1190 BMessage container; 1191 rgb_color color={ 0,0,0,255 }; 1192 1193 // a little longer than we need in case someone tries to pass index=255 or something 1194 char fieldname[4]; 1195 1196 // These default settings the same ones as found in ~/config/settings/ 1197 // app_server_settings on R5 1198 1199 container.AddInt32("timing_pixel_clock",25175); 1200 container.AddInt16("timing_h_display",640); 1201 container.AddInt16("timing_h_sync_start",656); 1202 container.AddInt16("timing_h_sync_end",752); 1203 container.AddInt16("timing_h_total",800); 1204 container.AddInt16("timing_v_display",480); 1205 container.AddInt16("timing_v_sync_start",490); 1206 container.AddInt16("timing_v_sync_end",492); 1207 container.AddInt16("timing_v_total",525); 1208 container.AddInt32("timing_flags",0); 1209 1210 container.AddInt32("color_space",B_CMAP8); 1211 container.AddData("bgcolor",B_RGB_COLOR_TYPE,&color,sizeof(rgb_color)); 1212 1213 container.AddInt16("virtual_width",640); 1214 container.AddInt16("virtual_height",480); 1215 1216 sprintf(fieldname,"%d",index); 1217 1218 // Just in case... 1219 msg->RemoveName(fieldname); 1220 1221 msg->AddMessage(fieldname, &container); 1222 } 1223 1224 //---------------------------------------------------------------------------------- 1225 // Debug method 1226 1227 void 1228 Workspace::PrintToStream() const 1229 { 1230 printf("Workspace %ld hierarchy shown from back to front:\n", fID); 1231 for (ListData *item = fTopItem; item != NULL; item = item->lowerItem) 1232 { 1233 WindowLayer *wb = (WindowLayer*)item->layerPtr; 1234 printf("\tName: %s\t%s", wb->Name(), wb->IsHidden()?"Hidden\t": "Visible\t"); 1235 if(wb->Feel() == B_FLOATING_SUBSET_WINDOW_FEEL) 1236 printf("\t%s\n", "B_FLOATING_SUBSET_WINDOW_FEEL"); 1237 if(wb->Feel() == B_FLOATING_APP_WINDOW_FEEL) 1238 printf("\t%s\n", "B_FLOATING_APP_WINDOW_FEEL"); 1239 if(wb->Feel() == B_FLOATING_ALL_WINDOW_FEEL) 1240 printf("\t%s\n", "B_FLOATING_ALL_WINDOW_FEEL"); 1241 if(wb->Feel() == B_MODAL_SUBSET_WINDOW_FEEL) 1242 printf("\t%s\n", "B_MODAL_SUBSET_WINDOW_FEEL"); 1243 if(wb->Feel() == B_MODAL_APP_WINDOW_FEEL) 1244 printf("\t%s\n", "B_MODAL_APP_WINDOW_FEEL"); 1245 if(wb->Feel() == B_MODAL_ALL_WINDOW_FEEL) 1246 printf("\t%s\n", "B_MODAL_ALL_WINDOW_FEEL"); 1247 if(wb->Feel() == B_NORMAL_WINDOW_FEEL) 1248 printf("\t%s\n", "B_NORMAL_WINDOW_FEEL"); 1249 if(wb->Feel() == B_SYSTEM_LAST) 1250 printf("\t%s\n", "B_SYSTEM_LAST"); 1251 if(wb->Feel() >= B_SYSTEM_FIRST) 1252 printf("\t%s\n", "B_SYSTEM_FIRST"); 1253 1254 } 1255 printf("Focus Layer:\t%s\n", fFocusItem? fFocusItem->layerPtr->Name(): "NULL"); 1256 printf("Front Layer:\t%s\n\n", fFrontItem? fFrontItem->layerPtr->Name(): "NULL"); 1257 } 1258 1259 1260 void 1261 Workspace::PrintItem(ListData *item) const 1262 { 1263 printf("ListData members:\n"); 1264 if(item) 1265 { 1266 printf("WindowLayer:\t%s\n", item->layerPtr? item->layerPtr->Name(): "NULL"); 1267 printf("UpperItem:\t%s\n", item->upperItem? item->upperItem->layerPtr->Name(): "NULL"); 1268 printf("LowerItem:\t%s\n", item->lowerItem? item->lowerItem->layerPtr->Name(): "NULL"); 1269 } 1270 else 1271 { 1272 printf("NULL item\n"); 1273 } 1274 } 1275 1276 //---------------------------------------------------------------------------------- 1277 // PRIVATE 1278 //---------------------------------------------------------------------------------- 1279 /* 1280 Insert item in the top-bottom direction. 1281 */ 1282 void 1283 Workspace::InsertItem(ListData *item, ListData *before) 1284 { 1285 // insert before one other item; 1286 if (before) { 1287 if (before->upperItem) 1288 before->upperItem->lowerItem = item; 1289 1290 item->upperItem = before->upperItem; 1291 item->lowerItem = before; 1292 before->upperItem = item; 1293 1294 if (fTopItem == before) 1295 fTopItem = item; 1296 } else { 1297 // insert item at the end. 1298 item->upperItem = fBottomItem; 1299 if (fBottomItem) 1300 fBottomItem->lowerItem = item; 1301 1302 fBottomItem = item; 1303 1304 if (!fTopItem) 1305 fTopItem = item; 1306 } 1307 } 1308 1309 1310 void 1311 Workspace::RemoveItem(ListData *item) 1312 { 1313 if (!item) 1314 return; 1315 1316 if (fBottomItem == item) 1317 fBottomItem = item->upperItem; 1318 else 1319 item->lowerItem->upperItem = item->upperItem; 1320 1321 if (fTopItem == item) 1322 fTopItem = item->lowerItem; 1323 else 1324 item->upperItem->lowerItem = item->lowerItem; 1325 1326 // set all these to NULL to avoid confusion later. 1327 1328 item->upperItem = NULL; 1329 item->lowerItem = NULL; 1330 1331 if (fFocusItem == item) 1332 fFocusItem = NULL; 1333 1334 if (fFrontItem == item) 1335 fFrontItem = NULL; 1336 } 1337 1338 1339 ListData* 1340 Workspace::HasItem(const ListData *item, int32 *index) const 1341 { 1342 int32 idx = 0; 1343 ListData* itemX; 1344 1345 for (itemX = fBottomItem; itemX != NULL; itemX = itemX->upperItem) { 1346 if (item == itemX) 1347 break; 1348 1349 idx++; 1350 } 1351 1352 if (index && itemX) 1353 *index = idx; 1354 1355 return itemX; 1356 } 1357 1358 1359 ListData* 1360 Workspace::HasItem(const WindowLayer *layer, int32 *index) const 1361 { 1362 int32 idx = 0; 1363 ListData* itemX; 1364 1365 for (itemX = fBottomItem; itemX != NULL; itemX = itemX->upperItem) { 1366 if (layer == itemX->layerPtr) 1367 break; 1368 1369 idx++; 1370 } 1371 1372 if (index && itemX) 1373 *index = idx; 1374 1375 return itemX; 1376 } 1377 1378 1379 /*! 1380 \brief Returns the index of the specified item starting from the back-most window. 1381 */ 1382 int32 1383 Workspace::IndexOf(const ListData *item) const 1384 { 1385 if (!item) 1386 return -1; 1387 1388 int32 index = 0; 1389 for (ListData *itemX = fTopItem; itemX != NULL; itemX = itemX->lowerItem) { 1390 if (itemX->layerPtr == item->layerPtr) 1391 return index; 1392 index++; 1393 } 1394 return -1; 1395 } 1396 1397 1398 inline bool 1399 Workspace::placeToBack(ListData *newLast) 1400 { 1401 int32 level = newLast->layerPtr->Level(); 1402 ListData* cursor = newLast->upperItem; 1403 1404 switch (level) { 1405 case B_FLOATING_ALL: 1406 case B_FLOATING_APP: 1407 { 1408 int32 count = 0; 1409 while (cursor && cursor->layerPtr->Level() == level) { 1410 if (!cursor->layerPtr->IsHidden()) 1411 count++; 1412 cursor = cursor->upperItem; 1413 } 1414 1415 // we're already the last floating window 1416 if (count == 0) 1417 return false; 1418 else { 1419 bool changeFocus = false; 1420 1421 if (fFocusItem == newLast) 1422 changeFocus = true; 1423 1424 if (changeFocus) { 1425 ListData* cursor = newLast->upperItem; 1426 while (cursor 1427 && (cursor->layerPtr->IsHidden() 1428 || cursor->layerPtr->WindowFlags() & B_AVOID_FOCUS) 1429 && cursor->layerPtr->Level() == level) { 1430 cursor = cursor->upperItem; 1431 } 1432 1433 // give focus only if a unhidden floating window could be selected 1434 // otherwise this('newLast') window keeps focus 1435 if (cursor->layerPtr->Level() == level) 1436 fFocusItem = cursor; 1437 } 1438 1439 RemoveItem(newLast); 1440 InsertItem(newLast, cursor ? cursor->lowerItem : fTopItem); 1441 1442 return true; 1443 } 1444 break; 1445 } 1446 1447 case B_NORMAL: 1448 { 1449 int32 count = 0; 1450 int32 cursorLevel; 1451 while (cursor) { 1452 cursorLevel = cursor->layerPtr->Level(); 1453 if (cursorLevel == B_MODAL_APP) 1454 cursorLevel = B_NORMAL; 1455 1456 if (cursorLevel < level) { 1457 break; 1458 } else { 1459 count++; 1460 cursor = cursor->upperItem; 1461 } 1462 } 1463 1464 // we're already the last normal window 1465 if (count == 0) 1466 return false; 1467 else { 1468 RemoveItem(newLast); 1469 InsertItem(newLast, cursor ? cursor->lowerItem : fTopItem); 1470 return true; 1471 } 1472 break; 1473 } 1474 } 1475 1476 return false; 1477 } 1478 1479 //---------------------------------------------------------------------------------- 1480 /*! 1481 \brief Based on it's WindowLayer type, places this item in front as it is possible. 1482 */ 1483 void 1484 Workspace::placeInFront(ListData *item, const bool userBusy) 1485 { 1486 if (!item) 1487 return; 1488 1489 int32 level = item->layerPtr->Level(); 1490 ListData* cursor = fBottomItem; 1491 int32 cursorLevel; 1492 1493 // make MODAL windows act just like normal ones. 1494 if (level == B_MODAL_APP) 1495 level = B_NORMAL; 1496 1497 // B_SYSTEM_LAST - always place (the most) last 1498 if (level == B_SYSTEM_LAST) { 1499 InsertItem(item, fTopItem); 1500 return; 1501 } 1502 1503 // search for the exact place... 1504 while (cursor) { 1505 cursorLevel = cursor->layerPtr->Level(); 1506 1507 // make MODAL windows act just like normal ones. 1508 if (cursorLevel == B_MODAL_APP) 1509 cursorLevel = B_NORMAL; 1510 1511 if (level < cursorLevel) { 1512 cursor = cursor->upperItem; 1513 continue; 1514 } else { 1515 // that's it, we've found the proper place. 1516 break; 1517 } 1518 } 1519 1520 if (cursor) { 1521 // if user is busy typing something, or has an opened menu... 1522 if (userBusy && cursor == fFrontItem) 1523 InsertItem(item, cursor); 1524 else 1525 InsertItem(item, cursor->lowerItem); 1526 } else 1527 InsertItem(item, fTopItem); 1528 } 1529 1530 1531 inline bool 1532 Workspace::removeAndPlaceBefore(ListData *item, ListData *beforeItem) 1533 { 1534 if (item && item != beforeItem) { 1535 RemoveItem(item); 1536 // insert into proper place. 1537 InsertItem(item, beforeItem); 1538 return true; 1539 } 1540 return false; 1541 } 1542 1543 /*! 1544 \brief Insert the specified WindowLayer before given item. First search the 1545 specified WindowLayer in Workspace's list an remove it. 1546 \resolution: private 1547 */ 1548 inline bool 1549 Workspace::removeAndPlaceBefore(const WindowLayer *wb, ListData *beforeItem) 1550 { 1551 return removeAndPlaceBefore(HasItem(wb), beforeItem); 1552 } 1553 1554 1555 inline WindowLayer* 1556 Workspace::searchANormalWindow(WindowLayer *wb) const 1557 { 1558 ListData* listItem = fBottomItem; 1559 while (listItem) { 1560 if (listItem->layerPtr->Level() == B_NORMAL && !listItem->layerPtr->IsHidden() 1561 && listItem->layerPtr->App()->ClientTeam() == wb->App()->ClientTeam()) 1562 return listItem->layerPtr; 1563 1564 listItem = listItem->upperItem; 1565 } 1566 return NULL; 1567 } 1568 1569 1570 inline WindowLayer* 1571 Workspace::searchFirstMainWindow(WindowLayer *wb) const 1572 { 1573 ListData* listItem = fBottomItem; 1574 while (listItem) { 1575 if (listItem->layerPtr->Level() == B_NORMAL && !listItem->layerPtr->IsHidden() 1576 && listItem->layerPtr->App()->ClientTeam() == wb->App()->ClientTeam() 1577 && listItem->layerPtr->fSubWindowList.HasItem(wb)) 1578 return listItem->layerPtr; 1579 1580 listItem = listItem->upperItem; 1581 } 1582 return NULL; 1583 } 1584 1585 //---------------------------------------------------------------------------------- 1586 1587 inline 1588 bool Workspace::windowHasVisibleModals(const WindowLayer *winBorder) const 1589 { 1590 int32 i, count; 1591 WindowLayer **wbList; 1592 1593 // check window's list 1594 count = winBorder->fSubWindowList.CountItems(); 1595 wbList = (WindowLayer**)winBorder->fSubWindowList.Items(); 1596 for(i = 0; i < count; i++) 1597 { 1598 if (wbList[i]->Level() == B_MODAL_APP && !wbList[i]->IsHidden()) 1599 return true; 1600 } 1601 1602 // application's list only has modal windows. 1603 count = winBorder->App()->fAppSubWindowList.CountItems(); 1604 wbList = (WindowLayer**)winBorder->App()->fAppSubWindowList.Items(); 1605 for(i = 0; i < count; i++) 1606 { 1607 if (!wbList[i]->IsHidden()) 1608 return true; 1609 } 1610 1611 return false; 1612 } 1613 1614 //---------------------------------------------------------------------------------- 1615 1616 inline 1617 ListData* Workspace::putModalsInFront(ListData *item) 1618 { 1619 int32 i, count, revIndex, revIndexItem; 1620 WindowLayer **wbList; 1621 ListData *itemX; 1622 ListData *lastPlaced = NULL; 1623 ListData *before = item->lowerItem; 1624 1625 HasItem(item, &revIndex); 1626 1627 // check window's list 1628 count = item->layerPtr->fSubWindowList.CountItems(); 1629 wbList = (WindowLayer**)item->layerPtr->fSubWindowList.Items(); 1630 for(i = 0; i < count; i++) 1631 { 1632 if (wbList[i]->Level() == B_MODAL_APP && !wbList[i]->IsHidden()) 1633 { 1634 itemX = HasItem(wbList[i], &revIndexItem); 1635 if (!itemX) 1636 { 1637 itemX = fPool.GetCleanMemory(wbList[i]); 1638 1639 InsertItem(itemX, before); 1640 lastPlaced = itemX; 1641 } 1642 else if (revIndexItem > revIndex) 1643 { 1644 removeAndPlaceBefore(itemX, before); 1645 lastPlaced = itemX; 1646 } 1647 } 1648 } 1649 1650 // application's list only has modal windows. 1651 count = item->layerPtr->App()->fAppSubWindowList.CountItems(); 1652 wbList = (WindowLayer**)item->layerPtr->App()->fAppSubWindowList.Items(); 1653 for(i = 0; i < count; i++) 1654 { 1655 if (!wbList[i]->IsHidden()) 1656 { 1657 itemX = HasItem(wbList[i], &revIndexItem); 1658 if (!itemX) 1659 { 1660 itemX = fPool.GetCleanMemory(wbList[i]); 1661 1662 InsertItem(itemX, before); 1663 lastPlaced = itemX; 1664 } 1665 else if (revIndexItem > revIndex) 1666 { 1667 removeAndPlaceBefore(itemX, before); 1668 lastPlaced = itemX; 1669 } 1670 } 1671 } 1672 1673 return lastPlaced; 1674 } 1675 1676 1677 void 1678 Workspace::putFloatingInFront(ListData *item) 1679 { 1680 int32 i; 1681 ListData *newItem; 1682 ListData *before = item->lowerItem; 1683 WindowLayer *wb; 1684 1685 i = 0; 1686 while ((wb = (WindowLayer*)item->layerPtr->fSubWindowList.ItemAt(i))) 1687 { 1688 if (wb->Level() == B_MODAL_APP) 1689 { 1690 break; 1691 } 1692 else if (!wb->IsHidden()) 1693 { 1694 newItem = fPool.GetCleanMemory(wb); 1695 1696 InsertItem(newItem, before); 1697 1698 item->layerPtr->fSubWindowList.RemoveItem(i); 1699 } 1700 else 1701 i++; 1702 } 1703 } 1704 1705 //---------------------------------------------------------------------------------- 1706 1707 inline 1708 void Workspace::saveFloatingWindows(ListData *itemNormal) 1709 { 1710 ListData *item = itemNormal->lowerItem; 1711 ListData *toast; 1712 while(item) 1713 { 1714 if (item->layerPtr->Level() == B_FLOATING_APP) 1715 { 1716 itemNormal->layerPtr->fSubWindowList.AddWindowLayer(item->layerPtr); 1717 1718 toast = item; 1719 item = item->lowerItem; 1720 RemoveItem(toast); 1721 fPool.ReleaseMemory(toast); 1722 } 1723 else 1724 break; 1725 } 1726 } 1727 1728 //---------------------------------------------------------------------------------- 1729 1730 inline 1731 ListData* Workspace::findNextFront() const 1732 { 1733 ListData *item = fBottomItem; 1734 1735 while(item) 1736 { 1737 if (!item->layerPtr->IsHidden() 1738 && item->layerPtr->Level() != B_FLOATING_ALL 1739 && item->layerPtr->Level() != B_FLOATING_APP 1740 && !(item->layerPtr->WindowFlags() & B_AVOID_FRONT)) 1741 { 1742 return item; 1743 } 1744 item = item->upperItem; 1745 } 1746 1747 // we cannot ignore anymore B_AVOID_FRONT windows. 1748 1749 item = fBottomItem; 1750 while(item) 1751 { 1752 if (!item->layerPtr->IsHidden() 1753 && item->layerPtr->Level() != B_FLOATING_ALL 1754 && item->layerPtr->Level() != B_FLOATING_APP) 1755 { 1756 return item; 1757 } 1758 item = item->upperItem; 1759 } 1760 1761 return NULL; 1762 } 1763 1764 1765 1766 1767 // TODO: BAD, bad memory manager!!! replace!!! 1768 Workspace::MemoryPool::MemoryPool() 1769 { 1770 } 1771 1772 Workspace::MemoryPool::~MemoryPool() 1773 { 1774 } 1775 1776 inline 1777 ListData* Workspace::MemoryPool::GetCleanMemory(WindowLayer *winBorder) 1778 { 1779 ListData *item = (ListData*)malloc(sizeof(ListData)); 1780 item->layerPtr = winBorder; 1781 item->upperItem = NULL; 1782 item->lowerItem = NULL; 1783 return item; 1784 } 1785 1786 inline 1787 void Workspace::MemoryPool::ReleaseMemory(ListData *mem) 1788 { 1789 free(mem); 1790 } 1791 1792 void Workspace::MemoryPool::expandBuffer(int32 start) 1793 { 1794 } 1795