/*
 *      Copyright (C) 1997-2007 Andrei Los.
 *      This file is part of the lSwitcher source package.
 *      lSwitcher is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published
 *      by the Free Software Foundation, in version 2 as it comes in the
 *      "COPYING" file of the lSwitcher main distribution.
 *      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.
 */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "lswitch.h"
#include "common.h"
#include "taskbar.h"
#include "settings.h"
#include "apm.h"
#include "lswres.h"
#include "object.h"

#define PROCITEMHGT 6/5

#ifdef XWORKPLACE
// resolved function pointers from XFLDR.DLL
PKRNSENDDAEMONMSG pkrnSendDaemonMsg = NULL;
CHAR       szHelpFile[CCHMAXPATH];
#endif


SHORT TaskArrItemFromHsw(LSWDATA * plswData, USHORT hsw, BOOL bUseFilters)
{
    SHORT iItem, k;

    if (!plswData->bNowActive)
	InitTaskArr(plswData, FALSE, TRUE, bUseFilters);

    for (k = 0, iItem = -1; k < plswData->usItems && iItem < 0; k++)
	if ((plswData->TaskArr[k].hsw & 0xFFFF) == hsw)
	    iItem = k;

    return iItem;
}

// Modified from John Martin Alfredsson's wxTask XCenter widget
void FillTaskMenu(HAB hab, HWND hwndTaskBar, HWND hwndMenu, SHORT TskBarHgt, BOOL bProcesses)
{
    ULONG ulItemCount, k, l;
    SHORT sMenuItemNum, sItemId;
    MENUITEM mi;

    sMenuItemNum = MenuItemCount(hwndMenu);
    while (sMenuItemNum > 0) {
	sItemId =
	    SHORT1FROMMR(WinSendMsg
			 (hwndMenu, MM_ITEMIDFROMPOSITION,
			  MPFROMSHORT(sMenuItemNum - 1), 0));
	WinSendMsg(hwndMenu, MM_QUERYITEM, MPFROM2SHORT(sItemId, FALSE),
		   MPFROMP(&mi));
	if (mi.afStyle & MIS_PROCESS) {
	    free(((PROCDATA *) mi.hItem)->pszTitle);
	    free((PROCDATA *) mi.hItem);
	}
	sMenuItemNum =
	    SHORT1FROMMR(WinSendMsg
			 (hwndMenu, MM_DELETEITEM,
			  MPFROM2SHORT(sItemId, FALSE), 0));
    }

    if (bProcesses) {
	static UCHAR szPidPath[_MAX_PATH], szName[_MAX_FNAME],
	    szExt[_MAX_EXT];
	UCHAR ucIndent[64], *pBuf;
	QSPTRREC *pRecHead;
	QSPREC *pApp;
	PID pidPrev = 0, pidParent = 0;
	HSWITCH hsw;
	SWCNTRL swctl;
	PROCDATA *pProcData;
	POINTL aptl[TXTBOX_COUNT];
	HPS hps;
	USHORT usItemStyle;

	pBuf = (char *)malloc(0x8000);
	memset(pBuf, 0, 0x8000);
	DosQuerySysState(QS_PROCESS, 0, 0, 0, (char *)pBuf, 0x8000);	// Get processes
	pRecHead = (QSPTRREC *) pBuf;	// Point to first process
	pApp = pRecHead->pProcRec;
	for (k = 0, pidPrev = 0, ucIndent[0] = '\0'; pApp != NULL && pApp->RecType == 1; k++) {	// While its a process record
	    if (pApp->ppid == pidPrev && pApp->ppid != 0) {
		if (strlen(ucIndent) == 0)
		    strncat(ucIndent, "юд",
			    sizeof(ucIndent) - strlen(ucIndent));
		else {
		    strrev(ucIndent);
		    strncat(ucIndent, "    ",
			    sizeof(ucIndent) - strlen(ucIndent));
		    strrev(ucIndent);
		}
		pidParent = pidPrev;
	    }
	    else if (pApp->ppid != pidParent) {
		for (l = 1; l < k; l++) {
		    WinSendMsg(hwndMenu, MM_QUERYITEM,
			       MPFROM2SHORT(101 + k - l, FALSE),
			       MPFROMP(&mi));
		    if (HIUSHORT(mi.hItem) == pApp->ppid) {
			pidParent = pApp->ppid;
			WinSendMsg(hwndMenu, MM_QUERYITEMTEXT,
				   MPFROM2SHORT(101 + k - l,
						sizeof(ucIndent)),
				   MPFROMP(ucIndent));
			ucIndent[strspn(ucIndent, "юд ")] = '\0';
			break;
		    }
		}
		if (l == k)
		    ucIndent[0] = '\0';
	    }
	    pidPrev = pApp->pid;

	    memset(szPidPath, 0, _MAX_PATH);
	    memset(&swctl, 0, sizeof(swctl));
	    DosQueryModuleName(pApp->hMte, sizeof(szPidPath), szPidPath);
	    hsw = WinQuerySwitchHandle(0, pApp->pid);
	    if (hsw != NULLHANDLE)
		WinQuerySwitchEntry(hsw, &swctl);
	    if (strlen(szPidPath) == 0)	// If no hit this is the kernel
		sprintf(szPidPath, "%s*SYSINIT  %s (0x%X)", ucIndent,
			swctl.idProcess == pApp->pid ? swctl.szSwtitle : "",
			pApp->pid);
	    else {
		_splitpath(szPidPath, NULL, NULL, szName, szExt);
		sprintf(szPidPath, "%s%s%s  %s (0x%X)", ucIndent, szName,
			szExt,
			swctl.idProcess == pApp->pid ? swctl.szSwtitle : "",
			pApp->pid);
	    }
            pProcData = (PROCDATA *) malloc(sizeof(PROCDATA));
            memset(pProcData, 0, sizeof(PROCDATA));
	    pProcData->pszTitle = strdup(szPidPath);
	    pProcData->pid = pApp->pid;
	    pProcData->ppid = pApp->ppid;

	    usItemStyle = MIS_OWNERDRAW | MIS_SYSCOMMAND | MIS_PROCESS;

	    hps = WinGetPS(hwndMenu);
	    GpiQueryTextBox(hps, 1, "M", TXTBOX_COUNT, aptl);
	    WinReleasePS(hps);

	    if (k > 0
		&& k %
		((WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN) -
		  TskBarHgt) / max(1,
				   (aptl[TXTBOX_TOPLEFT].y -
				    aptl[TXTBOX_BOTTOMLEFT].y) *
				   PROCITEMHGT)) == 0)
		usItemStyle |= MIS_BREAKSEPARATOR;

	    InsertMenuItem(hwndMenu, NULLHANDLE, MIT_END, 101 + k, "",
			   usItemStyle, 0, (ULONG) pProcData);
	    pApp = (QSPREC *) ((pApp->pThrdRec) + pApp->cTCB);
	}
	free(pBuf);
    }
    else {
	PSWBLOCK pSwb;

	if ((pSwb = GetSwitchList(hab, TRUE, &ulItemCount)) == NULL)
	    return;
	for (k = 0; k < ulItemCount; k++) {
	    if (pSwb->aswentry[k].swctl.uchVisibility == SWL_VISIBLE &&
		pSwb->aswentry[k].swctl.fbJump == SWL_JUMPABLE)
		InsertMenuItem(hwndMenu, NULLHANDLE, MIT_END,
			       pSwb->aswentry[k].hswitch, "",
			       MIS_OWNERDRAW | MIS_SYSCOMMAND, 0,
			       GetWndIcon(pSwb->aswentry[k].swctl.hwnd));
	}
	GetSwitchList(hab, FALSE, NULL);
    }
}

VOID DrawMenuItem(POWNERITEM pItem, LSWDATA * plswData, BOOL bProcesses)
{
    SWCNTRL swctl;
    SWP swp = { 0 };
    UCHAR Title[_MAX_PATH];
    BOOL bHilite;
    LONG lBgndCol, lTextCol, lTskBarCol = plswData->Settings.lTskBarRGBCol;

    if (!bProcesses) {
	WinQuerySwitchEntry(pItem->idItem, &swctl);
	WinQueryWindowPos(swctl.hwnd, &swp);
    }

    GpiCreateLogColorTable(pItem->hps, 0, LCOLF_RGB, 0, 0, NULL);
    bHilite = (pItem->fsAttribute & MIA_HILITED) != 0;

    pItem->rclItem.xLeft += 1;
    pItem->rclItem.xRight -= 1;

    if (!bHilite) {
	if (plswData->Settings.b3DTaskBar)
	    lTextCol = (swp.fl & (SWP_HIDE | SWP_MINIMIZE)) ?
		plswData->Settings.lNormalHiddenBtnTitleRGBCol3D : plswData->
		Settings.lNormalBtnTitleRGBCol3D;
	else
	    lTextCol = (swp.fl & (SWP_HIDE | SWP_MINIMIZE)) ?
		plswData->Settings.lNormalHiddenBtnTitleRGBCol : plswData->
		Settings.lNormalBtnTitleRGBCol;

	if (plswData->Settings.b3DTaskBar)
	    lBgndCol =
		((lTskBarCol & 0xFF) + 240) / 2 +
		(((lTskBarCol & 0xFF00) >> 8) + 240) / 2 * 256 +
		(((lTskBarCol & 0xFF0000) >> 16) + 240) / 2 * 65536;
	else
	    lBgndCol = plswData->Settings.lNormalBtnRGBCol;

	WinFillRect(pItem->hps, &pItem->rclItem, lBgndCol);
    }
    else {
	if (swp.fl & (SWP_HIDE | SWP_MINIMIZE)) {
	    lTextCol =
		plswData->Settings.b3DTaskBar ? plswData->Settings.
		lActiveHiddenBtnTitleRGBCol3D : plswData->Settings.
		lActiveHiddenBtnTitleRGBCol;
	    lBgndCol =
		plswData->Settings.b3DTaskBar ? plswData->Settings.
		lActiveHiddenBtnRGBCol3D : plswData->Settings.
		lActiveHiddenBtnRGBCol;
	}
	else {
	    lTextCol =
		plswData->Settings.b3DTaskBar ? plswData->Settings.
		lActiveBtnTitleRGBCol3D : plswData->Settings.
		lActiveBtnTitleRGBCol;
	    lBgndCol =
		plswData->Settings.b3DTaskBar ? plswData->Settings.
		lActiveBtnRGBCol3D : plswData->Settings.lActiveBtnRGBCol;
	}

	if (plswData->Settings.b3DTaskBar)
	    FillRectGradient(pItem->hps, &pItem->rclItem, NULL, lBgndCol,
			     RGB_WHITE, TRUE);
	else
	    WinFillRect(pItem->hps, &pItem->rclItem, lBgndCol);

	WinDrawBorder(pItem->hps, &pItem->rclItem, BUTTONBORDERWIDTH,
		      BUTTONBORDERWIDTH, SUNKENFRAMERGBCOL, RAISEDFRAMERGBCOL,
		      DB_DEPRESSED);
    }

    if (!bProcesses)
	WinDrawPointer(pItem->hps,
		       pItem->rclItem.xLeft + 1 + BUTTONBORDERWIDTH + bHilite,
		       pItem->rclItem.yBottom + BUTTONBORDERWIDTH + 2 -
		       bHilite, pItem->hItem, DP_MINIICON);

// adjust the rect for text drawing
// shifting the text and icon of a pressed button by one pixel looks better
// than shifting by button border width
    pItem->rclItem.xLeft +=
	(bProcesses ? 2 : pItem->rclItem.yTop - pItem->rclItem.yBottom) +
	bHilite + 1;
    pItem->rclItem.xRight -= BUTTONBORDERWIDTH + 2;
    pItem->rclItem.yTop -= bHilite;
    pItem->rclItem.yBottom -= bHilite;

    if (bProcesses && pItem->hItem != 0)
	strncpy(Title, ((PROCDATA *) pItem->hItem)->pszTitle, sizeof(Title));
    else
	GetItemTitle(pItem->idItem, Title, sizeof(Title), FALSE);
    WinDrawText(pItem->hps, strlen(Title), Title, &pItem->rclItem, lTextCol,
		lBgndCol, DT_VCENTER);
}

SHORT GetItemIdFromPointerPos(HWND hwndMenu, POINTL ptlPointer)
{
    SHORT sId, k;
    HAB hab = WinQueryAnchorBlock(hwndMenu);
    RECTL rectl;

    for (k = 0; k < MenuItemCount(hwndMenu); k++) {
	if ((sId =
	     SHORT1FROMMR(WinSendMsg
			  (hwndMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(k),
			   0))) == MIT_NONE)
	    continue;

	WinSendMsg(hwndMenu, MM_QUERYITEMRECT, MPFROM2SHORT(sId, FALSE),
		   MPFROMP(&rectl));
	if (WinPtInRect(hab, &rectl, &ptlPointer))
	    return sId;
    }
    return MIT_NONE;
}

