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 "Taskbar.h" 
    32: #include "../Menu/PreviewItem.h" 
    33: 
    34: extern Taskbar *pTaskbar;
    35: extern Toolbar* pToolbar;
    36: extern Settings *pSettings;
    37: extern Desktop * pDesktop;
    38: extern MenuCommon *pMenuCommon;
    39: extern PluginManager *pPluginManager;
    40: extern Tooltips *pTooltips;
    41: extern Workspaces *pWorkspaces;
    42: extern PreviewItem* pPreviewItem;
    43: 
    44: //===========================================================================
    45: 
    46: Taskbar::Taskbar()
    47: {
    48:     ZeroMemory(this, sizeof(Taskbar));
    49:     ZeroMemory(&taskList, sizeof(taskList));
    50: 
    51:     hBlackboxWnd = GetBBWnd();
    52: 
    53:     cachedTaskButtonActive = CreateCompatibleDC(NULL);
    54:     cachedTaskButtonInactive = CreateCompatibleDC(NULL);
    55:     cachedTaskButtonsExist = false;
    56: 
    57:     taskButtonsToDraw = taskButtonsOffset = 0;
    58:     taskButtonWidth = taskButtonHeight = taskButtonWidthMinusPadding = taskButtonHeightMinusPadding = 0;
    59: 
    60:     lastHoveredTaskButton = -1;
    61:     taskbarMouseHoverPoint.x = taskbarMouseHoverPoint.y = 0;
    62: 
    63:     blockNextMouseClick = false;
    64:     enumeratingTasks = false;
    65: }
    66: 
    67: //===========================================================================
    68: 
    69: Taskbar::~Taskbar()
    70: {
    71:     // Clear all elements in the taskList...
    72:     for (int i=0; i < (int)taskList.size(); i++)
    73:     {
    74: //      DestroyIcon(taskList[i]->icon);
    75:         delete taskList[i];
    76:         taskList.erase(taskList.begin() + i);
    77:     }
    78:     taskList.clear();
    79: 
    80:     // Delete cached bitmaps...
    81:     DeleteDC(cachedTaskButtonActive);
    82:     DeleteDC(cachedTaskButtonInactive);
    83: }
    84: 
    85: //===========================================================================
    86: 
    87: void Taskbar::InitializeTaskList()
    88: {
    89:     enumeratingTasks = true;
    90: //  if (pSettings->debugLogging) Log("==================== TASKBAR WINDOW ENUMERATION STARTING ====================", "");
    91:     EnumWindows(TaskEnumerator, 0);
    92: //  if (pSettings->debugLogging) Log("==================== TASKBAR WINDOW ENUMERATION FINISHED ====================", "");
    93:     enumeratingTasks = false;
    94:     CheckTaskListIntegrity();
    95:     SendMessage(hBlackboxWnd, BB_TASKSUPDATE, NULL, (LPARAM)TASKITEM_ADDED);
    96: }
    97: 
    98: BOOL CALLBACK TaskEnumerator(HWND window, LPARAM main)
    99: {
   100: /*
   101:     if (pSettings->debugLogging)
   102:     {
   103:         char msg[MAX_LINE_LENGTH], windowText[MAX_LINE_LENGTH], windowClass[MAX_LINE_LENGTH];
   104:         GetWindowText(window, windowText, sizeof(windowText));
   105:         if (!strnlen_s(windowText, sizeofArray(windowText))) strcpy_s(windowText, sizeofArray(windowText), "NULL");
   106:         GetClassName(window, windowClass, sizeof(windowClass));
   107:         if (!strnlen_s(windowClass, sizeofArray(windowClass))) strcpy_s(windowClass, sizeofArray(windowClass), "NULL");
   108:         sprintf_s(msg, sizeofArray(msg), "DEBUG -> Taskbar::TaskEnumerator -> %s | %s", windowText, windowClass);
   109:         Log(msg, "");
   110:     }
   111: */
   112:     pTaskbar->AddTask(window);
   113: 
   114:     return 1;
   115: }
   116: 
   117: //===========================================================================
   118: // Function: AddTask
   119: // Purpose:
   120: //===========================================================================
   121: 
   122: void Taskbar::AddTask(HWND window)
   123: {
   124:     if (!IsAppWindow(window)) return;
   125: 
   126:     // Check if the task is already present in the taskList...
   127:     int i = FindTask(window);
   128:     // ...and whether the task is a DWM cloaked window...
   129:     bool cloaked = CheckCloakedWindow(window);
   130: 
   131:     if (i != -1) // -> This is an *existing* task item, but check if any of its parameters need updating...
   132:     {
   133:         if (pSettings->debugLogging)
   134:         {
   135:             if (taskList[i]->hidden != cloaked)
   136:             {
   137:                 char msg[MAX_LINE_LENGTH], windowText[MAX_LINE_LENGTH];
   138:                 GetWindowText(window, windowText, sizeof(windowText));
   139:                 if (cloaked) sprintf_s(msg, sizeofArray(msg), "DEBUG -> Taskbar::AddTask -> Window cloaking! -> %s", windowText);
   140:                 else sprintf_s(msg, sizeofArray(msg), "DEBUG -> Taskbar::AddTask -> Window uncloaking! -> %s", windowText);
   141:                 SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
   142:                 Log(msg, "");
   143:             }
   144:         }
   145:         taskList[i]->hidden = cloaked;
   146:     }
   147:     else // -> This is a *new* task item, so let's add it to the taskList...
   148:     {
   149:         // ...but first, let's also check for various other types of rogue windows that don't belong on the taskbar...
   150:         char newWindowTemp[MAX_LINE_LENGTH];
   151:         GetClassName(window, newWindowTemp, MAX_LINE_LENGTH);
   152:         if (strnlen_s(newWindowTemp, sizeofArray(newWindowTemp)) == 0) return;
   153:         if (!_stricmp(newWindowTemp, "AcrobatOffscreenDocumentWnd")) return; // Check for Adobe Acrobat 7.0 offscreen windows...
   154:         bool isAppPlugin = (!_strnicmp(newWindowTemp, "BBAppPlugin", 11)); // Allow specific "application-like" plugins to show up on the taskbar...
   155: 
   156:         GetWindowText(window, newWindowTemp, sizeof(newWindowTemp));
   157:         if (strnlen_s(newWindowTemp, sizeofArray(newWindowTemp)) == 0) return;
   158:         // Check for Microsoft Powerpoint non-document windows...
   159:         // "Microsoft Powerpoint - [" or "Microsoft Office PowerPoint - ["
   160:         //  if (IsInString(newWindowTemp, " Powerpoint - [")) return;
   161: 
   162:         if (pSettings->debugLogging && !enumeratingTasks)
   163:         {
   164:             char msg[MAX_LINE_LENGTH], windowText[MAX_LINE_LENGTH];
   165:             GetWindowText(window, windowText, sizeof(windowText));
   166:             if (cloaked) sprintf_s(msg, sizeofArray(msg), "DEBUG -> Taskbar::AddTask -> Cloaked window found! -> %s", windowText);
   167:             else sprintf_s(msg, sizeofArray(msg), "DEBUG -> Taskbar::AddTask -> Uncloaked window found! -> %s", windowText);
   168:             SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
   169:             Log(msg, "");
   170:         }
   171: 
   172:         // Increase the "last used" counter for all other taskbar items...
   173:         for (int i = 0; i < (int)taskList.size(); i++) taskList[i]->lastUsed++;
   174: 
   175:         // -> All checks passed, so now we can create the new taskList item! :)
   176:         taskListItem *newTask = new taskListItem;
   177:         newTask->hwnd = window;
   178:         newTask->active = false;
   179: //      if (IsIconic(window)) newTask->workspace = 255;
   180: //      else newTask->workspace = pSettings->currentWorkspace;
   181:         newTask->workspace = pSettings->currentWorkspace;
   182:         if (cloaked) newTask->hidden = true;
   183:         else newTask->hidden = false;
   184: //      newTask->hidden = false;
   185:         newTask->isAppPlugin = isAppPlugin;
   186:         GetWindowText(window, newTask->captionANSI, 255); // -> ANSI representation
   187:         GetWindowTextW(window, newTask->captionUnicode, 255); // -> Unicode representation
   188:         newTask->lastUsed = 0; // ...because the new task is automatically also the most recently active task...
   189:         newTask->priorityClass = 0;
   190:         newTask->dimensions.placement = PLACEMENT_DEFAULT; // All windows start in the default non-tiled state
   191: 
   192:         DWORD pid = 0;
   193:         GetWindowThreadProcessId(window, &pid);
   194:         HANDLE windowProcessHandle = OpenProcess((PROCESS_QUERY_INFORMATION), FALSE, pid);
   195:         if (windowProcessHandle != NULL)
   196:         {
   197:             GetModuleFileNameEx(windowProcessHandle, NULL, newTask->path, sizeof(newTask->path));
   198:             CloseHandle(windowProcessHandle);
   199:         }
   200:         else newTask->path[0] = '\0';
   201: 
   202:         taskList.push_back(newTask);
   203:     }
   204: 
   205:     CheckTaskListIntegrity();
   206: 
   207:     //====================
   208: 
   209:     // Redraw the taskbar...
   210:     if (!enumeratingTasks)
   211:     {
   212:         if (i != -1) SendMessage(hBlackboxWnd, BB_TASKSUPDATE, NULL, (LPARAM)TASKITEM_REFRESH);
   213:         else SendMessage(hBlackboxWnd, BB_TASKSUPDATE, (WPARAM)window, (LPARAM)TASKITEM_ADDED);
   214:     }
   215: }
   216: 
   217: //===========================================================================
   218: // Function: RemoveTask
   219: // Purpose:
   220: //===========================================================================
   221: 
   222: void Taskbar::RemoveTask(HWND oldWindow)
   223: {
   224:     int i = FindTask(oldWindow);
   225:     if (i != -1)
   226:     {
   227:         // Task found in taskList, let's remove it + any associated tooltips...
   228: 
   229:         if (pSettings->debugLogging)
   230:         {
   231:             char msg[MAX_LINE_LENGTH], windowText[MAX_LINE_LENGTH];
   232:             GetWindowText(oldWindow, windowText, sizeof(windowText));
   233:             sprintf_s(msg, sizeofArray(msg), "DEBUG -> Taskbar::RemoveTask -> %s", windowText);
   234:             SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
   235:             Log(msg, "");
   236:         }
   237: 
   238:         if (pSettings->taskbarTooltips) pTooltips->DeleteToolTip((UINT)oldWindow, TOOLTIP_TYPE_TASK);
   239: 
   240: //      DestroyIcon(taskList[i]->icon);
   241:         delete taskList[i];
   242:         taskList.erase(taskList.begin() + i);
   243: 
   244:         CheckTaskListIntegrity();
   245: 
   246:         // Adjust the visible taskbar items if one of them was removed and we're at the *end* of
   247:         // the task list... (i.e. leave no gap at the end, adjust the offset backwards instead)
   248:         while ((FindLastVisible(FindFirstVisible()) < 0) && (taskButtonsOffset > 0)) taskButtonsOffset--;
   249: 
   250:         // Redraw the taskbar...
   251:         SendMessage(hBlackboxWnd, BB_TASKSUPDATE, (WPARAM)oldWindow, (LPARAM)TASKITEM_REMOVED);
   252:     }
   253: }
   254: 
   255: //===========================================================================
   256: // Function: FindTask
   257: // Purpose:
   258: //===========================================================================
   259: 
   260: int Taskbar::FindTask(HWND window)
   261: {
   262:     for (int i=0; i < (int)taskList.size(); i++)
   263:     {
   264:         if (taskList[i]->hwnd == window) return i;
   265:     }
   266: 
   267:     return -1;
   268: }
   269: 
   270: //===========================================================================
   271: // Function: CheckTaskListIntegrity
   272: // Purpose:
   273: //===========================================================================
   274: 
   275: void Taskbar::CheckTaskListIntegrity()
   276: {
   277:     // Look for zombie items in the taskList...
   278:     for (int i=0; i < (int)taskList.size(); i++)
   279:     {
   280:         if (!IsWindow(taskList[i]->hwnd))
   281:         {
   282:             if (pSettings->taskbarTooltips) pTooltips->DeleteToolTip((UINT)taskList[i]->hwnd, TOOLTIP_TYPE_TASK);
   283: 
   284: //          DestroyIcon(taskList[i]->icon);
   285:             delete taskList[i];
   286:             taskList.erase(taskList.begin() + i);
   287:         }
   288:     }
   289: 
   290: //  GetTaskButtonsToDraw();
   291: }
   292: 
   293: //===========================================================================
   294: // Function: SetActiveTask
   295: // Purpose:
   296: //===========================================================================
   297: 
   298: void Taskbar::SetActiveTask(HWND window)
   299: {
   300:     bool cloakingChanged = false;
   301: 
   302:     int i = FindTask(window);
   303: 
   304:     if (i != -1) // -> Focus has moved to an item shown on the taskbar...
   305:     {
   306:         // First, we hide any open and non-pinned menus as focus has moved to another application...
   307:         if (pMenuCommon) pMenuCommon->Hide();
   308: 
   309:         bool cloaked = CheckCloakedWindow(window);
   310: 
   311:         // Increase the "last used" counter for all other taskbar items...
   312:         for (int i = 0; i < (int)taskList.size(); i++) taskList[i]->lastUsed++; // (yes, I know this could in *theory* wrap around, but... ;))
   313: 
   314:         // Find the new active task... (and set all other tasks to inactive)
   315:         for (int i=0; i < (int)taskList.size(); i++)
   316:         {
   317:             if (taskList[i]->hwnd == window)
   318:             {
   319:                 taskList[i]->active = true;
   320:                 taskList[i]->lastUsed = 0; // Reset the "last used" counter for the new active item...
   321: /*
   322:                 if (pSettings->debugLogging)
   323:                 {
   324:                     if (taskList[i]->hidden != cloaked)
   325:                     {
   326:                         char msg[MAX_LINE_LENGTH], windowText[MAX_LINE_LENGTH];
   327:                         GetWindowText(window, windowText, sizeof(windowText));
   328:                         if (cloaked) sprintf_s(msg, sizeofArray(msg), "DEBUG -> Taskbar::SetActiveTask -> Window cloaking! -> %s", windowText);
   329:                         else sprintf_s(msg, sizeofArray(msg), "DEBUG -> Taskbar::SetActiveTask -> Window uncloaking! -> %s", windowText);
   330:                         // SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
   331:                         Log(msg, "");
   332:                     }
   333:                 }
   334: */
   335:                 if (taskList[i]->hidden != cloaked) cloakingChanged = true;
   336: //              taskList[i]->hidden = cloaked;
   337:                 taskList[i]->hidden = false; // Note: Necessary because some apps go active *before* they uncloak... (i.e. avoiding related taskbar update race conditions)
   338:             }
   339:             else taskList[i]->active = false;
   340:         }
   341: 
   342:         // Should we update the visible section of the taskbar to follow the newly active task?
   343:         if (pSettings->taskbarSorting == TASKBAR_SORT_FOLLOW_ACTIVE)
   344:         {
   345:             GetTaskButtonsToDraw();
   346:             int firstButton = FindFirstVisible();
   347:             int lastButton = FindLastVisible(firstButton);
   348:             if (lastButton < 0) lastButton = (int)taskList.size() - 1; // Failsafe
   349: 
   350:             if (i < firstButton)
   351:             {
   352:                 while ((i < firstButton) && (taskButtonsOffset > 0))
   353:                 {
   354:                     taskButtonsOffset--;
   355:                     firstButton = FindFirstVisible();
   356:                 }
   357:             }
   358:             else if (i > lastButton)
   359:             {
   360:                 while ((i > lastButton) && (taskButtonsOffset < ((int)taskList.size() - 1)))
   361:                 {
   362:                     taskButtonsOffset++;
   363:                     lastButton = FindLastVisible(FindFirstVisible());
   364:                 }
   365:                 if (lastButton < 0) taskButtonsOffset = 0; // Failsafe
   366:             }
   367:         }
   368:         else if (pSettings->taskbarSorting == TASKBAR_SORT_BY_LAST_USED)
   369:         {
   370: //          int i = FindFirstVisible();
   371: //          int centerX = taskList[i]->r.left + ((taskList[i]->r.right - taskList[i]->r.left) / 2);
   372: //          int centerY = taskList[i]->r.top + ((taskList[i]->r.bottom - taskList[i]->r.top) / 2);
   373: //          POINT pt = { centerX, centerY };
   374: //          ClientToScreen(pToolbar->hToolbarWnd, &pt);
   375: //          SetCursorPos(pt.x, pt.y);
   376: 
   377:             SortTaskbarItems(TASKBAR_SORT_BY_LAST_USED);
   378:             taskButtonsOffset = 0;
   379:         }
   380:         // else if (pSettings->taskbarSorting == TASKBAR_SORT_BY_NAME) SortTaskbarItems(TASKBAR_SORT_BY_NAME); // ...in the end not that attractive given that task titles may change over time... (kept only for future reference)
   381: 
   382:         // Since one task has become active and the others non-active
   383:         // we need to refresh all task buttons -> use NULL as WPARAM
   384: //      if (cloakingChanged) SendMessage(hBlackboxWnd, BB_TASKSUPDATE, NULL, (LPARAM)TASKITEM_REFRESH);
   385: //      else SendMessage(hBlackboxWnd, BB_TASKSUPDATE, (WPARAM)window, (LPARAM)TASKITEM_ACTIVATED);
   386:         SendMessage(hBlackboxWnd, BB_TASKSUPDATE, (WPARAM)window, (LPARAM)TASKITEM_ACTIVATED);
   387:     }
   388:     else // -> Focus has moved to something not shown on the taskbar... (e.g. *box UI element)
   389:     {
   390:         bool foundActive = false;
   391: 
   392:         for (int i=0; i < (int)taskList.size(); i++)
   393:         {
   394:             if (taskList[i]->active) foundActive = true;
   395:             taskList[i]->active = false;
   396:         }
   397: 
   398:         if (foundActive) SendMessage(hBlackboxWnd, BB_TASKSUPDATE, NULL, (LPARAM)TASKITEM_ACTIVATED);
   399:     }
   400: }
   401: 
   402: //===========================================================================
   403: // Function: GetActiveTask / GetActiveWindow
   404: // Purpose:
   405: //===========================================================================
   406: 
   407: int Taskbar::GetActiveTask()
   408: {
   409:     // Find the currently active task...
   410:     for (int i=0; i < (int)taskList.size(); i++)
   411:     {
   412:         if (taskList[i]->active) return i;
   413:     }
   414: 
   415:     return NULL;
   416: }
   417: 
   418: HWND Taskbar::GetActiveWindow()
   419: {
   420:     // Find the currently active window...
   421:     for (int i=0; i < (int)taskList.size(); i++)
   422:     {
   423:         if (taskList[i]->active) return taskList[i]->hwnd;
   424:     }
   425: 
   426:     return NULL;
   427: }
   428: 
   429: //===========================================================================
   430: // Function: RedrawTask
   431: // Purpose:
   432: //===========================================================================
   433: 
   434: void Taskbar::RedrawTask(HWND window)
   435: {
   436:     int i = FindTask(window);
   437:     if (i != -1)
   438:     {
   439:         bool cloaked = CheckCloakedWindow(window);
   440: 
   441:         bool cloakingChanged = false;
   442:         if (taskList[i]->hidden != cloaked) cloakingChanged = true;
   443:         taskList[i]->hidden = cloaked;
   444: 
   445:         if (pSettings->debugLogging && cloakingChanged)
   446:         {
   447:             char msg[MAX_LINE_LENGTH], windowText[MAX_LINE_LENGTH];
   448:             GetWindowText(window, windowText, sizeof(windowText));
   449:             if (cloaked) sprintf_s(msg, sizeofArray(msg), "DEBUG -> Taskbar::RedrawTask -> Window cloaking! -> %s", windowText);
   450:             else sprintf_s(msg, sizeofArray(msg), "DEBUG -> Taskbar::RedrawTask -> Window uncloaking! -> %s", windowText);
   451:             SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
   452:             Log(msg, "");
   453:         }
   454: 
   455:         // if ((pSettings->taskbarMode != TASKBAR_MODE_HIDDEN) && pToolbar) InvalidateRect(pToolbar->hToolbarWnd, &taskList[i]->r, false);
   456: 
   457:         if (cloakingChanged) SendMessage(hBlackboxWnd, BB_TASKSUPDATE, NULL, (LPARAM)TASKITEM_REFRESH);
   458:         else if (!cloaked)
   459:         {
   460:             GetWindowText(taskList[i]->hwnd, taskList[i]->captionANSI, 255); // -> ANSI representation
   461:             GetWindowTextW(taskList[i]->hwnd, taskList[i]->captionUnicode, 255); // -> Unicode representation
   462: 
   463:             if (flashingHwnd != 0) SendMessage(hBlackboxWnd, BB_TASKSUPDATE, (WPARAM)taskList[i]->hwnd, (LPARAM)TASKITEM_FLASHED);
   464:             else SendMessage(hBlackboxWnd, BB_TASKSUPDATE, (WPARAM)taskList[i]->hwnd, (LPARAM)TASKITEM_MODIFIED);
   465:         }
   466:     }
   467:     else
   468:     {
   469: /*
   470:         if (pSettings->debugLogging)
   471:         {
   472:             char msg[MAX_LINE_LENGTH], windowText[MAX_LINE_LENGTH];
   473:             GetWindowText(window, windowText, sizeof(windowText));
   474:             sprintf_s(msg, sizeofArray(msg), "DEBUG -> Taskbar::RedrawTask -> Task not found, redirecting to AddTask... -> %s", windowText);
   475:             // SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
   476:             Log(msg, "");
   477:         }
   478: */
   479:         // The task to be redrawn wasn't present in the taskList for some reason, so let's add it... (nb. AddTask will perform IsAppWindow() etc checks itself)
   480:         AddTask(window);
   481:     }
   482: }
   483: 
   484: //===========================================================================
   485: // Function: ActivateShellWindow
   486: // Purpose:
   487: //===========================================================================
   488: 
   489: void Taskbar::ActivateShellWindow()
   490: {
   491:     for (int i=0; i < (int)taskList.size(); i++)
   492:     {
   493:         taskList[i]->active = false;
   494:     }
   495: 
   496: //  SetForegroundWindow(hBlackboxWnd);
   497: 
   498:     // Since all tasks have become non-active we need
   499:     // to refresh all task buttons -> use NULL as WPARAM
   500:     SendMessage(hBlackboxWnd, BB_TASKSUPDATE, NULL, (LPARAM)TASKITEM_ACTIVATED);
   501: }
   502: 
   503: //===========================================================================
   504: // Function: MinimizeAllWindows
   505: // Purpose:
   506: //===========================================================================
   507: 
   508: void Taskbar::MinimizeAllWindows()
   509: {
   510:     // Minimize all windows...
   511:     for (int i=0; i < (int)taskList.size(); i++)
   512:     {
   513: //      if (!IsIconic(taskList[i]->hwnd)) ShowWindow(taskList[i]->hwnd, SW_MINIMIZE);
   514:         ShowWindow(taskList[i]->hwnd, SW_MINIMIZE);
   515: //      if (taskList[i]->isAppPlugin) SendMessage(taskList[i]->hwnd, BB_BROADCAST, 0, (LPARAM)"@AppPlugin Hide");
   516: //      else ShowWindow(taskList[i]->hwnd, SW_MINIMIZE);
   517:         taskList[i]->active = false;
   518:     }
   519: 
   520:     // Since all tasks have become non-active we need
   521:     // to refresh all task buttons -> use NULL as WPARAM
   522:     SendMessage(hBlackboxWnd, BB_TASKSUPDATE, NULL, (LPARAM)TASKITEM_ACTIVATED);
   523: 
   524:     // Finally, we trigger the "minimize" message...
   525:     SendMessage(hBlackboxWnd, BB_WINDOWMINIMIZE, 0, (LPARAM)taskList[0]->hwnd);
   526:     PlaySoundFX(SFX_TASKBAR_MINIMIZE);
   527: }
   528: 
   529: //===========================================================================
   530: // Function: RestoreAllWindows
   531: // Purpose:
   532: //===========================================================================
   533: 
   534: void Taskbar::RestoreAllWindows()
   535: {
   536:     // Find the currently active window so we can
   537:     // focus it again after restoring all windows...
   538:     HWND activeWindow = GetActiveWindow();
   539: 
   540:     //====================
   541: 
   542:     // Restore all windows... (except DWM cloaked ones)
   543:     for (int i=0; i < (int)taskList.size(); i++)
   544:     {
   545: //      if (IsIconic(taskList[i]->hwnd) && !CheckCloakedWindow(taskList[i]->hwnd))
   546:         if (IsIconic(taskList[i]->hwnd) && !taskList[i]->hidden)
   547:         {
   548:             if (taskList[i]->isAppPlugin) SendMessage(taskList[i]->hwnd, BB_BROADCAST, 0, (LPARAM)"@AppPlugin Show");
   549:             else ShowWindow(taskList[i]->hwnd, SW_RESTORE);
   550:         }
   551:     }
   552: 
   553:     //====================
   554: 
   555:     // If we had an active window to begin with we now focus it again...
   556:     if (activeWindow != NULL)
   557:     {
   558:         SetForegroundWindow(activeWindow);
   559:         SendMessage(hBlackboxWnd, BB_BRINGTOFRONT, 0, (LPARAM)activeWindow);
   560:     }
   561: 
   562:     PlaySoundFX(SFX_TASKBAR_RESTORE);
   563: }
   564: 
   565: //===========================================================================
   566: // Function: DropFiles
   567: // Purpose:
   568: //===========================================================================
   569: 
   570: int Taskbar::DropFiles(HWND hwnd, WPARAM wParam, bool checkTaskbarDrop)
   571: {
   572:     if (checkTaskbarDrop)
   573:     {
   574:         if (MouseButtonOnTaskbar(hwnd, WM_DROPFILES, wParam, NULL)) return 0;
   575:     }
   576: 
   577:     return ParseDropFiles(hwnd, wParam);
   578: }
   579: 
   580: //===========================================================================
   581: // Function: MouseButtonOnTaskbar
   582: // Purpose: ...
   583: //===========================================================================
   584: 
   585: bool Taskbar::MouseButtonOnTaskbar(HWND hwnd, unsigned int message, WPARAM wParam, LPARAM lParam)
   586: {
   587:     POINT pt;
   588: 
   589:     if (message == WM_DROPFILES)
   590:     {
   591:         // Drag'n'drop of files onto a task button...
   592:         GetCursorPos(&pt);
   593:         ScreenToClient(hwnd, &pt);
   594:     }
   595:     else
   596:     {
   597:         // Regular mouse clicks on a task button...
   598:         pt.x = LOWORD(lParam);
   599:         pt.y = HIWORD(lParam);
   600:     }
   601: 
   602:     if (!PtInRect(&TaskbarRect, pt)) return false;
   603: 
   604:     //====================
   605: 
   606:     HWND window;
   607: 
   608:     for (int i = FindFirstVisible(); i < (int)taskList.size(); i++)
   609:     {
   610:         // Should we exclude tasks not on the current workspace? (-> user configurable "current workspace only" taskbar setting)
   611:         if (!OnCurrentWorkspace(taskList[i]->hwnd)) continue;
   612: 
   613:         //====================
   614: 
   615:         if (PtInRect(&taskList[i]->r, pt))
   616:         {
   617:             switch (message)
   618:             {
   619:                 //====================
   620: 
   621:                 case WM_LBUTTONDOWN:
   622:                 {
   623:                     if (pMenuCommon) pMenuCommon->Hide();
   624: 
   625:                     if (GetAsyncKeyState(VK_CONTROL) & 0x8000) // -> Ctrl+Left click on the task button
   626:                     {
   627:                         // Toggle the window's stickiness... (i.e. whether it should be visible on all workspaces or not)
   628:                         if (!CheckSticky(taskList[i]->hwnd))
   629:                         {
   630:                             MakeSticky(taskList[i]->hwnd);
   631:                             taskList[i]->workspace = 254; // -> Visible on all workspaces! ("sticky")
   632:                         }
   633:                         else
   634:                         {
   635:                             RemoveSticky(taskList[i]->hwnd);
   636:                             taskList[i]->workspace = pSettings->currentWorkspace; // -> Visible only on the current workspace! ("non-sticky")
   637:                         }
   638: /*
   639:                         window = taskList[i]->hwnd;
   640:                         if (IsIconic(window))
   641:                         {
   642:                             if (taskList[i]->isAppPlugin) SendMessage(window, BB_BROADCAST, 0, (LPARAM)"@AppPlugin Show");
   643:                             else ShowWindow(window, SW_RESTORE);
   644:                             if (!CheckSticky(taskList[i]->hwnd)) taskList[i]->workspace = pSettings->currentWorkspace;
   645:                         }
   646:                         SetForegroundWindow(window);
   647:                         SendMessage(hBlackboxWnd, BB_BRINGTOFRONT, 0, (LPARAM)window);
   648: */
   649: /*
   650:                         if (pSettings->debugLogging)
   651:                         {
   652:                             char msg[MAX_LINE_LENGTH];
   653:                             if (CheckSticky(window)) sprintf_s(msg, sizeofArray(msg), "Taskbar -> %s -> Sticky! (on all workspaces)", taskList[i]->captionANSI);
   654:                             else sprintf_s(msg, sizeofArray(msg), "Taskbar -> %s -> Located on workspace #%d", taskList[i]->captionANSI, taskList[i]->workspace+1);
   655:                             SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
   656:                         }
   657: */
   658:                         PlaySoundFX(SFX_TOGGLE_ELEMENT);
   659:                     }
   660: 
   661:                     // First we show and focus the window in question...
   662:                     window = taskList[i]->hwnd;
   663:                     if (IsIconic(window)) ShowWindow(window, SW_RESTORE);
   664: //                  if (taskList[i]->isAppPlugin) SendMessage(window, BB_BROADCAST, 0, (LPARAM)"@AppPlugin Show");
   665: //                  else if (IsIconic(window)) ShowWindow(window, SW_RESTORE);
   666:                     SetForegroundWindow(window);
   667:                     SendMessage(hBlackboxWnd, BB_BRINGTOFRONT, 0, (LPARAM)window);
   668: /*
   669:                     if (GetAsyncKeyState(VK_MENU) & 0x8000)
   670:                     {
   671: 
   672:                         if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
   673:                         {
   674:                             window = taskList[i]->hwnd;
   675:                             if (taskList[i]->isAppPlugin) SendMessage(window, BB_BROADCAST, 0, (LPARAM)"@AppPlugin Show");
   676:                             else if (IsIconic(window)) ShowWindow(window, SW_RESTORE);
   677:                             SetForegroundWindow(window);
   678:                             SendMessage(hBlackboxWnd, BB_BRINGTOFRONT, 0, (LPARAM)window);
   679:                             PostMessage(window, WM_SYSCOMMAND, SC_MOVE, 0);
   680:                         }
   681:                         else RestoreAllWindows();
   682:                     }
   683: */
   684:                     if (GetAsyncKeyState(VK_MENU) & 0x8000) // -> Alt+Left click on the task button
   685:                     {
   686:                         if (!CheckSticky(taskList[i]->hwnd))
   687:                         {
   688:                             // Move the window to the next workspace...
   689:                             SendMessage(hBlackboxWnd, BB_BRINGTOFRONT, 0, (LPARAM)window);
   690:                             MakeSticky(window);
   691:                             pWorkspaces->NextWorkspace();
   692:                             RemoveSticky(window);
   693:                             taskList[i]->workspace = pSettings->currentWorkspace;
   694:                         }
   695: 
   696:                         PlaySoundFX(SFX_TOGGLE_ELEMENT);
   697:                     }
   698:                     else if (GetAsyncKeyState(VK_SHIFT) & 0x8000) // -> Shift+Left click on the task button
   699:                     {
   700:                         // Toggle the priority class of the window's parent process... (Default<->High)
   701:                         DWORD pid = 0;
   702:                         GetWindowThreadProcessId(taskList[i]->hwnd, &pid);
   703:                         HANDLE h = OpenProcess((PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION), TRUE, pid);
   704:                         if (taskList[i]->priorityClass == 0)
   705:                         {
   706:                             taskList[i]->priorityClass = GetPriorityClass(h);
   707:                             SetPriorityClass(h, HIGH_PRIORITY_CLASS);
   708:                         }
   709:                         else
   710:                         {
   711:                             SetPriorityClass(h, taskList[i]->priorityClass);
   712:                             taskList[i]->priorityClass = 0;
   713:                         }
   714:                         CloseHandle(h);
   715: 
   716:                         PlaySoundFX(SFX_TOGGLE_ELEMENT);
   717:                     }
   718:                     else // -> Left click on the task button (no keyboard modifiers)
   719:                     {
   720:                         // ...no specific action needed here, as we've already made the window visible above...
   721: 
   722:                         PlaySoundFX(SFX_TASKBAR_RESTORE);
   723:                     }
   724: 
   725:                     return true;
   726:                 }
   727:                 break;
   728: 
   729:                 //====================
   730: 
   731:                 case WM_LBUTTONUP:
   732:                 case WM_LBUTTONDBLCLK:
   733:                 {
   734:                     return true;
   735:                 }
   736:                 break;
   737: 
   738:                 //====================
   739: 
   740:                 case WM_RBUTTONDOWN:   // -> Minimize window...
   741:                 {
   742:                     if (GetAsyncKeyState(VK_MENU) & 0x8000) // -> Alt+Right click on the task button
   743:                     {
   744:                         MinimizeAllWindows();
   745:                         PlaySoundFX(SFX_TASKBAR_MINIMIZE);
   746:                     }
   747: /*
   748:                     {
   749:                         if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
   750:                         {
   751:                             window = taskList[i]->hwnd;
   752:                             if (taskList[i]->isAppPlugin) SendMessage(window, BB_BROADCAST, 0, (LPARAM)"@AppPlugin Show");
   753:                             else if (IsIconic(window)) ShowWindow(window, SW_RESTORE);
   754:                             SetForegroundWindow(window);
   755:                             SendMessage(hBlackboxWnd, BB_BRINGTOFRONT, 0, (LPARAM)window);
   756:                             PostMessage(window, WM_SYSCOMMAND, SC_SIZE, 0);
   757:                         }
   758:                         else MinimizeAllWindows();
   759:                     }
   760: */
   761:                     else if (GetAsyncKeyState(VK_CONTROL) & 0x8000) // -> Ctrl+Right click on the task button
   762:                     {
   763:                         return true; // Unassigned (for now at least)
   764:                     }
   765:                     else if (GetAsyncKeyState(VK_SHIFT) & 0x8000) // -> Shift+Right click on the task button
   766:                     {
   767:                         return true; // Pass through -> Show the configuration menu on RBUTTONUP, see below!
   768:                     }
   769:                     else // -> Right click on the task button (no keyboard modifiers)
   770:                     {
   771:                         if ((message == WM_RBUTTONDOWN) && pSettings->taskbarCurrentOnly && (taskButtonsToDraw == 1)) blockNextMouseClick = true;
   772: 
   773:                         // Minimize the window...
   774:                         window = taskList[i]->hwnd;
   775:                         if (!IsIconic(window)) ShowWindow(window, SW_MINIMIZE);
   776: //                      if (taskList[i]->isAppPlugin) SendMessage(window, BB_BROADCAST, 0, (LPARAM)"@AppPlugin Hide");
   777: //                      else if (!IsIconic(window)) ShowWindow(window, SW_MINIMIZE);
   778:                         taskList[i]->active = false;
   779: //                      taskList[i]->workspace = 255;
   780:                         SendMessage(hBlackboxWnd, BB_WINDOWMINIMIZE, 0, (LPARAM)window);
   781: 
   782: //                      if ((pSettings->taskbarMode != TASKBAR_MODE_HIDDEN) && pToolbar) InvalidateRect(pToolbar->hToolbarWnd, &pTaskbar->taskList[i]->r, false);
   783:                         if (pSettings->taskbarMode != TASKBAR_MODE_HIDDEN) SendMessage(hBlackboxWnd, BB_TASKSUPDATE, (WPARAM)taskList[i]->hwnd, (LPARAM)TASKITEM_MODIFIED);
   784: 
   785:                         PlaySoundFX(SFX_TASKBAR_MINIMIZE);
   786:                     }
   787: 
   788:                     return true;
   789:                 }
   790:                 break;
   791: 
   792:                 //====================
   793: 
   794:                 case WM_RBUTTONUP: // Only show menus on RButtonUp...
   795:                 {
   796:                     if (GetAsyncKeyState(VK_SHIFT) & 0x8000) SendMessage(GetBBWnd(), BB_MENU, 2, 0);
   797:                     return true;
   798:                 }
   799:                 break;
   800: 
   801:                 //====================
   802: 
   803:                 case WM_MBUTTONDOWN:
   804:                 {
   805:                     if (pMenuCommon) pMenuCommon->Hide();
   806: 
   807:                     // First we show and focus the window in question...
   808:                     window = taskList[i]->hwnd;
   809:                     if (taskList[i]->isAppPlugin) SendMessage(window, BB_BROADCAST, 0, (LPARAM)"@AppPlugin Show");
   810:                     else if (IsIconic(window)) ShowWindow(window, SW_RESTORE);
   811:                     SetForegroundWindow(window);
   812:                     SendMessage(hBlackboxWnd, BB_BRINGTOFRONT, 0, (LPARAM)window);
   813: 
   814:                     if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
   815:                     {
   816: /*
   817:                         if (GetAsyncKeyState(VK_MENU) & 0x8000) // -> Alt+Shift+Mid click on the task button
   818:                         {
   819:                             SendMessage(hBlackboxWnd, BB_BROADCAST, 0, (LPARAM)"@xoblite Window Tile Bottom");
   820:                         }
   821:                         else SendMessage(hBlackboxWnd, BB_BROADCAST, 0, (LPARAM)"@xoblite Window Tile Top"); // -> Shift+Mid click on the task button
   822: */
   823:                         switch (taskList[i]->dimensions.placement)
   824:                         {
   825:                             case PLACEMENT_DEFAULT:         { TileWindow(PLACEMENT_LEFT_HALF); break; }
   826:                             case PLACEMENT_LEFT_HALF:       { TileWindow(PLACEMENT_RIGHT_HALF); break; }
   827:                             case PLACEMENT_RIGHT_HALF:      { TileWindow(PLACEMENT_TOP_HALF); break; }
   828:                             case PLACEMENT_TOP_HALF:        { TileWindow(PLACEMENT_BOTTOM_HALF); break; }
   829:                             case PLACEMENT_BOTTOM_HALF:     { TileWindow(PLACEMENT_LEFT_HALF); break; }
   830:                             default:                        { TileWindow(PLACEMENT_DEFAULT); break; }
   831:                         }
   832: 
   833:                         PlaySoundFX(SFX_TASKBAR_TILE);
   834:                     }
   835:                     else if (GetAsyncKeyState(VK_CONTROL) & 0x8000) // -> Ctrl+Mid click on the task button
   836:                     {
   837:                         SendMessage(hBlackboxWnd, BB_BROADCAST, 0, (LPARAM)"@xoblite Window Tile Left");
   838:                     }
   839:                     else if (GetAsyncKeyState(VK_MENU) & 0x8000) // -> Alt+Mid click on the task button
   840:                     {
   841:                         SendMessage(hBlackboxWnd, BB_BROADCAST, 0, (LPARAM)"@xoblite Window Tile Right");
   842:                     }
   843: /*
   844:                     if (GetAsyncKeyState(VK_MENU) & 0x8000) // -> Alt+Mid click on the task button
   845:                     {
   846:                         // Shade/unshade the window...
   847:                         if (taskList[i]->isAppPlugin) SendMessage(window, BB_BROADCAST, 0, (LPARAM)"@AppPlugin ToggleShaded");
   848:                         else if (pDesktop) pDesktop->ShadeWindow();
   849:                         PlaySoundFX(SFX_TASKBAR_ZOOM); // ...assign a unique SFX later? (TBD)
   850:                     }
   851:                     else if (GetAsyncKeyState(VK_CONTROL) & 0x8000) // -> Ctrl+Mid click on the task button
   852:                     {
   853:                         if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
   854:                         {
   855:                             if (!CheckSticky(taskList[i]->hwnd))
   856:                             {
   857:                                 MakeSticky(taskList[i]->hwnd);
   858:                                 taskList[i]->workspace = 254; // Visible on all workspaces
   859:                             }
   860:                             else
   861:                             {
   862:                                 RemoveSticky(taskList[i]->hwnd);
   863:                                 taskList[i]->workspace = pSettings->currentWorkspace;
   864:                             }
   865:                         }
   866:                         else if (!CheckSticky(taskList[i]->hwnd))
   867:                         {
   868:                             // Move the window to the next/previous workspace...
   869:                             SendMessage(hBlackboxWnd, BB_BRINGTOFRONT, 0, (LPARAM)window);
   870:                             MakeSticky(window);
   871:                             if (GetAsyncKeyState(VK_MENU) & 0x8000) pWorkspaces->PreviousWorkspace();
   872:                             else pWorkspaces->NextWorkspace();
   873:                             RemoveSticky(window);
   874:                             taskList[i]->workspace = pSettings->currentWorkspace;
   875: 
   876: //                          if (GetAsyncKeyState(VK_MENU) & 0x8000) pWorkspaces->MoveWindowToPreviousWorkspace(window);
   877: //                          else pWorkspaces->MoveWindowToNextWorkspace(window);
   878:                         }
   879: 
   880:                         SendMessage(hBlackboxWnd, BB_BROADCAST, 0, (LPARAM)"@xoblite Window Tile Left"); // Temporary (for now at least)
   881:                         return true; // Unassigned (for now at least)
   882:                     }
   883:                     else if (GetAsyncKeyState(VK_SHIFT) & 0x8000) // -> Shift+Mid click on the task button
   884:                     {
   885: /*
   886:                         if (!taskList[i]->isAppPlugin)
   887:                         {
   888:                             // Close the application...
   889:                             window = taskList[i]->hwnd;
   890:                             if (IsIconic(window)) ShowWindow(window, SW_RESTORE);
   891:                             SetForegroundWindow(window);
   892:                             PostMessage(window, WM_SYSCOMMAND, SC_CLOSE, 0);
   893:                         }
   894: 
   895:                         SendMessage(hBlackboxWnd, BB_BROADCAST, 0, (LPARAM)"@xoblite Window Tile Right"); // Temporary (for now at least)
   896:                         return true; // Unassigned (for now at least)
   897:                     }
   898: */
   899:                     else // -> Mid click on the task button (no keyboard modifiers)
   900:                     {
   901:                         // Toggle the window maximized/restored... (i.e. equivalent to clicking the window's "zoom" button)
   902: 
   903:                         if (taskList[i]->dimensions.placement != PLACEMENT_DEFAULT)
   904:                         {
   905:                             pTaskbar->TileWindow(PLACEMENT_DEFAULT);
   906:                             PlaySoundFX(SFX_TASKBAR_TILE);
   907:                         }
   908:                         else
   909:                         {
   910:                             if (taskList[i]->isAppPlugin)
   911:                             {
   912:                                 SendMessage(window, BB_BROADCAST, 0, (LPARAM)"@AppPlugin ToggleMaximized");
   913:                             }
   914:                             else if (IsZoomed(window))
   915:                             {
   916:                                 ShowWindow(window, SW_RESTORE);
   917: /*
   918:                                 if (pSettings->desktopAreaDefined) // ...JUST TESTING SOME STUFF... ;)
   919:                                 {
   920:                                     RECT workArea;
   921:                                     SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&workArea, SPIF_SENDCHANGE);
   922:                                     int newWindowX = workArea.left + pSettings->desktopArea.left;
   923:                                     int newWindowY = workArea.top + pSettings->desktopArea.top;
   924:                                     int newWindowWidth = (workArea.right - workArea.left) - pSettings->desktopArea.left - pSettings->desktopArea.right;
   925:                                     int newWindowHeight = (workArea.bottom - workArea.top) - pSettings->desktopArea.top - pSettings->desktopArea.bottom;
   926:                                     SetWindowPos(window, NULL, newWindowX, newWindowY, newWindowWidth, newWindowHeight, SWP_SHOWWINDOW | SWP_NOZORDER);
   927:                                 }
   928: */
   929:                             }
   930:                             else ShowWindow(window, SW_MAXIMIZE);
   931: 
   932:                             PlaySoundFX(SFX_TASKBAR_ZOOM);
   933:                         }
   934:                     }
   935: 
   936:                     return true;
   937:                 }
   938:                 break;
   939: 
   940:                 //====================
   941: 
   942:                 case WM_MBUTTONUP: 
   943:                 {
   944:                     return true;
   945:                 }
   946:                 break;
   947: 
   948:                 //====================
   949: 
   950:                 case WM_XBUTTONDOWN:
   951:                 {
   952:                     if (pMenuCommon) pMenuCommon->Hide();
   953: 
   954:                     // First we show and focus the window in question...
   955:                     window = taskList[i]->hwnd;
   956:                     if (taskList[i]->isAppPlugin) SendMessage(window, BB_BROADCAST, 0, (LPARAM)"@AppPlugin Show");
   957:                     else if (IsIconic(window)) ShowWindow(window, SW_RESTORE);
   958:                     SetForegroundWindow(window);
   959:                     SendMessage(hBlackboxWnd, BB_BRINGTOFRONT, 0, (LPARAM)window);
   960: 
   961:                     if (HIWORD(wParam) == XBUTTON1)
   962:                     {
   963:                         if (GetAsyncKeyState(VK_MENU) & 0x8000) // -> Alt+X1 click on the task button
   964:                         {
   965:                             SendMessage(hBlackboxWnd, BB_BROADCAST, 0, (LPARAM)"@xoblite Window Tile Right"); // Temporary (for now at least)
   966:                         }
   967:                         else // -> X1 click on the task button (no keyboard modifiers)
   968:                         {
   969:                             if (!CheckSticky(taskList[i]->hwnd))
   970:                             {
   971:                                 // Move the window to the *previous* workspace...
   972:                                 MakeSticky(window);
   973:                                 pWorkspaces->PreviousWorkspace();
   974:                                 RemoveSticky(window);
   975:                                 taskList[i]->workspace = pSettings->currentWorkspace;
   976:                             }
   977:                         }
   978:                     }
   979:                     else if (HIWORD(wParam) == XBUTTON2)
   980:                     {
   981:                         if (GetAsyncKeyState(VK_MENU) & 0x8000) // -> Alt+X2 click on the task button
   982:                         {
   983:                             SendMessage(hBlackboxWnd, BB_BROADCAST, 0, (LPARAM)"@xoblite Window Tile Left"); // Temporary (for now at least)
   984:                         }
   985:                         else // -> X2 click on the task button (no keyboard modifiers)
   986:                         {
   987:                             if (!CheckSticky(taskList[i]->hwnd))
   988:                             {
   989:                                 // Move the window to the *next* workspace...
   990:                                 MakeSticky(window);
   991:                                 pWorkspaces->NextWorkspace();
   992:                                 RemoveSticky(window);
   993:                                 taskList[i]->workspace = pSettings->currentWorkspace;
   994:                             }
   995:                         }
   996:                     }
   997: 
   998:                     return true;
   999:                 }
  1000:                 break;
  1001: 
  1002:                 case WM_XBUTTONUP: { } break;
  1003: 
  1004:                 //====================
  1005: 
  1006:                 case WM_DROPFILES:
  1007:                 {
  1008:                     // Drag'n'drop of file(s) onto the task button:
  1009:                     // -> Forward the drag'n'drop information to the window in question...
  1010:                     window = taskList[i]->hwnd;
  1011:                     if (taskList[i]->isAppPlugin) SendMessage(window, BB_BROADCAST, 0, (LPARAM)"@AppPlugin Show");
  1012:                     else if (IsIconic(window)) ShowWindow(window, SW_RESTORE);
  1013:                     SetForegroundWindow(window);
  1014:                     SendMessage(hBlackboxWnd, BB_BRINGTOFRONT, 0, (LPARAM)window);
  1015: 
  1016:                     PostMessage(window, WM_DROPFILES, wParam, lParam);
  1017: 
  1018:                     return true;
  1019:                 }
  1020:                 break;
  1021: 
  1022:                 //====================
  1023:             }
  1024:         }
  1025:     }
  1026: 
  1027:     return false;
  1028: }
  1029: 
  1030: //===========================================================================
  1031: // Function: DrawTaskbar
  1032: // Purpose: ...
  1033: //===========================================================================
  1034: 
  1035: void Taskbar::DrawTaskbar(HDC hdc, int iconPos, RECT taskbarRect)
  1036: {
  1037:     CopyRect(&TaskbarRect, &taskbarRect);
  1038:     activeTaskAvailable = false;
  1039: 
  1040:     // Reset flash indicator if flashing is disabled...
  1041:     if (!pSettings->taskbarFlashing) flashingHwnd = 0;
  1042: 
  1043:     //====================
  1044: 
  1045:     if (!pSettings->toolbarVertical)
  1046:     {
  1047:         // Failsafe: Abort if the taskbar is not wide enough to fit all the task buttons... (nb. quite simplistic implementation at the moment)
  1048:         if ((TaskbarRect.right - TaskbarRect.left) < (taskButtonsToDraw*16)) return;
  1049:     }
  1050: 
  1051:     //====================
  1052: 
  1053:     // Get the number of task buttons to draw...
  1054:     GetTaskButtonsToDraw();
  1055: 
  1056:     if ((taskButtonsToDraw == 0) && (pSettings->taskbarMode != TASKBAR_MODE_HIDDEN))
  1057:     {
  1058:         HFONT font = CreateFont(pSettings->Toolbar->FontHeight, 0, 0, 0, pSettings->Toolbar->FontWeight, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, pSettings->Toolbar->Font);
  1059:         HGDIOBJ oldfont = SelectObject(hdc, font);
  1060:         SetBkMode(hdc, TRANSPARENT);
  1061: 
  1062:         SetTextColor(hdc, pSettings->Toolbar->TextColor);
  1063: 
  1064:         unsigned int format = DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS;
  1065: 
  1066:         int totalNumberOfTasks = 0;
  1067:         if (pSettings->taskbarCurrentOnly)
  1068:         {
  1069:             for (int i = 0; i < (int)taskList.size(); i++)
  1070:             {
  1071:                 if (!taskList[i]->hidden) totalNumberOfTasks++;
  1072:             }
  1073:         }
  1074: 
  1075:         if (pSettings->taskbarCurrentOnly && (totalNumberOfTasks > 0))
  1076:         {
  1077:             // -> There are no tasks on the current workspace, but there are on other workspaces...
  1078: //          DrawText(hdc, "(No tasks on this workspace)", strlen("(No tasks on this workspace)"), &TaskbarRect, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS);
  1079:             DrawTextWithEffects(hdc, TaskbarRect, "(No tasks on this workspace)", format, pSettings->Toolbar->TextColor, pSettings->Toolbar->FontOutline, pSettings->Toolbar->OutlineColor, pSettings->Toolbar->FontShadow, pSettings->Toolbar->ShadowColor, pSettings->Toolbar->ShadowX, pSettings->Toolbar->ShadowY);
  1080:         }
  1081:         else
  1082:         {
  1083:             // -> There are no tasks on the current or any other workspace, so let's advertise the shell instead... ;)
  1084: //          DrawText(hdc, "xoblite", strlen("xoblite"), &TaskbarRect, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS);
  1085: //          DrawText(hdc, "Welcome to xoblite.", strlen("Welcome to xoblite."), &TaskbarRect, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS);
  1086:             DrawTextWithEffects(hdc, TaskbarRect, "Welcome to xoblite.", format, pSettings->Toolbar->TextColor, pSettings->Toolbar->FontOutline, pSettings->Toolbar->OutlineColor, pSettings->Toolbar->FontShadow, pSettings->Toolbar->ShadowColor, pSettings->Toolbar->ShadowX, pSettings->Toolbar->ShadowY);
  1087: 
  1088: /*
  1089:             int width = TaskbarRect.right - TaskbarRect.left;x
  1090:             int iconSize = height;
  1091:             if (iconSize > 16) iconSize = 16;
  1092:             int xpos = TaskbarRect.left + ((width - iconSize) / 2);
  1093:             int ypos = TaskbarRect.top + ((height - iconSize) / 2);
  1094:             RECT iconRect;
  1095:             SetRect(&iconRect, xpos, ypos, xpos+iconSize, ypos+iconSize);
  1096: 
  1097:             HICON xobIcon = LoadIcon(pToolbar->hToolbarInstance, MAKEINTRESOURCE(IDI_XOBLITE));
  1098:             DrawSatHueIcon(hdc, iconRect, xobIcon, iconSize, 255, 0);
  1099:             DeleteObject(xobIcon);
  1100: */
  1101:         }
  1102: 
  1103:         DeleteObject(SelectObject(hdc, oldfont));
  1104:     }
  1105:     else DrawTaskButtons(hdc);
  1106: }
  1107: 
  1108: //===========================================================================
  1109: // Function: DrawTaskButtons
  1110: // Purpose: Draws task buttons on the taskbar
  1111: //===========================================================================
  1112: 
  1113: int Taskbar::DrawTaskButtons(HDC hdc)
  1114: {
  1115:     RECT TaskbarButtonsRect;
  1116:     CopyRect(&TaskbarButtonsRect, &TaskbarRect);
  1117: 
  1118:     int taskbarScrollIndicatorSize;
  1119:     if (pSettings->Toolbar->marginWidth > 0) taskbarScrollIndicatorSize = pSettings->Toolbar->marginWidth;
  1120:     else if (pSettings->Toolbar->borderWidth > 0) taskbarScrollIndicatorSize = pSettings->Toolbar->borderWidth;
  1121:     taskbarScrollIndicatorSize = 2 * pSettings->scalingFactorHiDPI;
  1122: 
  1123:     // Get the number of task buttons to draw...
  1124: //  GetTaskButtonsToDraw();
  1125: 
  1126:     // Get the range (first<->last) of currently visible taskbar items, if so applicable...
  1127:     int firstButton = FindFirstVisible();
  1128:     int lastButton = FindLastVisible(firstButton);
  1129:     if (lastButton < 0) lastButton = (int)taskList.size()-1; // Failsafe
  1130: 
  1131:     // Is the taskbar scrollable to the left/up? If so, make room for indicator...
  1132:     if (taskButtonsOffset > 0)
  1133:     {
  1134:         if (pSettings->toolbarVertical) TaskbarButtonsRect.top += taskbarScrollIndicatorSize;
  1135:         else TaskbarButtonsRect.left += taskbarScrollIndicatorSize;
  1136:     }
  1137: 
  1138:     // Is the taskbar scrollable to the right/down? If so, make room for indicator...
  1139:     for (int i = (lastButton+1); i < (int)taskList.size(); i++)
  1140:     {
  1141:         if (!OnCurrentWorkspace(taskList[i]->hwnd) || taskList[i]->hidden) continue;
  1142:         else
  1143:         {
  1144:             if (pSettings->toolbarVertical) TaskbarButtonsRect.bottom -= taskbarScrollIndicatorSize;
  1145:             else TaskbarButtonsRect.right -= taskbarScrollIndicatorSize;
  1146:             break;
  1147:         }
  1148:     }
  1149: 
  1150:     // For the vertical toolbar we only allow Bars or Bars+Icons mode... (at least for the time being)
  1151:     int drawTaskbarMode = pSettings->taskbarMode;
  1152:     if (pSettings->toolbarVertical && (pSettings->taskbarMode == TASKBAR_MODE_ICONS)) drawTaskbarMode = TASKBAR_MODE_BARSICONS;
  1153: 
  1154:     //====================
  1155: 
  1156:     // Calculate task button and icon dimensions...
  1157: 
  1158:     int oldButtonHeight = taskButtonHeightMinusPadding;
  1159:     taskButtonHeight = TaskbarButtonsRect.bottom - TaskbarButtonsRect.top;
  1160:     if (pSettings->toolbarVertical)
  1161:     {
  1162:         if (taskButtonsToDraw > 0) taskButtonHeight = taskButtonHeight / taskButtonsToDraw;
  1163:         // ##### EXPERIMENTAL SAFEGUARD #####
  1164:         // Just after startup the height of the vertical toolbar may
  1165:         // not yet have been set to match the number of task buttons...
  1166:         if (taskButtonHeight < pSettings->Toolbar->FontHeight) return 0;
  1167:         // ##################################
  1168:         taskButtonHeightMinusPadding = taskButtonHeight;;// -pSettings->Toolbar->marginWidth;
  1169:     }
  1170:     else
  1171:     {
  1172:         taskButtonHeightMinusPadding = taskButtonHeight;
  1173:     }
  1174: 
  1175:     if (taskButtonHeightMinusPadding != oldButtonHeight) cachedTaskButtonsExist = false;
  1176: 
  1177:     // Choose icon size depending on the height of the task button...
  1178: //  iconSize = 11;
  1179: //  if (taskButtonHeight > 20) iconSize = 16;
  1180: //  if (taskButtonHeight > 36) iconSize = 32;
  1181:     if (taskButtonHeight < 20) iconSize = taskButtonHeight - 4;
  1182:     else iconSize = 16;
  1183:     if (iconSize < 11) iconSize = 11;
  1184: 
  1185: /*
  1186:     if (drawTaskbarMode != TASKBAR_MODE_ICONS) // -> Bars or Bars+Icons mode...
  1187:     {
  1188:         taskButtonWidth = TaskbarButtonsRect.right - TaskbarButtonsRect.left;
  1189:         if (pSettings->toolbarVertical)
  1190:         {
  1191:             taskButtonWidthMinusPadding = taskButtonWidth;
  1192:         }
  1193:         else
  1194:         {
  1195:             if (taskButtonsToDraw > 0) taskButtonWidth = taskButtonWidth / taskButtonsToDraw;
  1196:             taskButtonWidthMinusPadding = taskButtonWidth - 2; // Padding 2 pixels between task buttons...
  1197: //          taskButtonWidthMinusPadding = taskButtonWidth + pSettings->InactiveTask->borderWidth; // No padding between task buttons...
  1198:         }
  1199:     }
  1200:     else // TASKBAR_MODE_ICONS -> Icons mode
  1201:     {
  1202:         taskButtonWidth = iconSize + 7;
  1203:         taskButtonWidthMinusPadding = taskButtonWidth - 1; // Padding 1 pixel between task buttons...
  1204: //      taskButtonWidth = iconSize + 5;
  1205: //      taskButtonWidthMinusPadding = taskButtonWidth + pSettings->InactiveTask->borderWidth; // No padding between task buttons...
  1206:     }
  1207: */
  1208: 
  1209:     int oldButtonWidth = taskButtonWidthMinusPadding;
  1210:     taskButtonWidth = TaskbarButtonsRect.right - TaskbarButtonsRect.left;
  1211:     if (pSettings->toolbarVertical)
  1212:     {
  1213:         taskButtonWidthMinusPadding = taskButtonWidth;
  1214:     }
  1215:     else
  1216:     {
  1217:         if (taskButtonsToDraw > 0) taskButtonWidth = taskButtonWidth / taskButtonsToDraw;
  1218:         taskButtonWidthMinusPadding = taskButtonWidth - 2; // Padding 2 pixels between task buttons...
  1219: //      taskButtonWidthMinusPadding = taskButtonWidth + pSettings->InactiveTask->borderWidth; // No padding between task buttons...
  1220:     }
  1221: 
  1222:     if (taskButtonWidthMinusPadding != oldButtonWidth) cachedTaskButtonsExist = false;
  1223: 
  1224:     //====================
  1225: 
  1226:     // If we have not yet created any cached task buttons, or they need to be updated for other reasons, let's do that...
  1227:     if (!cachedTaskButtonsExist)
  1228:     {
  1229: /*
  1230:         if (cachedTaskButtonActive) DeleteDC(cachedTaskButtonActive);
  1231:         if (cachedTaskButtonInactive) DeleteDC(cachedTaskButtonInactive);
  1232:         cachedTaskButtonActive = CreateCompatibleDC(NULL);
  1233:         cachedTaskButtonInactive = CreateCompatibleDC(NULL);
  1234: */
  1235:         RECT r = {0, 0, taskButtonWidthMinusPadding, taskButtonHeightMinusPadding};
  1236: 
  1237:         HBITMAP tempBitmapActive = CreateCompatibleBitmap(hdc, taskButtonWidthMinusPadding, taskButtonHeightMinusPadding);
  1238:         HBITMAP oldBitmapActive = (HBITMAP)SelectObject(cachedTaskButtonActive, tempBitmapActive);
  1239:         DeleteObject(oldBitmapActive);
  1240:         MakeGradientSuper(cachedTaskButtonActive, r, pSettings->ActiveTask->type, pSettings->ActiveTask->Color1, pSettings->ActiveTask->Color2, pSettings->ActiveTask->Color3, pSettings->ActiveTask->Color4, pSettings->ActiveTask->Color5, pSettings->ActiveTask->Color6, pSettings->ActiveTask->Color7, pSettings->ActiveTask->Color8, pSettings->ActiveTask->interlaced, pSettings->ActiveTask->bevelstyle, pSettings->ActiveTask->bevelposition, pSettings->bevelWidth, pSettings->ActiveTask->borderColor, pSettings->ActiveTask->borderWidth);
  1241:         DeleteObject(tempBitmapActive);
  1242: 
  1243:         HBITMAP tempBitmapInactive = CreateCompatibleBitmap(hdc, taskButtonWidthMinusPadding, taskButtonHeightMinusPadding);
  1244:         HBITMAP oldBitmapInactive = (HBITMAP)SelectObject(cachedTaskButtonInactive, tempBitmapInactive);
  1245:         DeleteObject(oldBitmapInactive);
  1246:         MakeGradientSuper(cachedTaskButtonInactive, r, pSettings->InactiveTask->type, pSettings->InactiveTask->Color1, pSettings->InactiveTask->Color2, pSettings->InactiveTask->Color3, pSettings->InactiveTask->Color4, pSettings->InactiveTask->Color5, pSettings->InactiveTask->Color6, pSettings->InactiveTask->Color7, pSettings->InactiveTask->Color8, pSettings->InactiveTask->interlaced, pSettings->InactiveTask->bevelstyle, pSettings->InactiveTask->bevelposition, pSettings->bevelWidth, pSettings->InactiveTask->borderColor, pSettings->InactiveTask->borderWidth);
  1247:         DeleteObject(tempBitmapInactive);
  1248: 
  1249:         // Set the "cached task buttons created" indicator...
  1250:         cachedTaskButtonsExist = true;
  1251:     }
  1252: 
  1253:     //====================
  1254: 
  1255:     // Delete any existing taskbar tooltips... (nb. because a full flush is much easier+safer than delta updates)
  1256:     if (pSettings->taskbarTooltips) pTooltips->DeleteAllTooltips();
  1257: 
  1258:     // ...and if applicable, any existing *in-button* live preview thumbnail... (nb. see also MouseHoveringOverTaskbar() below)
  1259:     if (pSettings->taskbarActiveLivePreview && (pToolbar->thumbnail != NULL))
  1260:     {
  1261:         DwmUnregisterThumbnail(pToolbar->thumbnail);
  1262:         pToolbar->thumbnail = NULL;
  1263:     }
  1264: 
  1265:     //====================
  1266: 
  1267:     // Draw the taskbar buttons...
  1268:     int drawnTasks = 0;
  1269: 
  1270:     for (int i = firstButton; i <= lastButton; i++)
  1271:     {
  1272:         if (drawnTasks >= taskButtonsToDraw) break;
  1273: 
  1274:         // Exclude tasks not on the current workspace?
  1275:         if (!OnCurrentWorkspace(taskList[i]->hwnd)) continue;
  1276:         // Exclude hidden/cloaked tasks...
  1277:         if (taskList[i]->hidden) continue;
  1278: 
  1279:         //====================
  1280: 
  1281:         // Calculate the bounding rect of the current task button...
  1282: 
  1283:         CopyRect(&currentTaskButton, &TaskbarButtonsRect);
  1284: 
  1285:         if (pSettings->toolbarVertical)
  1286:         {
  1287:             currentTaskButton.top = TaskbarButtonsRect.top + (drawnTasks * taskButtonHeight);
  1288:             currentTaskButton.bottom = currentTaskButton.top + taskButtonHeightMinusPadding;
  1289: 
  1290:             // Extend the bottommost button to fit the bottom border of the taskbar...
  1291:             if (drawnTasks == (taskButtonsToDraw-1)) currentTaskButton.bottom = TaskbarButtonsRect.bottom;
  1292: 
  1293:             if (currentTaskButton.bottom > TaskbarButtonsRect.bottom) break; // Failsafe
  1294:         }
  1295:         else
  1296:         {
  1297:             currentTaskButton.left = TaskbarButtonsRect.left + (drawnTasks * taskButtonWidth);
  1298:             currentTaskButton.right = currentTaskButton.left + taskButtonWidthMinusPadding;
  1299: 
  1300:             if (drawTaskbarMode != TASKBAR_MODE_ICONS) // Bars or Bars+Icons mode
  1301:             {
  1302:                 // Extend the rightmost button to fit the right border of the taskbar...
  1303:                 if (drawnTasks == (taskButtonsToDraw-1)) currentTaskButton.right = TaskbarButtonsRect.right;
  1304:             }
  1305: 
  1306:             if (currentTaskButton.right > TaskbarButtonsRect.right) break; // Failsafe
  1307:         }
  1308: 
  1309:         CopyRect(&taskList[i]->r, &currentTaskButton); // ...and save it for later use
  1310: 
  1311:         //====================
  1312: 
  1313:         // Have we previously increased the process priority class for this task? If so, let's indicate that...
  1314:         if ((taskList[i]->priorityClass != 0) || CheckSticky(taskList[i]->hwnd))
  1315:         {
  1316:             int highPrioIndicatorSize = 1 * pSettings->scalingFactorHiDPI;
  1317: 
  1318:             RECT r;
  1319:             SetRect(&r, currentTaskButton.left, currentTaskButton.top, currentTaskButton.right, currentTaskButton.top+highPrioIndicatorSize);
  1320: 
  1321:             COLORREF priorityIndicatorColor = 0x0000ff; // Show a smoothly faded in/out *RED* gradient indicator for high priority tasks!
  1322:             COLORREF stickyIndicatorColor = 0x008888;   // Show a smoothly faded in/out *YELLOW* gradient indicator for stickied tasks!
  1323:                                                         // ...or if both high priority *and* stickied, a top yellow / bottom red gradient indicator.
  1324: 
  1325:             if (CheckSticky(taskList[i]->hwnd)) MakeGradientSuper(hdc, r, B_SPLITHORIZONTAL, GetPixel(hdc, r.left, r.top), stickyIndicatorColor, stickyIndicatorColor, GetPixel(hdc, r.right - 1, r.top), 0, 0, 0, 0, false, BEVEL_FLAT, BEVEL1, 0, 0, 0);
  1326:             else MakeGradientSuper(hdc, r, B_SPLITHORIZONTAL, GetPixel(hdc, r.left, r.top), priorityIndicatorColor, priorityIndicatorColor, GetPixel(hdc, r.right-1, r.top), 0, 0, 0, 0, false, BEVEL_FLAT, BEVEL1, 0, 0, 0);
  1327: 
  1328:             SetRect(&r, currentTaskButton.left, currentTaskButton.bottom-highPrioIndicatorSize, currentTaskButton.right, currentTaskButton.bottom);
  1329:             if (taskList[i]->priorityClass != 0) MakeGradientSuper(hdc, r, B_SPLITHORIZONTAL, GetPixel(hdc, r.left, r.bottom-1), priorityIndicatorColor, priorityIndicatorColor, GetPixel(hdc, r.right-1, r.bottom-1), 0, 0, 0, 0, false, BEVEL_FLAT, BEVEL1, 0, 0, 0);
  1330:             else MakeGradientSuper(hdc, r, B_SPLITHORIZONTAL, GetPixel(hdc, r.left, r.bottom-1), stickyIndicatorColor, stickyIndicatorColor, GetPixel(hdc, r.right-1, r.bottom-1), 0, 0, 0, 0, false, BEVEL_FLAT, BEVEL1, 0, 0, 0);
  1331: 
  1332:             CopyRect(&r, &currentTaskButton);
  1333:             InflateRect(&r, 0, -(highPrioIndicatorSize*2));
  1334:             if (taskList[i]->active) MakeGradientSuper(hdc, r, pSettings->ActiveTask->type, pSettings->ActiveTask->Color1, pSettings->ActiveTask->Color2, pSettings->ActiveTask->Color3, pSettings->ActiveTask->Color4, pSettings->ActiveTask->Color5, pSettings->ActiveTask->Color6, pSettings->ActiveTask->Color7, pSettings->ActiveTask->Color8, pSettings->ActiveTask->interlaced, pSettings->ActiveTask->bevelstyle, pSettings->ActiveTask->bevelposition, pSettings->bevelWidth, pSettings->ActiveTask->borderColor, pSettings->ActiveTask->borderWidth);
  1335:             else if (pSettings->taskbarInactiveBackground) MakeGradientSuper(hdc, r, pSettings->InactiveTask->type, pSettings->InactiveTask->Color1, pSettings->InactiveTask->Color2, pSettings->InactiveTask->Color3, pSettings->InactiveTask->Color4, pSettings->InactiveTask->Color5, pSettings->InactiveTask->Color6, pSettings->InactiveTask->Color7, pSettings->InactiveTask->Color8, pSettings->InactiveTask->interlaced, pSettings->InactiveTask->bevelstyle, pSettings->InactiveTask->bevelposition, pSettings->bevelWidth, pSettings->InactiveTask->borderColor, pSettings->InactiveTask->borderWidth);
  1336:         }
  1337:         else if (taskList[i]->hwnd == flashingHwnd) // Flashing task button?
  1338:         {
  1339:             // Paint border+background for this flashed taskbar button...
  1340:             MakeGradientSuper(hdc, currentTaskButton, pSettings->ActiveTask->type, pSettings->FlashingTask->Color1, pSettings->FlashingTask->Color2, pSettings->FlashingTask->Color3, pSettings->FlashingTask->Color4, pSettings->FlashingTask->Color5, pSettings->FlashingTask->Color6, pSettings->FlashingTask->Color7, pSettings->FlashingTask->Color8, pSettings->InactiveTask->interlaced, pSettings->ActiveTask->bevelstyle, pSettings->ActiveTask->bevelposition, pSettings->bevelWidth, pSettings->FlashingTask->borderColor, pSettings->ActiveTask->borderWidth);
  1341:         }
  1342: //      else if ((drawnTasks == (taskButtonsToDraw-1)) && (drawTaskbarMode != TASKBAR_MODE_ICONS) && !pSettings->toolbarVertical) // Rightmost button on a horizontal taskbar?
  1343:         else if (drawnTasks == (taskButtonsToDraw-1))
  1344:         {
  1345:             // Manually paint the border+background for the last visible task button... (i.e. don't use the fixed size cached
  1346:             // task button bitmap, in order to allow this button's size to be adjusted to perfectly fit the remaining space available)
  1347:             if (taskList[i]->active) MakeGradientSuper(hdc, currentTaskButton, pSettings->ActiveTask->type, pSettings->ActiveTask->Color1, pSettings->ActiveTask->Color2, pSettings->ActiveTask->Color3, pSettings->ActiveTask->Color4, pSettings->ActiveTask->Color5, pSettings->ActiveTask->Color6, pSettings->ActiveTask->Color7, pSettings->ActiveTask->Color8, pSettings->ActiveTask->interlaced, pSettings->ActiveTask->bevelstyle, pSettings->ActiveTask->bevelposition, pSettings->bevelWidth, pSettings->ActiveTask->borderColor, pSettings->ActiveTask->borderWidth);
  1348:             else if (pSettings->taskbarInactiveBackground) MakeGradientSuper(hdc, currentTaskButton, pSettings->InactiveTask->type, pSettings->InactiveTask->Color1, pSettings->InactiveTask->Color2, pSettings->InactiveTask->Color3, pSettings->InactiveTask->Color4, pSettings->InactiveTask->Color5, pSettings->InactiveTask->Color6, pSettings->InactiveTask->Color7, pSettings->InactiveTask->Color8, pSettings->InactiveTask->interlaced, pSettings->InactiveTask->bevelstyle, pSettings->InactiveTask->bevelposition, pSettings->bevelWidth, pSettings->InactiveTask->borderColor, pSettings->InactiveTask->borderWidth);
  1349:         }
  1350:         else
  1351:         {
  1352:             // Copy the cached task button bitmap into the temporary buffer...
  1353:             if (taskList[i]->active) BitBlt(hdc, currentTaskButton.left, currentTaskButton.top, taskButtonWidthMinusPadding, taskButtonHeightMinusPadding, cachedTaskButtonActive, 0, 0, SRCCOPY);
  1354:             else if (pSettings->taskbarInactiveBackground) BitBlt(hdc, currentTaskButton.left, currentTaskButton.top, taskButtonWidthMinusPadding, taskButtonHeightMinusPadding, cachedTaskButtonInactive, 0, 0, SRCCOPY);
  1355:         }
  1356: 
  1357:         //====================
  1358: 
  1359:         if (taskList[i]->active)
  1360:         {
  1361:             // Store the active task RECT for possible later use by the toolbar... (i.e. active task alpha transparency etc)
  1362:             CopyRect(&ActiveTaskRect, &currentTaskButton);
  1363:             activeTaskAvailable = true;
  1364:         }
  1365: 
  1366:         //====================
  1367: 
  1368:         int padding = ((currentTaskButton.bottom - currentTaskButton.top - iconSize) / 2);
  1369: 
  1370:         // Should we draw an icon on the task button? (-> all taskbar modes except "Bars" mode)
  1371:         if (drawTaskbarMode != TASKBAR_MODE_BARS)
  1372:         {
  1373:             // Fetch the window icon...
  1374:             currentTaskButtonWnd = taskList[i]->hwnd;
  1375:             if (currentTaskButtonIcon) DeleteObject(currentTaskButtonIcon);
  1376:             currentTaskButtonIcon = NULL;
  1377: 
  1378:             if (taskList[i]->isAppPlugin) // -> "Application-like" plugins get a xoblite icon for their task buttons...
  1379:             {
  1380:                 currentTaskButtonIcon = LoadIcon(pToolbar->hToolbarInstance, MAKEINTRESOURCE(IDI_XOBLITE));
  1381:             }
  1382:             else
  1383:             {
  1384:                 if (iconSize <= 16) // -> Use small size (ICON_SMALL) source icon when applicable...
  1385:                 {
  1386:                     SendMessageTimeout(currentTaskButtonWnd, WM_GETICON, ICON_SMALL, 0, SMTO_ABORTIFHUNG|SMTO_BLOCK, 200, (PDWORD_PTR)&currentTaskButtonIcon);
  1387:                     if (!currentTaskButtonIcon) currentTaskButtonIcon = (HICON)GetClassLongPtr(currentTaskButtonWnd, GCLP_HICONSM);
  1388:                 }
  1389:                 if (!currentTaskButtonIcon) SendMessageTimeout(currentTaskButtonWnd, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG|SMTO_BLOCK, 200, (PDWORD_PTR)&currentTaskButtonIcon);
  1390:                 if (!currentTaskButtonIcon) currentTaskButtonIcon = (HICON)GetClassLongPtr(currentTaskButtonWnd, GCLP_HICON);
  1391:             }
  1392: 
  1393:             // Calculate icon position...
  1394:             if (drawTaskbarMode == TASKBAR_MODE_BARSICONS)
  1395:             {
  1396:                 // Bars+Icons mode -> Left adjusted icons...
  1397:                 CopyRect(&iconRect, &currentTaskButton);
  1398:                 InflateRect(&iconRect, -padding, 0);
  1399:             }
  1400:             else // TASKBAR_MODE_ICONS
  1401:             {
  1402:                 // Icons mode -> Centered icons...
  1403:                 iconRect.left = currentTaskButton.left + (((currentTaskButton.right - currentTaskButton.left) - iconSize) / 2);
  1404:             }
  1405: 
  1406:             iconRect.top = currentTaskButton.top + (taskButtonHeightMinusPadding/2) - (iconSize/2);
  1407:             iconRect.right = iconRect.left + iconSize;
  1408:             iconRect.bottom = iconRect.top + iconSize;
  1409: 
  1410:             // Draw the icon...
  1411:             if (currentTaskButtonIcon)
  1412:             {
  1413:                 if (taskList[i]->active && !pSettings->taskbarActiveSatHue) DrawIconEx(hdc, iconRect.left, iconRect.top, currentTaskButtonIcon, iconSize, iconSize, 0, NULL, DI_NORMAL);
  1414:                 else DrawSatHueIcon(hdc, iconRect, currentTaskButtonIcon, iconSize, pSettings->taskbarSaturationValue, pSettings->taskbarHueIntensity);
  1415:             }
  1416: 
  1417:             if (currentTaskButtonIcon) DeleteObject(currentTaskButtonIcon);
  1418:         }
  1419: 
  1420:         //====================
  1421: 
  1422:         // Copy the current task's window label, i.e. its titlebar text...
  1423:         // (note: this may later be used for the task button as well as its associated tooltip, so we should not add anything here.)
  1424:         GetWindowText(taskList[i]->hwnd, taskList[i]->captionANSI, 255); // -> ANSI representation
  1425:         GetWindowTextW(taskList[i]->hwnd, taskList[i]->captionUnicode, 255); // -> Unicode representation
  1426: 
  1427:         // Should we draw the window label on the task button?
  1428:         if (drawTaskbarMode != TASKBAR_MODE_ICONS) // -> Bars or Bars+Icons mode
  1429:         {
  1430:             HFONT font = CreateFont(pSettings->Toolbar->FontHeight, 0, 0, 0, pSettings->Toolbar->FontWeight, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, pSettings->Toolbar->Font);
  1431:             HGDIOBJ oldfont = SelectObject(hdc, font);
  1432:             SetBkMode(hdc, TRANSPARENT);
  1433: 
  1434:             CopyRect(&textRect, &currentTaskButton);
  1435:             InflateRect(&textRect, -padding, 0);
  1436:             if (drawTaskbarMode == TASKBAR_MODE_BARSICONS)
  1437:             {
  1438:                 // ...adjust text to the already drawn icon...
  1439:                 textRect.left = iconRect.right + padding;
  1440:                 if (textRect.left > currentTaskButton.right) textRect.left = currentTaskButton.left; // "Failsafe"
  1441:             }
  1442: 
  1443:             // Added support for Unicode for the task button labels...
  1444:             wchar_t currentTaskButtonCaption[275];
  1445:             if (pSettings->taskbarShowTaskWorkspace)
  1446:             {
  1447:                 if (IsIconic(taskList[i]->hwnd)) // -> The task is minimized (workspace==255)
  1448:                 {
  1449: //                  taskList[i]->workspace = 255; // ...just in case the task's workspace tag is not up-to-date for some reason...
  1450:                     wcscpy_s(currentTaskButtonCaption, sizeofArray(currentTaskButtonCaption), L"[_] ");
  1451:                 }
  1452:                 else if (CheckSticky(taskList[i]->hwnd)) // -> The task is "sticky" i.e. visible on all workspaces (sticky)
  1453:                 {
  1454:                     taskList[i]->workspace = 254; // ...just in case the task's workspace tag is not up-to-date for some reason...
  1455:                     wcscpy_s(currentTaskButtonCaption, sizeofArray(currentTaskButtonCaption), L"[*] ");
  1456:                 }
  1457:                 else // -> The task is visible and located on a single workspace
  1458:                 {
  1459:                     if (taskList[i]->workspace >= 254) taskList[i]->workspace = pSettings->currentWorkspace; // ...just in case the task's workspace tag is not up-to-date for some reason...
  1460:                     swprintf(currentTaskButtonCaption, sizeof(currentTaskButtonCaption), L"[%d] ", taskList[i]->workspace + 1);
  1461:                 }
  1462:                 wcscat_s(currentTaskButtonCaption, sizeofArray(currentTaskButtonCaption), taskList[i]->captionUnicode);
  1463:             }
  1464:             else wcscpy_s(currentTaskButtonCaption, sizeofArray(currentTaskButtonCaption), taskList[i]->captionUnicode);
  1465: 
  1466:             unsigned int flags = DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS;
  1467:             if (taskList[i]->hwnd == flashingHwnd) DrawTextWithEffectsUnicode(hdc, textRect, currentTaskButtonCaption, flags, pSettings->FlashingTask->TextColor, pSettings->ActiveTask->FontOutline, pSettings->FlashingTask->OutlineColor, pSettings->ActiveTask->FontShadow, pSettings->FlashingTask->ShadowColor, pSettings->ActiveTask->ShadowX, pSettings->ActiveTask->ShadowY);
  1468:             else if (taskList[i]->active) DrawTextWithEffectsUnicode(hdc, textRect, currentTaskButtonCaption, flags, pSettings->ActiveTask->TextColor, pSettings->ActiveTask->FontOutline, pSettings->ActiveTask->OutlineColor, pSettings->ActiveTask->FontShadow, pSettings->ActiveTask->ShadowColor, pSettings->ActiveTask->ShadowX, pSettings->ActiveTask->ShadowY);
  1469:             else DrawTextWithEffectsUnicode(hdc, textRect, currentTaskButtonCaption, flags, pSettings->InactiveTask->TextColor, pSettings->InactiveTask->FontOutline, pSettings->InactiveTask->OutlineColor, pSettings->InactiveTask->FontShadow, pSettings->InactiveTask->ShadowColor, pSettings->InactiveTask->ShadowX, pSettings->InactiveTask->ShadowY);
  1470: 
  1471:             DeleteObject(SelectObject(hdc, oldfont));
  1472: 
  1473:             // Should we display a live preview thumbnail for the currently active task?
  1474:             if (taskList[i]->active && pSettings->taskbarActiveLivePreview)
  1475:             {
  1476:                 HRESULT hr = DwmRegisterThumbnail(pToolbar->hToolbarWnd, taskList[i]->hwnd, &pToolbar->thumbnail);
  1477:                 if (SUCCEEDED(hr))
  1478:                 {
  1479: //                  RECT windowRect;
  1480: //                  GetWindowRect(taskList[i]->hwnd, &windowRect);
  1481: 
  1482:                     RECT thumbnailRect;
  1483:                     CopyRect(&thumbnailRect, &textRect);
  1484:                     InflateRect(&thumbnailRect, 0, -(padding/2));
  1485: /*
  1486:                     double windowRatio = (windowRect.right - windowRect.left) / (windowRect.bottom - windowRect.top);
  1487:                     double thumbnailRatio = (thumbnailRect.right - thumbnailRect.left) / (thumbnailRect.bottom - thumbnailRect.top);
  1488: 
  1489:                     if (thumbnailRatio > windowRatio)
  1490:                     {
  1491:                         int thumbnailWidth = (thumbnailRect.right - thumbnailRect.left) / windowRatio;
  1492:                         int thumbnailPadding = ((thumbnailRect.right - thumbnailRect.left) - thumbnailWidth) / 2;
  1493:                         InflateRect(&thumbnailRect, -thumbnailPadding, 0);
  1494:                     }
  1495:                     else if (windowRatio > thumbnailRatio)
  1496:                     {
  1497:                         int thumbnailWidth = (thumbnailRect.right - thumbnailRect.left) / windowRatio;
  1498:                         int thumbnailPadding = ((thumbnailRect.right - thumbnailRect.left) - thumbnailWidth) / 2;
  1499:                         InflateRect(&thumbnailRect, -thumbnailPadding, 0);
  1500:                     }
  1501: */
  1502:                     DWM_THUMBNAIL_PROPERTIES dskThumbProps;
  1503:                     dskThumbProps.dwFlags = DWM_TNP_RECTDESTINATION | DWM_TNP_OPACITY | DWM_TNP_VISIBLE | DWM_TNP_SOURCECLIENTAREAONLY;
  1504:                     dskThumbProps.rcDestination = thumbnailRect;
  1505:                     dskThumbProps.opacity = 255;
  1506:                     dskThumbProps.fVisible = TRUE;
  1507:                     dskThumbProps.fSourceClientAreaOnly = FALSE;
  1508:                     DwmUpdateThumbnailProperties(pToolbar->thumbnail, &dskThumbProps);
  1509:                 }
  1510:             }
  1511:         }
  1512: 
  1513:         //====================
  1514: 
  1515:         if (taskList[i]->hwnd == flashingHwnd) flashingHwnd = 0; // Reset flash indicator...
  1516: 
  1517:         // Should we create a tooltip for the task button?
  1518:         if (pSettings->taskbarTooltips) pTooltips->CreateToolTip((UINT)pTaskbar->taskList[i]->hwnd, pTaskbar->taskList[i]->r, pTaskbar->taskList[i]->captionANSI, TOOLTIP_TYPE_TASK);
  1519: 
  1520:         drawnTasks++;
  1521:     }
  1522: 
  1523:     //====================
  1524: 
  1525:     // Finally, we draw "scroll for more" indicators at the left/top (-> more items to the left, or above on a vertical toolbar)
  1526:     // and/or right/bottom (-> more items to the right, or below on a vertical toolbar) respectively if so applicable...
  1527: 
  1528:     if (taskButtonsOffset > 0)
  1529:     {
  1530:         RECT r;
  1531:         if (pSettings->toolbarVertical) SetRect(&r, TaskbarRect.left, TaskbarRect.top, TaskbarRect.right, TaskbarRect.top + taskbarScrollIndicatorSize);
  1532:         else SetRect(&r, TaskbarRect.left, TaskbarRect.top, TaskbarRect.left + taskbarScrollIndicatorSize, TaskbarRect.bottom);
  1533: 
  1534:         COLORREF beginIndicatorColor = GetPixel(hdc, r.left, r.top);
  1535:         COLORREF endIndicatorColor = GetPixel(hdc, r.right-1, r.bottom-1);
  1536: 
  1537:         int centerX = r.left + ((r.right - r.left) / 2);
  1538:         int centerY = r.top + ((r.bottom - r.top) / 2);
  1539:         COLORREF scrollIndicatorColor = pSettings->MixColors(GetPixel(hdc, centerX, centerY), pSettings->Toolbar->TextColor);
  1540: 
  1541:         if (pSettings->toolbarVertical) MakeGradientSuper(hdc, r, B_SPLITHORIZONTAL, beginIndicatorColor, scrollIndicatorColor, scrollIndicatorColor, endIndicatorColor, 0, 0, 0, 0, false, BEVEL_FLAT, BEVEL1, 0, 0, 0);
  1542:         else MakeGradientSuper(hdc, r, B_SPLITVERTICAL, beginIndicatorColor, scrollIndicatorColor, scrollIndicatorColor, endIndicatorColor, 0, 0, 0, 0, false, BEVEL_FLAT, BEVEL1, 0, 0, 0);
  1543:     }
  1544: 
  1545:     for (int i = (lastButton+1); i < (int)taskList.size(); i++)
  1546:     {
  1547:         if (!OnCurrentWorkspace(taskList[i]->hwnd) || taskList[i]->hidden) continue;
  1548:         else
  1549:         {
  1550:             RECT r;
  1551:             if (pSettings->toolbarVertical) SetRect(&r, TaskbarRect.left, TaskbarRect.bottom - taskbarScrollIndicatorSize, TaskbarRect.right, TaskbarRect.bottom);
  1552:             else SetRect(&r, TaskbarRect.right - taskbarScrollIndicatorSize, TaskbarRect.top, TaskbarRect.right, TaskbarRect.bottom);
  1553: 
  1554:             COLORREF beginIndicatorColor = GetPixel(hdc, r.left, r.top);
  1555:             COLORREF endIndicatorColor = GetPixel(hdc, r.right-1, r.bottom-1);
  1556: 
  1557:             int centerX = r.left + ((r.right - r.left) / 2);
  1558:             int centerY = r.top + ((r.bottom - r.top) / 2);
  1559:             COLORREF scrollIndicatorColor = pSettings->MixColors(GetPixel(hdc, centerX, centerY), pSettings->Toolbar->TextColor);
  1560: 
  1561:             if (pSettings->toolbarVertical) MakeGradientSuper(hdc, r, B_SPLITHORIZONTAL, beginIndicatorColor, scrollIndicatorColor, scrollIndicatorColor, endIndicatorColor, 0, 0, 0, 0, false, BEVEL_FLAT, BEVEL1, 0, 0, 0);
  1562:             else MakeGradientSuper(hdc, r, B_SPLITVERTICAL, beginIndicatorColor, scrollIndicatorColor, scrollIndicatorColor, endIndicatorColor, 0, 0, 0, 0, false, BEVEL_FLAT, BEVEL1, 0, 0, 0);
  1563: 
  1564:             break;
  1565:         }
  1566:     }
  1567: 
  1568:     return 1;
  1569: }
  1570: 
  1571: //===========================================================================
  1572: // Function: MouseHoveringOverTaskbar
  1573: // Purpose: ...
  1574: //===========================================================================
  1575: 
  1576: void Taskbar::MouseHoveringOverTaskbar(HWND hwnd, unsigned int message, WPARAM wParam, LPARAM lParam)
  1577: {
  1578:     if (!pSettings->taskbarPreviews) return;
  1579: 
  1580:     if (pPreviewItem)
  1581:     {
  1582:         taskbarMouseHoverPoint = { LOWORD(lParam), HIWORD(lParam) };
  1583: 
  1584:         //====================
  1585: 
  1586:         // Is the taskbar visible and if so are we mouse hovering within its area? If not...
  1587:         if ((pSettings->taskbarMode == TASKBAR_MODE_HIDDEN) || !PtInRect(&TaskbarRect, taskbarMouseHoverPoint))
  1588:         {
  1589:             pPreviewItem->Hide();
  1590:             if (pToolbar->thumbnail != NULL)
  1591:             {
  1592:                 DwmUnregisterThumbnail(pToolbar->thumbnail);
  1593:                 pToolbar->thumbnail = NULL;
  1594:             }
  1595:             lastHoveredTaskButton = -1; // Reset the taskbar button mouse hover tracking upon the mouse pointer leaving the taskbar
  1596:             return;
  1597:         }
  1598: 
  1599:         //====================
  1600: 
  1601:         // Get the range (first<->last) of currently visible taskbar items, if so applicable...
  1602:         int firstButton = FindFirstVisible();
  1603:         int lastButton = FindLastVisible(firstButton);
  1604:         if (lastButton < 0) lastButton = (int)taskList.size() - 1; // Failsafe
  1605: 
  1606:         // ...then check if we're mouse hovering over any of them...
  1607:         for (int i = firstButton; i <= lastButton; i++)
  1608:         {
  1609:             if (OnCurrentWorkspace(taskList[i]->hwnd) && !taskList[i]->hidden && PtInRect(&taskList[i]->r, taskbarMouseHoverPoint))
  1610:             {
  1611:                 if (i != lastHoveredTaskButton) // ...and whether we have moved between buttons since the last update...
  1612:                 {
  1613:                     pPreviewItem->Hide();
  1614:                     lastHoveredTaskButton = i;
  1615: 
  1616:                     // Calculate the position for the task button preview item...
  1617:                     RECT toolbarRect;
  1618:                     GetWindowRect(pToolbar->hToolbarWnd, &toolbarRect);
  1619: 
  1620:                     RECT windowRect;
  1621:                     int windowWidth, windowHeight;
  1622:                     if (IsIconic(taskList[i]->hwnd))
  1623:                     {
  1624:                         // Note: We can *not* use GetWindowRect() to fetch the dimensions of minimized windows...
  1625:                         // (read: these windows will then be reported to have a fixed size of 237x39 pixels and their true aspect ratio will not be known)
  1626:                         // Temporary(?) solution -> Use the same aspect ratio as the screen also for the preview item
  1627:                         windowWidth = GetSystemMetrics(SM_CXSCREEN);
  1628:                         windowHeight = GetSystemMetrics(SM_CYSCREEN);
  1629: 
  1630:                         // FFS: COULD WE USE PREVIOUSLY INTERNALLY SAVED RESTORED WINDOW DIMENSIONS HERE INSTEAD? (CF. TASKBAR INTERNALS USED FOR TILING ETC)
  1631:                     }
  1632:                     else
  1633:                     {
  1634:                         GetWindowRect(taskList[i]->hwnd, &windowRect);
  1635:                         windowWidth = (windowRect.right - windowRect.left);
  1636:                         windowHeight = (windowRect.bottom - windowRect.top);
  1637:                     }
  1638: 
  1639: //                  int previewItemWidth = 150 * pSettings->scalingFactorHiDPI; // Note: The preview item width is internally auto-fixed relative to the HiDPI setting etc...
  1640:                     int previewItemWidth;
  1641:                     if (pSettings->toolbarVertical) previewItemWidth = pToolbar->ToolbarWidth;
  1642: //                  else if (pSettings->taskbarMode != TASKBAR_MODE_ICONS) previewItemWidth = (taskList[i]->r.right - taskList[i]->r.left);
  1643:                     else previewItemWidth = 150 * pSettings->scalingFactorHiDPI;
  1644: 
  1645:                     if (previewItemWidth < 100) previewItemWidth = 100;
  1646: 
  1647:                     int previewItemHeight = (previewItemWidth * windowHeight) / windowWidth; // ...while the preview item height follows the aspect ratio of the task's window.
  1648: 
  1649:                     int x, y;
  1650:                     int gap;
  1651:                     if (pSettings->Toolbar->borderWidth > 0) gap = pSettings->Toolbar->borderWidth;
  1652:                     else gap = 2 * pSettings->scalingFactorHiDPI; // -> The same gap as for the menu preview items
  1653: //                  else gap = 4 * pSettings->scalingFactorHiDPI;
  1654: 
  1655:                     if (pSettings->toolbarVertical)
  1656:                     {
  1657:                         x = toolbarRect.right + gap;
  1658:                         y = toolbarRect.top + taskList[i]->r.top + ((taskList[i]->r.bottom - taskList[i]->r.top) / 2);
  1659: 
  1660:                         // If there isn't enough space for the preview item on the right hand
  1661:                         // side of the toolbar, we move it to the left hand side instead...
  1662:                         int screenWidth = GetSystemMetrics(SM_CXSCREEN);
  1663:                         if ((x + previewItemWidth) > screenWidth) x = toolbarRect.left - gap - previewItemWidth;
  1664:                     }
  1665:                     else // if (!pSettings->toolbarVertical)
  1666:                     {
  1667:                         int previewItemHalfHeight = previewItemHeight / 2;
  1668:                         if ((pSettings->Toolbar->borderWidth > 0) && (previewItemHeight & 1)) gap += 1; // Make sure the actual gap is always equal to the toolbar border width
  1669: 
  1670:                         x = toolbarRect.left + taskList[i]->r.left + ((taskList[i]->r.right - taskList[i]->r.left) / 2) - (pPreviewItem->GetWidth() / 2);
  1671:                         y = toolbarRect.top - gap - previewItemHalfHeight;
  1672: 
  1673:                         // If there isn't enough space for the preview item above
  1674:                         // the toolbar, we move it below the toolbar instead...
  1675: //                      int screenHeight = GetSystemMetrics(SM_CYSCREEN);
  1676:                         if ((y - previewItemHalfHeight) < 0) y = toolbarRect.bottom + gap + previewItemHalfHeight;
  1677:                     }
  1678: 
  1679:                     // Show the preview item after a short delay...
  1680:                     pPreviewItem->Show(x, y, previewItemWidth, previewItemHeight, NULL, 500);
  1681: 
  1682:                     if (pToolbar->thumbnail != NULL)
  1683:                     {
  1684:                         DwmUnregisterThumbnail(pToolbar->thumbnail);
  1685:                         pToolbar->thumbnail = NULL;
  1686:                     }
  1687: 
  1688:                     HRESULT hr = DwmRegisterThumbnail(pPreviewItem->hPreviewItemWnd, taskList[i]->hwnd, &pToolbar->thumbnail);
  1689:                     if (SUCCEEDED(hr))
  1690:                     {
  1691:                         RECT thumbnailRect;
  1692:                         thumbnailRect.left = 0;
  1693:                         thumbnailRect.top = 0;
  1694:                         thumbnailRect.right = previewItemWidth; // pPreviewItem->GetWidth();
  1695:                         thumbnailRect.bottom = previewItemHeight; // pPreviewItem->GetHeight();
  1696: 
  1697:                         int previewBorder = 2 * pSettings->scalingFactorHiDPI;
  1698:                         InflateRect(&thumbnailRect, -previewBorder, -previewBorder);
  1699: 
  1700:                         DWM_THUMBNAIL_PROPERTIES dskThumbProps;
  1701:                         dskThumbProps.dwFlags = DWM_TNP_RECTDESTINATION | DWM_TNP_OPACITY | DWM_TNP_VISIBLE | DWM_TNP_SOURCECLIENTAREAONLY;
  1702:                         dskThumbProps.rcDestination = thumbnailRect;
  1703:                         dskThumbProps.opacity = 255;
  1704:                         dskThumbProps.fVisible = TRUE;
  1705:                         dskThumbProps.fSourceClientAreaOnly = FALSE;
  1706:                         DwmUpdateThumbnailProperties(pToolbar->thumbnail, &dskThumbProps);
  1707:                     }
  1708: 
  1709:                     return;
  1710:                 }
  1711:             }
  1712:         }
  1713:     }
  1714: }
  1715: 
  1716: //===========================================================================
  1717: // Function: FindFirstVisible / FindLastVisible
  1718: // Purpose: ...
  1719: //===========================================================================
  1720: 
  1721: int Taskbar::FindFirstVisible()
  1722: {
  1723:     int visibleItemsFound = 0;
  1724: 
  1725:     for (int i = 0; i < (int)taskList.size(); i++)
  1726:     {
  1727:         if (!OnCurrentWorkspace(taskList[i]->hwnd) || taskList[i]->hidden) continue;
  1728:         else
  1729:         {
  1730:             if (visibleItemsFound == taskButtonsOffset) return i; // -> Requested offset found!
  1731:             visibleItemsFound++;
  1732:         }
  1733:     }
  1734: 
  1735:     return 0; // -> Failsafe (requested offset not found)
  1736: }
  1737: 
  1738: int Taskbar::FindLastVisible(int offset)
  1739: {
  1740:     int visibleItemsFound = 0;
  1741: 
  1742:     for (int i = offset; i < (int)taskList.size(); i++)
  1743:     {
  1744:         if (!OnCurrentWorkspace(taskList[i]->hwnd) || taskList[i]->hidden) continue;
  1745:         else
  1746:         {
  1747:             visibleItemsFound++;
  1748:             if (visibleItemsFound == pSettings->taskbarMaxItems) return i;
  1749:         }
  1750:     }
  1751: 
  1752:     return -1; // -> Fewer than the maximum number of simultaneously visible items left in the taskbar list...
  1753: }
  1754: 
  1755: //===========================================================================
  1756: // Function: NextTask / PreviousTask
  1757: // Purpose: ...
  1758: //===========================================================================
  1759: 
  1760: void Taskbar::NextTask(bool currentWorkspaceOnly, bool visibleOnly)
  1761: {
  1762:     if ((int)taskList.size() == 0) return;
  1763: 
  1764:     HWND nextWindow = NULL;
  1765:     bool isAppPlugin = false;
  1766: 
  1767:     int offset = GetActiveTask();
  1768:     if (offset == NULL) offset = 0;
  1769:     else
  1770:     {
  1771:         offset++;
  1772:         if (offset >= (int)taskList.size()) offset = 0;
  1773:     }
  1774: 
  1775:     for (int i = offset; i < (int)taskList.size(); i++)
  1776:     {
  1777:         if (taskList[i]->active || taskList[i]->hidden) continue;
  1778:         else if (visibleOnly && IsIconic(taskList[i]->hwnd)) continue;
  1779:         else if (currentWorkspaceOnly && !OnCurrentWorkspace(taskList[i]->hwnd)) continue;
  1780:         else
  1781:         {
  1782:             nextWindow = taskList[i]->hwnd;
  1783:             if (taskList[i]->isAppPlugin) isAppPlugin = true;
  1784:             break;
  1785:         }
  1786:     }
  1787: 
  1788:     if ((offset > 0) && (nextWindow == NULL))
  1789:     {
  1790:         for (int i = 0; i < offset; i++)
  1791:         {
  1792:             if (taskList[i]->active || taskList[i]->hidden) continue;
  1793:             else if (visibleOnly && IsIconic(taskList[i]->hwnd)) continue;
  1794:             else if (currentWorkspaceOnly && !OnCurrentWorkspace(taskList[i]->hwnd)) continue;
  1795:             else
  1796:             {
  1797:                 nextWindow = taskList[i]->hwnd;
  1798:                 if (taskList[i]->isAppPlugin) isAppPlugin = true;
  1799:                 break;
  1800:             }
  1801:         }
  1802:     }
  1803: 
  1804:     if (nextWindow != NULL)
  1805:     {
  1806:         SetForegroundWindow(pToolbar->hToolbarWnd);
  1807:         SendMessage(hBlackboxWnd, BB_BRINGTOFRONT, 0, (LPARAM)nextWindow);
  1808:         SetActiveTask(nextWindow);
  1809:         if (isAppPlugin) SendMessage(nextWindow, BB_BROADCAST, 0, (LPARAM)"@AppPlugin Show");
  1810:         else if (IsIconic(nextWindow)) ShowWindow(nextWindow, SW_RESTORE);
  1811:         SetForegroundWindow(nextWindow);
  1812:         SetWindowPos(nextWindow, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
  1813:         PlaySoundFX(SFX_TASKBAR_RESTORE);
  1814:     }
  1815: }
  1816: 
  1817: //====================
  1818: 
  1819: void Taskbar::PreviousTask(bool currentWorkspaceOnly, bool visibleOnly)
  1820: {
  1821:     if ((int)taskList.size() == 0) return;
  1822: 
  1823:     HWND previousWindow = NULL;
  1824:     bool isAppPlugin = false;
  1825: 
  1826:     int offset = GetActiveTask();
  1827:     if (offset == NULL) offset = 0;
  1828:     else if (offset > 0) offset--;
  1829: 
  1830:     for (int i = offset; i >= 0; i--)
  1831:     {
  1832:         if (taskList[i]->active || taskList[i]->hidden) continue;
  1833:         else if (visibleOnly && IsIconic(taskList[i]->hwnd)) continue;
  1834:         else if (currentWorkspaceOnly && !OnCurrentWorkspace(taskList[i]->hwnd)) continue;
  1835:         else
  1836:         {
  1837:             previousWindow = taskList[i]->hwnd;
  1838:             if (taskList[i]->isAppPlugin) isAppPlugin = true;
  1839:             break;
  1840:         }
  1841:     }
  1842: 
  1843:     if (previousWindow == NULL)
  1844:     {
  1845:         for (int i = ((int)taskList.size()-1); i > offset; i--)
  1846:         {
  1847:             if (taskList[i]->active || taskList[i]->hidden) continue;
  1848:             else if (visibleOnly && IsIconic(taskList[i]->hwnd)) continue;
  1849:             else if (currentWorkspaceOnly && !OnCurrentWorkspace(taskList[i]->hwnd)) continue;
  1850:             else
  1851:             {
  1852:                 previousWindow = taskList[i]->hwnd;
  1853:                 if (taskList[i]->isAppPlugin) isAppPlugin = true;
  1854:                 break;
  1855:             }
  1856:         }
  1857:     }
  1858: 
  1859:     if (previousWindow != NULL)
  1860:     {
  1861:         SetForegroundWindow(pToolbar->hToolbarWnd);
  1862:         SendMessage(hBlackboxWnd, BB_BRINGTOFRONT, 0, (LPARAM)previousWindow);
  1863:         SetActiveTask(previousWindow);
  1864:         if (isAppPlugin) SendMessage(previousWindow, BB_BROADCAST, 0, (LPARAM)"@AppPlugin Show");
  1865:         else if (IsIconic(previousWindow)) ShowWindow(previousWindow, SW_RESTORE);
  1866:         SetForegroundWindow(previousWindow);
  1867:         SetWindowPos(previousWindow, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
  1868:         PlaySoundFX(SFX_TASKBAR_RESTORE);
  1869:     }
  1870: }
  1871: 
  1872: //===========================================================================
  1873: // Function: ChangeTaskbarMode
  1874: // Purpose: ...
  1875: //===========================================================================
  1876: 
  1877: void Taskbar::ChangeTaskbarMode(int mode)
  1878: {
  1879:     char setting[MAX_LINE_LENGTH];
  1880: 
  1881:     if (mode == TASKBAR_MODE_BARS)
  1882:     {
  1883:         pSettings->taskbarMode = TASKBAR_MODE_BARS;
  1884:         strcpy_s(setting, sizeofArray(setting), "Bars");
  1885:     }
  1886:     else if (mode == TASKBAR_MODE_BARSICONS)
  1887:     {
  1888:         pSettings->taskbarMode = TASKBAR_MODE_BARSICONS;
  1889:         strcpy_s(setting, sizeofArray(setting), "Bars+Icons");
  1890:     }
  1891:     else if (mode == TASKBAR_MODE_ICONS)
  1892:     {
  1893:         pSettings->taskbarMode = TASKBAR_MODE_ICONS;
  1894:         strcpy_s(setting, sizeofArray(setting), "Icons");
  1895:     }
  1896:     else // TASKBAR_MODE_HIDDEN
  1897:     {
  1898:         pSettings->taskbarMode = TASKBAR_MODE_HIDDEN;
  1899:         strcpy_s(setting, sizeofArray(setting), "Hidden");
  1900:     }
  1901: 
  1902:     if ((pSettings->taskbarMode == TASKBAR_MODE_HIDDEN) && pSettings->taskbarTooltips) pTooltips->DeleteAllTooltips();
  1903: 
  1904:     pToolbar->UpdatePosition(); // -> Refreshes the toolbar including the change of modes...
  1905:     PlaySoundFX(SFX_TOGGLE_ELEMENT);
  1906: 
  1907:     WriteString(pSettings->xobrcFile, "xoblite.taskbar.mode:", setting);
  1908: }
  1909: 
  1910: //===========================================================================
  1911: // Function: ToggleCurrentOnly
  1912: // Purpose: ...
  1913: //===========================================================================
  1914: 
  1915: void Taskbar::ToggleCurrentOnly()
  1916: {
  1917:     if (!pSettings->taskbarCurrentOnly) pSettings->taskbarCurrentOnly = true;
  1918:     else pSettings->taskbarCurrentOnly = false;
  1919: 
  1920:     SendMessage(hBlackboxWnd, BB_TASKSUPDATE, NULL, (LPARAM)TASKITEM_REFRESH);
  1921: 
  1922:     WriteBool(pSettings->xobrcFile, "xoblite.taskbar.currentOnly:", pSettings->taskbarCurrentOnly);
  1923: }
  1924: 
  1925: //===========================================================================
  1926: // Function: OnCurrentWorkspace
  1927: // Purpose: ...
  1928: //===========================================================================
  1929: 
  1930: bool Taskbar::OnCurrentWorkspace(HWND window)
  1931: {
  1932:     if (!pSettings->taskbarCurrentOnly) return true;
  1933: 
  1934: //  int TaskOnWorkspaceNumber = pWorkspaces->GetWorkspaceByWindow(window);
  1935: //  if ((TaskOnWorkspaceNumber == pSettings->currentWorkspace) || (TaskOnWorkspaceNumber == 254) || (TaskOnWorkspaceNumber == 255)) return true;
  1936: //  else return false;
  1937: 
  1938:     int i = FindTask(window);
  1939:     if (i >= 0)
  1940:     {
  1941:         if ((taskList[i]->workspace == pSettings->currentWorkspace) || (taskList[i]->workspace == 254)) return true;
  1942:     }
  1943: 
  1944:     return false;
  1945: }
  1946: 
  1947: //===========================================================================
  1948: // Function: GetTaskButtonsToDraw
  1949: // Purpose: Get the number of task buttons to draw on the taskbar
  1950: //          (number depends on the "current workspace only" boolean setting)
  1951: //===========================================================================
  1952: 
  1953: int Taskbar::GetTaskButtonsToDraw()
  1954: {
  1955:     taskButtonsToDraw = 0;
  1956: 
  1957:     for (int i=0; i < (int)taskList.size(); i++)
  1958:     {
  1959:         if (pSettings->taskbarCurrentOnly && !OnCurrentWorkspace(taskList[i]->hwnd)) continue;
  1960:         if (!taskList[i]->hidden) taskButtonsToDraw++;
  1961:     }
  1962: 
  1963:     if ((pSettings->taskbarMaxItems > 0) && (taskButtonsToDraw > pSettings->taskbarMaxItems)) taskButtonsToDraw = pSettings->taskbarMaxItems;
  1964: 
  1965:     return taskButtonsToDraw;
  1966: }
  1967: 
  1968: //===========================================================================
  1969: // Function: GetTaskbarScrollIndicatorSizes
  1970: // Purpose: ...
  1971: //===========================================================================
  1972: 
  1973: int Taskbar::GetTaskbarScrollIndicatorSizes(int* leftTopPadding, int* rightBottomPadding)
  1974: {
  1975:     int taskbarScrollIndicatorSize;
  1976:     if (pSettings->Toolbar->marginWidth > 0) taskbarScrollIndicatorSize = pSettings->Toolbar->marginWidth;
  1977:     else if (pSettings->Toolbar->borderWidth > 0) taskbarScrollIndicatorSize = pSettings->Toolbar->borderWidth;
  1978:     taskbarScrollIndicatorSize = 2 * pSettings->scalingFactorHiDPI;
  1979: 
  1980:     GetTaskButtonsToDraw();
  1981:     int firstButton = FindFirstVisible();
  1982:     int lastButton = FindLastVisible(firstButton);
  1983:     if (lastButton < 0) lastButton = (int)taskList.size()-1; // Failsafe
  1984: 
  1985:     if (taskButtonsOffset > 0) *leftTopPadding = taskbarScrollIndicatorSize; // -> Left/top taskbar scroll indicator to be drawn!
  1986:     else *leftTopPadding = 0;
  1987: 
  1988:     for (int i = (lastButton+1); i < (int)taskList.size(); i++)
  1989:     {
  1990:         if (!OnCurrentWorkspace(taskList[i]->hwnd) || taskList[i]->hidden) continue;
  1991:         else
  1992:         {
  1993:             *rightBottomPadding = taskbarScrollIndicatorSize; // -> Right/bottom taskbar scroll indicator to be drawn!
  1994:             return taskbarScrollIndicatorSize;
  1995:         }
  1996:     }
  1997: 
  1998:     *rightBottomPadding = 0;
  1999: 
  2000:     return taskbarScrollIndicatorSize;
  2001: }
  2002: 
  2003: //===========================================================================
  2004: // Function: CheckCloakedWindow
  2005: // Purpose: Checks if a window is a DWM cloaked window
  2006: //===========================================================================
  2007: 
  2008: bool Taskbar::CheckCloakedWindow(HWND hwnd)
  2009: {
  2010:     // Check for DWM cloaked windows... (e.g. preloading Windows 10 apps like Microsoft Edge etc)
  2011:     int cloaked = 0;
  2012:     HRESULT hr = DwmGetWindowAttribute(hwnd, DWMWA_CLOAKED, &cloaked, 4);
  2013:     if (hr != S_OK) return false;
  2014: 
  2015:     if (cloaked > 0)
  2016:     {
  2017: /*
  2018:         if (pSettings->debugLogging)
  2019:         {
  2020:             char msg[MAX_LINE_LENGTH], windowText[MAX_LINE_LENGTH];
  2021:             GetWindowText(hwnd, windowText, sizeof(windowText));
  2022:             if (cloaked == DWM_CLOAKED_APP) sprintf_s(msg, sizeofArray(msg), "DEBUG -> Taskbar::CheckCloakedWindow -> Cloaked window found! (DWM_CLOAKED_APP) -> %s", windowText);
  2023:             else if (cloaked == DWM_CLOAKED_SHELL) sprintf_s(msg, sizeofArray(msg), "DEBUG -> Taskbar::CheckCloakedWindow -> Cloaked window found! (DWM_CLOAKED_SHELL) -> %s", windowText);
  2024:             else if (cloaked == DWM_CLOAKED_INHERITED) sprintf_s(msg, sizeofArray(msg), "DEBUG -> Taskbar::CheckCloakedWindow -> Cloaked window found! (DWM_CLOAKED_INHERITED) -> %s", windowText);
  2025:             else sprintf_s(msg, sizeofArray(msg), "DEBUG -> Taskbar::CheckCloakedWindow -> Cloaked window found! (unknown DWMWA_CLOAKED value) -> %s", windowText);
  2026:             SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
  2027:             Log(msg, "");
  2028:         }
  2029: */
  2030:         return true;
  2031:     }
  2032:     else
  2033:     {
  2034: /*
  2035:         if (pSettings->debugLogging)
  2036:         {
  2037:             char msg[MAX_LINE_LENGTH], windowText[MAX_LINE_LENGTH];
  2038:             GetWindowText(hwnd, windowText, sizeof(windowText));
  2039:             sprintf_s(msg, sizeofArray(msg), "DEBUG -> Taskbar::CheckCloakedWindow -> This window is uncloaked... -> %s", windowText);
  2040:             SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
  2041:             Log(msg, "");
  2042:         }
  2043: */
  2044:         return false;
  2045:     }
  2046: }
  2047: 
  2048: //===========================================================================
  2049: // Function: SortTaskbarItems + CompareTaskbarItemsByName/LastUsed
  2050: // Purpose: Sorts the taskbar items in alphabetical or "last used" order
  2051: //===========================================================================
  2052: 
  2053: void Taskbar::SortTaskbarItems(int mode)
  2054: {
  2055:     if (mode == TASKBAR_SORT_BY_LAST_USED) sort(taskList.begin(), taskList.end(), Taskbar::CompareTaskbarItemsByLastUsed);
  2056: //  else if (mode == TASKBAR_SORT_BY_NAME) sort(taskList.begin(), taskList.end(), Taskbar::CompareTaskbarItemsByName);
  2057: }
  2058: 
  2059: bool Taskbar::CompareTaskbarItemsByLastUsed(taskListItem* t1, taskListItem* t2)
  2060: {
  2061:     return t1->lastUsed < t2->lastUsed;
  2062: }
  2063: /*
  2064: bool Taskbar::CompareTaskbarItemsByName(taskListItem* t1, taskListItem* t2)
  2065: {
  2066:     return _stricmp(t1->caption, t2->caption) < 0;
  2067: }
  2068: */
  2069: //===========================================================================
  2070: // Functions: TileWindow
  2071: // Purpose: Support for basic window tiling (via e.g. hotkey'able bro@ms)
  2072: //===========================================================================
  2073: 
  2074: void Taskbar::TileWindow(int placement)
  2075: {
  2076:     // Find the currently active task...
  2077:     int i = GetActiveTask();
  2078:     if (i == -1) return;
  2079:     if (taskList[i]->dimensions.placement == placement) return;
  2080: 
  2081:     HWND currentWnd = taskList[i]->hwnd;
  2082: 
  2083:     RECT workArea;
  2084:     SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&workArea, SPIF_SENDCHANGE);
  2085:     int screenWidth = (workArea.right - workArea.left);
  2086:     int screenHeight = (workArea.bottom - workArea.top);
  2087:     int halfScreenWidth = screenWidth / 2;
  2088:     int halfScreenHeight = screenHeight / 2;
  2089:     int quarterScreenWidth = screenWidth / 4;
  2090:     int quarterScreenHeight = screenHeight / 4;
  2091:     int thirdScreenWidth = screenWidth / 3;
  2092:     
  2093:     if (taskList[i]->dimensions.placement == PLACEMENT_DEFAULT)
  2094:     {
  2095:         // Save the position and dimensions of a non-tiled window before tiling it,
  2096:         // so we can go back to this non-tiled state later on...
  2097:         if (IsZoomed(currentWnd))
  2098:         {
  2099:             taskList[i]->dimensions.centeredx = taskList[i]->dimensions.centeredy = true; // For now we re-use these placement bools to save the maximized/restored state of the window
  2100:             ShowWindow(currentWnd, SW_RESTORE);
  2101:         }
  2102:         else taskList[i]->dimensions.centeredx = taskList[i]->dimensions.centeredy = false;
  2103: 
  2104:         RECT r;
  2105:         GetWindowRect(currentWnd, &r);
  2106:         taskList[i]->dimensions.x = r.left;
  2107:         taskList[i]->dimensions.y = r.top;
  2108:         taskList[i]->dimensions.width = r.right - r.left;
  2109:         taskList[i]->dimensions.height = r.bottom - r.top;
  2110:     }
  2111: 
  2112:     taskList[i]->dimensions.placement = placement; // Save the new window placement
  2113:     
  2114:     switch (placement)
  2115:     {
  2116:         // ###################################
  2117:         // ##### Default non-tiled state #####
  2118:         // ###################################
  2119: 
  2120:         case PLACEMENT_DEFAULT:
  2121:         {
  2122:             MoveWindow(currentWnd, taskList[i]->dimensions.x, taskList[i]->dimensions.y, taskList[i]->dimensions.width, taskList[i]->dimensions.height, true);
  2123:             if (taskList[i]->dimensions.centeredx && taskList[i]->dimensions.centeredy) ShowWindow(currentWnd, SW_MAXIMIZE);
  2124:             break;
  2125:         }
  2126: 
  2127:         // #######################################
  2128:         // ##### Centered at 2/3 screen size #####
  2129:         // #######################################
  2130: 
  2131:         case PLACEMENT_CENTERED:
  2132:         {
  2133:             MoveWindow(currentWnd, workArea.left + (quarterScreenWidth / 2), workArea.top + (quarterScreenHeight / 2), (halfScreenWidth + quarterScreenWidth), (halfScreenHeight + quarterScreenHeight), true);
  2134:             break;
  2135:         }
  2136: 
  2137:         // ###########################################
  2138:         // ##### Half screen size tiling options #####
  2139:         // ###########################################
  2140: 
  2141:         case PLACEMENT_LEFT_HALF:
  2142:         {
  2143:             MoveWindow(currentWnd, workArea.left, workArea.top, halfScreenWidth, screenHeight, true);
  2144:             break;
  2145:         }
  2146: 
  2147:         case PLACEMENT_RIGHT_HALF:
  2148:         {
  2149:             MoveWindow(currentWnd, workArea.left + halfScreenWidth, workArea.top, halfScreenWidth, screenHeight, true);
  2150:             break;
  2151:         }
  2152: 
  2153:         case PLACEMENT_TOP_HALF:
  2154:         {
  2155:             MoveWindow(currentWnd, workArea.left, workArea.top, screenWidth, halfScreenHeight, true);
  2156:             break;
  2157:         }
  2158: 
  2159:         case PLACEMENT_BOTTOM_HALF:
  2160:         {
  2161:             MoveWindow(currentWnd, workArea.left, workArea.top + halfScreenHeight, screenWidth, halfScreenHeight, true);
  2162:             break;
  2163:         }
  2164: 
  2165:         // ################################################
  2166:         // ##### One third screen size tiling options #####
  2167:         // ################################################
  2168: 
  2169:         case PLACEMENT_CENTER_LEFT:
  2170:         {
  2171:             MoveWindow(currentWnd, workArea.left, workArea.top, thirdScreenWidth, screenHeight, true);
  2172:             break;
  2173:         }
  2174: 
  2175:         case PLACEMENT_CENTER_CENTER:
  2176:         {
  2177:             MoveWindow(currentWnd, workArea.left + thirdScreenWidth, workArea.top, thirdScreenWidth, screenHeight, true);
  2178:             break;
  2179:         }
  2180: 
  2181:         case PLACEMENT_CENTER_RIGHT:
  2182:         {
  2183:             MoveWindow(currentWnd, workArea.right - thirdScreenWidth, workArea.top, thirdScreenWidth, screenHeight, true);
  2184:             break;
  2185:         }
  2186: 
  2187:         // ##################################################
  2188:         // ##### One quarter screen size tiling options #####
  2189:         // ##################################################
  2190: 
  2191:         case PLACEMENT_TOP_LEFT:
  2192:         {
  2193:             MoveWindow(currentWnd, workArea.left, workArea.top, halfScreenWidth, halfScreenHeight, true);
  2194:             break;
  2195:         }
  2196: 
  2197:         case PLACEMENT_BOTTOM_LEFT:
  2198:         {
  2199:             MoveWindow(currentWnd, workArea.left, workArea.bottom - halfScreenHeight, halfScreenWidth, halfScreenHeight, true);
  2200:             break;
  2201:         }
  2202: 
  2203:         case PLACEMENT_TOP_RIGHT:
  2204:         {
  2205:             MoveWindow(currentWnd, workArea.left + halfScreenWidth, workArea.top, halfScreenWidth, halfScreenHeight, true);
  2206:             break;
  2207:         }
  2208: 
  2209:         case PLACEMENT_BOTTOM_RIGHT:
  2210:         {
  2211:             MoveWindow(currentWnd, workArea.left + halfScreenWidth, workArea.top + halfScreenHeight, halfScreenWidth, halfScreenHeight, true);
  2212:             break;
  2213:         }
  2214: 
  2215:         // ##################################################
  2216:         // #####  One sixth screen size tiling options  #####
  2217:         // ##### (i.e. matches one third options above) #####
  2218:         // ##################################################
  2219: 
  2220:         case PLACEMENT_TOP_CENTER:
  2221:         {
  2222:             MoveWindow(currentWnd, workArea.left + thirdScreenWidth, workArea.top, thirdScreenWidth, halfScreenHeight, true);
  2223:             break;
  2224:         }
  2225: 
  2226:         case PLACEMENT_BOTTOM_CENTER:
  2227:         {
  2228:             MoveWindow(currentWnd, workArea.left + thirdScreenWidth, workArea.top + halfScreenHeight, thirdScreenWidth, halfScreenHeight, true);
  2229:             break;
  2230:         }
  2231: 
  2232:         default: { break; }
  2233:     }
  2234: 
  2235:     InvalidateRect(currentWnd, NULL, false);
  2236:     SetForegroundWindow(currentWnd);
  2237:     PlaySoundFX(SFX_TASKBAR_TILE);
  2238: }
  2239: 
  2240: //===========================================================================
  2241: