/*
 *      Copyright (C) 1997-2001 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 "lswitch.h"
#include "common.h"
#include "taskbar.h"
#include "settings.h"


VOID AdjustDesktop(LSWDATA *plswData,BOOL bRestore)
{ /*HWND hwndDesktop,hwndNext;
  USHORT cyScreen,cyTitleBar,cyBorder;
  SWP swp1,swp2,swp3,swp4;
  BOOL bWarpCenter,bXCenter,b1,b2,b3;
  HENUM henum;
  UCHAR ucBuf[32];
  RECTL rcl1,rcl2;
  FILE *f;
*/
/*  if (!IsDesktop((hwndDesktop=WinQueryWindow(HWND_DESKTOP,QW_BOTTOM)))) return;

  bWarpCenter=bXCenter=FALSE; swp3.y=swp3.cy=swp4.y=swp4.cy=0;

  henum=WinBeginEnumWindows(HWND_DESKTOP);
  while ((hwndNext=WinGetNextWindow(henum))!=NULLHANDLE) {
    if (IsWindowClass(hwndNext,"#3") &&
        (WinQueryWindowText(hwndNext,sizeof(ucBuf),ucBuf),strcmp(ucBuf,"SmartCenter")==0) &&
        WinIsWindowShowing(hwndNext)) {
      bWarpCenter=TRUE;
      WinQueryWindowPos(hwndNext,&swp3);
    }
    if (IsWindowClass(hwndNext,"#1") &&
        IsWindowClass(WinWindowFromID(hwndNext,FID_CLIENT),"XWPCenterClient") &&
        WinIsWindowShowing(hwndNext)) {
      bXCenter=TRUE;
      WinQueryWindowPos(hwndNext,&swp4);
    }
  }
  WinEndEnumWindows(henum);

  cyScreen=WinQuerySysValue(HWND_DESKTOP,SV_CYSCREEN);
  cyTitleBar=WinQuerySysValue(HWND_DESKTOP,SV_CYTITLEBAR);
  cyBorder=WinQuerySysValue(HWND_DESKTOP,SV_CYSIZEBORDER);

  WinQueryWindowPos(hwndDesktop,&swp1);
  WinQueryWindowPos(plswData->hwndTaskBar,&swp2);

  if (bRestore || !plswData->Settings.bTaskBarAlwaysVisible)
    swp2.y=swp2.cy=0;

  swp1.y=max((swp2.y>0)?0:swp2.y+swp2.cy,max((swp3.y>0)?0:swp3.y+swp3.cy,(swp4.y>0)?0:swp4.y+swp4.cy))+cyBorder;

  b1=(swp2.y!=0 ^ swp3.y!=0); b2=(swp2.y!=0 ^ swp4.y!=0); b3=(swp3.y!=0 ^ swp4.y!=0);

  swp1.cy=cyScreen-2*cyBorder-
    (b1 && b2)*swp2.cy-(b1 && b3)*swp3.cy-(b2 && b3)*swp4.cy-
    max(b1?0:max(swp2.cy,swp3.cy),max(b2?0:max(swp2.cy,swp4.cy),b3?0:max(swp3.cy,swp4.cy)));


//  WinSetWindowPos(hwndDesktop,0,swp1.x,swp1.y,swp1.cx,swp1.cy,SWP_MOVE | SWP_SIZE);

*/
/*  WinQueryDesktopWorkArea(HWND_DESKTOP,&rcl1);

//  f=fopen("desktop.txt","a");
//  fprintf(f,"%i %i %i %i\n", rcl.xLeft,rcl.yBottom,rcl.xRight,rcl.yTop);

  WinQueryWindowPos(plswData->hwndTaskBar,&swp1);

  rcl2.xLeft = rcl1.xLeft; rcl2.xRight = rcl1.xRight;
  if (!plswData->Settings.bTaskBarAlwaysVisible || bRestore) {
    rcl2.yBottom = 0; rcl2.yTop = 600;
  } else
    if (plswData->Settings.bTaskBarTopScr)
      rcl2.yTop = swp1.y-WinQuerySysValue(HWND_DESKTOP,SV_CYSIZEBORDER);
    else
      rcl2.yBottom = swp1.y+swp1.cy+WinQuerySysValue(HWND_DESKTOP,SV_CYSIZEBORDER)-1;

  if (rcl1.yBottom!=rcl2.yBottom || rcl1.yTop!=rcl2.yTop) {
    WinSetDesktopWorkArea(HWND_DESKTOP,&rcl2);
    DosBeep(1000,1);
  }

//  fprintf(f,"%i %i %i %i\n", rcl.xLeft,rcl.yBottom,rcl.xRight,rcl.yTop);

//  WinQueryDesktopWorkArea(HWND_DESKTOP,&rcl2);

//  fprintf(f,"%i %i %i %i\n\n", rcl.xLeft,rcl.yBottom,rcl.xRight,rcl.yTop);
//  fclose(f);
  */
}

