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(¤tTaskButton, &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, ¤tTaskButton); // ...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, ¤tTaskButton);
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, ¤tTaskButton);
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)¤tTaskButtonIcon);
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)¤tTaskButtonIcon);
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, ¤tTaskButton);
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, ¤tTaskButton);
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: