/*
 ============================================================================
 xoblite -> an alternative shell based on Blackbox for Windows
 Copyright © 2002-2005 Karl-Henrik Henriksson [qwilk]
 Copyright © 2001-2004 The Blackbox for Windows Development Team
 http://xoblite.net/ - #bb4win on irc.freenode.net
 ============================================================================

  Blackbox for Windows is free software, released under the
  GNU General Public License (GPL version 2 or later), with an extension
  that allows linking of proprietary modules under a controlled interface.
  What this means is that plugins etc. are allowed to be released
  under any license the author wishes. Please note, however, that the
  original Blackbox gradient math code used in Blackbox for Windows
  is available under the BSD license.

  http://www.fsf.org/licenses/gpl.html
  http://www.fsf.org/licenses/gpl-faq.html#LinkingOverControlledInterface
  http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.

  For additional license information, please read the included license.html

 ============================================================================

  Note1: The saturation/hue code section in SystembarWndProc was inspired by
  the equivalent section in LiteStep's systray2 module (systray.cpp),
  which is copyright (C) 1997-2002 The LiteStep Development Team.

  Note2: Parts of the TrayManager icon handling code was derived from the
  geOShell "TrayService" code, which is (C) 1999-2001 Geoffrey J. Elliott
  and the geOShell Development Team.

 ============================================================================
*/

#include "Systembar.h" 

const char szSystembarName[] = "BBSystembar"; // Window class etc.

extern BImage *pBImage;
extern Desk *pDesk;
extern Systembar *pSystembar;
extern TrayManager *pTrayManager;
extern Settings *pSettings;
extern MenuMaker *pMenuMaker;
extern Workspaces *pWorkspaces;
extern Toolbar *pToolbar;
extern Slit *pSlit;

//===========================================================================