SHORT TaskArrItemFromHsw(LSWDATA *plswData,USHORT hsw)
{ SHORT iItem,k;

  InitTaskArr(plswData,FALSE,TRUE);

  for(k=0,iItem=-1;k<plswData->usItems && iItem<0;k++)
    if ((plswData->TaskArr[k].hsw & 0xFFFF)==hsw) iItem=k;

  return iItem;
}


MRESULT EXPENTRY ButtonWndProc(HWND hwnd,ULONG msg,MPARAM mp1,MPARAM mp2)
{ LSWDATA *plswData;
  MRESULT mrc=0;
  static BOOL bChord = FALSE;

  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 (msg) {
  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
    mrc = (((BTNDATA*)WinQueryWindowPtr(hwnd,0))->pOldWndProc)(hwnd,msg,mp1,mp2);
    break;

  case WM_BUTTON1CLICK:
  case WM_BUTTON2CLICK:
  case WM_BUTTON3CLICK:
  case WM_BUTTON1UP:
  case WM_BUTTON2UP: {
    BOOL bShiftKeyDown,bActiveBtn;
    SHORT sItem;

    bShiftKeyDown = ((WinGetPhysKeyState(HWND_DESKTOP,0x1d)&0x8000) ||
                     (WinGetPhysKeyState(HWND_DESKTOP,0x5b)&0x8000) ||
                     (WinGetPhysKeyState(HWND_DESKTOP,0x38)&0x8000) ||
                     (WinGetPhysKeyState(HWND_DESKTOP,0x5e)&0x8000) ||
                     (WinGetPhysKeyState(HWND_DESKTOP,0x2a)&0x8000) ||
                     (WinGetPhysKeyState(HWND_DESKTOP,0x36)&0x8000));

    if (!bShiftKeyDown && bChord &&
        ((msg==WM_BUTTON1UP && !(WinGetKeyState(HWND_DESKTOP,VK_BUTTON2)&0x8000)) ||
         (msg==WM_BUTTON2UP && !(WinGetKeyState(HWND_DESKTOP,VK_BUTTON1)&0x8000)))) {
      msg=WM_CHORD;
      bChord=FALSE;
    }

    if (!bShiftKeyDown && msg!=WM_BUTTON1UP && msg!=WM_BUTTON2UP &&
        (sItem=TaskArrItemFromHsw(plswData,WinQueryWindowUShort(hwnd,QWS_ID)))>=0) {

      plswData->usCurrItem = sItem;
      bActiveBtn=(BOOL)WinSendMsg(plswData->hwndTaskBarClient,LSWM_QUERYACTIVEBTN,MPFROMHWND(hwnd),0);

      if ((!bActiveBtn || (plswData->TaskArr[sItem].fl & (SWP_MINIMIZE|SWP_HIDE))) &&
          msg==plswData->Settings.usSwitchMEvent)
        WinPostMsg(plswData->hwndPopup,WM_COMMAND,MPFROMSHORT(CMD_SWITCHFROMPM),MPFROM2SHORT(CMDSRC_OTHER,TRUE));
      else if ((bActiveBtn || (plswData->Settings.usMinMEvent!=plswData->Settings.usSwitchMEvent))&&
               !(plswData->TaskArr[sItem].fl & (SWP_MINIMIZE|SWP_HIDE)) &&
               msg==plswData->Settings.usMinMEvent) {
        if (!ChangeWindowPos(plswData,sItem,CMD_MINIMIZE)) ChangeWindowPos(plswData,sItem,CMD_HIDE);
      } else if (msg==plswData->Settings.usCloseMEvent)
        ChangeWindowPos(plswData,sItem,CMD_CLOSE);
    }

    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)))>=0) {
      ShowBubble(plswData,0,0,0,-2);
      ShowMenu(plswData, IsDesktop(plswData->TaskArr[plswData->iMenuAtItem].hwnd) ?
               -1 : plswData->iMenuAtItem,TRUE);
    }
    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 = (BOOL)WinSendMsg(WinQueryWindow(hwnd,QW_PARENT),LSWM_QUERYACTIVEBTN,MPFROMHWND(hwnd),0);
    pBtnData = WinQueryWindowPtr(hwnd,0);
    bHidden = (pBtnData->flItemWnd&(SWP_HIDE|SWP_MINIMIZE));

    switch(lParam) {
    case PP_FOREGROUNDCOLOR:
      if (bActiveBtn)
        if (bHidden)
          plswData->Settings.lActiveHiddenBtnTitleRGBCol = lValue;
        else
          plswData->Settings.lActiveBtnTitleRGBCol = lValue;
      else
        if (bHidden)
          plswData->Settings.lNormalHiddenBtnTitleRGBCol = lValue;
        else
          plswData->Settings.lNormalBtnTitleRGBCol = lValue;

      break;

    case PP_BACKGROUNDCOLOR:
      if (bActiveBtn)
        if (bHidden)
          plswData->Settings.lActiveHiddenBtnRGBCol = lValue;
        else
          plswData->Settings.lActiveBtnRGBCol = lValue;
      else
        if (bHidden)
          plswData->Settings.lNormalHiddenBtnRGBCol = 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);

  }

  return mrc;
}

