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