home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1991 / 07 / dflat.791 < prev    next >
Text File  |  1991-06-11  |  25KB  |  722 lines

  1. _C PROGRAMMING COLUMN_
  2. by Al Stevens
  3.  
  4.  
  5. [LISTING ONE]
  6.  
  7. /* ----------- message.h ------------ */
  8.  
  9. #ifndef MESSAGES_H
  10. #define MESSGAES_H
  11.  
  12. #define MAXMESSAGES 50
  13. #define DELAYTICKS 1
  14. #define FIRSTDELAY 7
  15. #define DOUBLETICKS 5
  16.  
  17. typedef enum messages {
  18.     /* ------------- process communication messages --------- */
  19.     START,                  /* start message processing       */
  20.     STOP,                   /* stop message processing        */
  21.     COMMAND,                /* send a command to a window     */
  22.     /* ------------- window management messages ------------- */
  23.     CREATE_WINDOW,          /* create a window                */
  24.     SHOW_WINDOW,            /* show a window                  */
  25.     HIDE_WINDOW,            /* hide a window                  */
  26.     CLOSE_WINDOW,           /* delete a window                */
  27.     SETFOCUS,               /* set and clear the focus        */
  28.     PAINT,                  /* paint the window's data space  */
  29.     BORDER,                 /* paint the window's border      */
  30.     TITLE,                  /* display the window's title     */
  31.     MOVE,                   /* move the window                */
  32.     SIZE,                   /* change the window's size       */
  33.     MAXIMIZE,               /* maximize the window            */
  34.     MINIMIZE,               /* minimize the window            */
  35.     RESTORE,                /* restore the window             */
  36.     INSIDE_WINDOW,          /* test x/y inside a window       */
  37.     /* ------------- clock messages ------------------------- */
  38.     CLOCKTICK,              /* the clock ticked               */
  39.     CAPTURE_CLOCK,          /* capture clock into a window    */
  40.     RELEASE_CLOCK,          /* release clock to the system    */
  41.     /* ------------- keyboard and screen messages ----------- */
  42.     KEYBOARD,               /* key was pressed                */
  43.     CAPTURE_KEYBOARD,       /* capture keyboard into a window */
  44.     RELEASE_KEYBOARD,       /* release keyboard to system     */
  45.     KEYBOARD_CURSOR,        /* position the keyboard cursor   */
  46.     CURRENT_KEYBOARD_CURSOR,/* read the cursor position       */
  47.     HIDE_CURSOR,            /* hide the keyboard cursor       */
  48.     SHOW_CURSOR,            /* display the keyboard cursor    */
  49.     SAVE_CURSOR,            /* save the cursor's configuration*/
  50.     RESTORE_CURSOR,         /* restore the saved cursor       */
  51.     SHIFT_CHANGED,          /* the shift status changed       */
  52.     /* ------------- mouse messages ------------------------- */
  53.     MOUSE_INSTALLED,        /* test for mouse installed       */
  54.     RIGHT_BUTTON,           /* right button pressed           */
  55.     LEFT_BUTTON,            /* left button pressed            */
  56.     DOUBLE_CLICK,           /* right button double-clicked    */
  57.     MOUSE_MOVED,            /* mouse changed position         */
  58.     BUTTON_RELEASED,        /* mouse button released          */
  59.     CURRENT_MOUSE_CURSOR,   /* get mouse position             */
  60.     MOUSE_CURSOR,           /* set mouse position             */
  61.     SHOW_MOUSE,             /* make mouse cursor visible      */
  62.     HIDE_MOUSE,             /* hide mouse cursor              */
  63.     WAITMOUSE,              /* wait until button released     */
  64.     TESTMOUSE,              /* test any mouse button pressed  */
  65.     CAPTURE_MOUSE,          /* capture mouse into a window    */
  66.     RELEASE_MOUSE,          /* release the mouse to system    */
  67.     /* ------------- text box messages ---------------------- */
  68.     ADDTEXT,                /* add text to the text box       */
  69.     CLEARTEXT,              /* clear the edit box             */
  70.     SETTEXT,                /* set address of text buffer     */
  71.     SCROLL,                 /* vertical scroll of text box    */
  72.     HORIZSCROLL,            /* horizontal scroll of text box  */
  73.     /* ------------- edit box messages ---------------------- */
  74.     EB_GETTEXT,             /* get text from an edit box      */
  75.     EB_PUTTEXT,             /* put text into an edit box      */
  76.     /* ------------- menubar messages ----------------------- */
  77.     BUILDMENU,              /* build the menu display         */
  78.     SELECTION,              /* menubar selection              */
  79.     /* ------------- popdown messages ----------------------- */
  80.     BUILD_SELECTIONS,       /* build the menu display         */
  81.     CLOSE_POPDOWN,          /* tell parent popdown is closing */
  82.     /* ------------- list box messages ---------------------- */
  83.     LB_SELECTION,           /* sent to parent on selection    */
  84.     LB_CHOOSE,              /* sent when user chooses         */
  85.     LB_CURRENTSELECTION,    /* return the current selection   */
  86.     LB_GETTEXT,             /* return the text of selection   */
  87.     LB_SETSELECTION,        /* sets the listbox selection     */
  88.     /* ------------- dialog box messages -------------------- */
  89.     INITIATE_DIALOG,        /* begin a dialog                 */
  90.     ENTERFOCUS,             /* tell DB control got focus      */
  91.     LEAVEFOCUS,             /* tell DB control lost focus     */
  92.     ENDDIALOG               /* end a dialog                   */
  93. } MESSAGE;
  94.  
  95. /* --------- message prototypes ----------- */
  96. void init_messages(void);
  97. void PostMessage(WINDOW, MESSAGE, PARAM, PARAM);
  98. int SendMessage(WINDOW, MESSAGE, PARAM, PARAM);
  99. int dispatch_message(void);
  100. int TestCriticalError(void);
  101.  
  102. #endif
  103.  
  104.  
  105.  
  106.  
  107. [LISTING TWO]
  108.  
  109. /* --------- message.c ---------- */
  110.  
  111. #include <stdio.h>
  112. #include <dos.h>
  113. #include <conio.h>
  114. #include <string.h>
  115. #include <time.h>
  116. #include "dflat.h"
  117.  
  118. static int px = -1, py = -1;
  119. static int pmx = -1, pmy = -1;
  120. static int mx, my;
  121.  
  122. static int CriticalError;
  123.  
  124. /* ---------- event queue ---------- */
  125. static struct events    {
  126.     MESSAGE event;
  127.     int mx;
  128.     int my;
  129. } EventQueue[MAXMESSAGES];
  130.  
  131. /* ---------- message queue --------- */
  132. static struct msgs {
  133.     WINDOW wnd;
  134.     MESSAGE msg;
  135.     PARAM p1;
  136.     PARAM p2;
  137. } MsgQueue[MAXMESSAGES];
  138.  
  139. static int EventQueueOnCtr;
  140. static int EventQueueOffCtr;
  141. static int EventQueueCtr;
  142.  
  143. static int MsgQueueOnCtr;
  144. static int MsgQueueOffCtr;
  145. static int MsgQueueCtr;
  146.  
  147. static int lagdelay = FIRSTDELAY;
  148.  
  149. static void (interrupt far *oldtimer)(void) = NULL;
  150. WINDOW CaptureMouse = NULLWND;
  151. WINDOW CaptureKeyboard = NULLWND;
  152. static int NoChildCaptureMouse = FALSE;
  153. static int NoChildCaptureKeyboard = FALSE;
  154.  
  155. static int doubletimer = -1;
  156. static int delaytimer  = -1;
  157. static int clocktimer  = -1;
  158.  
  159. WINDOW Cwnd = NULLWND;
  160.  
  161. /* ------- timer interrupt service routine ------- */
  162. static void interrupt far newtimer(void)
  163. {
  164.     if (timer_running(doubletimer))
  165.         countdown(doubletimer);
  166.     if (timer_running(delaytimer))
  167.         countdown(delaytimer);
  168.     if (timer_running(clocktimer))
  169.         countdown(clocktimer);
  170.     oldtimer();
  171. }
  172.  
  173. static char ermsg[] = "Error accessing drive x";
  174.  
  175. /* -------- test for critical errors --------- */
  176. int TestCriticalError(void)
  177. {
  178.     int rtn = 0;
  179.     if (CriticalError)    {
  180.         rtn = 1;
  181.         CriticalError = FALSE;
  182.         if (TestErrorMessage(ermsg) == FALSE)
  183.             rtn = 2;
  184.     }
  185.     return rtn;
  186. }
  187.  
  188. /* ------ critical error interrupt service routine ------ */
  189. static void interrupt far newcrit(IREGS ir)
  190. {
  191.     if (!(ir.ax & 0x8000))     {
  192.         ermsg[sizeof(ermsg) - 2] = (ir.ax & 0xff) + 'A';
  193.         CriticalError = TRUE;
  194.     }
  195.     ir.ax = 0;
  196. }
  197.  
  198. /* ------------ initialize the message system --------- */
  199. void init_messages(void)
  200. {
  201.     resetmouse();
  202.     show_mousecursor();
  203.     px = py = -1;
  204.     pmx = pmy = -1;
  205.     mx = my = 0;
  206.     CaptureMouse = CaptureKeyboard = NULLWND;
  207.     NoChildCaptureMouse = FALSE;
  208.     NoChildCaptureKeyboard = FALSE;
  209.     MsgQueueOnCtr = MsgQueueOffCtr = MsgQueueCtr = 0;
  210.     EventQueueOnCtr = EventQueueOffCtr = EventQueueCtr = 0;
  211.     if (oldtimer == NULL)    {
  212.         oldtimer = getvect(TIMER);
  213.         setvect(TIMER, newtimer);
  214.     }
  215.     setvect(CRIT, newcrit);    
  216.     PostMessage(NULLWND,START,0,0);
  217.     lagdelay = FIRSTDELAY;
  218. }
  219.  
  220. /* ----- post an event and parameters to event queue ---- */
  221. static void PostEvent(MESSAGE event, int p1, int p2)
  222. {
  223.     if (EventQueueCtr != MAXMESSAGES)    {
  224.         EventQueue[EventQueueOnCtr].event = event;
  225.         EventQueue[EventQueueOnCtr].mx = p1;
  226.         EventQueue[EventQueueOnCtr].my = p2;
  227.         if (++EventQueueOnCtr == MAXMESSAGES)
  228.             EventQueueOnCtr = 0;
  229.         EventQueueCtr++;
  230.     }
  231. }
  232.  
  233. /* ------ collect mouse, clock, and keyboard events ----- */
  234. static void near collect_events(void)
  235. {
  236.     struct tm *now;
  237.     static int flipflop = FALSE;
  238.     static char timestr[8];
  239.     int hr, sk;
  240.     static int ShiftKeys = 0;
  241.  
  242.     /* -------- test for a clock event (one/second) ------- */
  243.     if (timed_out(clocktimer))    {
  244.         /* ----- get the current time ----- */
  245.         time_t t = time(NULL);
  246.         now = localtime(&t);
  247.         hr = now->tm_hour > 12 ?
  248.              now->tm_hour - 12 :
  249.              now->tm_hour;
  250.         if (hr == 0)
  251.             hr = 12;
  252.         sprintf(timestr, "%2.2d:%02d", hr, now->tm_min);
  253.         strcpy(timestr+5, now->tm_hour > 11 ? "pm" : "am");
  254.         /* ------- blink the : at one-second intervals ----- */
  255.         if (flipflop)
  256.             *(timestr+2) = ' ';
  257.         flipflop ^= TRUE;
  258.         /* -------- reset the timer -------- */
  259.         set_timer(clocktimer, 1);
  260.         /* -------- post the clock event -------- */
  261.         PostEvent(CLOCKTICK, FP_SEG(timestr), FP_OFF(timestr));
  262.     }
  263.  
  264.     /* --------- keyboard events ---------- */
  265.     if ((sk = getshift()) != ShiftKeys)    {
  266.         ShiftKeys = sk;
  267.         /* ---- the shift status changed ---- */
  268.         PostEvent(SHIFT_CHANGED, sk, 0);
  269.     }
  270.  
  271.     /* ---- build keyboard events for key combinations that
  272.         BIOS doesn't report --------- */
  273.     if (sk & ALTKEY)
  274.         if (inp(0x60) == 14)    {
  275.             while (!(inp(0x60) & 0x80))
  276.                 ;
  277.             PostEvent(KEYBOARD, ALT_BS, sk);
  278.         }
  279.     if (sk & CTRLKEY)
  280.         if (inp(0x60) == 82)    {
  281.             while (!(inp(0x60) & 0x80))
  282.                 ;
  283.             PostEvent(KEYBOARD, CTRL_INS, sk);
  284.         }
  285.  
  286.     /* ----------- test for keystroke ------- */
  287.     if (keyhit())    {
  288.         static int cvt[] = {SHIFT_INS,END,DN,PGDN,BS,'5',
  289.                         FWD,HOME,UP,PGUP};
  290.         int c = getkey();
  291.  
  292.         /* -------- convert numeric pad keys ------- */
  293.         if (sk & (LEFTSHIFT | RIGHTSHIFT))    {
  294.             if (c >= '0' && c <= '9')
  295.                 c = cvt[c-'0'];
  296.             else if (c == '.' || c == DEL)
  297.                 c = SHIFT_DEL;
  298.             else if (c == INS)
  299.                 c = SHIFT_INS;
  300.         }
  301.         /* -------- clear the BIOS readahead buffer -------- */
  302.         *(int far *)(MK_FP(0x40,0x1a)) =
  303.             *(int far *)(MK_FP(0x40,0x1c));
  304.         /* ---- if help key call generic help function ---- */
  305.         if (c == F1)
  306.             HelpFunction();
  307.         else
  308.             /* ------ post the keyboard event ------ */
  309.             PostEvent(KEYBOARD, c, sk);
  310.     }
  311.  
  312.     /* ------------ test for mouse events --------- */
  313.     get_mouseposition(&mx, &my);
  314.     if (mx != px || my != py)  {
  315.         px = mx;
  316.         py = my;
  317.         PostEvent(MOUSE_MOVED, mx, my);
  318.     }
  319.     if (rightbutton())
  320.         PostEvent(RIGHT_BUTTON, mx, my);
  321.     if (leftbutton())    {
  322.         if (mx == pmx && my == pmy)    {
  323.             /* ---- same position as last left button ---- */
  324.             if (timer_running(doubletimer))    {
  325.                 /* -- second click before double timeout -- */
  326.                 disable_timer(doubletimer);
  327.                 PostEvent(DOUBLE_CLICK, mx, my);
  328.             }
  329.             else if (!timer_running(delaytimer))    {
  330.                 /* ---- button held down a while ---- */
  331.                 delaytimer = lagdelay;
  332.                 lagdelay = DELAYTICKS;
  333.                 /* ---- post a typematic-like button ---- */
  334.                 PostEvent(LEFT_BUTTON, mx, my);
  335.             }
  336.         }
  337.         else    {
  338.             /* --------- new button press ------- */
  339.             disable_timer(doubletimer);
  340.             delaytimer = FIRSTDELAY;
  341.             lagdelay = DELAYTICKS;
  342.             PostEvent(LEFT_BUTTON, mx, my);
  343.             pmx = mx;
  344.             pmy = my;
  345.         }
  346.     }
  347.     else
  348.         lagdelay = FIRSTDELAY;
  349.     if (button_releases())    {
  350.         /* ------- the button was released -------- */
  351.         doubletimer = DOUBLETICKS;
  352.         PostEvent(BUTTON_RELEASED, mx, my);
  353.         disable_timer(delaytimer);
  354.     }
  355. }
  356.  
  357. /* ----- post a message and parameters to msg queue ---- */
  358. void PostMessage(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  359. {
  360.     if (MsgQueueCtr != MAXMESSAGES)    {
  361.         MsgQueue[MsgQueueOnCtr].wnd = wnd;
  362.         MsgQueue[MsgQueueOnCtr].msg = msg;
  363.         MsgQueue[MsgQueueOnCtr].p1 = p1;
  364.         MsgQueue[MsgQueueOnCtr].p2 = p2;
  365.         if (++MsgQueueOnCtr == MAXMESSAGES)
  366.             MsgQueueOnCtr = 0;
  367.         MsgQueueCtr++;
  368.     }
  369. }
  370.  
  371. /* --------- send a message to a window ----------- */
  372. int SendMessage(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  373. {
  374.     int rtn = TRUE, x, y;
  375.     if (wnd != NULLWND)
  376.         switch (msg)    {
  377.             case PAINT:
  378.             case BORDER:
  379.             case RIGHT_BUTTON:
  380.             case LEFT_BUTTON:
  381.             case DOUBLE_CLICK:
  382.             case BUTTON_RELEASED:
  383.             case KEYBOARD:
  384.             case SHIFT_CHANGED:
  385.                 /* ------- don't send these messages unless the
  386.                     window is visible -------- */
  387.                 if (!isVisible(wnd))
  388.                     break;
  389.             default:
  390.                 rtn = wnd->wndproc(wnd, msg, p1, p2);
  391.                 break;
  392.         }
  393.     /* ----- window processor returned or the message was sent
  394.         to no window at all (NULLWND) ----- */
  395.     if (rtn != FALSE)    {
  396.         /* --------- process messages that a window sends to the
  397.             system itself ---------- */
  398.         switch (msg)    {
  399.             case STOP:
  400.                 hide_mousecursor();
  401.                 if (oldtimer != NULL)    {
  402.                     setvect(TIMER, oldtimer);
  403.                     oldtimer = NULL;
  404.                 }
  405.                 break;
  406.             /* ------- clock messages --------- */
  407.             case CAPTURE_CLOCK:
  408.                 Cwnd = wnd;
  409.                 set_timer(clocktimer, 0);
  410.                 break;
  411.             case RELEASE_CLOCK:
  412.                 Cwnd = NULLWND;
  413.                 disable_timer(clocktimer);
  414.                 break;
  415.             /* -------- keyboard messages ------- */
  416.             case KEYBOARD_CURSOR:
  417.                 if (wnd == NULLWND)
  418.                     cursor((int)p1, (int)p2);
  419.                 else
  420.                  cursor(GetClientLeft(wnd)+(int)p1, GetClientTop(wnd)+(int)p2);
  421.                 break;
  422.             case CAPTURE_KEYBOARD:
  423.                 if (p2)
  424.                     ((WINDOW)p2)->PrevKeyboard=CaptureKeyboard;
  425.                 else
  426.                     wnd->PrevKeyboard = CaptureKeyboard;
  427.                 CaptureKeyboard = wnd;
  428.                 NoChildCaptureKeyboard = (int)p1;
  429.                 break;
  430.             case RELEASE_KEYBOARD:
  431.                 CaptureKeyboard = wnd->PrevKeyboard;
  432.                 NoChildCaptureKeyboard = FALSE;
  433.                 break;
  434.             case CURRENT_KEYBOARD_CURSOR:
  435.                 curr_cursor(&x, &y);
  436.                 *(int*)p1 = x;
  437.                 *(int*)p2 = y;
  438.                 break;
  439.             case SAVE_CURSOR:
  440.                 savecursor();
  441.                 break;
  442.             case RESTORE_CURSOR:
  443.                 restorecursor();
  444.                 break;
  445.             case HIDE_CURSOR:
  446.                 normalcursor();
  447.                 hidecursor();
  448.                 break;
  449.             case SHOW_CURSOR:
  450.                 if (p1)
  451.                     set_cursor_type(0x0106);
  452.                 else
  453.                     set_cursor_type(0x0607);
  454.                 unhidecursor();
  455.                 break;
  456.             /* -------- mouse messages -------- */
  457.             case MOUSE_INSTALLED:
  458.                 rtn = mouse_installed();
  459.                 break;
  460.             case SHOW_MOUSE:
  461.                 show_mousecursor();
  462.                 break;
  463.             case HIDE_MOUSE:
  464.                 hide_mousecursor();
  465.                 break;
  466.             case MOUSE_CURSOR:
  467.                 set_mouseposition((int)p1, (int)p2);
  468.                 break;
  469.             case CURRENT_MOUSE_CURSOR:
  470.                 get_mouseposition((int*)p1,(int*)p2);
  471.                 break;
  472.             case WAITMOUSE:
  473.                 waitformouse();
  474.                 break;
  475.             case TESTMOUSE:
  476.                 rtn = mousebuttons();
  477.                 break;
  478.             case CAPTURE_MOUSE:
  479.                 if (p2)
  480.                     ((WINDOW)p2)->PrevMouse = CaptureMouse;
  481.                 else
  482.                     wnd->PrevMouse = CaptureMouse;
  483.                 CaptureMouse = wnd;
  484.                 NoChildCaptureMouse = (int)p1;
  485.                 break;
  486.             case RELEASE_MOUSE:
  487.                 CaptureMouse = wnd->PrevMouse;
  488.                 NoChildCaptureMouse = FALSE;
  489.                 break;
  490.             default:
  491.                 break;
  492.         }
  493.     }
  494.     return rtn;
  495. }
  496.  
  497. /* ---- dispatch messages to the message proc function ---- */
  498. int dispatch_message(void)
  499. {
  500.     WINDOW Mwnd, Kwnd;
  501.     /* -------- collect mouse and keyboard events ------- */
  502.     collect_events();
  503.     /* --------- dequeue and process events -------- */
  504.     while (EventQueueCtr > 0)  {
  505.         struct events ev = EventQueue[EventQueueOffCtr];
  506.  
  507.         if (++EventQueueOffCtr == MAXMESSAGES)
  508.             EventQueueOffCtr = 0;
  509.         --EventQueueCtr;
  510.  
  511.         /* ------ get the window in which a
  512.                         mouse event occurred ------ */
  513.         Mwnd = inWindow(ev.mx, ev.my);
  514.  
  515.         /* ---- process mouse captures ----- */
  516.         if (CaptureMouse != NULLWND)
  517.             if (Mwnd == NULLWND ||
  518.                     NoChildCaptureMouse ||
  519.                         GetParent(Mwnd) != CaptureMouse)
  520.                 Mwnd = CaptureMouse;
  521.  
  522.         /* ------ get the window in which a
  523.                         keyboard event occurred ------ */
  524.         Kwnd = inFocus;
  525.  
  526.         /* ---- process keyboard captures ----- */
  527.         if (CaptureKeyboard != NULLWND)
  528.             if (Kwnd == NULLWND ||
  529.                     NoChildCaptureKeyboard ||
  530.                         GetParent(Kwnd) != CaptureKeyboard)
  531.                 Kwnd = CaptureKeyboard;
  532.  
  533.         /* -------- send mouse and keyboard messages to the
  534.             window that should get them -------- */
  535.         switch (ev.event)    {
  536.             case SHIFT_CHANGED:
  537.             case KEYBOARD:
  538.                 SendMessage(Kwnd, ev.event, ev.mx, ev.my);
  539.                 break;
  540.             case LEFT_BUTTON:
  541.                 if (!CaptureMouse ||
  542.                         (!NoChildCaptureMouse &&
  543.                             GetParent(Mwnd) == CaptureMouse))
  544.                     if (Mwnd != inFocus)
  545.                         SendMessage(Mwnd, SETFOCUS, TRUE, 0);
  546.             case BUTTON_RELEASED:
  547.             case DOUBLE_CLICK:
  548.             case RIGHT_BUTTON:
  549.             case MOUSE_MOVED:
  550.                 SendMessage(Mwnd, ev.event, ev.mx, ev.my);
  551.                 break;
  552.             case CLOCKTICK:
  553.                 SendMessage(Cwnd, ev.event,
  554.                     (PARAM) MK_FP(ev.mx, ev.my), 0);
  555.             default:
  556.                 break;
  557.         }
  558.     }
  559.     /* ------ dequeue and process messages ----- */
  560.     while (MsgQueueCtr > 0)  {
  561.         struct msgs mq = MsgQueue[MsgQueueOffCtr];
  562.         if (++MsgQueueOffCtr == MAXMESSAGES)
  563.             MsgQueueOffCtr = 0;
  564.         --MsgQueueCtr;
  565.         SendMessage(mq.wnd, mq.msg, mq.p1, mq.p2);
  566.         if (mq.msg == STOP || mq.msg == ENDDIALOG)
  567.                return FALSE;
  568.     }
  569.     return TRUE;
  570. }
  571.  
  572.  
  573.  
  574.  
  575.  
  576. [LISTING THREE]
  577.  
  578. /* ------- display a window's border ----- */
  579. void RepaintBorder(WINDOW wnd, RECT *rcc)
  580. {
  581.     int y;
  582.     int lin, side, ne, nw, se, sw;
  583.     RECT rc, clrc;
  584.  
  585.     if (!TestAttribute(wnd, HASBORDER))
  586.         return;
  587.     if (rcc == NULL)    {
  588.         rc = SetRect(0, 0, WindowWidth(wnd)-1,
  589.                 WindowHeight(wnd)-1);
  590.         if (TestAttribute(wnd, SHADOW))    {
  591.             rc.rt++;
  592.             rc.bt++;
  593.         }
  594.     }
  595.     else
  596.         rc = *rcc;
  597.     clrc = rc;
  598.     /* -------- adjust the client rectangle ------- */
  599.     if (RectLeft(rc) == 0)
  600.         --clrc.rt;
  601.     else
  602.         --clrc.lf;
  603.     if (RectTop(rc) == 0)
  604.         --clrc.bt;
  605.     else
  606.         --clrc.tp;
  607.     RectRight(clrc) = min(RectRight(clrc), WindowWidth(wnd)-3);
  608.     RectBottom(clrc) = min(RectBottom(clrc), WindowHeight(wnd)-3);
  609.     if (wnd == inFocus)    {
  610.         lin  = FOCUS_LINE;
  611.         side = FOCUS_SIDE;
  612.         ne   = FOCUS_NE;
  613.         nw   = FOCUS_NW;
  614.         se   = FOCUS_SE;
  615.         sw   = FOCUS_SW;
  616.     }
  617.     else    {
  618.         lin  = LINE;
  619.         side = SIDE;
  620.         ne   = NE;
  621.         nw   = NW;
  622.         se   = SE;
  623.         sw   = SW;
  624.     }
  625.     line[WindowWidth(wnd)] = '\0';
  626.     /* ---------- window title ------------ */
  627.     if (RectTop(rc) == 0)
  628.         if (RectLeft(rc) < WindowWidth(wnd))
  629.             if (TestAttribute(wnd, TITLEBAR))
  630.                 DisplayTitle(wnd, clrc);
  631.     foreground = FrameForeground(wnd);
  632.     background = FrameBackground(wnd);
  633.     /* -------- top frame corners --------- */
  634.     if (RectTop(rc) == 0)    {
  635.         if (RectLeft(rc) == 0)
  636.             PutWindowChar(wnd, -1, -1, nw);
  637.         if (RectLeft(rc) < RectRight(rc))    {
  638.             if (RectRight(rc) >= WindowWidth(wnd)-1)
  639.                 PutWindowChar(wnd, WindowWidth(wnd)-2, -1, ne);
  640.  
  641.             if (TestAttribute(wnd, TITLEBAR) == 0)    {
  642.                 /* ----------- top line ------------- */
  643.                 memset(line,lin,WindowWidth(wnd)-1);
  644.                 line[RectRight(clrc)+1] = '\0';
  645.                 if (strlen(line+RectLeft(clrc)) > 1 || 
  646.                                            TestAttribute(wnd, SHADOW) == 0)
  647.                     writeline(wnd, line+RectLeft(clrc),
  648.                             RectLeft(clrc), -1, FALSE);
  649.             }
  650.         }
  651.     }
  652.     /* ----------- window body ------------ */
  653.     for (y = 0; y < ClientHeight(wnd); y++)    {
  654.         int ch;
  655.         if (y >= RectTop(clrc) && y <= RectBottom(clrc))    {
  656.             if (RectLeft(rc) == 0)
  657.                 PutWindowChar(wnd, -1, y, side);
  658.             if (RectLeft(rc) < RectRight(rc))    {
  659.                 if (RectRight(rc) >= ClientWidth(wnd))    {
  660.                     if (TestAttribute(wnd, VSCROLLBAR))
  661.                         ch = (    y == 0 ? UPSCROLLBOX      :
  662.                                   y == WindowHeight(wnd)-3  ?
  663.                                        DOWNSCROLLBOX        :
  664.                                   y == wnd->VScrollBox      ?
  665.                                        SCROLLBOXCHAR        :
  666.                                        SCROLLBARCHAR );
  667.                     else
  668.                         ch = side;
  669.                     PutWindowChar(wnd,WindowWidth(wnd)-2,y,ch);
  670.                 }
  671.             }
  672.             if (RectRight(rc) == WindowWidth(wnd))
  673.                 shadow_char(wnd, y);
  674.         }
  675.     }
  676.     if (RectTop(rc) < RectBottom(rc) &&
  677.             RectBottom(rc) >= WindowHeight(wnd)-1)    {
  678.         /* -------- bottom frame corners ---------- */
  679.         if (RectLeft(rc) == 0)
  680.             PutWindowChar(wnd, -1, WindowHeight(wnd)-2, sw);
  681.         if (RectRight(rc) >= WindowWidth(wnd)-1)
  682.             PutWindowChar(wnd, WindowWidth(wnd)-2,
  683.                 WindowHeight(wnd)-2, se);
  684.         /* ----------- bottom line ------------- */
  685.         memset(line,lin,WindowWidth(wnd)-1);
  686.         if (TestAttribute(wnd, HSCROLLBAR))    {
  687.             line[0] = LEFTSCROLLBOX;
  688.             line[WindowWidth(wnd)-3] = RIGHTSCROLLBOX;
  689.             memset(line+1, SCROLLBARCHAR, WindowWidth(wnd)-4);
  690.             line[wnd->HScrollBox] = SCROLLBOXCHAR;
  691.         }
  692.         line[RectRight(clrc)+1] = '\0';
  693.         if (strlen(line+RectLeft(clrc)) > 1 || TestAttribute(wnd, SHADOW) == 0)
  694.             writeline(wnd,
  695.                 line+RectLeft(clrc),
  696.                 RectLeft(clrc),
  697.                 WindowHeight(wnd)-2,
  698.                 FALSE);
  699.         if (RectRight(rc) == WindowWidth(wnd))
  700.             shadow_char(wnd, WindowHeight(wnd)-2);
  701.     }
  702.     if (RectBottom(rc) == WindowHeight(wnd))
  703.         /* ---------- bottom shadow ------------- */
  704.         shadowline(wnd, clrc);
  705. }
  706.  
  707.  
  708.  
  709.  
  710.  
  711. Example 1: 
  712.  
  713. #include <stdio.h>
  714. main()
  715. {
  716.     int x=1,y=1;
  717.     x = (y++,y+3);
  718.     printf("x=%d,y=%d\n",x,y);
  719.     printf("++y=%d,x=%d\n",(--x,++y),x);
  720. }
  721.  
  722.