MRESULT EXPENTRY TskBarFrameWndProc(HWND hwnd,ULONG msg,MPARAM mp1,MPARAM mp2)
{ LSWDATA *plswData;

  switch (msg) {
  case WM_WINDOWPOSCHANGED: {
    PSWP pswp;

    pswp = ((PSWP)PVOIDFROMMP(mp1));
    if (pswp->fl & (SWP_SIZE|SWP_MOVE)) {
      DosGetNamedSharedMem((PVOID*)&plswData,SHAREMEM_NAME,PAG_READ | PAG_WRITE);

      plswData->Settings.sTskBarX = pswp->x; plswData->Settings.sTskBarY = pswp->y;
      plswData->Settings.sTskBarCX = pswp->cx; plswData->Settings.sTskBarCY = pswp->cy;

      AdjustDesktop(plswData,FALSE);
      DosFreeMem(plswData);
    }
    break;
  }
  case WM_DESTROY:
    DosGetNamedSharedMem((PVOID*)&plswData,SHAREMEM_NAME,PAG_READ | PAG_WRITE);
    AdjustDesktop(plswData,TRUE);
    DosFreeMem(plswData);

    break;

  case WM_ADJUSTWINDOWPOS: {
    SWP *pswp;

    pswp = PVOIDFROMMP(mp1);

    if (pswp->fl & SWP_ACTIVATE) pswp->fl &= ~SWP_ACTIVATE;
    break;
  }
  }

  return ((PFNWP)WinQueryWindowPtr(hwnd,0))(hwnd,msg,mp1,mp2);
}

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;
  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_QUERYACTIVEBTN:
    mrc = (MPARAM)(WinQueryWindowUShort(HWNDFROMMP(mp1),QWS_ID)==usHswActive);
    break;

  case LSWM_ACTIVEWNDCHANGED: {
    USHORT usOldActive;

    if (!WinIsWindow(plswData->hab,HWNDFROMMP(mp2))) break;
    DosSleep(1);
    usOldActive=usHswActive;
    usHswActive=WinQuerySwitchHandle(WinQueryActiveWindow(HWND_DESKTOP),0)&0xFFFF;

    if (usHswActive!=usOldActive) {
      WinInvalidateRect(WinWindowFromID(hwnd,usOldActive),NULL,FALSE);
      WinInvalidateRect(WinWindowFromID(hwnd,usHswActive),NULL,FALSE);
    }
    break;
  }

  case LSWM_WNDSTATECHANGED: {
    HWND hwndBtn;
    BTNDATA *pbtnData;

    if (!WinIsWindow(plswData->hab,HWNDFROMMP(mp2))) break;
    hwndBtn = WinWindowFromID(hwnd,SHORT1FROMMP(mp1));
    if (hwndBtn != NULLHANDLE) {
      if ((pbtnData = WinQueryWindowPtr(hwndBtn,0))!=NULL &&
          UpdateWinFlags(&pbtnData->flItemWnd,SHORT2FROMMP(mp1)))
        WinInvalidateRect(hwndBtn,NULL,FALSE);
    }
    break;
  }

  case LSWM_WNDICONCHANGED: {
    HWND hwndBtn;
    RECTL rcl;

    hwndBtn=WinWindowFromID(hwnd,WinQuerySwitchHandle(HWNDFROMMP(mp2),0));
    if (hwndBtn!=NULLHANDLE) {
      ((BTNDATA*)WinQueryWindowPtr(hwndBtn,0))->hIcon=LONGFROMMP(mp1);
      WinSendMsg(HWNDFROMMP(mp2),WM_NULL,0,0); // to make sure the icon handle has become valid
      WinQueryWindowRect(hwndBtn,&rcl);
      rcl.xRight = usMinBtnWid;
      WinInvalidateRect(hwndBtn,&rcl,FALSE);
    }
    break;
  }

  case LSWM_SWITCHLISTCHANGED: {
    ULONG ulFunc;
    HSWITCH hsw;
    BOOL bHiddenItem;
    SWCNTRL swctl;
    SWP swp;
    HWND hwndFound;

//    static struct _PRES {ULONG cb; ULONG id1; ULONG cb1; UCHAR szFnt1[sizeof(DEFTITLEFONT3)];} pres=
//      {sizeof(ULONG)*2+sizeof(DEFTITLEFONT3),PP_FONTNAMESIZE,sizeof(DEFTITLEFONT3),DEFTITLEFONT3};

    ulFunc=LONGFROMMP(mp1); //0x1 or 0x10001 -- create switch entry
                            //0x2 -- modify, 0x3 -- delete
    hsw=LONGFROMMP(mp2);

    if (hsw==0 || (ulFunc!=3 && (WinQuerySwitchEntry(hsw,&swctl)!=0 ||
                                 !WinIsWindow(plswData->hab,swctl.hwnd) ||
                                 !WinQueryWindowPos(swctl.hwnd,&swp))))
      break;

    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, swctl.szSwtitle,TRUE));

    hwndFound = WinWindowFromID(hwnd,hsw&0xFFFF);

    if (hwndFound != NULLHANDLE) {
      if (ulFunc == 0x2 && !bHiddenItem) {
        RECTL rcl;
        SHORT sItem;

        WinQueryWindowRect(hwndFound,&rcl);
        rcl.xLeft = usMinBtnWid;
        WinInvalidateRect(hwndFound,&rcl,FALSE);

        if (!plswData->bNowActive && (sItem=TaskArrItemFromHsw(plswData,hsw))>=0)
          ShowBubble(plswData,sItem,0,0,11);

        break;
      } else if ((ulFunc==0x2 && bHiddenItem) || ulFunc==0x3) {
        BTNDATA *pbData;

        pbData=WinQueryWindowPtr(hwndFound,0);
        WinDestroyWindow(hwndFound);
        free(pbData);
        WinInvalidateRect(hwnd,NULL,FALSE);
      } else
        break;
    } else {
      if ((ulFunc==0x1 || ulFunc==0x10001 || ulFunc==0x2) && !bHiddenItem) {
        BTNDATA *pbData;
        HWND hwndBtn;

        hwndBtn=WinCreateWindow(
          hwnd,WC_BUTTON,"",WS_VISIBLE | BS_USERBUTTON | BS_NOPOINTERFOCUS,
          0,0,0,0,hwnd,IsDesktop(swctl.hwnd)?HWND_TOP:HWND_BOTTOM,hsw & 0xFFFF, NULL,NULL);
        if (hwndBtn==NULLHANDLE) break;
        if ((pbData=malloc(sizeof(BTNDATA)))!=NULL) {
          pbData->hIcon = GetItemIcon(swctl.hwnd);
          pbData->flItemWnd = swp.fl;
          WinSetWindowPtr(hwndBtn,0,(VOID *)pbData);
          pbData->pOldWndProc=WinSubclassWindow(hwndBtn,ButtonWndProc);
          WinSetPresParam(hwndBtn,PP_FONTNAMESIZE,strlen(plswData->Settings.ucButtonFont)+1,plswData->Settings.ucButtonFont);
        } else
          WinDestroyWindow(hwndBtn);
      } else
        break;
    }
  }

  case WM_SIZE: {
    USHORT usButtons,usDskBtnHgt,k,usBtn1,usScrWid,usBtnWid,usBtnRows,usBtnHgt,
           usBtnPerRow,usRowWid,usBigBtnPerRow,usMinBtnHgt,usMaxBtnWid;
    HENUM henum;
    HWND hwndNext,hwndTop;
    RECTL rcl;
    BOOL bIsDesktop;
    SWP *aswp;
    SWCNTRL swctl;

    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;

    WinQuerySwitchEntry(WinQueryWindowUShort(hwndTop,QWS_ID),&swctl);
    bIsDesktop = IsDesktop(swctl.hwnd);

    WinQueryWindowRect(hwnd,&rcl); // may not be WM_SIZE, can't use mp2 to get size

    usMinBtnWid = WinQuerySysValue(HWND_DESKTOP,SV_CXICON)/2+2*usBorderWid+2;
    usMaxBtnWid = plswData->Settings.usMaxBtnWid;

#ifdef XWORKPLACE
    if (plswData->pWidget->pGlobals->flDisplayStyle & XCS_FLATBUTTONS) {
      usBorderWid = 1;
      usMinBtnHgt = usMinBtnWid+2;
    } else {
      usBorderWid = 2;  // didn't find any constants for this
      usMinBtnHgt = usMinBtnWid;
    }
#else
    usBorderWid = BUTTONBORDERWIDTH;
    usMinBtnHgt = usMinBtnWid;
#endif

    usBtnHgt = rcl.yTop/max(rcl.yTop/usMinBtnHgt,1);

    usDskBtnHgt = rcl.yTop;

    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);

    aswp=malloc(sizeof(SWP)*usButtons);
    henum=WinBeginEnumWindows(hwnd); k=0;
    while ((hwndNext=WinGetNextWindow(henum))!=NULLHANDLE) {
      if (!IsWindowClass(hwndNext,"#3")) continue;

      if (k==0 && bIsDesktop) { //desktop button
        aswp[k].x = aswp[k].y = 0;
        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;
        aswp[k].cy = usBtnHgt;
      }
#ifdef XWORKPLACE
      if (plswData->pWidget->pGlobals->flDisplayStyle & XCS_FLATBUTTONS) {
        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: {
#ifndef XWORKPLACE
    DosGetNamedSharedMem((PVOID*)&plswData,SHAREMEM_NAME,PAG_READ | PAG_WRITE);
    if (plswData==NULL) {
      mrc=(MRESULT)TRUE;
      break;
    }
    WinSetWindowPtr(hwnd, 0, plswData);
    DosFreeMem(plswData);
#else
    VOID *pData;
    PXCENTERWIDGET pWidget;
    LONG lrc;

    pWidget = (PXCENTERWIDGET)mp1;
    if (pWidget==NULL || pWidget->pfnwpDefWidgetProc==NULL) {
      mrc = (MRESULT)TRUE;
      break;
    }

    pData = (PVOID)pWidget;
    lrc = SwitcherInit(WinQueryAnchorBlock(hwnd), 0, NULL, 0, &pData);
    if (lrc > 0) {
      if (pData != NULL) SwitcherTerm((PLSWDATA)pData);
      mrc = (MRESULT)TRUE;
      break;
    } else if (lrc == LSWERROLDSETTINGS) {
    }

    plswData = (PLSWDATA)pData; pWidget->pUser=plswData;
    plswData->pWidget = pWidget; plswData->hwndTaskBarClient = hwnd;

    WinSetWindowPtr(hwnd, 0, pWidget);
#endif

    WinStartTimer(WinQueryAnchorBlock(hwnd), hwnd, 0, BUBBLETIMERINTERVAL);
    WinPostMsg(hwnd,LSWM_INITBUTTONS,0,0);
  }

  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=min(MAXITEMS,ulItemCount)-1;k>=0;k--)
      WinSendMsg(hwnd,LSWM_SWITCHLISTCHANGED,
                 MPFROMLONG(IsInSkipList(&plswData->Settings,pSwb->aswentry[k].swctl.szSwtitle,TRUE)?2:1),
                 MPFROMLONG(pSwb->aswentry[k].hswitch));
    GetSwitchList(0,FALSE,NULL);
    WinSendMsg(hwnd,LSWM_ACTIVEWNDCHANGED,MPFROMLONG(1),MPFROMHWND(WinQueryActiveWindow(HWND_DESKTOP)));

    break;
  }

  case WM_DESTROY: {
#ifdef XWORKPLACE
    PFNWP DefWgtWndProc;
#endif

    WinStopTimer(plswData->hab,hwnd,0);

#ifdef XWORKPLACE
    DefWgtWndProc=plswData->pWidget->pfnwpDefWidgetProc;
    SwitcherTerm(plswData);
    return DefWgtWndProc(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;
      plswData->Settings.lTskBarRGBCol = lValue;
      WinInvalidateRect(hwnd,NULL,FALSE);
    }
    break;
  }

  case WM_PAINT: {
    HPS hps;
    RECTL rcl;
    SWP swp;
    POINTL ptl;
    HWND hwndBottom;

    hps = WinBeginPaint(hwnd,NULLHANDLE,&rcl);
    WinQueryWindowRect(hwnd, &rcl);
    GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL);

    WinFillRect(hps,&rcl,plswData->Settings.lTskBarRGBCol);

