home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / VSWITCH.LZH / vswitch.c < prev    next >
C/C++ Source or Header  |  1992-08-12  |  13KB  |  519 lines

  1. /*
  2.          VSWITCH -- switch between full-screen OS/2 sessions
  3.  
  4.    Based on code by David Burton (Burton Systems Software) and Peter
  5.    Fitzsimmons (A:Ware).
  6.  
  7.          A:Ware BBS: (416)867-9663 or (416)867-9664
  8.          Burton BBS: (919)233-0106
  9.  
  10.    Task list modifications by Scott Dudley.
  11.  
  12.    This program is not copyrighted (public domain).
  13.  
  14. ----------------------------------------------------------------------------
  15. */
  16.  
  17. #define INCL_DOSSEMAPHORES
  18. #define INCL_DOSPROCESS
  19. #define INCL_SUB
  20. #define INCL_DOSMONITORS
  21. #define INCL_DOSINFOSEG
  22. #define INCL_WIN
  23. #define INCL_WINSWITCHLIST
  24. #include <os2.h>
  25.  
  26. #include <stdio.h>
  27. #include <conio.h> /*SJD Wed  08-12-1992  19:52:45 */
  28. #include <string.h>
  29. #include <stdlib.h>
  30. #include <process.h>
  31.  
  32. /* Bit mask to distinguish key press from key release */
  33. enum {RELEASE=0x40};
  34.  
  35. /* Maximum number of task list sessions we can examine */
  36. enum {MAXNUMSESS=32};
  37.  
  38. enum {MINSES=2, MAXSES=19};  /* we'll monitor sessions numbered 2..9 */
  39. /* Note: start with session 2 to skip dos box (session 0) and PM (session 1) */
  40.  
  41. /* KBD monitor data record */
  42. struct KeyPacket
  43.   {
  44.     unsigned mnflags;
  45.     KBDKEYINFO cp;
  46.     unsigned ddflags;
  47.   };
  48.  
  49. /* keyboard handle from monitor open */
  50. HKBD KBDHandle;
  51.  
  52. /* RAM semaphore cleared to kill program when any thread dies */
  53. static ULONG semDead = 0;
  54.  
  55. /* Activate pop-up screem? */
  56. static ULONG semPopup = 0;
  57.  
  58. /* ThreadProc_t is the type of the pointer-to-function parameter
  59.    expected by _beginthread() */
  60.  
  61. typedef void (_cdecl _far * ThreadProc_t)(void _far *);
  62.  
  63.  
  64.  
  65.  
  66. /* Switch to the specified session */
  67.  
  68. static void near switch_session(PSWBLOCK pswb, USHORT usSession) /*SJD Wed  08-12-1992  22:20:46 */
  69. {
  70.   WinSwitchToProgram(pswb->aswentry[usSession].hswitch);
  71. }
  72.  
  73.  
  74.  
  75.  
  76. /* Find the current process's entry in the task list, if any */
  77.  
  78. static USHORT near set_default(PSWBLOCK pswb, USHORT pidForeground)
  79. {
  80.   USHORT i;
  81.   USHORT pid;
  82. /*  char temp[100];
  83.  
  84.   sprintf(temp,"\r\nforeground PID is %d\r\n", pidForeground);
  85.   VioWrtTTY(temp, strlen(temp), 0);*/
  86.  
  87.   for (i=0; i < pswb->cswentry; i++)
  88.   {
  89. /*  sprintf(temp,"\r\nchecking %d\r\n", i);
  90.     VioWrtTTY(temp, strlen(temp), 0);*/
  91.  
  92.     /* See if this PID is for any of the parents in the session */
  93.  
  94.     pid=pidForeground;
  95.  
  96.     do
  97.     {
  98. /*    sprintf(temp, "checked pid %x (%s)  ", pid,
  99.               pid==pidForeground ? "PID" : "PPID");
  100.  
  101.       VioWrtTTY(temp, strlen(temp), 0);*/
  102.  
  103.       if (pid && pid==pswb->aswentry[i].swctl.idProcess)
  104.       {
  105. /*      sprintf(temp,"\r\nmatch on %d\r\n", i);
  106.         VioWrtTTY(temp, strlen(temp), 0);*/
  107.         return i;
  108.       }
  109.     }
  110.     while (pid && DosGetPPID(pid, &pid)==0);
  111.   }
  112.  
  113.   /* Else find the first available entry */
  114.  
  115.   if (pswb->aswentry[i].swctl.uchVisibility==SWL_VISIBLE)
  116.     return i;
  117.  
  118.   while (i < pswb->cswentry-1)
  119.     if (pswb->aswentry[++i].swctl.uchVisibility==SWL_VISIBLE)
  120.       return i;
  121.  
  122.   return 1;
  123. }
  124.  
  125.  
  126.  
  127.  
  128. /* Get screen dimensions */
  129.  
  130. static void near get_dims(USHORT *pusWidth, USHORT *pusHeight) /*SJD Wed  08-12-1992  19:52:28 */
  131. {
  132.   VIOMODEINFO vmi;
  133.  
  134.   VioGetMode(&vmi, 0);
  135.   *pusWidth=vmi.col;
  136.   *pusHeight=vmi.row;
  137. }
  138.  
  139.  
  140.  
  141. #define SELECTED 0x4000u    /* Bitmask indicating that <enter> or <space>   *
  142.                              * was pressed                                  */
  143.  
  144. static USHORT near get_key(PSWBLOCK pswb, USHORT usSelection) /*SJD Wed  08-12-1992  22:20:42 */
  145. {
  146.   USHORT usOrigSel=usSelection;
  147.   USHORT i, usTry;
  148.   int ch;
  149.  
  150.   switch (ch=getch())
  151.   {
  152.     case 0x1b:    /* esc */
  153.       return (USHORT)-1;
  154.  
  155.     case 0:   /* cursor key */
  156.     case 0xe0:
  157.       switch (getch())
  158.       {
  159.         case 45: /* alt-x */
  160.           return (USHORT)-2;
  161.  
  162.         case 79: /* end */
  163.         case 81: /* pgdn */
  164.           usSelection=pswb->cswentry-1;
  165.  
  166.           if (pswb->aswentry[usSelection].swctl.uchVisibility==SWL_VISIBLE)
  167.             break;
  168.           /* else fall-thru */
  169.  
  170.         case 72: /* up */
  171.         case 75: /* left */
  172.           while (usSelection != 0)
  173.           {
  174.             if (pswb->aswentry[--usSelection].swctl.uchVisibility==SWL_VISIBLE)
  175.               break;
  176.           }
  177.  
  178.           if (pswb->aswentry[usSelection].swctl.uchVisibility != SWL_VISIBLE)
  179.             usSelection=usOrigSel;
  180.           break;
  181.  
  182.         case 71: /* home */
  183.         case 73: /* pgup */
  184.           usSelection=0;
  185.  
  186.           if (pswb->aswentry[usSelection].swctl.uchVisibility==SWL_VISIBLE)
  187.             break;
  188.           /* else fall-thru */
  189.  
  190.         case 77: /* right */
  191.         case 80: /* down */
  192.           while (usSelection < pswb->cswentry-1)
  193.           {
  194.             if (pswb->aswentry[++usSelection].swctl.uchVisibility==SWL_VISIBLE)
  195.               break;
  196.           }
  197.  
  198.           if (pswb->aswentry[usSelection].swctl.uchVisibility != SWL_VISIBLE)
  199.             usSelection=usOrigSel;
  200.           break;
  201.       }
  202.       break;
  203.  
  204.     case 13:  /* enter */
  205.     case 32:  /* space */
  206.       return usSelection | SELECTED;
  207.       break;
  208.  
  209.     default:  /* select a session by letter */
  210.       ch=tolower(ch);
  211.       usTry=(USHORT)-1;
  212.  
  213.       for (i=0; i < pswb->cswentry; i++)
  214.         if (ch==tolower(*pswb->aswentry[i].swctl.szSwtitle))
  215.         {
  216.           if (usSelection==i ||
  217.               (i < usSelection &&
  218.                tolower(*pswb->aswentry[usSelection].swctl.szSwtitle)==ch))
  219.           {
  220.             /* If this letter is already selected, skip to the next         *
  221.              * one with this name.                                          */
  222.  
  223.             if (usTry==(USHORT)-1)
  224.               usTry=i;
  225.  
  226.             continue;
  227.           }
  228.  
  229.           return i;
  230.         }
  231.  
  232.       if (usTry != (USHORT)-1)
  233.         return usTry;
  234.       break;
  235.   }
  236.  
  237.   return usSelection;
  238. }
  239.  
  240. #define ATTR_NORMAL 31
  241. #define ATTR_SELECT 14
  242.  
  243. /* Ugly code which draws a task list window */
  244.  
  245. static void near draw_list(PSWBLOCK pswb, USHORT usWidth, USHORT usHeight, USHORT usSelection) /*SJD Wed  08-12-1992  22:20:37 */
  246. {
  247.   BYTE abCell[2];
  248.   USHORT usMenuWidth, usMenuHeight;
  249.   char temp[120];
  250.   USHORT usLeft, usTop;
  251.   USHORT i, len;
  252.   BYTE bAttr;
  253.  
  254.   usMenuWidth=usMenuHeight=0;
  255.  
  256.   /* Determine the size required to hold all task names */
  257.  
  258.   for (i=0; i < pswb->cswentry; i++)
  259.   {
  260.     if (pswb->aswentry[i].swctl.uchVisibility != SWL_VISIBLE)
  261.       continue;
  262.  
  263.     if ((len=strlen(pswb->aswentry[i].swctl.szSwtitle)) > usMenuWidth)
  264.       usMenuWidth=len;
  265.  
  266.     usMenuHeight++;
  267.   }
  268.  
  269.   /* Leave space for the border */
  270.  
  271.   usMenuWidth += 4;
  272.   usMenuHeight += 2;
  273.  
  274.   /* Center window */
  275.  
  276.   usLeft=(usWidth-usMenuWidth) >> 1;
  277.   usTop=(usHeight-usMenuHeight) >> 1;
  278.  
  279.   /* Draw the top border */
  280.  
  281.   abCell[1]=ATTR_NORMAL;
  282.  
  283.   abCell[0]='╔';  VioWrtNCell(abCell, 1, usTop, usLeft, 0);
  284.   abCell[0]='═';  VioWrtNCell(abCell, usMenuWidth-2, usTop, usLeft+1, 0);
  285.   abCell[0]='╗';  VioWrtNCell(abCell, 1, usTop, usLeft+usMenuWidth-1, 0);
  286.   usTop++;
  287.  
  288.   /* Draw the switch entries */
  289.  
  290.   for (i=0; i < pswb->cswentry; i++)
  291.   {
  292.     if (pswb->aswentry[i].swctl.uchVisibility != SWL_VISIBLE)
  293.       continue;
  294.  
  295.     /* left border */
  296.  
  297.     bAttr=ATTR_NORMAL;
  298.     VioWrtCharStrAtt("║", 1, usTop, usLeft, &bAttr, 0);
  299.  
  300.     /* Draw the application name */
  301.  
  302.     bAttr=(BYTE)((i==usSelection) ? ATTR_SELECT : ATTR_NORMAL);
  303.     sprintf(temp, " %-*s ", usMenuWidth-4,
  304.             pswb->aswentry[i].swctl.szSwtitle);
  305.  
  306.     VioWrtCharStrAtt(temp, usMenuWidth-2, usTop, usLeft+1, &bAttr, 0);
  307.  
  308.     /* right border */
  309.  
  310.     bAttr=ATTR_NORMAL;
  311.     VioWrtCharStrAtt("║", 1, usTop, usLeft+usMenuWidth-1, &bAttr, 0);
  312.  
  313.     /* draw shadow */
  314.  
  315.     bAttr=7;
  316.     VioWrtNAttr(&bAttr, 1, usTop, usLeft+usMenuWidth, 0);
  317.  
  318.     usTop++;
  319.   }
  320.  
  321.   /* bottom border */
  322.  
  323.   abCell[0]='╚';  VioWrtNCell(abCell, 1, usTop, usLeft, 0);
  324.   abCell[0]='═';  VioWrtNCell(abCell, usMenuWidth-2, usTop, usLeft+1, 0);
  325.   abCell[0]='╝';  VioWrtNCell(abCell, 1, usTop, usLeft+usMenuWidth-1, 0);
  326.  
  327.   /* Draw bottom of shadow */
  328.  
  329.   abCell[1]=7;
  330.   abCell[0]=' ';  VioWrtNAttr(&bAttr, 1, usTop, usLeft+usMenuWidth, 0);
  331.  
  332.   bAttr=7;        VioWrtNAttr(&bAttr, usMenuWidth, usTop+1, usLeft+1, 0);
  333. }
  334.  
  335.  
  336. /* Do the pop-up vio screen */
  337.  
  338. static void near do_popup(void) /*SJD Wed  08-12-1992  19:52:31 */
  339. {
  340.   SEL selG, selL;
  341.   GINFOSEG far *pgis;
  342.  
  343.   USHORT usSelection=0;
  344.   PSWBLOCK pswb;
  345.   ULONG ulcEntries;
  346.   ULONG usSize;
  347.   USHORT pfWait;
  348.   USHORT usWidth, usHeight;
  349.   USHORT pidForeground;
  350.  
  351.   /* Get the PID of the current foreground session */
  352.  
  353.   DosGetInfoSeg(&selG, &selL);
  354.   pgis=MAKEPGINFOSEG(selG);
  355.   pidForeground=pgis->pidForeground;
  356.  
  357.   /* Get a pop-up screen.  If we can't make it transparent, it means that   *
  358.    * some Vio program is in graphics mode.  In that case, try to make       *
  359.    * it opaque.                                                             */
  360.  
  361.   pfWait=VP_NOWAIT | VP_TRANSPARENT;
  362.  
  363.   if (VioPopUp(&pfWait, 0) != 0)
  364.   {
  365.     pfWait=VP_NOWAIT | VP_OPAQUE;
  366.  
  367.     if (VioPopUp(&pfWait, 0) != 0)
  368.     {
  369.       DosSemSet(&semPopup);
  370.       return;
  371.     }
  372.   }
  373.  
  374.   /* Get the switch list information */
  375.  
  376.   ulcEntries=WinQuerySwitchList(0, NULL, 0);
  377.   usSize=sizeof(SWBLOCK)+sizeof(HSWITCH)+(ulcEntries+4)*(long)sizeof(SWENTRY);
  378.  
  379.   /* Allocate memory for list */
  380.  
  381.   if ((pswb=malloc((unsigned)usSize)) != NULL)
  382.   {
  383.     /* Put the info in the list */
  384.  
  385.     ulcEntries=WinQuerySwitchList(0, pswb, (USHORT)(usSize-sizeof(SWENTRY)));
  386.  
  387.     /* Get screen size */
  388.  
  389.     get_dims(&usWidth, &usHeight);
  390.  
  391.     /* Set the default entry on our task list */
  392.  
  393.     usSelection=set_default(pswb, pidForeground);
  394.  
  395.     do
  396.     {
  397.       draw_list(pswb, usWidth, usHeight, usSelection);
  398.       usSelection=get_key(pswb, usSelection);
  399.     }
  400.     while ((usSelection & SELECTED)==0);
  401.   }
  402.  
  403.   /* Get rid of the pop-up screen */
  404.  
  405.   VioEndPopUp(0);
  406.  
  407.   /* Did the user press alt-x? */
  408.  
  409.   if (usSelection==(USHORT)-2)
  410.     DosSemClear(&semDead);
  411.   else if (usSelection != (USHORT)-1)
  412.     switch_session(pswb, usSelection & ~SELECTED);
  413.  
  414.   if (pswb)
  415.     free(pswb);
  416.  
  417.   /* Set the pop-up semaphore for next time 'round */
  418.  
  419.   DosSemSet(&semPopup);
  420. }
  421.  
  422.  
  423. void far _loadds cdecl monitor( long session )
  424.   {
  425.    struct KeyPacket keybufr;
  426.    USHORT count;  /* number of chars in monitor read/write buffer */
  427.    MONIN InBuff;  /* buffers for monitor read/writes: */
  428.    MONOUT OutBuff;
  429.  
  430.    keybufr.cp.chChar = 0;
  431.    InBuff.cb = sizeof(InBuff);
  432.    OutBuff.cb = sizeof(OutBuff);
  433.  
  434.     /* register the buffers to be used for monitoring */
  435.     if (DosMonReg( KBDHandle, (PBYTE)&InBuff, (PBYTE)&OutBuff, MONITOR_BEGIN,
  436.                    (USHORT)session ))
  437.         return;
  438.  
  439.     /* Main loop: read key into monitor buffer, examine it and take action
  440.        if it is one of our hot keys, otherwise pass it on to device driver */
  441.     for(;;)
  442.       {
  443.         count = sizeof(keybufr);
  444.  
  445.         if (DosMonRead( (PBYTE)&InBuff, IO_WAIT, (PBYTE)&keybufr, (PUSHORT)&count ))
  446.             break;
  447.  
  448.         if ((keybufr.ddflags & RELEASE)==0 && keybufr.cp.chScan==53 &&
  449.             (keybufr.cp.fsState & RIGHTALT))
  450.         {
  451.             DosSemClear(&semPopup);
  452.         }
  453.         else
  454.         {
  455.             if (DosMonWrite( (PBYTE)&OutBuff, (PBYTE)&keybufr, count ))
  456.                 break;
  457.         }
  458.       }/*for*/
  459.   } /* monitor */
  460.  
  461.  
  462. int cdecl main (void)
  463.   {
  464.     USHORT usSem; /* number of cleared semaphore */
  465.     DEFINEMUXSEMLIST(mxs, 2)
  466.     int i;
  467.  
  468.     /* Get a handle for registering buffers */
  469.     DosMonOpen ( "KBD$", &KBDHandle );
  470.  
  471.     /* Bump up the process priority so that Ctrl-Break (for instance) is
  472.        seen immediately */
  473.     (void)DosSetPrty( PRTYS_PROCESSTREE, PRTYC_TIMECRITICAL, 0, 0 );
  474.  
  475.     /* set semaphore (which will be cleared when the user presses hotkey) */
  476.  
  477.     DosSemSet(&semDead);
  478.     DosSemSet(&semPopup);
  479.  
  480.  
  481.     /* For each session, start a thread which installs itself as a keyboard
  482.        monitor to watch for hot-keys */
  483.  
  484.     for (i=MINSES; i<=MAXSES; i++)
  485.         _beginthread( (ThreadProc_t)monitor, NULL, 2048, (void far *)(long)i);
  486.  
  487.     /* Now set up the array for DosMuxSemWait */
  488.  
  489.     mxs.cmxs=2;
  490.  
  491.     mxs.amxs[0].zero=0;
  492.     mxs.amxs[0].hsem=&semPopup;
  493.  
  494.     mxs.amxs[1].zero=0;
  495.     mxs.amxs[1].hsem=&semDead;
  496.  
  497.     do
  498.     {
  499.       /* Wait until one of the specified semaphores is cleared */
  500.  
  501.       if (DosMuxSemWait(&usSem, &mxs, SEM_INDEFINITE_WAIT) != 0)
  502.         usSem=-1;
  503.  
  504.       if (usSem==0)
  505.         do_popup();
  506.  
  507.       DosSleep(1L); /* magic */
  508.     }
  509.     while (usSem==0); /* loop until we get a semDead */
  510.  
  511.     /* Close connection with keyboard */
  512.     DosMonClose ( KBDHandle );
  513.  
  514.     /* Exit - kill all threads */
  515.     DosExit ( EXIT_PROCESS, 0 );
  516.     return 0;  /* shut up compiler warning */
  517.   } /*main*/
  518.  
  519.