Systembar::Systembar(HINSTANCE hInstance, bool DisableTray)
{
        // At startup, xoblite checks if the -nosystray switch was used or if it
        // is running on top of Explorer (which unfortunately also locks on to a
        // stand alone systray atm), and if so disables the xoblite internal systray
        if (DisableTray) SysTrayDisabled = true;
        else SysTrayDisabled = false;

        hSystembarWnd = NULL;
        hToolTips = NULL;
        hBlackboxWnd = GetBBWnd();
        hSystembarInstance = hInstance;

        cachedBackground = CreateCompatibleDC(NULL);
        cachedBackgroundExists = false;

        cachedTaskButtonActive = CreateCompatibleDC(NULL);
        cachedTaskButtonInactive = CreateCompatibleDC(NULL);
        cachedTaskButtonsExist = false;

        DockedToSlit = false;
        SystembarPosInProgress = false;

        //====================

        // Get size and position for our window...
        GetSettings();

        // Register our window class...
        WNDCLASS wc;
        ZeroMemory(&wc,sizeof(wc));
        wc.lpfnWndProc = SystembarWndProc;                                              // our window procedure
        wc.hInstance = hSystembarInstance;
        wc.lpszClassName = szSystembarName;                                             // our window class name

        if (!RegisterClass(&wc))
        {
                MessageBox(0, "Error registering window class", szSystembarName, MB_OK | MB_ICONERROR | MB_TOPMOST);
                Log("Systembar: Error registering window class", NULL);
                return;
        }

        hSystembarWnd = CreateWindowEx(
                WS_EX_TOOLWINDOW,                                                                       // exstyles
                szSystembarName,                                                                        // our window class name
                NULL,                                                                                           // use description for a window title
                WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
                SystembarX, SystembarY,                                                         // position
                SystembarWidth, SystembarHeight,                                        // width & height of window
                NULL,                                                                                           // parent window
                NULL,                                                                                           // no menu
                hSystembarInstance,                                                                     // hInstance of DLL
                NULL);

        if (!hSystembarWnd)
        {
                UnregisterClass(szSystembarName,hSystembarInstance); // unregister window class
                MessageBox(0, "Error creating window", szSystembarName, MB_OK | MB_ICONERROR | MB_TOPMOST);
                Log("Systembar: Error creating window", NULL);
                return;
        }

        //====================

        int msgs[] = { BB_RECONFIGURE, BB_TOGGLESYSTEMBAR, BB_ADDTASK, BB_REMOVETASK, BB_REDRAW, BB_ACTIVETASK, BB_ACTIVATESHELLWINDOW, 0 };
        SendMessage(hBlackboxWnd, BB_REGISTERMESSAGE, (WPARAM)hSystembarWnd, (LPARAM)msgs);

        // Make the systembar window sticky...
        MakeSticky(hSystembarWnd);
        // Set window to accept doubleclicks...
        SetClassLongPtr(hSystembarWnd, GCL_STYLE, CS_DBLCLKS | GetClassLongPtr(hSystembarWnd, GCL_STYLE));
        // Set window to accept drag'n'drop...
        DragAcceptFiles(hSystembarWnd, true);

        // Dock to slit depending on placement setting...
        if (!stricmp(pSettings->systembarPlacement, "DockedToSlit"))
        {
                ShowWindow(hSystembarWnd, SW_SHOWNOACTIVATE);
                SendMessage(pSlit->hSlitWnd, SLIT_ADD, NULL, (LPARAM)hSystembarWnd);
                DockedToSlit = true;
        }
        else
        {
                // If the systembar is docked to the toolbar it inherits the
                // toolbar alpha transparency value and AlwaysOnTop setting...
                if (!stricmp(pSettings->systembarPlacement, "DockedToToolbar"))
                {
                        if (pSettings->toolbarOnTop) SetWindowPos(hSystembarWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
                        else SetWindowPos(hSystembarWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
                        SetTransparency(hSystembarWnd, pSettings->toolbarTransparencyAlpha);
                }
                else
                {
                        if (pSettings->systembarOnTop) SetWindowPos(hSystembarWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
                        else SetWindowPos(hSystembarWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
                        SetTransparency(hSystembarWnd, pSettings->systembarTransparencyAlpha);
                }

                ShowWindow(hSystembarWnd, pSettings->systembarHidden ? SW_HIDE : SW_SHOWNOACTIVATE);
        }

        //====================

        INITCOMMONCONTROLSEX ic;
        ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
        ic.dwICC = ICC_BAR_CLASSES;

        InitCommonControlsEx(&ic);

        //====================

        if (!pSettings->systembarTooltipsDisabled) CreateTooltipsWindow();

        WinEnumeratorCount = 0;
        blockNextMouseClick = false;
        saveWidthOnRestart = false;
        ZeroMemory(&WindowList, sizeof(WindowList));
}

//===========================================================================

Systembar::~Systembar()
{
        if (pSlit && DockedToSlit) SendMessage(pSlit->hSlitWnd, SLIT_REMOVE, NULL, (LPARAM)hSystembarWnd);

        // Go through each of the elements in the WindowList array clearing each one
        for (int i=0; i < WinEnumeratorCount; i++)
        { 
                memset(&WindowList[i], 0, sizeof(TaskButton));
        }

        int msgs[] = { BB_RECONFIGURE, BB_TOGGLESYSTEMBAR, BB_ADDTASK, BB_REMOVETASK, BB_REDRAW, BB_ACTIVETASK, BB_ACTIVATESHELLWINDOW, 0 };
        SendMessage(hBlackboxWnd, BB_UNREGISTERMESSAGE, (WPARAM)hSystembarWnd, (LPARAM)msgs);
        if (hSystembarWnd) DestroyWindow(hSystembarWnd); // delete our window
        if (hToolTips) DestroyWindow(hToolTips);
        UnregisterClass(szSystembarName,hSystembarInstance); // unregister window class

        // Delete cached bitmaps...
        DeleteDC(cachedTaskButtonInactive);
        DeleteDC(cachedTaskButtonActive);
        DeleteDC(cachedBackground);
}

//===========================================================================

void Systembar::Initialize()
{
        EnumWindows(WinEnumerator, 0);
}

//===========================================================================

LRESULT CALLBACK SystembarWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        
        switch (message)
        {
        //====================

                case WM_PAINT:
                {
                        PAINTSTRUCT ps;
                        HDC hdc = BeginPaint(hwnd, &ps);
                        HDC buf = CreateCompatibleDC(NULL);
                        RECT r;
                        int updateRectWidth = ps.rcPaint.right - ps.rcPaint.left;
                        int updateRectHeight = ps.rcPaint.bottom - ps.rcPaint.top;

                        HBITMAP bufbmp = CreateCompatibleBitmap(hdc, pSystembar->SystembarWidth, pSystembar->SystembarHeight);
                        HBITMAP oldbuf = (HBITMAP)SelectObject(buf, bufbmp);

                        //====================

                        // If we have not yet created a cached background, let's do that...
                        if (!pSystembar->cachedBackgroundExists)
                        {
                                // Create a temporary bitmap...
                                HBITMAP tempBitmap = CreateCompatibleBitmap(hdc, pSystembar->SystembarWidth, pSystembar->SystembarHeight);

                                // Delete the previously cached gradient...
                                HBITMAP oldBitmap = (HBITMAP)SelectObject(pSystembar->cachedBackground, tempBitmap);
                                DeleteObject(oldBitmap);

                                // Paint background + border... (now using MakeGradient instead of CreateBorder + CreateGradientByRect)
                                GetClientRect(hwnd, &r);
                                MakeGradient(pSystembar->cachedBackground, r, pSettings->Toolbar->type, pSettings->Toolbar->Color, pSettings->Toolbar->ColorTo, pSettings->Toolbar->interlaced, pSettings->Toolbar->bevelstyle, pSettings->Toolbar->bevelposition, pSettings->bevelWidth, pSettings->Toolbar->borderColor, pSettings->Toolbar->borderWidth);

                                // Clean up - delete the temporary bitmap...
                                DeleteObject(tempBitmap);

                                // Set the "cached background created" indicator...
                                pSystembar->cachedBackgroundExists = true;
                        }

                        //====================

                        // Copy the cached background into the temporary buffer...
                        BitBlt(buf, ps.rcPaint.left, ps.rcPaint.top, updateRectWidth, updateRectHeight, pSystembar->cachedBackground, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);

                        // Paint the system tray and taskbar...
                        int iconPos = pSystembar->DrawSysTray(buf);

                        if (!pSystembar->SysTrayDisabled)
                        {
                                if (pTrayManager->ShowBalloonTooltip)
                                {
                                        // Create a single maximum width button for the "balloon tooltip"...
                                        r.left = r.top = pSettings->Toolbar->borderWidth + 2;
                                        r.right = pSystembar->SystembarWidth - iconPos - 2;
                                        int xmin = r.left + ICON_SIZE + 8;
                                        int xmax = r.right - 5;
                                        r.bottom = pSystembar->SystembarHeight - pSettings->Toolbar->borderWidth - 2;

                                        BYTE red, green, blue;
                                        COLORREF bColor, bColorTo, bTextColor, bShadowColor;
                                        red = GetRValue(pSettings->ActiveTask->Color);
                                        green = GetGValue(pSettings->ActiveTask->Color);
                                        blue = GetBValue(pSettings->ActiveTask->Color);
//                                      bColor = RGB((BYTE)blue, (BYTE)red, (BYTE)green);
//                                      bColor = RGB((BYTE)green, (BYTE)blue, (BYTE)red);
                                        bColor = RGB((BYTE)blue, (BYTE)green, (BYTE)red);
//                                      bColor = RGB((BYTE)red, (BYTE)green, (BYTE)blue);
                                        red = GetRValue(pSettings->ActiveTask->ColorTo);
                                        green = GetGValue(pSettings->ActiveTask->ColorTo);
                                        blue = GetBValue(pSettings->ActiveTask->ColorTo);
//                                      bColorTo = RGB((BYTE)blue, (BYTE)red, (BYTE)green);
//                                      bColorTo = RGB((BYTE)green, (BYTE)blue, (BYTE)red);
                                        bColorTo = RGB((BYTE)blue, (BYTE)green, (BYTE)red);
//                                      bColorTo = RGB((BYTE)red, (BYTE)green, (BYTE)blue);
                                        red = GetRValue(pSettings->ActiveTask->TextColor);
                                        green = GetGValue(pSettings->ActiveTask->TextColor);
                                        blue = GetBValue(pSettings->ActiveTask->TextColor);
//                                      bTextColor = RGB((BYTE)blue, (BYTE)red, (BYTE)green);
//                                      bTextColor = RGB((BYTE)green, (BYTE)blue, (BYTE)red);
                                        bTextColor = RGB((BYTE)blue, (BYTE)green, (BYTE)red);
//                                      bTextColor = RGB((BYTE)red, (BYTE)green, (BYTE)blue);
                                        red = GetRValue(pSettings->activeTaskShadowColor);
                                        green = GetGValue(pSettings->activeTaskShadowColor);
                                        blue = GetBValue(pSettings->activeTaskShadowColor);
//                                      bShadowColor = RGB((BYTE)blue, (BYTE)red, (BYTE)green);
//                                      bShadowColor = RGB((BYTE)green, (BYTE)blue, (BYTE)red);
                                        bShadowColor = RGB((BYTE)blue, (BYTE)green, (BYTE)red);
//                                      bShadowColor = RGB((BYTE)red, (BYTE)green, (BYTE)blue);

//                                      MakeGradient(buf, r, B_SOLID, 0xccffff, 0xccffff, false, BEVEL_FLAT, BEVEL1, 0, 0x000000, 1);
                                        MakeGradient(buf, r, pSettings->ActiveTask->type, bColor, bColorTo, false, pSettings->ActiveTask->bevelstyle, pSettings->ActiveTask->bevelposition, pSettings->bevelWidth, pSettings->Toolbar->borderColor, 1);
//                                      MakeGradient(buf, r, pSettings->Slit->type, pSettings->Slit->Color, pSettings->Slit->ColorTo, pSettings->Slit->interlaced, pSettings->Slit->bevelstyle, pSettings->Slit->bevelposition, pSettings->bevelWidth, pSettings->slitBorderColor, 1);
//                                      MakeGradient(buf, r, pSettings->ActiveTask->type, pSettings->Slit->Color, pSettings->Slit->ColorTo, false, pSettings->ActiveTask->bevelstyle, pSettings->ActiveTask->bevelposition, pSettings->bevelWidth, pSettings->slitBorderColor, 1);

                                        SIZE size;
                                        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, pSettings->Toolbar->Font);
                                        HGDIOBJ oldfont = SelectObject(buf, font);
                                        SetBkMode(buf, TRANSPARENT);
                                        GetTextExtentPoint32(buf, pTrayManager->BalloonTooltipText, strlen(pTrayManager->BalloonTooltipText), &size);
                                        r.left = ((r.right - r.left - size.cx)/2) + 12;
                                        r.right = r.left + size.cx;
                                        if (r.left < xmin) r.left = xmin;
                                        if (r.right > xmax) r.right = xmax;
//                                      DrawTextWithShadow(buf, pTrayManager->BalloonTooltipText, r, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS, 0x000000, 0x000000, false);
                                        DrawTextWithShadow(buf, pTrayManager->BalloonTooltipText, r, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS, bTextColor, bShadowColor, pSettings->ActiveTask->FontShadow);
//                                      DrawTextWithShadow(buf, pTrayManager->BalloonTooltipText, r, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS, pSettings->ActiveTask->TextColor, pSettings->activeTaskShadowColor, pSettings->ActiveTask->FontShadow);
                                        DeleteObject(SelectObject(buf, oldfont));

                                        RECT iconRect;
                                        iconRect.left = r.left - ICON_SIZE - 2;
                                        iconRect.right = r.left + ICON_SIZE;
                                        iconRect.top = r.top + 1;
                                        iconRect.bottom = r.top + ICON_SIZE;

                                        HICON bIcon = LoadIcon(NULL, pTrayManager->BalloonTooltipIcon);

//                                      pSystembar->DrawSatHueIcon(buf, bIcon, ICON_SIZE, iconRect, false, false);
                                        DrawIconEx(buf, iconRect.left, iconRect.top, bIcon, ICON_SIZE, ICON_SIZE, 0, NULL, DI_NORMAL);
                                        DeleteObject(bIcon);

                                        if (pTrayManager->BalloonTooltipItem.hWnd != NULL)
                                        {
                                                // Inform the parent application that the balloon tooltip has been shown...
                                                PostMessage(pTrayManager->BalloonTooltipItem.hWnd, pTrayManager->BalloonTooltipItem.uCallbackMessage, pTrayManager->BalloonTooltipItem.uID, NIN_BALLOONSHOW);
                                        }
                                }
                                else
                                {
                                        r.left = r.top = pSettings->Toolbar->borderWidth + 2;
                                        r.right = pSystembar->SystembarWidth - iconPos - 2;
                                        r.bottom = pSystembar->SystembarHeight - pSettings->Toolbar->borderWidth - 2;
                                        if (!pSettings->taskbarOnToolbar) pSystembar->DrawTaskbar(buf, iconPos, r);
                                        else if (pToolbar) pToolbar->DrawWindowLabel(buf, r);
                                }
                        }
                        else
                        {
                                r.left = r.top = pSettings->Toolbar->borderWidth + 2;
                                r.right = pSystembar->SystembarWidth - iconPos - 2;
                                r.bottom = pSystembar->SystembarHeight - pSettings->Toolbar->borderWidth - 2;
                                if (!pSettings->taskbarOnToolbar) pSystembar->DrawTaskbar(buf, iconPos, r);
                                else if (pToolbar) pToolbar->DrawWindowLabel(buf, r);
                        }

                        // Finally, we copy the buffer to the display...
                        BitBlt(hdc, 0, 0, pSystembar->SystembarWidth, pSystembar->SystembarHeight, buf, 0, 0, SRCCOPY);

                        //====================

                        SelectObject(buf, oldbuf);
                        DeleteDC(buf);
                        DeleteObject(bufbmp);
                        DeleteObject(oldbuf);

                        EndPaint(hwnd, &ps);
                        return 0;
                }
                break;

                //====================

                case BB_ADDTASK:
                {
                        pSystembar->AddWindow((HWND)wParam);
                }
                break;

                //====================

                case BB_REMOVETASK:
                {
                        pSystembar->RemoveWindow((HWND)wParam);
                }
                break;

                //====================

                case BB_ACTIVETASK:
                {
                        for (int i=0; i < pSystembar->WinEnumeratorCount; i++)
                        {
                                if (pSystembar->WindowList[i].Window == (HWND)wParam)
                                {
                                        pSystembar->WindowList[i].Active = true;
//                                      SetTransparency(pSystembar->WindowList[i].Window, 255);
                                }
                                else
                                {
                                        pSystembar->WindowList[i].Active = false;
//                                      SetTransparency(pSystembar->WindowList[i].Window, 210);
                                }
                        }

                        if (pSettings->taskbarOnToolbar && pToolbar) InvalidateRect(pToolbar->hToolbarWnd, &pToolbar->winlabelRect, false);
                        else if (pSystembar) InvalidateRect(pSystembar->hSystembarWnd, &pSystembar->MainRect, false);
                }
                break;

                //====================

                case BB_REDRAW:
                {
                        for (int i=0; i < pSystembar->WinEnumeratorCount; i++)
                        {
                                if (pSystembar->WindowList[i].Window == (HWND)wParam)
                                {
                                        if (pSettings->taskbarOnToolbar && pToolbar) InvalidateRect(pToolbar->hToolbarWnd, &pSystembar->WindowList[i].r, false);
                                        else if (pSystembar) InvalidateRect(pSystembar->hSystembarWnd, &pSystembar->WindowList[i].r, false);
                                        break;
                                }
                        }
                }
                break;

                //====================

                case BB_ACTIVATESHELLWINDOW:
                {
                        for (int i=0; i < pSystembar->WinEnumeratorCount; i++)
                                pSystembar->WindowList[i].Active = false;

//                      SetForegroundWindow(pSystembar->hBlackboxWnd);

                        if (pSettings->taskbarOnToolbar && pToolbar) InvalidateRect(pToolbar->hToolbarWnd, &pToolbar->winlabelRect, false);
                        else if (pSystembar) InvalidateRect(pSystembar->hSystembarWnd, &pSystembar->MainRect, false);
                }
                break;

                //====================

                case WM_DROPFILES:
                {
                        if (pSystembar->MouseButtonOnTaskbar(hwnd, message, wParam, lParam))
                        {
                                return 0;
                        }
                        else
                        {
                                static TCHAR filename[MAX_LINE_LENGTH];
                                DragQueryFile((HDROP)wParam, 0, filename, sizeof(filename));

                                // Make sure the dropped file isn't a directory...
                                if (PathIsDirectory(filename))
                                {
                                        MessageBox(0, "Trying to fool me, eh?\n...drag'n'drop a style file instead!", "xoblite", MB_OK | MB_TOPMOST);
                                        DragFinish((HDROP)wParam);
                                        return 0;
                                }
                                else
                                {
                                        // Look for a line that should "always" exist in a style file...
                                        if (strlen(ReadString(filename, "menu.frame:", "")))
                                        {
                                                // Set new style...
                                                SendMessage(pSystembar->hBlackboxWnd, BB_SETSTYLE, 0, (LPARAM)filename);
                                                DragFinish((HDROP)wParam);
                                        }
                                        else
                                        {
                                                MessageBox(0, "Trying to fool me, eh?\n...drag'n'drop a style file instead!", "xoblite", MB_OK | MB_TOPMOST);
                                                DragFinish((HDROP)wParam);
                                        }

                                        return 0;
                                }
                        }
                }
                break;

                //====================

                case BB_RECONFIGURE:
                {
                        // If needed, get new settings, resize window etc...
                        // NOTE: If DockedToToolbar then pSystembar->UpdatePosition is called from Toolbar!
                        if (stricmp(pSettings->systembarPlacement, "DockedToToolbar")) pSystembar->UpdatePosition();
//                      if (pSystembar->DockedToSlit) SendMessage(pSlit->hSlitWnd, SLIT_UPDATE, NULL, NULL);
                }
                break;

                //====================

                case BB_TOGGLESYSTEMBAR:
                {
                        if (!pSystembar->DockedToSlit)
                        {
                                if (!pSettings->systembarHidden) pSettings->systembarHidden = true;
                                else pSettings->systembarHidden = false;

                                WriteBool(pSettings->extrcFile, "xoblite.systembar.hidden:", pSettings->systembarHidden);

                                if (!pSettings->systembarHidden) pSystembar->UpdatePosition(); // Get new setting, resize window etc...
                                ShowWindow(pSystembar->hSystembarWnd, pSettings->systembarHidden ? SW_HIDE : SW_SHOWNOACTIVATE);
                        }
                        else MessageBox(GetBBWnd(), "Please note that the systembar window can not   \nbe independently hidden while docked to the slit.   \n\n...try hiding the slit window instead.", "xoblite", MB_OK | MB_ICONINFORMATION | MB_TOPMOST);
                }
                break;

                //====================

                case WM_CLOSE:
                        return 0;

                //====================

                case WM_DISPLAYCHANGE:
                {
                        if (pSettings->systembarHidden) break;
                        // If needed, get new settings, resize window etc...
                        // NOTE: If DockedToToolbar then pSystembar->UpdatePosition is called from Toolbar!
                        if (stricmp(pSettings->systembarPlacement, "DockedToToolbar")) pSystembar->UpdatePosition(); // Gets new settings and resizes window...
                        if (!pSystembar->SysTrayDisabled) pSystembar->UpdateToolTipPositions(); // Update tooltip x/y positions...
//                      // Force re-rendering of the background and task button bitmaps...
//                      pSystembar->cachedBackgroundExists = false;
//                      pSystembar->cachedTaskButtonsExist = false;
//                      if (pSystembar->DockedToSlit) SendMessage(pSlit->hSlitWnd, SLIT_UPDATE, NULL, NULL);
//                      InvalidateRect(pSystembar->hSystembarWnd, NULL, false);
                }
                break;

                //====================
/*
                case WM_MOUSEACTIVATE:
                        return MA_NOACTIVATE;

                case WM_ACTIVATE:
                        if (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE) SetActiveWindow(hwnd);
                return 0;
*/
                //====================

                case WM_WINDOWPOSCHANGING:
                {
                        // Snap window to screen edges when in manual positioning mode?
                        if (pSettings->systembarPlacement[0] == 'M' && pSettings->systembarSnapToEdges)
                        {
                                if (pSystembar)
                                {
                                        if (!pSystembar->DockedToSlit && IsWindowVisible(hwnd)) SnapWindowToEdge((WINDOWPOS*)lParam, pSettings->edgeSnapThreshold, true);
                                }
                        }
                }
                break;

                //====================

                case WM_EXITSIZEMOVE:
                {
                        if (pSystembar->SystembarPosInProgress)
                        {
                                pSystembar->SystembarPosInProgress = false;

                                RECT r;
                                GetWindowRect(pSystembar->hSystembarWnd, &r);
                                pSystembar->SystembarX = r.left;
                                pSystembar->SystembarY = r.top;
                                sprintf(pSettings->systembarPlacement, "Manual x%d y%d", pSystembar->SystembarX, pSystembar->SystembarY);

                                pSystembar->UpdatePosition(); // NOTE: Including saving placement to extensions.rc
                        }

                        return 0;
                }

                //====================

                // Allow window to move if control key is being held down,
                // holding down the shift key and left clicking moves the window
                // back to the default position...
                case WM_NCHITTEST:
                {
                        if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) && !pSystembar->DockedToSlit)
                        {
                                pSystembar->SystembarPosInProgress = true;
                                return HTCAPTION;
                        }
                        return HTCLIENT;
                }
                break;

                //====================

                case WM_MOUSEMOVE:
                {
                        if (pSettings->toolbarAutoHide && pToolbar)
                        {
                                if (!stricmp(pSettings->systembarPlacement, "DockedToToolbar"))
                                {
                                        if (IsInString(pSettings->toolbarPlacement, "Bottom"))
                                        {
                                                if (HIWORD(lParam) == (pSystembar->SystembarHeight - 1)) pToolbar->AutoShow();
                                        }
                                        else
                                        {
                                                if (HIWORD(lParam) == 0) pToolbar->AutoShow();
                                        }
                                }
                        }
/*
                        if (pSystembar->hToolTips) // Reroute mouse messages to the tooltip window...
                        {
                                MSG ttMsg;

                                ttMsg.message = message;
                                ttMsg.hwnd = hwnd;
                                ttMsg.wParam = wParam;
                                ttMsg.lParam = lParam;

                                SendMessage(pSystembar->hToolTips, TTM_RELAYEVENT, 0, (LPARAM)(LPMSG)&ttMsg);
                        }
*/
                }
                break;

                //====================

                case WM_LBUTTONDOWN:
                case WM_LBUTTONUP:
                case WM_LBUTTONDBLCLK:
                case WM_RBUTTONDOWN:
                case WM_RBUTTONUP:
                case WM_RBUTTONDBLCLK:
                case WM_MBUTTONDOWN:
                case WM_MBUTTONUP:
                case WM_MBUTTONDBLCLK:
                {
                        if (pSystembar->MouseButtonOnTaskbar(hwnd, message, wParam, lParam))
                        {
                                return DefWindowProc(hwnd, message, wParam, lParam);
                        }
                        else
                        {
                                if (!pSettings->systrayHidden && !pSystembar->SysTrayDisabled)
                                {
                                        int offsetIconX = 2 + pSettings->Toolbar->borderWidth;
//                                      int offsetIconY = 3 + pSettings->Toolbar->borderWidth;
                                        int offsetIconY = pSystembar->SystembarHeight/2 - ICON_SIZE/2;

                                        // Calculate relative x position from the right...
                                        int relX = pSystembar->SystembarWidth - LOWORD(lParam) - offsetIconX;
                                        // Calculate relative y position...
                                        int relY = HIWORD(lParam);

//                                      if (relY >= offsetIconY && relY <= (pSystembar->SystembarHeight - offsetIconY))
                                        if (relY >= offsetIconY && relY <= (offsetIconY + ICON_SIZE))
                                        {
                                                for (int i = 0; i < (int)pTrayManager->trayIconList.size(); i++)
                                                {
                                                        if ((relX > (i * (ICON_SIZE + 2))) && (relX <= ((i+1) * (ICON_SIZE + 2))))
                                                        {
                                                                if (pTrayManager->trayIconList[i]->hWnd)
                                                                {
                                                                        // Set the focus to the right/left click icon menu, so that it will disappear when it looses focus
                                                                        if (message == WM_RBUTTONDOWN || message == WM_LBUTTONDOWN || message == WM_MBUTTONDOWN) SetForegroundWindow(pTrayManager->trayIconList[i]->hWnd);
                                                                        // Reroute the mouse message to the tray icon's host window...
//                                                                      SendMessage(pTrayManager->trayIconList[i]->hWnd, pTrayManager->trayIconList[i]->uCallbackMessage, pTrayManager->trayIconList[i]->uID, LPARAM(message));
                                                                        PostMessage(pTrayManager->trayIconList[i]->hWnd, pTrayManager->trayIconList[i]->uCallbackMessage, pTrayManager->trayIconList[i]->uID, LPARAM(message));
                                                                        return DefWindowProc(hwnd, message, wParam, lParam);
                                                                }
                                                        }
                                                }
                                        }
                                }

                                //====================

                                if (message == WM_LBUTTONUP)
                                {
                                        POINT pt;
                                        int pointx = LOWORD(lParam);
                                        int pointy = HIWORD(lParam);
                                        pt.x = pointx;
                                        pt.y = pointy;

                                        if (PtInRect(&pSystembar->ToggleTrayButtonRect, pt))
                                        {
                                                pSystembar->ToggleSysTray();
                                                return DefWindowProc(hwnd, message, wParam, lParam);
                                        }
                                }

                                //====================

                                if (message == WM_LBUTTONDOWN || message == WM_LBUTTONUP)
                                {
                                        pMenuMaker->Hide();
                                        if ((GetAsyncKeyState(VK_SHIFT) & 0x8000) && !pSystembar->DockedToSlit)
                                        {
                                                if (!stricmp(pSettings->systembarPlacement, "DockedToToolbar") && pToolbar) pToolbar->UpdatePosition();
                                                else pSystembar->UpdatePosition();
                                        }
                                }

                                if (message == WM_RBUTTONUP) // Only show menus on RButtonUp...
                                {
                                        if (pSystembar->blockNextMouseClick)
                                        {
                                                pSystembar->blockNextMouseClick = false;
                                                return DefWindowProc(hwnd, message, wParam, lParam);
                                        }

                                        // Is the Alt key held down?
                                        if (GetAsyncKeyState(VK_MENU) & 0x8000) SendMessage(GetBBWnd(), BB_MENU, 0, 0);
                                        else SendMessage(GetBBWnd(), BB_MENU, 3, 0);
                                        return DefWindowProc(hwnd, message, wParam, lParam);
                                }

                                if (message == WM_MBUTTONUP)
                                {
                                        if (GetAsyncKeyState(VK_SHIFT) & 0x8000) PostMessage(GetBBWnd(), BB_TOGGLEPLUGINS, 0, 0);
                                        else if (stricmp(pSettings->systembarPlacement, "DockedToToolbar")) PostMessage(GetBBWnd(), BB_TOGGLETOOLBAR, 0, 0);
                                        else PostMessage(GetBBWnd(), BB_TOGGLESLIT, 0, 0);
                                }

                                return DefWindowProc(hwnd, message, wParam, lParam);
                        }
                }
                break;

                //====================

                case WM_XBUTTONDOWN:
                {
                        if (pSystembar->MouseButtonOnTaskbar(hwnd, message, wParam, lParam))
                        {
                                return DefWindowProc(hwnd, message, wParam, lParam);
                        }
                        else if (HIWORD(wParam) == XBUTTON1)
                        {
                                if (!pSettings->taskbarOnToolbar)
                                {
                                        if (GetAsyncKeyState(VK_MENU) & 0x8000) pSystembar->RestoreAllWindows();
                                        else pSystembar->MinimizeAllWindows();
                                }
                                else BBExecute(GetDesktopWindow(), NULL, "control.exe", "desk.cpl,,3", NULL, SW_SHOWNORMAL, false);
                        }
                        else if (HIWORD(wParam) == XBUTTON2)
                        {
                                if (!pSettings->taskbarOnToolbar) pSystembar->RestoreAllWindows();
                                else BBExecute(GetDesktopWindow(), NULL, "control.exe", "mmsys.cpl", NULL, SW_SHOWNORMAL, false);
                        }
                }
                break;

                case WM_XBUTTONUP: { } break;

                //====================

                case WM_MOUSEWHEEL:
                {
                        // Only allow mousewheel resizing when the control key is held down...
                        if (!(GetAsyncKeyState(VK_CONTROL) & 0x8000)) break;
                        // Do not allow mousewheel resizing if DockedToToolbar or DockedToSlit...
                        if (IsInString(pSettings->systembarPlacement, "DockedTo")) break;

                        bool sizechanged = false;

                        if (GET_WHEEL_DELTA_WPARAM(wParam) < 0)
                        {
                                if (pSettings->systembarWidthPercent > 30)
                                {
                                        sizechanged = true;
                                        pSettings->systembarWidthPercent--;
                                }
                        }
                        else
                        {
                                if (pSettings->systembarWidthPercent < 100)
                                {
                                        sizechanged = true;
                                        pSettings->systembarWidthPercent++;
                                }
                        }

                        if (sizechanged)
                        {
                                pSystembar->GetSettings();
                                // Force re-rendering of the background and task button bitmaps...
                                pSystembar->cachedBackgroundExists = false;
                                pSystembar->cachedTaskButtonsExist = false;
                                InvalidateRect(pSystembar->hSystembarWnd, NULL, false);

                                MoveWindow(pSystembar->hSystembarWnd, pSystembar->SystembarX, pSystembar->SystembarY, pSystembar->SystembarWidth, pSystembar->SystembarHeight, true);
                                if (pSettings->toolbarOnTop) SetWindowPos(pSystembar->hSystembarWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
                                else SetWindowPos(pSystembar->hSystembarWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
                                if (!pSystembar->SysTrayDisabled) pSystembar->UpdateToolTipPositions(); // Update tooltip x/y positions...

                                pSystembar->saveWidthOnRestart = true;
                        }

                        // Due to the number of repeated updates when using the mousewheel to change the systembar width,
                        // we do not save the systembar width to extensions.rc each time -> on restart/quit instead...
                        // WriteInt(pSettings->extrcFile, "xoblite.systembar.widthPercent:", pSettings->systembarWidthPercent);
                }
                break;

                //====================

                case WM_TIMER:
                {
                        if (wParam == SYSTEMBAR_XOBLOON_TIMER)
                        {
                                if (!pSystembar->SysTrayDisabled)
                                {
                                        if (pTrayManager->ShowBalloonTooltip)
                                        {
                                                KillTimer(pSystembar->hSystembarWnd, SYSTEMBAR_XOBLOON_TIMER);
                                                pTrayManager->ShowBalloonTooltip = false;
                                                if (pTrayManager->BalloonTooltipItem.hWnd != NULL)
                                                {
                                                        // Inform the parent application that the balloon tooltip has been dismissed on timeout...
                                                        PostMessage(pTrayManager->BalloonTooltipItem.hWnd, pTrayManager->BalloonTooltipItem.uCallbackMessage, pTrayManager->BalloonTooltipItem.uID, NIN_BALLOONTIMEOUT);
                                                }
                                                InvalidateRect(pSystembar->hSystembarWnd, NULL, false);
                                                return true;
                                        }
                                }
                        }
                        return 0;
                }
                break;

                //====================

                default:
                        return DefWindowProc(hwnd,message,wParam,lParam);

        //====================
        }
        return 0;
}

//===========================================================================
// Function: MouseButtonOnTaskbar
// Purpose: ...
//===========================================================================

bool Systembar::MouseButtonOnTaskbar(HWND hwnd, unsigned int message, WPARAM wParam, LPARAM lParam)
{
        if (!SysTrayDisabled)
        {
                if (pTrayManager->ShowBalloonTooltip)
                {
                        pTrayManager->ShowBalloonTooltip = false;
                        if (pTrayManager->BalloonTooltipItem.hWnd != NULL)
                        {
                                // Inform the parent application that the balloon tooltip has been dismissed by user click...
                                PostMessage(pTrayManager->BalloonTooltipItem.hWnd, pTrayManager->BalloonTooltipItem.uCallbackMessage, pTrayManager->BalloonTooltipItem.uID, NIN_BALLOONUSERCLICK);
                        }
                        InvalidateRect(hSystembarWnd, NULL, false);
                        return true;
                }
        }

        //====================

        if (pSettings->taskbarHidden) return false;
        if (pSettings->taskbarOnToolbar && (hwnd == pSystembar->hSystembarWnd)) return false;

        //====================

        POINT pt;

        if (message == WM_DROPFILES)
        {
                // Drag'n'drop of files onto a task button...
                GetCursorPos(&pt);
                ScreenToClient(hwnd, &pt);
        }
        else
        {
                // Regular mouse clicks on a task button...
                pt.x = LOWORD(lParam);
                pt.y = HIWORD(lParam);
        }

        if (!PtInRect(&MainRect, pt)) return false;

        //====================
        
        HWND Window;
        int mousex;

        if (pSettings->taskbarCurrentOnly) NumberOfTasks = CurrentOnlyCount;
        else NumberOfTasks = WinEnumeratorCount;

        if (pSettings->taskbarMode != 2) // Bars or Bars+Icons mode
        {
            TaskWidth = MainRect.right - MainRect.left;
                if (NumberOfTasks > 0) TaskWidth = TaskWidth / NumberOfTasks;
        }
        else // Icons mode
        {
                if (pSettings->taskbarOnToolbar) TaskWidth = 18; // 11+7 -> Smaller icons when placed on the toolbar...
                else TaskWidth = 22; // 14+8 -> Larger icons when placed on the systembar...
        }

        mousex = pt.x;
        mousex = mousex - MainRect.left;
        mousex = abs(mousex / TaskWidth);
        
        if (mousex >= NumberOfTasks) return false;

        //====================

        // Is the taskbar showing only tasks on the current workspace?
        if (pSettings->taskbarCurrentOnly)
        {
                int TaskOnWorkspaceNumber;
                int counter = mousex + 1;

                for (mousex = 0; counter != 0; mousex++)
                {
                        TaskOnWorkspaceNumber = pWorkspaces->getDesktop(WindowList[mousex].Window);
                        if (TaskOnWorkspaceNumber == pWorkspaces->currentScreen || TaskOnWorkspaceNumber == 255)
                                counter--;
                }
                mousex--;
        }

        //====================

        switch (message)
    {
                //====================

                case WM_LBUTTONDOWN: // Restore and focus window
                {
                        if (pMenuMaker) pMenuMaker->Hide();

                        if (GetAsyncKeyState(VK_MENU) & 0x8000)
                        {
                                if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
                                {
                                        Window = WindowList[mousex].Window;
                                        if (IsIconic(Window)) ShowWindow(Window, SW_RESTORE);
                                        SetForegroundWindow(Window);
                                        SendMessage(hBlackboxWnd, BB_BRINGTOFRONT, 0, (LPARAM)Window);
                                        PostMessage(Window, WM_SYSCOMMAND, SC_MOVE, 0);
                                }
                                else RestoreAllWindows();
                        }
                        else if ((GetAsyncKeyState(VK_SHIFT) & 0x8000) && !DockedToSlit)
                        {
                                if (!stricmp(pSettings->systembarPlacement, "DockedToToolbar") && pToolbar) pToolbar->UpdatePosition();
                                else UpdatePosition();
                        }
                        else
                        { 
                                Window = WindowList[mousex].Window;
                                if (IsIconic(Window)) ShowWindow(Window, SW_RESTORE);
                                SetForegroundWindow(Window);
                                SendMessage(hBlackboxWnd, BB_BRINGTOFRONT, 0, (LPARAM)Window);
                        } 
                        return true;
                }
                break;

                //====================

                case WM_LBUTTONDBLCLK: 
                case WM_RBUTTONDOWN:   // Minimize (iconify) window
                {
                        if (GetAsyncKeyState(VK_MENU) & 0x8000)
                        {
                                if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
                                {
                                        Window = WindowList[mousex].Window;
                                        if (IsIconic(Window)) ShowWindow(Window, SW_RESTORE);
                                        SetForegroundWindow(Window);
                                        SendMessage(hBlackboxWnd, BB_BRINGTOFRONT, 0, (LPARAM)Window);
                                        PostMessage(Window, WM_SYSCOMMAND, SC_SIZE, 0);
                                }
                                else MinimizeAllWindows();
                        }
                        else if (GetAsyncKeyState(VK_SHIFT) & 0x8000) return true; // Pass through -> menu click on RBUTTONUP below...
                        else
                        {
                                if ((message == WM_RBUTTONDOWN) && pSettings->taskbarCurrentOnly && (NumberOfTasks == 1)) blockNextMouseClick = true;
                                Window = WindowList[mousex].Window;
                                ShowWindow(Window, SW_MINIMIZE);
                                SendMessage(hBlackboxWnd, BB_WINDOWMINIMIZE, 0, (LPARAM)Window);
                        }
                        return true;
                }
                break;

                //====================

                case WM_MBUTTONDOWN:
                {
                        Window = WindowList[mousex].Window;
                        if (IsIconic(Window)) ShowWindow(Window, SW_RESTORE);
                        SetForegroundWindow(Window);

                        if (GetAsyncKeyState(VK_MENU) & 0x8000)
                        {
                                // Pass through if the Alt+Shift keys are held down...
                                // (the close application command is triggered on WM_MBUTTONUP)
                                if (GetAsyncKeyState(VK_SHIFT) & 0x8000) return true;
                                // Shade the window if the Alt key is held down...
                                else pDesk->ShadeWindow();
                        }
                        else
                        {
                                // ...otherwise move the window to the next/previous workspace
                                SendMessage(hBlackboxWnd, BB_BRINGTOFRONT, 0, (LPARAM)Window);

                                MakeSticky(Window);
                                if (GetAsyncKeyState(VK_MENU) & 0x8000) pWorkspaces->DeskLeft();
                                else pWorkspaces->DeskRight();
                                RemoveSticky(Window);
                        }

                        return true;
                }
                break;

                //====================

                case WM_LBUTTONUP: 
                {
                        return true;
                }
                break;

                //====================

                case WM_RBUTTONUP: // Only show menus on RButtonUp...
                {
                        if (GetAsyncKeyState(VK_SHIFT) & 0x8000) SendMessage(GetBBWnd(), BB_MENU, 3, 0);
                        return true;
                }
                break;

                //====================

                case WM_MBUTTONUP: 
                {
                        // Close the application if the Alt+Shift keys are held down...
                        if ((GetAsyncKeyState(VK_MENU) & 0x8000) && (GetAsyncKeyState(VK_SHIFT) & 0x8000))
                        {
                                Window = WindowList[mousex].Window;
                                if (IsIconic(Window)) ShowWindow(Window, SW_RESTORE);
                                SetForegroundWindow(Window);
                                PostMessage(Window, WM_SYSCOMMAND, SC_CLOSE, 0);
                        }

                        return true;
                }
                break;

                //====================

                case WM_XBUTTONDOWN:
                {
                        if (HIWORD(wParam) == XBUTTON1)
                        {
                                if (GetAsyncKeyState(VK_MENU) & 0x8000) RestoreAllWindows();
                                else MinimizeAllWindows();
                        }
                        else if (HIWORD(wParam) == XBUTTON2)
                        {
                                RestoreAllWindows();
                        }
                        return true;
                }
                break;

                case WM_XBUTTONUP: { } break;

                //====================

                case WM_DROPFILES:
                {
                        // Forward the drag'n'drop information to the window in question...
                        Window = WindowList[mousex].Window;
                        if (IsIconic(Window)) ShowWindow(Window, SW_RESTORE);
                        SetForegroundWindow(Window);
                        SendMessage(hBlackboxWnd, BB_BRINGTOFRONT, 0, (LPARAM)Window);

                        PostMessage(Window, WM_DROPFILES, wParam, lParam);

                        return true;
                }
                break;

                //====================
        }

        return false;
}

//===========================================================================
// Function: DrawSysTray
// Purpose: ...
//===========================================================================

int Systembar::DrawSysTray(HDC hdc)
{
        RECT iconRect;
        int offsetIconX = 2 + pSettings->Toolbar->borderWidth;
//      int offsetIconY = 3 + pSettings->Toolbar->borderWidth;
        int offsetIconY = SystembarHeight/2 - ICON_SIZE/2;
        int iconPos = 0; // This default is used by WindowListerWM_PAINT (see below) if there are no icons in the systray

        if (!SysTrayDisabled)
        {
                if (!pSettings->systrayHidden)
                {
                        for (int i=0; i < (int)pTrayManager->trayIconList.size(); i++)
                        {
                                if (!pTrayManager->trayIconList[i]->hWnd) break;
                                iconPos = (i+1) * (ICON_SIZE + 2) + offsetIconX;        // Calculate icon position...
                                if (iconPos > (SystembarWidth - offsetIconX)) break; // Check if the icon fits the toolbar...

                                iconRect.left = SystembarWidth - iconPos;
                                iconRect.top = offsetIconY;
                                iconRect.right = iconRect.left + ICON_SIZE;
                                iconRect.bottom = iconRect.top + ICON_SIZE;

                                if (pTrayManager->trayIconList[i]->hIcon) DrawSatHueIcon(hdc, pTrayManager->trayIconList[i]->hIcon, ICON_SIZE, iconRect, true, false);

                                // Save the icon rect so we can InvalidateRect for this icon only if needed (see TrayManager::ModifyTrayIcon)
                                SetRect(&pTrayManager->trayIconList[i]->iconRect, iconRect.left, iconRect.top, iconRect.right, iconRect.bottom);
                        }

                        iconPos = iconPos + 3; // Add two pixels of padding between the systray icons and the taskbar...
                        ToggleTrayButtonRect.right = SystembarWidth - iconPos;
                }
                else
                {
                        ToggleTrayButtonRect.right = SystembarWidth - pSettings->Toolbar->borderWidth - 3;
                        iconPos = pSettings->Toolbar->borderWidth + 3;
                }

                // Draw toggle tray button...
                ToggleTrayButtonRect.left = ToggleTrayButtonRect.right - 8;
                ToggleTrayButtonRect.top = pSettings->Toolbar->borderWidth + 3;
                ToggleTrayButtonRect.bottom = SystembarHeight - pSettings->Toolbar->borderWidth - 3;
                pBImage->CreateGradientByRect(hdc, ToggleTrayButtonRect, pSettings->Toolbar->type, pSettings->Toolbar->Color, pSettings->Toolbar->ColorTo, false, BEVEL_RAISED, BEVEL1, 1);

                iconPos = iconPos + 8; // Add two pixels of padding between the systray icons and the taskbar...
        }
        else iconPos = pSettings->Toolbar->borderWidth; // SysTray disabled

        TrayRect.left = SystembarWidth - iconPos;
        TrayRect.top = pSettings->Toolbar->borderWidth;
        TrayRect.right = SystembarWidth - pSettings->Toolbar->borderWidth;
        TrayRect.bottom = SystembarHeight - pSettings->Toolbar->borderWidth;

        return iconPos;
}

//===========================================================================
// Function: DrawTaskbar
// Purpose: ...
//===========================================================================

void Systembar::DrawTaskbar(HDC hdc, int iconPos, RECT taskbarRect)
{
        CopyRect(&MainRect, &taskbarRect);
        MainDC = hdc;

        // Reset flash indicator if flashing is disabled...
        if (!pSettings->taskbarFlashing) flashingHwnd = 0;

        //====================

        if (!pSettings->taskbarHidden)
        {
                if (pSettings->taskbarCurrentOnly)
                {
                        CurrentOnlyCount = 0;
                        int TaskOnWorkspaceNumber;

                        for (int x = 0; x < WinEnumeratorCount; x++)
                        {
//                              if (pWorkspaces->getDesktop(WindowList[x].Window) == pWorkspaces->currentScreen)
                                TaskOnWorkspaceNumber = pWorkspaces->getDesktop(WindowList[x].Window);
                                if (TaskOnWorkspaceNumber == pWorkspaces->currentScreen || TaskOnWorkspaceNumber == 255)
                                        CurrentOnlyCount++;
                        }

                        NumberOfTasks = CurrentOnlyCount;
                }
                else NumberOfTasks = WinEnumeratorCount;
        }

        //====================

        if (pSettings->taskbarHidden || NumberOfTasks == 0)
        {
                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, pSettings->Toolbar->Font);
                HGDIOBJ oldfont = SelectObject(MainDC, font);
                SetBkMode(MainDC, TRANSPARENT);

                SetTextColor(MainDC, pSettings->Toolbar->TextColor);
                DrawText(MainDC, "xoblite", strlen("xoblite"), &MainRect, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS);

                DeleteObject(SelectObject(MainDC, oldfont));
        }
        else DrawTaskButtons();
}

//===========================================================================
// Function: DrawTaskButtons
// Purpose: Draws task buttons on the taskbar
//===========================================================================

int Systembar::DrawTaskButtons()
{
        // Smaller icons when placed on the toolbar,
        // larger icons when placed on the systembar...
        if (pSettings->taskbarOnToolbar) iconSize = 11;
        else iconSize = 14;

        //====================

        // Calculate button dimensions...

        if (pSettings->taskbarMode != 2)
        {
                // Bars or Bars+Icons mode...
                TaskWidth = MainRect.right - MainRect.left;
                if (NumberOfTasks > 0) TaskWidth = TaskWidth / NumberOfTasks;
                TaskWidthMinusPadding = TaskWidth - 2; // Padding 2 pixels between task buttons...
        }
        else
        {
                // Icons mode...
                if (pSettings->taskbarOnToolbar)
                {
                        TaskWidth = iconSize + 7;
                        TaskWidthMinusPadding = TaskWidth - 1; // Padding 1 pixel between task buttons...
                }
                else
                {
                        TaskWidth = iconSize + 8;
                        TaskWidthMinusPadding = TaskWidth - 2; // Padding 2 pixels between task buttons...
                }
        }

        TaskHeight = MainRect.bottom - MainRect.top;

        //====================

        // If we have not yet created cached task buttons, let's do that...
        if (!pSystembar->cachedTaskButtonsExist)
        {
                RECT r = {0, 0, TaskWidthMinusPadding, TaskHeight};

                HBITMAP tempBitmapActive = CreateCompatibleBitmap(MainDC, TaskWidthMinusPadding, TaskHeight);
                HBITMAP oldBitmapActive = (HBITMAP)SelectObject(cachedTaskButtonActive, tempBitmapActive);
                DeleteObject(oldBitmapActive);
//              MakeGradient(cachedTaskButtonActive, r, pSettings->ActiveTask->type, pSettings->ActiveTask->Color, pSettings->ActiveTask->ColorTo, pSettings->ActiveTask->interlaced, BEVEL_SUNKEN, pSettings->ActiveTask->bevelposition, pSettings->bevelWidth, pSettings->Toolbar->borderColor, 1);
                MakeGradient(cachedTaskButtonActive, r, pSettings->ActiveTask->type, pSettings->ActiveTask->Color, pSettings->ActiveTask->ColorTo, pSettings->ActiveTask->interlaced, pSettings->ActiveTask->bevelstyle, pSettings->ActiveTask->bevelposition, pSettings->bevelWidth, pSettings->Toolbar->borderColor, 1);
                DeleteObject(tempBitmapActive);

                HBITMAP tempBitmapInactive = CreateCompatibleBitmap(MainDC, TaskWidthMinusPadding, TaskHeight);
                HBITMAP oldBitmapInactive = (HBITMAP)SelectObject(cachedTaskButtonInactive, tempBitmapInactive);
                DeleteObject(oldBitmapInactive);
//              MakeGradient(cachedTaskButtonInactive, r, pSettings->InactiveTask->type, pSettings->InactiveTask->Color, pSettings->InactiveTask->ColorTo, pSettings->InactiveTask->interlaced, BEVEL_RAISED, pSettings->InactiveTask->bevelposition, pSettings->bevelWidth, pSettings->Toolbar->borderColor, 1);
                MakeGradient(cachedTaskButtonInactive, r, pSettings->InactiveTask->type, pSettings->InactiveTask->Color, pSettings->InactiveTask->ColorTo, pSettings->InactiveTask->interlaced, pSettings->InactiveTask->bevelstyle, pSettings->InactiveTask->bevelposition, pSettings->bevelWidth, pSettings->Toolbar->borderColor, 1);
                DeleteObject(tempBitmapInactive);

                // Set the "cached task buttons created" indicator...
                pSystembar->cachedTaskButtonsExist = true;
        }

        //====================

        int DrawnTasks = 0;
        int TaskOnWorkspaceNumber;

        ThisButton.bottom = MainRect.bottom;
        ThisButton.top = MainRect.top;

        for (int i = 0; i < WinEnumeratorCount; i++)
        {
                //====================

                if (pSettings->taskbarCurrentOnly)
                {
                        // Exclude tasks not on the current workspace...
                        TaskOnWorkspaceNumber = pWorkspaces->getDesktop(WindowList[i].Window);
                        if (TaskOnWorkspaceNumber != pWorkspaces->currentScreen && TaskOnWorkspaceNumber != 255)
                                continue;
                }

                //====================

                // Calculate the bounding rect of the current task button
                // and save it so we can InvalidateRect it specifically if needed...

                ThisButton.left = MainRect.left + (DrawnTasks * TaskWidth);
                ThisButton.right = ThisButton.left + TaskWidthMinusPadding;

                if (pSettings->taskbarMode != 2) // Bars or Bars+Icons mode
                {
                        // Extend the rightmost button to fit the right border of the taskbar...
                        if (DrawnTasks == (NumberOfTasks - 1)) ThisButton.right = MainRect.right;
                }
                
                if (ThisButton.right > MainRect.right) break;

                CopyRect(&WindowList[i].r, &ThisButton);

                //====================

                // Create new tooltip or update existing tooltip with new bounding rect...
                GetWindowText(WindowList[i].Window, ThisButtonWindowText, 255);
                SetToolTip((UINT)WindowList[i].Window, WindowList[i].r, ThisButtonWindowText);

                //====================

                if (WindowList[i].Window == flashingHwnd) // Flashing task button?
                {
                        // Paint border+background for this flashed taskbar button...
                        MakeGradient(MainDC, ThisButton, pSettings->ActiveTask->type, pSettings->FlashingTask->Color, pSettings->FlashingTask->ColorTo, pSettings->InactiveTask->interlaced, pSettings->ActiveTask->bevelstyle, pSettings->ActiveTask->bevelposition, pSettings->bevelWidth, pSettings->Toolbar->borderColor, 1);
//                      MakeGradient(MainDC, ThisWin, pSettings->InactiveTask->type, pSettings->FlashingTask->Color, pSettings->FlashingTask->ColorTo, pSettings->InactiveTask->interlaced, pSettings->InactiveTask->bevelstyle, pSettings->InactiveTask->bevelposition, pSettings->bevelWidth, pSettings->Toolbar->borderColor, 1);
                }
                else if ((DrawnTasks == (NumberOfTasks - 1)) && (pSettings->taskbarMode != 2)) // Rightmost button on the taskbar?
                {
                        // Paint border+background for this taskbar button...
//                      if (WindowList[i].Active) MakeGradient(MainDC, ThisButton, pSettings->ActiveTask->type, pSettings->ActiveTask->Color, pSettings->ActiveTask->ColorTo, pSettings->ActiveTask->interlaced, BEVEL_SUNKEN, pSettings->ActiveTask->bevelposition, pSettings->bevelWidth, pSettings->Toolbar->borderColor, 1);
//                      else MakeGradient(MainDC, ThisButton, pSettings->InactiveTask->type, pSettings->InactiveTask->Color, pSettings->InactiveTask->ColorTo, pSettings->InactiveTask->interlaced, BEVEL_RAISED, pSettings->InactiveTask->bevelposition, pSettings->bevelWidth, pSettings->Toolbar->borderColor, 1);
                        if (WindowList[i].Active) MakeGradient(MainDC, ThisButton, pSettings->ActiveTask->type, pSettings->ActiveTask->Color, pSettings->ActiveTask->ColorTo, pSettings->ActiveTask->interlaced, pSettings->ActiveTask->bevelstyle, pSettings->ActiveTask->bevelposition, pSettings->bevelWidth, pSettings->Toolbar->borderColor, 1);
                        else if (pSettings->taskbarInactiveBackground) MakeGradient(MainDC, ThisButton, pSettings->InactiveTask->type, pSettings->InactiveTask->Color, pSettings->InactiveTask->ColorTo, pSettings->InactiveTask->interlaced, pSettings->InactiveTask->bevelstyle, pSettings->InactiveTask->bevelposition, pSettings->bevelWidth, pSettings->Toolbar->borderColor, 1);
                }
                else
                {
                        // Copy the cached task button bitmap into the temporary buffer...
                        if (WindowList[i].Active) BitBlt(MainDC, ThisButton.left, ThisButton.top, TaskWidthMinusPadding, TaskHeight, cachedTaskButtonActive, 0, 0, SRCCOPY);
                        else if (pSettings->taskbarInactiveBackground) BitBlt(MainDC, ThisButton.left, ThisButton.top, TaskWidthMinusPadding, TaskHeight, cachedTaskButtonInactive, 0, 0, SRCCOPY);
                }

                //====================

                // Should we draw an icon on the task button?
                if (pSettings->taskbarMode != 1) // Bars+Icons or Icons mode
                {
                        // Fetch the window icon...
                        ThisButtonWnd = WindowList[i].Window;
                    SendMessageTimeout(ThisButtonWnd, WM_GETICON, ICON_SMALL, 0, SMTO_ABORTIFHUNG|SMTO_BLOCK, 200, (PDWORD_PTR)&ThisButtonIcon);
                        if (!ThisButtonIcon) ThisButtonIcon = (HICON)GetClassLongPtr(ThisButtonWnd, GCLP_HICONSM);
                        if (!ThisButtonIcon) SendMessageTimeout(ThisButtonWnd, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG|SMTO_BLOCK, 200, (PDWORD_PTR)&ThisButtonIcon);
                        if (!ThisButtonIcon) ThisButtonIcon = (HICON)GetClassLongPtr(ThisButtonWnd, GCLP_HICON);

                        // Calculate icon position...
                        if (pSettings->taskbarMode == 3) iconRect.left = ThisButton.left + 5; // Bars+Icons mode
                        else iconRect.left = ThisButton.left + 3; // Icons mode
//                      iconRect.top = ThisButton.top + 2;
                        iconRect.top = ThisButton.top + (TaskHeight/2) - (iconSize/2);
                        iconRect.right = iconRect.left + iconSize;
                        iconRect.bottom = iconRect.top + iconSize;

                        // Draw the icon...
                        if (ThisButtonIcon) DrawSatHueIcon(MainDC, ThisButtonIcon, iconSize, iconRect, false, WindowList[i].Active);

                        ThisButton.left = iconRect.right + 3;
                }
                else ThisButton.left = ThisButton.left + 5;

                ThisButton.right = ThisButton.right - 5;

                //====================

                // Should we draw the window label on the task button?
                if (pSettings->taskbarMode != 2) // Bars or Bars+Icons mode
                {
                        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, pSettings->Toolbar->Font);
                        HGDIOBJ oldfont = SelectObject(MainDC, font);
                        SetBkMode(MainDC, TRANSPARENT);

                        if (WindowList[i].Window == flashingHwnd) DrawTextWithShadow(MainDC, ThisButtonWindowText, ThisButton, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS, pSettings->FlashingTask->TextColor, pSettings->flashingTaskShadowColor, pSettings->ActiveTask->FontShadow);
                        else if (WindowList[i].Active) DrawTextWithShadow(MainDC, ThisButtonWindowText, ThisButton, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS, pSettings->ActiveTask->TextColor, pSettings->activeTaskShadowColor, pSettings->ActiveTask->FontShadow);
                        else DrawTextWithShadow(MainDC, ThisButtonWindowText, ThisButton, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS, pSettings->InactiveTask->TextColor, pSettings->inactiveTaskShadowColor, pSettings->InactiveTask->FontShadow);

                        DeleteObject(SelectObject(MainDC, oldfont));
                }

                //====================

                if (WindowList[i].Window == flashingHwnd) flashingHwnd = 0; // Reset flash indicator...

                DrawnTasks++;
        }

        return 1;
}