#ifndef XWORKPLACE
/*    hwndBottom = WinQueryWindow(hwnd,QW_BOTTOM);
    if (hwndBottom!=NULLHANDLE)
      WinQueryWindowPos(hwndBottom,&swp);
    else
      swp.x = swp.cx = 0;

    ptl.x=swp.x+swp.cx; ptl.y=0;
    GpiMove(hps,&ptl);
    ptl.x=rcl.xRight;
    GpiSetColor(hps,SUNKENFRAMERGBCOL);
    GpiLine(hps,&ptl);

    ptl.x=(swp.y+swp.cy==rcl.yTop?swp.x+swp.cx:0);
    ptl.y=rcl.yTop-1;
    GpiMove(hps,&ptl);
    ptl.x=rcl.xRight;
    GpiSetColor(hps, RAISEDFRAMERGBCOL);
    GpiLine(hps,&ptl);*/
    WinDrawBorder(hps,&rcl,0,TSKBARFRAMEWIDTH,SUNKENFRAMERGBCOL,RAISEDFRAMERGBCOL,DB_RAISED);
#endif

    WinEndPaint(hps);
    break;
  }

#ifdef XWORKPLACE
  case LSWM_MOUSEOVERBTN:
    if (!(plswData->pWidget->pGlobals->flDisplayStyle & XCS_FLATBUTTONS)) break;

    if (SHORT1FROMMP(mp2)==FALSE)
      hwndMouseOver = 0;
    else if (WinQueryWindowUShort(HWNDFROMMP(mp1),QWS_ID)!=usHswActive)
      hwndMouseOver = HWNDFROMMP(mp1);

    WinInvalidateRect(SHORT1FROMMP(mp2)==FALSE?HWNDFROMMP(mp1):hwndMouseOver,NULL,FALSE);

    break;
