home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / MISC / LSW270SR.ZIP / common.c next >
Text File  |  2004-04-11  |  52KB  |  1,432 lines

  1. /*
  2.  *      Copyright (C) 1997-2004 Andrei Los.
  3.  *      This file is part of the lSwitcher source package.
  4.  *      lSwitcher is free software; you can redistribute it and/or modify
  5.  *      it under the terms of the GNU General Public License as published
  6.  *      by the Free Software Foundation, in version 2 as it comes in the
  7.  *      "COPYING" file of the lSwitcher main distribution.
  8.  *      This program is distributed in the hope that it will be useful,
  9.  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.  *      GNU General Public License for more details.
  12.  */
  13.  
  14. #include <process.h>
  15. #include <string.h>
  16. #include <stdio.h>
  17. #include <ctype.h>
  18. #include "common.h"
  19. #include "msg.h"
  20. #include "apm.h"
  21. #include "prmdlg.h"
  22. #include "settings.h"
  23.  
  24. #ifdef XWORKPLACE
  25.   #include "dlgids.h"
  26. #endif
  27.  
  28. ULONG MapCommand(USHORT cmd)
  29. {
  30.   switch (cmd) {
  31.   case CMD_HIDE:     return MAKEULONG(SC_HIDE,SWP_HIDE);
  32.   case CMD_MAXIMIZE: return MAKEULONG(SC_MAXIMIZE,SWP_MAXIMIZE);
  33.   case CMD_MINIMIZE: return MAKEULONG(SC_MINIMIZE,SWP_MINIMIZE);
  34.   case CMD_RESTORE:  return MAKEULONG(SC_RESTORE,SWP_RESTORE);
  35.   case CMD_SHOW:     return MAKEULONG(0,SWP_SHOW);
  36.   case CMD_MOVE:     return MAKEULONG(SC_MOVE,SWP_MOVE);
  37.   case CMD_CLOSE:    return MAKEULONG(SC_CLOSE,0);
  38.   default: return 0;
  39.   }
  40. }
  41.  
  42. /* This advanced killing Copyright (C)1996 by Holger.Veit@gmd.de */
  43. HFILE OpenXF86(VOID)
  44. { HFILE hfd;
  45.   ULONG action;
  46.  
  47.   if (DosOpen((PSZ)"/dev/fastio$", (PHFILE)&hfd, &action, 0, FILE_SYSTEM, FILE_OPEN,
  48.       OPEN_SHARE_DENYNONE|OPEN_FLAGS_NOINHERIT|OPEN_ACCESS_READONLY, 0)!=0)
  49.     return 0;
  50.   else
  51.     return hfd;
  52. }
  53.  
  54. BOOL Death(PID pid)
  55. { HFILE hfd;
  56.   ULONG plen;
  57.   USHORT param;
  58.  
  59.  
  60.   if ((hfd=OpenXF86())==0) return FALSE;
  61.   param = pid;
  62.  
  63.   if (DosDevIOCtl(hfd,0x76,0x65,(PULONG*)¶m,sizeof(USHORT),&plen,NULL,0,NULL)!=0) {
  64.     DosClose(hfd);
  65.     return FALSE;
  66.   }
  67.  
  68.   DosClose(hfd);
  69.   return TRUE;
  70. }
  71.  
  72. PID GetWPSPid(VOID)
  73. { HWND hwnd;
  74.   PID pid; TID tid;
  75.  
  76.   if (hwnd=WinQueryWindow(HWND_DESKTOP,QW_BOTTOM),IsWindowClass(hwnd,"wpFolder window")) {
  77.     WinQueryWindowProcess(hwnd,&pid,&tid);
  78.     return pid;
  79.   } else
  80.     return 0;
  81. }
  82.  
  83. SHORT TaskArrItemFromHsw(LSWDATA *plswData,USHORT hsw,BOOL bUseFilters)
  84. { SHORT iItem,k;
  85.  
  86.   InitTaskArr(plswData,FALSE,TRUE,bUseFilters);
  87.  
  88.   for(k=0,iItem=-1;k<plswData->usItems && iItem<0;k++)
  89.     if ((plswData->TaskArr[k].hsw & 0xFFFF)==hsw) iItem=k;
  90.  
  91.   return iItem;
  92. }
  93.  
  94. BOOL ChangeWindowPos(LSWDATA *plswData,SHORT iItemNum,USHORT cmd)
  95. { USHORT cmd1;
  96.   BOOL bDoIt;
  97.  
  98.   cmd1=LOUSHORT(MapCommand(cmd));
  99.  
  100.   bDoIt = ((cmd==CMD_KILL || cmd==CMD_DEATH || cmd==CMD_CLOSE || cmd==CMD_CLOSEQUIT) ? TRUE :
  101.            cmd == CMD_SHOW ? (!(plswData->TaskArr[iItemNum].fl & SWP_SHOW)):
  102.            WndHasControl(plswData->hab,plswData->TaskArr[iItemNum].hwnd,cmd1));
  103.  
  104.   if (bDoIt) {
  105.     if (cmd==CMD_SHOW)
  106.       WinShowWindow(plswData->TaskArr[iItemNum].hwnd,TRUE);
  107.     else if (cmd==CMD_CLOSEQUIT)
  108.       WinPostMsg(plswData->TaskArr[iItemNum].hwnd, WM_QUIT, 0,0);
  109.     else if (cmd==CMD_KILL)
  110.       DosKillProcess(DKP_PROCESS,plswData->TaskArr[iItemNum].pid);
  111.     else if (cmd==CMD_DEATH)
  112.       Death(plswData->TaskArr[iItemNum].pid);
  113.     else
  114.       WinPostMsg(plswData->TaskArr[iItemNum].hwnd,WM_SYSCOMMAND,MPFROMSHORT(cmd1),MPFROM2SHORT(CMDSRC_OTHER,FALSE));
  115.   }
  116.  
  117.   return bDoIt;
  118. }
  119.  
  120.  
  121. /* this procedure returns TRUE if the the popup menu for the usItem item in
  122.  the TaskArr needs the menu item usId. If yes, the title is returned also */
  123. BOOL MenuNeedsItem(LSWDATA *plswData,USHORT usItem,USHORT usId,UCHAR *pszTitle,USHORT usLen,BOOL bGroup)
  124. { BOOL bNeedsItem=FALSE;
  125.   USHORT k;
  126.  
  127.   if (bGroup && ((usId>=CMD_SWITCHFROMPM && usId<=CMD_CLOSE) || usId==CMD_ADDFILTER)) {
  128.     for (k=0;k<plswData->usItems && bNeedsItem==FALSE;k++) {
  129.       if (plswData->TaskArr[k].pid!=plswData->TaskArr[usItem].pid) continue;
  130.  
  131.       if (usId==CMD_SHOW && (plswData->TaskArr[k].fl & SWP_HIDE))
  132.         bNeedsItem=TRUE;
  133.       else if (usId>=CMD_HIDE && usId<=CMD_CLOSE && usId!=CMD_MOVE) {
  134.         bNeedsItem = WndHasControl(plswData->hab,plswData->TaskArr[k].hwnd,LOUSHORT(MapCommand(usId)));
  135.         if (usId == CMD_HIDE) bNeedsItem &=(!(plswData->TaskArr[k].fl & SWP_HIDE));
  136.       }
  137.     }
  138.   } else {
  139.     if (usId == CMD_SWITCHFROMPM || usId == CMD_CLOSEQUIT)
  140.       bNeedsItem = TRUE;
  141.     else if (usId==CMD_KILL || usId==CMD_DEATH || usId==CMD_PRIORITY) {
  142.       bNeedsItem=(plswData->TaskArr[usItem].pid!=GetWPSPid());
  143.       if (usId==CMD_DEATH) {
  144.         HFILE hfd;
  145.         if ((hfd = OpenXF86())!=0) DosClose(hfd);
  146.         bNeedsItem &=(hfd!=0);
  147.       }
  148.     } else if (usId == CMD_ADDFILTER)
  149.       bNeedsItem = TRUE;
  150.     else if (usId == CMD_MOVE) {
  151.       bNeedsItem =
  152.         (!(plswData->TaskArr[usItem].fl & SWP_HIDE) &&
  153.          !IsMinToViewer(plswData->TaskArr[usItem].hwnd,plswData->TaskArr[usItem].fl) &&
  154.          WndHasControl(plswData->hab,plswData->TaskArr[usItem].hwnd,SC_MOVE));
  155.     } else if (usId == CMD_SHOW)
  156.       bNeedsItem = (plswData->TaskArr[usItem].fl & SWP_HIDE);
  157.     else
  158.       bNeedsItem = WndHasControl(plswData->hab,plswData->TaskArr[usItem].hwnd,LOUSHORT(MapCommand(usId)));
  159.  
  160.     if (usId == CMD_HIDE) bNeedsItem &=(!(plswData->TaskArr[usItem].fl & SWP_HIDE));
  161.   }
  162.  
  163.   if (bNeedsItem)
  164.     WinLoadString(plswData->hab,plswData->hmodRes,usId,usLen,pszTitle);
  165.  
  166.   return bNeedsItem;
  167. }
  168.  
  169. BOOL WndHasControl(HAB hab,HWND hwndToCheck,USHORT usControl)
  170. { HWND hwndSysMenu, hwndMinMax;
  171.  
  172.   return
  173.     (WinIsWindow(hab,hwndToCheck) && WinIsWindowEnabled(hwndToCheck) &&
  174.      (
  175.       (
  176.        (hwndSysMenu=WinWindowFromID(hwndToCheck,FID_SYSMENU))!=NULLHANDLE &&
  177.        SHORT1FROMMR(WinSendMsg(hwndSysMenu,MM_ISITEMVALID,MPFROM2SHORT(usControl,TRUE),0))==TRUE
  178.       ) ||
  179.       (
  180.        (hwndMinMax=WinWindowFromID(hwndToCheck,FID_MINMAX))!=NULLHANDLE &&
  181.        SHORT1FROMMR(WinSendMsg(hwndMinMax,MM_QUERYITEMCOUNT,0,0))>0 &&
  182.        (SHORT)WinSendMsg(hwndMinMax,MM_ITEMPOSITIONFROMID,MPFROM2SHORT(usControl,0),0)!=MIT_NONE
  183.       )
  184.      )
  185.     );
  186. }
  187.  
  188. SHORT InsertMenuItem(HWND hwndMenu, HWND hwndSubMenu, SHORT iPosition, SHORT sItemId,
  189.                      char *ItemTitle, SHORT afStyle, SHORT afAttr, ULONG hItem)
  190. { MENUITEM mi;
  191.  
  192.   mi.iPosition = iPosition;
  193.   mi.afStyle = afStyle;
  194.   mi.afAttribute = afAttr;
  195.   mi.id = sItemId;
  196.   mi.hwndSubMenu = hwndSubMenu;
  197.   mi.hItem = hItem;
  198.   return SHORT1FROMMR(WinSendMsg(hwndMenu, MM_INSERTITEM, (MPARAM)&mi, (MPARAM)ItemTitle));
  199. }
  200.  
  201. VOID InitTaskActionsMenu(HWND hwndMenu, LSWDATA *plswData,SHORT iMenuAtItem,BOOL bTaskBar,BOOL bGroup)
  202. { SHORT sItemId,sItemNum,sLastId,k,sAttr;
  203.   UCHAR ucBuf[64];
  204.   HWND hwndSubmenu;
  205.  
  206.   sItemNum = SHORT1FROMMR(WinSendMsg(hwndMenu,MM_QUERYITEMCOUNT,0,0));
  207.   while (sItemNum > 0) {
  208.     sItemId = SHORT1FROMMR(WinSendMsg(hwndMenu,MM_ITEMIDFROMPOSITION,
  209.                                       MPFROMSHORT(sItemNum-1),0));
  210.     sItemNum = SHORT1FROMMR(WinSendMsg(hwndMenu,
  211.                                        sItemId==CMD_XCENTERSUBMENU?MM_REMOVEITEM:MM_DELETEITEM,
  212.                                        MPFROM2SHORT(sItemId,FALSE),0));
  213.   }
  214.  
  215.   if (iMenuAtItem >= 0) {  //neither an empty spot on the taskbar nor the Desktop button, show context menu
  216.     for (sItemId = CMD_SWITCHFROMPM,sLastId=0; sItemId <= CMD_MOVE; sItemId++) {
  217.       if (!bTaskBar && sItemId==CMD_MOVE)
  218.         continue;
  219.       if (MenuNeedsItem(plswData,iMenuAtItem,sItemId,ucBuf,sizeof(ucBuf),bGroup)) {
  220.         if ((sItemId == CMD_CLOSE || sItemId == CMD_KILL || sLastId==CMD_SWITCHFROMPM) &&
  221.             SHORT1FROMMR(WinSendMsg(hwndMenu,MM_QUERYITEMCOUNT,0,0))>0)
  222.           InsertMenuItem(hwndMenu, NULLHANDLE, MIT_END, 0, "", MIS_SEPARATOR, 0,0);
  223.         InsertMenuItem(hwndMenu, NULLHANDLE, MIT_END, sItemId, ucBuf, MIS_TEXT, 0,0);
  224.         sLastId=sItemId;
  225.       }
  226.     }
  227.  
  228.     if (!IsDesktop(plswData->TaskArr[iMenuAtItem].hwnd)) {
  229.       WinLoadString(plswData->hab,plswData->hmodRes,CMD_CLOSE,sizeof(ucBuf),ucBuf);
  230.       if (SHORT1FROMMR(WinSendMsg(hwndMenu,MM_QUERYITEMCOUNT,0,0))>0)
  231.         InsertMenuItem(hwndMenu, NULLHANDLE, MIT_END, 0, "", MIS_SEPARATOR, 0,0);
  232.  
  233.       hwndSubmenu = WinCreateMenu(hwndMenu, NULL);
  234.  
  235.       if (hwndSubmenu != NULLHANDLE) {
  236.         WinSetWindowULong(hwndSubmenu,QWL_STYLE,
  237.                           WinQueryWindowULong(hwndSubmenu,QWL_STYLE) | MS_CONDITIONALCASCADE);
  238.         sItemId=InsertMenuItem(hwndMenu, hwndSubmenu, MIT_END, CMD_CLOSE, ucBuf, MIS_TEXT|MIS_SUBMENU, 0,0);
  239.  
  240.         if (sItemId != MIT_MEMERROR && sItemId != MIT_ERROR) {
  241.           sAttr = MIA_CHECKED;
  242.           if (MenuNeedsItem(plswData,iMenuAtItem,CMD_CLOSE,ucBuf,sizeof(ucBuf),bGroup)) {
  243.             InsertMenuItem(hwndSubmenu, NULLHANDLE, MIT_END, CMD_CLOSE, "SC_CLOSE", MIS_TEXT, MIA_CHECKED,0);
  244.             sAttr = 0;
  245.           }
  246.           InsertMenuItem(hwndSubmenu, NULLHANDLE, MIT_END, CMD_CLOSEQUIT, "WM_QUIT", MIS_TEXT, sAttr,0);
  247.  
  248.           if (MenuNeedsItem(plswData,iMenuAtItem,CMD_KILL,ucBuf,sizeof(ucBuf),bGroup))
  249.             InsertMenuItem(hwndSubmenu, NULLHANDLE, MIT_END, CMD_KILL, ucBuf, MIS_TEXT, 0,0);
  250.  
  251.           if (MenuNeedsItem(plswData,iMenuAtItem,CMD_DEATH,ucBuf,sizeof(ucBuf),bGroup))
  252.             InsertMenuItem(hwndSubmenu, NULLHANDLE, MIT_END, CMD_DEATH, ucBuf, MIS_TEXT, 0,0);
  253.         }
  254.       }
  255.     }
  256.  
  257.     if (MenuNeedsItem(plswData,iMenuAtItem,CMD_PRIORITY,ucBuf,sizeof(ucBuf),bGroup)) {
  258.       InsertMenuItem(hwndMenu, NULLHANDLE, MIT_END, 0, "", MIS_SEPARATOR, 0,0);
  259.       InsertMenuItem(hwndMenu, NULLHANDLE, MIT_END, CMD_PRIORITY, ucBuf, MIS_TEXT, 0,0);
  260.     }
  261.  
  262.     if (MenuNeedsItem(plswData,iMenuAtItem,CMD_ADDFILTER,ucBuf,sizeof(ucBuf),bGroup)) {
  263.       InsertMenuItem(hwndMenu, NULLHANDLE, MIT_END, 0, "", MIS_SEPARATOR, 0,0);
  264.       InsertMenuItem(hwndMenu, NULLHANDLE, MIT_END, CMD_ADDFILTER, ucBuf, MIS_TEXT, 0,0);
  265.     }
  266.   }
  267. #ifndef XWORKPLACE
  268.   else { //iMenuAtItem==-1, either an empty spot on the taskbar or the Desktop button, show generic menu
  269.     WinLoadString(plswData->hab,plswData->hmodRes,STRID_RUN,sizeof(ucBuf),ucBuf);
  270.     InsertMenuItem(hwndMenu, NULLHANDLE, MIT_END, CMD_RUN, ucBuf, MIS_TEXT, 0,0);
  271.     InsertMenuItem(hwndMenu, NULLHANDLE, MIT_END, 0, "", MIS_SEPARATOR, 0,0);
  272.     WinLoadString(plswData->hab,plswData->hmodRes,STRID_SUSPEND,sizeof(ucBuf),ucBuf);
  273.     InsertMenuItem(hwndMenu, NULLHANDLE, MIT_END, CMD_SUSPEND, ucBuf, MIS_TEXT, 0,0);
  274.     InsertMenuItem(hwndMenu, NULLHANDLE, MIT_END, 0, "", MIS_SEPARATOR, 0,0);
  275.     WinLoadString(plswData->hab,plswData->hmodRes,STRID_SHOWSETTINGS,sizeof(ucBuf),ucBuf);
  276.     InsertMenuItem(hwndMenu, NULLHANDLE, MIT_END, CMD_SHOWSETTINGS, ucBuf, MIS_TEXT, 0,0);
  277.     WinLoadString(plswData->hab,plswData->hmodRes,STRID_QUIT,sizeof(ucBuf),ucBuf);
  278.     InsertMenuItem(hwndMenu, NULLHANDLE, MIT_END, CMD_QUIT, ucBuf, MIS_TEXT, 0,0);
  279.   }
  280. #else
  281.   WinSetPresParam(plswData->pWidget->hwndContextMenu,PP_FONTNAMESIZE,7,"8.Helv");
  282.  
  283.   if (bTaskBar && iMenuAtItem >= 0) {
  284.   // now set the old context menu as submenu;
  285.     InsertMenuItem(hwndMenu, NULLHANDLE, MIT_END, 0, "", MIS_SEPARATOR, 0,0);
  286.  
  287.     WinLoadString(plswData->hab,plswData->hmodRes,STRID_XCENTERSUBMENU,sizeof(ucBuf),ucBuf);
  288.     InsertMenuItem(hwndMenu, plswData->pWidget->hwndContextMenu, MIT_END,
  289.                    CMD_XCENTERSUBMENU, ucBuf, MIS_TEXT | MIS_SUBMENU, 0,0);
  290.   }
  291. #endif
  292. }
  293.  
  294. VOID ShowMenu(LSWDATA *plswData,SHORT iMenuAtItem,BOOL bTaskBar,BOOL bGroup)
  295. { POINTL ptl;
  296.  
  297.   InitTaskActionsMenu(plswData->hwndMenu,plswData,iMenuAtItem,bTaskBar,bGroup);
  298.   WinQueryPointerPos(HWND_DESKTOP,&ptl);
  299. #ifdef XWORKPLACE
  300.   WinPopupMenu(HWND_DESKTOP, bTaskBar?plswData->hwndTaskBarClient:plswData->hwndPopClient,
  301.                (iMenuAtItem<0&&bTaskBar)?plswData->pWidget->hwndContextMenu:plswData->hwndMenu,
  302.                ptl.x, ptl.y,0, PU_HCONSTRAIN | PU_VCONSTRAIN | PU_MOUSEBUTTON1 | PU_MOUSEBUTTON2 | PU_KEYBOARD);
  303. #else
  304.   WinPopupMenu(HWND_DESKTOP, bTaskBar?plswData->hwndTaskBarClient:plswData->hwndPopClient,plswData->hwndMenu,
  305.                ptl.x, ptl.y,0, PU_HCONSTRAIN | PU_VCONSTRAIN | PU_MOUSEBUTTON1 | PU_MOUSEBUTTON2 | PU_KEYBOARD);
  306. #endif
  307. }
  308.  
  309. VOID ShowBubble(LSWDATA *plswData,SHORT iMouseIsAtItem,USHORT usX,USHORT usY,SHORT iFunc,UCHAR *ucTitle2)
  310. { static SHORT iMouseWasAtItem=-1,iCounter1=0,iBubbleAtItem=-1,iSource;
  311.   USHORT usSizeX,usSizeY;
  312.   POINTL aptl[TXTBOX_COUNT];
  313.   UCHAR ucTitle[NAMELEN];
  314.   HPS hps;
  315.   LONG cxScreen;
  316.   SWP swp;
  317.  
  318.   if (iFunc>0) {
  319.     if (iFunc<=10) { //iFunc==11 -- update bubble text
  320.       if (iMouseIsAtItem == iMouseWasAtItem || iMouseWasAtItem < 0)
  321.         iCounter1+=BUBBLETIMERINTERVAL;
  322.       else
  323.         iCounter1=0;
  324.       iMouseWasAtItem = iMouseIsAtItem;
  325.       iSource=iFunc;
  326.     }
  327.  
  328.     if ((iFunc<=10 && ((iCounter1 >= 800 /*ms*/&& iBubbleAtItem < 0) ||
  329.         (iBubbleAtItem >= 0  && iBubbleAtItem != iMouseIsAtItem))) ||
  330.         (iFunc==11 && iMouseIsAtItem==iBubbleAtItem)) {
  331.       if (ucTitle2==NULL)
  332.         GetItemTitle(plswData->TaskArr[iMouseIsAtItem].hsw,ucTitle,sizeof(ucTitle),FALSE);
  333.       else
  334.         strncpy(ucTitle,ucTitle2,sizeof(ucTitle)-1);
  335.       hps = WinGetPS(plswData->hwndBubble);
  336.       GpiQueryTextBox(hps,strlen(ucTitle),ucTitle,TXTBOX_COUNT,aptl);
  337.       WinReleasePS(hps);
  338.       if (iFunc==11) {
  339.         WinQueryWindowPos(plswData->hwndBubble,&swp);
  340.         usX = swp.x; usY = swp.y;
  341.       }
  342.       usSizeX = aptl[TXTBOX_TOPRIGHT].x-aptl[TXTBOX_TOPLEFT].x+8;
  343.       usSizeY = aptl[TXTBOX_TOPLEFT].y-aptl[TXTBOX_BOTTOMLEFT].y+4;
  344.       cxScreen=WinQuerySysValue(HWND_DESKTOP,SV_CXSCREEN);
  345.       if (usX+usSizeX>cxScreen) usX-=usX+usSizeX-cxScreen;
  346.       WinSetWindowPos(plswData->hwndBubble,HWND_TOP,
  347.                       usX,usY,usSizeX,usSizeY,
  348.                       SWP_MOVE | SWP_SIZE | SWP_SHOW | SWP_ZORDER);
  349.       WinSetWindowPos(WinWindowFromID(plswData->hwndBubble,ID_BUBBLEFRAME),0,0,0,
  350.                       usSizeX,usSizeY, SWP_MOVE | SWP_SIZE | SWP_SHOW);
  351.       WinSetWindowText(plswData->hwndBubble,ucTitle);
  352.       iBubbleAtItem = iMouseIsAtItem;
  353.     } else if (iBubbleAtItem>=0 &&
  354.                (WinQueryWindowPos(plswData->hwndBubble,&swp),
  355.                 aptl[0].x=swp.x,aptl[0].y=aptl[1].y=swp.y+swp.cy-1,aptl[1].x=swp.x+swp.cx-1,
  356.                 WinWindowFromPoint(HWND_DESKTOP,&aptl[0],FALSE)!=plswData->hwndBubble ||
  357.                 WinWindowFromPoint(HWND_DESKTOP,&aptl[1],FALSE)!=plswData->hwndBubble
  358.               )) {
  359.       WinSetWindowPos(plswData->hwndBubble,HWND_TOP,0,0,0,0,SWP_ZORDER);
  360.       WinInvalidateRect(plswData->hwndBubble,NULL,TRUE);
  361.     }
  362.   } else if (abs(iFunc)==iSource) {
  363.     UCHAR ucBuf[32];
  364.  
  365.     if (WinIsWindowVisible(plswData->hwndBubble))
  366.       WinSetWindowPos(plswData->hwndBubble,HWND_BOTTOM,0,0,0,0,SWP_HIDE | SWP_ZORDER);
  367.     iBubbleAtItem = -1;
  368.     iMouseWasAtItem = -1;
  369.     iCounter1 = 0;
  370.  
  371.     WinQueryPresParam(plswData->hwndBubble,PP_BACKGROUNDCOLOR,0,NULL,sizeof(ucBuf),ucBuf,QPF_NOINHERIT);
  372.     plswData->Settings.lBubbleRGBCol = ucBuf[0]+ucBuf[1]*256+ucBuf[2]*65536;
  373.     WinQueryPresParam(plswData->hwndBubble,PP_FOREGROUNDCOLOR,0,NULL,sizeof(ucBuf),ucBuf,QPF_NOINHERIT);
  374.     plswData->Settings.lBubbleTextRGBCol = ucBuf[0]+ucBuf[1]*256+ucBuf[2]*65536;
  375.   }
  376. }
  377.  
  378. BOOL IsWindowClass(HWND hwnd,UCHAR *pszClassName)
  379. { UCHAR ucBuf[128];
  380.  
  381.   WinQueryClassName(hwnd,sizeof(ucBuf),ucBuf);
  382.   return (strcmp(ucBuf,pszClassName)==0);
  383. }
  384.  
  385. PVOID GetSwitchList(HAB hab,BOOL bInit,ULONG *ItemCount)
  386. { static PSWBLOCK pSwb=NULL;
  387.   static ULONG ulItemCount,ulRecCount=0;
  388.  
  389.   if (bInit) {
  390.     ulRecCount++;
  391.     if (pSwb!=NULL) {
  392.       *ItemCount=ulItemCount;
  393.       return pSwb;
  394.     }
  395.     if ((ulItemCount = WinQuerySwitchList(hab, NULL, 0))==0 ||
  396.         (pSwb=malloc(sizeof(HSWITCH)+sizeof(SWENTRY)*ulItemCount))==NULL) {
  397.       return NULL;
  398.     }
  399.     /* get all switch entries in one call; calling WinQuerySwitchHandle/SwitchEntry
  400.      for each window turns out to be noticeably slower */
  401.     ulItemCount = WinQuerySwitchList(hab,pSwb,sizeof(HSWITCH)+sizeof(SWENTRY)*ulItemCount);
  402.     *ItemCount=ulItemCount;
  403.     return pSwb;
  404.   } else {
  405.     ulRecCount--;
  406.     if (ulRecCount==0) {
  407.       if (pSwb!=NULL) free(pSwb);
  408.       pSwb=NULL;
  409.     }
  410.     return NULL;
  411.   }
  412. }
  413.  
  414. BOOL IsMinToViewer(HWND hwnd,ULONG flopt)
  415. {
  416.   return
  417.     ((flopt & SWP_MINIMIZE) && WinQueryWindowUShort(hwnd,QWS_YMINIMIZE)==33536);
  418. }
  419.  
  420. //returns TRUE if any window part is currently within desktop (with some probability<100%)
  421. BOOL IsInDesktop(HWND hwnd)
  422. { SWP swp;
  423.   USHORT usCXScreen=WinQuerySysValue(HWND_DESKTOP,SV_CXSCREEN),
  424.   usCYScreen=WinQuerySysValue(HWND_DESKTOP,SV_CYSCREEN);
  425.  
  426.   WinQueryWindowPos(hwnd,&swp);
  427.   return (
  428.      (swp.x<usCXScreen && swp.y<usCYScreen && swp.x>=0 && swp.y>=0) ||
  429.      (swp.x+swp.cx<usCXScreen && swp.y<usCYScreen && swp.x+swp.cx>=0 && swp.y>=0) ||
  430.      (swp.x<usCXScreen && swp.y+swp.cy<usCYScreen && swp.x>=0 && swp.y+swp.cy>=0) ||
  431.      (swp.x+swp.cx<usCXScreen && swp.y+swp.cy<usCYScreen && swp.x+swp.cx>=0 && swp.y+swp.cy>=0) ||
  432.      (swp.x+swp.cx/2<usCXScreen && swp.y+swp.cy/2<usCYScreen && swp.x+swp.cx/2>=0 && swp.y+swp.cy/2>=0) ||
  433.      (swp.x+swp.cx/3<usCXScreen && swp.y+swp.cy/3<usCYScreen && swp.x+swp.cx/3>=0 && swp.y+swp.cy/3>=0) ||
  434.      (swp.x+swp.cx*2/3<usCXScreen && swp.y+swp.cy/3<usCYScreen && swp.x+swp.cx*2/3>=0 && swp.y+swp.cy/3>=0) ||
  435.      (swp.x+swp.cx/3<usCXScreen && swp.y+swp.cy*2/3<usCYScreen && swp.x+swp.cx/3>=0 && swp.y+swp.cy*2/3>=0) ||
  436.      (swp.x+swp.cx*2/3<usCXScreen && swp.y+swp.cy*2/3<usCYScreen && swp.x+swp.cx*2/3>=0 && swp.y+swp.cy*2/3>=0)
  437.     );
  438. }
  439.  
  440. //get the virtual desktop number relative to the one on which the program was started
  441. LONG GetCurrDesktop(LSWDATA *plswData)
  442. { USHORT usCXScreen=WinQuerySysValue(HWND_DESKTOP,SV_CXSCREEN),
  443.          usCYScreen=WinQuerySysValue(HWND_DESKTOP,SV_CYSCREEN);
  444.   SWP swp;
  445.   SHORT x,y;
  446.  
  447.   if (plswData->bNowActive) return -1;
  448.  
  449.   WinQueryWindowPos(plswData->hwndPopup,&swp);
  450.   x=(POPUPWINHIDEPOSX-swp.x)/usCXScreen;
  451.   y=(POPUPWINHIDEPOSY-swp.y)/usCYScreen;
  452.   return ((x<<8)+y);
  453. }
  454.  
  455. VOID MinimizeHideAll(LSWDATA *plswData, BOOL bReset, HWND hwndReset)
  456. { SHORT i;
  457.   HSWITCH hswDesktop;
  458.   static USHORT usNumWin;
  459.   static BOOL bRestoreAll=FALSE;
  460.   static LONG lDskNum;
  461.   static HWND *hwndList=NULL;
  462.  
  463.   if (bReset) {
  464.     if (hwndList!=NULL)
  465.     for (i=0;i<usNumWin;i++)
  466.       if (hwndReset==hwndList[i]) {
  467.         free(hwndList); hwndList=NULL;
  468.         bRestoreAll=FALSE;
  469.         break;
  470.       }
  471.     return;
  472.   }
  473.  
  474.   if (!bRestoreAll) {
  475.     if (hwndList!=NULL) free(hwndList);
  476.     hswDesktop=plswData->TaskArr[plswData->usCurrItem].hsw;
  477.     InitTaskArr(plswData,FALSE,FALSE,FALSE);
  478.     if ((hwndList=malloc(plswData->usItems*sizeof(HWND)))!=NULL)
  479.       for (i = plswData->usItems-2,usNumWin=0; i >= 0; i--) {
  480. //make sure the window is in the current virtual desktop and not minimized or hidden
  481.         if (!(plswData->TaskArr[i].fl&(SWP_MINIMIZE|SWP_HIDE))&&IsInDesktop(plswData->TaskArr[i].hwnd)) {
  482.           if (ChangeWindowPos(plswData,i,CMD_HIDE) || ChangeWindowPos(plswData,i,CMD_MINIMIZE))
  483.             hwndList[usNumWin++]=plswData->TaskArr[i].hwnd;
  484.         }
  485.       }
  486.     lDskNum=GetCurrDesktop(plswData);
  487.     WinSwitchToProgram(hswDesktop);
  488.   } else {
  489.     if (hwndList==NULL || lDskNum!=GetCurrDesktop(plswData)) return;
  490.  
  491.     for (i=0;i<usNumWin;i++) {
  492.       WinSetWindowPos(hwndList[i],HWND_TOP,0,0,0,0,SWP_SHOW|SWP_ZORDER);
  493.       WinSwitchToProgram(WinQuerySwitchHandle(hwndList[i],0));
  494.     }
  495.  
  496.     free(hwndList); hwndList=NULL;
  497.   }
  498.  
  499.   bRestoreAll ^= TRUE;
  500. }
  501.  
  502.  
  503. VOID GetItemTitle(HSWITCH hsw,UCHAR *ucTitle,USHORT usLen,BOOL bSessNum)
  504. { SWCNTRL swctl;
  505.   USHORT k;
  506.  
  507.   if (WinQuerySwitchEntry(hsw, &swctl)!=0) {
  508.     strcpy(ucTitle,"");
  509.     return;
  510.   }
  511.  
  512.   if (bSessNum)
  513.     sprintf(ucTitle,"%.*s (0x%X)",usLen-6,swctl.szSwtitle,swctl.idProcess);
  514.   else
  515.     strncpy(ucTitle,swctl.szSwtitle,usLen-1);
  516.  
  517.   for (k=0;k<strlen(ucTitle);k++)
  518.     if (ucTitle[k]=='\r' || ucTitle[k]=='\n') ucTitle[k]=' ';
  519. }
  520.  
  521.  
  522. HPOINTER GetItemIcon(HWND hwnd)
  523. { HPOINTER hIcon;
  524.   UCHAR *pszPath;
  525.   HWND hwnd1;
  526.  
  527.   if ((hIcon=(HPOINTER)WinSendMsg(hwnd,WM_QUERYICON,0,0))!=NULLHANDLE)
  528.     return hIcon;
  529.  
  530.   if (IsWindowClass((hwnd1=WinWindowFromID(hwnd,FID_CLIENT)),"SeamlessClass")) {
  531.     pszPath = (UCHAR *)WinQueryWindowULong(hwnd1,0L);
  532.     hIcon=WinLoadFileIcon(pszPath,FALSE);
  533.   } /*else {
  534.     ULONG ulItemCount;
  535.     LONG k;
  536.     PSWBLOCK pSwb;
  537.     PID pid;
  538.     TID tid;
  539.  
  540.     if ((pSwb=GetSwitchList(0,TRUE,&ulItemCount))!=NULL) {
  541.       for (k=ulItemCount-1;k>=0 && hIcon==NULLHANDLE;k--) {
  542.         WinQueryWindowProcess(hwnd,&pid,&tid);
  543.         if (pSwb->aswentry[k].swctl.hwnd!=hwnd && pSwb->aswentry[k].swctl.idProcess==pid)
  544.           hIcon=(HPOINTER)WinSendMsg(pSwb->aswentry[k].swctl.hwnd,WM_QUERYICON,0,0);
  545.       }
  546.       GetSwitchList(0,FALSE,NULL);
  547.     }
  548.   }*/
  549.  
  550.   if (hIcon == NULLHANDLE)
  551.     hIcon = WinQuerySysPointer(HWND_DESKTOP,SPTR_PROGRAM,FALSE);
  552.  
  553.   return hIcon;
  554. }
  555.  
  556. PSZ GetObjectName(USHORT usObjHandle)
  557. { UCHAR ucKey[16],*pucObjData,*substr=NULL,*pszName=NULL;
  558.   ULONG k,ulDataSize;
  559.  
  560.   if ((pucObjData=malloc(ulDataSize=1024))==NULL) return NULL;
  561.   sprintf(ucKey,"%X",usObjHandle);
  562.   if (PrfQueryProfileData(HINI_USERPROFILE,"PM_Abstract:Objects",ucKey,pucObjData,&ulDataSize))
  563.     for (k=0,substr=NULL;substr==NULL && k<ulDataSize-strlen("WPAbstract");k++)
  564.       if ((substr=strstr(&pucObjData[k],"WPAbstract"))!=NULL) substr+=17;
  565.  
  566.   if (substr!=NULL) pszName=strdup(substr);
  567.   free(pucObjData);
  568.   return pszName;
  569. }
  570.  
  571. BOOL IsDesktop(HWND hwnd)
  572. {
  573.   return (hwnd==WinQueryWindow(HWND_DESKTOP,QW_BOTTOM) &&
  574.           (IsWindowClass(hwnd,"wpFolder window")));
  575. }
  576.  
  577. //Written by Staffan Ulfberg
  578. char Match(char *string, char *pattern)
  579. {
  580.   for (; '*'^*pattern; ++pattern, ++string) {
  581.     if (!*string)
  582.       return (!*pattern);
  583.     if (toupper(*string)^toupper(*pattern) && '?'^*pattern)
  584.       return FALSE;
  585.   }
  586.   /* two-line patch to prevent *too* much recursiveness: */
  587.   while('*' == pattern[1])
  588.     pattern++;
  589.   do {
  590.     if ( Match(string, pattern + 1) )
  591.       return TRUE;
  592.   } while (*string++);
  593.   return FALSE;
  594. }
  595.  
  596.  
  597. BOOL IsInSkipList(LSWSETTINGS *pSettings,UCHAR *ucTitle,BOOL bTskBar)
  598. { BOOL bFound;
  599.   USHORT j;
  600.   SKIPLIST *pSkipList;
  601.  
  602.   pSkipList = bTskBar ? &pSettings->SkipListTskBar : &pSettings->SkipListPopup;
  603.   for (j = 0, bFound = FALSE;
  604.        j < MAXITEMS && (*pSkipList)[j]!=NULL &&
  605.          !(bFound=Match(ucTitle, (*pSkipList)[j]));
  606.        j++);
  607.  
  608.   return bFound;
  609. }
  610.  
  611.  
  612. VOID InitTaskArr(LSWDATA *plswData,BOOL bFullScreen,BOOL bTaskBar,BOOL bUseFilters)
  613. { ULONG sidCurr,ulItemCount,ulItem;
  614.   PSWBLOCK pSwb;
  615.   HENUM henum;
  616.   HWND hwndNext,hwndActive;
  617.   SWP swp;
  618.   UCHAR ucIndex;
  619.   SWITEM ditem;
  620.   BOOL bFound,bIsCurrent;
  621.  
  622.   sidCurr = 0;
  623.   hwndActive = NULLHANDLE;
  624.  
  625.   plswData->usItems = plswData->usCurrItem = plswData->iShift = 0;
  626.   memset(plswData->TaskArr,0,sizeof(plswData->TaskArr));
  627.  
  628.   if ((pSwb=GetSwitchList(plswData->hab,TRUE,&ulItemCount))==NULL) return;
  629. /* get SID of the current fullscreen process */
  630.   if (bFullScreen) {
  631.     if (DosQuerySysInfo(24,24,&sidCurr,sizeof(sidCurr))!=0) sidCurr=0;
  632.   } else {
  633.     hwndActive = WinQueryActiveWindow(WinQueryDesktopWindow(plswData->hab,NULLHANDLE));
  634.   }
  635.  
  636.   henum = WinBeginEnumWindows(WinQueryDesktopWindow(plswData->hab,NULLHANDLE));
  637.  
  638.   while ((hwndNext = WinGetNextWindow(henum))!=NULLHANDLE && plswData->usItems < MAXITEMS-1) {
  639.     for (ulItem = 0, bFound = FALSE; ulItem < ulItemCount; ulItem++)
  640.       if ((bFound=(hwndNext == pSwb->aswentry[ulItem].swctl.hwnd))==TRUE) break;
  641.  
  642.     if (!bFound || !WinIsWindow(plswData->hab,hwndNext) ||
  643.         pSwb->aswentry[ulItem].swctl.uchVisibility != SWL_VISIBLE)
  644.       continue;
  645.  
  646.     WinQueryWindowPos(hwndNext,&swp);
  647.  
  648.     bFound = (!bUseFilters || (sidCurr == pSwb->aswentry[ulItem].swctl.idSession ||
  649.                (((bTaskBar?plswData->Settings.bShowHiddenTskBar:plswData->Settings.bShowHidden) || !(swp.fl & SWP_HIDE)) &&
  650.                 ((bTaskBar?plswData->Settings.bShowViewerTskBar:plswData->Settings.bShowViewer) || !IsMinToViewer(hwndNext,swp.fl)))) &&
  651.               !IsInSkipList(&plswData->Settings, pSwb->aswentry[ulItem].swctl.szSwtitle,bTaskBar));
  652.  
  653.     /* save the current entry in the last element of the array even if it's
  654.      not supposed to be switched to. It will be used if switching is cancelled */
  655.     bIsCurrent = ((!bFullScreen &&
  656.                   (hwndNext == hwndActive ||
  657.                    hwndNext == WinQueryWindow(hwndActive,QW_OWNER))) ||
  658.                   (bFullScreen && pSwb->aswentry[ulItem].swctl.idSession == sidCurr));
  659.  
  660.     if (bFound) {
  661.       ucIndex = plswData->usItems;
  662.       plswData->usItems++;
  663.     } else if (bIsCurrent)
  664.       ucIndex = MAXITEMS-1;
  665.     else
  666.       continue;
  667.  
  668.     plswData->TaskArr[ucIndex].ulType = pSwb->aswentry[ulItem].swctl.bProgType;
  669.     plswData->TaskArr[ucIndex].fl = swp.fl;
  670.     plswData->TaskArr[ucIndex].hsw = pSwb->aswentry[ulItem].hswitch;
  671.     plswData->TaskArr[ucIndex].hwnd = hwndNext;
  672.     plswData->TaskArr[ucIndex].hIcon = GetItemIcon(hwndNext);
  673.     plswData->TaskArr[ucIndex].pid = pSwb->aswentry[ulItem].swctl.idProcess;
  674.  
  675.     if (bFound && bIsCurrent) {
  676.       memcpy(&plswData->TaskArr[MAXITEMS-1],&plswData->TaskArr[ucIndex],sizeof(SWITEM));
  677.       /* make sure current session or window is in the 0th element of the TaskArr */
  678.       if (ucIndex != 0) {
  679.         memcpy(&ditem,&plswData->TaskArr[ucIndex],sizeof(ditem));
  680.         memmove(&plswData->TaskArr[1],&plswData->TaskArr[0],sizeof(ditem)*ucIndex);
  681.         memcpy(&plswData->TaskArr[0],&ditem,sizeof(ditem));
  682.       }
  683.     }
  684.   }
  685.  
  686.   WinEndEnumWindows(henum);
  687.  
  688.   GetSwitchList(0,FALSE,NULL);
  689.  
  690.   if (plswData->TaskArr[MAXITEMS-1].hsw == 0)
  691.     plswData->TaskArr[MAXITEMS-1].hwnd = hwndActive;
  692. }
  693.  
  694. BOOL AddFilter(LSWSETTINGS *pSettings,UCHAR *ucName,BOOL bTskBar)
  695. { SHORT iNum;
  696.   SKIPLIST *pSkipList;
  697.  
  698.   pSkipList = bTskBar?&pSettings->SkipListTskBar:&pSettings->SkipListPopup;
  699.  
  700.   if (strlen(ucName)==0 || IsInSkipList(pSettings,ucName,bTskBar)) return FALSE;
  701.  
  702.   for (iNum=0; (*pSkipList)[iNum]!=NULL && iNum<MAXITEMS; iNum++);
  703.   if (iNum==MAXITEMS) return FALSE;
  704.  
  705.   (*pSkipList)[iNum++]=strdup(ucName);
  706.   return TRUE;
  707. }
  708.  
  709. BOOL RemoveFilter(LSWSETTINGS *pSettings,UCHAR *ucName,BOOL bTskBar)
  710. { SHORT iNum,k;
  711.   SKIPLIST *pSkipList;
  712.  
  713.   pSkipList = bTskBar?&pSettings->SkipListTskBar:&pSettings->SkipListPopup;
  714.  
  715.   for (iNum=0; (*pSkipList)[iNum]!=NULL && iNum<MAXITEMS; iNum++);
  716.  
  717.   for (k = 0; k < iNum; k++)
  718.     if (strcmp((*pSkipList)[k],ucName)==0) {
  719.       free((*pSkipList)[k]);
  720.       memmove(&(*pSkipList)[k], &(*pSkipList)[k+1],
  721.               sizeof(pSettings->SkipListPopup[0])*(iNum-k-1));
  722.       (*pSkipList)[--iNum]=NULL;
  723.       return TRUE;
  724.     }
  725.  
  726.   return FALSE;
  727. }
  728.  
  729. USHORT RunCommand(LSWDATA *plswData,UCHAR *ucCommand,UCHAR *ucErrMsg,USHORT usErrMsgLen)
  730. { STARTDATA SData;
  731.   UCHAR k,ucCmdLine[_MAX_PATH]="",ucPath[_MAX_PATH],ucPgmInp[_MAX_PATH],
  732.     drive[_MAX_DRIVE],dir[_MAX_DIR],name[_MAX_FNAME],ext[_MAX_EXT],*args;
  733.   static UCHAR ucExtStr[4][4]={"bat\0","cmd\0","com\0","exe\0"};
  734.   APIRET rc;
  735.   PID pid;
  736.   ULONG ulSessID,ulAppType;
  737.  
  738.   if ((args=strchr(ucCommand,' '))!=NULL) {
  739.     strcpy(ucCmdLine,args);
  740.     *args='\0';
  741.   }
  742.   strcpy(ucPath,ucCommand);
  743.  
  744.   _splitpath(ucPath,drive,dir,name,ext);
  745.  
  746.   for (k=0,rc=0;k<(strlen(ext)==0?4:1);k++) { //add an extension if needed and find if file exists
  747.     if (strlen(ext)==0) _makepath(ucPath,drive,dir,name,ucExtStr[k]);
  748.     ulAppType=0;
  749.     rc=DosQueryAppType(ucPath,&ulAppType);
  750.     if (rc==0 || rc==191 || rc==193)
  751.       break;
  752.     else
  753.       strncpy(ucPath,name,sizeof(ucPath));
  754.   }
  755.  
  756.   memset(&SData,0,sizeof(SData));
  757.   SData.Length  = sizeof(SData);
  758.   SData.Related = SSF_RELATED_INDEPENDENT;
  759.   SData.FgBg    = SSF_FGBG_FORE;
  760.   SData.TraceOpt = SSF_TRACEOPT_NONE;
  761.   SData.InheritOpt = SSF_INHERTOPT_SHELL;
  762.   SData.PgmControl = SSF_CONTROL_VISIBLE;
  763.   SData.SessionType = SSF_TYPE_DEFAULT;
  764.  
  765.   if (ulAppType==0x20 || strcmpi(ucPath + strlen(ucPath) - 4, ".BAT") == 0)
  766.     SData.SessionType = SSF_TYPE_WINDOWEDVDM;
  767.  
  768.   if (ulAppType&(FAPPTYP_WINDOWSREAL|FAPPTYP_WINDOWSPROT|FAPPTYP_WINDOWSPROT31)) {
  769.     SData.PgmName="WINOS2.COM";
  770.     sprintf(ucPgmInp, "/3 %s %s", ucPath, ucCmdLine);
  771.     SData.SessionType = PROG_31_ENHSEAMLESSCOMMON;
  772.   } else if (rc!=0 || strcmpi(ucPath + strlen(ucPath) - 4, ".CMD") == 0) {
  773.     sprintf(ucPgmInp, "/C%s %s", ucPath, ucCmdLine);
  774.   } else {
  775.     SData.PgmName = ucPath;
  776.     strcpy(ucPgmInp, ucCmdLine);
  777.   }
  778.   SData.PgmInputs = ucPgmInp;
  779.  
  780.   if ((rc=DosStartSession(&SData, &ulSessID, &pid))!=0) {
  781.     WinLoadString(plswData->hab,plswData->hmodRes,MSG_CANTEXECUTE,usErrMsgLen,ucErrMsg);
  782.     strncat(ucErrMsg,SData.PgmName,usErrMsgLen-strlen(ucErrMsg)-1);
  783.     return rc;
  784.   }
  785.  
  786.   return 0;
  787. }
  788.  
  789. VOID SetControlsFont(HWND hwnd,BOOL bDoTitleBar)
  790. { ULONG aulSysInfo[2]={0};
  791.   UCHAR ucFont[FACESIZE];
  792.   HWND hwndCtl;
  793.   HENUM henum;
  794.  
  795.   DosQuerySysInfo(QSV_VERSION_MAJOR, QSV_VERSION_MINOR,aulSysInfo,sizeof(aulSysInfo));
  796.   strcpy(ucFont,(aulSysInfo[0]==20 && aulSysInfo[1]>=40)?DEFTITLEFONT4:DEFTITLEFONT3);
  797.  
  798.   henum = WinBeginEnumWindows(hwnd);
  799.   while ((hwndCtl=WinGetNextWindow(henum))!=NULLHANDLE) {
  800.     if (!bDoTitleBar && IsWindowClass(hwndCtl,"#9")) continue;
  801.     WinSetPresParam(hwndCtl,PP_FONTNAMESIZE,strlen(ucFont)+1,ucFont);
  802.   }
  803.   WinEndEnumWindows(henum);
  804. }
  805.  
  806. VOID GetStartupDir(UCHAR *ucDir,USHORT usLen)
  807. { PPIB ppib;
  808.   PTIB ptib;
  809.   SHORT k;
  810.  
  811. #ifndef XWORKPLACE
  812.   DosGetInfoBlocks(&ptib,&ppib);
  813.   DosQueryModuleName(ppib->pib_hmte, usLen, ucDir);
  814. #else
  815.   DosQueryModuleName(hmodWidgetDll, usLen, ucDir);
  816. #endif
  817.  
  818.   for (k = strlen(ucDir)-1; ucDir[k] != '\\' && k >= 0; k--);
  819.   ucDir[k+1] = '\0';
  820. }
  821.  
  822. BOOL queryAppInstance(VOID)
  823. { HEV hev;
  824.  
  825.   if (hev=0, DosOpenEventSem(SEMRUNNINGNAME,&hev))
  826.     return FALSE;
  827.   else {
  828.     DosCloseEventSem(hev);
  829.     return TRUE;
  830.   }
  831. }
  832.  
  833. BOOL UpdateWinFlags(ULONG *OldFlags,ULONG NewFlags)
  834. { BOOL bNeedUpdate;
  835.  
  836.   NewFlags &= (SWP_MINIMIZE|SWP_MAXIMIZE|SWP_RESTORE|SWP_SHOW|SWP_HIDE|
  837.                SWP_ACTIVATE|SWP_DEACTIVATE);
  838.  
  839.   bNeedUpdate = (((NewFlags & SWP_MINIMIZE) && !(*OldFlags & SWP_MINIMIZE)) ||
  840.                  ((NewFlags & SWP_ACTIVATE) && !(*OldFlags & SWP_ACTIVATE)) ||
  841.                  ((NewFlags & SWP_DEACTIVATE) && !(*OldFlags & SWP_DEACTIVATE)) ||
  842.                  ((NewFlags & SWP_SHOW) && !(*OldFlags & SWP_SHOW)) ||
  843.                  ((NewFlags & SWP_HIDE) && !(*OldFlags & SWP_HIDE)) ||
  844.                  ((NewFlags & SWP_RESTORE) && (*OldFlags & SWP_MINIMIZE)) ||
  845.                  ((NewFlags & SWP_MAXIMIZE) && (*OldFlags & SWP_MINIMIZE))
  846.                 );
  847.  
  848.   *OldFlags |= NewFlags;
  849.  
  850.   if (NewFlags & SWP_MINIMIZE) *OldFlags &= (~(SWP_RESTORE|SWP_MAXIMIZE));
  851.   if (NewFlags & SWP_RESTORE)  *OldFlags &= (~(SWP_MINIMIZE|SWP_MAXIMIZE));
  852.   if (NewFlags & SWP_MAXIMIZE) *OldFlags &= (~(SWP_MINIMIZE|SWP_RESTORE));
  853.  
  854.   if (NewFlags & SWP_HIDE) *OldFlags &= (~SWP_SHOW);
  855.   if (NewFlags & SWP_SHOW) *OldFlags &= (~SWP_HIDE);
  856.  
  857.   if (NewFlags & SWP_ACTIVATE)   *OldFlags &= (~SWP_DEACTIVATE);
  858.   if (NewFlags & SWP_DEACTIVATE) *OldFlags &= (~SWP_ACTIVATE);
  859.  
  860.   return bNeedUpdate;
  861. }
  862.  
  863. VOID MakeFitStr(HPS hps,UCHAR *ucStr,USHORT usStrLen, USHORT usStrWid)
  864. { USHORT k,usLen;
  865.   POINTL aptl[TXTBOX_COUNT], ptlStart, *ptlStr;
  866.  
  867.   usLen = strlen(ucStr);
  868.   ptlStr = malloc(sizeof(POINTL)*(usLen+1));
  869.   ptlStart.x = ptlStart.y = 0;
  870.  
  871.   GpiQueryCharStringPosAt(hps, &ptlStart, 0, usLen, ucStr, NULL, ptlStr);
  872.   if (ptlStr[usLen].x <= usStrWid) {
  873.     free(ptlStr);
  874.     return;
  875.   }
  876.  
  877.   GpiQueryTextBox(hps,2,"..",TXTBOX_COUNT,aptl);
  878.  
  879.   k = usLen;
  880.   do {
  881.     k--;
  882.   } while (ptlStr[k].x+(aptl[TXTBOX_BOTTOMRIGHT].x-aptl[TXTBOX_BOTTOMLEFT].x) >
  883.            usStrWid && k > 0);
  884.  
  885.   ucStr[k]='\0';
  886.   if (k > 0) strncat(ucStr,"..",usStrLen-k-2);
  887.  
  888.   free(ptlStr);
  889. }
  890.  
  891. USHORT FindResDll(UCHAR *ucDllName, USHORT usNameLen, UCHAR *ucLang, UCHAR *ucLangStr, USHORT usLangStrLen)
  892. { static UCHAR ucDir[_MAX_PATH],ucName[_MAX_PATH],ucErr[32];
  893.   static HDIR hdir = HDIR_CREATE;
  894.   HMODULE hmodRes;
  895.   FILEFINDBUF3 FindBuffer = {0};
  896.   ULONG ulResultBufLen, ulFindCount;
  897.   APIRET rc;
  898.   RESVERPROC *ResVerProc;
  899.   ULONG ulVer;
  900.  
  901.   ulResultBufLen = sizeof(FILEFINDBUF3);
  902.   ulFindCount = 1;
  903.   *ucLang = 0;
  904.  
  905.   if (hdir == HDIR_CREATE) {
  906.     GetStartupDir(ucDir,sizeof(ucDir));
  907.     sprintf(ucName,"%s*.dll",ucDir);
  908.     rc = DosFindFirst(ucName, &hdir, FILE_NORMAL, &FindBuffer, ulResultBufLen, &ulFindCount, FIL_STANDARD);
  909.   } else
  910.     rc = DosFindNext(hdir, &FindBuffer, ulResultBufLen, &ulFindCount);
  911.  
  912.   if (rc == 0) {
  913.     sprintf(ucName,"%s%s",ucDir,FindBuffer.achName);
  914.     if (DosLoadModule(ucErr, sizeof(ucErr), ucName, &hmodRes)==0) {
  915.       if (DosQueryProcAddr(hmodRes, 0, "QueryResourceVersion", &ResVerProc)==0 &&
  916.           (ulVer = ResVerProc(ucLangStr,usLangStrLen),
  917.             (LOUCHAR(LOUSHORT(ulVer)) >= LASTINIVERMAJOROK &&
  918.              HIUCHAR(LOUSHORT(ulVer)) >= LASTINIVERMINOROK &&
  919.              LOUCHAR(HIUSHORT(ulVer)) >= LASTINIREVISIONOK))) {
  920.         *ucLang = HIUCHAR(HIUSHORT(ulVer));
  921.         strncpy(ucDllName,ucName,usNameLen);
  922.       }
  923.       DosFreeModule(hmodRes);
  924.     }
  925.   } else {
  926.     DosFindClose(hdir);
  927.     hdir = HDIR_CREATE;
  928.     return 0;
  929.   }
  930.   return 1;
  931. }
  932.  
  933. HMODULE LoadResource(UCHAR ucLang, LSWDATA *plswData, BOOL bEngOk)
  934. { static UCHAR ucDllName[_MAX_PATH], ucLangStr[32], ucResLang, ucErr[32], ucFoundDllName[_MAX_PATH];
  935.   HMODULE hmodRes;
  936.   USHORT usFound = 0;
  937.  
  938.   while (FindResDll(ucDllName, sizeof(ucDllName), &ucResLang, ucLangStr, sizeof(ucLangStr)))
  939.     if (ucResLang!=0) {
  940.       if (ucResLang==ucLang)
  941.         usFound = 1;
  942.       else if (bEngOk && ucResLang==ENGLISH && usFound==0)
  943.         usFound = 2;
  944.       else
  945.         continue;
  946.       strcpy(ucFoundDllName,ucDllName);
  947.     }
  948.  
  949.   if (usFound && DosLoadModule(ucErr, sizeof(ucErr), ucFoundDllName, &hmodRes)==0) {
  950.     if ((plswData->haccAlt = WinLoadAccelTable(plswData->hab,hmodRes,ID_ALTACCELTABLE))==0 ||
  951.         (plswData->haccCtrl = WinLoadAccelTable(plswData->hab,hmodRes,ID_CTRLACCELTABLE))==0 ||
  952.         (plswData->haccNoAlt = WinLoadAccelTable(plswData->hab,hmodRes,ID_NOALTACCELTABLE))==0) {
  953.       DosFreeModule(hmodRes);
  954.       return 0;
  955.     } else {
  956.       plswData->Settings.ucLanguage = (usFound==1?ucLang:ENGLISH);
  957.       return hmodRes;
  958.     }
  959.   } else
  960.     return 0;
  961. }
  962.  
  963. typedef struct _MSGSTRUCT {
  964.   HWND hwnd;
  965.   ULONG ulMsgid;
  966.   MPARAM mpParam1, mpParam2;
  967.   MRESULT mrRes;
  968.   HEV hev;
  969. } MSGSTRUCT;
  970.  
  971. typedef MSGSTRUCT *pMSGSTRUCT;
  972.  
  973. VOID SendMsgThread(VOID *pParm)
  974. { LSWDATA *plswData=NULL;
  975.   HMQ hmq;
  976.  
  977.   DosGetNamedSharedMem((PVOID*)&plswData,SHAREMEM_NAME,PAG_READ | PAG_WRITE);
  978.   hmq = WinCreateMsgQueue(plswData->hab, 0);
  979.   DosFreeMem(plswData);
  980.  
  981.   ((pMSGSTRUCT)pParm)->mrRes=
  982.      WinSendMsg(((pMSGSTRUCT)pParm)->hwnd,((pMSGSTRUCT)pParm)->ulMsgid,
  983.                 ((pMSGSTRUCT)pParm)->mpParam1,((pMSGSTRUCT)pParm)->mpParam2);
  984.   DosPostEventSem(((pMSGSTRUCT)pParm)->hev);
  985. }
  986.  
  987. BOOL WinSendMsgAsync(HWND hwnd, ULONG ulMsgid, MPARAM mpParam1, MPARAM mpParam2, MRESULT *mrRes)
  988. { int tid;
  989.   MSGSTRUCT MsgStruct;
  990.   BOOL bRet;
  991.  
  992.   MsgStruct.hwnd=hwnd;
  993.   MsgStruct.ulMsgid=ulMsgid;
  994.   MsgStruct.mpParam1=mpParam1;
  995.   MsgStruct.mpParam2=mpParam2;
  996.  
  997.   DosCreateEventSem("\\SEM32\\SNDMSGSEM",&MsgStruct.hev,0,0);
  998.   tid=_beginthread(SendMsgThread,NULL,0x4000,&MsgStruct);
  999.  
  1000.   if (DosWaitEventSem(MsgStruct.hev,200)==640) { //timeout
  1001.     DosBeep(1000,10);
  1002.     DosKillThread(tid);
  1003.     *mrRes=0;
  1004.     bRet=FALSE;
  1005.   } else {
  1006.     *mrRes=MsgStruct.mrRes;
  1007.     bRet=TRUE;
  1008.   }
  1009.  
  1010.   DosCloseEventSem(MsgStruct.hev);
  1011.  
  1012.   return bRet;
  1013. }
  1014.  
  1015. /* this function is adapted from Roman Stangle's APM/2 package */
  1016. USHORT ProcessAPMOffRequest(USHORT usPowerState,USHORT usDevice)
  1017. {  APIRET rc=NO_ERROR;
  1018.    ULONG ulPacketSize, ulDataSize, ulVersion[2],ulAction=0;
  1019.    struct POWERRETURNCODE powerRC;
  1020.    struct SENDPOWEREVENT  sendpowereventAPM;
  1021.    HFILE hfileAPM;
  1022.  
  1023.    /* For /Shutdown "Request", we need Warp 4 otherwise at least a CHKDSK reliably occurs (if the request
  1024.     does work at all) */
  1025.    DosQuerySysInfo(QSV_VERSION_MAJOR, QSV_VERSION_MINOR, ulVersion, sizeof(ulVersion));
  1026.    if(usPowerState==POWERSTATE_OFF) {
  1027.      if((ulVersion[0]<0x14) || (ulVersion[1]<0x28))
  1028.        return 1;
  1029.    }
  1030.  
  1031.    if (DosOpen("\\DEV\\APM$", &hfileAPM, &ulAction, 0, FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS,
  1032.        OPEN_FLAGS_FAIL_ON_ERROR | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE, NULL)!=NO_ERROR)
  1033.      return 2;
  1034.  
  1035.    memset(&sendpowereventAPM, 0, sizeof(sendpowereventAPM));
  1036.    powerRC.usReturnCode=0;
  1037.                                     /* Enable PWR MGMT function */
  1038.    sendpowereventAPM.usSubID=SUBID_ENABLE_POWER_MANAGEMENT;
  1039.    ulPacketSize=sizeof(sendpowereventAPM);
  1040.    ulDataSize=sizeof(powerRC);
  1041.    rc=DosDevIOCtl(hfileAPM, IOCTL_POWER, POWER_SENDPOWEREVENT, &sendpowereventAPM, ulPacketSize,
  1042.                   &ulPacketSize, &powerRC, ulDataSize, &ulDataSize);
  1043.    if(rc!=NO_ERROR || powerRC.usReturnCode!=POWER_NOERROR) {
  1044.      DosClose(hfileAPM);
  1045.      return 3;
  1046.    }
  1047.  
  1048.    DosSleep(1000);    /* need a delay before the set state call for some reason */
  1049.    /* Invoke APM request */
  1050.    memset(&sendpowereventAPM, 0, sizeof(sendpowereventAPM));
  1051.    powerRC.usReturnCode=0;
  1052.    sendpowereventAPM.usSubID=SUBID_SET_POWER_STATE;
  1053.    sendpowereventAPM.usData1=usDevice;
  1054.    sendpowereventAPM.usData2=usPowerState;
  1055.    ulPacketSize=sizeof(sendpowereventAPM);
  1056.    ulDataSize=sizeof(powerRC);
  1057.    rc=DosDevIOCtl(hfileAPM, IOCTL_POWER, POWER_SENDPOWEREVENT,&sendpowereventAPM, ulPacketSize,
  1058.                   &ulPacketSize, &powerRC, ulDataSize, &ulDataSize);
  1059.    DosClose(hfileAPM);
  1060.  
  1061.    if(rc!=NO_ERROR || powerRC.usReturnCode!=POWER_NOERROR)
  1062.      return 4;
  1063.    else
  1064.      return 0;
  1065. }
  1066.  
  1067. VOID FillRectGradient(HPS hps, RECTL *rcl, RECTL *rclClip, LONG RGBDark, LONG RGBLight, BOOL bReverse)
  1068. { USHORT k,usBorderHgt,usRDark,usGDark,usBDark,usRLight,usGLight,usBLight,usYDiff;
  1069.   float fRGrad,fGGrad,fBGrad;
  1070.   POINTL ptl;
  1071.  
  1072.   usRDark=(RGBDark&0xFF0000)>>16,
  1073.   usGDark=(RGBDark&0xFF00)>>8,
  1074.   usBDark=(RGBDark&0xFF);
  1075.   usRLight=(RGBLight&0xFF0000)>>16,
  1076.   usGLight=(RGBLight&0xFF00)>>8,
  1077.   usBLight=(RGBLight&0xFF);
  1078.   usYDiff=rcl->yTop-rcl->yBottom;
  1079.   fRGrad=(float)(usRLight-usRDark)/(float)(usYDiff==0?1:usYDiff);
  1080.   fGGrad=(float)(usGLight-usGDark)/(float)(usYDiff==0?1:usYDiff);
  1081.   fBGrad=(float)(usBLight-usBDark)/(float)(usYDiff==0?1:usYDiff);
  1082.  
  1083.   for (k=0;k<rcl->yTop-rcl->yBottom;k++) {
  1084.     ptl.x=rcl->xLeft;
  1085.     ptl.y=bReverse?rcl->yTop-k-1:rcl->yBottom+k;
  1086.     if (rclClip!=NULL && (ptl.y<rclClip->yBottom || ptl.y>rclClip->yTop)) continue;
  1087.     GpiMove(hps,&ptl);
  1088.     ptl.x=rcl->xRight-1;
  1089.     GpiSetColor(hps,(int)(usRDark+fRGrad*k)*65536+(int)(usGDark+fGGrad*k)*256+(int)(usBDark+fBGrad*k));
  1090.     GpiLine(hps,&ptl);
  1091.   }
  1092. }
  1093.  
  1094. LONG CalcBrightCol(LONG lColor,UCHAR ucBright)
  1095. { UCHAR ucR,ucG,ucB,ucMax;
  1096.   LONG lBrightCol;
  1097.  
  1098.   ucB=lColor&0xFF;  ucG=(lColor&0xFF00)>>8;  ucR=(lColor&0xFF0000)>>16;
  1099.   ucMax=max(ucR,max(ucG,ucB));
  1100.   return (ucBright*ucR/ucMax*65536+ucBright*ucG/ucMax*256+ucBright*ucB/ucMax);
  1101. }
  1102.  
  1103. static MRESULT EXPENTRY PrtyDlgProc(HWND hwnd,ULONG msg,MPARAM mp1,MPARAM mp2)
  1104. { static HWND hwndPrty;
  1105.   static PID pidPrty;
  1106.  
  1107.   switch (msg) {
  1108.   case WM_INITDLG: {
  1109.     USHORT usPrty;
  1110.     SHORT sPrtyC, sPrtyD;
  1111.     UCHAR ucBuf[128],ucTitle[NAMELEN];
  1112.     HPS hps;
  1113.     HWND hwndTBar;
  1114.     RECTL rcl;
  1115.     POINTL aptl[TXTBOX_COUNT];
  1116.  
  1117.     LSWDATA *plswData;
  1118.  
  1119.     SetControlsFont(hwnd,TRUE);
  1120.  
  1121.     plswData = (LSWDATA*)PVOIDFROMMP(mp2);
  1122.     hwndPrty = plswData->TaskArr[plswData->iMenuAtItem].hwnd;
  1123.     pidPrty = plswData->TaskArr[plswData->iMenuAtItem].pid;
  1124.  
  1125.     WinQueryDlgItemText(hwnd,FID_TITLEBAR,sizeof(ucBuf),ucBuf);
  1126.     GetItemTitle(plswData->TaskArr[plswData->iMenuAtItem].hsw,ucTitle,sizeof(ucTitle),TRUE);
  1127.     strncat(ucBuf,": ",sizeof(ucBuf)-strlen(ucTitle)-1);
  1128.     strncat(ucBuf,ucTitle,sizeof(ucBuf)-strlen(ucTitle)-1);
  1129.  
  1130.     hwndTBar=WinWindowFromID(hwnd,FID_TITLEBAR);
  1131.     hps=WinGetPS(hwndTBar);
  1132.     WinQueryWindowRect(hwndTBar,&rcl);
  1133.     GpiQueryTextBox(hps,1,"W",TXTBOX_COUNT,aptl);
  1134.  
  1135.     MakeFitStr(hps,ucBuf,sizeof(ucBuf), rcl.xRight-rcl.xLeft-aptl[TXTBOX_BOTTOMRIGHT].x-aptl[TXTBOX_BOTTOMLEFT].x);
  1136.     WinReleasePS(hps);
  1137.  
  1138.     WinSetDlgItemText(hwnd,FID_TITLEBAR,ucBuf);
  1139.  
  1140.     DosGetPrty(PRTYS_PROCESS, &usPrty, pidPrty);
  1141.     sPrtyC = (usPrty+PRTYD_MAXIMUM)>>8;
  1142.     sPrtyD = usPrty-(sPrtyC<<8);
  1143.  
  1144.     WinCheckButton(hwnd, sPrtyC==PRTYC_IDLETIME?RAD_IDLETIME:
  1145.                          sPrtyC==PRTYC_REGULAR?RAD_REGULAR:
  1146.                          sPrtyC==PRTYC_TIMECRITICAL?RAD_CRITICAL:RAD_FGNDSERVER,TRUE);
  1147.  
  1148.     WinSendDlgItemMsg(hwnd,SPIN_DELTA,SPBM_SETLIMITS,MPFROMLONG(PRTYD_MAXIMUM),MPFROMLONG(PRTYD_MINIMUM));
  1149.     WinSendDlgItemMsg(hwnd,SPIN_DELTA,SPBM_SETTEXTLIMIT,MPFROMSHORT(3),0);
  1150.     WinSendDlgItemMsg(hwnd,SPIN_DELTA,SPBM_SETCURRENTVALUE,MPFROMLONG(sPrtyD),0);
  1151.  
  1152.     break;
  1153.   }
  1154.   case WM_COMMAND:
  1155.     if (SHORT1FROMMP(mp1)==DID_OK) {
  1156.       SHORT sPrtyC, sPrtyD;
  1157.       BOOL bDesc;
  1158.  
  1159.       WinSendDlgItemMsg(hwnd,SPIN_DELTA,SPBM_QUERYVALUE,MPFROMP(&sPrtyD),MPFROM2SHORT(0,SPBQ_ALWAYSUPDATE));
  1160.       if (WinQueryButtonCheckstate(hwnd,RAD_IDLETIME)) sPrtyC=PRTYC_IDLETIME;
  1161.       else if (WinQueryButtonCheckstate(hwnd,RAD_REGULAR)) sPrtyC=PRTYC_REGULAR;
  1162.       else if (WinQueryButtonCheckstate(hwnd,RAD_CRITICAL)) sPrtyC = PRTYC_TIMECRITICAL;
  1163.       else sPrtyC = PRTYC_FOREGROUNDSERVER;
  1164.  
  1165.       bDesc = (WinQueryButtonCheckstate(hwnd,CHK_DESCENDANTS));
  1166.  
  1167.       WinPostMsg(hwndPrty,LSWM_SETPRIORITY,
  1168.                  MPFROM2SHORT(((sPrtyC<<8)+sPrtyD)|(bDesc?0x8000:0),PRTY_MAGIC),
  1169.                  MPFROMLONG(pidPrty));
  1170.     }
  1171.   default:
  1172.     return WinDefDlgProc(hwnd, msg, mp1, mp2);
  1173.   }
  1174.   return 0;
  1175. }
  1176.  
  1177. static MRESULT EXPENTRY RunDlgProc(HWND hwnd,ULONG msg,MPARAM mp1,MPARAM mp2)
  1178. { static HWND hwndList;
  1179.   static UCHAR ucFName[_MAX_PATH];
  1180.  
  1181.   switch (msg) {
  1182.   case WM_INITDLG: {
  1183.     UCHAR *ucBuf;
  1184.     HFILE hFile;
  1185.     ULONG ulAction,ulcbRead,k,pos;
  1186.     APIRET rc;
  1187.  
  1188.     SetControlsFont(hwnd,FALSE);
  1189.     hwndList=WinWindowFromID(hwnd,CB_RUNCOMMAND);
  1190.     WinSendMsg(hwndList,EM_SETTEXTLIMIT,MPFROMSHORT(_MAX_PATH),0);
  1191.     GetStartupDir(ucFName,sizeof(ucFName));
  1192.     strncat(ucFName,HSTFILENAME,sizeof(ucFName)-strlen(ucFName)-1);
  1193.     rc=DosOpen(ucFName,&hFile,&ulAction,0,FILE_ARCHIVED|FILE_NORMAL,
  1194.                OPEN_ACTION_OPEN_IF_EXISTS|OPEN_ACTION_FAIL_IF_NEW,
  1195.                OPEN_FLAGS_FAIL_ON_ERROR|OPEN_SHARE_DENYWRITE|OPEN_ACCESS_READWRITE,0);
  1196.     if (rc==0) {
  1197.       if ((ucBuf=malloc((_MAX_PATH+2)*MAXRUNLISTHST))==NULL) {
  1198.         DosClose(hFile);
  1199.         break;
  1200.       }
  1201.       DosRead(hFile,ucBuf,(_MAX_PATH+2)*MAXRUNLISTHST,&ulcbRead);
  1202.       DosClose(hFile);
  1203.       for (k=0,pos=0;k<ulcbRead;k++)
  1204.         if (ucBuf[k]=='\n') {
  1205.           ucBuf[k]=ucBuf[k-1]='\0';
  1206.           WinSendMsg(hwndList,LM_INSERTITEM,MPFROMSHORT(LIT_END),MPFROMP(&ucBuf[pos]));
  1207.           pos=k+1;
  1208.         }
  1209.       free(ucBuf);
  1210.       WinSendMsg(hwndList,LM_SELECTITEM,MPFROMSHORT(0),MPFROMSHORT(TRUE));
  1211.     }
  1212.  
  1213.     break;
  1214.   }
  1215.  
  1216.   case WM_COMMAND:
  1217.     switch (SHORT1FROMMP(mp1)) {
  1218.     case DID_OK: {
  1219.       UCHAR ucCmd[_MAX_PATH+2],ucErrMsg[128],ucItemText[_MAX_PATH];
  1220.       USHORT k,usItemCount;
  1221.       SHORT sIndex;
  1222.       ULONG ulcbWrite,ulAction;
  1223.       APIRET rc;
  1224.       HFILE hFile;
  1225.       LSWDATA *plswData;
  1226.  
  1227.       WinQueryWindowText(hwndList,sizeof(ucCmd), ucCmd);
  1228.       strcpy(ucItemText,ucCmd); //RunCommand changes ucCmd
  1229.  
  1230.       if (DosGetNamedSharedMem((PVOID*)&plswData,SHAREMEM_NAME,PAG_READ | PAG_WRITE)==0 &&
  1231.           (rc=RunCommand(plswData,ucCmd,ucErrMsg,sizeof(ucErrMsg)))!=0) {
  1232.         WinMessageBox(HWND_DESKTOP,HWND_DESKTOP,ucErrMsg,PGMNAME,0,MB_ERROR | MB_CANCEL);
  1233.         DosFreeMem(plswData);
  1234.         break;
  1235.       }
  1236.  
  1237.       sIndex=(SHORT)WinSendMsg(hwndList,LM_SEARCHSTRING,MPFROM2SHORT(0,LIT_FIRST),MPFROMP(ucItemText));
  1238.       if (sIndex!=LIT_NONE)
  1239.         WinSendMsg(hwndList,LM_DELETEITEM,MPFROMSHORT(sIndex),0);
  1240.       WinSendMsg(hwndList,LM_INSERTITEM,MPFROMSHORT(0),MPFROMP(ucItemText));
  1241.  
  1242.       rc=DosOpen(ucFName,&hFile,&ulAction,0,FILE_ARCHIVED|FILE_NORMAL,
  1243.                  OPEN_ACTION_REPLACE_IF_EXISTS|OPEN_ACTION_CREATE_IF_NEW,
  1244.                  OPEN_FLAGS_FAIL_ON_ERROR|OPEN_SHARE_DENYWRITE|OPEN_ACCESS_READWRITE,0);
  1245.       if (rc==0) {
  1246.         usItemCount=LONGFROMMR(WinSendMsg(hwndList,LM_QUERYITEMCOUNT,0,0));
  1247.         for (k=0;k<usItemCount && k<MAXRUNLISTHST;k++) {
  1248.           WinSendMsg(hwndList,LM_QUERYITEMTEXT,MPFROM2SHORT(k,sizeof(ucItemText)),MPFROMP(ucItemText));
  1249.           sprintf(ucCmd,"%s\r\n",ucItemText);
  1250.           DosWrite(hFile,ucCmd,strlen(ucCmd),&ulcbWrite);
  1251.         }
  1252.         DosClose(hFile);
  1253.       }
  1254.  
  1255.       return WinDefDlgProc(hwnd, msg, mp1, mp2);
  1256.     }
  1257.     case PB_BROWSE: {
  1258.       static FILEDLG fild={0};
  1259.       HWND hwndFDlg;
  1260.       SHORT k;
  1261.  
  1262.       fild.cbSize = sizeof(FILEDLG);
  1263.       fild.fl = FDS_CENTER | FDS_OPEN_DIALOG ;
  1264.       hwndFDlg = WinFileDlg(HWND_DESKTOP, hwnd, &fild);
  1265.       if (hwndFDlg!=NULLHANDLE && (fild.lReturn == DID_OK))
  1266.         WinSetWindowText(hwndList,(PCHAR)PVOIDFROMMP(fild.szFullFile));
  1267.       for (k=strlen(fild.szFullFile);k>=0;k--)
  1268.         if (fild.szFullFile[k]=='\\') {
  1269.           fild.szFullFile[k+1]='\0';
  1270.           strcat(fild.szFullFile,"*.EXE");
  1271.           break;
  1272.         }
  1273.  
  1274.       break;
  1275.     }
  1276.     case DID_CANCEL:
  1277.       WinSendDlgItemMsg(hwnd,CB_RUNCOMMAND,CBM_SHOWLIST,MPFROMSHORT(FALSE),0);
  1278.       return WinDefDlgProc(hwnd, msg, mp1, mp2);
  1279.  
  1280.     default:
  1281.       return WinDefDlgProc(hwnd, msg, mp1, mp2);
  1282.     }
  1283.     break;
  1284.   default:
  1285.     return WinDefDlgProc(hwnd, msg, mp1, mp2);
  1286.   }
  1287.   return 0;
  1288. }
  1289.  
  1290. VOID ProcessCommand(USHORT cmd, USHORT src, LSWDATA *plswData, BOOL bTaskBar, BOOL bAll)
  1291. {
  1292.   switch (cmd) {
  1293.   case CMD_CANCELPOPUP:
  1294.   case CMD_CANCELPOPUP1:
  1295.     plswData->usCurrItem = MAXITEMS-1;
  1296.  
  1297.   case CMD_SWITCHFROMPM:
  1298.     if (plswData->bNowActive) {
  1299.       WinSetWindowPos(plswData->hwndPopup,HWND_BOTTOM, plswData->usPopupWinHideX,
  1300.                       plswData->usPopupWinHideY, 0, 0, SWP_MOVE | SWP_SIZE | SWP_ZORDER);
  1301.       ShowBubble(plswData,0,0,0,-1,NULL);
  1302.     }
  1303.  
  1304.     if (src==CMDSRC_MENU) plswData->usCurrItem = plswData->iMenuAtItem;
  1305.  
  1306.   case CMD_SWITCHFROMFS:
  1307.     /* turn the flag off only after the window has been repositioned or
  1308.      our subclassed frame window function won't let do this */
  1309.     plswData->bNowActive = FALSE;
  1310.  
  1311.     if (cmd != CMD_CANCELPOPUP && cmd != CMD_CANCELPOPUP1) {
  1312.       if (plswData->Settings.bDesktopMinimizes && IsDesktop(plswData->TaskArr[plswData->usCurrItem].hwnd)) {
  1313.         MinimizeHideAll(plswData,FALSE,0);
  1314.         break; //switching to desktop is done in MinimizeHideAll function
  1315.       }
  1316.  
  1317.       // for some weird reason WinSwitchToProgram does not always bring the window to top
  1318.       // showing is needed for hidden windows and won't hurt in other cases
  1319.       WinSetWindowPos(plswData->TaskArr[plswData->usCurrItem].hwnd,HWND_TOP,0,0,0,0,SWP_SHOW|SWP_ZORDER);
  1320.     }
  1321.  
  1322.     /* don't switch if the popup has been cancelled and  current program
  1323.      has been minimized or hidden or if a close window query has popped up and
  1324.      changed the focus to itself (and the POPUP_CANCEL has been triggered by
  1325.      the WM_TIMER) after the close command has been sent to a window */
  1326.  
  1327.     if (cmd != CMD_CANCELPOPUP1) {
  1328.       if (cmd != CMD_CANCELPOPUP ||
  1329.           ((plswData->TaskArr[plswData->usCurrItem].fl & (SWP_HIDE | SWP_MINIMIZE))==0) ||
  1330.           ((plswData->TaskArr[plswData->usCurrItem].ulType==PROG_FULLSCREEN ||
  1331.             plswData->TaskArr[plswData->usCurrItem].ulType==PROG_VDM) &&
  1332.            plswData->Settings.bPMPopupInFS))
  1333.  
  1334. // if we want to switch to the currently active window, which may be required if it's in
  1335. // another virtual desktop, activate desktop first, otherwise WinSwitchToProgram will not work
  1336.         if (WinQueryActiveWindow(HWND_DESKTOP)==plswData->TaskArr[plswData->usCurrItem].hwnd)
  1337.           WinSetActiveWindow(HWND_DESKTOP,plswData->TaskArr[plswData->usItems-1].hwnd);
  1338.  
  1339.         if (plswData->TaskArr[plswData->usCurrItem].hsw != 0)
  1340.           WinSwitchToProgram(plswData->TaskArr[plswData->usCurrItem].hsw);
  1341.         else
  1342.           WinSetWindowPos(plswData->TaskArr[plswData->usCurrItem].hwnd,
  1343.                           HWND_TOP,0,0,0,0,SWP_ACTIVATE | SWP_ZORDER);
  1344.  
  1345.       /* this is needed to make a full screen session current */
  1346.       if  (plswData->TaskArr[plswData->usCurrItem].ulType==PROG_FULLSCREEN ||
  1347.            plswData->TaskArr[plswData->usCurrItem].ulType==PROG_VDM)
  1348.         WinSetWindowPos(plswData->TaskArr[plswData->usCurrItem].hwnd,HWND_TOP,
  1349.                         0,0,0,0,SWP_ZORDER | SWP_ACTIVATE);
  1350.     }
  1351.     break;
  1352.  
  1353.   case CMD_SHOWSETTINGS:
  1354.     if (!plswData->bNowActive) EditSettings(plswData);
  1355.     break;
  1356.  
  1357.   case CMD_PRIORITY:
  1358.     if (src==CMDSRC_ACCELERATOR) {
  1359.       if (!MenuNeedsItem(plswData,plswData->usCurrItem,CMD_PRIORITY,NULL,0,FALSE))
  1360.         break;
  1361.  
  1362.       plswData->iMenuAtItem = plswData->usCurrItem;
  1363.     }
  1364.  
  1365.     WinDlgBox(HWND_DESKTOP,HWND_DESKTOP,PrtyDlgProc,plswData->hmodRes,DLG_PRTY,plswData);
  1366.     break;
  1367.  
  1368.   case CMD_ADDFILTER: {
  1369.     ENTRYNAME ucName;
  1370.  
  1371.     if (src==CMDSRC_ACCELERATOR)
  1372.       plswData->iMenuAtItem = plswData->usCurrItem;
  1373.  
  1374.     GetItemTitle(plswData->TaskArr[plswData->iMenuAtItem].hsw,ucName,sizeof(ucName),FALSE);
  1375.     if (AddFilter(&plswData->Settings,ucName,bTaskBar)) {
  1376.       USHORT k;
  1377.       ENTRYNAME ucName1;
  1378.  
  1379.       for (k=0;k<plswData->usItems;k++) { //check for entries with the same name
  1380.         GetItemTitle(plswData->TaskArr[k].hsw,ucName1,sizeof(ucName1),FALSE);
  1381.         if (strcmp(ucName,ucName1)==0)
  1382.           WinPostMsg(bTaskBar?plswData->hwndTaskBarClient:plswData->hwndPopClient,LSWM_SWITCHLISTCHANGED, MPFROMLONG(2), MPFROMLONG(plswData->TaskArr[k].hsw));
  1383.       }
  1384.     }
  1385.  
  1386.     break;
  1387.   }
  1388.  
  1389.   case CMD_HIDE:
  1390.   case CMD_SHOW:
  1391.   case CMD_RESTORE:
  1392.   case CMD_MINIMIZE:
  1393.   case CMD_MAXIMIZE:
  1394.   case CMD_MOVE:
  1395.   case CMD_CLOSE:
  1396.   case CMD_KILL:
  1397.   case CMD_DEATH:
  1398.   case CMD_CLOSEQUIT:
  1399.     if (bAll && cmd>=CMD_HIDE && cmd<=CMD_CLOSE) {
  1400.       SHORT k;
  1401.       for (k=plswData->usItems-1;k>=0;k--)
  1402.         if (plswData->TaskArr[k].pid==
  1403.             plswData->TaskArr[src==CMDSRC_MENU?plswData->iMenuAtItem:plswData->usCurrItem].pid &&
  1404.             !IsDesktop(plswData->TaskArr[k].hwnd) &&
  1405.             (cmd!=CMD_CLOSE||(cmd==CMD_CLOSE && WndHasControl(plswData->hab,plswData->TaskArr[k].hwnd,SC_CLOSE))))
  1406.           ChangeWindowPos(plswData, k,cmd);
  1407.     } else
  1408.       /* if this command comes from the keyboard use plswData->usCurrItem */
  1409.       ChangeWindowPos(plswData, src==CMDSRC_MENU ? plswData->iMenuAtItem : plswData->usCurrItem,cmd);
  1410.     break;
  1411.  
  1412.   case CMD_RUN: {
  1413.     static HWND hwndRunDlg=NULLHANDLE;
  1414.  
  1415.     if (!WinIsWindow(plswData->hab,hwndRunDlg))
  1416.       hwndRunDlg=WinLoadDlg(HWND_DESKTOP,NULLHANDLE,RunDlgProc,plswData->hmodRes,DLG_RUN,NULL);
  1417.     if (hwndRunDlg != NULLHANDLE) {
  1418.       WinSetWindowPos(hwndRunDlg,HWND_TOP,0,0,0,0,SWP_SHOW | SWP_ZORDER | SWP_ACTIVATE);
  1419.       WinProcessDlg(hwndRunDlg);
  1420.       WinDestroyWindow(hwndRunDlg);
  1421.     }
  1422.     break;
  1423.   }
  1424.  
  1425.   case CMD_QUIT:
  1426.     WinPostMsg(plswData->hwndPopup, WM_QUIT, 0, 0);
  1427.     break;
  1428.   }
  1429. }
  1430.  
  1431.  
  1432.