//===========================================================================
// Function: DrawSatHueIcon
// Purpose: ...
//===========================================================================

void Systembar::DrawSatHueIcon(HDC hdc, HICON icon, int size, RECT r, bool trayIcon, bool activeTask)
{
        DrawIconEx(hdc, r.left, r.top, icon, size, size, 0, NULL, DI_NORMAL);

        if (activeTask && !pSettings->taskbarActiveSatHue) return;

        //====================

        int saturation, hue;

        if (trayIcon)
        {
                saturation = pSettings->systraySaturationValue;
                hue = pSettings->systrayHueIntensity;
        }
        else
        {
                saturation = pSettings->taskbarSaturationValue;
                hue = pSettings->taskbarHueIntensity;
        }

        //====================

        // Should we apply saturation or hue?
        if (saturation < 255 || hue > 0)
        {
                hueColor = pSettings->Toolbar->Color;

                HDC iconhdc = CreateCompatibleDC(hdc);
                HBITMAP iconbufbmp = ::CreateCompatibleBitmap(hdc, size, size);
                HBITMAP oldiconbuf = (HBITMAP) ::SelectObject(iconhdc, iconbufbmp);

                // First we draw a masked version of the icon to the temporary buffer...
                DrawIconEx(iconhdc, 0, 0, icon, size, size, 0, NULL, DI_MASK);

                invsat = 255 - saturation;
                invhue = 255 - hue;

                for (int y=0; y < size; y++)
                {
                        for (int x=0; x < size; x++)
                        {
                                // Check if the mask pixel is white, ie. a transparent pixel...
                                if (!GetPixel(iconhdc, x, y))
                                {
                                        // First we read the original pixel's color...
                                        pixel = GetPixel(hdc, (r.left + x), (r.top + y));
                                        red = GetRValue(pixel);
                                        green = GetGValue(pixel);
                                        blue = GetBValue(pixel);

                                        // ...then we apply saturation...
                                        if (saturation < 255)
                                        {
                                                greyscale = (BYTE)(red*0.3086 + green*0.6094 + blue*0.0820);
                                                red = (BYTE)((red*saturation + greyscale*invsat + 255)>>8);
                                                green = (BYTE)((green*saturation + greyscale*invsat + 255)>>8);
                                                blue = (BYTE)((blue*saturation + greyscale*invsat + 255)>>8);
                                        }
                                        // ...and hue according to color and intensity...
                                        if (hue > 0)
                                        {
                                                red = (BYTE)((red*invhue + GetRValue(hueColor)*hue + 255)>>8);
                                                green = (BYTE)((green*invhue + GetGValue(hueColor)*hue + 255)>>8);
                                                blue = (BYTE)((blue*invhue + GetBValue(hueColor)*hue + 255)>>8);
                                        }
                                        // ...and finally we overwrite the original pixel with the new one...
                                        SetPixel(hdc, (r.left + x), (r.top + y), RGB(red, green, blue));
                                }
                        }
                }

                SelectObject(iconhdc, oldiconbuf);
                DeleteObject(iconbufbmp);
                DeleteDC(iconhdc);
        }
}