MRESULT EXPENTRY ButtonMenuWndProc(HWND hwnd, ULONG msg, MPARAM mp1,
				   MPARAM mp2)
{
    MRESULT mrc = 0;
    static SHORT sClickId = 0;


    if (!WinQueryWindowPtr(hwnd, 0))
        return WinDefWindowProc(hwnd, msg, mp1, mp2);

    switch (msg) {
    case WM_CHAR:
    case WM_ADJUSTWINDOWPOS:
	if ((msg == WM_ADJUSTWINDOWPOS
	     && !(((PSWP) PVOIDFROMMP(mp1))->fl & SWP_HIDE))
	    || (msg == WM_CHAR
		&& !(SHORT1FROMMP(mp1) & KC_VIRTUALKEY
		     && (SHORT2FROMMP(mp2) == VK_UP
			 || SHORT2FROMMP(mp2) == VK_DOWN)))) {
	    mrc = ((PFNWP) WinQueryWindowPtr(hwnd, 0)) (hwnd, msg, mp1, mp2);
	    break;
	}
    case MM_SELECTITEM:{
	    SHORT k, sId;

	    for (k = 0; k < MenuItemCount(hwnd); k++) {
		MENUITEM mi;

		if ((sId =
		     SHORT1FROMMR(WinSendMsg
				  (hwnd, MM_ITEMIDFROMPOSITION,
				   MPFROMSHORT(k), 0))) == MIT_NONE
		    || (msg == MM_SELECTITEM && sId == SHORT1FROMMP(mp1)))
		    continue;
		WinSendMsg(hwnd, MM_QUERYITEM, MPFROM2SHORT(sId, FALSE),
			   MPFROMP(&mi));
		if (mi.afStyle & MIS_SUBMENU) {
		    WinShowWindow(mi.hwndSubMenu, FALSE);
		    WinSetParent(mi.hwndSubMenu, HWND_DESKTOP, FALSE);
		    mi.afStyle &= ~MIS_SUBMENU;
		    mi.hwndSubMenu = 0;
		    WinSendMsg(hwnd, MM_SETITEM, MPFROM2SHORT(0, FALSE),
			       MPFROMP(&mi));
		}
	    }
	    mrc = ((PFNWP) WinQueryWindowPtr(hwnd, 0)) (hwnd, msg, mp1, mp2);
	    break;
	}

    case WM_CONTEXTMENU:{
	    SHORT sId, sSelId;
	    POINTL ptl;
	    LSWDATA *plswData;
	    MENUITEM mi;

	    ptl.x = SHORT1FROMMP(mp1);
	    ptl.y = SHORT2FROMMP(mp1);
	    if ((sId = GetItemIdFromPointerPos(hwnd, ptl)) == MIT_NONE)
		break;

	    sSelId = SHORT1FROMMR(WinSendMsg(hwnd, MM_QUERYSELITEMID, 0, 0));
	    WinSendMsg(hwnd, MM_QUERYITEM, MPFROM2SHORT(sSelId, FALSE),
		       MPFROMP(&mi));

	    if (mi.afStyle & MIS_SUBMENU) {
		if (sId == sSelId)
		    break;
		else {
		    WinShowWindow(mi.hwndSubMenu, FALSE);
		    mi.afStyle &= (~MIS_SUBMENU);
		    mi.hwndSubMenu = 0;
		    WinSendMsg(hwnd, MM_SETITEM, MPFROM2SHORT(0, FALSE),
			       MPFROMP(&mi));
		}
	    }

	    if (DosGetNamedSharedMem
		((PVOID *) & plswData, SHAREMEM_NAME,
		 PAG_READ | PAG_WRITE) != 0)
		break;
	    if (!plswData->bNowActive
		&& (plswData->iMenuAtItem =
		    TaskArrItemFromHsw(plswData, sId, FALSE)) >= 0) {
		if (MenuItemCount(plswData->hwndMenu) == 0) {
		    //without these commands the task submenu won't show for some reason if it's a first popup;
		    //apparently WinPopopMenu does some initialization to the menu window
		    WinPopupMenu(HWND_DESKTOP, hwnd, plswData->hwndMenu, 0, 0,
				 0, 0);
		    WinShowWindow(plswData->hwndMenu, FALSE);
		}

		InitTaskActionsMenu(plswData->hwndMenu, plswData,
                                    plswData->iMenuAtItem, TRUE,
                                    MenuItemCount(((BTNDATA *) WinQueryWindowPtr(hwnd, 0))->
				    hwndSubWinMenu) > 0);
		WinSendMsg(hwnd, MM_SELECTITEM, MPFROM2SHORT(sId, TRUE),
			   MPFROM2SHORT(0, FALSE));
		WinSendMsg(hwnd, MM_QUERYITEM, MPFROM2SHORT(sId, FALSE),
			   MPFROMP(&mi));
		mi.afStyle |= MIS_SUBMENU;
		mi.hwndSubMenu = plswData->hwndMenu;
		WinSendMsg(hwnd, MM_SETITEM, MPFROM2SHORT(0, FALSE),
			   MPFROMP(&mi));
		WinPostMsg(hwnd, WM_CHAR, MPFROM2SHORT(KC_VIRTUALKEY, 0),
			   MPFROM2SHORT(0, VK_RIGHT));
	    }
	    DosFreeMem(plswData);
	    break;
	}

    case WM_BUTTON1UP:
    case WM_BUTTON2UP:
    case WM_BUTTON3UP:
    case WM_CHORD:{
	    POINTL ptl;

	    ptl.x = SHORT1FROMMP(mp1);
	    ptl.y = SHORT2FROMMP(mp1);
	    sClickId = GetItemIdFromPointerPos(hwnd, ptl);
	}
    case WM_BUTTON1CLICK:
    case WM_BUTTON2CLICK:
    case WM_BUTTON3CLICK:
	WinSendMsg(WinQueryWindow(hwnd, QW_OWNER),
		   (msg /*+0x3a1 */ ) | 0x1000,
		   mp1, MPFROM2SHORT(sClickId, SHORT2FROMMP(mp2)));

    default:
	mrc = ((PFNWP) WinQueryWindowPtr(hwnd, 0)) (hwnd, msg, mp1, mp2);
    }

    return mrc;
}

MRESULT EXPENTRY ButtonWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
    LSWDATA *plswData;
    MRESULT mrc = 0;
    static BOOL bChord = FALSE;
    static ULONG ulBtnDnTime = 0;

    if (!WinQueryWindowPtr(hwnd, 0))
        return WinDefWindowProc(hwnd, msg, mp1, mp2);

    if (msg != WM_DESTROY)
#ifdef XWORKPLACE
	plswData =
	    ((PXCENTERWIDGET)
	     WinQueryWindowPtr(WinQueryWindow(hwnd, QW_PARENT), 0))->pUser;
#else
	plswData = WinQueryWindowPtr(WinQueryWindow(hwnd, QW_PARENT), 0);
#endif

    switch (LOUSHORT(msg)) {
    case WM_MEASUREITEM:{
            UCHAR Title[_MAX_PATH] = {0};
	    POINTL aptl[TXTBOX_COUNT];
	    POWNERITEM pItem = ((POWNERITEM) mp2);
	    MENUITEM mi;
	    BOOL bMenuProcMode;

	    WinSendMsg(plswData->hwndTaskMenu, MM_QUERYITEM,
		       MPFROM2SHORT(pItem->idItem, FALSE), MPFROMP(&mi));
	    bMenuProcMode = (mi.afStyle & MIS_PROCESS);

	    //if (!bMenuProcMode)
                GetItemTitle(pItem->idItem, Title, sizeof(Title), FALSE);
            /*else
                strncpy(Title, ((PROCDATA *) pItem->hItem)->pszTitle,
                        sizeof(Title) - 1);*/
            GpiQueryTextBox(pItem->hps,	strlen(Title), Title,
                            TXTBOX_COUNT, aptl);
	    pItem->rclItem.yTop =
		(bMenuProcMode
		 ? (aptl[TXTBOX_TOPLEFT].y -
		    aptl[TXTBOX_BOTTOMLEFT].y) *
		 PROCITEMHGT : WinQuerySysValue(HWND_DESKTOP,
						SV_CYICON) / 2 +
		 2 * BUTTONBORDERWIDTH + 2);
	    pItem->rclItem.xRight =
		aptl[TXTBOX_BOTTOMRIGHT].x - aptl[TXTBOX_BOTTOMLEFT].x +
		(bMenuProcMode ? 0 : pItem->rclItem.yTop);

	    mrc = (MRESULT) pItem->rclItem.yTop;

	    break;
	}

    case WM_DRAWITEM:{
	    POWNERITEM pItem = ((POWNERITEM) mp2);
	    MENUITEM mi;
	    BOOL bMenuProcMode;

	    WinSendMsg(plswData->hwndTaskMenu, MM_QUERYITEM,
		       MPFROM2SHORT(pItem->idItem, FALSE), MPFROMP(&mi));
	    bMenuProcMode = (mi.afStyle & MIS_PROCESS);

	    if (pItem->fsAttribute == pItem->fsAttributeOld ||
		((pItem->fsAttribute & MIA_HILITED) !=
		 (pItem->fsAttributeOld & MIA_HILITED))) {
		DrawMenuItem(pItem, plswData, bMenuProcMode);
		pItem->fsAttributeOld = (pItem->fsAttribute &= ~MIA_HILITED);
		mrc = (MRESULT) TRUE;
	    }

	    break;
	}

    case WM_COMMAND:
	if (SHORT1FROMMP(mp1) == CMD_ADDFILTER ||
	    (SHORT1FROMMP(mp1) >= CMD_FIRST && SHORT1FROMMP(mp1) <= CMD_LAST))
	    ProcessCommand(SHORT1FROMMP(mp1), SHORT1FROMMP(mp2), plswData,
			   TRUE, FALSE);
#ifdef XWORKPLACE
	else
	    WinPostMsg(plswData->pWidget->hwndWidget, msg, mp1, mp2);
#endif

	break;

    case WM_SYSCOMMAND:{
	    MENUITEM mi;
	    BOOL bMenuProcMode;

	    if (SHORT1FROMMP(mp2) != CMDSRC_MENU)
		break;

	    WinSendMsg(plswData->hwndTaskMenu, MM_QUERYITEM,
		       MPFROM2SHORT(SHORT1FROMMP(mp1), FALSE), MPFROMP(&mi));
	    bMenuProcMode = (mi.afStyle & MIS_PROCESS);

	    if (!bMenuProcMode) {
		SWCNTRL swctl;
		WinQuerySwitchEntry(SHORT1FROMMP(mp1), &swctl);
		WinSetWindowPos(swctl.hwnd, HWND_TOP, 0, 0, 0, 0,
				SWP_SHOW | SWP_ZORDER);
		WinSwitchToProgram(SHORT1FROMMP(mp1));
	    }
	    else {
		UCHAR ucBuf[256];
		PID pid;
		PSZ pszName;

		pid = ((PROCDATA *) mi.hItem)->pid;
		pszName = ((PROCDATA *) mi.hItem)->pszTitle;

		if (pid == 1 || IsWPSPid(pid)) {
		    WinLoadString(plswData->hab, plswData->hmodRes,
				  MSG_CANTKILL, sizeof(ucBuf), ucBuf);
		    WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, ucBuf, PGMNAME,
				  0, MB_ERROR | MB_CANCEL);
		}
		else {
		    ULONG ulResult, k, ulInfoSize;
		    UCHAR ucCancel[MAX_MBDTEXT];
		    MB2INFO *pmbInfo;
		    BOOL bDeathBtn = XF86Installed() || CADHInstalled();

#ifdef __WATCOMC__
		    MB2D mb2dBut[3] =
			{ {"~DosKillProcess", 0, 501, BS_PUSHBUTTON}
		    , {"~SIGKILL", 0, 502, BS_PUSHBUTTON}
		    ,
		    {"", 0, 503, BS_PUSHBUTTON | BS_DEFAULT}
		    };
#else
		    MB2D mb2dBut[3] = { {"~DosKillProcess", 501, BS_PUSHBUTTON}
		    , {"~SIGKILL", 502, BS_PUSHBUTTON}
		    ,
		    {"", 503, BS_PUSHBUTTON | BS_DEFAULT}
		    };
#endif

		    k = strspn(pszName, "юд ");
		    memmove(pszName, &pszName[k], strlen(pszName) - k + 1);
		    WinLoadString(plswData->hab, plswData->hmodRes,
				  MSG_KILLQUERY, sizeof(ucBuf), ucBuf);
		    WinLoadString(plswData->hab, plswData->hmodRes,
				  MSG_CANCEL, sizeof(ucCancel), ucCancel);
		    strcpy(mb2dBut[2].achText, ucCancel);
		    sprintf(&ucBuf[strlen(ucBuf)], " %s?", pszName);
		    // Need space for MB2INFO plus 3 additional buttons (one button is defined in the MB2INFO structure).
		    ulInfoSize =
			sizeof(MB2INFO) + sizeof(MB2D) * (1 + bDeathBtn);
		    pmbInfo = malloc(ulInfoSize);
		    pmbInfo->cb = ulInfoSize;	/* Size of block              */
		    pmbInfo->hIcon = NULLHANDLE;
		    pmbInfo->cButtons = 2 + bDeathBtn;	/* Number of buttons for box  */
		    pmbInfo->flStyle = MB_ICONQUESTION | MB_MOVEABLE;
		    pmbInfo->hwndNotify = NULLHANDLE;
		    for (k = 0; k < 3; k += (bDeathBtn ? 1 : 2))
			memcpy(pmbInfo->mb2d + k - (k == 2 && !bDeathBtn),
			       mb2dBut + k, sizeof(MB2D));

		    ulResult =
			WinMessageBox2(HWND_DESKTOP, HWND_DESKTOP, ucBuf,
				       PGMNAME, 0, pmbInfo);
		    free(pmbInfo);

		    if (ulResult == 501)
			DosKillProcess(DKP_PROCESS, pid);
		    else if (ulResult == 502)
			Death(pid);
		}
	    }
	    break;
	}

    case WM_CHORD | 0x1000:
    case WM_CHORD:			//for some reason if either mouse button is down, sending
	bChord = TRUE;			//WM_SYSCOMMAND does not have the effect, so need to do it the stupid way
	if (msg == WM_CHORD)
	    mrc =
		(((BTNDATA *) WinQueryWindowPtr(hwnd, 0))->pOldWndProc) (hwnd,
									 msg,
									 mp1,
									 mp2);
	break;

    case WM_BUTTON1DOWN:
	ulBtnDnTime = WinQueryMsgTime(plswData->hab);
	break;
    case WM_BUTTON1DBLCLK:
    case WM_BUTTON1CLICK:
    case WM_BUTTON2CLICK:
    case WM_BUTTON3CLICK:
    case WM_BUTTON1CLICK | 0x1000:
    case WM_BUTTON2CLICK | 0x1000:
    case WM_BUTTON3CLICK | 0x1000:
    case WM_BUTTON1UP:
    case WM_BUTTON2UP:
    case WM_BUTTON1UP | 0x1000:
    case WM_BUTTON2UP | 0x1000:{
	    BOOL bShiftKeyDown, bMenuCmd = (msg & 0x1000);
	    SHORT sItem;
            USHORT usHswActive, usHsw;
            SHORT activeInGroup = 0;
            BOOL  bTaskBarTopScr;

	    bShiftKeyDown = ((WinGetKeyState(HWND_DESKTOP, VK_CTRL) & 0x8000)
			     || (WinGetKeyState(HWND_DESKTOP, VK_ALT) &
				 0x8000)
			     || (WinGetKeyState(HWND_DESKTOP, VK_ALTGRAF) &
				 0x8000)
			     || (WinGetKeyState(HWND_DESKTOP, VK_SHIFT) &
				 0x8000));

	    usHswActive =
		(USHORT) WinSendMsg(plswData->hwndTaskBarClient,
				    LSWM_QUERYACTIVEBTNID, 0, 0);
	    //    usActiveBtn=(USHORT)WinSendMsg(plswData->hwndTaskBarClient,LSWM_QUERYACTIVEBTN,MPFROMHWND(hwnd),0);
            usHsw =
		bMenuCmd ? SHORT1FROMMP(mp2) : WinQueryWindowUShort(hwnd,
								    QWS_ID);
	    sItem = TaskArrItemFromHsw(plswData, usHsw, TRUE);
	    plswData->usCurrItem = sItem;

	    if (!bShiftKeyDown && bChord &&
		(((msg & 0xFFF) == WM_BUTTON1UP
		  && !(WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000))
		 || ((msg & 0xFFF) == WM_BUTTON2UP
		     && !(WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) &
			  0x8000)))) {
		msg = WM_CHORD;
		bChord = FALSE;
	    }

	    // Show task menu
