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