//===========================================================================
// Function: GetSettings
// Purpose: ...
//===========================================================================

void Systembar::GetSettings()
{
        ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
        ScreenHeight = GetSystemMetrics(SM_CYSCREEN);

//      if (pSettings->usingWin2kXP)
//      {
//              ScreenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
//              ScreenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
//      }
//      else
//      {
//              ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
//              ScreenHeight = GetSystemMetrics(SM_CYSCREEN);
//      }

        //====================

//      int     ToolbarHeight;
//      if (pSettings->taskbarOnToolbar) ToolbarHeight = 17 + (pSettings->Toolbar->borderWidth * 2);
//      else ToolbarHeight = 15 + (pSettings->Toolbar->borderWidth * 2);
        int     ToolbarHeight = 0;
        if (pToolbar) ToolbarHeight = pToolbar->ToolbarHeight;

//      SystembarHeight = 22  + (pSettings->Toolbar->borderWidth * 2);
        int minimumHeight = 22  + (pSettings->Toolbar->borderWidth * 2);
        if (ToolbarHeight < minimumHeight) SystembarHeight = minimumHeight;
        else SystembarHeight = ToolbarHeight;

        //====================

        if (!stricmp(pSettings->systembarPlacement, "DockedToSlit"))
        {
                // We only need to calculate the size, position is set by the slit...
                SystembarWidth = (ScreenWidth * pSettings->systembarWidthPercent) / 100;
        }
        else if (!stricmp(pSettings->systembarPlacement, "DockedToToolbar"))
        {
                // Show the toolbar if hidden, we want to dock to it...
                if (!pSettings->systembarHidden && pSettings->toolbarHidden) PostMessage(GetBBWnd(), BB_TOGGLETOOLBAR, 0, 0);

                SystembarWidth = (ScreenWidth * pSettings->toolbarWidthPercent) / 100;

                if (pSettings->toolbarPlacement[0] == 'M') // Manual positioning
                {
                        if (pToolbar)
                        {
                                RECT tbRect;
                                GetWindowRect(pToolbar->hToolbarWnd, &tbRect);
                                SystembarX = tbRect.left;
                                if (tbRect.top >= (SystembarHeight-pSettings->Toolbar->borderWidth)) SystembarY = tbRect.top - SystembarHeight + pSettings->Toolbar->borderWidth;
                                else SystembarY = tbRect.bottom - pSettings->Toolbar->borderWidth;
                        }
                }
                else if (!stricmp(pSettings->toolbarPlacement, "TopCenter"))
                {
                        SystembarX = (ScreenWidth - SystembarWidth) / 2;
                        SystembarY = ToolbarHeight - pSettings->Toolbar->borderWidth;
                }
                else if (!stricmp(pSettings->toolbarPlacement, "BottomCenter"))
                {
                        SystembarX = (ScreenWidth - SystembarWidth) / 2;
                        SystembarY = ScreenHeight - (ToolbarHeight - pSettings->Toolbar->borderWidth) - SystembarHeight;
                }
                else if (!stricmp(pSettings->toolbarPlacement, "TopLeft"))
                {
                        SystembarX = 0;
                        SystembarY = ToolbarHeight - pSettings->Toolbar->borderWidth;
                }
                else if (!stricmp(pSettings->toolbarPlacement, "BottomLeft"))
                {
                        SystembarX = 0;
                        SystembarY = ScreenHeight - (ToolbarHeight - pSettings->Toolbar->borderWidth) - SystembarHeight;
                }
                else if (!stricmp(pSettings->toolbarPlacement, "TopRight"))
                {
                        SystembarX = ScreenWidth - SystembarWidth;
                        SystembarY = ToolbarHeight - pSettings->Toolbar->borderWidth;
                }
                else if (!stricmp(pSettings->toolbarPlacement, "BottomRight"))
                {
                        SystembarX = ScreenWidth - SystembarWidth;
                        SystembarY = ScreenHeight - ToolbarHeight - SystembarHeight;
                }
                else SystembarY = ScreenHeight - (ToolbarHeight - pSettings->Toolbar->borderWidth) - SystembarHeight;
        }
        else
        {
                SystembarWidth = (ScreenWidth * pSettings->systembarWidthPercent) / 100;

                char tempPlacement[MAX_LINE_LENGTH];
                strcpy(tempPlacement, pSettings->systembarPlacement);

                //====================

                if (tempPlacement[0] == 'M') // Manual positioning
                {
                        char token1[MAX_LINE_LENGTH], token2[MAX_LINE_LENGTH], token3[MAX_LINE_LENGTH];
                        LPSTR tokens[2];
                        tokens[0] = token1;
                        tokens[1] = token2;

                        token1[0] = token2[0] = token3[0] = '\0';
                        BBTokenize (tempPlacement, tokens, 2, token3);

                        SystembarX = atoi(&token2[1]); // "x123"
                        SystembarY = atoi(&token3[1]); // "y456"

                        // Make sure the systembar is inside the visible screen...
                        int xmax = ScreenWidth - SystembarWidth;
                        int ymax = ScreenHeight - SystembarHeight;
                        if (SystembarX < 0) SystembarX = 0;
                        if (SystembarY < 0) SystembarY = 0;
                        if (SystembarX > xmax) SystembarX = xmax;
                        if (SystembarY > ymax) SystembarY = ymax;

                        return;
                }

                //====================

                if (!stricmp(tempPlacement, "OppositeToolbar") || !stricmp(pSettings->systembarPlacement, "DockedToToolbar")) // Also used if docked to slit (forces use of systembar width regardless of placement)
                {
                        if (!stricmp(pSettings->toolbarPlacement, "TopCenter")) strcpy(tempPlacement, "BottomCenter");
                        else if (!stricmp(pSettings->toolbarPlacement, "BottomCenter")) strcpy(tempPlacement, "TopCenter");
                        else if (!stricmp(pSettings->toolbarPlacement, "TopLeft")) strcpy(tempPlacement, "BottomLeft");
                        else if (!stricmp(pSettings->toolbarPlacement, "BottomLeft")) strcpy(tempPlacement, "TopLeft");
                        else if (!stricmp(pSettings->toolbarPlacement, "TopRight")) strcpy(tempPlacement, "BottomRight");
                        else if (!stricmp(pSettings->toolbarPlacement, "BottomRight")) strcpy(tempPlacement, "TopRight");
                }

                //====================

                if (!stricmp(tempPlacement, "TopCenter"))
                {
                        SystembarX = (ScreenWidth - SystembarWidth) / 2;
                        SystembarY = 0;
                }
                else if (!stricmp(tempPlacement, "BottomCenter"))
                {
                        SystembarX = (ScreenWidth - SystembarWidth) / 2;
                        SystembarY = ScreenHeight - SystembarHeight;
                }
                else if (!stricmp(tempPlacement, "TopLeft"))
                {
                        SystembarX = 0;
                        SystembarY = 0;
                }
                else if (!stricmp(tempPlacement, "BottomLeft"))
                {
                        SystembarX = 0;
                        SystembarY = ScreenHeight - SystembarHeight;
                }
                else if (!stricmp(tempPlacement, "TopRight"))
                {
                        SystembarX = ScreenWidth - SystembarWidth;
                        SystembarY = 0;
                }
                else if (!stricmp(tempPlacement, "BottomRight"))
                {
                        SystembarX = ScreenWidth - SystembarWidth;
                        SystembarY = ScreenHeight - SystembarHeight;
                }
                else SystembarY = ScreenHeight - SystembarHeight;
        }
}