#ifdef XWORKPLACE
            bTaskBarTopScr = (plswData->pWidget->pGlobals->ulPosition == XCENTER_TOP);
#else
            bTaskBarTopScr = plswData->Settings.bTaskBarTopScr;
#endif
	    if (((msg == WM_BUTTON1UP
		  && WinQueryMsgTime(plswData->hab) - ulBtnDnTime >
		  WinQuerySysValue(HWND_DESKTOP, SV_DBLCLKTIME)
		  && !bShiftKeyDown) || (msg == WM_BUTTON1CLICK
					 && ((SHORT2FROMMP(mp2) & KC_SHIFT) ^
					     (SHORT2FROMMP(mp2) & KC_CTRL))))
		&& IsDesktop(plswData->TaskArr[sItem].hwnd)) {
		SWP swp;
		POINTL ptl;
		SHORT sItems = 0;
		USHORT usItemHgt = 0, usFrameWid = 0;
		LONG lMenuCol;
		BOOL bMenuProcMode;

                WinStopTimer(plswData->hab, hwnd, TSKHIDEDELAYTIMERID);
		bMenuProcMode = (SHORT2FROMMP(mp2) & KC_CTRL);
		FillTaskMenu(plswData->hab, hwnd, plswData->hwndTaskMenu,
			     plswData->Settings.sTskBarCY, bMenuProcMode);
		WinQueryWindowPos(hwnd, &swp);
		ptl.x = swp.x;
		ptl.y = swp.y;
		if (bTaskBarTopScr) {
		    if (bMenuProcMode) {
			POINTL aptl[TXTBOX_COUNT];
			HPS hps = WinGetPS(plswData->hwndTaskMenu);

			GpiQueryTextBox(hps, 1, "M", TXTBOX_COUNT, aptl);
			usItemHgt =
			    (aptl[TXTBOX_TOPLEFT].y -
			     aptl[TXTBOX_BOTTOMLEFT].y) * PROCITEMHGT;
			WinReleasePS(hps);
		    }
		    else
			usItemHgt =
			    WinQuerySysValue(HWND_DESKTOP,
					     SV_CYICON) / 2 +
			    2 * BUTTONBORDERWIDTH + 2;

		    sItems = MenuItemCount(plswData->hwndTaskMenu);
		    usFrameWid =
			WinQuerySysValue(HWND_DESKTOP, SV_CYDLGFRAME);
		}
		WinMapWindowPoints(WinQueryWindow(hwnd, QW_PARENT),
				   HWND_DESKTOP, &ptl, 1);
		if (plswData->Settings.b3DTaskBar) {
		    LONG lTskBarCol = plswData->Settings.lTskBarRGBCol;

		    lMenuCol =
			((lTskBarCol & 0xFF) + 240) / 2 +
			(((lTskBarCol & 0xFF00) >> 8) + 240) / 2 * 256 +
			(((lTskBarCol & 0xFF0000) >> 16) + 240) / 2 * 65536;
		}
		else
		    lMenuCol = plswData->Settings.lNormalBtnRGBCol;
		WinSetPresParam(plswData->hwndTaskMenu,
				PP_MENUBACKGROUNDCOLOR, sizeof(lMenuCol),
                                &lMenuCol);
                if ((SHORT)WinSendMsg(plswData->hwndTaskMenu, MM_ITEMPOSITIONFROMID,
                                      MPFROM2SHORT(usHswActive, 0), 0) != MIT_NONE)
                    activeInGroup = PU_SELECTITEM;
                WinPopupMenu(HWND_DESKTOP, hwnd, plswData->hwndTaskMenu,
			     ptl.x,
			     ptl.y +
			    (bTaskBarTopScr ? -sItems *
			     usItemHgt - 2 * usFrameWid : swp.cy),
			     usHswActive,
			     PU_HCONSTRAIN | PU_VCONSTRAIN | PU_MOUSEBUTTON1 |
			     PU_KEYBOARD | activeInGroup);
	    }
	    else if (!bShiftKeyDown && msg != WM_BUTTON1UP
		     && msg != WM_BUTTON2UP && sItem >= 0) {
		HWND hwndSubWinMenu =
		    ((BTNDATA *) WinQueryWindowPtr(hwnd, 0))->hwndSubWinMenu;
		USHORT usMenuItems = MenuItemCount(hwndSubWinMenu);
		SWP swp;

		if (msg == plswData->Settings.usSwitchMEvent
		    && usMenuItems > 0) {
		    POINTL ptl;
                    USHORT usItemHgt = 0, usFrameWid = 0;

		    WinQueryWindowPos(hwnd, &swp);
		    ptl.x = swp.x;
		    ptl.y = swp.y;
		    if (bTaskBarTopScr) {
			usItemHgt =
			    WinQuerySysValue(HWND_DESKTOP,
					     SV_CYICON) / 2 +
			    2 * BUTTONBORDERWIDTH + 2;
			usFrameWid =
			    WinQuerySysValue(HWND_DESKTOP, SV_CYDLGFRAME);
		    }
		    WinMapWindowPoints(WinQueryWindow(hwnd, QW_PARENT),
                                       HWND_DESKTOP, &ptl, 1);
                    if ((SHORT)WinSendMsg(hwndSubWinMenu, MM_ITEMPOSITIONFROMID,
                                          MPFROM2SHORT(usHswActive, 0), 0) != MIT_NONE)
                        activeInGroup = PU_SELECTITEM;
		    WinPopupMenu(HWND_DESKTOP, hwnd, hwndSubWinMenu, ptl.x,
				 ptl.y +
				 (bTaskBarTopScr ? -usMenuItems * usItemHgt -
				  2 * usFrameWid : swp.cy), usHswActive,
				 PU_NONE | PU_HCONSTRAIN | PU_VCONSTRAIN |
				 PU_MOUSEBUTTON1 | PU_KEYBOARD | activeInGroup);
		}
		else if ((msg & 0xFFF) == plswData->Settings.usSwitchMEvent &&
			 (MenuNeedsItem
			  (plswData, sItem, CMD_SWITCHFROMPM, NULL, 0,
			   !bMenuCmd && usMenuItems > 0)
                          || IsDesktop(plswData->TaskArr[sItem].hwnd))) {
                    ProcessCommand(CMD_SWITCHFROMPM, CMDSRC_OTHER, plswData,
				   TRUE, FALSE);
		}
		else if (msg == WM_BUTTON1DBLCLK
			 && MenuNeedsItem(plswData, sItem, CMD_SWITCHFROMPM,
                                          NULL, 0, FALSE)) {
		    ProcessCommand(CMD_SWITCHFROMPM, CMDSRC_OTHER, plswData,
				   TRUE, FALSE);
		}
		else if ((msg & 0xFFF) == plswData->Settings.usMinMEvent) {
		    if (MenuNeedsItem
			(plswData, sItem, CMD_HIDE, NULL, 0, !bMenuCmd
			 && usMenuItems > 0))
			ChangeWindowPos(plswData, sItem, CMD_HIDE);
		    else if (MenuNeedsItem
			     (plswData, sItem, CMD_MINIMIZE, NULL, 0,
			      !bMenuCmd && usMenuItems > 0))
                        ChangeWindowPos(plswData, sItem, CMD_MINIMIZE);
		}
		else if (msg == plswData->Settings.usCloseMEvent) {
		    ProcessCommand(CMD_CLOSE, CMDSRC_OTHER, plswData, TRUE,
				   !bMenuCmd && usMenuItems > 0);
		}
	    }

	    mrc =
		(((BTNDATA *) WinQueryWindowPtr(hwnd, 0))->pOldWndProc) (hwnd,
									 msg,
									 mp1,
									 mp2);
	    break;
	}

    case WM_CONTEXTMENU:
	if (!plswData->bNowActive &&
	    (plswData->iMenuAtItem =
	     TaskArrItemFromHsw(plswData, WinQueryWindowUShort(hwnd, QWS_ID),
				TRUE)) >= 0) {
	    ShowBubble(plswData, 0, 0, 0, -2, NULL);
	    ShowMenu(plswData,
		     IsDesktop(plswData->TaskArr[plswData->iMenuAtItem].
			       hwnd) ? -1 : plswData->iMenuAtItem, TRUE,
		     MenuItemCount(((BTNDATA *) WinQueryWindowPtr(hwnd, 0))->
				   hwndSubWinMenu) > 0, FALSE);
	}
	break;

    case WM_PRESPARAMCHANGED:{
	    UCHAR ucBuf[64];
	    LONG lParam, lValue;
	    BOOL bActiveBtn, bHidden;
	    BTNDATA *pBtnData;

	    lParam = LONGFROMMP(mp1);

	    if (!
		(lParam == PP_FOREGROUNDCOLOR || lParam == PP_BACKGROUNDCOLOR
		 || lParam == PP_FONTNAMESIZE)
		|| (LONG) WinQueryPresParam(hwnd, lParam, 0, NULL,
					    sizeof(ucBuf), ucBuf,
					    QPF_NOINHERIT) == 0)
		break;

	    lValue = ucBuf[0] + ucBuf[1] * 256 + ucBuf[2] * 65536;
	    bActiveBtn =
		((USHORT)
		 WinSendMsg(WinQueryWindow(hwnd, QW_PARENT),
			    LSWM_QUERYACTIVEBTNID, 0,
			    0) == WinQueryWindowUShort(hwnd, QWS_ID));
	    pBtnData = WinQueryWindowPtr(hwnd, 0);
	    bHidden = (pBtnData->flItemWnd & (SWP_HIDE | SWP_MINIMIZE));

	    switch (lParam) {
	    case PP_FOREGROUNDCOLOR:
		if (bActiveBtn)
		    if (bHidden)
			if (plswData->Settings.b3DTaskBar)
			    plswData->Settings.lActiveHiddenBtnTitleRGBCol3D =
				lValue;
			else
			    plswData->Settings.lActiveHiddenBtnTitleRGBCol =
				lValue;
		    else if (plswData->Settings.b3DTaskBar)
			plswData->Settings.lActiveBtnTitleRGBCol3D = lValue;
		    else
			plswData->Settings.lActiveBtnTitleRGBCol = lValue;
		else if (bHidden)
		    if (plswData->Settings.b3DTaskBar)
			plswData->Settings.lNormalHiddenBtnTitleRGBCol3D =
			    lValue;
		    else
			plswData->Settings.lNormalHiddenBtnTitleRGBCol =
			    lValue;
		else if (plswData->Settings.b3DTaskBar)
		    plswData->Settings.lNormalBtnTitleRGBCol3D = lValue;
		else
		    plswData->Settings.lNormalBtnTitleRGBCol = lValue;
		break;

	    case PP_BACKGROUNDCOLOR:
		if (bActiveBtn)
		    if (bHidden)
			if (plswData->Settings.b3DTaskBar)
			    plswData->Settings.lActiveHiddenBtnRGBCol3D =
				lValue;
			else
			    plswData->Settings.lActiveHiddenBtnRGBCol =
				lValue;
		    else if (plswData->Settings.b3DTaskBar)
			plswData->Settings.lActiveBtnRGBCol3D = lValue;
		    else
			plswData->Settings.lActiveBtnRGBCol = lValue;
		else if (bHidden)
		    if (plswData->Settings.b3DTaskBar)
			plswData->Settings.lNormalHiddenBtnRGBCol3D = lValue;
		    else
			plswData->Settings.lNormalHiddenBtnRGBCol = lValue;
		else if (plswData->Settings.b3DTaskBar)
		    plswData->Settings.lNormalBtnRGBCol3D = lValue;
		else
		    plswData->Settings.lNormalBtnRGBCol = lValue;
		break;

	    case PP_FONTNAMESIZE:{
		    HENUM henum;
		    HWND hwndNext;

		    if (strcmp(plswData->Settings.ucButtonFont, ucBuf) == 0)
			break;		//we don't want infinite recursion

		    strncpy(plswData->Settings.ucButtonFont, ucBuf,
			    sizeof(plswData->Settings.ucButtonFont));

		    henum =
			WinBeginEnumWindows(WinQueryWindow(hwnd, QW_PARENT));
		    while ((hwndNext = WinGetNextWindow(henum)) != NULLHANDLE) {
			if (IsWindowClass(hwndNext, "#3") && hwndNext != hwnd)
			    WinSetPresParam(hwndNext, PP_FONTNAMESIZE,
					    strlen(plswData->Settings.
						   ucButtonFont) + 1,
					    plswData->Settings.ucButtonFont);
		    }
		    WinEndEnumWindows(henum);
		    break;
		}

	    }

	    if (bActiveBtn)
	        WinInvalidateRect(hwnd, NULL, FALSE);
	    else
		WinInvalidateRect(WinQueryWindow(hwnd, QW_PARENT), NULL,
				  TRUE);

	    break;
	}

    default:
	if (!(WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000) &&
	    !(WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000))
	    bChord = FALSE;

	mrc =
	    (((BTNDATA *) WinQueryWindowPtr(hwnd, 0))->pOldWndProc) (hwnd,
								     msg, mp1,
								     mp2);
	break;
    }

    return mrc;
}

