home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / spmio10.zip / gcc2 / stdwin / stdwin.cc < prev    next >
C/C++ Source or Header  |  1994-08-28  |  12KB  |  396 lines

  1.  
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include "stdwin.h"
  5.  
  6. #ifdef NDEBUG
  7. #define LOG(format, args...)
  8. #else
  9. FILE *logfile;
  10. #define LOG(format, args...) \
  11. fprintf (logfile, "%s:%d: " format "\n", __FILE__, __LINE__ , ##args )
  12. #endif
  13.  
  14. /* The purpose of this class is to provide a scope whose members all
  15.  * have friend priveledges with respect to class StdWin
  16.  */
  17. class StdWinUtils
  18. {
  19. public:
  20.   static MRESULT ClientWindowProcedure (HWND, unsigned long, MPARAM, MPARAM);
  21. };
  22.  
  23. /* The Name of the PM class created to deal with std windows */
  24. const char * const classname = "FreeStandardWindow";
  25.  
  26. /* get_hab -- get the HAB handle for the program.  If the user mislinks
  27.  * his application, this call will fail.  On the bright side, if he mislinks
  28.  * his app, stdio probably works, so we can issue a diagnostic.
  29.  */
  30. static HAB get_hab ()
  31. {
  32.   HAB hab = WinInitialize (0);
  33. #ifndef NDEBUG
  34.   logfile = fopen ("log", "wt");
  35.   setbuf (logfile, 0);
  36. #endif
  37.   LOG ("In get_hab");
  38.   if (hab == 0)
  39.     {
  40.       fprintf (stderr,
  41.            "WinInitialize failed.  Did you forget to put WINDOWAPI in "
  42.            "your linker\n definition file?");
  43.       exit (1);
  44.     }
  45.   /* Register the client class for StdWin before any windows are created */
  46.   WinRegisterClass (hab, classname, StdWinUtils::ClientWindowProcedure,
  47.             CS_SIZEREDRAW, sizeof (void *));
  48.   return hab;
  49. }
  50.  
  51. /* get_hab -- get the HAB handle for the program.  Another opportunity
  52.  * to make fun of the user who mislinks his application.
  53.  */
  54. static HMQ get_hmq ()
  55. {
  56.   HMQ hmq = WinCreateMsgQueue (StdWin::hab, 0);
  57.   if (hmq == 0)
  58.     {
  59.       fprintf (stderr,
  60.            "WinCreateMsgQueue failed.  Did you forget to put WINDOWAPI in "
  61.            "your linker\n definition file?");
  62.       exit (1);
  63.     }
  64.   LOG ("finished get_hmq");
  65.   return hmq;
  66. }
  67.  
  68. /* Class static data - HAB and HMQ handles */
  69. HAB StdWin::hab = get_hab ();
  70. HMQ StdWin::hmq = get_hmq ();
  71.  
  72. /* Phony Object to effect the destruction of the hab and hmq when the
  73.  * program exits */
  74. class Destroyer
  75. {
  76. public:
  77.   ~Destroyer ();
  78. };
  79. static Destroyer destroyer;
  80. Destroyer::~Destroyer ()
  81. {
  82.   WinDestroyMsgQueue(StdWin::hmq);
  83.   WinTerminate(StdWin::hab);
  84. }
  85.  
  86.  
  87. /* Variable used for communicating the window being created between
  88.  * StdWin::activate_window and ClientWindowProcedure.  Note that this
  89.  * only works if we have only one thread of execution.  To improve this,
  90.  * we need to avoid WinCreateStdWindow and create the window the hard way.
  91.  * But that would be harder to read and understand. */
  92. static StdWin *activating_window = 0;
  93.  
  94. /* ClientWindowProcedure -- the function that accepts all PM messages
  95.  * on behalf of all instances of StdWin.  This function will find the
  96.  * appropriate StdWin instance that the client window belongs to
  97.  * and pass the message on to the instance's own message handler.
  98.  */
  99. MRESULT StdWinUtils::ClientWindowProcedure (HWND win, unsigned long msg,
  100.                         MPARAM mp1, MPARAM mp2)
  101. {
  102.   StdWin *window_object;
  103.   if (msg == WM_CREATE && activating_window != 0)
  104.     {
  105.       window_object = activating_window;
  106.       activating_window = 0;
  107.       WinSetWindowPtr (win, 0, window_object);
  108.     }
  109.   else
  110.     window_object = (StdWin *) WinQueryWindowPtr (win, 0);
  111.   if (window_object != 0)
  112.     return window_object->message (win, msg, mp1, mp2);
  113.   // Punt
  114.   LOG ("Punting message");
  115.   return WinDefWindowProc (win, msg, mp1, mp2);
  116. }
  117.  
  118. /* Stdwin object constructor.
  119.  * The default frame style is a frame with everything except those items
  120.  * which require a resource file
  121.  */
  122. StdWin::StdWin ()
  123. : window (0),
  124.   style_flags (FCF_SYSMENU | FCF_TASKLIST | FCF_SIZEBORDER | FCF_TITLEBAR
  125.            | FCF_MINMAX | FCF_SHELLPOSITION),
  126.   resource_id (0),
  127.   window_is_active (0)
  128. {
  129. }
  130.  
  131. /* Stdwin object destructor */
  132. StdWin::~StdWin ()
  133. {
  134.   // Destroy the window if the user left it active.
  135.   destroy_window ();
  136. }
  137.  
  138. /* Functions to change the frame options.  These must be called before
  139.  * the window is activated.
  140.  * Does anyone think this would be more readable and easier to maintain
  141.  * without these macros?
  142.  */
  143. #define ENABLE(item, bit)            \
  144. void StdWin::enable_##item()            \
  145. {                        \
  146.   style_flags |= FCF_##bit;            \
  147. }                        \
  148. void StdWin::disable_##item()            \
  149. {                        \
  150.   style_flags &= ~ (FCF_##bit);            \
  151. }
  152. ENABLE (acceltable, ACCELTABLE);
  153. ENABLE (icon, ICON);
  154. ENABLE (maxbutton, MAXBUTTON);
  155. ENABLE (menu, MENU);
  156. ENABLE (minbutton, MINBUTTON);
  157. ENABLE (minmax, MINMAX);
  158. ENABLE (shellposition, SHELLPOSITION);
  159. ENABLE (sizeborder, SIZEBORDER);
  160. ENABLE (sysmenu, SYSMENU);
  161. ENABLE (tasklist, TASKLIST);
  162. ENABLE (titlebar, TITLEBAR);
  163.  
  164. /* The function that causes a PM window to be created that is controlled
  165.  * by this StdWin instance.
  166.  */
  167. void StdWin::activate_window ()
  168. {
  169.   HWND foo;
  170.   activating_window = this;
  171.   window_is_active = 1;
  172.   WinCreateStdWindow (HWND_DESKTOP, WS_VISIBLE, &style_flags,
  173.               classname, 0, 0, 0, resource_id, &foo);
  174. }
  175.  
  176. /* A function to shutdown/remove the PM window controlled by this StdWin
  177.  * instance */
  178. void StdWin::destroy_window ()
  179. {
  180.   if (window_is_active)
  181.     WinDestroyWindow(frame);
  182.   window_is_active = 0;
  183. }
  184.  
  185. /* A member function that accepts all PM messages directed at the PM window
  186.  * controlled by this StdWin instance.
  187.  * The default behavior of this handler is to decode the mp1 and mp2
  188.  * message arguments and send the message on to a message-specific virtual
  189.  * member function for further processing.
  190.  */
  191. MRESULT StdWin::message (HWND win, unsigned amsg, MPARAM amp1, MPARAM amp2)
  192. {
  193.   unsigned save_msg = amsg;
  194.   MPARAM save_mp1 = mp1;
  195.   MPARAM save_mp2 = mp2;
  196.   window = win;
  197.   msg = amsg;
  198.   mp1 = amp1;
  199.   mp2 = amp2;
  200.   MRESULT ret;
  201.   switch (msg)
  202.     {
  203.     case WM_CREATE:
  204.       // Init the instance's frame window handle
  205.       frame = WinQueryWindow (win, QW_PARENT);
  206.       ret = msg_create ();
  207.       break;
  208.       
  209.     case WM_ACTIVATE:
  210.       ret = msg_activate (SHORT1FROMMP (mp1), (HWND) mp2);
  211.       break;
  212.     case WM_ADJUSTWINDOWPOS:
  213.       ret = msg_adjustwindowpos ((SWP *) mp1);
  214.       break;
  215.     case WM_CHAR:
  216.       ret = msg_char (SHORT1FROMMP (mp1), CHAR3FROMMP (mp1), CHAR4FROMMP (mp1),
  217.               SHORT1FROMMP (mp2), SHORT2FROMMP (mp2));
  218.       break;
  219.     case WM_CLOSE:
  220.       ret = msg_close ();
  221.       break;
  222.     case WM_CONTROLPOINTER:
  223.       ret = msg_controlpointer (SHORT1FROMMP (mp1), (HPOINTER) mp2);
  224.       break;
  225.     case WM_DESTROY:
  226.       ret = msg_destroy ();
  227.       break;
  228.     case WM_ERASEBACKGROUND:
  229.       ret = msg_erasebackground ((HPS) mp1, (RECTL *) mp2);
  230.       break;
  231.     case WM_FOCUSCHANGE:
  232.       ret = msg_focuschange ((HWND) mp1,
  233.                  SHORT1FROMMP (mp2), SHORT2FROMMP (mp2));
  234.       break;
  235.     case WM_FORMATFRAME:
  236.       ret = msg_formatframe ((SWP *) mp1, (RECTL *) mp2);
  237.       break;
  238.     case WM_MOUSEMOVE:
  239.       ret = msg_mousemove (SHORT1FROMMP (mp1), SHORT2FROMMP (mp1),
  240.                SHORT1FROMMP (mp2), SHORT2FROMMP (mp2));
  241.       break;
  242.     case WM_PAINT:
  243.       ret = msg_paint ();
  244.       break;
  245.     case WM_REALIZEPALETTE:
  246.       ret = msg_realizepalette ();
  247.       break;
  248.     case WM_SAVEAPPLICATION:
  249.       ret = msg_saveapplication ();
  250.       break;
  251.     case WM_SETFOCUS:
  252.       ret = msg_setfocus ((HWND) mp1, SHORT1FROMMP (mp2));
  253.       break;
  254.     case WM_SETSELECTION:
  255.       ret = msg_setselection (SHORT1FROMMP (mp1));
  256.       break;
  257.     case WM_SHOW:
  258.       ret = msg_show (SHORT1FROMMP (mp1));
  259.       break;
  260.     case WM_SIZE:
  261.       ret = msg_size (SHORT1FROMMP (mp1), SHORT2FROMMP (mp1),
  262.               SHORT1FROMMP (mp2), SHORT2FROMMP (mp2));
  263.       break;
  264.     case WM_WINDOWPOSCHANGED:
  265.       ret = msg_windowposchanged ((SWP *) mp1, (unsigned) mp2);
  266.       break;
  267.     case WM_USER+1:
  268.       ret = msg_user1 (mp1, mp2);
  269.       break;
  270.     case WM_USER+2:
  271.       ret = msg_user2 (mp1, mp2);
  272.       break;
  273.     case WM_USER+3:
  274.       ret = msg_user3 (mp1, mp2);
  275.       break;
  276.     case WM_USER+4:
  277.       ret = msg_user4 (mp1, mp2);
  278.       break;
  279.     default:
  280.       LOG ("Undecoded message: 0x%04X", msg);
  281.       ret = default_message ();
  282.       break;
  283.       
  284.       
  285.       // The following messages need work.  I have not yet decoded the
  286.       // arguments for these functions...
  287.     case WM_QUERYFOCUSCHAIN:
  288.       ret = msg_queryfocuschain ();
  289.       break;
  290.     case WM_QUERYDLGCODE:
  291.       ret = msg_querydlgcode ();
  292.       break;
  293.       
  294.     }
  295.   msg = save_msg;
  296.   mp1 = save_mp1;
  297.   mp2 = save_mp2;
  298.   return ret;
  299. }
  300.  
  301. /* Send functions for sending messages to the HWND controlled by the
  302.  * StdWin object.
  303.  */
  304. MRESULT StdWin::send_msg (unsigned amsg, MPARAM amp1, MPARAM amp2)
  305. {
  306.   return WinSendMsg (window, amsg, amp1, amp2);
  307. }
  308.  
  309. MRESULT StdWin::send_close ()
  310. {
  311.   return send_msg (WM_CLOSE, 0, 0);
  312. }
  313.  
  314. MRESULT StdWin::send_user1 (MPARAM mp1, MPARAM mp2)
  315. {
  316.   return send_msg (WM_USER + 1, mp1, mp2);
  317. }
  318.  
  319. MRESULT StdWin::send_user2 (MPARAM mp1, MPARAM mp2)
  320. {
  321.   return send_msg (WM_USER + 2, mp1, mp2);
  322. }
  323.  
  324. MRESULT StdWin::send_user3 (MPARAM mp1, MPARAM mp2)
  325. {
  326.   return send_msg (WM_USER + 3, mp1, mp2);
  327. }
  328.  
  329. MRESULT StdWin::send_user4 (MPARAM mp1, MPARAM mp2)
  330. {
  331.   return send_msg (WM_USER + 4, mp1, mp2);
  332. }
  333.    
  334.  
  335. /* A handler for messages that we want to default to the behavior of
  336.  * the default PM message handler.
  337.  * Note that we have squirreled away the actual mp1 and mp2 arguments in the
  338.  * function StdWin::message.  We do this for two reasons:  First, this
  339.  * way we don't have to re-encode the arguments back into the mp1 and mp2
  340.  * types.  Second, if any of the fields of mp1 and mp2 that are
  341.  * RESERVED in the PM documentation are actually used by PM, the squirelled
  342.  * values of mp1 and mp2 will preserve the contents of the reserved fields.
  343.  */
  344. MRESULT StdWin::default_message ()
  345. {
  346.   return WinDefWindowProc (window, msg, mp1, mp2);
  347. }
  348.  
  349. /* For every message type that we have created virtual member functions for,
  350.  * we write a default method that simply causes the default window procedure
  351.  * to be invoked.
  352.  */
  353. #define DEFAULT(msg)                \
  354. MRESULT StdWin::msg                \
  355. {                        \
  356.   LOG(#msg " sent to base class");        \
  357.   return default_message ();            \
  358. }
  359. DEFAULT (msg_create ());
  360. DEFAULT (msg_paint ());
  361. DEFAULT (msg_activate (int, HWND));
  362. DEFAULT (msg_adjustwindowpos (SWP *));
  363. DEFAULT (msg_char (unsigned short, unsigned char, unsigned char,
  364.            unsigned short, unsigned short));
  365. DEFAULT (msg_close ());
  366. DEFAULT (msg_controlpointer (unsigned short, HPOINTER));
  367. DEFAULT (msg_destroy ());
  368. DEFAULT (msg_erasebackground (HPS, RECTL *));
  369. DEFAULT (msg_focuschange (HWND, unsigned short, unsigned short));
  370. DEFAULT (msg_formatframe (SWP *, RECTL *));
  371. DEFAULT (msg_mousemove (short, short, unsigned short, unsigned short));
  372. DEFAULT (msg_realizepalette ());
  373. DEFAULT (msg_saveapplication ());
  374. DEFAULT (msg_setfocus (HWND, unsigned short));
  375. DEFAULT (msg_setselection (unsigned short));
  376. DEFAULT (msg_show (unsigned short));
  377. DEFAULT (msg_size (short, short, short, short));
  378. DEFAULT (msg_windowposchanged (SWP *, unsigned));
  379. DEFAULT (msg_user1 (MPARAM, MPARAM));
  380. DEFAULT (msg_user2 (MPARAM, MPARAM));
  381. DEFAULT (msg_user3 (MPARAM, MPARAM));
  382. DEFAULT (msg_user4 (MPARAM, MPARAM));
  383.  
  384. // Functions that need work
  385. DEFAULT (msg_querydlgcode ());
  386. DEFAULT (msg_queryfocuschain ());
  387.  
  388.  
  389. /* Standard message dispatch loop */
  390. void StdWin::StdMessageLoop ()
  391. {
  392.   QMSG qmsg;
  393.   while (WinGetMsg(hab, &qmsg, 0, 0, 0))
  394.     WinDispatchMsg(hab, &qmsg);
  395. }
  396.