#endif

  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;
      SHORT sItem;

      hsw = SHORT1FROMMP(mp1);

      switch (SHORT2FROMMP(mp1)) {
      case BN_PAINT: {
        USERBUTTON *pubButton;
        RECTL rcl;
        ENTRYNAME Title;
        BOOL bHilite;
        BTNDATA *pbtnData;
        LONG lBgndCol, lTextCol;
        USHORT usRclHgt;

        if ((pubButton=(USERBUTTON *)mp2) == NULL || !WinIsWindow(plswData->hab,pubButton->hwnd))
          break;

        if ((pbtnData = WinQueryWindowPtr(pubButton->hwnd,0))==NULL) break;

        WinQueryWindowRect(pubButton->hwnd,&rcl);
        usRclHgt = rcl.yTop;

        GpiCreateLogColorTable(pubButton->hps, 0, LCOLF_RGB, 0, 0, NULL);

        bHilite=((LOUSHORT(pubButton->fsState)&BDS_HILITED)==BDS_HILITED ||
                 hsw==usHswActive);

        if (bHilite)
          if (pbtnData->flItemWnd&(SWP_HIDE|SWP_MINIMIZE)) {
            lTextCol = plswData->Settings.lActiveHiddenBtnTitleRGBCol;
            lBgndCol = plswData->Settings.lActiveHiddenBtnRGBCol;
          } else {
            lTextCol = plswData->Settings.lActiveBtnTitleRGBCol;
            lBgndCol = plswData->Settings.lActiveBtnRGBCol;
          }
        else
          if (pbtnData->flItemWnd&(SWP_HIDE|SWP_MINIMIZE)) {
            lTextCol = plswData->Settings.lNormalHiddenBtnTitleRGBCol;
            lBgndCol = plswData->Settings.lNormalHiddenBtnRGBCol;
          } else {
            lTextCol = plswData->Settings.lNormalBtnTitleRGBCol;
            lBgndCol = plswData->Settings.lNormalBtnRGBCol;
          }

        WinFillRect(pubButton->hps, &rcl, lBgndCol);

#ifdef XWORKPLACE
        if (!(plswData->pWidget->pGlobals->flDisplayStyle & XCS_FLATBUTTONS) ||
            bHilite || hwndMouseOver==pubButton->hwnd)
#endif
          WinDrawBorder(pubButton->hps,&rcl,usBorderWid,usBorderWid,
            SUNKENFRAMERGBCOL,RAISEDFRAMERGBCOL,bHilite?DB_DEPRESSED:DB_RAISED);

// 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;

        if (!plswData->Settings.bIconsOnlyInTskBar) {
          GetItemTitle(hsw,Title,sizeof(Title),FALSE);
          MakeFitStr(pubButton->hps,Title, sizeof(Title),
                     rcl.xRight-rcl.xLeft+bHilite-1);
          WinDrawText(pubButton->hps,strlen(Title),Title,&rcl,
                      lTextCol,lBgndCol, DT_VCENTER);
        }

        WinDrawPointer(pubButton->hps, usBorderWid+bHilite+1,
                       (usRclHgt-usMinBtnWid)/2+usBorderWid-bHilite+1,
                       ((BTNDATA*)WinQueryWindowPtr(pubButton->hwnd,0))->hIcon, DP_MINIICON);
        break;
      }
      }
    }
    break;

  case WM_ERASEBACKGROUND:
    mrc=(MRESULT)TRUE;
    break;

  case WM_CONTEXTMENU:
    if (!plswData->bNowActive) {
      ShowBubble(plswData,0,0,0,-2);
      ShowMenu(plswData, -1,TRUE);
    }
    break;

  case WM_COMMAND:
    if (SHORT1FROMMP(mp1)==CMD_ADDFILTER) {
      ENTRYNAME ucName;
// TaskArr is filled in the show menu sequence
      GetItemTitle(plswData->TaskArr[plswData->iMenuAtItem].hsw,ucName,sizeof(ucName),FALSE);
      if (AddFilter(&plswData->Settings,ucName,TRUE)) {
        USHORT k;
        ENTRYNAME ucName1;

        for (k=0;k<plswData->usItems;k++) { //check for entries with the same name
          GetItemTitle(plswData->TaskArr[k].hsw,ucName1,sizeof(ucName1),FALSE);
          if (strcmp(ucName,ucName1)==0)
            WinPostMsg(hwnd,LSWM_SWITCHLISTCHANGED, MPFROMLONG(2), MPFROMLONG(plswData->TaskArr[k].hsw));
        }
      }
    } else if (SHORT1FROMMP(mp1)>=CMD_FIRST && SHORT1FROMMP(mp1)<=CMD_LAST)
      WinPostMsg(plswData->hwndPopClient,msg,mp1,mp2);