MRESULT EXPENTRY TskBarFrameWndProc(HWND hwnd, ULONG msg, MPARAM mp1,
				    MPARAM mp2)
{
    LSWDATA *plswData;

    if (msg != WM_CREATE)
	plswData = WinQueryWindowPtr(WinWindowFromID(hwnd, FID_CLIENT), 0);

    switch (msg) {
    case WM_WINDOWPOSCHANGED:{
	    PSWP pswp = ((PSWP) PVOIDFROMMP(mp1));
	    if (pswp->fl & (SWP_SIZE | SWP_MOVE)) {
		if (!IsInDesktop(plswData->hab, hwnd, plswData->lCurrDesktop)) {
		    WinSetWindowPos(hwnd, 0, plswData->Settings.sTskBarX,
		        	    plswData->Settings.sTskBarY, 0, 0,
		        	    SWP_MOVE);
		}
		else {
		    plswData->Settings.sTskBarX = pswp->x;
		    plswData->Settings.sTskBarY = pswp->y;
		    plswData->Settings.sTskBarCX = pswp->cx;
		    plswData->Settings.sTskBarCY = pswp->cy;
		}
	    }
	    break;
	}

    case WM_ADJUSTWINDOWPOS:{
	    SWP *pswp = PVOIDFROMMP(mp1);

	    if (pswp->fl & SWP_ACTIVATE)
		pswp->fl &= ~SWP_ACTIVATE;
	    break;
	}

    }

    return ((PFNWP) WinQueryWindowPtr(hwnd, 0)) (hwnd, msg, mp1, mp2);
}

BOOL IsDesktopBtn(HWND hwndBtn)
{
    SWCNTRL swctl;

    WinQuerySwitchEntry(WinQueryWindowUShort(hwndBtn, QWS_ID), &swctl);
    return IsDesktop(swctl.hwnd);
}

HWND GetBtnFromHsw(HWND hwndTaskBar, HSWITCH hsw)
{
    HWND hwndNext, hwndFound = 0;
    HENUM henum = WinBeginEnumWindows(hwndTaskBar);
    BTNDATA *pbData;

//look in submenus first
    while ((hwndNext = WinGetNextWindow(henum)) != NULLHANDLE
	   && hwndFound == 0)
	if (IsWindowClass(hwndNext, "#3")
	    && (pbData = WinQueryWindowPtr(hwndNext, 0)) != NULL
	    && (SHORT) WinSendMsg(pbData->hwndSubWinMenu,
				  MM_ITEMPOSITIONFROMID,
				  MPFROM2SHORT(hsw & 0xFFFF, FALSE),
				  0) != MIT_NONE)
	    hwndFound = pbData->hwndSubWinMenu;
    WinEndEnumWindows(henum);
    if (!hwndFound)
	hwndFound = WinWindowFromID(hwndTaskBar, hsw & 0xFFFF);
    return hwndFound;
}

HWND GetBtnFromHmte(HWND hwndTaskBar, SWCNTRL swctl)
{
    SWCNTRL swctl1stItem;
    HWND hwndNext, hwndBtnSameHmte = 0;
    HENUM henum = WinBeginEnumWindows(hwndTaskBar);
    BTNDATA *pbData;

    while ((hwndNext = WinGetNextWindow(henum)) != NULLHANDLE
           && hwndBtnSameHmte == 0) {
        if (IsWindowClass(hwndNext, "#3")) {
            pbData = WinQueryWindowPtr(hwndNext, 0);
            if (pbData && pbData->hMte == HmteFromPID(swctl.idProcess)
                && (!IsWPSPid(swctl.idProcess) || (!IsDesktopBtn(hwndNext)))) {
                WinQuerySwitchEntry(WinQuerySwitchHandle(pbData->hwndFirstItem, 0), &swctl1stItem);
                if (swctl.bProgType == 0 || swctl1stItem.bProgType == 0 ||
                    swctl.bProgType == swctl1stItem.bProgType)
                    hwndBtnSameHmte = hwndNext;
            }
        }

    }
    WinEndEnumWindows(henum);

    return hwndBtnSameHmte;
}

VOID UpdateTaskMenu(LSWDATA * plswData, HSWITCH hsw, SWCNTRL swctl,
		    ULONG ulFunc)
{
    MENUITEM mi;
    ENTRYNAME Title;
    BOOL bExists, bHidden;

    if (!WinIsWindowVisible(plswData->hwndTaskMenu)
	|| MenuItemCount(plswData->hwndTaskMenu) == 0
	||
	(WinSendMsg
	 (plswData->hwndTaskMenu, MM_QUERYITEM,
	  MPFROM2SHORT((SHORT)
		       WinSendMsg(plswData->hwndTaskMenu,
				  MM_ITEMIDFROMPOSITION, MPFROMSHORT(0), 0),
		       0), MPFROMP(&mi)), mi.afStyle & MIS_PROCESS))
	return;

    bExists =
	((SHORT)
	 WinSendMsg(plswData->hwndTaskMenu, MM_ITEMPOSITIONFROMID,
		    MPFROM2SHORT(hsw, 0), 0) != MIT_NONE);
    bHidden = (swctl.uchVisibility != SWL_VISIBLE
	       || swctl.fbJump != SWL_JUMPABLE);

    if (((ulFunc & 1) || ulFunc == 2) && !bExists && !bHidden) {
	InsertMenuItem(plswData->hwndTaskMenu, NULLHANDLE, 0, hsw, "",
		       MIS_OWNERDRAW | MIS_SYSCOMMAND, 0,
		       GetWndIcon(swctl.hwnd));
    }
    else if (ulFunc == 3 || (ulFunc == 2 && bHidden)) {
	WinSendMsg(plswData->hwndTaskMenu, MM_DELETEITEM,
		   MPFROM2SHORT(hsw, FALSE), 0);
    }
    else if (ulFunc == 2 && bExists) {
	GetItemTitle(hsw, Title, sizeof(Title), FALSE);
	WinSendMsg(plswData->hwndTaskMenu, MM_SETITEMTEXT, MPFROMSHORT(hsw),
		   MPFROMP(Title));
    }
}

VOID UpdateTaskbarItem(LSWDATA * plswData, USHORT usMinBtnWid,
		       HSWITCH hswItem, HWND hwndItem)
{
    RECTL rcl;
    SHORT sItem;
    ENTRYNAME Title;

    if (IsWindowClass(hwndItem, "#3")) {	//the item is the button itself
// update button text
	WinQueryWindowRect(hwndItem, &rcl);
        rcl.xLeft = usMinBtnWid;
            WinInvalidateRect(hwndItem, &rcl, FALSE);
// update bubble text
	if (!plswData->bNowActive
	    && (sItem = TaskArrItemFromHsw(plswData, hswItem, TRUE)) >= 0)
	    ShowBubble(plswData, sItem, 0, 0, 11, NULL);
    }
    else {				//the item is in the button submenu
	GetItemTitle(hswItem, Title, sizeof(Title), FALSE);
	WinSendMsg(hwndItem, MM_SETITEMTEXT, MPFROMSHORT(hswItem),
		   MPFROMP(Title));
    }
}

VOID RemoveTaskbarItem(LSWDATA * plswData, HSWITCH hswItem, HWND hwndItem)
{
    BTNDATA *pbData;

    if (IsWindowClass(hwndItem, "#3")) {
        pbData = WinQueryWindowPtr(hwndItem, 0);
        if (pbData) {
            WinSetWindowPtr(pbData->hwndSubWinMenu, QWL_USER, NULL);
            WinDestroyWindow(pbData->hwndSubWinMenu);
            if (pbData->pszObjName)
                free(pbData->pszObjName);
            if (pbData->pszDataFName)
                free(pbData->pszDataFName);
            if (pbData->hObjIcon)
                WinDestroyPointer(pbData->hObjIcon);
            free(pbData);
            pbData = NULL;
        }
        WinSetWindowPtr(hwndItem, QWL_USER, NULL);
	WinDestroyWindow(hwndItem);
        DosSleep(20);
        WinSendMsg(plswData->hwndTaskBarClient, WM_SIZE, 0, 0);
    }
    else {
	HWND hwndBtn = WinQueryWindow(hwndItem, QW_OWNER);
	SHORT sItemCount;

	pbData = WinQueryWindowPtr(hwndBtn, 0);
	WinSendMsg(pbData->hwndSubWinMenu, MM_DELETEITEM,
		   MPFROM2SHORT(hswItem, FALSE), 0);
        sItemCount = MenuItemCount(hwndItem);
        // last menu item or button item
        if (sItemCount >= 1 || (hswItem & 0xFFFF) == WinQueryWindowUShort(hwndBtn, QWS_ID)) {
	    SWCNTRL swctlItem;
	    SWP swpItem;
	    SHORT sId =
		(SHORT) WinSendMsg(pbData->hwndSubWinMenu,
				   MM_ITEMIDFROMPOSITION, 0, 0);

	    WinSetWindowUShort(hwndBtn, QWS_ID, sId);
	    WinQuerySwitchEntry(sId, &swctlItem);
	    WinQueryWindowPos(swctlItem.hwnd, &swpItem);
	    pbData->flItemWnd = swpItem.fl;
	    pbData->hwndFirstItem = swctlItem.hwnd;
	    pbData->hMte = HmteFromPID(swctlItem.idProcess);
	    if (sItemCount >= 1) {
                pbData->hIcon = GetWndIcon(swctlItem.hwnd);
            }
            if (sItemCount == 1) {
		WinSendMsg(pbData->hwndSubWinMenu, MM_DELETEITEM,
                           MPFROM2SHORT(sId, FALSE), 0);
	    }
        }
    }
}

