/***********************************************************************\ * PC2.c * * Copyright (C) by Stangl Roman, 1993 * * This Code may be freely distributed, provided the Copyright isn't * * removed, under the conditions indicated in the documentation. * * * * PC/2 - Program Commander/2 is a configurable program starter for * * OS/2 2.x PM. If the user clicks button 1 on the DESKTOP, a user * * modifyable popup menu is displayed. The user then selects a program * * to be started, or configuration of PC/2 or dismisses it. * * PC/2 is an alternative method of starting programs compared to * * icons and uses no space on DESKTOP, and no folder must be opended * * to start a program. For frequently used programs, this reduces the * * time to start an application. * * PC/2 also implements an optional virtual Desktop and sliding focus. * * * \***********************************************************************/ static char RCSID[]="@(#) $Header: PC2.c/PC2.h Version 1.60 06,1993 $ (LBL)"; #define _FILE_ "PC/2 - PC2.c V1.60" #include "PC2.h" /* User include files */ #include "Error.h" /* PC/2 semaphore to avoid loading PC/2 twice */ #define PC2_SEM "\\SEM32\\PC2_SEM.SEM" #define DESKTOP_CLASS "#37" /* Class name of the "Desktop" window handle (which is reserved in the Toolkit */ HEV hevPc2; /* Handle of PC/2 semaphore */ BOOL InstallHelp; /* True if we're installing */ UCHAR *pucFilenameProfile; /* The buffer holding the filename of the profile */ UCHAR *pucFilenameINI; /* Path and filename of PC2.INI */ UCHAR *pucFilenameHLP; /* The buffer holding the filename of the HLP file */ UCHAR *pucPathDLL; /* Directory of PC/2 to seek for DLL file */ HMODULE hDllPc2; /* Handle of PC/2 DLL */ PFFUNCPTR1 *pPC2DLL_SetParameters; /* Pointer to DLL-Functions */ PFFUNCPTR2 *pPC2DLL_QueryParameters; PFFUNCPTR3 *pPC2DLL_Hook; SWP swpApplications[64]; /* Window position of all enumerated applications except Window List, PC/2 and optionally Desktop */ ULONG ulApplicationsCount; /* Counter of last filled entry within array swpApplications */ /* *\ * Reserve data referenced generally through all modules. This isn't the best way, hope * * that C++ comes out soon... * \* */ HAB hab; /* Handle of PM anchor block */ HMQ hmq; /* Handle of message queue */ HWND hwndFrame; /* Frame handle of window */ HWND hwndClient; /* Client handle of window */ HWND hwndPopupMenu; /* Handel of popup menu window */ /* Input options: mouse button 1 depressed, Input devices keyboard or mouse button 1, popup menu allways visible on DESKTOP, position so that ID_CONFIGDIALOG is under the pointer */ HWND hwndHelp; /* Help window handle */ HOOKPARAMETERS HookParameters; /* Parameters passed to PC2HOOK.DLL */ SESSIONDATA SessionData; /* Used by Menu Installation dialog and by Program Installation dialog to store menu or program data, to be filled from the user or to be presented to the user. */ MENUDATA *pPopupMenu=NULL; /* Used by all procedures as the starting point of a linked list of menu entries. */ MENUDATA *pMenuData; /* This pointer points to the current level of Submenus and Menuitems within the configuration dialog procedure */ /* Create linked list by starting with this ID */ USHORT MenuDataId=ID_POPUPMENU; USHORT DialogResult; /* Each dialog procedure returns the result in this variable to enable the calling routine to check, if there is valid data or not. */ FILE *Pc2Profile; /* Open the profile, where the user entered menu data is stored, with this handle */ SWP swpScreen; /* The screen dimensions */ /*--------------------------------------------------------------------------------------*\ * The main procedure. * * Req: * * argc, argv, envp * * Returns: * * int ........... Exitcode (0, or errorlevel) * \*--------------------------------------------------------------------------------------*/ int main(int argc, char *argv[], char *envp[]) { QMSG qmsg; /* Message queue */ ULONG counter; /* Temporary counter */ /* Frame creation control flag */ ULONG flCreate=FCF_ICON | FCF_TITLEBAR | FCF_HIDEBUTTON | FCF_SIZEBORDER | FCF_TASKLIST | FCF_ACCELTABLE; /* Default the Popup-Menu is displayed after a WM_BUTTON1CLICK on the Desktop, but users may prefer WM_BUTTON1DBLCLK to popup the menu */ HookParameters.ulClickFlag=WM_BUTTON1DBLCLK; /* *\ * Get the full path and filename of the running copy of PC/2 and change the extension * * .EXE into .cfg to open the configuration file under this name. If the user supplies * * [-,/Profile filename.ext] then use this filename as the Profile. Also change .EXE * * into .HLP, .INI and PC/2 directory as the current directory to access .DLL. * \* */ /* Long enough to hold user Profile name */ pucFilenameProfile=malloc(strlen(argv[0])+64); pucFilenameINI=malloc(strlen(argv[0])+1); pucFilenameHLP=malloc(strlen(argv[0])+1); pucPathDLL=malloc(strlen(argv[0])+1); strcpy(pucFilenameProfile, argv[0]); strcpy(pucFilenameINI, argv[0]); strcpy(pucFilenameHLP, argv[0]); strcpy(pucPathDLL, argv[0]); strcpy(strchr(pucFilenameProfile, '.'), ".cfg"); strcpy(strchr(pucFilenameINI, '.'), ".ini"); strcpy(strchr(pucFilenameHLP, '.'), ".hlp"); strcpy(strrchr(pucPathDLL, '\\'), ""); /* Backward scan for \ */ InstallHelp=FALSE; /* Assume no installation */ for(counter=1; counterTID_USERMAX) /* Inform user if we can't find a timer */ USR_ERR("Cannot obtain a timer", hwndFrame, hwndClient); } break; case WM_PAINT: /* Draw overview of virtual Desktop */ { HPS hpsClient; RECTL rcClient; SWP swpClient; float fScaleX; /* Reduce factor to reduce horizontal size of virtual Desktop to horizonal client window size */ float fScaleY; POINTL ptlOrigin; /* Coordinates (0|0) within client area */ POINTL ptl[2]; /* Point of lines,... */ ULONG ulColor=1; /* Use least significant 2 bits for window colors */ LONG lTemp; /* Get a cached presentation space */ hpsClient=WinBeginPaint(hwnd, NULLHANDLE, &rcClient); /* Get the client area size */ WinQueryWindowPos(hwnd, &swpClient); /* Fill background of client area gray */ WinFillRect(hpsClient, &rcClient, CLR_PALEGRAY); /* Now get scale factor to scale virtual Desktop to client area */ fScaleX=(float)(swpClient.cx-1)/(3*HookParameters.DesktopSize.x); fScaleY=(float)(swpClient.cy)/(3*HookParameters.DesktopSize.y); /* Get coordinates (0|0) origin */ ptlOrigin.x=HookParameters.DesktopSize.x*fScaleX; ptlOrigin.y=HookParameters.DesktopSize.y*fScaleY; /* Draw the borders of the 3 * 3 Desktops */ GpiSetColor(hpsClient, CLR_YELLOW); for(lTemp=0; lTemp<=3; lTemp++) { ptl[0].x=0; ptl[0].y=ptlOrigin.y*lTemp; GpiMove(hpsClient, &ptl[0]); ptl[0].x=swpClient.cx; GpiLine(hpsClient, &ptl[0]); ptl[0].x=ptlOrigin.x*lTemp; ptl[0].y=0; GpiMove(hpsClient, &ptl[0]); ptl[0].y=swpClient.cy; GpiLine(hpsClient, &ptl[0]); } /* Get physical Desktop origin */ ptlOrigin.x+=(float)HookParameters.VirtualDesktopPos.x*fScaleX; ptlOrigin.y+=(float)HookParameters.VirtualDesktopPos.y*fScaleY; /* Now display the physical Desktop */ GpiSetColor(hpsClient, CLR_DARKRED); ptl[0].x=ptl[1].x=ptlOrigin.x; ptl[0].y=ptl[1].y=ptlOrigin.y; ptl[1].x+=(float)HookParameters.DesktopSize.x*fScaleX; ptl[1].y+=(float)HookParameters.DesktopSize.y*fScaleY; GpiMove(hpsClient, &ptl[0]); GpiBox(hpsClient, DRO_OUTLINEFILL, &ptl[1], 0, 0); GpiSetLineWidth(hpsClient, 3<<16); /* Set line width to 2 */ /* Now display the windows from topmost to bottommost */ for(lTemp=ulApplicationsCount; lTemp>=0; lTemp--) { GpiSetColor(hpsClient, 1+(ulColor & 0x3)); ptl[0].x=ptl[1].x=ptlOrigin.x+(float)swpApplications[lTemp].x*fScaleX; ptl[0].y=ptl[1].y=ptlOrigin.y+(float)swpApplications[lTemp].y*fScaleY; ptl[1].x+=(float)swpApplications[lTemp].cx*fScaleX; ptl[1].y+=(float)swpApplications[lTemp].cy*fScaleY; GpiMove(hpsClient, &ptl[0]); GpiBox(hpsClient, DRO_OUTLINE, &ptl[1], 0, 0); ulColor++; } WinEndPaint(hpsClient); } break; /* *\ * Syntax: WM_SETPOPUPMENU, NULL, NULL * \* */ case WM_SETPOPUPMENU: /* *\ * Open the profile for reading the linked list containing the popup menu data. If the * * profile can't be opened, the file is assumed to be empty so the popup menu is empty. * \* */ if((Pc2Profile=fopen(pucFilenameProfile, "r"))==NULL) { pPopupMenu=AllocateMenuData(); /* Allocate an empty MENUDATA structure used as the first element of linked list */ USR_ERR("Cannot open confguration file - assuming empty file", hwndFrame, hwndClient); } else { static UCHAR Buffer[256]; pPopupMenu=AllocateMenuData(); /* Allocate an empty MENUDATA structure used as the first element of linked list */ fgets(Buffer, sizeof(Buffer), Pc2Profile); if(strcmp(Buffer, "PROFILE START\n")==0) LoadMenu(pPopupMenu); /* Load the rest by calling a recursive procedure */ fclose(Pc2Profile); } pMenuData=pPopupMenu; /* Initialize *MENUDATA for Configuration dialog procedure to a known value */ break; case WM_TIMER: /* *\ * If we run without the WPS, the user may decide to start PMSHELL sometimes. If he * * does this, the window handle of the Desktop, where we catch the mouse button clicks * * changes. So we use the timer on a regular basis of about 2 seconds the query for the * * window handle to see any changes immediately. * \* */ /* Query all windows to initialize array holding all window positions, because windows may have been started or deleted */ WinPostMsg(hwnd, WM_DESKTOPMOVE, MPFROMLONG(0), MPFROMLONG(0)); /* *\ * Syntax: WM_SETDESKTOPHANDLE, NULL, NULL * \* */ case WM_SETDESKTOPHANDLE: /* *\ * Query the window handle of the Desktop windows and load them into PC2HOOK.DLL * * library. If the WPS is installed, we can obtain its handle by searching for a window * * class of #37. Even if the WPS is installed, we can also obtain the the window handle * * of the PM, which is also present, if the WPS isn't installed. * \* */ { UCHAR ucClass[8]; /* Save class name here */ HWND hwndWPS; /* Save WPS window handle */ HWND hwndDesktop; /* Save PM window handle */ HENUM henumWindows; /* Enumerate windows */ /* Get to bottommost window handle of the "Desktop" */ hwndDesktop=WinQueryWindow(HWND_DESKTOP, QW_BOTTOM); /* Enumerate all windows at "Desktop" z-order */ henumWindows=WinBeginEnumWindows(hwndDesktop); HookParameters.hwndWPS=0; while(hwndWPS=WinGetNextWindow(henumWindows)) { /* Now get the class name of that window handle */ WinQueryClassName(hwndWPS, sizeof(ucClass), (PCH)ucClass); /* If we find the required "Desktop" window (it has a class name of #37, which is reserved in the Toolkit) set this value into the Hook DLL. This class is owned by the WPS, so we found the WPS' window handle */ if(!strcmp(ucClass, DESKTOP_CLASS)) break; } WinEndEnumWindows(henumWindows); /* End enumeration */ /* *\ * Now get the PM window handle for the case, that the WPS is not installed, or moved * * outwards of the display (by setting the move Desktop checkbox). * \* */ /* Without WPS installed we can only get the "Desktop" window handle */ hwndDesktop=WinQueryDesktopWindow(hab, NULLHANDLE); /* Inform DLL if Desktop windows handles have changed */ if((hwndWPS!=HookParameters.hwndWPS) || (hwndDesktop!=HookParameters.hwndDesktop)) { HookParameters.hwndWPS=hwndWPS; HookParameters.hwndDesktop=hwndDesktop; pPC2DLL_SetParameters(&HookParameters); } } break; /* *\ * Syntax: WM_DESKTOPMOVE, LONG SlidingXFactor, LONG SlidingYFactor * \* */ case WM_DESKTOPMOVE: /* *\ * The hook found that button the pointer was over one of the border rows and/or * * columns of the physical Desktop. The passed parameter mp1 contains a bitmapped flag * * which direction all windows in the virtual Desktop should be move. We calculate * * if and where the physical Desktop must be moved, or ignore it, if we're allready at * * a border position on the virtual Desktop. * \* */ { LONG SlidingXFactor; /* Slide in x direction in pixels */ LONG SlidingYFactor; /* Slide in y direction in pixels */ BOOL bChanged=FALSE; /* TRUE if window(s) changes since last enumeration */ HENUM henumDesktop; /* Window handle of WC_FRAME class Desktop */ HWND hwndApplication; /* Window handles of enumerated application */ SWP swpCurrent; /* Window position of current enumerated application */ UCHAR ucClassname[7]; /* Class name of enumerated application */ UCHAR ucWindowText[33]; /* Window text of enumerated application */ SlidingXFactor=LONGFROMMP(mp1); SlidingYFactor=LONGFROMMP(mp2); /* Enumerate all descendants of HWND_DESKTOP, which are the frame windows seen on Desktop, but not having necessarily the class WC_FRAME */ henumDesktop=WinBeginEnumWindows(HWND_DESKTOP); ulApplicationsCount=0; /* Begin with offset 0 in first iteration */ while(hwndApplication=WinGetNextWindow(henumDesktop)) { WinQueryWindowPos(hwndApplication, &swpCurrent); WinQueryClassName(hwndApplication, sizeof(ucClassname), ucClassname); WinQueryWindowText(hwndApplication, sizeof(ucWindowText), ucWindowText); /* Only move WC_FRAME class (#1) windows and minimized icons class (#32765) windows. If it is such a window, overwrite current offset with next enumeration so that array only contains windows that must be moved */ if((strcmp(ucClassname, "#1")) && (strcmp(ucClassname, "#32765"))) continue; /* Ignore some zero-sized dummies? */ if((swpCurrent.cx==0) || (swpCurrent.cy==0)) continue; /* Seamless WIN-OS2 seems to introduce dummies? */ if(strstr(ucWindowText, "Seamless")) continue; /* Preserve Window list */ if(!strcmp(ucWindowText, "Window List")) continue; /* Preserve PC/2's window */ if(!strcmp(ucWindowText, "PC/2")) continue; /* Move Desktop only if user requested it */ if(!strcmp(ucWindowText, HookParameters.ucDesktopName) && !(HookParameters.ulStatusFlag & MOVEDESKTOP)) continue; /* Only move windows */ swpCurrent.fl=SWP_MOVE | SWP_NOADJUST; swpCurrent.x+=SlidingXFactor; swpCurrent.y+=SlidingYFactor; /* Now compare current one if it changed */ if(memcmp(&swpApplications[ulApplicationsCount], &swpCurrent, sizeof(SWP))) { bChanged=TRUE; memcpy(&swpApplications[ulApplicationsCount], &swpCurrent, sizeof(SWP)); } ulApplicationsCount++; } WinEndEnumWindows(henumDesktop); /* End enumeration */ /* Now move all windows */ if(SlidingXFactor || SlidingYFactor) { /* VirtualDesktopPos may have been changed */ pPC2DLL_QueryParameters(&HookParameters); bChanged=TRUE; if(!WinSetMultWindowPos(hab, swpApplications, ulApplicationsCount)) GEN_ERR(hab, hwndFrame, hwndClient); } /* If windows changed, repaint client area */ if(bChanged) WinInvalidateRect(hwnd, NULL, TRUE); } break; /* *\ * Syntax: WM_LOADHOOK, NULL, NULL * \* */ case WM_LOADHOOK: /* *\ * Install the hook into the system input queue pointing to the PC2DLL_Hook() procedure * * in the DLL PC2HOOK.DLL. If we can't do this we exit after an error message box. * \* */ /* Query and set the window handle of the Desktop */ WinSendMsg(hwnd, WM_SETDESKTOPHANDLE, NULL, NULL); if(WinSetHook( /* Set a hook */ hab, /* Handle of anchor block */ NULLHANDLE, /* Hook into system message queue */ HK_INPUT, /* Hook of system input queue */ (PFN)pPC2DLL_Hook, /* Pointer to hook procedure */ hDllPc2)==FALSE) { USR_ERR("Hooking the system input queue failed - exiting...", hwndFrame, hwndClient); WinPostMsg(hwnd, WM_QUIT, NULL, NULL); } break; /* *\ * Syntax: WM_POPUPMENU, (SHORT x, SHORT y), HWND hwndPopup * \* */ case WM_POPUPMENU: /* *\ * The hook found that button 1 was clicked on the Desktop and sent us this message. It * * is either a WM_BUTTON1CLICK or WM_BUTTON1DBLCLK. First we obtain the focus, to be * * able to start our programs in the foreground. * \* */ { POINTL ptlPopupPosition; HWND hwndPopup; USHORT fsOptions=PU_NONE | PU_KEYBOARD | PU_MOUSEBUTTON1 | PU_POSITIONONITEM | PU_HCONSTRAIN | PU_VCONSTRAIN; /* Get the position and window, where the user clicked to get the Popup-Menu */ ptlPopupPosition.x=(ULONG)SHORT1FROMMP(mp1); ptlPopupPosition.y=(ULONG)SHORT2FROMMP(mp1); hwndPopup=HWNDFROMMP(mp2); /* Map these window coordinated to display coordinates, so that the Menu will be displayed relative to the lower, left edge of the display */ WinMapWindowPoints(hwndPopup, HWND_DESKTOP, &ptlPopupPosition, sizeof(ptlPopupPosition)/sizeof(POINTL)); WinSetFocus(HWND_DESKTOP, hwnd); /* Set focus to our window */ if(!WinPopupMenu( /* Pop up the popup menu */ HWND_DESKTOP, /* Parent window handle */ hwnd, /* Owner window handle that receives all the notification messages generated by the pop-up menu */ hwndPopupMenu, /* Popup menu window handle */ ptlPopupPosition.x, /* x-coordinate of mouse pointer for popup menu */ ptlPopupPosition.y, /* y-coordinate of mouse pointer for popup menu */ ID_PC2SETUP, /* Input item identity, if PU_POSITIONONITEM or PU_SELECTITEM is set */ fsOptions) /* Input options */ ) GEN_ERR(hab, (HWND)NULL, (HWND)NULL); break; } case WM_CLOSE: if(WinMessageBox( /* Ask the user if he really wants to exit */ HWND_DESKTOP, HWND_DESKTOP, "Are you sure you want to close PC/2?", "PC/2 - Program Commander/2", ID_PC2MAINWINDOW, MB_OKCANCEL | MB_ICONQUESTION | MB_DEFBUTTON2)!=MBID_OK) return((MRESULT)TRUE); /* Only exit if OK is pressed */ if(WinReleaseHook( /* Release hook */ hab, /* Handle of anchor block */ NULLHANDLE, /* Release from system hook chain */ HK_INPUT, /* Hook of system input queue */ (PFN)pPC2DLL_Hook, /* Pointer to hook procedure */ hDllPc2)==FALSE) { USR_ERR("Unhooking the system input queue failed, System ShutDown suggested - exiting...", hwndFrame, hwndClient); WinPostMsg(hwnd, WM_QUIT, NULL, NULL); } DosFreeModule(hDllPc2); /* Free DLL reference */ WinPostMsg(hwnd, WM_QUIT, NULL, NULL); break; case HM_ERROR: { GEN_ERR(hab, hwndFrame, hwndClient); break; } case WM_COMMAND: { USHORT command; command=SHORT1FROMMP(mp1); /* Extract the command value */ /* *\ * Filter the IDs of the user defined items of the Popup-Menu. If one is found, call * * SearchItem() to search for the corresponding MENUDATA structure, copy it to a * * SESSIONDATA structure and start the session. * \* */ if((command>=USERITEMFIRST) && (command<=USERITEMLAST)) { ULONG id=(ULONG)command; MENUDATA *pMD=NULL; /* Search in the linked list for this entry */ if((pMD=SearchItem(pPopupMenu, &id))!=NULL) if(pMD->Item==ENTRYMENUITEM) { /* Load SessionData with MENUDATA structure */ LoadMenuData2SessionData(FALSE, pMD, &SessionData); /* Start the session */ StartSession(&SessionData); } } switch(command) { case ID_HELP: /* Display general help panel */ if(hwndHelp!=NULLHANDLE) WinSendMsg( hwndHelp, /* Help window */ HM_DISPLAY_HELP, /* Display a help panel */ MPFROMSHORT(ID_HELP), /* Panel ID in ressource file */ HM_RESOURCEID); /* MP1 points to the help window identity */ break; case ID_CONFIGDIALOG: /* Popup menuitem Configure Menu selected */ if(!WinDlgBox( /* Start Configure PC/2 dialog box */ HWND_DESKTOP, /* DESKTOP is parent */ HWND_DESKTOP, /* DESKTOP is owner */ CD_DialogProcedure, /* Dialog procedure of Program Installation dialog */ 0, /* Ressource is .EXE file */ CDID_CONFIGDIALOG, /* ID of Configure PC/2 dialog */ 0)) /* No initialization data */ GEN_ERR(hab, hwndFrame, hwndClient); break; case ID_DESKTOPDIALOG: /* Popup menuitem Configure Desktop selected */ if(!WinDlgBox(HWND_DESKTOP, HWND_DESKTOP, DD_DialogProcedure, 0, DDID_DESKTOPDIALOG, 0)) GEN_ERR(hab, hwndFrame, hwndClient); break; case ID_SHUTDOWN: /* ShutDown OS/2 menuitem selected */ if(WinMessageBox( /* Ask the user if he really wants to shut down OS/2 */ HWND_DESKTOP, HWND_DESKTOP, "Are you really sure you want to ShutDown OS/2?", "PC/2 - Program Commander/2", ID_PC2MAINWINDOW, MB_OKCANCEL | MB_ICONQUESTION | MB_DEFBUTTON2)!=MBID_OK) return((MRESULT)TRUE); /* Only shut down if OK is pressed */ if(!WinDlgBox( /* Start ShutDown OS/2 dialog box */ HWND_DESKTOP, HWND_DESKTOP, SD_DialogProcedure, 0, SDID_SHUTDOWNDIALOG, 0)) GEN_ERR(hab, hwndFrame, hwndClient); break; case ID_EXIT: /* User selected F3 to shutdown PC/2 */ WinPostMsg(hwnd, WM_CLOSE, 0, 0); break; case ID_ABOUTDIALOG: /* User selected About PC/2 dialog */ if(!WinDlgBox( /* Start About PC/2 dialog box */ HWND_DESKTOP, /* DESKTOP is parent */ HWND_DESKTOP, /* DESKTOP is owner */ AD_DialogProcedure, /* Dialog procedure of Program Installation dialog */ 0, /* Ressource is .EXE file */ ADID_ABOUTDIALOG, /* ID of Program Installation dialog */ 0)) /* No initialization data */ GEN_ERR(hab, hwndFrame, hwndClient); break; } break; } default: /* Default window procedure must be called */ return((MRESULT)WinDefWindowProc(hwnd, msg, mp1, mp2)); } return((MRESULT)FALSE); /* We have handled the message */ } /*--------------------------------------------------------------------------------------*\ * This dialog procedure handles the PC/2 - Configuration (Setup) dialog. * * Req: none * \*--------------------------------------------------------------------------------------*/ MRESULT EXPENTRY CD_DialogProcedure(HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2) { switch(msg) { case WM_INITDLG: { SWP swp; WinQueryWindowPos( /* Query position of dialog window */ hwndDlg, /* Handle of dialog window */ &swp); /* Fill with position */ WinSetWindowPos( /* Set dialog window position */ hwndDlg, /* Handle of dialog window */ HWND_TOP, /* Position on top and center of DESKTOP */ (swpScreen.cx-swp.cx)/2, (swpScreen.cy-swp.cy)/2, 0, 0, SWP_MOVE); /* Initialize the listbox */ WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL); break; } /* *\ * Syntax: WM_LOADPOPUPMENU, *MENUDATA, NULL * \* */ case WM_LOADPOPUPMENU: /* Load the current level of the Popup-Menu in the listbox after removing the old items */ { MENUDATA *pMD; pMD=PVOIDFROMMP(mp1); /* Get the pointer to the first MENUDATA of the current level */ WinSendDlgItemMsg( /* Send message to listbox */ hwndDlg, /* Handle of dialog window */ CDLB_MENUPROGRAM, /* Submenu & Program listbox */ LM_DELETEALL, /* Delete all list box items */ (MPARAM)NULL, (MPARAM)NULL); if(pMD==NULL) break; /* If linked list is empty break out */ do { if(pMD->Item==ENTRYSUBMENU) /* It is a Submenu */ { UCHAR Buffer[EF_SIZE60+4]; /* Add >> for a Submenu */ sprintf(Buffer, "%s >>", pMD->PgmTitle); WinSendDlgItemMsg( hwndDlg, CDLB_MENUPROGRAM, LM_INSERTITEM, /* Insert Submenu Title at the end */ MPFROMSHORT(LIT_END), MPFROMP(Buffer)); } if(pMD->Item==ENTRYMENUITEM) /* It's a Menuitem */ WinSendDlgItemMsg( hwndDlg, CDLB_MENUPROGRAM, LM_INSERTITEM, /* Insert Menuitem Title at the end */ MPFROMSHORT(LIT_END), MPFROMP(pMD->PgmTitle)); /* It may also be an empty entry, but then we ignore it, because it must be filled with Menuitem or Submenu data first */ if(pMD->Next!=NULL) /* Get through linked list without diving into Submenus */ pMD=pMD->Next; else break; /* We're at the end of the linked list */ }while(TRUE); break; } /* *\ * Syntax: WM_SAVEPOPUPMENU, NULL, NULL * \* */ case WM_SAVEPOPUPMENU: /* Save the Popup-Menu to the configuraion file */ if((Pc2Profile=fopen(pucFilenameProfile, "w"))==NULL) USR_ERR("Cannot open confguration file - changes won't be saved", hwndFrame, hwndClient); else { fprintf(Pc2Profile, "PROFILE START\n"); SaveMenu(pPopupMenu); /* Save the menu linked list */ fprintf(Pc2Profile, "PROFILE END\n"); fclose(Pc2Profile); } break; case WM_HELP: /* Help pressed */ WinSendMsg( hwndHelp, /* Help window */ HM_DISPLAY_HELP, /* Display a help panel */ MPFROMSHORT(ID_CONFIGDIALOG), /* Panel ID in ressource file */ HM_RESOURCEID); /* MP1 points to the help window identity */ break; case WM_COMMAND: /* Button pressed */ switch(SHORT1FROMMP(mp1)) { /* *\ * Chain up the linked list until we find the node, where this part-list comes from or * * the beginning of the complete list. The pointer pMenuData is adjusted. * \* */ case CDID_LEVELUP: /* Get up one level in the linked list */ { MENUDATA *pMD; /* Pointer to a MENUDATA structure to find the Submenu where this part-list starts */ pMD=pMenuData; /* Point to the first element of the linked list at the current level */ if(pMD->Back==NULL) /* If we're at the beginning of the complete linked list ignore button */ return((MRESULT)FALSE); else pMD=pMD->Back; /* Submenu which started current level */ /* Now chain back through the linked list and find the element, where the pointer to a Submenu equals the back pointer of the first element in this Submenu. Then we've found the node */ while(TRUE) { if(pMD->Back==NULL) /* If we're now at the beginning break */ break; if((pMD->Back)->Submenu==pMD) break; else pMD=pMD->Back; } pMenuData=pMD; /* Load as the top element of the current item */ /* Now redraw items in listbox */ WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL); return((MRESULT)FALSE); /* We handled this button */ } /* *\ * Test the user selection for being a Submenu. If one found chain into this submenu * * and adjust the pointer pMenuData. * \* */ case CDID_LEVELDOWN: /* Get down one level in the linked list */ { MENUDATA *pMD; /* Pointer to a MENUDATA structure to find the Submenu to chain into */ SHORT sCount; pMD=pMenuData; /* Point to the first element of the linked list at the current level */ /* Send message to listbox */ sCount=(SHORT)WinSendDlgItemMsg( hwndDlg, /* Handle of dialog window */ CDLB_MENUPROGRAM, /* Submenu & Program listbox */ LM_QUERYSELECTION, /* Query first selected list box item */ MPFROMSHORT(LIT_FIRST), (MPARAM)NULL); /* If no item selected, ignore this button */ if(sCount==LIT_NONE) return((MRESULT)FALSE); for( ;sCount>0; sCount--) /* Walk through the linked list to the selected item */ pMD=pMD->Next; if(pMD->Item!=ENTRYSUBMENU) /* It's not a Submenu that's selected, ignore */ return((MRESULT)FALSE); pMenuData=pMD->Submenu; /* Otherwise chain into this part-list */ /* Now redraw items in listbox */ WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL); return((MRESULT)FALSE); /* We handled this button */ } /* *\ * The user selected to add a (Sub)Menu. Thus dismiss the PC/2 Configuration dialog and * * load the (Sub)Menu Installation dialog. The new (Sub)Menu is entered in a * * STARTSESSION structure named StartSession. Save the changes and reload the PC/2 * * Configuration dialog again. * \* */ case CDID_ADDMENU: /* Add a Menu to PC/2 Configuration selected */ /* *\ * The user selected to add a Program. Thus dismiss the PC/2 Configuration dialog and * * load the Program Installation dialog. The new session data is entered in a * * STARTSESSION structure named StartSession. Save the changes and reload the PC/2 * * Configuration dialog again. * \* */ case CDID_ADDPROGRAM: /* Add a Program to PC/2 Configuration selected */ { UCHAR *pU; /* Temporary character pointer */ MENUDATA *pMD; /* Pointer to a MENUDATA structure to insert a new MENUDATA stucture after */ MENUDATA *pMDNew; /* Temporary pointer for the new item to be inserted after pMD */ SHORT sCount; pMD=pMenuData; /* Point to the first element of the linked list at the current level */ /* Send message to listbox */ sCount=(SHORT)WinSendDlgItemMsg( hwndDlg, /* Handle of dialog window */ CDLB_MENUPROGRAM, /* Submenu & Program listbox */ LM_QUERYSELECTION, /* Query first selected list box item */ MPFROMSHORT(LIT_FIRST), (MPARAM)NULL); /* If no item selected, and there exists one, add the new Menuitem after the last available Menuitem by querying the number from the listbox. Subtract 0 because we use 0-based instead 1-based. */ if((sCount==LIT_NONE) && (pMenuData->Item!=ENTRYEMPTY)) sCount=(SHORT)WinSendDlgItemMsg(hwndDlg, CDLB_MENUPROGRAM, LM_QUERYITEMCOUNT, MPFROM2SHORT(NULL, NULL), (MPARAM)NULL)-1; for( ;sCount>0; sCount--) /* Walk through the linked list to the selected item */ pMD=pMD->Next; /* Allocate a new item */ pMDNew=AllocateMenuData(); strcpy(pU=malloc(strlen("Insert here please")+1), "Insert here please"); free(pMDNew->PgmTitle); pMDNew->PgmTitle=pU; pMDNew->id=MenuDataId++; /* Increment ID */ /* Load SessionData with empty pMDNew structure */ LoadMenuData2SessionData(TRUE, pMDNew, &SessionData); WinDismissDlg(hwndDlg, TRUE); /* Clear up Configuration dialog */ if(SHORT1FROMMP(mp1)==CDID_ADDMENU) { if(!WinDlgBox( /* Start Addmenu PC/2 dialog box */ HWND_DESKTOP, /* DESKTOP is parent */ HWND_DESKTOP, /* DESKTOP is owner */ MI_DialogProcedure, /* Dialog procedure of Program Installation dialog */ 0, /* Ressource is .EXE file */ MIID_MENUDIALOG, /* ID of Addmenu PC/2 dialog */ 0)) /* No initialization data */ GEN_ERR(hab, hwndFrame, hwndClient); } else { if(!WinDlgBox( /* Start Program Installation dialog box */ HWND_DESKTOP, /* DESKTOP is parent */ HWND_DESKTOP, /* DESKTOP is owner */ PI_DialogProcedure, /* Dialog procedure of Program Installation dialog */ 0, /* Ressource is .EXE file */ PIID_PROGRAMDIALOG, /* ID of Addprogram PC/2 dialog */ 0)) /* No initialization data */ GEN_ERR(hab, hwndFrame, hwndClient); } if(DialogResult==DID_OK) /* If manipulation is done successfully, then load the SESSIONDATA structure back to the MENUDATA structure and save the changes */ { LoadSessionData2MenuData(pMDNew, &SessionData); if(pMD->Item!=ENTRYEMPTY) /* Add new entry, if the current entry isn't empty */ { if(SHORT1FROMMP(mp1)==CDID_ADDMENU) { /* It it is a Submenu, we also must add an empty first item for it */ MENUDATA *pMDTemp; pMDTemp=AllocateMenuData(); pMDNew->Submenu=pMDTemp; pMDTemp->Back=pMDNew; pMDNew->Item=ENTRYSUBMENU; } else pMDNew->Item=ENTRYMENUITEM; if(pMD->Next!=NULL) (pMD->Next)->Back=pMDNew; pMDNew->Next=pMD->Next; pMDNew->Back=pMD; pMD->Next=pMDNew; /* Insert item after the existing item */ SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMDNew), MPFROMLONG(pMD->id)); } else /* If it is an empty entry fill it with user data */ { UCHAR *pU; /* Temporary character pointer */ pMD->id=pMDNew->id; if(SHORT1FROMMP(mp1)==CDID_ADDMENU) { /* It it is a Submenu, we also must add an empty first item for it */ MENUDATA *pMDTemp; pMDTemp=AllocateMenuData(); pMD->Submenu=pMDTemp; pMDTemp->Back=pMD; pMD->Item=ENTRYSUBMENU; } else pMD->Item=ENTRYMENUITEM; strcpy(pU=malloc(strlen(pMDNew->PgmTitle)+1), pMDNew->PgmTitle); free(pMD->PgmTitle); pMD->PgmTitle=pU; strcpy(pU=malloc(strlen(pMDNew->PgmName)+1), pMDNew->PgmName); free(pMD->PgmName); pMD->PgmName=pU; strcpy(pU=malloc(strlen(pMDNew->PgmDirectory)+1), pMDNew->PgmDirectory); free(pMD->PgmDirectory); pMD->PgmDirectory=pU; strcpy(pU=malloc(strlen(pMDNew->PgmInputs)+1), pMDNew->PgmInputs); free(pMD->PgmInputs); pMD->PgmInputs=pU; pMD->SessionType=pMDNew->SessionType; pMD->PgmControl=pMDNew->PgmControl; pMD->FgBg=pMDNew->FgBg; pMD->InitXPos=pMDNew->InitXPos; pMD->InitYPos=pMDNew->InitYPos; pMD->InitXSize=pMDNew->InitXSize; pMD->InitYSize=pMDNew->InitYSize; if(pMD->Back!=NULL) /* This is the first item of a Submenu, then insert it there */ SetPopupMenu(MM_INSERTITEMSUBMENU, MPFROMP(pMD), MPFROMLONG((pMD->Back)->id)); else /* This is the complete first item of the linked list, so insert at the end */ SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMD), MPFROMLONG(MIT_END)); free(pMDNew->PgmTitle); /* Free temporary used structure */ free(pMDNew->PgmName); free(pMDNew->PgmDirectory); free(pMDNew->PgmInputs); free(pMDNew); } } else { free(pMDNew->PgmTitle); /* Free temporary MENUDATA structure */ free(pMDNew->PgmName); free(pMDNew->PgmDirectory); free(pMDNew->PgmInputs); free(pMDNew); } /* Initialize the listbox */ WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL); if(!WinDlgBox( /* Now reload the Configuration dialog */ HWND_DESKTOP, HWND_DESKTOP, CD_DialogProcedure, 0, CDID_CONFIGDIALOG, 0)) GEN_ERR(hab, hwndFrame, hwndClient); break; /* We never get here because of calling WinDlgBox() */ } /* *\ * The user selected to change an item. Thus dismiss the PC/2 Configuration dialog and * * load the Menu or Program Installation dialog. The new session data is entered in a * * STARTSESSION structure named StartSession. * * Then reload the PC/2 Configuration dialog again. * \* */ case CDID_CHANGEENTRY: /* Change a Menu or Program configuration selected */ { MENUDATA *pMD; SHORT sCount; pMD=pMenuData; /* Point to the first element of the linked list at the current level */ /* Send message to listbox */ sCount=(SHORT)WinSendDlgItemMsg( hwndDlg, /* Handle of dialog window */ CDLB_MENUPROGRAM, /* Submenu & Program listbox */ LM_QUERYSELECTION, /* Query first selected list box item */ MPFROMSHORT(LIT_FIRST), (MPARAM)NULL); if(sCount==LIT_NONE) /* If no item selected ignore this button */ return((MRESULT)FALSE); for( ;sCount>0; sCount--) /* Walk through the linked list to the selected item */ pMD=pMD->Next; /* Now load the MENUDATA to SESSIONDATA structure where the manipulations will take effect */ LoadMenuData2SessionData(FALSE, pMD, &SessionData); WinDismissDlg(hwndDlg, TRUE); /* Clear up Configuration dialog */ if(pMD->Submenu==NULL) /* It's a Menuitem so call the Program Installation dialog box */ { if(!WinDlgBox( /* Start Program Installation dialog box */ HWND_DESKTOP, /* DESKTOP is parent */ HWND_DESKTOP, /* DESKTOP is owner */ PI_DialogProcedure, /* Dialog procedure of Program Installation dialog */ 0, /* Ressource is .EXE file */ PIID_PROGRAMDIALOG, /* ID of Program Installation PC/2 dialog */ 0)) /* No initialization data */ GEN_ERR(hab, hwndFrame, hwndClient); } else /* It's a Submenu so call the Menu Installation dialog box */ { if(!WinDlgBox( /* Start Addmenu PC/2 dialog box */ HWND_DESKTOP, /* DESKTOP is parent */ HWND_DESKTOP, /* DESKTOP is owner */ MI_DialogProcedure, /* Dialog procedure of Program Installation dialog */ 0, /* Ressource is .EXE file */ MIID_MENUDIALOG, /* ID of Addmenu PC/2 dialog */ 0)) /* No initialization data */ GEN_ERR(hab, hwndFrame, hwndClient); } if(DialogResult==DID_OK) /* If manipulation is done successfully, then load the SESSIONDATA structure back to the MENUDATA structure and save the changes */ { LoadSessionData2MenuData(pMD, &SessionData); /* Now change the menuitem text to the new one */ SetPopupMenu(MM_SETITEMTEXT, MPFROMP(pMD), MPFROMLONG(pMD->id)); /* Initialize the listbox */ WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL); } if(!WinDlgBox( /* Now reload the Configuration dialog */ HWND_DESKTOP, HWND_DESKTOP, CD_DialogProcedure, 0, CDID_CONFIGDIALOG, 0)) GEN_ERR(hab, hwndFrame, hwndClient); break; /* We never get here because of calling WinDlgBox() */ } /* *\ * The user selected to remove an item. If thist item is the only one in the linked * * list or the first item of a submenu set it to empty otherwise free it's ressources * * and remove the entry. * \* */ case CDID_REMOVEENTRY: /* Remove a item of the PC/2 Configuration selected */ { UCHAR *pU; MENUDATA *pMD; SHORT sCount; pMD=pMenuData; /* Point to the first element of the linked list at the current level */ /* Send message to listbox */ sCount=(SHORT)WinSendDlgItemMsg( hwndDlg, /* Handle of dialog window */ CDLB_MENUPROGRAM, /* Submenu & Program listbox */ LM_QUERYSELECTION, /* Query first selected list box item */ MPFROMSHORT(LIT_FIRST), (MPARAM)NULL); if(sCount==LIT_NONE) /* If no item selected ignore this button */ return((MRESULT)FALSE); for( ;sCount>0; sCount--) /* Walk through the linked list to the selected item */ pMD=pMD->Next; while(TRUE) { if((pMD->Back==NULL) && (pMD->Next!=NULL)) { /* Remove the first item of the complete linked list */ if(pMD->Item==ENTRYSUBMENU) if((pMD->Submenu)->Item==ENTRYEMPTY) { /* If it is an empty Submenu remove it completely */ /* Remove the Submenu and the empty first item from the Popup-Menu */ SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id)); free((pMD->Submenu)->PgmTitle); free((pMD->Submenu)->PgmName); free((pMD->Submenu)->PgmDirectory); free((pMD->Submenu)->PgmInputs); free(pMD->Submenu); (pMD->Next)->Back=NULL; /* Now next element is the first one */ pPopupMenu=pMD->Next; pMenuData=pMD->Next; free(pMD->PgmTitle); free(pMD->PgmName); free(pMD->PgmDirectory); free(pMD->PgmInputs); free(pMD); break; /* Ensure we only test once, because each routine changes the pointers */ } if(pMD->Item==ENTRYMENUITEM) { /* If it is an empty Menuitem remove it completly */ (pMD->Next)->Back=NULL; /* Now next element is the first one */ pPopupMenu=pMD->Next; pMenuData=pMD->Next; /* Remove the item from the Popup-Menu */ SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id)); free(pMD->PgmTitle); free(pMD->PgmName); free(pMD->PgmDirectory); free(pMD->PgmInputs); free(pMD); break; /* Ensure we only test once, because each routine changes the pointers */ } } if((pMD->Back==NULL) && (pMD->Next==NULL)) { /* If it is the one and only item of the linked list set it to empty */ if(pMD->Item==ENTRYSUBMENU) if((pMD->Submenu)->Item==ENTRYEMPTY) { /* If it is an empty Submenu remove the empty item completely */ /* Remove the item from the Popup-Menu */ SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id)); free((pMD->Submenu)->PgmTitle); free((pMD->Submenu)->PgmName); free((pMD->Submenu)->PgmDirectory); free((pMD->Submenu)->PgmInputs); free(pMD->Submenu); free(pMD->PgmTitle); strcpy(pU=malloc(strlen("")+1), ""); pMD->PgmTitle=pU; free(pMD->PgmName); strcpy(pU=malloc(strlen("")+1), ""); pMD->PgmName=pU; free(pMD->PgmDirectory); strcpy(pU=malloc(strlen("")+1), ""); pMD->PgmDirectory=pU; free(pMD->PgmInputs); strcpy(pU=malloc(strlen("")+1), ""); pMD->PgmInputs=pU; pMD->Item=ENTRYEMPTY; pMD->Back=NULL; pMD->Submenu=NULL; pMD->Next=NULL; break; /* Ensure we only test once, because each routine changes the pointers */ } if(pMD->Item==ENTRYMENUITEM) { /* If it is a Menuitem set it to empty */ /* Remove the item from the Popup-Menu */ SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id)); strcpy(pU=malloc(strlen("")+1), ""); pMD->PgmTitle=pU; free(pMD->PgmName); strcpy(pU=malloc(strlen("")+1), ""); pMD->PgmName=pU; free(pMD->PgmDirectory); strcpy(pU=malloc(strlen("")+1), ""); pMD->PgmDirectory=pU; free(pMD->PgmInputs); strcpy(pU=malloc(strlen("")+1), ""); pMD->PgmInputs=pU; pMD->Item=ENTRYEMPTY; pMD->Back=NULL; pMD->Submenu=NULL; pMD->Next=NULL; break; /* Ensure we only test once, because each routine changes the pointers */ } } if(pMD->Back!=NULL) { /* It is any item of more than one item and not the first one */ if(((pMD->Back)->Submenu==pMD) && (pMD->Submenu==NULL) && (pMD->Next==NULL)) { /* If it is the first item of a Submenu not followed by any item, set it to empty */ /* Remove the item from the Popup-Menu */ SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id)); strcpy(pU=malloc(strlen("")+1), ""); pMD->PgmTitle=pU; free(pMD->PgmName); strcpy(pU=malloc(strlen("")+1), ""); pMD->PgmName=pU; free(pMD->PgmDirectory); strcpy(pU=malloc(strlen("")+1), ""); pMD->PgmDirectory=pU; free(pMD->PgmInputs); strcpy(pU=malloc(strlen("")+1), ""); pMD->Item=ENTRYEMPTY; break; /* Ensure we only test once, because each routine changes the pointers */ } if(pMD->Item==ENTRYSUBMENU) if((pMD->Submenu)->Item==ENTRYEMPTY) { /* If it is an empty Submenu so also remove the first item in the Submenu */ /* Remove the Submenu and the empty first item from the Popup-Menu */ SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id)); free((pMD->Submenu)->PgmTitle); free((pMD->Submenu)->PgmName); free((pMD->Submenu)->PgmDirectory); free((pMD->Submenu)->PgmInputs); free(pMD->Submenu); if(((pMD->Back)->Submenu==pMD) && (pMD->Next==NULL)) { /* If the previous item is a Submenu, this item is the first item of it. If none item follows, set this item to empty */ strcpy(pU=malloc(strlen("")+1), ""); pMD->PgmTitle=pU; free(pMD->PgmName); strcpy(pU=malloc(strlen("")+1), ""); pMD->PgmName=pU; free(pMD->PgmDirectory); strcpy(pU=malloc(strlen("")+1), ""); pMD->PgmDirectory=pU; free(pMD->PgmInputs); strcpy(pU=malloc(strlen("")+1), ""); pMD->Item=ENTRYEMPTY; pMD->Submenu=NULL; pMD->Next=NULL; break; /* Ensure we only test once, because each routine changes the pointers */ } if(((pMD->Back)->Submenu==pMD) && (pMD->Next!=NULL)) { /* If the previous item is a Submenu, this item ist the first item of it. If one item follows adjust the pointer to the current level of items */ pMenuData=pMD->Next; (pMD->Back)->Submenu=pMD->Next; if(pMD->Next!=NULL) (pMD->Next)->Back=pMD->Back; free(pMD->PgmTitle); free(pMD->PgmName); free(pMD->PgmDirectory); free(pMD->PgmInputs); free(pMD); break; /* Ensure we only test once, because each routine changes the pointers */ } if((pMD->Back)->Submenu!=pMD) { /* If this item isn't the first item of a Submenu */ (pMD->Back)->Next=pMD->Next; if(pMD->Next!=NULL) (pMD->Next)->Back=pMD->Back; free(pMD->PgmTitle); free(pMD->PgmName); free(pMD->PgmDirectory); free(pMD->PgmInputs); free(pMD); break; /* Ensure we only test once, because each routine changes the pointers */ } } if(pMD->Item==ENTRYMENUITEM) { /* If it is a Menuitem, just remove it completly */ /* Remove the item from the Popup-Menu */ SetPopupMenu(MM_DELETEITEM, MPFROMP(pMD), MPFROMLONG(pMD->id)); if(((pMD->Back)->Submenu==pMD) && (pMD->Next==NULL)) { /* If the previous item is a Submenu, this item is the first item of it. If none item follows, set this item to empty */ strcpy(pU=malloc(strlen("")+1), ""); pMD->PgmTitle=pU; free(pMD->PgmName); strcpy(pU=malloc(strlen("")+1), ""); pMD->PgmName=pU; free(pMD->PgmDirectory); strcpy(pU=malloc(strlen("")+1), ""); pMD->PgmDirectory=pU; free(pMD->PgmInputs); strcpy(pU=malloc(strlen("")+1), ""); pMD->Item=ENTRYEMPTY; pMD->Submenu=NULL; pMD->Next=NULL; break; /* Ensure we only test once, because each routine changes the pointers */ } if(((pMD->Back)->Submenu==pMD) && (pMD->Next!=NULL)) { /* If the previous item is a Submenu, this item ist the first item of it. If one item follows adjust the pointer to the current level of items */ pMenuData=pMD->Next; (pMD->Back)->Submenu=pMD->Next; if(pMD->Next!=NULL) (pMD->Next)->Back=pMD->Back; free(pMD->PgmTitle); free(pMD->PgmName); free(pMD->PgmDirectory); free(pMD->PgmInputs); free(pMD); break; /* Ensure we only test once, because each routine changes the pointers */ } if((pMD->Back)->Submenu!=pMD) { /* If this item isn't the first item of a Submenu */ (pMD->Back)->Next=pMD->Next; if(pMD->Next!=NULL) (pMD->Next)->Back=pMD->Back; free(pMD->PgmTitle); free(pMD->PgmName); free(pMD->PgmDirectory); free(pMD->PgmInputs); free(pMD); break; /* Ensure we only test once, because each routine changes the pointers */ } } } break; /* If we come here, we're trying to remove an not empty Submenu, but we also must exit the endless loop */ } /* Initialize the listbox */ WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL); return((MRESULT)FALSE); /* We have done everything */ } /* *\ * The user selected to resort the current level of the menuentries. Load the dialog * * and let the user resort the linked list of menues pointed to by pMenuData and to * * resort the menuentries of the Popup-Menu. * \* */ case CDID_RESORT: /* Load the resort dialog */ { WinDismissDlg(hwndDlg, TRUE); /* Clear up Configuration dialog */ if(!WinDlgBox( /* Start Resort dialog box */ HWND_DESKTOP, /* DESKTOP is parent */ HWND_DESKTOP, /* DESKTOP is owner */ RD_DialogProcedure, /* Dialog procedure of Program Installation dialog */ 0, /* Ressource is .EXE file */ RDID_RESORTDIALOG, /* ID of Program Installation PC/2 dialog */ 0)) /* No initialization data */ GEN_ERR(hab, hwndFrame, hwndClient); if(!WinDlgBox( /* Now reload the Configuration dialog */ HWND_DESKTOP, HWND_DESKTOP, CD_DialogProcedure, 0, CDID_CONFIGDIALOG, 0)) GEN_ERR(hab, hwndFrame, hwndClient); } break; case DID_OK: /* Enter key pressed */ /* Save the changes */ WinSendMsg(hwndDlg, WM_SAVEPOPUPMENU, NULL, NULL); DialogResult=DID_OK; /* Dialog terminated with DID_OK */ break; case DID_CANCEL: /* Escape or Cancel pressed */ DialogResult=DID_CANCEL; /* Dialog terminated with DID_CANCEL */ break; default: return(WinDefDlgProc(hwndDlg, msg, mp1, mp2)); } WinDismissDlg(hwndDlg, TRUE); /* Clear up dialog */ break; default: /* Default window procedure must be called */ return(WinDefDlgProc(hwndDlg, msg, mp1, mp2)); } return((MRESULT)FALSE); /* We have handled the message */ }