//===========================================================================
// Function: UpdatePosition
// Purpose: ...
//===========================================================================

void Systembar::UpdatePosition()
{
        // Fetch the new size and position parameters for our window...
        GetSettings();

        //====================

        // Dock to the slit if that is our new position and we are not already docked...
        if (!stricmp(pSettings->systembarPlacement, "DockedToSlit"))
        {
                // Resize the window and move it to its new position...
                MoveWindow(hSystembarWnd, 0, 0, SystembarWidth, SystembarHeight, true);
                // Force re-rendering of the background and task button bitmaps...
                cachedBackgroundExists = false;
                cachedTaskButtonsExist = false;
                InvalidateRect(hSystembarWnd, NULL, false);

                if (!DockedToSlit)
                {
                        // Disable transparency...
                        SetTransparency(hSystembarWnd, 255);
                        // Show the slit if hidden, we want to dock to it...
                        if (pSettings->slitHidden) PostMessage(GetBBWnd(), BB_TOGGLESLIT, 0, 0);
                        // Finally, we dock to the slit...
                        SendMessage(pSlit->hSlitWnd, SLIT_ADD, NULL, (LPARAM)hSystembarWnd);
                        DockedToSlit = true;
                }
                else SendMessage(pSlit->hSlitWnd, SLIT_UPDATE, NULL, NULL);
        }
        else
        {
                if (DockedToSlit)
                {
                        // Undock from the slit if already docked...
                        SendMessage(pSlit->hSlitWnd, SLIT_REMOVE, NULL, (LPARAM)hSystembarWnd);
                        DockedToSlit = false;
                }

                // Resize the window and move it to its new position...
                MoveWindow(hSystembarWnd, SystembarX, SystembarY, SystembarWidth, SystembarHeight, true);
                // Force re-rendering of the background and task button bitmaps...
                cachedBackgroundExists = false;
                cachedTaskButtonsExist = false;
                InvalidateRect(hSystembarWnd, NULL, false);

                // If the systembar is docked to the toolbar it inherits the
                // toolbar alpha transparency value and AlwaysOnTop setting...
                if (!stricmp(pSettings->systembarPlacement, "DockedToToolbar"))
                {
                        if (pSettings->toolbarOnTop) SetWindowPos(hSystembarWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
                        else SetWindowPos(hSystembarWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
                        SetTransparency(hSystembarWnd, pSettings->toolbarTransparencyAlpha);
                }
                else
                {
                        if (pSettings->systembarOnTop) SetWindowPos(hSystembarWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
                        else SetWindowPos(hSystembarWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
                        SetTransparency(hSystembarWnd, pSettings->systembarTransparencyAlpha);
                }
        }

        //====================

        // Update the toolbar position if autohide is enabled (needed e.g. if becoming DockedToToolbar)...
        if (pSettings->toolbarAutoHide && pToolbar)
        {
                pToolbar->AutoShow();
                if (!pToolbar->CheckIfMouseHover()) pToolbar->AutoHide();
        }

        // Finally, we update the tooltip positions...
        if (!SysTrayDisabled) UpdateToolTipPositions(); // Update tooltip x/y positions...

        WriteString(pSettings->extrcFile, "xoblite.systembar.placement:", pSettings->systembarPlacement);
}

//===========================================================================
// Function: ToggleAlwaysOnTop
// Purpose: ...
//===========================================================================

void Systembar::ToggleAlwaysOnTop()
{
        if (!stricmp(pSettings->systembarPlacement, "DockedToToolbar"))
        {
                if (pSettings->toolbarOnTop) SetWindowPos(hSystembarWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
                else SetWindowPos(hSystembarWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
                return;
        }

        if (!pSettings->systembarOnTop)
        {
                pSettings->systembarOnTop = true;
                SetWindowPos(hSystembarWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
        }
        else
        {
                pSettings->systembarOnTop = false;
                SetWindowPos(hSystembarWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
        }

        WriteBool(pSettings->extrcFile, "xoblite.systembar.onTop:", pSettings->systembarOnTop);
}

//===========================================================================
// Function: ToggleTaskbarMode
// Purpose: ...
//===========================================================================

void Systembar::ChangeTaskbarMode(int mode)
{
        char setting[MAX_LINE_LENGTH];

        if (mode == 1)
        {
                pSettings->taskbarMode = 1;
                strcpy(setting, "Bars");
        }
        else if (mode == 2)
        {
                pSettings->taskbarMode = 2;
                strcpy(setting, "Icons");
        }
        else
        {
                pSettings->taskbarMode = 3;
                strcpy(setting, "Bars+Icons");
        }

        cachedTaskButtonsExist = false;
        if (pSettings->taskbarOnToolbar && pToolbar) InvalidateRect(pToolbar->hToolbarWnd, &pToolbar->winlabelRect, false);
        else InvalidateRect(hSystembarWnd, &MainRect, false);
        if (!SysTrayDisabled) UpdateToolTipPositions(); // Update tooltip x/y positions...

        WriteString(pSettings->extrcFile, "xoblite.taskbar.mode:", setting);
}

//===========================================================================
// Function: ToggleSysTray
// Purpose: ...
//===========================================================================

void Systembar::ToggleSysTray()
{
        if (!pSettings->systrayHidden) pSettings->systrayHidden = true;
        else pSettings->systrayHidden = false;

        pSystembar->cachedTaskButtonsExist = false;
        InvalidateRect(pSystembar->hSystembarWnd, NULL, false);
        if (!SysTrayDisabled) UpdateToolTipPositions(); // Update tooltip x/y positions...

        WriteBool(pSettings->extrcFile, "xoblite.systray.hidden:", pSettings->systrayHidden);
}

//===========================================================================
// Function: ToggleCurrentOnly
// Purpose: ...
//===========================================================================

void Systembar::ToggleCurrentOnly()
{
        if (!pSettings->taskbarCurrentOnly) pSettings->taskbarCurrentOnly = true;
        else pSettings->taskbarCurrentOnly = false;

        cachedTaskButtonsExist = false;
        if (pSettings->taskbarOnToolbar && pToolbar) InvalidateRect(pToolbar->hToolbarWnd, &pToolbar->winlabelRect, false);
        else InvalidateRect(hSystembarWnd, &MainRect, false);
        if (!SysTrayDisabled) UpdateToolTipPositions(); // Update tooltip x/y positions...

        WriteBool(pSettings->extrcFile, "xoblite.taskbar.currentOnly:", pSettings->taskbarCurrentOnly);
}

//===========================================================================
// Function: AddWindow
// Purpose:
// In: HWND
// Out: void
//===========================================================================

void Systembar::AddWindow(HWND newWindow)
{
        CleanWindows();

        char newWindowTemp[MAX_LINE_LENGTH];

        // Check for Adobe Acrobat 7.0 offscreen windows...
        GetClassName(newWindow, newWindowTemp, MAX_LINE_LENGTH);
        if (!stricmp(newWindowTemp, "AcrobatOffscreenDocumentWnd")) return;

        // Get the window title...
//      GetWindowText(newWindow, newWindowTemp, MAX_LINE_LENGTH);

        //====================

//      if (IsAppWindow(newWindow) && !IsInString(newWindowTemp, "Microsoft Powerpoint - ["))
        if (IsAppWindow(newWindow))
        {
                bool windowFound = false;

                for (int i=0; i < WinEnumeratorCount; i++)
                {
                        if (WindowList[i].Window == newWindow)
                        {
                                windowFound = true;
                                break;
                        }
                }

                WindowList[i].Window = newWindow;

                if (!windowFound)
                {
                        WinEnumeratorCount++;

                        // Redraw the taskbar...
                        cachedTaskButtonsExist = false;
                        if (pSettings->taskbarOnToolbar && pToolbar) InvalidateRect(pToolbar->hToolbarWnd, &pToolbar->winlabelRect, false);
                        else InvalidateRect(hSystembarWnd, &MainRect, false);
                }
        }
}

//===========================================================================
// Function: RemoveWindow
// Purpose:
// In: HWND
// Out: void
//===========================================================================

void Systembar::RemoveWindow(HWND oldWindow)
{
        bool windowFound = false;

        //====================

        CleanWindows();

        for (int i=0; i < WinEnumeratorCount; i++)
        {
                if (WindowList[i].Window == oldWindow)
                {
                        windowFound = true;
                        break;
                }
        }

        if (windowFound)
        {
                DeleteToolTip((UINT)WindowList[i].Window);

                WinEnumeratorCount--;

                // Traverse the rest of the array moving the remaining icons up one
                for (i; i < WinEnumeratorCount; i++)
                        WindowList[i].Window = WindowList[i+1].Window;

                WindowList[WinEnumeratorCount].Window = NULL;

//              // Redraw the taskbar...
//              cachedTaskButtonsExist = false;
//              if (pSettings->taskbarOnToolbar && pToolbar) InvalidateRect(hToolbarWnd, &pToolbar->winlabelRect, false);
//              else InvalidateRect(hSystembarWnd, &MainRect, false);
        }

        //====================

        // Redraw the taskbar (regardless if windowFound or not, just in case...)
        cachedTaskButtonsExist = false;
        if (pSettings->taskbarOnToolbar && pToolbar) InvalidateRect(pToolbar->hToolbarWnd, &pToolbar->winlabelRect, false);
        else InvalidateRect(hSystembarWnd, &MainRect, false);
}

//===========================================================================
// Function: CleanWindows
// Purpose:
// In: HWND
// Out: void
//===========================================================================

void Systembar::CleanWindows()
{
        int windowEnd = WinEnumeratorCount;

        // Go through each of the elements in the WindowList array
        for (int i=0; i < windowEnd; i++)
        { 
                if (!IsWindow(WindowList[i].Window))
                {
                        DeleteToolTip((UINT)WindowList[i].Window);

                        WinEnumeratorCount--;

                        for (i; i < windowEnd; i++)
                        {
                                WindowList[i].Window = WindowList[i + 1].Window;
                        }
                }
        }
}

//===========================================================================
// Function: MinimizeAllWindows
// Purpose:
// In: void
// Out: void
//===========================================================================

void Systembar::MinimizeAllWindows()
{
        int windowEnd = WinEnumeratorCount;

        // Go through each of the elements in the WindowList array and minimize its window...
        for (int i=0; i < windowEnd; i++)
        {
                ShowWindow(WindowList[i].Window, SW_MINIMIZE);
        }
        // Finally, we trigger the "minimize" message (for e.g. BBSoundFX)
        SendMessage(hBlackboxWnd, BB_WINDOWMINIMIZE, 0, (LPARAM)WindowList[0].Window);
}

//===========================================================================
// Function: RestoreAllWindows
// Purpose:
// In: void
// Out: void
//===========================================================================

void Systembar::RestoreAllWindows()
{
        int i, activeWindow = 0, windowEnd = WinEnumeratorCount;
        bool foundActiveWindow = false;

        // Find the currently active window so we can focus it again after restoring all windows...
        for (i=0; i < windowEnd; i++)
        {
                if (WindowList[i].Active)
                {
                        activeWindow = i;
                        foundActiveWindow = true;
                }
        }

        // Go through each of the elements in the WindowList array and restore its window...
        for (i=0; i < windowEnd; i++)
        {
                if (IsIconic(WindowList[i].Window))
                        ShowWindow(WindowList[i].Window, SW_RESTORE);
        }

        // If we had an active window to begin with we now focus it again...
        if (foundActiveWindow)
        {
                SetForegroundWindow(WindowList[activeWindow].Window);
                SendMessage(hBlackboxWnd, BB_BRINGTOFRONT, 0, (LPARAM)activeWindow);
        }
}

//===========================================================================
// Function: GetCurrentWindow
// Purpose:
// In: void
// Out: HWND
//===========================================================================

HWND Systembar::GetCurrentWindow()
{
        int windowEnd = WinEnumeratorCount;

        // Find the currently active window so we can focus it again after restoring all windows...
        for (int i=0; i < windowEnd; i++)
        {
                if (WindowList[i].Active)
                {
                        return WindowList[i].Window;
                }
        }
        return 0;
}

//===========================================================================
// Function: WinEnumerator
// Purpose:
// In: HWND, LPARAM
// Out: int __stdcall
//===========================================================================

BOOL CALLBACK WinEnumerator(HWND Window, LPARAM Main)
{
        if (pSystembar->WinEnumeratorCount > 254) return 0;

        // Check for Adobe Acrobat 7.0 offscreen windows...
        char windowClass[MAX_LINE_LENGTH];
        GetClassName(Window, windowClass, MAX_LINE_LENGTH);
        if (!stricmp(windowClass, "AcrobatOffscreenDocumentWnd")) return 1;

        //====================

        // Add window to the systembar list of windows...
        if (IsAppWindow(Window))
        {
        pSystembar->WindowList[pSystembar->WinEnumeratorCount].Window = Window; 
                pSystembar->WindowList[pSystembar->WinEnumeratorCount].Active = false;
                pSystembar->WinEnumeratorCount++;
        }

        //====================

        return 1;
}

//===========================================================================
// Function: SetToolTip
// Purpose: To assign a ToolTip to an icon in the system tray
// In: unsigned int tipID, RECT tipRect, char tipText
// Out: void
//===========================================================================

void Systembar::SetToolTip(unsigned int tipID, RECT tipRect, char tipText[MAX_LINE_LENGTH])
{
        // Check to see if the hToolTips handle exists...
        if (!hToolTips) return;

        TOOLINFO ti;
        memset(&ti, 0, sizeof(TOOLINFO));

        bool exists;

        // Fill in the TOOLINFO structure...
        ti.cbSize = sizeof(TOOLINFO);
        ti.hwnd = hSystembarWnd;
        ti.uId = tipID;

        // Check to see if the tooltip exists...
        exists = SendMessage(hToolTips, TTM_GETTOOLINFO, 0,(LPARAM) (LPTOOLINFO) &ti) ? true : false;

        // Complete the rest of the TOOLINFO structure...
        ti.uFlags = TTF_SUBCLASS | TTF_CENTERTIP; // Center the tooltip below the item...
        ti.hinst =  hSystembarInstance;
        ti.lpszText = tipText;
        ti.rect = tipRect;

        // If it exists, modify the tooltip, if not, add it...
        if (exists) SendMessage(hToolTips, TTM_SETTOOLINFO, 0, (LPARAM)(LPTOOLINFO)&ti);
        else SendMessage(hToolTips, TTM_ADDTOOL, 0, (LPARAM)&ti);
}

//===========================================================================
// Function: DeleteToolTip
// Purpose: ...
// In: unsigned int tipID
// Out: void
//===========================================================================

void Systembar::DeleteToolTip(unsigned int tipID)
{
        if (!hToolTips) return;

        TOOLINFO ti;
        memset(&ti, 0, sizeof(TOOLINFO));
        
        bool exists;

        // Fill in the TOOLINFO structure...
        ti.cbSize = sizeof(TOOLINFO);
        ti.hwnd = hSystembarWnd;
        ti.uId = tipID;

        // Check to see if the tooltip exists...
        exists = SendMessage(hToolTips, TTM_GETTOOLINFO, 0,(LPARAM) (LPTOOLINFO) &ti) ? true : false;

        if (exists) SendMessage(hToolTips, TTM_DELTOOL, 0, (LPARAM)(LPTOOLINFO)&ti);
}

//===========================================================================
// Function: UpdateToolTipPositions
// Purpose: Modifies all tray icon x/y positions in the trayIcons array.
//          Used when screen resolution changes (ie. SystembarWidth changes ->
//          -> tray icon relative x/y positions change)
// In: void
// Out: void
//===========================================================================

void Systembar::UpdateToolTipPositions()
{
        if (!hToolTips) return;

        RECT iconRect;

        if (!SysTrayDisabled)
        {
                pTrayManager->CleanTray();

                if (!pSettings->systrayHidden) // SysTray shown
                {
                        int xPos = SystembarWidth - (2 + pSettings->Toolbar->borderWidth); // x position from the right...
//                      int yPos = 3 + pSettings->Toolbar->borderWidth; // y position
                        int yPos = SystembarHeight/2 - ICON_SIZE/2; // y position

                        for (int i=0; i < (int)pTrayManager->trayIconList.size(); i++)
                        {
                                if (!IsWindow(pTrayManager->trayIconList[i]->hWnd)) break;

                                xPos = xPos - (ICON_SIZE + 2);

                                pTrayManager->trayIconList[i]->x = xPos;
                                pTrayManager->trayIconList[i]->y = yPos;

                                // Define the region in which the tooltip should activate (the region of the icon)
                                iconRect.left = pTrayManager->trayIconList[i]->x;
                                iconRect.right = iconRect.left + ICON_SIZE;
                                iconRect.top = pTrayManager->trayIconList[i]->y;
                                iconRect.bottom = iconRect.top + ICON_SIZE;

                                // Set the tooltip
//                              SetToolTip((UINT)(1000 + i), iconRect, pTrayManager->trayIconList[i]->szTip);
                                SetToolTip(pTrayManager->trayIconList[i]->uID, iconRect, pTrayManager->trayIconList[i]->szTip);
                        }
                }
                else // SysTray hidden
                {
                        for (int i=0; i < (int)pTrayManager->trayIconList.size(); i++)
                        {
                                if (!IsWindow(pTrayManager->trayIconList[i]->hWnd)) break;
                                else DeleteToolTip(pTrayManager->trayIconList[i]->uID);
                        }
                }
        }
}

//===========================================================================

void Systembar::CreateTooltipsWindow()
{
        hToolTips = CreateWindowEx(
                WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
                TOOLTIPS_CLASS,
                NULL,
                WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                hSystembarWnd,
                NULL,
                hSystembarInstance,
                NULL);

        if (!hToolTips)
        {
                MessageBox(0, "Error creating tooltips window", szSystembarName, MB_OK | MB_ICONERROR | MB_TOPMOST);
                Log("Systembar: Error creating tooltips window", NULL);
                return;
        }
        else
        {
        SendMessage(hToolTips, TTM_SETMAXTIPWIDTH, 0, 300);
                SendMessage(hToolTips, TTM_SETDELAYTIME, (WPARAM)(DWORD)TTDT_AUTOPOP, (LPARAM)MAKELONG(3000, 0));
                SendMessage(hToolTips, TTM_SETDELAYTIME, (WPARAM)(DWORD)TTDT_INITIAL, (LPARAM)MAKELONG(1000, 0));
                SendMessage(hToolTips, TTM_SETDELAYTIME, (WPARAM)(DWORD)TTDT_RESHOW, (LPARAM)MAKELONG(1000, 0));
        }

        //====================

        if (!SysTrayDisabled)
        {
                RECT iconRect;
                for (int i=0; i < (int)pTrayManager->trayIconList.size(); i++)
                {
                        // Define the region in which the tooltip should activate (the region of the icon)
                        iconRect.left = pTrayManager->trayIconList[i]->x;
                        iconRect.right = iconRect.left + ICON_SIZE;
                        iconRect.top = pTrayManager->trayIconList[i]->y;
                        iconRect.bottom = iconRect.top + ICON_SIZE;

//                      SetToolTip((UINT)(1000 + i), iconRect, pTrayManager->trayIconList[i]->szTip);
                        SetToolTip(pTrayManager->trayIconList[i]->uID, iconRect, pTrayManager->trayIconList[i]->szTip);
                }
        }
}

//===========================================================================

void Systembar::ToggleTooltips()
{
        // Enable or disable tooltips depending on extensions.rc setting...
        if (!pSettings->systembarTooltipsDisabled)
        {
                pSettings->systembarTooltipsDisabled = true;
                if (hToolTips) DestroyWindow(hToolTips);
                hToolTips = NULL;
        }
        else
        {
                pSettings->systembarTooltipsDisabled = false;
                if (!hToolTips) CreateTooltipsWindow();
                if (!SysTrayDisabled) UpdateToolTipPositions(); // Update tooltip x/y positions...
        }

        WriteBool(pSettings->extrcFile, "xoblite.systembar.tooltips.disable:", pSettings->systembarTooltipsDisabled);
}

//===========================================================================





syntax highlighting by

w e b c p p
web c plus plus