VOID InitButtonGroup(BTNDATA * pbData, SWCNTRL swctl, PSZ pszCmdLine)
{
    INT rc;

    if (pbData->hMte == 0
	&& (swctl.bProgType == PROG_VDM
	    || swctl.bProgType == PROG_WINDOWEDVDM))
	pbData->pszObjName = strdup("VDM");
    else if (IsWPSPid(swctl.idProcess))
	pbData->pszObjName = strdup("WPS");
    else {
	PCHAR pszModuleName = malloc(MAX_PATH + 1), pszObjName =
	    malloc(MAX_PATH + 1);

	rc = DosQueryModuleName(pbData->hMte, MAX_PATH, pszModuleName);
        if (rc) {
            pbData->usObjHandle = 0xFFFF;
        }
	else {				//no errors
	    USHORT k;
	    UCHAR fname[_MAX_FNAME];

            if ((pbData->usObjHandle = ObjIDFromName(pszModuleName, pszCmdLine,
                                                     swctl.bProgType, TRUE)) == 0 ||
                !GetObjectTitle(pbData->usObjHandle, pszObjName, MAX_PATH)) {	//could not get object ID or title -- use filename
		_splitpath(pszModuleName, NULL, NULL, fname, NULL);
		strupr(fname);
		strlwr(&fname[1]);
                pbData->pszObjName = strdup(fname);
	    }
	    else {
                for (k = 0; pszModuleName[k] != '\0'; k++) {      //get rid of tildas in object title
                    if (pszModuleName[k] == '~') {
                        memmove(&pszObjName[k], &pszObjName[k + 1], strlen(&pszObjName[k + 1]) + 1);
                    }
                }
                pbData->pszObjName = strdup(pszObjName);
		pbData->hObjIcon =
		    GetObjectIcon(pbData->usObjHandle | 0x10000, NULL);
	    }
        }

	free(pszModuleName);
	free(pszObjName);
    }
}

VOID CreateTaskbarItem(LSWDATA * plswData, HWND hwndBtnGroup,
		       BTNDATA * pbDataGroup, HSWITCH hswItem,
		       SWCNTRL swctlItem, SWP swpItem)
{
  if (hwndBtnGroup && pbDataGroup->usObjHandle != 0xFFFF) {	//0xFFFF errors in getting object title

#if 0
//#ifdef XWORKPLACE
      if (plswData->Settings.bIconsOnlyInTskBar)
	bIconOnly =
	    !IsInSkipList(&plswData->Settings.ListIconsOnly,
                          pbDataGroup->pszObjName);
      else
	bIconOnly =
	    IsInSkipList(&plswData->Settings.ListIconsOnly,
			 pbDataGroup->pszObjName);
//#endif
#endif
	if (MenuItemCount(pbDataGroup->hwndSubWinMenu) == 0) {
	    InsertMenuItem(pbDataGroup->hwndSubWinMenu, NULLHANDLE, MIT_END,
			   WinQueryWindowUShort(hwndBtnGroup, QWS_ID), "",
			   MIS_OWNERDRAW, 0, pbDataGroup->hIcon);
	    if (IsWPSPid(swctlItem.idProcess)) {
		HLIB hlib;

		if ((hlib =
		     WinLoadLibrary(plswData->hab,
				    "PMWP.DLL")) != NULLHANDLE) {
		    pbDataGroup->hIcon =
			WinLoadPointer(HWND_DESKTOP, hlib, 26);
		    WinDeleteLibrary(plswData->hab, hlib);
		}
	    }
	    else if (pbDataGroup->hObjIcon != 0)
		pbDataGroup->hIcon = pbDataGroup->hObjIcon;
	}
	InsertMenuItem(pbDataGroup->hwndSubWinMenu, NULLHANDLE, MIT_END,
		       hswItem & 0xFFFF, "", MIS_OWNERDRAW, 0,
                       GetWndIcon(swctlItem.hwnd));
        WinPostMsg(plswData->hwndTaskBarClient, WM_SIZE, 0, 0);
    }
    else {
	BTNDATA *pbData1;
	ENTRYNAME Title;
	HWND hwndBtn;

	hwndBtn = WinCreateWindow(plswData->hwndTaskBarClient, WC_BUTTON, "",
				  WS_VISIBLE | BS_USERBUTTON |
				  BS_NOPOINTERFOCUS, 0, 0, 0, 0,
				  plswData->hwndTaskBarClient,
				  IsDesktop(swctlItem.
					    hwnd) ? HWND_TOP : HWND_BOTTOM,
				  hswItem & 0xFFFF, NULL, NULL);
        if (hwndBtn == NULLHANDLE)
            return;
	if ((pbData1 = calloc(1, sizeof(BTNDATA))) != NULL) {
	    GetItemTitle(hswItem, Title, sizeof(Title), FALSE);
//#ifdef XWORKPLACE
           // if (plswData->Settings.bIconsOnlyInTskBar)
              pbData1->bIconOnly = plswData->Settings.bIconsOnlyInTskBar;
           /*  !IsInSkipList(&plswData->Settings.ListIconsOnly, Title);
            else
              pbData1->bIconOnly =
             IsInSkipList(&plswData->Settings.ListIconsOnly, Title);
//#endif     */
	    pbData1->hIcon = GetWndIcon(swctlItem.hwnd);
	    pbData1->flItemWnd = swpItem.fl;
	    pbData1->hwndFirstItem = swctlItem.hwnd;
	    pbData1->hwndSubWinMenu = WinCreateMenu(HWND_DESKTOP, NULL);
	    WinSetWindowPtr(pbData1->hwndSubWinMenu, 0,
			    (VOID *) WinSubclassWindow(pbData1->
						       hwndSubWinMenu,
						       ButtonMenuWndProc));
	    WinSetOwner(pbData1->hwndSubWinMenu, hwndBtn);
	    pbData1->hMte = HmteFromPID(swctlItem.idProcess);
	    WinSetWindowPtr(hwndBtn, 0, (VOID *) pbData1);
	    pbData1->pOldWndProc = WinSubclassWindow(hwndBtn, ButtonWndProc);
	    /*WinSetPresParam(hwndBtn, PP_FONTNAMESIZE,
			    strlen(plswData->Settings.ucButtonFont) + 1,
			    plswData->Settings.ucButtonFont);*/
	    WinPostMsg(plswData->hwndTaskBarClient, WM_SIZE, 0, 0);
	}
	else
	    WinDestroyWindow(hwndBtn);
    }
}

MRESULT EXPENTRY TaskBarWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
    LSWDATA *plswData;
    static USHORT usMinBtnWid, usBorderWid, usHswActive = 0;
    static LONG cyScreen;
    static HWND hwndMouseOver = 0;
    static HWND groupmenuhwnd = 0;
    static ATOM atomGetProcCmd;
    MRESULT mrc = 0;

    if (msg != WM_CREATE)
#ifdef XWORKPLACE
	plswData = ((PXCENTERWIDGET) WinQueryWindowPtr(hwnd, 0))->pUser;
#else
	plswData = WinQueryWindowPtr(hwnd, 0);
