Back to index

tetex-bin  3.0
lib_mouse.c
Go to the documentation of this file.
00001 /****************************************************************************
00002  * Copyright (c) 1998-2003,2004 Free Software Foundation, Inc.              *
00003  *                                                                          *
00004  * Permission is hereby granted, free of charge, to any person obtaining a  *
00005  * copy of this software and associated documentation files (the            *
00006  * "Software"), to deal in the Software without restriction, including      *
00007  * without limitation the rights to use, copy, modify, merge, publish,      *
00008  * distribute, distribute with modifications, sublicense, and/or sell       *
00009  * copies of the Software, and to permit persons to whom the Software is    *
00010  * furnished to do so, subject to the following conditions:                 *
00011  *                                                                          *
00012  * The above copyright notice and this permission notice shall be included  *
00013  * in all copies or substantial portions of the Software.                   *
00014  *                                                                          *
00015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
00016  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
00017  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
00018  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
00019  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
00020  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
00021  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
00022  *                                                                          *
00023  * Except as contained in this notice, the name(s) of the above copyright   *
00024  * holders shall not be used in advertising or otherwise to promote the     *
00025  * sale, use or other dealings in this Software without prior written       *
00026  * authorization.                                                           *
00027  ****************************************************************************/
00028 
00029 /****************************************************************************
00030  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
00031  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
00032  *     and: Thomas E. Dickey                        1996-on                 *
00033  ****************************************************************************/
00034 
00035 /*
00036  * This module is intended to encapsulate ncurses's interface to pointing
00037  * devices.
00038  *
00039  * The first method used is xterm's internal mouse-tracking facility.
00040  * The second is Alessandro Rubini's GPM server.
00041  *
00042  * Notes for implementors of new mouse-interface methods:
00043  *
00044  * The code is logically split into a lower level that accepts event reports
00045  * in a device-dependent format and an upper level that parses mouse gestures
00046  * and filters events.  The mediating data structure is a circular queue of
00047  * MEVENT structures.
00048  *
00049  * Functionally, the lower level's job is to pick up primitive events and
00050  * put them on the circular queue.  This can happen in one of two ways:
00051  * either (a) _nc_mouse_event() detects a series of incoming mouse reports
00052  * and queues them, or (b) code in lib_getch.c detects the kmous prefix in
00053  * the keyboard input stream and calls _nc_mouse_inline to queue up a series
00054  * of adjacent mouse reports.
00055  *
00056  * In either case, _nc_mouse_parse() should be called after the series is
00057  * accepted to parse the digested mouse reports (low-level MEVENTs) into
00058  * a gesture (a high-level or composite MEVENT).
00059  *
00060  * Don't be too shy about adding new event types or modifiers, if you can find
00061  * room for them in the 32-bit mask.  The API is written so that users get
00062  * feedback on which theoretical event types they won't see when they call
00063  * mousemask. There's one bit per button (the RESERVED_EVENT bit) not being
00064  * used yet, and a couple of bits open at the high end.
00065  */
00066 
00067 #ifdef __EMX__
00068 #  include <io.h>
00069 #  define  INCL_DOS
00070 #  define  INCL_VIO
00071 #  define  INCL_KBD
00072 #  define  INCL_MOU
00073 #  define  INCL_DOSPROCESS
00074 #  include <os2.h>          /* Need to include before the others */
00075 #endif
00076 
00077 #include <curses.priv.h>
00078 
00079 MODULE_ID("$Id: lib_mouse.c,v 1.69 2004/10/09 17:50:31 tom Exp $")
00080 
00081 #include <term.h>
00082 #include <tic.h>
00083 
00084 #if USE_GPM_SUPPORT
00085 #ifndef LINT                /* don't need this for llib-lncurses */
00086 #undef buttons                     /* term.h defines this, and gpm uses it! */
00087 #include <gpm.h>
00088 #include <linux/keyboard.h> /* defines KG_* macros */
00089 /* use dynamic loader to avoid linkage dependency */
00090 #include <dlfcn.h>
00091 #ifdef RTLD_NOW
00092 #define my_RTLD RTLD_NOW
00093 #else
00094 #ifdef RTLD_LAZY
00095 #define my_RTLD RTLD_LAZY
00096 #else
00097 make an error
00098 #endif
00099 #endif
00100 #endif
00101 #endif                      /* USE_GPM_SUPPORT */
00102 
00103 #if USE_SYSMOUSE
00104 #undef buttons                     /* symbol conflict in consio.h */
00105 #undef mouse_info           /* symbol conflict in consio.h */
00106 #include <osreldate.h>
00107 #if (__FreeBSD_version >= 400017)
00108 #include <sys/consio.h>
00109 #include <sys/fbio.h>
00110 #else
00111 #include <machine/console.h>
00112 #endif
00113 #endif                      /* use_SYSMOUSE */
00114 
00115 #define MY_TRACE TRACE_ICALLS|TRACE_IEVENT
00116 
00117 #define       MASK_RELEASE(x)             ((001 << (6 * ((x) - 1))))
00118 #define       MASK_PRESS(x)        ((002 << (6 * ((x) - 1))))
00119 #define       MASK_CLICK(x)        ((004 << (6 * ((x) - 1))))
00120 #define       MASK_DOUBLE_CLICK(x) ((010 << (6 * ((x) - 1))))
00121 #define       MASK_TRIPLE_CLICK(x) ((020 << (6 * ((x) - 1))))
00122 #define       MASK_RESERVED_EVENT(x)      ((040 << (6 * ((x) - 1))))
00123 
00124 #define BUTTON_CLICKED  (BUTTON1_CLICKED  | BUTTON2_CLICKED  | BUTTON3_CLICKED)
00125 #define BUTTON_PRESSED  (BUTTON1_PRESSED  | BUTTON2_PRESSED  | BUTTON3_PRESSED)
00126 #define BUTTON_RELEASED (BUTTON1_RELEASED | BUTTON2_RELEASED | BUTTON3_RELEASED)
00127 
00128 #define INVALID_EVENT       -1
00129 #define NORMAL_EVENT 0
00130 
00131 #if USE_GPM_SUPPORT
00132 #ifndef LINT
00133 static Gpm_Connect gpm_connect;
00134 static int (*my_Gpm_Open) (Gpm_Connect *, int);
00135 static int (*my_Gpm_GetEvent) (Gpm_Event *);
00136 static int *my_gpm_fd;
00137 #endif
00138 #endif
00139 
00140 static mmask_t eventmask;   /* current event mask */
00141 
00142 static bool _nc_mouse_parse(int);
00143 static void _nc_mouse_resume(SCREEN *);
00144 static void _nc_mouse_wrap(SCREEN *);
00145 
00146 /* maintain a circular list of mouse events */
00147 
00148 /* The definition of the circular list size (EV_MAX), is in curses.priv.h, so
00149  * wgetch() may refer to the size and call _nc_mouse_parse() before circular
00150  * list overflow.
00151  */
00152 static MEVENT events[EV_MAX];      /* hold the last mouse event seen */
00153 static MEVENT *eventp = events;    /* next free slot in event queue */
00154 
00155 #undef  NEXT
00156 #define NEXT(ep)     ((ep == events + EV_MAX - 1) ? events : ep + 1)
00157 
00158 #undef  PREV
00159 #define PREV(ep)     ((ep == events) ? events + EV_MAX - 1 : ep - 1)
00160 
00161 #ifdef TRACE
00162 static void
00163 _trace_slot(const char *tag)
00164 {
00165     MEVENT *ep;
00166 
00167     _tracef(tag);
00168 
00169     for (ep = events; ep < events + EV_MAX; ep++)
00170        _tracef("mouse event queue slot %ld = %s",
00171               (long) (ep - events),
00172               _tracemouse(ep));
00173 }
00174 #endif
00175 
00176 #if USE_EMX_MOUSE
00177 
00178 #  define TOP_ROW          0
00179 #  define LEFT_COL         0
00180 
00181 static int mouse_wfd;
00182 static int mouse_thread;
00183 static int mouse_activated;
00184 static char mouse_buttons[] =
00185 {0, 1, 3, 2};
00186 
00187 #  define M_FD(sp) sp->_mouse_fd
00188 
00189 static void
00190 write_event(int down, int button, int x, int y)
00191 {
00192     char buf[6];
00193     unsigned long ignore;
00194 
00195     strncpy(buf, key_mouse, 3);    /* should be "\033[M" */
00196     buf[3] = ' ' + (button - 1) + (down ? 0 : 0x40);
00197     buf[4] = ' ' + x - LEFT_COL + 1;
00198     buf[5] = ' ' + y - TOP_ROW + 1;
00199     DosWrite(mouse_wfd, buf, 6, &ignore);
00200 }
00201 
00202 static void
00203 mouse_server(unsigned long ignored GCC_UNUSED)
00204 {
00205     unsigned short fWait = MOU_WAIT;
00206     /* NOPTRRECT mourt = { 0,0,24,79 }; */
00207     MOUEVENTINFO mouev;
00208     HMOU hmou;
00209     unsigned short mask = MOUSE_BN1_DOWN | MOUSE_BN2_DOWN | MOUSE_BN3_DOWN;
00210     int nbuttons = 3;
00211     int oldstate = 0;
00212     char err[80];
00213     unsigned long rc;
00214 
00215     /* open the handle for the mouse */
00216     if (MouOpen(NULL, &hmou) == 0) {
00217        rc = MouSetEventMask(&mask, hmou);
00218        if (rc) {            /* retry with 2 buttons */
00219            mask = MOUSE_BN1_DOWN | MOUSE_BN2_DOWN;
00220            rc = MouSetEventMask(&mask, hmou);
00221            nbuttons = 2;
00222        }
00223        if (rc == 0 && MouDrawPtr(hmou) == 0) {
00224            for (;;) {
00225               /* sit and wait on the event queue */
00226               rc = MouReadEventQue(&mouev, &fWait, hmou);
00227               if (rc) {
00228                   sprintf(err, "Error reading mouse queue, rc=%lu.\r\n", rc);
00229                   break;
00230               }
00231               if (!mouse_activated)
00232                   goto finish;
00233 
00234               /*
00235                * OS/2 numbers a 3-button mouse inconsistently from other
00236                * platforms:
00237                *      1 = left
00238                *      2 = right
00239                *      3 = middle.
00240                */
00241               if ((mouev.fs ^ oldstate) & MOUSE_BN1_DOWN)
00242                   write_event(mouev.fs & MOUSE_BN1_DOWN,
00243                             mouse_buttons[1], mouev.col, mouev.row);
00244               if ((mouev.fs ^ oldstate) & MOUSE_BN2_DOWN)
00245                   write_event(mouev.fs & MOUSE_BN2_DOWN,
00246                             mouse_buttons[3], mouev.col, mouev.row);
00247               if ((mouev.fs ^ oldstate) & MOUSE_BN3_DOWN)
00248                   write_event(mouev.fs & MOUSE_BN3_DOWN,
00249                             mouse_buttons[2], mouev.col, mouev.row);
00250 
00251              finish:
00252               oldstate = mouev.fs;
00253            }
00254        } else
00255            sprintf(err, "Error setting event mask, buttons=%d, rc=%lu.\r\n",
00256                   nbuttons, rc);
00257 
00258        DosWrite(2, err, strlen(err), &rc);
00259        MouClose(hmou);
00260     }
00261     DosExit(EXIT_THREAD, 0L);
00262 }
00263 
00264 static void
00265 server_state(const int state)
00266 {                           /* It would be nice to implement pointer-off and stop looping... */
00267     mouse_activated = state;
00268 }
00269 
00270 #endif /* USE_EMX_MOUSE */
00271 
00272 #if USE_SYSMOUSE
00273 static void
00274 handle_sysmouse(int sig GCC_UNUSED)
00275 {
00276     struct mouse_info the_mouse;
00277     MEVENT *work;
00278 
00279     the_mouse.operation = MOUSE_GETINFO;
00280     if (SP != 0
00281        && SP->_mouse_fd >= 0
00282        && SP->_sysmouse_tail < FIFO_SIZE
00283        && ioctl(SP->_mouse_fd, CONS_MOUSECTL, &the_mouse) != -1) {
00284 
00285        if (SP->_sysmouse_head > SP->_sysmouse_tail) {
00286            SP->_sysmouse_tail = 0;
00287            SP->_sysmouse_head = 0;
00288        }
00289        work = &(SP->_sysmouse_fifo[SP->_sysmouse_tail]);
00290        memset(work, 0, sizeof(*work));
00291        work->id = NORMAL_EVENT;    /* there's only one mouse... */
00292 
00293        SP->_sysmouse_old_buttons = SP->_sysmouse_new_buttons;
00294        SP->_sysmouse_new_buttons = the_mouse.u.data.buttons & 0x7;
00295 
00296        if (SP->_sysmouse_new_buttons) {
00297            if (SP->_sysmouse_new_buttons & 1)
00298               work->bstate |= BUTTON1_PRESSED;
00299            if (SP->_sysmouse_new_buttons & 2)
00300               work->bstate |= BUTTON2_PRESSED;
00301            if (SP->_sysmouse_new_buttons & 4)
00302               work->bstate |= BUTTON3_PRESSED;
00303        } else {
00304            if (SP->_sysmouse_old_buttons & 1)
00305               work->bstate |= BUTTON1_RELEASED;
00306            if (SP->_sysmouse_old_buttons & 2)
00307               work->bstate |= BUTTON2_RELEASED;
00308            if (SP->_sysmouse_old_buttons & 4)
00309               work->bstate |= BUTTON3_RELEASED;
00310        }
00311 
00312        /* for cosmetic bug in syscons.c on FreeBSD 3.[34] */
00313        the_mouse.operation = MOUSE_HIDE;
00314        ioctl(SP->_mouse_fd, CONS_MOUSECTL, &the_mouse);
00315        the_mouse.operation = MOUSE_SHOW;
00316        ioctl(SP->_mouse_fd, CONS_MOUSECTL, &the_mouse);
00317 
00318        /*
00319         * We're only interested if the button is pressed or released.
00320         * FIXME: implement continuous event-tracking.
00321         */
00322        if (SP->_sysmouse_new_buttons != SP->_sysmouse_old_buttons) {
00323            SP->_sysmouse_tail += 1;
00324        }
00325        work->x = the_mouse.u.data.x / SP->_sysmouse_char_width;
00326        work->y = the_mouse.u.data.y / SP->_sysmouse_char_height;
00327     }
00328 }
00329 #endif
00330 
00331 static int initialized;
00332 
00333 static void
00334 init_xterm_mouse(void)
00335 {
00336     SP->_mouse_type = M_XTERM;
00337     SP->_mouse_xtermcap = tigetstr("XM");
00338     if (!VALID_STRING(SP->_mouse_xtermcap))
00339        SP->_mouse_xtermcap = "\033[?1000%?%p1%{1}%=%th%el%;";
00340 }
00341 
00342 #if !USE_EMX_MOUSE
00343 static void
00344 enable_xterm_mouse(int enable)
00345 {
00346     putp(tparm(SP->_mouse_xtermcap, enable));
00347 }
00348 #endif /* !USE_EMX_MOUSE */
00349 
00350 static void
00351 initialize_mousetype(void)
00352 {
00353     static const char *xterm_kmous = "\033[M";
00354 
00355     /* Try gpm first, because gpm may be configured to run in xterm */
00356 #if USE_GPM_SUPPORT
00357     /* GPM does printf's without checking if stdout is a terminal */
00358     if (isatty(fileno(stdout))) {
00359        static bool first = TRUE;
00360        static bool found = FALSE;
00361 
00362        if (first) {
00363            void *obj;
00364            first = FALSE;
00365 
00366            if ((obj = dlopen("libgpm.so", my_RTLD)) != 0) {
00367               if ((my_gpm_fd = dlsym(obj, "gpm_fd")) == 0 ||
00368                   (my_Gpm_Open = dlsym(obj, "Gpm_Open")) == 0 ||
00369                   (my_Gpm_GetEvent = dlsym(obj, "Gpm_GetEvent")) == 0) {
00370                   T(("GPM initialization failed: %s", dlerror()));
00371                   dlclose(obj);
00372               } else {
00373                   found = TRUE;
00374               }
00375            }
00376        }
00377 
00378        if (found) {
00379            /* GPM: initialize connection to gpm server */
00380            gpm_connect.eventMask = GPM_DOWN | GPM_UP;
00381            gpm_connect.defaultMask = ~(gpm_connect.eventMask | GPM_HARD);
00382            gpm_connect.minMod = 0;
00383            gpm_connect.maxMod = ~((1 << KG_SHIFT) |
00384                                (1 << KG_SHIFTL) |
00385                                (1 << KG_SHIFTR));
00386            if (my_Gpm_Open(&gpm_connect, 0) >= 0) {     /* returns the file-descriptor */
00387               SP->_mouse_type = M_GPM;
00388               SP->_mouse_fd = *my_gpm_fd;
00389               return;
00390            }
00391        }
00392     }
00393 #endif
00394 
00395     /* OS/2 VIO */
00396 #if USE_EMX_MOUSE
00397     if (!mouse_thread
00398        && strstr(cur_term->type.term_names, "xterm") == 0
00399        && key_mouse) {
00400        int handles[2];
00401 
00402        if (pipe(handles) < 0) {
00403            perror("mouse pipe error");
00404            return;
00405        } else {
00406            int rc;
00407 
00408            if (!mouse_buttons[0]) {
00409               char *s = getenv("MOUSE_BUTTONS_123");
00410 
00411               mouse_buttons[0] = 1;
00412               if (s && strlen(s) >= 3) {
00413                   mouse_buttons[1] = s[0] - '0';
00414                   mouse_buttons[2] = s[1] - '0';
00415                   mouse_buttons[3] = s[2] - '0';
00416               }
00417            }
00418            mouse_wfd = handles[1];
00419            M_FD(SP) = handles[0];
00420            /* Needed? */
00421            setmode(handles[0], O_BINARY);
00422            setmode(handles[1], O_BINARY);
00423            /* Do not use CRT functions, we may single-threaded. */
00424            rc = DosCreateThread((unsigned long *) &mouse_thread,
00425                              mouse_server, 0, 0, 8192);
00426            if (rc) {
00427               printf("mouse thread error %d=%#x", rc, rc);
00428               return;
00429            } else {
00430               SP->_mouse_type = M_XTERM;
00431               return;
00432            }
00433        }
00434     }
00435 #endif
00436 
00437 #if USE_SYSMOUSE
00438     {
00439        struct mouse_info the_mouse;
00440        char *the_device = 0;
00441 
00442        if (isatty(SP->_ifd))
00443            the_device = ttyname(SP->_ifd);
00444        if (the_device == 0)
00445            the_device = "/dev/tty";
00446 
00447        SP->_mouse_fd = open(the_device, O_RDWR);
00448 
00449        if (SP->_mouse_fd >= 0) {
00450            /*
00451             * sysmouse does not have a usable user interface for obtaining
00452             * mouse events.  The logical way to proceed (reading data on a
00453             * stream) only works if one opens the device as root.  Even in
00454             * that mode, careful examination shows we lose events
00455             * occasionally.  The interface provided for user programs is to
00456             * establish a signal handler.  really.
00457             *
00458             * Take over SIGUSR2 for this purpose since SIGUSR1 is more
00459             * likely to be used by an application.  getch() will have to
00460             * handle the misleading EINTR's.
00461             */
00462            signal(SIGUSR2, SIG_IGN);
00463            the_mouse.operation = MOUSE_MODE;
00464            the_mouse.u.mode.mode = 0;
00465            the_mouse.u.mode.signal = SIGUSR2;
00466            if (ioctl(SP->_mouse_fd, CONS_MOUSECTL, &the_mouse) != -1) {
00467               signal(SIGUSR2, handle_sysmouse);
00468               the_mouse.operation = MOUSE_SHOW;
00469               ioctl(SP->_mouse_fd, CONS_MOUSECTL, &the_mouse);
00470 
00471 #if defined(FBIO_MODEINFO) || defined(CONS_MODEINFO)    /* FreeBSD > 2.x */
00472               {
00473 #ifndef FBIO_GETMODE        /* FreeBSD 3.x */
00474 #define FBIO_GETMODE    CONS_GET
00475 #define FBIO_MODEINFO   CONS_MODEINFO
00476 #endif /* FBIO_GETMODE */
00477                   video_info_t the_video;
00478 
00479                   if (ioctl(SP->_mouse_fd,
00480                            FBIO_GETMODE,
00481                            &the_video.vi_mode) != -1
00482                      && ioctl(SP->_mouse_fd,
00483                              FBIO_MODEINFO,
00484                              &the_video) != -1) {
00485                      SP->_sysmouse_char_width = the_video.vi_cwidth;
00486                      SP->_sysmouse_char_height = the_video.vi_cheight;
00487                   }
00488               }
00489 #endif /* defined(FBIO_MODEINFO) || defined(CONS_MODEINFO) */
00490 
00491               if (SP->_sysmouse_char_width <= 0)
00492                   SP->_sysmouse_char_width = 8;
00493               if (SP->_sysmouse_char_height <= 0)
00494                   SP->_sysmouse_char_height = 16;
00495               SP->_mouse_type = M_SYSMOUSE;
00496               return;
00497            }
00498        }
00499     }
00500 #endif /* USE_SYSMOUSE */
00501 
00502     /* we know how to recognize mouse events under "xterm" */
00503     if (key_mouse != 0) {
00504        if (!strcmp(key_mouse, xterm_kmous)) {
00505            init_xterm_mouse();
00506            return;
00507        }
00508     } else if (strstr(cur_term->type.term_names, "xterm") != 0) {
00509        (void) _nc_add_to_try(&(SP->_keytry), xterm_kmous, KEY_MOUSE);
00510        init_xterm_mouse();
00511        return;
00512     }
00513 }
00514 
00515 static void
00516 _nc_mouse_init(void)
00517 /* initialize the mouse */
00518 {
00519     int i;
00520 
00521     if (!initialized) {
00522        initialized = TRUE;
00523 
00524        TR(MY_TRACE, ("_nc_mouse_init() called"));
00525 
00526        for (i = 0; i < EV_MAX; i++)
00527            events[i].id = INVALID_EVENT;
00528 
00529        initialize_mousetype();
00530 
00531        T(("_nc_mouse_init() set mousetype to %d", SP->_mouse_type));
00532     }
00533 }
00534 
00535 /*
00536  * Query to see if there is a pending mouse event.  This is called from
00537  * fifo_push() in lib_getch.c
00538  */
00539 static bool
00540 _nc_mouse_event(SCREEN *sp GCC_UNUSED)
00541 {
00542     bool result = FALSE;
00543 
00544     switch (SP->_mouse_type) {
00545     case M_XTERM:
00546        /* xterm: never have to query, mouse events are in the keyboard stream */
00547 #if USE_EMX_MOUSE
00548        {
00549            char kbuf[3];
00550 
00551            int i, res = read(M_FD(sp), &kbuf, 3);       /* Eat the prefix */
00552            if (res != 3)
00553               printf("Got %d chars instead of 3 for prefix.\n", res);
00554            for (i = 0; i < res; i++) {
00555               if (kbuf[i] != key_mouse[i])
00556                   printf("Got char %d instead of %d for prefix.\n",
00557                         (int) kbuf[i], (int) key_mouse[i]);
00558            }
00559            result = TRUE;
00560        }
00561 #endif /* USE_EMX_MOUSE */
00562        break;
00563 
00564 #if USE_GPM_SUPPORT
00565     case M_GPM:
00566        {
00567            /* query server for event, return TRUE if we find one */
00568            Gpm_Event ev;
00569 
00570            if (my_Gpm_GetEvent(&ev) == 1) {
00571               /* there's only one mouse... */
00572               eventp->id = NORMAL_EVENT;
00573 
00574               eventp->bstate = 0;
00575               switch (ev.type & 0x0f) {
00576               case (GPM_DOWN):
00577                   if (ev.buttons & GPM_B_LEFT)
00578                      eventp->bstate |= BUTTON1_PRESSED;
00579                   if (ev.buttons & GPM_B_MIDDLE)
00580                      eventp->bstate |= BUTTON2_PRESSED;
00581                   if (ev.buttons & GPM_B_RIGHT)
00582                      eventp->bstate |= BUTTON3_PRESSED;
00583                   break;
00584               case (GPM_UP):
00585                   if (ev.buttons & GPM_B_LEFT)
00586                      eventp->bstate |= BUTTON1_RELEASED;
00587                   if (ev.buttons & GPM_B_MIDDLE)
00588                      eventp->bstate |= BUTTON2_RELEASED;
00589                   if (ev.buttons & GPM_B_RIGHT)
00590                      eventp->bstate |= BUTTON3_RELEASED;
00591                   break;
00592               default:
00593                   break;
00594               }
00595 
00596               eventp->x = ev.x - 1;
00597               eventp->y = ev.y - 1;
00598               eventp->z = 0;
00599 
00600               /* bump the next-free pointer into the circular list */
00601               eventp = NEXT(eventp);
00602               result = TRUE;
00603            }
00604        }
00605        break;
00606 #endif
00607 
00608 #if USE_SYSMOUSE
00609     case M_SYSMOUSE:
00610        if (SP->_sysmouse_head < SP->_sysmouse_tail) {
00611            *eventp = SP->_sysmouse_fifo[SP->_sysmouse_head];
00612 
00613            /*
00614             * Point the fifo-head to the next possible location.  If there
00615             * are none, reset the indices.  This may be interrupted by the
00616             * signal handler, doing essentially the same reset.
00617             */
00618            SP->_sysmouse_head += 1;
00619            if (SP->_sysmouse_head == SP->_sysmouse_tail) {
00620               SP->_sysmouse_tail = 0;
00621               SP->_sysmouse_head = 0;
00622            }
00623 
00624            /* bump the next-free pointer into the circular list */
00625            eventp = NEXT(eventp);
00626            result = TRUE;
00627        }
00628        break;
00629 #endif /* USE_SYSMOUSE */
00630 
00631     case M_NONE:
00632        break;
00633     }
00634 
00635     return result;          /* true if we found an event */
00636 }
00637 
00638 static bool
00639 _nc_mouse_inline(SCREEN *sp)
00640 /* mouse report received in the keyboard stream -- parse its info */
00641 {
00642     bool result = FALSE;
00643 
00644     TR(MY_TRACE, ("_nc_mouse_inline() called"));
00645 
00646     if (SP->_mouse_type == M_XTERM) {
00647        unsigned char kbuf[4];
00648        mmask_t prev;
00649        size_t grabbed;
00650        int res;
00651 
00652        /* This code requires that your xterm entry contain the kmous
00653         * capability and that it be set to the \E[M documented in the
00654         * Xterm Control Sequences reference.  This is how we
00655         * arrange for mouse events to be reported via a KEY_MOUSE
00656         * return value from wgetch().  After this value is received,
00657         * _nc_mouse_inline() gets called and is immediately
00658         * responsible for parsing the mouse status information
00659         * following the prefix.
00660         *
00661         * The following quotes from the ctrlseqs.ms document in the
00662         * X distribution, describing the X mouse tracking feature:
00663         *
00664         * Parameters for all mouse tracking escape sequences
00665         * generated by xterm encode numeric parameters in a single
00666         * character as value+040.  For example, !  is 1.
00667         *
00668         * On button press or release, xterm sends ESC [ M CbCxCy.
00669         * The low two bits of Cb encode button information: 0=MB1
00670         * pressed, 1=MB2 pressed, 2=MB3 pressed, 3=release.  The
00671         * upper bits encode what modifiers were down when the
00672         * button was pressed and are added together.  4=Shift,
00673         * 8=Meta, 16=Control.  Cx and Cy are the x and y coordinates
00674         * of the mouse event.  The upper left corner is (1,1).
00675         *
00676         * (End quote)  By the time we get here, we've eaten the
00677         * key prefix.  FYI, the loop below is necessary because
00678         * mouse click info isn't guaranteed to present as a
00679         * single clist item.  It always does under Linux but often
00680         * fails to under Solaris.
00681         */
00682        for (grabbed = 0; grabbed < 3; grabbed += res) {
00683 
00684            /* For VIO mouse we add extra bit 64 to disambiguate button-up. */
00685 #if USE_EMX_MOUSE
00686            res = read(M_FD(sp) >= 0 ? M_FD(sp) : sp->_ifd, &kbuf, 3);
00687 #else
00688            res = read(sp->_ifd, kbuf + grabbed, 3 - grabbed);
00689 #endif
00690            if (res == -1)
00691               break;
00692        }
00693        kbuf[3] = '\0';
00694 
00695        TR(TRACE_IEVENT,
00696           ("_nc_mouse_inline sees the following xterm data: '%s'", kbuf));
00697 
00698        /* there's only one mouse... */
00699        eventp->id = NORMAL_EVENT;
00700 
00701        /* processing code goes here */
00702        eventp->bstate = 0;
00703        prev = PREV(eventp)->bstate;
00704 
00705 #if USE_EMX_MOUSE
00706 #define PRESS_POSITION(n) \
00707        eventp->bstate = MASK_PRESS(n); \
00708        if (kbuf[0] & 0x40) \
00709            eventp->bstate = MASK_RELEASE(n)
00710 #else
00711 #define PRESS_POSITION(n) \
00712        eventp->bstate = (prev & MASK_PRESS(n) \
00713                      ? REPORT_MOUSE_POSITION \
00714                      : MASK_PRESS(n))
00715 #endif
00716 
00717        switch (kbuf[0] & 0x3) {
00718        case 0x0:
00719            PRESS_POSITION(1);
00720            break;
00721 
00722        case 0x1:
00723            PRESS_POSITION(2);
00724            break;
00725 
00726        case 0x2:
00727            PRESS_POSITION(3);
00728            break;
00729 
00730        case 0x3:
00731            /*
00732             * Release events aren't reported for individual buttons, just for
00733             * the button set as a whole.  However, because there are normally
00734             * no mouse events under xterm that intervene between press and
00735             * release, we can infer the button actually released by looking at
00736             * the previous event.
00737             */
00738            if (prev & (BUTTON_PRESSED | BUTTON_RELEASED)) {
00739               eventp->bstate = BUTTON_RELEASED;
00740               if (!(prev & BUTTON1_PRESSED))
00741                   eventp->bstate &= ~BUTTON1_RELEASED;
00742               if (!(prev & BUTTON2_PRESSED))
00743                   eventp->bstate &= ~BUTTON2_RELEASED;
00744               if (!(prev & BUTTON3_PRESSED))
00745                   eventp->bstate &= ~BUTTON3_RELEASED;
00746            } else {
00747               /*
00748                * XFree86 xterm will return a stream of release-events to
00749                * let the application know where the mouse is going, if the
00750                * private mode 1002 or 1003 is enabled.
00751                */
00752               eventp->bstate = REPORT_MOUSE_POSITION;
00753            }
00754            break;
00755        }
00756        result = (eventp->bstate & REPORT_MOUSE_POSITION) ? TRUE : FALSE;
00757 
00758        if (kbuf[0] & 4) {
00759            eventp->bstate |= BUTTON_SHIFT;
00760        }
00761        if (kbuf[0] & 8) {
00762            eventp->bstate |= BUTTON_ALT;
00763        }
00764        if (kbuf[0] & 16) {
00765            eventp->bstate |= BUTTON_CTRL;
00766        }
00767 
00768        eventp->x = (kbuf[1] - ' ') - 1;
00769        eventp->y = (kbuf[2] - ' ') - 1;
00770        TR(MY_TRACE,
00771           ("_nc_mouse_inline: primitive mouse-event %s has slot %ld",
00772            _tracemouse(eventp),
00773            (long) (eventp - events)));
00774 
00775        /* bump the next-free pointer into the circular list */
00776        eventp = NEXT(eventp);
00777 #if 0                       /* this return would be needed for QNX's mods to lib_getch.c */
00778        return (TRUE);
00779 #endif
00780     }
00781 
00782     return (result);
00783 }
00784 
00785 static void
00786 mouse_activate(bool on)
00787 {
00788     if (!on && !initialized)
00789        return;
00790 
00791     _nc_mouse_init();
00792 
00793     if (on) {
00794 
00795        switch (SP->_mouse_type) {
00796        case M_XTERM:
00797 #if NCURSES_EXT_FUNCS
00798            keyok(KEY_MOUSE, on);
00799 #endif
00800            TPUTS_TRACE("xterm mouse initialization");
00801 #if USE_EMX_MOUSE
00802            server_state(1);
00803 #else
00804            enable_xterm_mouse(1);
00805 #endif
00806            break;
00807 #if USE_GPM_SUPPORT
00808        case M_GPM:
00809            SP->_mouse_fd = *my_gpm_fd;
00810            break;
00811 #endif
00812 #if USE_SYSMOUSE
00813        case M_SYSMOUSE:
00814            signal(SIGUSR2, handle_sysmouse);
00815            break;
00816 #endif
00817        case M_NONE:
00818            return;
00819        }
00820        /* Make runtime binding to cut down on object size of applications that
00821         * do not use the mouse (e.g., 'clear').
00822         */
00823        SP->_mouse_event = _nc_mouse_event;
00824        SP->_mouse_inline = _nc_mouse_inline;
00825        SP->_mouse_parse = _nc_mouse_parse;
00826        SP->_mouse_resume = _nc_mouse_resume;
00827        SP->_mouse_wrap = _nc_mouse_wrap;
00828 
00829     } else {
00830 
00831        switch (SP->_mouse_type) {
00832        case M_XTERM:
00833            TPUTS_TRACE("xterm mouse deinitialization");
00834 #if USE_EMX_MOUSE
00835            server_state(0);
00836 #else
00837            enable_xterm_mouse(0);
00838 #endif
00839            break;
00840 #if USE_GPM_SUPPORT
00841        case M_GPM:
00842            break;
00843 #endif
00844 #if USE_SYSMOUSE
00845        case M_SYSMOUSE:
00846            signal(SIGUSR2, SIG_IGN);
00847            break;
00848 #endif
00849        case M_NONE:
00850            return;
00851        }
00852     }
00853     _nc_flush();
00854 }
00855 
00856 /**************************************************************************
00857  *
00858  * Device-independent code
00859  *
00860  **************************************************************************/
00861 
00862 static bool
00863 _nc_mouse_parse(int runcount)
00864 /* parse a run of atomic mouse events into a gesture */
00865 {
00866     MEVENT *ep, *runp, *next, *prev = PREV(eventp);
00867     int n;
00868     bool merge;
00869 
00870     TR(MY_TRACE, ("_nc_mouse_parse(%d) called", runcount));
00871 
00872     /*
00873      * When we enter this routine, the event list next-free pointer
00874      * points just past a run of mouse events that we know were separated
00875      * in time by less than the critical click interval. The job of this
00876      * routine is to collapse this run into a single higher-level event
00877      * or gesture.
00878      *
00879      * We accomplish this in two passes.  The first pass merges press/release
00880      * pairs into click events.  The second merges runs of click events into
00881      * double or triple-click events.
00882      *
00883      * It's possible that the run may not resolve to a single event (for
00884      * example, if the user quadruple-clicks).  If so, leading events
00885      * in the run are ignored.
00886      *
00887      * Note that this routine is independent of the format of the specific
00888      * format of the pointing-device's reports.  We can use it to parse
00889      * gestures on anything that reports press/release events on a per-
00890      * button basis, as long as the device-dependent mouse code puts stuff
00891      * on the queue in MEVENT format.
00892      */
00893     if (runcount == 1) {
00894        TR(MY_TRACE,
00895           ("_nc_mouse_parse: returning simple mouse event %s at slot %ld",
00896            _tracemouse(prev),
00897            (long) (prev - events)));
00898        return (prev->id >= NORMAL_EVENT)
00899            ? ((prev->bstate & eventmask) ? TRUE : FALSE)
00900            : FALSE;
00901     }
00902 
00903     /* find the start of the run */
00904     runp = eventp;
00905     for (n = runcount; n > 0; n--) {
00906        runp = PREV(runp);
00907     }
00908 
00909 #ifdef TRACE
00910     if (_nc_tracing & TRACE_IEVENT) {
00911        _trace_slot("before mouse press/release merge:");
00912        _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d",
00913               (long) (runp - events),
00914               (long) ((eventp - events) + (EV_MAX - 1)) % EV_MAX,
00915               runcount);
00916     }
00917 #endif /* TRACE */
00918 
00919     /* first pass; merge press/release pairs */
00920     do {
00921        merge = FALSE;
00922        for (ep = runp; (next = NEXT(ep)) != eventp; ep = next) {
00923            if (ep->x == next->x && ep->y == next->y
00924               && (ep->bstate & BUTTON_PRESSED)
00925               && (!(ep->bstate & BUTTON1_PRESSED)
00926                   == !(next->bstate & BUTTON1_RELEASED))
00927               && (!(ep->bstate & BUTTON2_PRESSED)
00928                   == !(next->bstate & BUTTON2_RELEASED))
00929               && (!(ep->bstate & BUTTON3_PRESSED)
00930                   == !(next->bstate & BUTTON3_RELEASED))
00931               ) {
00932               if ((eventmask & BUTTON1_CLICKED)
00933                   && (ep->bstate & BUTTON1_PRESSED)) {
00934                   ep->bstate &= ~BUTTON1_PRESSED;
00935                   ep->bstate |= BUTTON1_CLICKED;
00936                   merge = TRUE;
00937               }
00938               if ((eventmask & BUTTON2_CLICKED)
00939                   && (ep->bstate & BUTTON2_PRESSED)) {
00940                   ep->bstate &= ~BUTTON2_PRESSED;
00941                   ep->bstate |= BUTTON2_CLICKED;
00942                   merge = TRUE;
00943               }
00944               if ((eventmask & BUTTON3_CLICKED)
00945                   && (ep->bstate & BUTTON3_PRESSED)) {
00946                   ep->bstate &= ~BUTTON3_PRESSED;
00947                   ep->bstate |= BUTTON3_CLICKED;
00948                   merge = TRUE;
00949               }
00950               if (merge)
00951                   next->id = INVALID_EVENT;
00952            }
00953        }
00954     } while
00955        (merge);
00956 
00957 #ifdef TRACE
00958     if (_nc_tracing & TRACE_IEVENT) {
00959        _trace_slot("before mouse click merge:");
00960        _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d",
00961               (long) (runp - events),
00962               (long) ((eventp - events) + (EV_MAX - 1)) % EV_MAX,
00963               runcount);
00964     }
00965 #endif /* TRACE */
00966 
00967     /*
00968      * Second pass; merge click runs.  At this point, click events are
00969      * each followed by one invalid event. We merge click events
00970      * forward in the queue.
00971      *
00972      * NOTE: There is a problem with this design!  If the application
00973      * allows enough click events to pile up in the circular queue so
00974      * they wrap around, it will cheerfully merge the newest forward
00975      * into the oldest, creating a bogus doubleclick and confusing
00976      * the queue-traversal logic rather badly.  Generally this won't
00977      * happen, because calling getmouse() marks old events invalid and
00978      * ineligible for merges.  The true solution to this problem would
00979      * be to timestamp each MEVENT and perform the obvious sanity check,
00980      * but the timer element would have to have sub-second resolution,
00981      * which would get us into portability trouble.
00982      */
00983     do {
00984        MEVENT *follower;
00985 
00986        merge = FALSE;
00987        for (ep = runp; (next = NEXT(ep)) != eventp; ep = next)
00988            if (ep->id != INVALID_EVENT) {
00989               if (next->id != INVALID_EVENT)
00990                   continue;
00991               follower = NEXT(next);
00992               if (follower->id == INVALID_EVENT)
00993                   continue;
00994 
00995               /* merge click events forward */
00996               if ((ep->bstate & BUTTON_CLICKED)
00997                   && (follower->bstate & BUTTON_CLICKED)) {
00998                   if ((eventmask & BUTTON1_DOUBLE_CLICKED)
00999                      && (follower->bstate & BUTTON1_CLICKED)) {
01000                      follower->bstate &= ~BUTTON1_CLICKED;
01001                      follower->bstate |= BUTTON1_DOUBLE_CLICKED;
01002                      merge = TRUE;
01003                   }
01004                   if ((eventmask & BUTTON2_DOUBLE_CLICKED)
01005                      && (follower->bstate & BUTTON2_CLICKED)) {
01006                      follower->bstate &= ~BUTTON2_CLICKED;
01007                      follower->bstate |= BUTTON2_DOUBLE_CLICKED;
01008                      merge = TRUE;
01009                   }
01010                   if ((eventmask & BUTTON3_DOUBLE_CLICKED)
01011                      && (follower->bstate & BUTTON3_CLICKED)) {
01012                      follower->bstate &= ~BUTTON3_CLICKED;
01013                      follower->bstate |= BUTTON3_DOUBLE_CLICKED;
01014                      merge = TRUE;
01015                   }
01016                   if (merge)
01017                      ep->id = INVALID_EVENT;
01018               }
01019 
01020               /* merge double-click events forward */
01021               if ((ep->bstate &
01022                    (BUTTON1_DOUBLE_CLICKED
01023                     | BUTTON2_DOUBLE_CLICKED
01024                     | BUTTON3_DOUBLE_CLICKED))
01025                   && (follower->bstate & BUTTON_CLICKED)) {
01026                   if ((eventmask & BUTTON1_TRIPLE_CLICKED)
01027                      && (follower->bstate & BUTTON1_CLICKED)) {
01028                      follower->bstate &= ~BUTTON1_CLICKED;
01029                      follower->bstate |= BUTTON1_TRIPLE_CLICKED;
01030                      merge = TRUE;
01031                   }
01032                   if ((eventmask & BUTTON2_TRIPLE_CLICKED)
01033                      && (follower->bstate & BUTTON2_CLICKED)) {
01034                      follower->bstate &= ~BUTTON2_CLICKED;
01035                      follower->bstate |= BUTTON2_TRIPLE_CLICKED;
01036                      merge = TRUE;
01037                   }
01038                   if ((eventmask & BUTTON3_TRIPLE_CLICKED)
01039                      && (follower->bstate & BUTTON3_CLICKED)) {
01040                      follower->bstate &= ~BUTTON3_CLICKED;
01041                      follower->bstate |= BUTTON3_TRIPLE_CLICKED;
01042                      merge = TRUE;
01043                   }
01044                   if (merge)
01045                      ep->id = INVALID_EVENT;
01046               }
01047            }
01048     } while
01049        (merge);
01050 
01051 #ifdef TRACE
01052     if (_nc_tracing & TRACE_IEVENT) {
01053        _trace_slot("before mouse event queue compaction:");
01054        _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d",
01055               (long) (runp - events),
01056               (long) ((eventp - events) + (EV_MAX - 1)) % EV_MAX,
01057               runcount);
01058     }
01059 #endif /* TRACE */
01060 
01061     /*
01062      * Now try to throw away trailing events flagged invalid, or that
01063      * don't match the current event mask.
01064      */
01065     for (; runcount; prev = PREV(eventp), runcount--)
01066        if (prev->id == INVALID_EVENT || !(prev->bstate & eventmask)) {
01067            eventp = prev;
01068        }
01069 #ifdef TRACE
01070     if (_nc_tracing & TRACE_IEVENT) {
01071        _trace_slot("after mouse event queue compaction:");
01072        _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d",
01073               (long) (runp - events),
01074               (long) ((eventp - events) + (EV_MAX - 1)) % EV_MAX,
01075               runcount);
01076     }
01077     for (ep = runp; ep != eventp; ep = NEXT(ep))
01078        if (ep->id != INVALID_EVENT)
01079            TR(MY_TRACE,
01080               ("_nc_mouse_parse: returning composite mouse event %s at slot %ld",
01081               _tracemouse(ep),
01082               (long) (ep - events)));
01083 #endif /* TRACE */
01084 
01085     /* after all this, do we have a valid event? */
01086     return (PREV(eventp)->id != INVALID_EVENT);
01087 }
01088 
01089 static void
01090 _nc_mouse_wrap(SCREEN *sp GCC_UNUSED)
01091 /* release mouse -- called by endwin() before shellout/exit */
01092 {
01093     TR(MY_TRACE, ("_nc_mouse_wrap() called"));
01094 
01095     switch (SP->_mouse_type) {
01096     case M_XTERM:
01097        if (eventmask)
01098            mouse_activate(FALSE);
01099        break;
01100 #if USE_GPM_SUPPORT
01101        /* GPM: pass all mouse events to next client */
01102     case M_GPM:
01103        break;
01104 #endif
01105 #if USE_SYSMOUSE
01106     case M_SYSMOUSE:
01107        mouse_activate(FALSE);
01108        break;
01109 #endif
01110     case M_NONE:
01111        break;
01112     }
01113 }
01114 
01115 static void
01116 _nc_mouse_resume(SCREEN *sp GCC_UNUSED)
01117 /* re-connect to mouse -- called by doupdate() after shellout */
01118 {
01119     TR(MY_TRACE, ("_nc_mouse_resume() called"));
01120 
01121     switch (SP->_mouse_type) {
01122     case M_XTERM:
01123        /* xterm: re-enable reporting */
01124        if (eventmask)
01125            mouse_activate(TRUE);
01126        break;
01127 
01128 #if USE_GPM_SUPPORT
01129     case M_GPM:
01130        /* GPM: reclaim our event set */
01131        break;
01132 #endif
01133 
01134 #if USE_SYSMOUSE
01135     case M_SYSMOUSE:
01136        mouse_activate(TRUE);
01137        break;
01138 #endif
01139     case M_NONE:
01140        break;
01141     }
01142 }
01143 
01144 /**************************************************************************
01145  *
01146  * Mouse interface entry points for the API
01147  *
01148  **************************************************************************/
01149 
01150 NCURSES_EXPORT(int)
01151 getmouse(MEVENT * aevent)
01152 /* grab a copy of the current mouse event */
01153 {
01154     T((T_CALLED("getmouse(%p)"), aevent));
01155 
01156     if (aevent && (SP->_mouse_type != M_NONE)) {
01157        /* compute the current-event pointer */
01158        MEVENT *prev = PREV(eventp);
01159 
01160        /* copy the event we find there */
01161        *aevent = *prev;
01162 
01163        TR(TRACE_IEVENT, ("getmouse: returning event %s from slot %ld",
01164                        _tracemouse(prev),
01165                        (long) (prev - events)));
01166 
01167        prev->id = INVALID_EVENT;   /* so the queue slot becomes free */
01168        returnCode(OK);
01169     }
01170     returnCode(ERR);
01171 }
01172 
01173 NCURSES_EXPORT(int)
01174 ungetmouse(MEVENT * aevent)
01175 /* enqueue a synthesized mouse event to be seen by the next wgetch() */
01176 {
01177     T((T_CALLED("ungetmouse(%p)"), aevent));
01178 
01179     /* stick the given event in the next-free slot */
01180     *eventp = *aevent;
01181 
01182     /* bump the next-free pointer into the circular list */
01183     eventp = NEXT(eventp);
01184 
01185     /* push back the notification event on the keyboard queue */
01186     returnCode(ungetch(KEY_MOUSE));
01187 }
01188 
01189 NCURSES_EXPORT(mmask_t)
01190 mousemask(mmask_t newmask, mmask_t * oldmask)
01191 /* set the mouse event mask */
01192 {
01193     mmask_t result = 0;
01194 
01195     T((T_CALLED("mousemask(%#lx,%p)"), newmask, oldmask));
01196 
01197     if (oldmask)
01198        *oldmask = eventmask;
01199 
01200     if (!newmask && !initialized)
01201        returnBits(0);
01202 
01203     _nc_mouse_init();
01204     if (SP->_mouse_type != M_NONE) {
01205        eventmask = newmask &
01206            (REPORT_MOUSE_POSITION | BUTTON_ALT | BUTTON_CTRL | BUTTON_SHIFT
01207             | BUTTON_PRESSED
01208             | BUTTON_RELEASED
01209             | BUTTON_CLICKED
01210             | BUTTON1_DOUBLE_CLICKED | BUTTON1_TRIPLE_CLICKED
01211             | BUTTON2_DOUBLE_CLICKED | BUTTON2_TRIPLE_CLICKED
01212             | BUTTON3_DOUBLE_CLICKED | BUTTON3_TRIPLE_CLICKED);
01213 
01214        mouse_activate(eventmask != 0);
01215 
01216        result = eventmask;
01217     }
01218 
01219     returnBits(result);
01220 }
01221 
01222 NCURSES_EXPORT(bool)
01223 wenclose(const WINDOW *win, int y, int x)
01224 /* check to see if given window encloses given screen location */
01225 {
01226     bool result = FALSE;
01227 
01228     T((T_CALLED("wenclose(%p,%d,%d)"), win, y, x));
01229 
01230     if (win != 0) {
01231        y -= win->_yoffset;
01232        result = ((win->_begy <= y &&
01233                  win->_begx <= x &&
01234                  (win->_begx + win->_maxx) >= x &&
01235                  (win->_begy + win->_maxy) >= y) ? TRUE : FALSE);
01236     }
01237     returnBool(result);
01238 }
01239 
01240 NCURSES_EXPORT(int)
01241 mouseinterval(int maxclick)
01242 /* set the maximum mouse interval within which to recognize a click */
01243 {
01244     int oldval;
01245 
01246     T((T_CALLED("mouseinterval(%d)"), maxclick));
01247 
01248     if (SP != 0) {
01249        oldval = SP->_maxclick;
01250        if (maxclick >= 0)
01251            SP->_maxclick = maxclick;
01252     } else {
01253        oldval = DEFAULT_MAXCLICK;
01254     }
01255 
01256     returnCode(oldval);
01257 }
01258 
01259 /* This may be used by other routines to ask for the existence of mouse
01260    support */
01261 NCURSES_EXPORT(int)
01262 _nc_has_mouse(void)
01263 {
01264     return (SP->_mouse_type == M_NONE ? 0 : 1);
01265 }
01266 
01267 NCURSES_EXPORT(bool)
01268 wmouse_trafo(const WINDOW *win, int *pY, int *pX, bool to_screen)
01269 {
01270     bool result = FALSE;
01271 
01272     T((T_CALLED("wmouse_trafo(%p,%p,%p,%d)"), win, pY, pX, to_screen));
01273 
01274     if (win && pY && pX) {
01275        int y = *pY;
01276        int x = *pX;
01277 
01278        if (to_screen) {
01279            y += win->_begy + win->_yoffset;
01280            x += win->_begx;
01281            if (wenclose(win, y, x))
01282               result = TRUE;
01283        } else {
01284            if (wenclose(win, y, x)) {
01285               y -= (win->_begy + win->_yoffset);
01286               x -= win->_begx;
01287               result = TRUE;
01288            }
01289        }
01290        if (result) {
01291            *pX = x;
01292            *pY = y;
01293        }
01294     }
01295     returnBool(result);
01296 }