#ifdef XWORKPLACE
    else
      mrc=plswData->pWidget->pfnwpDefWidgetProc(hwnd, msg, mp1, mp2);
#endif

    break;

  case WM_TIMER: {
    POINTL ptl;
    HWND hwnd1;
    SHORT iItem;
    USHORT hsw,usX;
    RECTL rcl1,rcl2;

    if (!plswData->bNowActive && !WinIsWindowVisible(plswData->hwndMenu) &&
        (WinQueryPointerPos(HWND_DESKTOP,&ptl),usX=ptl.x,
         WinMapWindowPoints(HWND_DESKTOP,hwnd,&ptl,1),
         hwnd1=WinWindowFromPoint(hwnd,&ptl,FALSE),
         (WinIsWindowShowing(hwnd1) && WinQueryWindow(hwnd1,QW_PARENT)==hwnd)) &&
        (hsw=WinQueryWindowUShort(hwnd1,QWS_ID),
        (iItem=TaskArrItemFromHsw(plswData,hsw))>=0)) {

      WinQueryWindowRect(hwnd1,&rcl1); WinMapWindowPoints(hwnd1,HWND_DESKTOP,(POINTL*)&rcl1,2);
      WinQueryWindowRect(plswData->hwndBubble,&rcl2);
      ShowBubble(plswData,iItem,usX,rcl1.yTop+1+rcl2.yTop>cyScreen?
                 rcl1.yBottom-rcl2.yTop:rcl1.yTop+1,2);
    } else
      ShowBubble(plswData,0,0,0,-2);

    break;
  }
  default:
#ifdef XWORKPLACE
    return plswData->pWidget->pfnwpDefWidgetProc(hwnd, msg, mp1, mp2);
#else
    return WinDefWindowProc(hwnd, msg, mp1, mp2);
#endif
  }

  return (mrc);
}


SHORT InitTaskBar(LSWDATA* plswData,UCHAR *ucErrMsg,USHORT usMsgLen)
{ ULONG ulFrameFlags;

  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 = FCF_SIZEBORDER;
  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));

  WinSetWindowPos(plswData->hwndTaskBar,0 ,
                  plswData->Settings.sTskBarX,plswData->Settings.sTskBarY,
                  plswData->Settings.sTskBarCX,plswData->Settings.sTskBarCY,
                  SWP_MOVE | SWP_SIZE |
                  (plswData->Settings.bTaskBarAlwaysVisible?SWP_SHOW:0));
  return 0;
}

VOID DoneTaskBar(LSWDATA *plswData)
{
  WinDestroyWindow(plswData->hwndTaskBar);
  plswData->hwndTaskBar = NULLHANDLE;
}