#endif

    switch (msg) {
    case LSWM_QUERYACTIVEBTNID:{
	    mrc = (MPARAM) usHswActive;
	    break;
	}

    case LSWM_WNDSTATECHANGED:{
	    HWND hwndFound;
	    BTNDATA *pbtnData;

	    if (WinIsWindow(plswData->hab, HWNDFROMMP(mp2)) &&
		(hwndFound =
		 GetBtnFromHsw(hwnd, SHORT1FROMMP(mp1))) != NULLHANDLE) {
		if (IsWindowClass(hwndFound, "#3")
		    && (pbtnData = WinQueryWindowPtr(hwndFound, 0)) != NULL
		    && UpdateWinFlags(&pbtnData->flItemWnd,
				      SHORT2FROMMP(mp1)))
		    WinInvalidateRect(hwndFound, NULL, FALSE);
		else if (!IsWindowClass(hwndFound, "#3"))
		    WinInvalidateRect(WinQueryWindow(hwndFound, QW_OWNER),
				      NULL, TRUE);
		if (IsWindowClass(WinWindowFromID(HWNDFROMMP(mp2), FID_CLIENT), "SeamlessClass"))	//dynamic WIn-OS2 icon handles change
		    WinPostMsg(hwnd, LSWM_WNDICONCHANGED, NULL, mp2);
	    }
	    break;
	}

    case LSWM_WNDICONCHANGED:{
	    RECTL rcl;
	    BTNDATA *pbtnData;
	    HWND hwndFound, hwndBtn;
	    USHORT usHsw = WinQuerySwitchHandle(HWNDFROMMP(mp2), 0);
	    BOOL bTaskMenu = WinIsWindowVisible(plswData->hwndTaskMenu);

	    if ((hwndFound = GetBtnFromHsw(hwnd, usHsw)) == NULLHANDLE)
	        break;
	    hwndBtn =
		IsWindowClass(hwndFound,
			      "#3") ? hwndFound : WinQueryWindow(hwndFound,
								 QW_OWNER);

	    if ((hwndFound == hwndBtn
	         || WinQueryWindowUShort(hwndBtn, QWS_ID) == usHsw)
	        && (pbtnData = WinQueryWindowPtr(hwndBtn, 0)) != NULL) {
		if (IsWindowClass(WinWindowFromID(HWNDFROMMP(mp2), FID_CLIENT), "SeamlessClass")) {	//dynamic WIn-OS2 icon handles change
		    DosSleep(20);	//there is some delay in icon change
		    pbtnData->hIcon = GetWndIcon(HWNDFROMMP(mp2));
		}
		else {
		    WinSendMsg(HWNDFROMMP(mp2), WM_NULL, 0, 0);	//make sure the icon handle has become valid
		    pbtnData->hIcon = LONGFROMMP(mp1);
		}
		WinQueryWindowRect(hwndBtn, &rcl);
		rcl.xRight = usMinBtnWid;
		WinInvalidateRect(hwndBtn, &rcl, FALSE);
	    }
	    if (bTaskMenu || hwndFound != hwndBtn) {
		WinSendMsg(bTaskMenu ? plswData->hwndTaskMenu : hwndFound,
			   MM_SETITEMHANDLE, MPFROM2SHORT(usHsw, FALSE), mp1);
		WinSendMsg(bTaskMenu ? plswData->hwndTaskMenu : hwndFound,
			   MM_QUERYITEMRECT, MPFROM2SHORT(usHsw, FALSE),
			   MPFROMP(&rcl));
		WinInvalidateRect(bTaskMenu ? plswData->
				  hwndTaskMenu : hwndFound, &rcl, FALSE);
	    }

	    break;
	}

    case LSWM_SWITCHLISTCHANGED:{
	    ULONG ulFunc;
	    HSWITCH hsw;
	    BOOL bHiddenItem;
	    SWCNTRL swctl;
	    SWP swp;
            HWND hwndFound = 0;
            /*PSWBLOCK pSwb;
            ULONG ulItemCount;
            INT k;*/

//0x1 or 0x10001 -- create switch entry, 0x2 -- modify, 0x3 -- delete
//these are sent by task manager to the switch list and intercepted by our hook
//0x4 means the "second loop" of processing after checking the object name

	    ulFunc = LONGFROMMP(mp1);
            hsw = LONGFROMMP(mp2);

	    if (hsw == 0
		|| (ulFunc != 3
		    && (WinQuerySwitchEntry(hsw, &swctl) != 0
			|| !WinIsWindow(plswData->hab, swctl.hwnd)
			|| !WinQueryWindowPos(swctl.hwnd, &swp))))
		break;

	    UpdateTaskMenu(plswData, hsw, swctl, ulFunc);

	    if (ulFunc != 0x3)
		bHiddenItem = (swctl.uchVisibility != SWL_VISIBLE ||
			       (!plswData->Settings.bShowHiddenTskBar
				&& (swp.fl & SWP_HIDE))
			       || (!plswData->Settings.bShowViewerTskBar
				   && IsMinToViewer(swctl.hwnd, swp.fl))
			       || IsInSkipList(&plswData->Settings.
					       SkipListTskBar,
					       swctl.szSwtitle));

            if ((hwndFound = GetBtnFromHsw(hwnd, hsw)) != 0) {
		if (ulFunc == 0x2 && !bHiddenItem)	// item text has changed
		    UpdateTaskbarItem(plswData, usMinBtnWid, hsw, hwndFound);
                else if ((ulFunc == 0x2 && bHiddenItem) || ulFunc == 0x3) {	//item became hidden or has been deleted
                    RemoveTaskbarItem(plswData, hsw, hwndFound);
                    WinInvalidateRect(hwnd, NULL, TRUE);
                }
            }
	    else {
		if (ulFunc != 0x3 && !bHiddenItem) {	//an item became visible or a new item has been added
		    BTNDATA *pbData;
		    HWND hwndBtnSameHmte = 0;

		    if (plswData->Settings.bGroupItems
			&& (hwndBtnSameHmte =
                            GetBtnFromHmte(hwnd, swctl)) != 0) {
                        pbData = WinQueryWindowPtr(hwndBtnSameHmte, 0);
                    }

// 0xFFFF means errors in getting object title, don't make further attempts
		    if (hwndBtnSameHmte != 0 && pbData->pszObjName == NULL
                        && pbData->usObjHandle != 0xFFFF) {
			if (ulFunc != 4 && swctl.bProgType == PROG_PM
                            && !IsWPSPid(swctl.idProcess)) {
                            // This must be a Post
                            WinPostMsg(pbData->hwndFirstItem, atomGetProcCmd,
                                       0, mp2);
                            WinInvalidateRect(hwnd, NULL, TRUE);
			    break;
			}
			InitButtonGroup(pbData, swctl, plswData->buf);

			//extract first number from WP_OBJHANDLE env var, this may be the datafile objectID
			//      for (k=0;pbData->usDataHandles[k]!=0 && k<128;k++);
			//      if (k<128) pbData->usDataHandles[k]=strtoul(plswData->buf,NULL,10)&0xFFFF;

		    }
                    CreateTaskbarItem(plswData, hwndBtnSameHmte, pbData, hsw,
				      swctl, swp);
		}
            }
            /*pSwb = GetSwitchList(plswData->hab, TRUE, &ulItemCount);
            for (k = 0; k < min(MAXITEMS, ulItemCount) - 1; k++) {
                //if (pSwb->aswentry[k].swctl.bProgType != PROG_WINDOWABLEVIO){
                    PmpfF(("hwnd %i hwndIcon %i hprog %i PID %i Title %s",
                           pSwb->aswentry[k].swctl.hwnd,
                           pSwb->aswentry[k].swctl.hwndIcon,
                           pSwb->aswentry[k].swctl.hprog,
                           pSwb->aswentry[k].swctl.idProcess,
                           pSwb->aswentry[k].swctl.szSwtitle));
                  //  continue;
                //}
                if (!WinIsWindow(plswData->hab, pSwb->aswentry[k].swctl.hwnd)) { //!WinHAPPfromPID(pSwb->aswentry[k].swctl.idProcess)) {
                    WinRemoveSwitchEntry(pSwb->aswentry[k].hswitch);
                    DebugHereIAm();
                }
            }
            GetSwitchList(0, FALSE, NULL);*/
	    break;
	}

    case WM_SIZE: {    //2.70
      USHORT usButtons,usDskBtnHgt,k,usBtn1,usScrWid,usBtnWid,usBtnRows,usBtnHgt,
             usBtnPerRow,usRowWid,usBigBtnPerRow,usMinBtnHgt,usMaxBtnWid,usEdgeGap;
      HENUM henum;
      HWND hwndNext,hwndTop;
      RECTL rcl;
      BOOL bIsDesktop;
      SWP *aswp;
  
      henum = WinBeginEnumWindows(hwnd); usButtons = hwndTop = 0;
      while ((hwndNext=WinGetNextWindow(henum))!=NULLHANDLE) {
        if (IsWindowClass(hwndNext,"#3")) {
          usButtons++;
          if (hwndTop==0) hwndTop=hwndNext;
        }
      }
      WinEndEnumWindows(henum);
  
      if (usButtons==0) break;
  
      bIsDesktop = IsDesktopBtn(hwndTop);
      usBorderWid = BUTTONBORDERWIDTH;
#ifdef XWORKPLACE
      usBorderWid=((plswData->pWidget->pGlobals->flDisplayStyle & XCS_FLATBUTTONS)?1:2);// didn't find any constants for this
      // calc the minimum and maximum allowed button sizes
      if (plswData->pWidget->pGlobals && plswData->pWidget->pGlobals->flDisplayStyle & XCS_LARGEICONS) {
          usMinBtnWid = usMaxBtnWid = plswData->pWidget->pGlobals->cxMiniIcon +2*usBorderWid+2 ;
          usMaxBtnWid += plswData->Settings.usMaxBtnWid;
      }
      else {
          usMinBtnWid = WinQuerySysValue(HWND_DESKTOP,SV_CXICON)/2+2*usBorderWid+2;
          usMaxBtnWid = plswData->Settings.usMaxBtnWid;
      }
#else
      usMinBtnWid = WinQuerySysValue(HWND_DESKTOP,SV_CXICON) / (plswData->Settings.bLargeIcons ? 1 : 2)
          +2*usBorderWid+2;
      usMaxBtnWid = plswData->Settings.usMaxBtnWid;
#endif
  
#ifndef XWORKPLACE
      if (plswData->Settings.bTskBarGrow && plswData->Settings.bIconsOnlyInTskBar)
        WinSetWindowPos(plswData->hwndTaskBar,0,0,0,usMinBtnWid*usButtons+2*TSKBARFRAMEWIDTH,plswData->Settings.sTskBarCY,SWP_SIZE);
#endif
  
      WinQueryWindowRect(hwnd,&rcl); // may not be WM_SIZE, can't use mp2 to get size
  
      usEdgeGap = plswData->Settings.b3DTaskBar?min(cyScreen/100,rcl.yTop/6)/2:0; //half the gradient border width
  
#ifdef XWORKPLACE
      usMinBtnHgt = usMinBtnWid+((plswData->pWidget->pGlobals->flDisplayStyle & XCS_FLATBUTTONS)?2:0);
#else
      usMinBtnHgt = usMinBtnWid;
#endif
  
      usBtnHgt = (rcl.yTop-2*usEdgeGap)/max(rcl.yTop/usMinBtnHgt,1);
  
      usDskBtnHgt = rcl.yTop-2*usEdgeGap;
  
      usBtnRows = max(1,rcl.yTop/max(usBtnHgt,1));
      usRowWid = rcl.xRight-bIsDesktop*usMinBtnWid;
      usScrWid = usRowWid*usBtnRows;
      usBtn1 = usButtons-bIsDesktop;
  
  // excluding the desktop button
      if (plswData->Settings.bIconsOnlyInTskBar)
        usBtnPerRow = usRowWid/usMinBtnWid;
      else if ((usBigBtnPerRow = usRowWid/usMaxBtnWid)*usBtnRows>=usBtn1)
        usBtnPerRow = usBigBtnPerRow;
      else
        usBtnPerRow = min(max(usRowWid/usMinBtnWid,1),usBtn1/usBtnRows+(usBtn1%usBtnRows>0));
  
      usBtnWid = (usBtnPerRow==0) ? usMaxBtnWid :
                 plswData->Settings.bIconsOnlyInTskBar ? usMinBtnWid :
                 max(usRowWid/usBtnPerRow,usMinBtnWid);
  
      if ((aswp=malloc(sizeof(SWP)*usButtons))==NULL) break;
      henum=WinBeginEnumWindows(hwnd); k=0;
      while ((hwndNext=WinGetNextWindow(henum))!=NULLHANDLE) {
        if (!IsWindowClass(hwndNext,"#3")) continue;
  
        if (k==0 && bIsDesktop) { //desktop button
          aswp[k].x = 0; aswp[k].y = usEdgeGap;
          aswp[k].cx = usMinBtnWid; aswp[k].cy = usDskBtnHgt;
        } else {
          USHORT kc, usRow, usCol;
  
          kc = k-((k>0 && bIsDesktop)?1:0); //button number not counting desktop btn
          usRow = kc/usBtnPerRow; usCol = kc%usBtnPerRow; //not counting desktop btn
  
          aswp[k].x = usCol*usBtnWid+bIsDesktop*usMinBtnWid;
          aswp[k].cx = (usCol==usBtnPerRow-1 && usBtnWid!=usMinBtnWid) ? //last btn in a row
                        usRowWid-usBtnWid*(usBtnPerRow-1) : usBtnWid;
          aswp[k].y = usRow*usBtnHgt+usEdgeGap;
          aswp[k].cy = usBtnHgt;
        }
#ifdef XWORKPLACE
        if (plswData->pWidget->pGlobals->flDisplayStyle & XCS_FLATBUTTONS &&
            !plswData->Settings.b3DTaskBar) {
          aswp[k].y += 1; aswp[k].cy-=2;
        }
#endif
        aswp[k].hwnd = hwndNext;
        aswp[k].fl = SWP_SIZE | SWP_MOVE;
        k++;
      }
      WinEndEnumWindows(henum);
      WinSetMultWindowPos(plswData->hab,aswp,usButtons);
      free(aswp);
  
      break;
    }

    case WM_CREATE:{
#ifdef XWORKPLACE
	    VOID *pData;
	    PXCENTERWIDGET pWidget;
            LONG lrc;

            if (queryAppInstance()) {
                return (VOID *) 1;
    }
#endif
	    if (DosGetNamedSharedMem
		((PVOID *) & plswData, SHAREMEM_NAME,
		 PAG_READ | PAG_WRITE) != 0 || plswData == NULL) {
		mrc = (MRESULT) TRUE;
		break;
	    }
#ifndef XWORKPLACE
	    WinSetWindowPtr(hwnd, 0, plswData);
            plswData->hwndTaskBarClient = hwnd;
#else
	    pWidget = (PXCENTERWIDGET) mp1;
	    if (pWidget == NULL || pWidget->pfnwpDefWidgetProc == NULL) {
		mrc = (MRESULT) TRUE;
		break;
            }
            if (WgtQueryXWPWidgetBasePath (szHelpFile)) {
                CHAR cHelpFName[CCHMAXPATH];

                if (plswData->Settings.usLanguage == ES)
                    strcpy(cHelpFName, "\\lswitch_es.hlp");
                else
                    strcpy(cHelpFName, "\\lswitch.hlp");
                strcat(szHelpFile, cHelpFName);
                pWidget->pcszHelpLibrary = szHelpFile;
                pWidget->ulHelpPanelID   = 30004;
            }
	    pWidget->pUser = plswData;
	    plswData->pWidget = pWidget;
            plswData->hwndTaskBarClient = hwnd;

	    pData = (PVOID) plswData;
	    lrc = SwitcherInit(plswData->hab, 0, NULL, 0, &pData, 2);
	    if (lrc > 0) {
                if (pData != NULL)
		    SwitcherTerm(plswData, 1);
		mrc = (MRESULT) TRUE;
		break;
	    }
	    else if (lrc == LSWERROLDSETTINGS) {
	    }

	    WinSetWindowPtr(hwnd, 0, pWidget);
#endif

	    plswData->hwndTaskMenu = WinCreateMenu(HWND_DESKTOP, NULL);
	    WinSetWindowPtr(plswData->hwndTaskMenu, 0,
			    (VOID *) WinSubclassWindow(plswData->hwndTaskMenu,
						       ButtonMenuWndProc));

	    atomGetProcCmd =
		WinAddAtom(WinQuerySystemAtomTable(), LSWM_GETPROCCMD);

            DosFreeMem(plswData);
            WinPostMsg(hwnd, LSWM_INITBUTTONS, 0, 0);

#ifndef XWORKPLACE
            WinStartTimer(plswData->hab, hwnd, TSKHIDEDELAYTIMERID,
                          plswData->Settings.usAutoHideDelay * 1000);
#else
            pkrnSendDaemonMsg(XDM_ADDWINLISTWATCH,MPFROMHWND(hwnd),
                              MPFROMLONG(LSWM_ACTIVEWNDCHANGED));
#endif
	}

    case WM_SYSVALUECHANGED:
	cyScreen = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
	break;

    case LSWM_INITBUTTONS:{
	    ULONG ulItemCount;
	    LONG k;
	    PSWBLOCK pSwb;

	    if ((pSwb =
                 GetSwitchList(plswData->hab, TRUE, &ulItemCount)) == NULL)
                break;

	    for (k = 0; k < min(MAXITEMS, ulItemCount) - 1; k++)
		WinSendMsg(hwnd, LSWM_SWITCHLISTCHANGED, MPFROMLONG(3),
			   MPFROMLONG(pSwb->aswentry[k].hswitch));

            for (k = min(MAXITEMS, ulItemCount) - 1; k >= 0; k--) {
                //PmpfF(("Title %s", pSwb->aswentry[k].swctl.szSwtitle));
		WinSendMsg(hwnd, LSWM_SWITCHLISTCHANGED,
			   MPFROMLONG(IsInSkipList
				      (&plswData->Settings.SkipListTskBar,
				       pSwb->aswentry[k].swctl.szSwtitle) ? 2 : 1),
			   MPFROMLONG(pSwb->aswentry[k].hswitch));
            }
	    GetSwitchList(0, FALSE, NULL);
	    WinSendMsg(hwnd, LSWM_ACTIVEWNDCHANGED,
		       MPFROMHWND(WinQueryActiveWindow(HWND_DESKTOP)),
		       MPFROMLONG(WM_ACTIVATE));
	    break;
	}

    case WM_DESTROY:
	WinDeleteAtom(WinQuerySystemAtomTable(), atomGetProcCmd);
        WinDestroyWindow(plswData->hwndTaskMenu);
#ifdef XWORKPLACE
        pkrnSendDaemonMsg(XDM_REMOVEWINLISTWATCH,(MPARAM)hwnd,NULL);
        SwitcherTerm(plswData, 1);
        mrc = plswData->pWidget->pfnwpDefWidgetProc(hwnd, msg, mp1, mp2);
#endif
        break;


    case WM_PRESPARAMCHANGED:{
	    LONG lParam, lValue;
	    UCHAR ucBuf[4];

	    lParam = LONGFROMMP(mp1);

	    if (lParam == PP_BACKGROUNDCOLOR &&
		WinQueryPresParam(hwnd, lParam, 0, NULL, sizeof(ucBuf), ucBuf,
				  QPF_NOINHERIT) != 0) {
		lValue = ucBuf[0] + ucBuf[1] * 256 + ucBuf[2] * 65536;
		if (plswData->Settings.b3DTaskBar)
		    plswData->Settings.lTskBarRGBCol3D = lValue;
		else
		    plswData->Settings.lTskBarRGBCol = lValue;

		WinInvalidateRect(hwnd, NULL, FALSE);
	    }
	    break;
	}

    case WM_PAINT:{
	    HPS hps;
	    RECTL rcl, rcl1;

	    hps = WinBeginPaint(hwnd, NULLHANDLE, &rcl);
	    WinQueryWindowRect(hwnd, &rcl);
	    GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL);

	    if (plswData->Settings.b3DTaskBar) {
		SWP swp;
		HWND hwndBottom;
		USHORT usEdgeWid;

		if ((hwndBottom =
		     WinQueryWindow(hwnd, QW_BOTTOM)) != NULLHANDLE)
		    WinQueryWindowPos(hwndBottom, &swp);
		else
		    swp.x = swp.cx = 0;

		rcl1.xLeft =
		    (swp.y + swp.cy == rcl.yTop ? swp.x + swp.cx : 0);
		rcl1.xRight = rcl.xRight;
		usEdgeWid = min(cyScreen / 100, rcl.yTop / 6);
		rcl1.yBottom = rcl.yBottom;
		rcl1.yTop = rcl.yTop - usEdgeWid;
		FillRectGradient(hps, &rcl1, NULL,
				 plswData->Settings.lTskBarRGBCol3D,
				 RGB_WHITE, TRUE);

		rcl1.yBottom = rcl1.yTop;
		rcl1.yTop = rcl.yTop;
		FillRectGradient(hps, &rcl1, NULL,
				 plswData->Settings.lTskBarRGBCol3D,
				 240 * 65536 + 240 * 256 + 240, FALSE);
	    }
	    else
		WinFillRect(hps, &rcl, plswData->Settings.lTskBarRGBCol);

#ifndef XWORKPLACE
	    if (!plswData->Settings.b3DTaskBar)
		WinDrawBorder(hps, &rcl, 0, TSKBARFRAMEWIDTH,
			      SUNKENFRAMERGBCOL, RAISEDFRAMERGBCOL,
			      DB_RAISED);
#endif

	    WinEndPaint(hps);
	    break;
	}

    case LSWM_MOUSEOVERBTN:{
	    BTNDATA *pbtnData;
            HWND hwndOldOver;

	    hwndOldOver = hwndMouseOver;
            hwndMouseOver = HWNDFROMMP(mp1);

#ifdef XWORKPLACE
	    if (plswData->pWidget->pGlobals->flDisplayStyle & XCS_FLATBUTTONS) {
#else
	    if (plswData->Settings.bFlatButtons) {
#endif
		USHORT k;
		HWND hwndBtn, hwndActive;

		for (k = 0, hwndBtn = hwndOldOver; k < 2;
		     k++, hwndBtn = hwndMouseOver)
		    if (hwndBtn != 0
			&& (hwndActive =
			    GetBtnFromHsw(hwnd, usHswActive),
			    (IsWindowClass(hwndActive, "#3") ? hwndActive !=
			     hwndBtn : WinQueryWindow(hwndActive,
						      QW_OWNER) != hwndBtn)))
			WinInvalidateRect(hwndBtn, NULL, FALSE);
	    }

	    if (hwndMouseOver != 0 && !WinIsWindowVisible(plswData->hwndMenu)
		&& !WinIsWindowVisible(plswData->hwndTaskMenu)
		&& WinIsWindowShowing(hwndMouseOver)
		&& (pbtnData = WinQueryWindowPtr(hwndMouseOver, 0)) != NULL
		&& !WinIsWindowVisible(pbtnData->hwndSubWinMenu)) {
		WinStartTimer(plswData->hab, hwnd, TSKBARBUBBLETIMERID,
                              BUBBLETIMERINTERVAL);
	    }
	    else if (!(WinGetKeyState(HWND_DESKTOP, VK_SHIFT) & 0x8000)) {
		WinStopTimer(plswData->hab, hwnd, TSKBARBUBBLETIMERID);
		ShowBubble(plswData, 0, 0, 0, -2, NULL); //should be after WinStopTimer
            }
#ifndef XWORKPLACE
            if ((pbtnData = WinQueryWindowPtr(hwndMouseOver, 0)) != NULL &&
                    pbtnData->hwndSubWinMenu != 0)
                    groupmenuhwnd = pbtnData->hwndSubWinMenu;
            WinStartTimer(plswData->hab, hwnd, TSKHIDEDELAYTIMERID,
                          plswData->Settings.usAutoHideDelay * 1000);
#endif
	    break;
	}
    case WM_CONTROL:
#ifdef XWORKPLACE
	if (SHORT1FROMMP(mp1) == ID_XCENTER_CLIENT) {
	    if (SHORT2FROMMP(mp1) == XN_QUERYSIZE) {	//XCenter wants to know our size.
		PSIZEL pszl;

		pszl = (PSIZEL) mp2;
		pszl->cx = -1;		// desired width
// desired minimum height, 2 pixels more than the min button hgt, used for the dynamic border
		pszl->cy =
		    WinQuerySysValue(HWND_DESKTOP,
				     SV_CYICON) / 2 + 2 * BUTTONBORDERWIDTH +
		    2 + 2;
		mrc = (MRESULT) TRUE;
	    }
	}
	else
#endif
	{
	    USHORT hsw;

	    hsw = SHORT1FROMMP(mp1);

	    switch (SHORT2FROMMP(mp1)) {
	    case BN_PAINT:{
		    USERBUTTON *pubButton = (USERBUTTON *) mp2;
		    RECTL rcl;
		    BOOL bHilite, bAllHidden, bLargeIcons = FALSE;
		    BTNDATA *pbtnData;
		    LONG lBgndCol, lTextCol;
		    USHORT usRclHgt;
		    HWND hwndBtnActive, hwndSubWinMenu;
		    USHORT usMenuItems = MenuItemCount(hwndSubWinMenu);

		    if (pubButton == NULL
			|| !WinIsWindow(plswData->hab, pubButton->hwnd)
			|| (pbtnData =
			    WinQueryWindowPtr(pubButton->hwnd, 0)) == NULL)
			break;

                    hwndSubWinMenu = ((BTNDATA *) WinQueryWindowPtr(pubButton->hwnd, 0))->
			hwndSubWinMenu;
		    WinQueryWindowRect(pubButton->hwnd, &rcl);
		    usRclHgt = rcl.yTop;

		    GpiCreateLogColorTable(pubButton->hps, 0, LCOLF_RGB, 0, 0,
					   NULL);

		    hwndBtnActive = GetBtnFromHsw(hwnd, usHswActive);

		    if (usMenuItems > 0) {
			SHORT sId, k;
			SWCNTRL swctl;
			SWP swp;

			for (k = 0, bAllHidden = TRUE; k < usMenuItems; k++) {
			    sId =
				SHORT1FROMMR(WinSendMsg
					     (hwndSubWinMenu,
					      MM_ITEMIDFROMPOSITION,
					      MPFROMSHORT(k), 0));
			    WinQuerySwitchEntry(sId, &swctl);
			    WinQueryWindowPos(swctl.hwnd, &swp);
			    if (!(swp.fl & (SWP_HIDE | SWP_MINIMIZE))) {
				bAllHidden = FALSE;
				break;
			    }
			}
		    }

		    bHilite =
			((LOUSHORT(pubButton->fsState) & BDS_HILITED) ==
			 BDS_HILITED || hsw == usHswActive
			 || WinQueryWindow(hwndBtnActive,
					   QW_OWNER) == pubButton->hwnd);

		    if (bHilite)
			if ((usMenuItems > 0 && bAllHidden)
			    || (usMenuItems == 0
				&& pbtnData->
				flItemWnd & (SWP_HIDE | SWP_MINIMIZE))) {
			    lTextCol =
				plswData->Settings.b3DTaskBar ? plswData->
				Settings.
				lActiveHiddenBtnTitleRGBCol3D : plswData->
				Settings.lActiveHiddenBtnTitleRGBCol;
			    lBgndCol =
				plswData->Settings.b3DTaskBar ? plswData->
				Settings.lActiveHiddenBtnRGBCol3D : plswData->
				Settings.lActiveHiddenBtnRGBCol;
			}
			else {
			    lTextCol =
				plswData->Settings.b3DTaskBar ? plswData->
				Settings.lActiveBtnTitleRGBCol3D : plswData->
				Settings.lActiveBtnTitleRGBCol;
			    lBgndCol =
				plswData->Settings.b3DTaskBar ? plswData->
				Settings.lActiveBtnRGBCol3D : plswData->
				Settings.lActiveBtnRGBCol;
			}
		    else if ((usMenuItems > 0 && bAllHidden)
			     || (usMenuItems == 0
				 && pbtnData->
				 flItemWnd & (SWP_HIDE | SWP_MINIMIZE))) {
			lTextCol =
			    plswData->Settings.b3DTaskBar ? plswData->
			    Settings.
			    lNormalHiddenBtnTitleRGBCol3D : plswData->
			    Settings.lNormalHiddenBtnTitleRGBCol;
			lBgndCol =
			    plswData->Settings.b3DTaskBar ? plswData->
			    Settings.lNormalHiddenBtnRGBCol3D : plswData->
			    Settings.lNormalHiddenBtnRGBCol;
		    }
		    else {
			lTextCol =
			    plswData->Settings.b3DTaskBar ? plswData->
			    Settings.lNormalBtnTitleRGBCol3D : plswData->
			    Settings.lNormalBtnTitleRGBCol;
			lBgndCol =
			    plswData->Settings.b3DTaskBar ? plswData->
			    Settings.lNormalBtnRGBCol3D : plswData->Settings.
			    lNormalBtnRGBCol;
		    }

		    if (!plswData->Settings.b3DTaskBar)
			WinFillRect(pubButton->hps, &rcl, lBgndCol);

#ifdef XWORKPLACE
		    if (!
			(plswData->pWidget->pGlobals->
			 flDisplayStyle & XCS_FLATBUTTONS) ||
#else
		    if (!plswData->Settings.bFlatButtons ||
#endif
			bHilite || hwndMouseOver == pubButton->hwnd) {

			if (plswData->Settings.b3DTaskBar)
			    FillRectGradient(pubButton->hps, &rcl, NULL,
					     lBgndCol, RGB_WHITE, bHilite);

			WinDrawBorder(pubButton->hps, &rcl, usBorderWid,
				      usBorderWid, SUNKENFRAMERGBCOL,
				      RAISEDFRAMERGBCOL,
				      bHilite ? DB_DEPRESSED : DB_RAISED);
		    }
		    else if (plswData->Settings.b3DTaskBar) {
			RECTL rcl1, rclClient;
			SWP swp;

			WinQueryWindowPos(pubButton->hwnd, &swp);
			WinQueryWindowRect(hwnd, &rclClient);

			rcl1.xLeft = rcl.xLeft;
			rcl1.xRight = rcl.xRight;
			rcl1.yBottom = rcl.yBottom - swp.y;
			rcl1.yTop =
			    rclClient.yTop - swp.y - min(cyScreen / 100,
							 rclClient.yTop / 6);
			FillRectGradient(pubButton->hps, &rcl1, &rcl,
					 plswData->Settings.lTskBarRGBCol3D,
					 RGB_WHITE, TRUE);
			rcl1.yBottom = rcl1.yTop;
			rcl1.yTop = rclClient.yTop - swp.y;
			FillRectGradient(pubButton->hps, &rcl1, &rcl,
					 plswData->Settings.lTskBarRGBCol3D,
					 240 * 65536 + 240 * 256 + 240,
					 FALSE);
		    }

// adjust the rect for text drawing
// shifting the text and icon of a pressed button by one pixel looks better
// than shifting by button border width
		    rcl.xLeft += usMinBtnWid + bHilite + 1;
		    rcl.xRight -= usBorderWid + 2;
		    rcl.yTop -= bHilite;
		    rcl.yBottom -= bHilite;

                    {
			USHORT usMenuItems =
			    MenuItemCount(pbtnData->hwndSubWinMenu);
			USHORT usTitleLen =
			    max(usMenuItems ==
				0 ? 0 : strlen(pbtnData->pszObjName) + 5,
				sizeof(ENTRYNAME)) + 2;
			PCHAR pszTitle;

			if ((pszTitle = malloc(usTitleLen)) != NULL) {
			    pszTitle[0] = '\0';

			    if (usMenuItems > 0
				&& pbtnData->pszObjName != NULL) {
				sprintf(pszTitle, "%i - ", usMenuItems);
				strncat(pszTitle, pbtnData->pszObjName,
					usTitleLen - strlen(pszTitle));
			    }
			    else
				GetItemTitle(hsw, &pszTitle[strlen(pszTitle)],
					     usTitleLen - strlen(pszTitle),
					     FALSE);
			    MakeFitStr(pubButton->hps, pszTitle, usTitleLen,
				       rcl.xRight - rcl.xLeft + bHilite - 1);
			    WinDrawText(pubButton->hps, strlen(pszTitle),
					pszTitle, &rcl, lTextCol, lBgndCol,
					DT_VCENTER);
			    free(pszTitle);
			}
		    }
                    // Get the icons for the taskbar buttons
#ifdef XWORKPLACE
                    bLargeIcons = plswData->pWidget->pGlobals &&
                                   plswData->pWidget->pGlobals->flDisplayStyle & XCS_LARGEICONS;
#else
                    bLargeIcons = plswData->Settings.bLargeIcons;
#endif
                    WinDrawPointer(pubButton->hps, usBorderWid + bHilite + 1,
				   (usRclHgt - usMinBtnWid) / 2 +
				   usBorderWid - bHilite + 1,
				   ((BTNDATA *)
				    WinQueryWindowPtr(pubButton->hwnd,
                                                      0))->hIcon,
                                    bLargeIcons ? 0 : DP_MINIICON
				   /*|((pbtnData->flItemWnd&(SWP_HIDE|SWP_MINIMIZE))?DP_HALFTONED:0) */
				   );
		    break;
		}
#ifdef XWORKPLACE
	    default:
		mrc =
		    plswData->pWidget->pfnwpDefWidgetProc(hwnd, msg, mp1,
							  mp2);
#endif
	    }
	}
	break;

    case WM_ERASEBACKGROUND:
	mrc = (MRESULT) TRUE;
	break;

    case WM_CONTEXTMENU:
	if (!plswData->bNowActive) {
	    ShowBubble(plswData, 0, 0, 0, -2, NULL);
	    ShowMenu(plswData, -1, TRUE, FALSE, FALSE);
	}
	break;

    case WM_COMMAND:
	if (SHORT1FROMMP(mp1) == CMD_SUSPEND) {
	    ProcessAPMOffRequest(POWERSTATE_SUSPEND, DEVID_ALL_DEVICES);
	}
	else if (SHORT1FROMMP(mp1) == CMD_ADDFILTER ||
		 (SHORT1FROMMP(mp1) >= CMD_FIRST
		  && SHORT1FROMMP(mp1) <= CMD_LAST)) {
	    ProcessCommand(SHORT1FROMMP(mp1), SHORT1FROMMP(mp2), plswData,
			   TRUE,
			   !IsWindowClass(GetBtnFromHsw
					  (hwnd,
					   plswData->TaskArr[plswData->
							     iMenuAtItem].
					   hsw), "#3"));
	}
#ifdef XWORKPLACE
	else
	    mrc = plswData->pWidget->pfnwpDefWidgetProc(hwnd, msg, mp1, mp2);
#endif

	break;

    case LSWM_ACTIVEWNDCHANGED:
//#ifndef XWORKPLACE
//need a small delay as sometimes a window does not become active immediately after a WM_ACTIVATE
	WinStartTimer(plswData->hab, hwnd, TSKBARUPDATETIMERID,
		      TSKBARUPDATEINTERVAL);
	break;
//#endif
    case WM_TIMER:{
//#ifdef XWORKPLACE
//    if (msg==LSWM_ACTIVEWNDCHANGED /*&& (ULONG)mp2==WM_ACTIVATE*/) {
//#else
#if 0
        // Attempt to identify and remove phantom windows start the timer in create code
        if (SHORT1FROMMP(mp1) == TSKPHATOMWINCHKTIMERID) {
            int k;
            for (k = 0; k < plswData->usItems; k++)  {
                //DebugHereIAm();
                if ((plswData->TaskArr[k].hwnd  != 0) &&
                    (pbtnData = WinQueryWindowPtr(plswData->TaskArr[k].hwnd , 0)) != 0) {
                    //DebugHereIAm();
                    if (!WinIsWindow(plswData->hab, pbtnData->hwndFirstItem)) { //&&
                        //!WinIsWindowVisible(plswData->hwndMenu) &&
                        //!WinIsWindowVisible(plswData->hwndTaskMenu)&&
                        //!WinIsWindowVisible(groupmenuhwnd)) {
                       
                       pbtnData->hIcon));
                        //DebugHereIAm();  //try WinSendMsg LSWM_SWITCHLISTCHANGED
                        //WinSendMsg(hwnd, LSWM_SWITCHLISTCHANGED,
                        //           MPFROMLONG(3),
                        //           MPFROMLONG(plswData->TaskArr[k].hsw));
                        break;
                    }
                }
            }
            break;
        }
#endif
	    if (SHORT1FROMMP(mp1) == TSKBARUPDATETIMERID) {
//#endif
		USHORT usOldActive;
		HWND hwndActive;

//#ifndef XWORKPLACE
		WinStopTimer(plswData->hab, hwnd, TSKBARUPDATETIMERID);
//#endif

		usOldActive = usHswActive;
		hwndActive = WinQueryActiveWindow(HWND_DESKTOP);
                usHswActive = WinQuerySwitchHandle(hwndActive, 0) & 0xFFFF;
                if (usHswActive != usOldActive) {
		    HWND hwndHsw = GetBtnFromHsw(hwnd, usOldActive);
		    WinInvalidateRect(IsWindowClass(hwndHsw, "#3") ? hwndHsw :
				      WinQueryWindow(hwndHsw, QW_OWNER), NULL,
				      FALSE);
		    hwndHsw = GetBtnFromHsw(hwnd, usHswActive);
		    WinInvalidateRect(IsWindowClass(hwndHsw, "#3") ? hwndHsw :
				      WinQueryWindow(hwndHsw, QW_OWNER), NULL,
				      FALSE);
		}
		break;
            }
#ifndef XWORKPLACE
            if (SHORT1FROMMP(mp1) == TSKHIDEDELAYTIMERID) {
                static USHORT usOldY = 0xFFFF;
                USHORT cyScreen = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
                USHORT cyTskBar;
                POINTL ptl;
                RECTL rcl;
                ULONG fl = SWP_SHOW;

                if (!WinIsWindowVisible(plswData->hwndMenu) &&
                    !WinIsWindowVisible(plswData->hwndTaskMenu) &&
                    !WinIsWindowVisible(groupmenuhwnd))
                    fl = SWP_ZORDER;
                WinQueryWindowRect(plswData->hwndTaskBar, &rcl);
                cyTskBar = rcl.yTop;
                if (WinQueryPointerPos(HWND_DESKTOP, &ptl), ptl.y != usOldY) {
                    usOldY = ptl.y;
                    if (ptl.y > cyTskBar && ptl.y < cyScreen - cyTskBar) {
                        if (!WinIsWindowVisible(plswData->hwndMenu) &&
                            !WinIsWindowVisible(plswData->hwndTaskMenu)&&
                            !WinIsWindowVisible(groupmenuhwnd)) {
                            WinSetWindowPos(plswData->hwndTaskBar,
                                            HWND_BOTTOM, 0, 0, 0, 0,
                                            (plswData->Settings.bTaskBarAlwaysVisible ? fl :
                                             SWP_HIDE));
                        }
                    }
                }
                //if (!plswData->Settings.bTaskBarAlwaysVisible)
                //    WinStopTimer(plswData->hab, hwnd, TSKHIDEDELAYTIMERID);
                break;
            }
#endif
	    if (SHORT1FROMMP(mp1) == TSKBARBUBBLETIMERID) {
		POINTL ptl;
		SHORT iItem;
		USHORT usX, usSizeY;
		RECTL rcl1;
		BTNDATA *pbtnData;
		HPS hps;
		POINTL aptl[TXTBOX_COUNT];

		if (WinIsWindowShowing(hwndMouseOver) &&	//no activity in FS mode
		    (iItem =
		     TaskArrItemFromHsw(plswData,
					WinQueryWindowUShort(hwndMouseOver,
							     QWS_ID),
					TRUE)) >= 0
		    && (pbtnData =
			WinQueryWindowPtr(hwndMouseOver, 0)) != NULL) {
		    WinQueryPointerPos(HWND_DESKTOP, &ptl);
		    usX = ptl.x;
		    WinMapWindowPoints(HWND_DESKTOP, hwnd, &ptl, 1);
		    WinQueryWindowRect(hwndMouseOver, &rcl1);
		    WinMapWindowPoints(hwndMouseOver, HWND_DESKTOP,
				       (POINTL *) & rcl1, 2);
		    hps = WinGetPS(plswData->hwndBubble);
		    GpiQueryTextBox(hps, 1, "M", TXTBOX_COUNT, aptl);
		    WinReleasePS(hps);
		    usSizeY =
			aptl[TXTBOX_TOPLEFT].y - aptl[TXTBOX_BOTTOMLEFT].y +
			4;
		    ShowBubble(plswData, iItem, usX,
			       rcl1.yTop + 1 + usSizeY >
			       cyScreen ? rcl1.yBottom - usSizeY : rcl1.yTop +
			       1, 2,
			       MenuItemCount(pbtnData->hwndSubWinMenu) >
			       0 ? pbtnData->pszObjName : NULL);
		}
		break;
	    }
	}

    default:
#ifdef XWORKPLACE
	mrc = plswData->pWidget->pfnwpDefWidgetProc(hwnd, msg, mp1, mp2);
#else
	mrc = WinDefWindowProc(hwnd, msg, mp1, mp2);
#endif
    }

    return (mrc);
}

SHORT InitTaskBar(LSWDATA * plswData, UCHAR * ucErrMsg, USHORT usMsgLen)
{
    ULONG ulFrameFlags;
#ifdef XWORKPLACE
    BOOL bTaskBarTopScr = (plswData->pWidget->pGlobals->ulPosition == XCENTER_TOP);
#else
    BOOL bTaskBarTopScr = plswData->Settings.bTaskBarTopScr;
#endif

    if (!WinRegisterClass(plswData->hab, LSWTASKBARCLASS, TaskBarWndProc,
			  CS_PARENTCLIP | CS_SIZEREDRAW | /*CS_SYNCPAINT | */
			  CS_CLIPCHILDREN, sizeof(PLSWDATA))) {
	strncpy(ucErrMsg, "WinRegisterClass(lswTaskBarClass)", usMsgLen);
	return WinGetLastError(plswData->hab);
    }

    ulFrameFlags =
	plswData->Settings.bAllowResize ? FCF_SIZEBORDER : FCF_BORDER;
    plswData->hwndTaskBar =
	WinCreateStdWindow(HWND_DESKTOP, 0L, &ulFrameFlags, LSWTASKBARCLASS,
			   "", 0L, NULLHANDLE, 0,
			   &plswData->hwndTaskBarClient);

    if (plswData->hwndTaskBar == NULLHANDLE) {
	strncpy(ucErrMsg, "WinCreateStdWin(LSWTaskBar)", usMsgLen);
	return WinGetLastError(plswData->hab);
    }

    WinSendMsg(plswData->hwndTaskBar, WM_SETBORDERSIZE,
	       MPFROMSHORT(TSKBARFRAMEWIDTH), MPFROMSHORT(TSKBARFRAMEWIDTH));

    WinSetWindowPtr(plswData->hwndTaskBar, 0,
		    (VOID *) WinSubclassWindow(plswData->hwndTaskBar,
                                               TskBarFrameWndProc));
    if (plswData->Settings.sTskBarY != (WinQuerySysValue(HWND_DESKTOP,
                                                         SV_CYSCREEN) -
                                        plswData->Settings.sTskBarCY + TSKBARFRAMEWIDTH)) {
        if (bTaskBarTopScr)
            plswData->Settings.sTskBarY =
                WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN) -
                plswData->Settings.sTskBarCY + TSKBARFRAMEWIDTH;
#ifndef XWORKPLACE
        if (!plswData->Settings.bTskBarGrow) {
            plswData->Settings.bTskBarGrow = TRUE;
            DosSleep(10);
            plswData->Settings.bTskBarGrow = FALSE;
        }
#endif
    }
    WinSetWindowPos(plswData->hwndTaskBar, 0,
		    plswData->Settings.sTskBarX, plswData->Settings.sTskBarY,
		    plswData->Settings.sTskBarCX,
		    plswData->Settings.sTskBarCY,
                    SWP_MOVE | SWP_SIZE | (
#ifndef XWORKPLACE
                                           plswData->Settings.bTaskBarAlwaysVisible ? SWP_SHOW :
#endif
                                           SWP_HIDE));
#ifndef XWORKPLACE
    if (plswData->Settings.bTaskBarAlwaysVisible && plswData->Settings.bReduceDsk &&
        !plswData->Settings.bAllowResize && !plswData->Settings.bTskBarGrow)
        UpdateDesktopWorkarea(plswData, FALSE);
#endif
    WinPostMsg(0, WM_NULL, 0, 0);	//reset the hook

    return 0;
}

VOID DoneTaskBar(LSWDATA * plswData)
{
#ifndef XWORKPLACE
    UpdateDesktopWorkarea(plswData, TRUE);
#endif
    WinDestroyWindow(plswData->hwndTaskBar);
    plswData->hwndTaskBar = NULLHANDLE;
}
