home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / wps / utils / pc2 / source / pc2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-31  |  83.9 KB  |  1,491 lines

  1. /***********************************************************************\
  2.  *                                PC2.c                                *
  3.  *                 Copyright (C) by Stangl Roman, 1993                 *
  4.  * This Code may be freely distributed, provided the Copyright isn't   *
  5.  * removed, under the conditions indicated in the documentation.       *
  6.  *                                                                     *
  7.  * PC/2 - Program Commander/2 is a configurable program starter for    *
  8.  * OS/2 2.x PM. If the user clicks button 1 on the DESKTOP, a user     *
  9.  * modifyable popup menu is displayed. The user then selects a program *
  10.  * to be started, or configuration of PC/2 or dismisses it.            *
  11.  * PC/2 is an alternative method of starting programs compared to      *
  12.  * icons and uses no space on DESKTOP, and no folder must be opended   *
  13.  * to start a program. For frequently used programs, this reduces the  *
  14.  * time to start an application.                                       *
  15.  * PC/2 also implements an optional virtual Desktop and sliding focus. *
  16.  *                                                                     *
  17. \***********************************************************************/
  18.  
  19. static char RCSID[]="@(#) $Header: PC2.c/PC2.h Version 1.50 05,1993 $ (LBL)";
  20.  
  21. #define         _FILE_  "PC/2 - PC2.c V1.50"
  22.  
  23. #include        "PC2.h"                 /* User include files */
  24. #include        "Error.h"
  25.  
  26.                                         /* PC/2 semaphore to avoid loading PC/2 twice */
  27. #define         PC2_SEM "\\SEM32\\PC2_SEM.SEM"
  28. #define         DESKTOP_CLASS   "#37"   /* Class name of the "Desktop" window handle (which
  29.                                            is reserved in the Toolkit */
  30.  
  31. HEV             hevPc2;                 /* Handle of PC/2 semaphore */
  32. BOOL            InstallHelp;            /* True if we're installing */
  33. UCHAR           *pucFilenameProfile;    /* The buffer holding the filename of the profile */
  34. UCHAR           *pucFilenameINI;        /* Path and filename of PC2.INI */
  35. UCHAR           *pucFilenameHLP;        /* The buffer holding the filename of the HLP file */
  36. UCHAR           *pucPathDLL;            /* Directory of PC/2 to seek for DLL file */
  37. HMODULE         hDllPc2;                /* Handle of PC/2 DLL */
  38. PFFUNCPTR1      *pPC2DLL_SetParameters; /* Pointer to DLL-Functions */
  39. PFFUNCPTR2      *pPC2DLL_QueryParameters;
  40. PFFUNCPTR3      *pPC2DLL_Hook;
  41. SWP             swpApplications[64];    /* Window position of all enumerated applications
  42.                                            except Window List, PC/2 and optionally Desktop */
  43. ULONG           ulApplicationsCount;    /* Counter of last filled entry within array
  44.                                            swpApplications */
  45. /*                                                                                      *\
  46.  * Reserve data referenced generally through all modules. This isn't the best way, hope *
  47.  * that C++ comes out soon...                                                           *
  48. \*                                                                                      */
  49. HAB             hab;                    /* Handle of PM anchor block */
  50. HMQ             hmq;                    /* Handle of message queue */
  51. HWND            hwndFrame;              /* Frame handle of window */
  52. HWND            hwndClient;             /* Client handle of window */
  53. HWND            hwndPopupMenu;          /* Handel of popup menu window */
  54.                                         /* Input options: mouse button 1 depressed,
  55.                                            Input devices keyboard or mouse button 1,
  56.                                            popup menu allways visible on DESKTOP,
  57.                                            position so that ID_CONFIGDIALOG is under the
  58.                                            pointer */
  59. HWND            hwndHelp;               /* Help window handle */
  60. HOOKPARAMETERS  HookParameters;         /* Parameters passed to PC2HOOK.DLL */
  61. SESSIONDATA     SessionData;            /* Used by Menu Installation dialog and by
  62.                                            Program Installation dialog to store menu or
  63.                                            program data, to be filled from the user or
  64.                                            to be presented to the user. */
  65. MENUDATA        *pPopupMenu=NULL;       /* Used by all procedures as the starting point
  66.                                            of a linked list of menu entries. */
  67. MENUDATA        *pMenuData;             /* This pointer points to the current level of
  68.                                            Submenus and Menuitems within the configuration
  69.                                            dialog procedure */
  70.                                         /* Create linked list by starting with this ID */
  71. USHORT          MenuDataId=ID_POPUPMENU;
  72. USHORT          DialogResult;           /* Each dialog procedure returns the result in
  73.                                            this variable to enable the calling routine to
  74.                                            check, if there is valid data or not. */
  75. FILE            *Pc2Profile;            /* Open the profile, where the user entered menu
  76.                                            data is stored, with this handle */
  77. SWP             swpScreen;              /* The screen dimensions */
  78.  
  79. /*--------------------------------------------------------------------------------------*\
  80.  * The main procedure.                                                                  *
  81.  * Req:                                                                                 *
  82.  *      argc, argv, envp                                                                *
  83.  * Returns:                                                                             *
  84.  *      int ........... Exitcode (0, or errorlevel)                                     *
  85. \*--------------------------------------------------------------------------------------*/
  86. int main(int argc, char *argv[], char *envp[])
  87. {
  88. QMSG    qmsg;                           /* Message queue */
  89. ULONG   counter;                        /* Temporary counter */
  90.                                         /* Frame creation control flag */
  91. ULONG   flCreate=FCF_ICON | FCF_TITLEBAR | FCF_HIDEBUTTON | FCF_SIZEBORDER |
  92.                  FCF_TASKLIST | FCF_ACCELTABLE;
  93.  
  94.                                         /* Default the Popup-Menu is displayed after a
  95.                                            WM_BUTTON1CLICK on the Desktop, but users may
  96.                                            prefer WM_BUTTON1DBLCLK to popup the menu */
  97. HookParameters.ulClickFlag=WM_BUTTON1DBLCLK;
  98. /*                                                                                      *\
  99.  * Get the full path and filename of the running copy of PC/2 and change the extension  *
  100.  * .EXE into .cfg to open the configuration file under this name. If the user supplies  *
  101.  * [-,/Profile filename.ext] then use this filename as the Profile. Also change .EXE    *
  102.  * into .HLP, .INI and PC/2 directory as the current directory to access .DLL.          *
  103. \*                                                                                      */
  104.                                         /* Long enough to hold user Profile name */
  105. pucFilenameProfile=malloc(strlen(argv[0])+64);
  106. pucFilenameINI=malloc(strlen(argv[0])+1);
  107. pucFilenameHLP=malloc(strlen(argv[0])+1);
  108. pucPathDLL=malloc(strlen(argv[0])+1);
  109. strcpy(pucFilenameProfile, argv[0]);
  110. strcpy(pucFilenameINI, argv[0]);
  111. strcpy(pucFilenameHLP, argv[0]);
  112. strcpy(pucPathDLL, argv[0]);
  113. strcpy(strchr(pucFilenameProfile, '.'), ".cfg");
  114. strcpy(strchr(pucFilenameINI, '.'), ".ini");
  115. strcpy(strchr(pucFilenameHLP, '.'), ".hlp");
  116. strcpy(strrchr(pucPathDLL, '\\'), "");  /* Backward scan for \ */
  117. InstallHelp=FALSE;                      /* Assume no installation */
  118. for(counter=1; counter<argc; counter++)
  119.     {
  120.     strupr(argv[counter]);              /* Convert to uppercase */
  121.                                         /* Test for /PROFILE or -PROFILE to get a
  122.                                            profile name */
  123.     if((strstr(argv[counter], "/PROFILE")!=NULL) ||
  124.         (strstr(argv[counter], "-PROFILE")!=NULL))
  125.         strcpy((pucFilenameProfile+strlen(pucFilenameProfile)-7), argv[counter+1]);
  126.                                         /* Test for /INSTALL or -INSTALL to start the help
  127.                                            panels during initialization */
  128.     if((strstr(argv[counter], "/INSTALL")!=NULL) ||
  129.         (strstr(argv[counter], "-INSTALL")!=NULL))
  130.         InstallHelp=TRUE;
  131.                                         /* Test for /DOUBLECLICK or -DOUBLECLICK to display
  132.                                            the Popup-Menu after a double-click instead of
  133.                                            a single click */
  134.     if((strstr(argv[counter], "/DOUBLECLICK")!=NULL) ||
  135.         (strstr(argv[counter], "-DOUBLECLICK")!=NULL))
  136.         HookParameters.ulClickFlag=WM_BUTTON1DBLCLK;
  137.                                         /* Test for /SINGLECLICK or -SINGLECLICK to display
  138.                                            the Popup-Menu after a double-click instead of
  139.                                            a single click */
  140.     if((strstr(argv[counter], "/SINGLECLICK")!=NULL) ||
  141.         (strstr(argv[counter], "-SINGLECLICK")!=NULL))
  142.         HookParameters.ulClickFlag=WM_BUTTON1CLICK;
  143.     }
  144. INIAccess(pucFilenameINI, TRUE);        /* Get data from PC2.INI into HookParameters */
  145. do
  146. {
  147.                                         /* Initialize anchor block and message queue */
  148.     if(WinStartUp(&hab, &hmq)==FALSE) break;
  149.     HookParameters.habWindow=hab;       /* Save anchor block handle */
  150.     if(!WinRegisterClass(               /* Register window class */
  151.         hab,                            /* Handle of anchor block */
  152.         (PSZ)PC2_CLASSNAME,             /* Window class name */
  153.         (PFNWP)PC2_MainWindowProc,      /* Address of window procedure */
  154.         CS_SIZEREDRAW | CS_SAVEBITS,    /* Class style */
  155.         0))                             /* Extra window words */
  156.         {
  157.         GEN_ERR(hab, (HWND)NULL, (HWND)NULL);
  158.         break;
  159.         }
  160. /*                                                                                      *\
  161.  * Check if we are allready loaded before by querying a semaphore that is defined the   *
  162.  * first time PC/2 runs.                                                                *
  163. \*                                                                                      */
  164.     if(DosCreateEventSem(               /* Create a semaphore */
  165.         PC2_SEM,                        /* Name */
  166.         &hevPc2,                        /* Handle */
  167.         (ULONG)0,                       /* Named semaphores are allways shared */
  168.         (BOOL32)FALSE))                 /* Initially set */
  169.         {                               /* If an error occurs, either we can't create
  170.                                            the semaphore or it allready exists. We assume
  171.                                            that it exists, meaning PC/2 allready loaded.
  172.                                            Parameters NULL force an immediate exit(1). */
  173.         USR_ERR("PC/2 allready loaded - exiting...", (HWND)NULL, (HWND)NULL);
  174.         break;                          /* Not needed but for safety... */
  175.         }
  176. /*                                                                                      *\
  177.  * Now get device resolution and save it and other initilization data to the structure  *
  178.  * used to communicate with PC2HOOK.DLL.                                                *
  179. \*                                                                                      */
  180.                                         /* Query and save the device resolution, f.e.
  181.                                            1024 * 768 */
  182.     swpScreen.cx=WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
  183.     swpScreen.cy=WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
  184.                                         /* Now initialized the virtual Desktop data */
  185.     HookParameters.DesktopSize.x=swpScreen.cx;
  186.     HookParameters.DesktopSize.y=swpScreen.cy;
  187.     HookParameters.VirtualDesktopPos.x=0;
  188.     HookParameters.VirtualDesktopPos.y=0;
  189.     HookParameters.VirtualDesktopMin.x=-swpScreen.cx;
  190.     HookParameters.VirtualDesktopMin.y=-swpScreen.cy;
  191.     HookParameters.VirtualDesktopMax.x=swpScreen.cx;
  192.     HookParameters.VirtualDesktopMax.y=swpScreen.cy;
  193.     HookParameters.SlidingXFactor=(HookParameters.ulScrollPercentage*
  194.         HookParameters.DesktopSize.x)/100;
  195.     HookParameters.SlidingYFactor=(HookParameters.ulScrollPercentage*
  196.         HookParameters.DesktopSize.y)/100;
  197. /*                                                                                      *\
  198.  * Start frame window, which creates window(s) and WM_CREATE message.                   *
  199. \*                                                                                      */
  200.     if((hwndFrame=WinCreateStdWindow(   /* Create a standart window */
  201.         HWND_DESKTOP,                   /* DESKTOP is parent */
  202.         0,                              /* Standard window styles */
  203.         &flCreate,                      /* Frame control flags */
  204.         (PSZ)PC2_CLASSNAME,             /* Client window class name */
  205.         "",                             /* No window text */
  206.         0,                              /* No special class style */
  207.         (HMODULE)0,                     /* Ressource is in .EXE file */
  208.         ID_PC2MAINWINDOW,               /* Frame window identifier */
  209.         &hwndClient)                    /* Client window handle */
  210.         )==NULLHANDLE)
  211.         {
  212.         GEN_ERR(hab, (HWND)NULL, (HWND)NULL);
  213.         break;
  214.         }
  215.     HookParameters.hwndPC2=hwndClient;  /* Save window handle to send message to display
  216.                                            the Popup-Menu */
  217. /*                                                                                      *\
  218.  * Load the Pc2Hook DLL either from the current directory or a LIBPATH path and         *
  219.  * obtain the addresses of the entrypoints. There seems to be a little bug?, when the   *
  220.  * library name contains a .DLL extension - the DLL is loaded sucessfully but not       *
  221.  * always correct initialized? and calling functions in the DLL tend to fail. Extension *
  222.  * .DLL therefore not appended to library name.                                         *
  223. \*                                                                                      */
  224.     {
  225.     UCHAR       ucDrive;
  226.     UCHAR       ucBuffer[80];
  227.                                         /* Get drive of PC/2's startup directory
  228.                                            1=A, 2=B, 3=C,.... and direcotry itself */
  229.     ucDrive=tolower(pucPathDLL[0]);
  230.     DosSetDefaultDisk(++ucDrive-'a');
  231.     DosSetCurrentDir(pucPathDLL);
  232.     if(DosLoadModule(                   /* Load the DLL of PC/2 */
  233.         ucBuffer,                       /* Save failure there */
  234.         sizeof(ucBuffer)-1,             /* Length of save area */
  235.         "PC2Hook",                      /* Library name */
  236.         &hDllPc2)!=NO_ERROR)            /* DLL module handle */
  237.         {                               /* DLL couldn't be found in the current PC/2
  238.                                            directory or via the LIBPATH path */
  239.         USR_ERR("Can't find PC2HOOK.DLL, please check DLL file and LIBPATH - exiting...",
  240.             hwndFrame, hwndClient);
  241.         break;
  242.         }
  243.     if(DosQueryProcAddr(                /* Now get the address of the functions within the DLL */
  244.         hDllPc2,                        /* DLL module handle */
  245.         1,                              /* Ordinal number of procedure whose address is desired */
  246.         "PC2DLL_SetParameters",         /* Procedure name being referenced */
  247.                                         /* Procedure address returned */
  248.         (PFN *)(&pPC2DLL_SetParameters))!=NO_ERROR)
  249.         {                               /* An error occured */
  250.         DosFreeModule(hDllPc2);         /* Free DLL reference */
  251.         USR_ERR("Can't load from PC2HOOK.DLL - exiting...", hwndFrame, hwndClient);
  252.         break;
  253.         }
  254.     if(DosQueryProcAddr(hDllPc2, 2, "PC2DLL_QueryParameters", (PFN *)(&pPC2DLL_QueryParameters))!=NO_ERROR)
  255.         {                               /* An error occured */
  256.         DosFreeModule(hDllPc2);         /* Free DLL reference */
  257.         USR_ERR("Can't load from PC2HOOK.DLL - exiting...", hwndFrame, hwndClient);
  258.         break;
  259.         }
  260.     if(DosQueryProcAddr(hDllPc2, 3, "PC2DLL_Hook", (PFN *)(&pPC2DLL_Hook))!=NO_ERROR)
  261.         {
  262.         DosFreeModule(hDllPc2);
  263.         USR_ERR("Can't load from PC2HOOK.DLL - exiting...", hwndFrame, hwndClient);
  264.         break;
  265.         }
  266.     }
  267. /*                                                                                      *\
  268.  * Now initilize Help, if it can't be initialized the we get no help but that's no      *
  269.  * reason to terminate.                                                                 *
  270. \*                                                                                      */
  271.     if(WinStartHelp(hab, pucFilenameHLP, &hwndHelp)==FALSE)
  272.         USR_ERR("Can't find PC2.HLP, please check HLP file and HELP - ignoring help requests...",
  273.             hwndFrame, hwndClient);
  274. /*                                                                                      *\
  275.  * Set text to titlebar and size & position.                                            *
  276. \*                                                                                      */
  277.     WinSetWindowText(hwndFrame, "PC/2");
  278.     if(!WinSetWindowPos(                /* Set window postion */
  279.         hwndFrame,                      /* Window handle */
  280.         HWND_BOTTOM,
  281.         5,
  282.         5,
  283.         150,
  284.         150*3/4+WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR)+2*WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER),
  285.         SWP_HIDE | SWP_MOVE | SWP_SIZE | SWP_DEACTIVATE))
  286.         GEN_ERR(hab, (HWND)NULL, (HWND)NULL);
  287.                                         /* Display overview window if requested */
  288.     if(HookParameters.ulStatusFlag & OVERVIEW)
  289.         WinSetWindowPos(hwndFrame, HWND_BOTTOM, 0, 0, 0, 0, SWP_SHOW | SWP_DEACTIVATE);
  290. /*                                                                                      *\
  291.  * Now setup the Popup-Menu by loading the data from the profile and install the hook   *
  292.  * into the system input queue.                                                         *
  293. \*                                                                                      */
  294.     hwndPopupMenu=WinLoadMenu(          /* Load popup menu */
  295.         hwndClient,                     /* Owner window handle */
  296.         (HMODULE)0,                     /* Ressource in .EXE file */
  297.         ID_PC2POPUPMENU);               /* Menu identifier in ressource file */
  298.                                         /* Load the data from the profile */
  299.     WinPostMsg(hwndClient, WM_SETPOPUPMENU, NULL, NULL);
  300.                                         /* Now install the hook */
  301.     WinPostMsg(hwndClient, WM_LOADHOOK, NULL, NULL);
  302. /*                                                                                      *\
  303.  * Here we loop dispatching the messages...                                             *
  304. \*                                                                                      */
  305.     while(WinGetMsg(hab, &qmsg, 0, 0, 0))
  306.         WinDispatchMsg(hab, &qmsg);     /* Dispatch messages to window procedure */
  307.     WinDestroyWindow(hwndFrame);        /* Close window */
  308. } while (FALSE);
  309.  
  310. if(WinCloseDown(&hwndHelp, &hab, &hmq)==FALSE) return(1);
  311. else return(0);
  312. }
  313.  
  314. /*--------------------------------------------------------------------------------------*\
  315.  * This procedure is the PC/2 window procedure.                                         *
  316. \*--------------------------------------------------------------------------------------*/
  317. MRESULT EXPENTRY PC2_MainWindowProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  318. {
  319. switch(msg)
  320. {
  321. case WM_CREATE:                         /* Create window by WinCreateStdWindow() */
  322.     {
  323.     USHORT      usTimer;
  324.  
  325.                                         /* First call default window procedure */
  326.     WinDefWindowProc(hwnd, msg, mp1, mp2);
  327.     if(InstallHelp==TRUE)               /* For installation display help panels */
  328.         WinPostMsg(hwnd, WM_COMMAND, MPFROMSHORT(ID_HELP), NULL);
  329.                                         /* Query all windows to initialize array holding
  330.                                            all window positions */
  331.     WinPostMsg(hwnd, WM_SETDESKTOPHANDLE, (MPARAM)NULL, (MPARAM)NULL);
  332.                                         /* Start timer for WM_TIMER every 2,5 seconds */
  333.     for(usTimer=0; usTimer<=TID_USERMAX; usTimer++)
  334.                                         /* If we found the first timer break */
  335.         if(WinStartTimer(hab, hwnd, usTimer, 02500)) break;
  336.     if(usTimer>TID_USERMAX)             /* Inform user if we can't find a timer */
  337.         USR_ERR("Cannot obtain a timer", hwndFrame, hwndClient);
  338.     }
  339.     break;
  340.  
  341. case WM_PAINT:                          /* Draw overview of virtual Desktop */
  342.     {
  343.     HPS         hpsClient;
  344.     RECTL       rcClient;
  345.     SWP         swpClient;
  346.     float       fScaleX;                /* Reduce factor to reduce horizontal size of virtual
  347.                                            Desktop to horizonal client window size */
  348.     float       fScaleY;
  349.     POINTL      ptlOrigin;              /* Coordinates (0|0) within client area */
  350.     POINTL      ptl[2];                 /* Point of lines,... */
  351.     ULONG       ulColor=1;              /* Use least significant 2 bits for window colors */
  352.     LONG        lTemp;
  353.                                         /* Get a cached presentation space */
  354.     hpsClient=WinBeginPaint(hwnd, NULLHANDLE, &rcClient);
  355.                                         /* Get the client area size */
  356.     WinQueryWindowPos(hwnd, &swpClient);
  357.                                         /* Fill background of client area gray */
  358.     WinFillRect(hpsClient, &rcClient, CLR_PALEGRAY);
  359.                                         /* Now get scale factor to scale virtual Desktop
  360.                                            to client area */
  361.     fScaleX=(float)(swpClient.cx-1)/(3*HookParameters.DesktopSize.x);
  362.     fScaleY=(float)(swpClient.cy)/(3*HookParameters.DesktopSize.y);
  363.                                         /* Get coordinates (0|0) origin */
  364.     ptlOrigin.x=HookParameters.DesktopSize.x*fScaleX;
  365.     ptlOrigin.y=HookParameters.DesktopSize.y*fScaleY;
  366.                                         /* Draw the borders of the 3 * 3 Desktops */
  367.     GpiSetColor(hpsClient, CLR_YELLOW);
  368.     for(lTemp=0; lTemp<=3; lTemp++)
  369.         {
  370.         ptl[0].x=0; ptl[0].y=ptlOrigin.y*lTemp;
  371.         GpiMove(hpsClient, &ptl[0]);
  372.         ptl[0].x=swpClient.cx;
  373.         GpiLine(hpsClient, &ptl[0]);
  374.         ptl[0].x=ptlOrigin.x*lTemp; ptl[0].y=0;
  375.         GpiMove(hpsClient, &ptl[0]);
  376.         ptl[0].y=swpClient.cy;
  377.         GpiLine(hpsClient, &ptl[0]);
  378.         }
  379.                                         /* Get physical Desktop origin */
  380.     ptlOrigin.x+=(float)HookParameters.VirtualDesktopPos.x*fScaleX;
  381.     ptlOrigin.y+=(float)HookParameters.VirtualDesktopPos.y*fScaleY;
  382.                                         /* Now display the physical Desktop */
  383.     GpiSetColor(hpsClient, CLR_DARKRED);
  384.     ptl[0].x=ptl[1].x=ptlOrigin.x;
  385.     ptl[0].y=ptl[1].y=ptlOrigin.y;
  386.     ptl[1].x+=(float)HookParameters.DesktopSize.x*fScaleX;
  387.     ptl[1].y+=(float)HookParameters.DesktopSize.y*fScaleY;
  388.     GpiMove(hpsClient, &ptl[0]);
  389.     GpiBox(hpsClient, DRO_OUTLINEFILL, &ptl[1], 0, 0);
  390.     GpiSetLineWidth(hpsClient, 3<<16);  /* Set line width to 2 */
  391.                                         /* Now display the windows from topmost to bottommost */
  392.     for(lTemp=ulApplicationsCount; lTemp>=0; lTemp--)
  393.         {
  394.         GpiSetColor(hpsClient, 1+(ulColor & 0x3));
  395.         ptl[0].x=ptl[1].x=ptlOrigin.x+(float)swpApplications[lTemp].x*fScaleX;
  396.         ptl[0].y=ptl[1].y=ptlOrigin.y+(float)swpApplications[lTemp].y*fScaleY;
  397.         ptl[1].x+=(float)swpApplications[lTemp].cx*fScaleX;
  398.         ptl[1].y+=(float)swpApplications[lTemp].cy*fScaleY;
  399.         GpiMove(hpsClient, &ptl[0]);
  400.         GpiBox(hpsClient, DRO_OUTLINE, &ptl[1], 0, 0);
  401.         ulColor++;
  402.         }
  403.     WinEndPaint(hpsClient);
  404.     }
  405.     break;
  406.  
  407. /*                                                                                      *\
  408.  * Syntax: WM_SETPOPUPMENU, NULL, NULL                                                  *
  409. \*                                                                                      */
  410. case WM_SETPOPUPMENU:
  411. /*                                                                                      *\
  412.  * Open the profile for reading the linked list containing the popup menu data. If the  *
  413.  * profile can't be opened, the file is assumed to be empty so the popup menu is empty. *
  414. \*                                                                                      */
  415.     if((Pc2Profile=fopen(pucFilenameProfile, "r"))==NULL)
  416.         {
  417.         pPopupMenu=AllocateMenuData();  /* Allocate an empty MENUDATA structure used as
  418.                                            the first element of linked list */
  419.         USR_ERR("Cannot open confguration file - assuming empty file", hwndFrame, hwndClient);
  420.         }
  421.     else
  422.         {
  423.         static UCHAR    Buffer[256];
  424.  
  425.         pPopupMenu=AllocateMenuData();  /* Allocate an empty MENUDATA structure used as
  426.                                            the first element of linked list */
  427.         fgets(Buffer, sizeof(Buffer), Pc2Profile);
  428.         if(strcmp(Buffer, "PROFILE START\n")==0)
  429.             LoadMenu(pPopupMenu);       /* Load the rest by calling a recursive procedure */
  430.         fclose(Pc2Profile);
  431.         }
  432.     pMenuData=pPopupMenu;               /* Initialize *MENUDATA for Configuration dialog
  433.                                            procedure to a known value */
  434.     break;
  435.  
  436. case WM_TIMER:
  437. /*                                                                                      *\
  438.  * If we run without the WPS, the user may decide to start PMSHELL sometimes. If he     *
  439.  * does this, the window handle of the Desktop, where we catch the mouse button clicks  *
  440.  * changes. So we use the timer on a regular basis of about 2 seconds the query for the *
  441.  * window handle to see any changes immediately.                                        *
  442. \*                                                                                      */
  443.                                         /* Query all windows to initialize array holding
  444.                                            all window positions, because windows may
  445.                                            have been started or deleted */
  446.     WinPostMsg(hwnd, WM_DESKTOPMOVE, MPFROMLONG(0), MPFROMLONG(0));
  447. /*                                                                                      *\
  448.  * Syntax: WM_SETDESKTOPHANDLE, NULL, NULL                                              *
  449. \*                                                                                      */
  450. case WM_SETDESKTOPHANDLE:
  451. /*                                                                                      *\
  452.  * Query the window handle of the Desktop windows and load them into PC2HOOK.DLL        *
  453.  * library. If the WPS is installed, we can obtain its handle by searching for a window *
  454.  * class of #37. Even if the WPS is installed, we can also obtain the the window handle *
  455.  * of the PM, which is also present, if the WPS isn't installed.                        *
  456. \*                                                                                      */
  457.     {
  458.     UCHAR       ucClass[8];             /* Save class name here */
  459.     HWND        hwndWPS;                /* Save WPS window handle */
  460.     HWND        hwndDesktop;            /* Save PM window handle */
  461.     HENUM       henumWindows;           /* Enumerate windows */
  462.  
  463.                                         /* Get to bottommost window handle of the "Desktop" */
  464.     hwndDesktop=WinQueryWindow(HWND_DESKTOP, QW_BOTTOM);
  465.                                         /* Enumerate all windows at "Desktop" z-order */
  466.     henumWindows=WinBeginEnumWindows(hwndDesktop);
  467.     HookParameters.hwndWPS=0;
  468.     while(hwndWPS=WinGetNextWindow(henumWindows))
  469.         {
  470.                                         /* Now get the class name of that window handle */
  471.         WinQueryClassName(hwndWPS, sizeof(ucClass), (PCH)ucClass);
  472.                                         /* If we find the required "Desktop" window (it
  473.                                            has a class name of #37, which is reserved in the
  474.                                            Toolkit) set this value into the Hook DLL.
  475.                                            This class is owned by the WPS, so we found the
  476.                                            WPS' window handle */
  477.         if(!strcmp(ucClass, DESKTOP_CLASS)) break;
  478.         }
  479.     WinEndEnumWindows(henumWindows);    /* End enumeration */
  480. /*                                                                                      *\
  481.  * Now get the PM window handle for the case, that the WPS is not installed, or moved   *
  482.  * outwards of the display (by setting the move Desktop checkbox).                      *
  483. \*                                                                                      */
  484.                                         /* Without WPS installed we can only get the
  485.                                            "Desktop" window handle */
  486.     hwndDesktop=WinQueryDesktopWindow(hab, NULLHANDLE);
  487.                                         /* Inform DLL if Desktop windows handles have
  488.                                            changed */
  489.     if((hwndWPS!=HookParameters.hwndWPS) || (hwndDesktop!=HookParameters.hwndDesktop))
  490.         {
  491.         HookParameters.hwndWPS=hwndWPS;
  492.         HookParameters.hwndDesktop=hwndDesktop;
  493.         pPC2DLL_SetParameters(&HookParameters);
  494.         }
  495.     }
  496.     break;
  497.  
  498. /*                                                                                      *\
  499.  * Syntax: WM_DESKTOPMOVE, LONG SlidingXFactor, LONG SlidingYFactor                     *
  500. \*                                                                                      */
  501. case WM_DESKTOPMOVE:
  502. /*                                                                                      *\
  503.  * The hook found that button the pointer was over one of the border rows and/or        *
  504.  * columns of the physical Desktop. The passed parameter mp1 contains a bitmapped flag  *
  505.  * which direction all windows in the virtual Desktop should be move. We calculate      *
  506.  * if and where the physical Desktop must be moved, or ignore it, if we're allready at  *
  507.  * a border position on the virtual Desktop.                                            *
  508. \*                                                                                      */
  509.     {
  510.     LONG        SlidingXFactor;         /* Slide in x direction in pixels */
  511.     LONG        SlidingYFactor;         /* Slide in y direction in pixels */
  512.     BOOL        bChanged=FALSE;         /* TRUE if window(s) changes since last enumeration */
  513.     HENUM       henumDesktop;           /* Window handle of WC_FRAME class Desktop */
  514.     HWND        hwndApplication;        /* Window handles of enumerated application */
  515.     SWP         swpCurrent;             /* Window position of current enumerated application */
  516.     UCHAR       ucClassname[7];         /* Class name of enumerated application */
  517.     UCHAR       ucWindowText[33];       /* Window text of enumerated application */
  518.  
  519.     SlidingXFactor=LONGFROMMP(mp1);
  520.     SlidingYFactor=LONGFROMMP(mp2);
  521.                                         /* Enumerate all descendants of HWND_DESKTOP,
  522.                                            which are the frame windows seen on Desktop,
  523.                                            but not having necessarily the class WC_FRAME */
  524.     henumDesktop=WinBeginEnumWindows(HWND_DESKTOP);
  525.     ulApplicationsCount=0;              /* Begin with offset 0 in first iteration */
  526.     while(hwndApplication=WinGetNextWindow(henumDesktop))
  527.         {
  528.         WinQueryWindowPos(hwndApplication, &swpCurrent);
  529.         WinQueryClassName(hwndApplication, sizeof(ucClassname), ucClassname);
  530.         WinQueryWindowText(hwndApplication, sizeof(ucWindowText), ucWindowText);
  531.                                         /* Only move WC_FRAME class (#1) windows. If it
  532.                                            is such a window, overwrite current offset
  533.                                            with next enumeration so that array only
  534.                                            contains windows that must be moved */
  535.         if(strcmp(ucClassname, "#1")) continue;
  536.                                         /* Ignore untitled windows, where do they come from on
  537.                                            the hell ? */
  538.         if(!strcmp(ucWindowText, "")) continue;
  539.                                         /* Preserve Window list */
  540.         if(!strcmp(ucWindowText, "Window List")) continue;
  541.                                         /* Preserve PC/2's window */
  542.         if(!strcmp(ucWindowText, "PC/2")) continue;
  543.                                         /* Move Desktop only if user requested it */
  544.         if(!strcmp(ucWindowText, HookParameters.ucDesktopName) &&
  545.             !(HookParameters.ulStatusFlag & MOVEDESKTOP)) continue;
  546.                                         /* Only move windows */
  547.         swpCurrent.fl=SWP_MOVE | SWP_NOADJUST;
  548.         swpCurrent.x+=SlidingXFactor;
  549.         swpCurrent.y+=SlidingYFactor;
  550.                                         /* Now compare current one if it changed */
  551.         if(memcmp(&swpApplications[ulApplicationsCount], &swpCurrent, sizeof(SWP)))
  552.             {
  553.             bChanged=TRUE;
  554.             memcpy(&swpApplications[ulApplicationsCount], &swpCurrent, sizeof(SWP));
  555.             }
  556.         ulApplicationsCount++;
  557.         }
  558.     WinEndEnumWindows(henumDesktop);    /* End enumeration */
  559.                                         /* Now move all windows */
  560.     if(SlidingXFactor || SlidingYFactor)
  561.         {
  562.                                         /* VirtualDesktopPos may have been changed */
  563.         pPC2DLL_QueryParameters(&HookParameters);
  564.         bChanged=TRUE;
  565.         if(!WinSetMultWindowPos(hab, swpApplications, ulApplicationsCount))
  566.             GEN_ERR(hab, hwndFrame, hwndClient);
  567.         }
  568.                                         /* If windows changed, repaint client area */
  569.     if(bChanged) WinInvalidateRect(hwnd, NULL, TRUE);
  570.     }
  571.     break;
  572.  
  573. /*                                                                                      *\
  574.  * Syntax: WM_LOADHOOK, NULL, NULL                                                      *
  575. \*                                                                                      */
  576. case WM_LOADHOOK:
  577. /*                                                                                      *\
  578.  * Install the hook into the system input queue pointing to the PC2DLL_Hook() procedure *
  579.  * in the DLL PC2HOOK.DLL. If we can't do this we exit after an error message box.      *
  580. \*                                                                                      */
  581.                                         /* Query and set the window handle of the Desktop */
  582.     WinSendMsg(hwnd, WM_SETDESKTOPHANDLE, NULL, NULL);
  583.     if(WinSetHook(                      /* Set a hook */
  584.         hab,                            /* Handle of anchor block */
  585.         NULLHANDLE,                     /* Hook into system message queue */
  586.         HK_INPUT,                       /* Hook of system input queue */
  587.         (PFN)pPC2DLL_Hook,              /* Pointer to hook procedure */
  588.         hDllPc2)==FALSE)
  589.         {
  590.         USR_ERR("Hooking the system input queue failed - exiting...", hwndFrame, hwndClient);
  591.         WinPostMsg(hwnd, WM_QUIT, NULL, NULL);
  592.         }
  593.     break;
  594.  
  595. /*                                                                                      *\
  596.  * Syntax: WM_POPUPMENU, (SHORT x, SHORT y), HWND hwndPopup                             *
  597. \*                                                                                      */
  598. case WM_POPUPMENU:
  599. /*                                                                                      *\
  600.  * The hook found that button 1 was clicked on the Desktop and sent us this message. It *
  601.  * is either a WM_BUTTON1CLICK or WM_BUTTON1DBLCLK. First we obtain the focus, to be    *
  602.  * able to start our programs in the foreground.                                        *
  603. \*                                                                                      */
  604.     {
  605.     POINTL      ptlPopupPosition;
  606.     HWND        hwndPopup;
  607.     USHORT      fsOptions=PU_NONE | PU_KEYBOARD | PU_MOUSEBUTTON1 |
  608.                           PU_POSITIONONITEM | PU_HCONSTRAIN | PU_VCONSTRAIN;
  609.  
  610.                                         /* Get the position and window, where the user
  611.                                            clicked to get the Popup-Menu */
  612.     ptlPopupPosition.x=(ULONG)SHORT1FROMMP(mp1);
  613.     ptlPopupPosition.y=(ULONG)SHORT2FROMMP(mp1);
  614.     hwndPopup=HWNDFROMMP(mp2);
  615.                                         /* Map these window coordinated to display
  616.                                            coordinates, so that the Menu will be
  617.                                            displayed relative to the lower, left edge
  618.                                            of the display */
  619.     WinMapWindowPoints(hwndPopup, HWND_DESKTOP, &ptlPopupPosition,
  620.         sizeof(ptlPopupPosition)/sizeof(POINTL));
  621.     WinSetFocus(HWND_DESKTOP, hwnd);    /* Set focus to our window */
  622.     if(!WinPopupMenu(                   /* Pop up the popup menu */
  623.         HWND_DESKTOP,                   /* Parent window handle */
  624.         hwnd,                           /* Owner window handle that receives all the
  625.                                            notification messages generated by the pop-up
  626.                                            menu */
  627.         hwndPopupMenu,                  /* Popup menu window handle */
  628.         ptlPopupPosition.x,             /* x-coordinate of mouse pointer for popup menu */
  629.         ptlPopupPosition.y,             /* y-coordinate of mouse pointer for popup menu */
  630.         ID_PC2SETUP,                    /* Input item identity, if PU_POSITIONONITEM or
  631.                                            PU_SELECTITEM is set */
  632.         fsOptions)                      /* Input options */
  633.     ) GEN_ERR(hab, (HWND)NULL, (HWND)NULL);
  634.     break;
  635.     }
  636.  
  637. case WM_CLOSE:
  638.     if(WinMessageBox(                   /* Ask the user if he really wants to exit */
  639.         HWND_DESKTOP, HWND_DESKTOP,
  640.         "Are you sure you want to close PC/2?",
  641.         "PC/2 - Program Commander/2",
  642.         ID_PC2MAINWINDOW,
  643.         MB_OKCANCEL | MB_ICONQUESTION | MB_DEFBUTTON2)!=MBID_OK)
  644.         return((MRESULT)TRUE);          /* Only exit if OK is pressed */
  645.     if(WinReleaseHook(                  /* Release hook */
  646.         hab,                            /* Handle  of anchor block */
  647.         NULLHANDLE,                     /* Release from system hook chain */
  648.         HK_INPUT,                       /* Hook of system input queue */
  649.         (PFN)pPC2DLL_Hook,              /* Pointer to hook procedure */
  650.         hDllPc2)==FALSE)
  651.         {
  652.         USR_ERR("Unhooking the system input queue failed, System ShutDown suggested - exiting...",
  653.             hwndFrame, hwndClient);
  654.         WinPostMsg(hwnd, WM_QUIT, NULL, NULL);
  655.         }
  656.     DosFreeModule(hDllPc2);             /* Free DLL reference */
  657.     WinPostMsg(hwnd, WM_QUIT, NULL, NULL);
  658.     break;
  659.  
  660. case HM_ERROR:
  661.    {
  662.    GEN_ERR(hab, hwndFrame, hwndClient);
  663.    break;
  664.    }
  665.  
  666. case WM_COMMAND:
  667.     {
  668.     USHORT      command;
  669.  
  670.     command=SHORT1FROMMP(mp1);          /* Extract the command value */
  671. /*                                                                                      *\
  672.  * Filter the IDs of the user defined items of the Popup-Menu. If one is found, call    *
  673.  * SearchItem() to search for the corresponding MENUDATA structure, copy it to a        *
  674.  * SESSIONDATA structure and start the session.                                         *
  675. \*                                                                                      */
  676.     if((command>=USERITEMFIRST) && (command<=USERITEMLAST))
  677.         {
  678.         ULONG           id=(ULONG)command;
  679.         MENUDATA        *pMD=NULL;
  680.  
  681.                                         /* Search in the linked list for this entry */
  682.         if((pMD=SearchItem(pPopupMenu, &id))!=NULL)
  683.         if(pMD->Item==ENTRYMENUITEM)
  684.             {
  685.                                         /* Load SessionData with MENUDATA structure */
  686.             LoadMenuData2SessionData(FALSE, pMD, &SessionData);
  687.                                         /* Start the session */
  688.             StartSession(&SessionData);
  689.             }
  690.         }
  691.     switch(command)
  692.     {
  693.  
  694.     case ID_HELP:                       /* Display general help panel */
  695.         if(hwndHelp!=NULLHANDLE) WinSendMsg(
  696.             hwndHelp,                   /* Help window */
  697.             HM_DISPLAY_HELP,            /* Display a help panel */
  698.             MPFROMSHORT(ID_HELP),       /* Panel ID in ressource file */
  699.             HM_RESOURCEID);             /* MP1 points to the help window identity */
  700.         break;
  701.  
  702.     case ID_CONFIGDIALOG:               /* Popup menuitem Configure Menu selected */
  703.         if(!WinDlgBox(                  /* Start Configure PC/2 dialog box */
  704.             HWND_DESKTOP,               /* DESKTOP is parent */
  705.             HWND_DESKTOP,               /* DESKTOP is owner */
  706.             CD_DialogProcedure,         /* Dialog procedure of Program Installation
  707.                                            dialog */
  708.             0,                          /* Ressource is .EXE file */
  709.             CDID_CONFIGDIALOG,          /* ID of Configure PC/2 dialog */
  710.             0))                         /* No initialization data */
  711.         GEN_ERR(hab, hwndFrame, hwndClient);
  712.         break;
  713.  
  714.     case ID_DESKTOPDIALOG:              /* Popup menuitem Configure Desktop selected */
  715.         if(!WinDlgBox(HWND_DESKTOP, HWND_DESKTOP, DD_DialogProcedure,
  716.             0, DDID_DESKTOPDIALOG, 0))
  717.         GEN_ERR(hab, hwndFrame, hwndClient);
  718.         break;
  719.  
  720.     case ID_SHUTDOWN:                   /* ShutDown OS/2 menuitem selected */
  721.         if(WinMessageBox(               /* Ask the user if he really wants to shut down OS/2 */
  722.         HWND_DESKTOP, HWND_DESKTOP,
  723.         "Are you really sure you want to ShutDown OS/2?",
  724.         "PC/2 - Program Commander/2",
  725.         ID_PC2MAINWINDOW,
  726.         MB_OKCANCEL | MB_ICONQUESTION | MB_DEFBUTTON2)!=MBID_OK)
  727.         return((MRESULT)TRUE);          /* Only shut down if OK is pressed */
  728.         if(!WinDlgBox(                  /* Start ShutDown OS/2 dialog box */
  729.             HWND_DESKTOP, HWND_DESKTOP, SD_DialogProcedure, 0,
  730.             SDID_SHUTDOWNDIALOG, 0))
  731.         GEN_ERR(hab, hwndFrame, hwndClient);
  732.         break;
  733.  
  734.     case ID_EXIT:                       /* User selected F3 to shutdown PC/2 */
  735.         WinPostMsg(hwnd, WM_CLOSE, 0, 0);
  736.         break;
  737.  
  738.     case ID_ABOUTDIALOG:                /* User selected About PC/2 dialog */
  739.         if(!WinDlgBox(                  /* Start About PC/2 dialog box */
  740.             HWND_DESKTOP,               /* DESKTOP is parent */
  741.             HWND_DESKTOP,               /* DESKTOP is owner */
  742.             AD_DialogProcedure,         /* Dialog procedure of Program Installation
  743.                                            dialog */
  744.             0,                          /* Ressource is .EXE file */
  745.             ADID_ABOUTDIALOG,           /* ID of Program Installation dialog */
  746.             0))                         /* No initialization data */
  747.             GEN_ERR(hab, hwndFrame, hwndClient);
  748.         break;
  749.     }
  750.     break;
  751.     }
  752.  
  753. default:                                /* Default window procedure must be called */
  754.     return((MRESULT)WinDefWindowProc(hwnd, msg, mp1, mp2));
  755. }
  756. return((MRESULT)FALSE);                 /* We have handled the message */
  757. }
  758.  
  759. /*--------------------------------------------------------------------------------------*\
  760.  * This dialog procedure handles the PC/2 - Configuration (Setup) dialog.               *
  761.  * Req: none                                                                            *
  762. \*--------------------------------------------------------------------------------------*/
  763. MRESULT  EXPENTRY CD_DialogProcedure(HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2)
  764. {
  765. switch(msg)
  766. {
  767. case WM_INITDLG:
  768.     {
  769.     SWP         swp;
  770.  
  771.     WinQueryWindowPos(                  /* Query position of dialog window */
  772.         hwndDlg,                        /* Handle of dialog window */
  773.         &swp);                          /* Fill with position */
  774.     WinSetWindowPos(                    /* Set dialog window position */
  775.         hwndDlg,                        /* Handle of dialog window */
  776.         HWND_TOP,                       /* Position on top and center of DESKTOP */
  777.         (swpScreen.cx-swp.cx)/2,
  778.         (swpScreen.cy-swp.cy)/2,
  779.         0,
  780.         0,
  781.         SWP_MOVE);
  782.                                         /* Initialize the listbox */
  783.     WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL);
  784.     break;
  785.     }
  786.  
  787. /*                                                                                      *\
  788.  * Syntax: WM_LOADPOPUPMENU, *MENUDATA, NULL                                            *
  789. \*                                                                                      */
  790. case WM_LOADPOPUPMENU:                  /* Load the current level of the Popup-Menu in
  791.                                            the listbox after removing the old items */
  792.     {
  793.     MENUDATA    *pMD;
  794.  
  795.     pMD=PVOIDFROMMP(mp1);               /* Get the pointer to the first MENUDATA of the
  796.                                            current level */
  797.     WinSendDlgItemMsg(                  /* Send message to listbox */
  798.         hwndDlg,                        /* Handle of dialog window */
  799.         CDLB_MENUPROGRAM,               /* Submenu & Program listbox */
  800.         LM_DELETEALL,                   /* Delete all list box items */
  801.         (MPARAM)NULL,
  802.         (MPARAM)NULL);
  803.     if(pMD==NULL) break;                /* If linked list is empty break out */
  804.     do
  805.     {
  806.         if(pMD->Item==ENTRYSUBMENU)     /* It is a Submenu */
  807.             {
  808.             UCHAR       Buffer[EF_SIZE60+4];
  809.                                         /* Add >> for a Submenu */
  810.             sprintf(Buffer, "%s >>", pMD->PgmTitle);
  811.             WinSendDlgItemMsg(
  812.                 hwndDlg,
  813.                 CDLB_MENUPROGRAM,
  814.                 LM_INSERTITEM,          /* Insert Submenu Title at the end */
  815.                 MPFROMSHORT(LIT_END),
  816.                 MPFROMP(Buffer));
  817.             }
  818.         if(pMD->Item==ENTRYMENUITEM)    /* It's a Menuitem */
  819.             WinSendDlgItemMsg(
  820.                 hwndDlg,
  821.                 CDLB_MENUPROGRAM,
  822.                 LM_INSERTITEM,          /* Insert Menuitem Title at the end */
  823.                 MPFROMSHORT(LIT_END),
  824.                 MPFROMP(pMD->PgmTitle));
  825.                                         /* It may also be an empty entry, but then we
  826.                                            ignore it, because it must be filled with
  827.                                            Menuitem or Submenu data first */
  828.         if(pMD->Next!=NULL)             /* Get through linked list without diving into
  829.                                            Submenus */
  830.                 pMD=pMD->Next;
  831.         else break;                     /* We're at the end of the linked list */
  832.     }while(TRUE);
  833.     break;
  834.     }
  835.  
  836. /*                                                                                      *\
  837.  * Syntax: WM_SAVEPOPUPMENU, NULL, NULL                                                 *
  838. \*                                                                                      */
  839. case WM_SAVEPOPUPMENU:                  /* Save the Popup-Menu to the configuraion file */
  840.     if((Pc2Profile=fopen(pucFilenameProfile, "w"))==NULL)
  841.         USR_ERR("Cannot open confguration file - changes won't be saved",
  842.                 hwndFrame, hwndClient);
  843.     else
  844.         {
  845.         fprintf(Pc2Profile, "PROFILE START\n");
  846.         SaveMenu(pPopupMenu);           /* Save the menu linked list */
  847.         fprintf(Pc2Profile, "PROFILE END\n");
  848.         fclose(Pc2Profile);
  849.         }
  850.     break;
  851.  
  852. case WM_HELP:                           /* Help pressed */
  853.     WinSendMsg(
  854.         hwndHelp,                       /* Help window */
  855.         HM_DISPLAY_HELP,                /* Display a help panel */
  856.         MPFROMSHORT(ID_CONFIGDIALOG),   /* Panel ID in ressource file */
  857.         HM_RESOURCEID);                 /* MP1 points to the help window identity */
  858.     break;
  859.  
  860. case WM_COMMAND:                        /* Button pressed */
  861.     switch(SHORT1FROMMP(mp1))
  862.     {
  863. /*                                                                                      *\
  864.  * Chain up the linked list until we find the node, where this part-list comes from or  *
  865.  * the beginning of the complete list. The pointer pMenuData is adjusted.               *
  866. \*                                                                                      */
  867.     case CDID_LEVELUP:                  /* Get up one level in the linked list */
  868.         {
  869.         MENUDATA        *pMD;           /* Pointer to a MENUDATA structure to find the
  870.                                            Submenu where this part-list starts */
  871.  
  872.         pMD=pMenuData;                  /* Point to the first element of the linked list
  873.                                            at the current level */
  874.         if(pMD->Back==NULL)             /* If we're at the beginning of the complete linked
  875.                                            list ignore button */
  876.             return((MRESULT)FALSE);
  877.         else pMD=pMD->Back;             /* Submenu which started current level */
  878.                                         /* Now chain back through the linked list and find
  879.                                            the element, where the pointer to a Submenu
  880.                                            equals the back pointer of the first element
  881.                                            in this Submenu. Then we've found the node */
  882.         while(TRUE)
  883.             {
  884.             if(pMD->Back==NULL)         /* If we're now at the beginning break */
  885.                 break;
  886.             if((pMD->Back)->Submenu==pMD)
  887.                 break;
  888.             else pMD=pMD->Back;
  889.             }
  890.         pMenuData=pMD;                  /* Load as the top element of the current item */
  891.                                         /* Now redraw items in listbox */
  892.         WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL);
  893.         return((MRESULT)FALSE);         /* We handled this button */
  894.         }
  895.  
  896. /*                                                                                      *\
  897.  * Test the user selection for being a Submenu. If one found chain into this submenu    *
  898.  * and adjust the pointer pMenuData.                                                    *
  899. \*                                                                                      */
  900.     case CDID_LEVELDOWN:                /* Get down one level in the linked list */
  901.         {
  902.         MENUDATA        *pMD;           /* Pointer to a MENUDATA structure to find the
  903.                                            Submenu to chain into */
  904.         SHORT           sCount;
  905.  
  906.         pMD=pMenuData;                  /* Point to the first element of the linked list
  907.                                            at the current level */
  908.                                         /* Send message to listbox */
  909.         sCount=(SHORT)WinSendDlgItemMsg(
  910.             hwndDlg,                    /* Handle of dialog window */
  911.             CDLB_MENUPROGRAM,           /* Submenu & Program listbox */
  912.             LM_QUERYSELECTION,          /* Query first selected list box item */
  913.             MPFROMSHORT(LIT_FIRST),
  914.             (MPARAM)NULL);
  915.                                         /* If no item selected, ignore this button */
  916.         if(sCount==LIT_NONE)
  917.             return((MRESULT)FALSE);
  918.         for( ;sCount>0; sCount--)       /* Walk through the linked list to the selected
  919.                                            item */
  920.             pMD=pMD->Next;
  921.         if(pMD->Item!=ENTRYSUBMENU)     /* It's not a Submenu that's selected, ignore */
  922.             return((MRESULT)FALSE);
  923.         pMenuData=pMD->Submenu;         /* Otherwise chain into this part-list */
  924.                                         /* Now redraw items in listbox */
  925.         WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL);
  926.         return((MRESULT)FALSE);         /* We handled this button */
  927.         }
  928.  
  929. /*                                                                                      *\
  930.  * The user selected to add a (Sub)Menu. Thus dismiss the PC/2 Configuration dialog and *
  931.  * load the (Sub)Menu Installation dialog. The new (Sub)Menu is entered in a            *
  932.  * STARTSESSION structure named StartSession. Save the changes and reload the PC/2      *
  933.  * Configuration dialog again.                                                          *
  934. \*                                                                                      */
  935.     case CDID_ADDMENU:                  /* Add a Menu to PC/2 Configuration selected */
  936. /*                                                                                      *\
  937.  * The user selected to add a Program. Thus dismiss the PC/2 Configuration dialog and   *
  938.  * load the Program Installation dialog. The new session data is entered in a           *
  939.  * STARTSESSION structure named StartSession. Save the changes and reload the PC/2      *
  940.  * Configuration dialog again.                                                          *
  941. \*                                                                                      */
  942.     case CDID_ADDPROGRAM:               /* Add a Program to PC/2 Configuration selected */
  943.         {
  944.         UCHAR           *pU;            /* Temporary character pointer */
  945.         MENUDATA        *pMD;           /* Pointer to a MENUDATA structure to insert a
  946.                                            new MENUDATA stucture after */
  947.         MENUDATA        *pMDNew;        /* Temporary pointer for the new item to be inserted
  948.                                            after pMD */
  949.         SHORT           sCount;
  950.  
  951.         pMD=pMenuData;                  /* Point to the first element of the linked list
  952.                                            at the current level */
  953.                                         /* Send message to listbox */
  954.         sCount=(SHORT)WinSendDlgItemMsg(
  955.             hwndDlg,                    /* Handle of dialog window */
  956.             CDLB_MENUPROGRAM,           /* Submenu & Program listbox */
  957.             LM_QUERYSELECTION,          /* Query first selected list box item */
  958.             MPFROMSHORT(LIT_FIRST),
  959.             (MPARAM)NULL);
  960.                                         /* If no item selected, and there exists one,
  961.                                            add the new Menuitem after the last available
  962.                                            Menuitem by querying the number from the listbox.
  963.                                            Subtract 0 because we use 0-based instead 1-based. */
  964.         if((sCount==LIT_NONE) && (pMenuData->Item!=ENTRYEMPTY))
  965.             sCount=(SHORT)WinSendDlgItemMsg(hwndDlg, CDLB_MENUPROGRAM, LM_QUERYITEMCOUNT,
  966.                 MPFROM2SHORT(NULL, NULL), (MPARAM)NULL)-1;
  967.  
  968.         for( ;sCount>0; sCount--)       /* Walk through the linked list to the selected
  969.                                            item */
  970.             pMD=pMD->Next;
  971.                                         /* Allocate a new item */
  972.         pMDNew=AllocateMenuData();
  973.         strcpy(pU=malloc(strlen("Insert here please")+1), "Insert here please");
  974.         free(pMDNew->PgmTitle);
  975.         pMDNew->PgmTitle=pU;
  976.         pMDNew->id=MenuDataId++;        /* Increment ID */
  977.                                         /* Load SessionData with empty pMDNew structure */
  978.         LoadMenuData2SessionData(TRUE, pMDNew, &SessionData);
  979.         WinDismissDlg(hwndDlg, TRUE);   /* Clear up Configuration dialog */
  980.         if(SHORT1FROMMP(mp1)==CDID_ADDMENU)
  981.             {
  982.             if(!WinDlgBox(              /* Start Addmenu PC/2 dialog box */
  983.                 HWND_DESKTOP,           /* DESKTOP is parent */
  984.                 HWND_DESKTOP,           /* DESKTOP is owner */
  985.                 MI_DialogProcedure,     /* Dialog procedure of Program Installation
  986.                                            dialog */
  987.                 0,                      /* Ressource is .EXE file */
  988.                 MIID_MENUDIALOG,        /* ID of Addmenu PC/2 dialog */
  989.                 0))                     /* No initialization data */
  990.                 GEN_ERR(hab, hwndFrame, hwndClient);
  991.             }
  992.         else
  993.             {
  994.             if(!WinDlgBox(              /* Start Program Installation dialog box */
  995.                 HWND_DESKTOP,           /* DESKTOP is parent */
  996.                 HWND_DESKTOP,           /* DESKTOP is owner */
  997.                 PI_DialogProcedure,     /* Dialog procedure of Program Installation
  998.                                            dialog */
  999.                 0,                      /* Ressource is .EXE file */
  1000.                 PIID_PROGRAMDIALOG,     /* ID of Addprogram PC/2 dialog */
  1001.                 0))                     /* No initialization data */
  1002.                 GEN_ERR(hab, hwndFrame, hwndClient);
  1003.             }
  1004.         if(DialogResult==DID_OK)        /* If manipulation is done successfully, then load
  1005.                                            the SESSIONDATA structure back to the MENUDATA
  1006.                                            structure and save the changes */
  1007.             {
  1008.             LoadSessionData2MenuData(pMDNew, &SessionData);
  1009.             if(pMD->Item!=ENTRYEMPTY)   /* Add new entry, if the current entry isn't empty */
  1010.                 {
  1011.                 if(SHORT1FROMMP(mp1)==CDID_ADDMENU)
  1012.                     {                   /* It it is a Submenu, we also must add an empty
  1013.                                            first item for it */
  1014.                     MENUDATA    *pMDTemp;
  1015.  
  1016.                     pMDTemp=AllocateMenuData();
  1017.                     pMDNew->Submenu=pMDTemp;
  1018.                     pMDTemp->Back=pMDNew;
  1019.                     pMDNew->Item=ENTRYSUBMENU;
  1020.                     }
  1021.                 else pMDNew->Item=ENTRYMENUITEM;
  1022.                 if(pMD->Next!=NULL) (pMD->Next)->Back=pMDNew;
  1023.                 pMDNew->Next=pMD->Next;
  1024.                 pMDNew->Back=pMD;
  1025.                 pMD->Next=pMDNew;
  1026.                                         /* Insert item after the existing item */
  1027.                 SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMDNew), MPFROMLONG(pMD->id));
  1028.                 }
  1029.             else                        /* If it is an empty entry fill it with user data */
  1030.                 {
  1031.                 UCHAR   *pU;            /* Temporary character pointer */
  1032.  
  1033.                 pMD->id=pMDNew->id;
  1034.                 if(SHORT1FROMMP(mp1)==CDID_ADDMENU)
  1035.                     {                   /* It it is a Submenu, we also must add an empty
  1036.                                            first item for it */
  1037.                     MENUDATA    *pMDTemp;
  1038.  
  1039.                     pMDTemp=AllocateMenuData();
  1040.                     pMD->Submenu=pMDTemp;
  1041.                     pMDTemp->Back=pMD;
  1042.                     pMD->Item=ENTRYSUBMENU;
  1043.                     }
  1044.                 else pMD->Item=ENTRYMENUITEM;
  1045.                 strcpy(pU=malloc(strlen(pMDNew->PgmTitle)+1), pMDNew->PgmTitle);
  1046.                 free(pMD->PgmTitle);
  1047.                 pMD->PgmTitle=pU;
  1048.                 strcpy(pU=malloc(strlen(pMDNew->PgmName)+1), pMDNew->PgmName);
  1049.                 free(pMD->PgmName);
  1050.                 pMD->PgmName=pU;
  1051.                 strcpy(pU=malloc(strlen(pMDNew->PgmDirectory)+1), pMDNew->PgmDirectory);
  1052.                 free(pMD->PgmDirectory);
  1053.                 pMD->PgmDirectory=pU;
  1054.                 strcpy(pU=malloc(strlen(pMDNew->PgmInputs)+1), pMDNew->PgmInputs);
  1055.                 free(pMD->PgmInputs);
  1056.                 pMD->PgmInputs=pU;
  1057.                 pMD->SessionType=pMDNew->SessionType;
  1058.                 pMD->PgmControl=pMDNew->PgmControl;
  1059.                 pMD->FgBg=pMDNew->FgBg;
  1060.                 pMD->InitXPos=pMDNew->InitXPos;
  1061.                 pMD->InitYPos=pMDNew->InitYPos;
  1062.                 pMD->InitXSize=pMDNew->InitXSize;
  1063.                 pMD->InitYSize=pMDNew->InitYSize;
  1064.                 if(pMD->Back!=NULL)     /* This is the first item of a Submenu, then
  1065.                                            insert it there */
  1066.                     SetPopupMenu(MM_INSERTITEMSUBMENU, MPFROMP(pMD), MPFROMLONG((pMD->Back)->id));
  1067.                 else                    /* This is the complete first item of the linked
  1068.                                            list, so insert at the end */
  1069.                     SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMD), MPFROMLONG(MIT_END));
  1070.                 free(pMDNew->PgmTitle); /* Free temporary used structure */
  1071.                 free(pMDNew->PgmName);
  1072.                 free(pMDNew->PgmDirectory);
  1073.                 free(pMDNew->PgmInputs);
  1074.                 free(pMDNew);
  1075.                 }
  1076.             }
  1077.         else
  1078.             {
  1079.             free(pMDNew->PgmTitle);     /* Free temporary MENUDATA structure */
  1080.             free(pMDNew->PgmName);
  1081.             free(pMDNew->PgmDirectory);
  1082.             free(pMDNew->PgmInputs);
  1083.             free(pMDNew);
  1084.             }
  1085.                                         /* Initialize the listbox */
  1086.         WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL);
  1087.         if(!WinDlgBox(                  /* Now reload the Configuration dialog */
  1088.             HWND_DESKTOP,
  1089.             HWND_DESKTOP,
  1090.             CD_DialogProcedure,
  1091.             0,
  1092.             CDID_CONFIGDIALOG,
  1093.             0)) GEN_ERR(hab, hwndFrame, hwndClient);
  1094.         break;                          /* We never get here because of calling WinDlgBox() */
  1095.         }
  1096.  
  1097. /*                                                                                      *\
  1098.  * The user selected to change an item. Thus dismiss the PC/2 Configuration dialog and  *
  1099.  * load the Menu or Program Installation dialog. The new session data is entered in a   *
  1100.  * STARTSESSION structure named StartSession.                                           *
  1101.  * Then reload the PC/2 Configuration dialog again.                                     *
  1102. \*                                                                                      */
  1103.     case CDID_CHANGEENTRY:              /* Change a Menu or Program configuration selected */
  1104.         {
  1105.         MENUDATA        *pMD;
  1106.         SHORT           sCount;
  1107.  
  1108.         pMD=pMenuData;                  /* Point to the first element of the linked list
  1109.                                            at the current level */
  1110.                                         /* Send message to listbox */
  1111.         sCount=(SHORT)WinSendDlgItemMsg(
  1112.             hwndDlg,                    /* Handle of dialog window */
  1113.             CDLB_MENUPROGRAM,           /* Submenu & Program listbox */
  1114.             LM_QUERYSELECTION,          /* Query first selected list box item */
  1115.             MPFROMSHORT(LIT_FIRST),
  1116.             (MPARAM)NULL);
  1117.         if(sCount==LIT_NONE)            /* If no item selected ignore this button */
  1118.             return((MRESULT)FALSE);
  1119.         for( ;sCount>0; sCount--)       /* Walk through the linked list to the selected
  1120.                                            item */
  1121.             pMD=pMD->Next;
  1122.                                         /* Now load the MENUDATA to SESSIONDATA structure
  1123.                                            where the manipulations will take effect */
  1124.         LoadMenuData2SessionData(FALSE, pMD, &SessionData);
  1125.         WinDismissDlg(hwndDlg, TRUE);   /* Clear up Configuration dialog */
  1126.         if(pMD->Submenu==NULL)          /* It's a Menuitem so call the Program Installation
  1127.                                            dialog box */
  1128.             {
  1129.             if(!WinDlgBox(              /* Start Program Installation dialog box */
  1130.                 HWND_DESKTOP,           /* DESKTOP is parent */
  1131.                 HWND_DESKTOP,           /* DESKTOP is owner */
  1132.                 PI_DialogProcedure,     /* Dialog procedure of Program Installation
  1133.                                            dialog */
  1134.                 0,                      /* Ressource is .EXE file */
  1135.                 PIID_PROGRAMDIALOG,     /* ID of Program Installation PC/2 dialog */
  1136.                 0))                     /* No initialization data */
  1137.                 GEN_ERR(hab, hwndFrame, hwndClient);
  1138.             }
  1139.         else                            /* It's a Submenu so call the Menu Installation
  1140.                                            dialog box */
  1141.             {
  1142.             if(!WinDlgBox(              /* Start Addmenu PC/2 dialog box */
  1143.                 HWND_DESKTOP,           /* DESKTOP is parent */
  1144.                 HWND_DESKTOP,           /* DESKTOP is owner */
  1145.                 MI_DialogProcedure,     /* Dialog procedure of Program Installation
  1146.                                            dialog */
  1147.                 0,                      /* Ressource is .EXE file */
  1148.                 MIID_MENUDIALOG,        /* ID of Addmenu PC/2 dialog */
  1149.                 0))                     /* No initialization data */
  1150.                 GEN_ERR(hab, hwndFrame, hwndClient);
  1151.             }
  1152.         if(DialogResult==DID_OK)        /* If manipulation is done successfully, then load
  1153.                                            the SESSIONDATA structure back to the MENUDATA
  1154.                                            structure and save the changes */
  1155.             {
  1156.             LoadSessionData2MenuData(pMD, &SessionData);
  1157.                                         /* Now change the menuitem text to the new one */
  1158.             SetPopupMenu(MM_SETITEMTEXT, MPFROMP(pMD), MPFROMLONG(pMD->id));
  1159.                                         /* Initialize the listbox */
  1160.             WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL);
  1161.             }
  1162.         if(!WinDlgBox(                  /* Now reload the Configuration dialog */
  1163.             HWND_DESKTOP,
  1164.             HWND_DESKTOP,
  1165.             CD_DialogProcedure,
  1166.             0,
  1167.             CDID_CONFIGDIALOG,
  1168.             0)) GEN_ERR(hab, hwndFrame, hwndClient);
  1169.         break;                          /* We never get here because of calling WinDlgBox() */
  1170.         }
  1171.  
  1172. /*                                                                                      *\
  1173.  * The user selected to remove an item. If thist item is the only one in the linked     *
  1174.  * list or the first item of a submenu set it to empty otherwise free it's ressources   *
  1175.  * and remove the entry.                                                                *
  1176. \*                                                                                      */
  1177.     case CDID_REMOVEENTRY:              /* Remove a item of the PC/2 Configuration selected */
  1178.         {
  1179.         UCHAR           *pU;
  1180.         MENUDATA        *pMD;
  1181.         SHORT           sCount;
  1182.  
  1183.         pMD=pMenuData;                  /* Point to the first element of the linked list
  1184.                                            at the current level */
  1185.                                         /* Send message to listbox */
  1186.         sCount=(SHORT)WinSendDlgItemMsg(
  1187.             hwndDlg,                    /* Handle of dialog window */
  1188.             CDLB_MENUPROGRAM,           /* Submenu & Program listbox */
  1189.             LM_QUERYSELECTION,          /* Query first selected list box item */
  1190.             MPFROMSHORT(LIT_FIRST),
  1191.             (MPARAM)NULL);
  1192.         if(sCount==LIT_NONE)            /* If no item selected ignore this button */
  1193.             return((MRESULT)FALSE);
  1194.         for( ;sCount>0; sCount--)       /* Walk through the linked list to the selected
  1195.                                            item */
  1196.             pMD=pMD->Next;
  1197.         while(TRUE)
  1198.             {
  1199.             if((pMD->Back==NULL) && (pMD->Next!=NULL))
  1200.                 {                       /* Remove the first item of the complete linked list */
  1201.                 if(pMD->Item==ENTRYSUBMENU)
  1202.                 if((pMD->Submenu)->Item==ENTRYEMPTY)
  1203.                     {                   /* If it is an empty Submenu remove it completely */
  1204.                                         /* Remove the Submenu and the empty first item
  1205.                                            from the Popup-Menu */
  1206.                     SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id));
  1207.                     free((pMD->Submenu)->PgmTitle);
  1208.                     free((pMD->Submenu)->PgmName);
  1209.                     free((pMD->Submenu)->PgmDirectory);
  1210.                     free((pMD->Submenu)->PgmInputs);
  1211.                     free(pMD->Submenu);
  1212.                     (pMD->Next)->Back=NULL;
  1213.                                         /* Now next element is the first one */
  1214.                     pPopupMenu=pMD->Next;
  1215.                     pMenuData=pMD->Next;
  1216.                     free(pMD->PgmTitle);
  1217.                     free(pMD->PgmName);
  1218.                     free(pMD->PgmDirectory);
  1219.                     free(pMD->PgmInputs);
  1220.                     free(pMD);
  1221.                     break;              /* Ensure we only test once, because each routine
  1222.                                            changes the pointers */
  1223.                     }
  1224.                 if(pMD->Item==ENTRYMENUITEM)
  1225.                     {                   /* If it is an empty Menuitem remove it completly */
  1226.                     (pMD->Next)->Back=NULL;
  1227.                                         /* Now next element is the first one */
  1228.                     pPopupMenu=pMD->Next;
  1229.                     pMenuData=pMD->Next;
  1230.                                         /* Remove the item from the Popup-Menu */
  1231.                     SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id));
  1232.                     free(pMD->PgmTitle);
  1233.                     free(pMD->PgmName);
  1234.                     free(pMD->PgmDirectory);
  1235.                     free(pMD->PgmInputs);
  1236.                     free(pMD);
  1237.                     break;              /* Ensure we only test once, because each routine
  1238.                                            changes the pointers */
  1239.                     }
  1240.                 }
  1241.             if((pMD->Back==NULL) && (pMD->Next==NULL))
  1242.                 {                       /* If it is the one and only item of the linked list
  1243.                                            set it to empty */
  1244.                 if(pMD->Item==ENTRYSUBMENU)
  1245.                 if((pMD->Submenu)->Item==ENTRYEMPTY)
  1246.                     {                   /* If it is an empty Submenu remove the empty
  1247.                                            item completely */
  1248.                                         /* Remove the item from the Popup-Menu */
  1249.                     SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id));
  1250.                     free((pMD->Submenu)->PgmTitle);
  1251.                     free((pMD->Submenu)->PgmName);
  1252.                     free((pMD->Submenu)->PgmDirectory);
  1253.                     free((pMD->Submenu)->PgmInputs);
  1254.                     free(pMD->Submenu);
  1255.                     free(pMD->PgmTitle);
  1256.                     strcpy(pU=malloc(strlen("")+1), "");
  1257.                     pMD->PgmTitle=pU;
  1258.                     free(pMD->PgmName);
  1259.                     strcpy(pU=malloc(strlen("")+1), "");
  1260.                     pMD->PgmName=pU;
  1261.                     free(pMD->PgmDirectory);
  1262.                     strcpy(pU=malloc(strlen("")+1), "");
  1263.                     pMD->PgmDirectory=pU;
  1264.                     free(pMD->PgmInputs);
  1265.                     strcpy(pU=malloc(strlen("")+1), "");
  1266.                     pMD->PgmInputs=pU;
  1267.                     pMD->Item=ENTRYEMPTY;
  1268.                     pMD->Back=NULL;
  1269.                     pMD->Submenu=NULL;
  1270.                     pMD->Next=NULL;
  1271.                     break;              /* Ensure we only test once, because each routine
  1272.                                            changes the pointers */
  1273.                     }
  1274.                 if(pMD->Item==ENTRYMENUITEM)
  1275.                     {                   /* If it is a Menuitem set it to empty */
  1276.                                         /* Remove the item from the Popup-Menu */
  1277.                     SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id));
  1278.                     strcpy(pU=malloc(strlen("")+1), "");
  1279.                     pMD->PgmTitle=pU;
  1280.                     free(pMD->PgmName);
  1281.                     strcpy(pU=malloc(strlen("")+1), "");
  1282.                     pMD->PgmName=pU;
  1283.                     free(pMD->PgmDirectory);
  1284.                     strcpy(pU=malloc(strlen("")+1), "");
  1285.                     pMD->PgmDirectory=pU;
  1286.                     free(pMD->PgmInputs);
  1287.                     strcpy(pU=malloc(strlen("")+1), "");
  1288.                     pMD->PgmInputs=pU;
  1289.                     pMD->Item=ENTRYEMPTY;
  1290.                     pMD->Back=NULL;
  1291.                     pMD->Submenu=NULL;
  1292.                     pMD->Next=NULL;
  1293.                     break;              /* Ensure we only test once, because each routine
  1294.                                            changes the pointers */
  1295.                     }
  1296.                 }
  1297.             if(pMD->Back!=NULL)
  1298.                 {                       /* It is any item of more than one item and not
  1299.                                            the first one */
  1300.                 if(((pMD->Back)->Submenu==pMD) && (pMD->Submenu==NULL) && (pMD->Next==NULL))
  1301.                 {                       /* If it is the first item of a Submenu not followed
  1302.                                            by any item, set it to empty */
  1303.                                         /* Remove the item from the Popup-Menu */
  1304.                     SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id));
  1305.                     strcpy(pU=malloc(strlen("")+1), "");
  1306.                     pMD->PgmTitle=pU;
  1307.                     free(pMD->PgmName);
  1308.                     strcpy(pU=malloc(strlen("")+1), "");
  1309.                     pMD->PgmName=pU;
  1310.                     free(pMD->PgmDirectory);
  1311.                     strcpy(pU=malloc(strlen("")+1), "");
  1312.                     pMD->PgmDirectory=pU;
  1313.                     free(pMD->PgmInputs);
  1314.                     strcpy(pU=malloc(strlen("")+1), "");
  1315.                     pMD->Item=ENTRYEMPTY;
  1316.                     break;              /* Ensure we only test once, because each routine
  1317.                                            changes the pointers */
  1318.                     }
  1319.                 if(pMD->Item==ENTRYSUBMENU)
  1320.                 if((pMD->Submenu)->Item==ENTRYEMPTY)
  1321.                     {                   /* If it is an empty Submenu so also remove the
  1322.                                            first item in the Submenu */
  1323.                                         /* Remove the Submenu and the empty first item
  1324.                                            from the Popup-Menu */
  1325.                     SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id));
  1326.                     free((pMD->Submenu)->PgmTitle);
  1327.                     free((pMD->Submenu)->PgmName);
  1328.                     free((pMD->Submenu)->PgmDirectory);
  1329.                     free((pMD->Submenu)->PgmInputs);
  1330.                     free(pMD->Submenu);
  1331.                     if(((pMD->Back)->Submenu==pMD) && (pMD->Next==NULL))
  1332.                         {               /* If the previous item is a Submenu, this item is
  1333.                                            the first item of it. If none item follows, set
  1334.                                            this item to empty */
  1335.                         strcpy(pU=malloc(strlen("")+1), "");
  1336.                         pMD->PgmTitle=pU;
  1337.                         free(pMD->PgmName);
  1338.                         strcpy(pU=malloc(strlen("")+1), "");
  1339.                         pMD->PgmName=pU;
  1340.                         free(pMD->PgmDirectory);
  1341.                         strcpy(pU=malloc(strlen("")+1), "");
  1342.                         pMD->PgmDirectory=pU;
  1343.                         free(pMD->PgmInputs);
  1344.                         strcpy(pU=malloc(strlen("")+1), "");
  1345.                         pMD->Item=ENTRYEMPTY;
  1346.                         pMD->Submenu=NULL;
  1347.                         pMD->Next=NULL;
  1348.                         break;          /* Ensure we only test once, because each routine
  1349.                                            changes the pointers */
  1350.                         }
  1351.                     if(((pMD->Back)->Submenu==pMD) && (pMD->Next!=NULL))
  1352.                         {               /* If the previous item is a Submenu, this item ist
  1353.                                            the first item of it. If one item follows adjust
  1354.                                            the pointer to the current level of items */
  1355.                         pMenuData=pMD->Next;
  1356.                         (pMD->Back)->Submenu=pMD->Next;
  1357.                         if(pMD->Next!=NULL) (pMD->Next)->Back=pMD->Back;
  1358.                         free(pMD->PgmTitle);
  1359.                         free(pMD->PgmName);
  1360.                         free(pMD->PgmDirectory);
  1361.                         free(pMD->PgmInputs);
  1362.                         free(pMD);
  1363.                         break;          /* Ensure we only test once, because each routine
  1364.                                            changes the pointers */
  1365.                         }
  1366.                     if((pMD->Back)->Submenu!=pMD)
  1367.                         {               /* If this item isn't the first item of a Submenu */
  1368.                         (pMD->Back)->Next=pMD->Next;
  1369.                         if(pMD->Next!=NULL) (pMD->Next)->Back=pMD->Back;
  1370.                         free(pMD->PgmTitle);
  1371.                         free(pMD->PgmName);
  1372.                         free(pMD->PgmDirectory);
  1373.                         free(pMD->PgmInputs);
  1374.                         free(pMD);
  1375.                         break;          /* Ensure we only test once, because each routine
  1376.                                            changes the pointers */
  1377.                         }
  1378.                     }
  1379.                 if(pMD->Item==ENTRYMENUITEM)
  1380.                     {                   /* If it is a Menuitem, just remove it completly */
  1381.                                         /* Remove the item from the Popup-Menu */
  1382.                     SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id));
  1383.                     if(((pMD->Back)->Submenu==pMD) && (pMD->Next==NULL))
  1384.                         {               /* If the previous item is a Submenu, this item is
  1385.                                            the first item of it. If none item follows, set
  1386.                                            this item to empty */
  1387.                         strcpy(pU=malloc(strlen("")+1), "");
  1388.                         pMD->PgmTitle=pU;
  1389.                         free(pMD->PgmName);
  1390.                         strcpy(pU=malloc(strlen("")+1), "");
  1391.                         pMD->PgmName=pU;
  1392.                         free(pMD->PgmDirectory);
  1393.                         strcpy(pU=malloc(strlen("")+1), "");
  1394.                         pMD->PgmDirectory=pU;
  1395.                         free(pMD->PgmInputs);
  1396.                         strcpy(pU=malloc(strlen("")+1), "");
  1397.                         pMD->Item=ENTRYEMPTY;
  1398.                         pMD->Submenu=NULL;
  1399.                         pMD->Next=NULL;
  1400.                         break;          /* Ensure we only test once, because each routine
  1401.                                            changes the pointers */
  1402.                         }
  1403.                     if(((pMD->Back)->Submenu==pMD) && (pMD->Next!=NULL))
  1404.                         {               /* If the previous item is a Submenu, this item ist
  1405.                                            the first item of it. If one item follows adjust
  1406.                                            the pointer to the current level of items */
  1407.                         pMenuData=pMD->Next;
  1408.                         (pMD->Back)->Submenu=pMD->Next;
  1409.                         if(pMD->Next!=NULL) (pMD->Next)->Back=pMD->Back;
  1410.                         free(pMD->PgmTitle);
  1411.                         free(pMD->PgmName);
  1412.                         free(pMD->PgmDirectory);
  1413.                         free(pMD->PgmInputs);
  1414.                         free(pMD);
  1415.                         break;          /* Ensure we only test once, because each routine
  1416.                                            changes the pointers */
  1417.                         }
  1418.                     if((pMD->Back)->Submenu!=pMD)
  1419.                         {               /* If this item isn't the first item of a Submenu */
  1420.                         (pMD->Back)->Next=pMD->Next;
  1421.                         if(pMD->Next!=NULL) (pMD->Next)->Back=pMD->Back;
  1422.                         free(pMD->PgmTitle);
  1423.                         free(pMD->PgmName);
  1424.                         free(pMD->PgmDirectory);
  1425.                         free(pMD->PgmInputs);
  1426.                         free(pMD);
  1427.                         break;          /* Ensure we only test once, because each routine
  1428.                                            changes the pointers */
  1429.                         }
  1430.                     }
  1431.                 }
  1432.             break;                      /* If we come here, we're trying to remove an not
  1433.                                            empty Submenu, but we also must exit the
  1434.                                            endless loop */
  1435.             }
  1436.                                         /* Initialize the listbox */
  1437.         WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL);
  1438.         return((MRESULT)FALSE);         /* We have done everything */
  1439.         }
  1440.  
  1441. /*                                                                                      *\
  1442.  * The user selected to resort the current level of the menuentries. Load the dialog    *
  1443.  * and let the user resort the linked list of menues pointed to by pMenuData and to     *
  1444.  * resort the menuentries of the Popup-Menu.                                            *
  1445. \*                                                                                      */
  1446.     case CDID_RESORT:                   /* Load the resort dialog */
  1447.         {
  1448.         WinDismissDlg(hwndDlg, TRUE);   /* Clear up Configuration dialog */
  1449.         if(!WinDlgBox(                  /* Start Resort dialog box */
  1450.             HWND_DESKTOP,               /* DESKTOP is parent */
  1451.             HWND_DESKTOP,               /* DESKTOP is owner */
  1452.             RD_DialogProcedure,         /* Dialog procedure of Program Installation
  1453.                                            dialog */
  1454.             0,                          /* Ressource is .EXE file */
  1455.             RDID_RESORTDIALOG,          /* ID of Program Installation PC/2 dialog */
  1456.             0))                         /* No initialization data */
  1457.             GEN_ERR(hab, hwndFrame, hwndClient);
  1458.         if(!WinDlgBox(                  /* Now reload the Configuration dialog */
  1459.             HWND_DESKTOP,
  1460.             HWND_DESKTOP,
  1461.             CD_DialogProcedure,
  1462.             0,
  1463.             CDID_CONFIGDIALOG,
  1464.             0)) GEN_ERR(hab, hwndFrame, hwndClient);
  1465.         }
  1466.         break;
  1467.  
  1468.     case DID_OK:                        /* Enter key pressed */
  1469.                                         /* Save the changes */
  1470.         WinSendMsg(hwndDlg, WM_SAVEPOPUPMENU, NULL, NULL);
  1471.         DialogResult=DID_OK;            /* Dialog terminated with DID_OK */
  1472.         break;
  1473.  
  1474.     case DID_CANCEL:                    /* Escape or Cancel pressed */
  1475.         DialogResult=DID_CANCEL;        /* Dialog terminated with DID_CANCEL */
  1476.         break;
  1477.  
  1478.     default:
  1479.         return(WinDefDlgProc(hwndDlg, msg, mp1, mp2));
  1480.     }
  1481.     WinDismissDlg(hwndDlg, TRUE);       /* Clear up dialog */
  1482.     break;
  1483.  
  1484. default:                                /* Default window procedure must be called */
  1485.     return(WinDefDlgProc(hwndDlg, msg, mp1, mp2));
  1486. }
  1487. return((MRESULT)FALSE);                 /* We have handled the message */
  1488. }
  1489.  
  1490.  
  1491.