1: /*
     2:  ============================================================================
     3:  xoblite™ -> an advanced "extended shell" for Microsoft® Windows® 11
     4:  Copyright © 2002-2026 Karl Henrik Henriksson [qwilk/@xoblite]
     5:  Copyright © 2001-2004 The Blackbox for Windows Development Team
     6:  http://xoblite.net/ + https://github.com/xoblite/
     7:  ============================================================================
     8: 
     9:   Blackbox for Windows is free software, released under the
    10:   GNU General Public License (GPL version 2 or later), with an extension
    11:   that allows linking of proprietary modules under a controlled interface.
    12:   What this means is that plugins etc. are allowed to be released
    13:   under any license the author wishes. Please note, however, that the
    14:   original Blackbox gradient math code used in Blackbox for Windows
    15:   is available under the BSD license.
    16: 
    17:   http://www.fsf.org/licenses/gpl.html
    18:   http://www.fsf.org/licenses/gpl-faq.html#LinkingOverControlledInterface
    19:   http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
    20: 
    21:   This program is distributed in the hope that it will be useful,
    22:   but WITHOUT ANY WARRANTY; without even the implied warranty of
    23:   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    24:   GNU General Public License for more details.
    25: 
    26:   For additional license information, please read the included license.html.
    27: 
    28:  ============================================================================
    29: */
    30: 
    31: #include "..\API\BBApi.h" 
    32: #include "Workspaces.h" 
    33: #include "..\Settings\Settings.h" 
    34: #include "..\Toolbar\Toolbar.h" 
    35: #include "..\Blackbox.h" 
    36: 
    37: //===========================================================================
    38: 
    39: const char szWorkspacesName[] = "Workspaces"; // Window class etc.
    40: 
    41: extern Workspaces* pWorkspaces;
    42: extern Settings* pSettings;
    43: extern Desktop* pDesktop;
    44: extern Toolbar* pToolbar;
    45: extern Taskbar* pTaskbar;
    46: 
    47: //typedef void (__stdcall *STTWTYPE)(HWND, int);
    48: //extern STTWTYPE BBSwitchToThisWindow;
    49: 
    50: int workspacesMessageSubscription[] = { BB_WORKSPACE, BB_RECONFIGURE, BB_SWITCHTON, BB_ACTIVETASK, BB_LISTDESKTOPS, BB_BRINGTOFRONT, 0 };
    51: 
    52: //===========================================================================
    53: 
    54: Workspaces::Workspaces(HINSTANCE hMainInstance)
    55: {
    56:     hWorkspacesInstance = hMainInstance;
    57: 
    58:     ScreenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
    59:     ScreenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
    60: 
    61:     UpdateWorkspaceNames();
    62: 
    63:     //====================
    64: 
    65:     // Register window class...
    66:     WNDCLASS wc;
    67:     ZeroMemory(&wc,sizeof(wc));
    68:     wc.hInstance = hWorkspacesInstance;     
    69:     wc.lpfnWndProc = WndProc;               // Window procedure
    70:     wc.lpszClassName = szWorkspacesName;    // Window class name
    71: 
    72:     if (!RegisterClass(&wc))
    73:     {
    74:         MessageBox(0, "Error registering workspaces window class!", szWorkspacesName, MB_OK);
    75:         Log("Workspaces", "Error registering window class!");
    76:         return;
    77:     }
    78: 
    79:     // Create workspaces handling window...
    80:     hWorkspacesWnd = CreateWindowEx(
    81:         WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE,    // window style
    82:         szWorkspacesName,                       // window class
    83:         NULL,                                   // window name
    84:         0,                                      // window parameters
    85:         0,                                      // x position
    86:         0,                                      // y position
    87:         0,                                      // window width
    88:         0,                                      // window height
    89:         GetBBWnd(),                             // owner window
    90:         NULL,                                   // no menu
    91:         hWorkspacesInstance,                    // hInstance
    92:         NULL                                    // no window creation data
    93:     );
    94: 
    95:     if (!hWorkspacesWnd)
    96:     {                          
    97:         UnregisterClass(szWorkspacesName, hWorkspacesInstance); // Unregister window class
    98:         MessageBox(0, "Error creating workspaces window!", szWorkspacesName, MB_OK);
    99:         Log("Workspaces", "Error creating window!");
   100:         return;
   101:     }
   102: 
   103:     //====================
   104: 
   105:     // Subscribe to Blackbox messages applicable to workspaces handling...
   106:     SendMessage(GetBBWnd(), BB_REGISTERMESSAGE, (WPARAM)hWorkspacesWnd, (LPARAM)workspacesMessageSubscription);
   107: 
   108:     MakeSticky(hWorkspacesWnd);     
   109: }
   110: 
   111: //===========================================================================
   112: 
   113: Workspaces::~Workspaces()
   114: {
   115:     GatherWindows();
   116: 
   117:     // Unsubscribe to previously subscribed Blackbox messages...
   118:     SendMessage(GetBBWnd(), BB_UNREGISTERMESSAGE, (WPARAM)hWorkspacesWnd, (LPARAM)workspacesMessageSubscription);
   119: 
   120:     DestroyWindow(hWorkspacesWnd); // Destroy window...
   121:     UnregisterClass(szWorkspacesName, hWorkspacesInstance); // Unregister window class...
   122: 
   123:     workspaceNames.clear();
   124: }
   125: 
   126: //===========================================================================
   127: 
   128: LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   129: {
   130:     switch (message)
   131:     {
   132:         //====================
   133: 
   134:         case BB_RECONFIGURE:
   135:         {
   136:             pWorkspaces->UpdateWorkspaceNames();
   137:         }
   138:         break;
   139: 
   140:         //====================
   141: 
   142:         case BB_SWITCHTON:
   143:         {
   144:             pWorkspaces->SwitchToWorkspace((int)wParam);
   145:             break;
   146:         }
   147: 
   148:         //====================
   149: 
   150:         case BB_ACTIVETASK:
   151:         {
   152:             // Change workspaces automatically when the active task changes? (e.g. via Alt+Tab)
   153:             if (pSettings->followActive) pWorkspaces->SwitchToWorkspace(pWorkspaces->GetWorkspaceByWindow((HWND)wParam));
   154:         }
   155: 
   156:         //====================
   157: 
   158:         case BB_LISTDESKTOPS:
   159:         {
   160:             DesktopInfo deskInfo;
   161:             ZeroMemory(&deskInfo, sizeof(deskInfo));
   162:             for (int i = 0; i < pSettings->numberOfWorkspaces; i++)
   163:             {
   164:                 deskInfo.isCurrent = (pSettings->currentWorkspace == i);
   165:                 deskInfo.number = i;
   166: 
   167:                 if (pWorkspaces->workspaceNames[i] == "null")
   168:                 {
   169:                     sprintf_s(deskInfo.name, sizeofArray(deskInfo.name), "Workspace %d", i + 1);
   170:                 }
   171:                 else
   172:                 {
   173:                     strcpy_s(deskInfo.name, sizeofArray(deskInfo.name), pWorkspaces->workspaceNames[i].c_str());
   174:                 }
   175: 
   176:                 SendMessage((HWND)wParam, BB_DESKTOPINFO, 0, (LPARAM) &deskInfo);
   177:             }
   178:             break;
   179:         }
   180: 
   181:         //====================
   182: 
   183:         case BB_BRINGTOFRONT: 
   184:         {
   185:             // Change window focus via message... (+ change workspace if needed)
   186:             int n = pWorkspaces->GetWorkspaceByWindow((HWND)lParam);
   187:             if (n != pSettings->currentWorkspace) pWorkspaces->SwitchToWorkspace(n);
   188: //          BBSwitchToThisWindow((HWND)lParam, FALSE);
   189:             BringWindowToTop((HWND)lParam);
   190:             break;
   191:         }
   192: 
   193:         //====================
   194: 
   195:         case BB_WORKSPACE:
   196:         {
   197:             switch (wParam)
   198:             {
   199:                 case 0: // "BBWS_PreviousWorkspace"
   200:                     pWorkspaces->PreviousWorkspace();
   201:                 break;
   202:                 case 1: // "BBWS_NextWorkspace"
   203:                     pWorkspaces->NextWorkspace();
   204:                 break;
   205:                 case 2: // "BBWS_NewWorkspace"
   206:                     pWorkspaces->NewWorkspace();
   207:                 break;
   208:                 case 3: // "BBWS_RemoveLastWorkspace"
   209:                     pWorkspaces->RemoveLastWorkspace();
   210:                 break;
   211:                 case 4: // "BBWS_SWITCHTODESK"
   212:                     pWorkspaces->SwitchToWorkspace((int)lParam);
   213:                 break;
   214:                 case 5: // "BBWS_GATHERWINDOWS"
   215:                     pWorkspaces->GatherWindows();
   216:                 break;
   217:                 case 6: // "BBWS_MOVEWINDOWLEFT"
   218:                     pWorkspaces->MoveWindowToPreviousWorkspace((HWND)lParam);
   219:                 break;
   220:                 case 7: // "BBWS_MOVEWINDOWRIGHT"
   221:                     pWorkspaces->MoveWindowToNextWorkspace((HWND)lParam);
   222:                 break;
   223:                 case 8: // "BBWS_PREVWINDOW"
   224:                     if (pTaskbar) pTaskbar->PreviousTask(!(bool)lParam, false);
   225:                 break;
   226:                 case 9: // "BBWS_NEXTWINDOW"
   227:                     if (pTaskbar) pTaskbar->NextTask(!(bool)lParam, false);
   228:                 break;
   229:                 case 10: // "BBWS_LastWorkspace"
   230:                     pWorkspaces->LastWorkspace();
   231:                 break;
   232: 
   233:                 //====================
   234: 
   235:                 // Below: Misc stuff included for for basic compatibility
   236:                 // with the bb(C)Lean(Mod)(Zero) modified BBApi...
   237:                 case BBWS_TOGGLESTICKY:
   238:                 case BBWS_MAKESTICKY:
   239:                 case BBWS_CLEARSTICKY:
   240:                 case BBWS_TOGGLEONTOP:
   241:                 {
   242:                     HWND hwnd = (HWND)lParam;
   243:                     if (hwnd == NULL)
   244:                     {
   245:                         if (pTaskbar) hwnd = pTaskbar->GetActiveWindow();
   246:                         if (hwnd == NULL) hwnd = GetForegroundWindow();
   247:                     }
   248: 
   249:                     if (message == BBWS_TOGGLESTICKY)
   250:                     {
   251:                         if (CheckSticky(hwnd)) RemoveSticky(hwnd);
   252:                         else MakeSticky(hwnd);
   253:                     }
   254:                     else if (message == BBWS_MAKESTICKY) MakeSticky(hwnd);
   255:                     else if (message == BBWS_CLEARSTICKY) RemoveSticky(hwnd);
   256:                     else if (message == BBWS_TOGGLEONTOP)
   257:                     {
   258:                         LONG_PTR windowIsOnTop = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
   259:                         if (windowIsOnTop & WS_EX_TOPMOST) SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
   260:                         else SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
   261:                     }
   262:                 }
   263:                 break;
   264: 
   265:                 //====================
   266: 
   267:                 default:
   268:                     break; // Note: Breaking as default avoids unintended behaviour if receiving unknown wParam, e.g. ones defined by the bb(C)Lean(Mod)(Zero) modified BBApi...
   269:             }
   270:         }
   271:         break;
   272: 
   273:         //====================
   274: 
   275:         case WM_DISPLAYCHANGE:
   276:         {
   277:             pWorkspaces->ScreenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
   278:             pWorkspaces->ScreenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
   279:         }
   280: 
   281:         //====================
   282: 
   283:         default:
   284:             return DefWindowProc(hwnd,message,wParam,lParam);
   285:     }
   286:     return 0;
   287: }
   288: 
   289: //===========================================================================
   290: // Functions: EnumWindowsProc
   291: // Purpose: Window enumeration process for the Workspaces window handling
   292: //===========================================================================
   293: 
   294: const long magicDWord = 0x49474541;
   295: 
   296: BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
   297: {
   298:     // Perform a few window validation checks...
   299:     // (nb. the taskbar already performs many such checks for its tasks prior to adding them, so we leverage that here too)
   300:     if (!IsOnTaskbar(hwnd)) return true;
   301:     if (CheckSticky(hwnd)) return true;
   302:     if (GetWindowLong(hwnd, GWLP_USERDATA) == magicDWord) return true; // For legacy backwards compatibility only (iirc this was used by the earliest bb4win sticky windows implementations)
   303: 
   304:     // Disregard Rainmeter widgets... (i.e. exclude them from the Workspaces handling altogether to avoid possible conflicts)
   305:     char temp[MAX_LINE_LENGTH];
   306:     GetClassName(hwnd, temp, MAX_LINE_LENGTH);
   307:     if (!_stricmp(temp, "RainmeterMeterWindow")) return true;
   308: 
   309:     //====================
   310: 
   311:     RECT r;
   312:     GetWindowRect(hwnd, &r);
   313: 
   314:     int addH = (int)lParam;
   315:     if (addH == -1)
   316:     {
   317:         int screenWidth = pWorkspaces->ScreenWidth;
   318:         int windowWidth = abs(r.right - r.left);
   319: 
   320:         // Initial x/width position calculation...
   321:         if (r.left > screenWidth)
   322:         {
   323:             r.left %= (screenWidth + 10);
   324:             if (r.left > screenWidth) r.left -= (screenWidth + 10);
   325:             r.right = r.left + windowWidth;
   326:         }
   327:         else if (r.left < -10)
   328:         {
   329:             r.left %= (screenWidth + 10);
   330:             while (r.left < -10) r.left += (screenWidth + 10);
   331:             r.right = r.left + windowWidth;
   332:         }
   333:     }
   334:     else
   335:     {
   336:         r.left -= addH;
   337:         r.right -= addH;
   338:     }
   339: 
   340:     HDWP hdwp = DeferWindowPos(pWorkspaces->dwp, hwnd, NULL, r.left, r.top, r.right-r.left, r.bottom-r.top, SWP_NOZORDER|SWP_NOACTIVATE);
   341:     if (hdwp != NULL) pWorkspaces->dwp = hdwp;
   342: /*
   343:     else if (pSettings->debugLogging)
   344:     {
   345:         char title[MAX_LINE_LENGTH], msg[MAX_LINE_LENGTH];
   346:         GetWindowText(hwnd, title, MAX_LINE_LENGTH);
   347:         sprintf_s(msg, sizeofArray(msg), "Workspaces -> DeferWindowPos() failed! -> %s", title);
   348:         SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_ERROR_MESSAGE, (LPARAM)msg);
   349:     }
   350: */
   351:     return true;
   352: }
   353: 
   354: //===========================================================================
   355: // Functions: PreviousWorkspace / NextWorkspace / LastWorkspace
   356: // Purpose: ...
   357: //===========================================================================
   358: 
   359: void Workspaces::PreviousWorkspace()
   360: {
   361:     int workspace;
   362:     if (pSettings->currentWorkspace > 0) workspace = pSettings->currentWorkspace - 1;
   363:     else workspace = pSettings->numberOfWorkspaces - 1;
   364:     SwitchToWorkspace(workspace);
   365: }
   366: 
   367: //====================
   368: 
   369: void Workspaces::NextWorkspace()
   370: {
   371:     int workspace;
   372:     if (pSettings->currentWorkspace < (pSettings->numberOfWorkspaces - 1)) workspace = pSettings->currentWorkspace + 1;
   373:     else workspace = 0;
   374:     SwitchToWorkspace(workspace);
   375: }
   376: 
   377: //====================
   378: 
   379: void Workspaces::LastWorkspace()
   380: {   
   381:     SwitchToWorkspace(pSettings->lastWorkspace);
   382: }
   383: 
   384: //===========================================================================
   385: // Function: SwitchToWorkspace
   386: // Purpose: ...
   387: //===========================================================================
   388: 
   389: void Workspaces::SwitchToWorkspace(int workspace)
   390: {
   391:     if ((workspace != pSettings->currentWorkspace) && (workspace >= 0) && (workspace < pSettings->numberOfWorkspaces))
   392:     {
   393:         int addH = ((workspace % pSettings->numberOfWorkspaces) - (pSettings->currentWorkspace % pSettings->numberOfWorkspaces)) * (ScreenWidth + 10);
   394: 
   395:         dwp = BeginDeferWindowPos(0);
   396:         EnumWindows(EnumWindowsProc, (LPARAM)addH);
   397:         EndDeferWindowPos(dwp);
   398: 
   399:         pSettings->lastWorkspace = pSettings->currentWorkspace;
   400:         pSettings->currentWorkspace = workspace;
   401: 
   402:         PlaySoundFX(SFX_WORKSPACE_CHANGE);
   403:         pDesktop->UpdateDesktopWindow();
   404: 
   405:         if (pSettings->wallpaperPerWorkspace)
   406:         {
   407:             pSettings->wallpaperPerWorkspaceSemaphore = true;
   408:             _beginthread(ExecuteRootCommand, 0, NULL);
   409:         }
   410: 
   411:         if (!pSettings->accessLock)
   412:         {
   413:             // Update the toolbar... (including workspace label, taskbar if applicable, etc)
   414:             if (pToolbar) pToolbar->UpdatePosition();
   415:         }
   416:     }
   417: }
   418: 
   419: //===========================================================================
   420: // Functions: NewWorkspace / RemoveLastWorkspace
   421: // Purpose: Adds a new / removes the last workspace
   422: //===========================================================================
   423: 
   424: void Workspaces::NewWorkspace()
   425: {
   426:     // Note:
   427:     // "Workspace 254" is used as a wildcard to e.g. list tasks on all workspaces
   428:     // "Workspace 255" is used for minimized tasks
   429:     if (pSettings->numberOfWorkspaces == 253) return; // -> We've reached the theoretical maximum number of workspaces... ;)
   430: 
   431:     pSettings->numberOfWorkspaces++;
   432:     UpdateWorkspaceNames();
   433: 
   434:     if (pTaskbar)
   435:     {
   436:         if (pSettings->taskbarMode != TASKBAR_MODE_HIDDEN) pTaskbar->cachedTaskButtonsExist = false;
   437:     }
   438:     if (pToolbar)
   439:     {
   440:         // Update the toolbar... (including workspace label, taskbar if applicable, etc)
   441:         pToolbar->cachedBitmapsExist = false;
   442:         pToolbar->UpdatePosition();
   443:     }
   444:     if (pDesktop) pDesktop->UpdateDesktopWindow(); // Update the number of workspace indicators on the desktop...
   445: 
   446:     WriteInt(pSettings->xobrcDefaultFile, "xoblite.workspaces:", pSettings->numberOfWorkspaces);
   447: }
   448: 
   449: //====================
   450: 
   451: void Workspaces::RemoveLastWorkspace()
   452: {
   453:     if (pSettings->numberOfWorkspaces != 1)
   454:     {
   455:         if (pSettings->currentWorkspace == pSettings->numberOfWorkspaces - 1)
   456:         {
   457:             SwitchToWorkspace(pSettings->currentWorkspace-1);
   458:         }
   459: 
   460:         pSettings->numberOfWorkspaces--;
   461:         UpdateWorkspaceNames();
   462: 
   463:         if (pTaskbar)
   464:         {
   465:             for (int i = 0; i < (int)pTaskbar->taskList.size(); i++)
   466:             {
   467:                 if (!CheckSticky(pTaskbar->taskList[i]->hwnd))
   468:                 {
   469:                     if (pTaskbar->taskList[i]->workspace > (pSettings->numberOfWorkspaces - 1)) pTaskbar->taskList[i]->workspace = pSettings->numberOfWorkspaces - 1;
   470:                 }
   471:             }
   472: 
   473:             if (pSettings->taskbarMode != TASKBAR_MODE_HIDDEN) pTaskbar->cachedTaskButtonsExist = false;
   474:         }
   475:         if (pToolbar)
   476:         {
   477:             // Update the toolbar... (including workspace label, taskbar if applicable, etc)
   478:             pToolbar->cachedBitmapsExist = false;
   479:             pToolbar->UpdatePosition();
   480:         }
   481:         if (pDesktop) pDesktop->UpdateDesktopWindow(); // Update the number of workspace indicators on the desktop...
   482:     }
   483: 
   484:     WriteInt(pSettings->xobrcDefaultFile, "xoblite.workspaces:", pSettings->numberOfWorkspaces);
   485: }
   486: 
   487: //===========================================================================
   488: // Function: UpdateWorkspaceNames
   489: // Purpose: Extracts individual workspace names from
   490: //          a single xoblite.rc configuration setting
   491: //===========================================================================
   492: 
   493: void Workspaces::UpdateWorkspaceNames()
   494: {
   495:     workspaceNames.clear();
   496:     char buffer[MAX_LINE_LENGTH], szBuffer[MAX_PATH];
   497:     strcpy_s(buffer, sizeofArray(buffer), pSettings->workspaceNames);
   498: 
   499:     for (int i = 0; i < pSettings->numberOfWorkspaces; i++)
   500:     {
   501:         strcpy_s(buffer, sizeofArray(buffer), Tokenize(buffer, szBuffer, ","));
   502:         if (!strcmp(szBuffer,"")) sprintf_s(szBuffer, sizeofArray(szBuffer), "Workspace #%d", i+1); // -> Default if no name configured
   503:         workspaceNames.push_back(string(szBuffer));
   504:     }
   505: }
   506: 
   507: //===========================================================================
   508: // Functions: GetWorkspaceByWindow / GetWorkspaceByRect
   509: // Purpose: ...
   510: //===========================================================================
   511: 
   512: int Workspaces::GetWorkspaceByWindow(HWND window)
   513: {
   514:     if (!window || IsIconic(window)) return 255;
   515: 
   516:     if (pTaskbar)
   517:     {
   518:         int i = pTaskbar->FindTask(window);
   519:         if (i >= 0) return pTaskbar->taskList[i]->workspace;
   520:     }
   521: 
   522:     // Use legacy GetWorkspaceByRect() based mechanism as fallback... (see below)
   523:     RECT r;
   524:     GetWindowRect(window, &r);
   525:     return (GetWorkspaceByRect(r));
   526: }
   527: 
   528: //====================
   529: 
   530: int Workspaces::GetWorkspaceByRect(RECT r)
   531: {
   532:     int offsetX = pSettings->currentWorkspace % pSettings->numberOfWorkspaces;
   533:     int offsetY = pSettings->currentWorkspace / pSettings->numberOfWorkspaces;
   534:     int workspace;
   535:     RECT tempRect, workspaceRect;
   536: 
   537:     workspaceRect.left = workspaceRect.top = 0;
   538:     workspaceRect.right = ScreenWidth;
   539:     workspaceRect.bottom = ScreenHeight;
   540: 
   541:     if (IntersectRect(&tempRect, &r, &workspaceRect)) return pSettings->currentWorkspace;
   542: 
   543:     r.left += offsetX * (ScreenWidth + 10);
   544:     r.top += offsetY * (ScreenHeight + 10);
   545: 
   546:     offsetX = ((r.left + 10) / (ScreenWidth + 10));
   547:     offsetY = ((r.top + 10) / (ScreenHeight + 10));
   548: 
   549:     workspace = (offsetY * pSettings->numberOfWorkspaces) + offsetX;
   550: 
   551:     if (workspace < 0 || workspace > pSettings->numberOfWorkspaces) workspace = pSettings->currentWorkspace;
   552: 
   553:     return workspace;
   554: }
   555: 
   556: //===========================================================================
   557: // Function: GatherWindows
   558: // Purpose: Moves all (top-level) windows to the current workspace
   559: //===========================================================================
   560: 
   561: void Workspaces::GatherWindows()
   562: {
   563:     dwp = BeginDeferWindowPos(0);
   564:     EnumWindows(EnumWindowsProc, (LPARAM)-1);
   565:     EndDeferWindowPos(dwp);
   566: 
   567:     if (pTaskbar)
   568:     {
   569:         for (int i = 0; i < (int)pTaskbar->taskList.size(); i++)
   570:         {
   571:             if (!CheckSticky(pTaskbar->taskList[i]->hwnd)) pTaskbar->taskList[i]->workspace = pSettings->currentWorkspace;
   572:         }
   573:     }
   574: 
   575:     if (!pSettings->accessLock)
   576:     {
   577:         // Update the toolbar... (including workspace label, taskbar if applicable, etc)
   578:         if (pToolbar) pToolbar->UpdatePosition();
   579:     }
   580: }
   581: 
   582: //===========================================================================
   583: // Functions: MoveWindowToWorkspace +
   584: //            MoveWindowToPreviousWorkspace / MoveWindowToNextWorkspace
   585: // Purpose: ...
   586: //===========================================================================
   587: 
   588: void Workspaces::MoveWindowToWorkspace(HWND window, int workspace)
   589: {
   590:     if (CheckSticky(window)) return;
   591:     if ((workspace < 0) || (workspace >= pSettings->numberOfWorkspaces)) return;
   592: 
   593:     SwitchToWorkspace(GetWorkspaceByWindow(window));
   594: //  BBSwitchToThisWindow(window, FALSE);
   595:     BringWindowToTop(window);
   596: 
   597:     MakeSticky(window);
   598:     SwitchToWorkspace(workspace);
   599:     RemoveSticky(window);
   600: 
   601:     if (pTaskbar)
   602:     {
   603:         int i = pTaskbar->FindTask(window);
   604:         if (i >= 0) pTaskbar->taskList[i]->workspace = workspace;
   605:     }
   606: 
   607:     if (!pSettings->accessLock)
   608:     {
   609:         // Do we need to update the toolbar?
   610:         if ((pSettings->taskbarMode != TASKBAR_MODE_HIDDEN) && pSettings->taskbarCurrentOnly && pToolbar)
   611:         {
   612:             pTaskbar->cachedTaskButtonsExist = false;
   613:             if (pToolbar) pToolbar->UpdatePosition();
   614:         }
   615:     }
   616: }
   617: 
   618: //====================
   619: 
   620: void Workspaces::MoveWindowToPreviousWorkspace(HWND window)
   621: {
   622:     int workspace;
   623:     if (pSettings->currentWorkspace == 0) workspace = pSettings->numberOfWorkspaces - 1;
   624:     else workspace = pSettings->currentWorkspace - 1;
   625:     MoveWindowToWorkspace(window, workspace);
   626: }
   627: 
   628: //====================
   629: 
   630: void Workspaces::MoveWindowToNextWorkspace(HWND window)
   631: {
   632:     int workspace;
   633:     if (pSettings->currentWorkspace == (pSettings->numberOfWorkspaces - 1)) workspace = 0;
   634:     else workspace = pSettings->currentWorkspace + 1;
   635:     MoveWindowToWorkspace(window, workspace);
   636: }
   637: 
   638: //===========================================================================
   639: