X-Git-Url: http://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=ncurses%2Fbase%2Flib_mouse.c;h=350eaa7b8c7bf49d4fb629a7d359ec55fe93a971;hp=aace7deb4c7fc7a334d15a169cc6a5198bdf2195;hb=f3eb40315f9e5eff503a172aed6d325b4e1f20c6;hpb=e6c7286022d8a7a7ea7f15a6ffa7f9addb00e42d diff --git a/ncurses/base/lib_mouse.c b/ncurses/base/lib_mouse.c index aace7deb..350eaa7b 100644 --- a/ncurses/base/lib_mouse.c +++ b/ncurses/base/lib_mouse.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2006,2007 Free Software Foundation, Inc. * + * Copyright (c) 1998-2010,2011 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -30,6 +30,7 @@ * Author: Zeyd M. Ben-Halim 1992,1995 * * and: Eric S. Raymond * * and: Thomas E. Dickey 1996-on * + * and: Juergen Pfeifer 2008 * ****************************************************************************/ /* @@ -79,9 +80,12 @@ #include -MODULE_ID("$Id: lib_mouse.c,v 1.88 2007/09/29 21:50:04 tom Exp $") +#ifndef CUR +#define CUR SP_TERMTYPE +#endif + +MODULE_ID("$Id: lib_mouse.c,v 1.129 2011/09/17 21:52:30 tom Exp $") -#include #include #if USE_GPM_SUPPORT @@ -118,12 +122,12 @@ make an error #define MY_TRACE TRACE_ICALLS|TRACE_IEVENT -#define MASK_RELEASE(x) NCURSES_MOUSE_MASK(x, 001) -#define MASK_PRESS(x) NCURSES_MOUSE_MASK(x, 002) -#define MASK_CLICK(x) NCURSES_MOUSE_MASK(x, 004) -#define MASK_DOUBLE_CLICK(x) NCURSES_MOUSE_MASK(x, 010) -#define MASK_TRIPLE_CLICK(x) NCURSES_MOUSE_MASK(x, 020) -#define MASK_RESERVED_EVENT(x) NCURSES_MOUSE_MASK(x, 040) +#define MASK_RELEASE(x) (mmask_t) NCURSES_MOUSE_MASK(x, 001) +#define MASK_PRESS(x) (mmask_t) NCURSES_MOUSE_MASK(x, 002) +#define MASK_CLICK(x) (mmask_t) NCURSES_MOUSE_MASK(x, 004) +#define MASK_DOUBLE_CLICK(x) (mmask_t) NCURSES_MOUSE_MASK(x, 010) +#define MASK_TRIPLE_CLICK(x) (mmask_t) NCURSES_MOUSE_MASK(x, 020) +#define MASK_RESERVED_EVENT(x) (mmask_t) NCURSES_MOUSE_MASK(x, 040) #if NCURSES_MOUSE_VERSION == 1 #define BUTTON_CLICKED (BUTTON1_CLICKED | BUTTON2_CLICKED | BUTTON3_CLICKED | BUTTON4_CLICKED) @@ -150,38 +154,47 @@ make an error #define LIBGPM_SONAME "libgpm.so" #endif -#define GET_DLSYM(name) (my_##name = (TYPE_##name) dlsym(obj, #name)) +#define GET_DLSYM(name) (my_##name = (TYPE_##name) dlsym(sp->_dlopen_gpm, #name)) #endif /* USE_GPM_SUPPORT */ -static bool _nc_mouse_parse(int); +static bool _nc_mouse_parse(SCREEN *, int); static void _nc_mouse_resume(SCREEN *); static void _nc_mouse_wrap(SCREEN *); /* maintain a circular list of mouse events */ +#define FirstEV(sp) ((sp)->_mouse_events) +#define LastEV(sp) ((sp)->_mouse_events + EV_MAX - 1) + #undef NEXT -#define NEXT(ep) ((ep == SP->_mouse_events + EV_MAX - 1) \ - ? SP->_mouse_events \ +#define NEXT(ep) ((ep >= LastEV(SP_PARM)) \ + ? FirstEV(SP_PARM) \ : ep + 1) #undef PREV -#define PREV(ep) ((ep == SP->_mouse_events) \ - ? SP->_mouse_events + EV_MAX - 1 \ +#define PREV(ep) ((ep <= FirstEV(SP_PARM)) \ + ? LastEV(SP_PARM) \ : ep - 1) +#define IndexEV(sp, ep) (ep - FirstEV(sp)) + +#define RunParams(sp, eventp, runp) \ + (long) IndexEV(sp, runp), \ + (long) (IndexEV(sp, eventp) + (EV_MAX - 1)) % EV_MAX + #ifdef TRACE static void -_trace_slot(const char *tag) +_trace_slot(SCREEN *sp, const char *tag) { MEVENT *ep; - _tracef(tag); + _tracef("%s", tag); - for (ep = SP->_mouse_events; ep < SP->_mouse_events + EV_MAX; ep++) + for (ep = FirstEV(sp); ep <= LastEV(sp); ep++) _tracef("mouse event queue slot %ld = %s", - (long) (ep - SP->_mouse_events), - _tracemouse(ep)); + (long) IndexEV(sp, ep), + _nc_tracemouse(sp, ep)); } #endif @@ -193,7 +206,7 @@ _trace_slot(const char *tag) # define M_FD(sp) sp->_mouse_fd static void -write_event(int down, int button, int x, int y) +write_event(SCREEN *sp, int down, int button, int x, int y) { char buf[6]; unsigned long ignore; @@ -202,12 +215,13 @@ write_event(int down, int button, int x, int y) buf[3] = ' ' + (button - 1) + (down ? 0 : 0x40); buf[4] = ' ' + x - LEFT_COL + 1; buf[5] = ' ' + y - TOP_ROW + 1; - DosWrite(SP->_emxmouse_wfd, buf, 6, &ignore); + DosWrite(sp->_emxmouse_wfd, buf, 6, &ignore); } static void -mouse_server(unsigned long ignored GCC_UNUSED) +mouse_server(unsigned long param) { + SCREEN *sp = (SCREEN *) param; unsigned short fWait = MOU_WAIT; /* NOPTRRECT mourt = { 0,0,24,79 }; */ MOUEVENTINFO mouev; @@ -234,7 +248,7 @@ mouse_server(unsigned long ignored GCC_UNUSED) sprintf(err, "Error reading mouse queue, rc=%lu.\r\n", rc); break; } - if (!SP->_emxmouse_activated) + if (!sp->_emxmouse_activated) goto finish; /* @@ -245,14 +259,14 @@ mouse_server(unsigned long ignored GCC_UNUSED) * 3 = middle. */ if ((mouev.fs ^ oldstate) & MOUSE_BN1_DOWN) - write_event(mouev.fs & MOUSE_BN1_DOWN, - SP->_emxmouse_buttons[1], mouev.col, mouev.row); + write_event(sp, mouev.fs & MOUSE_BN1_DOWN, + sp->_emxmouse_buttons[1], mouev.col, mouev.row); if ((mouev.fs ^ oldstate) & MOUSE_BN2_DOWN) - write_event(mouev.fs & MOUSE_BN2_DOWN, - SP->_emxmouse_buttons[3], mouev.col, mouev.row); + write_event(sp, mouev.fs & MOUSE_BN2_DOWN, + sp->_emxmouse_buttons[3], mouev.col, mouev.row); if ((mouev.fs ^ oldstate) & MOUSE_BN3_DOWN) - write_event(mouev.fs & MOUSE_BN3_DOWN, - SP->_emxmouse_buttons[2], mouev.col, mouev.row); + write_event(sp, mouev.fs & MOUSE_BN3_DOWN, + sp->_emxmouse_buttons[2], mouev.col, mouev.row); finish: oldstate = mouev.fs; @@ -271,167 +285,235 @@ mouse_server(unsigned long ignored GCC_UNUSED) #if USE_SYSMOUSE static void -handle_sysmouse(int sig GCC_UNUSED) +sysmouse_server(SCREEN *sp) { struct mouse_info the_mouse; MEVENT *work; the_mouse.operation = MOUSE_GETINFO; - if (SP != 0 - && SP->_mouse_fd >= 0 - && SP->_sysmouse_tail < FIFO_SIZE - && ioctl(SP->_mouse_fd, CONS_MOUSECTL, &the_mouse) != -1) { - - if (SP->_sysmouse_head > SP->_sysmouse_tail) { - SP->_sysmouse_tail = 0; - SP->_sysmouse_head = 0; + if (sp != 0 + && sp->_mouse_fd >= 0 + && sp->_sysmouse_tail < FIFO_SIZE + && ioctl(sp->_mouse_fd, CONS_MOUSECTL, &the_mouse) != -1) { + + if (sp->_sysmouse_head > sp->_sysmouse_tail) { + sp->_sysmouse_tail = 0; + sp->_sysmouse_head = 0; } - work = &(SP->_sysmouse_fifo[SP->_sysmouse_tail]); + work = &(sp->_sysmouse_fifo[sp->_sysmouse_tail]); memset(work, 0, sizeof(*work)); work->id = NORMAL_EVENT; /* there's only one mouse... */ - SP->_sysmouse_old_buttons = SP->_sysmouse_new_buttons; - SP->_sysmouse_new_buttons = the_mouse.u.data.buttons & 0x7; + sp->_sysmouse_old_buttons = sp->_sysmouse_new_buttons; + sp->_sysmouse_new_buttons = the_mouse.u.data.buttons & 0x7; - if (SP->_sysmouse_new_buttons) { - if (SP->_sysmouse_new_buttons & 1) + if (sp->_sysmouse_new_buttons) { + if (sp->_sysmouse_new_buttons & 1) work->bstate |= BUTTON1_PRESSED; - if (SP->_sysmouse_new_buttons & 2) + if (sp->_sysmouse_new_buttons & 2) work->bstate |= BUTTON2_PRESSED; - if (SP->_sysmouse_new_buttons & 4) + if (sp->_sysmouse_new_buttons & 4) work->bstate |= BUTTON3_PRESSED; } else { - if (SP->_sysmouse_old_buttons & 1) + if (sp->_sysmouse_old_buttons & 1) work->bstate |= BUTTON1_RELEASED; - if (SP->_sysmouse_old_buttons & 2) + if (sp->_sysmouse_old_buttons & 2) work->bstate |= BUTTON2_RELEASED; - if (SP->_sysmouse_old_buttons & 4) + if (sp->_sysmouse_old_buttons & 4) work->bstate |= BUTTON3_RELEASED; } /* for cosmetic bug in syscons.c on FreeBSD 3.[34] */ the_mouse.operation = MOUSE_HIDE; - ioctl(SP->_mouse_fd, CONS_MOUSECTL, &the_mouse); + ioctl(sp->_mouse_fd, CONS_MOUSECTL, &the_mouse); the_mouse.operation = MOUSE_SHOW; - ioctl(SP->_mouse_fd, CONS_MOUSECTL, &the_mouse); + ioctl(sp->_mouse_fd, CONS_MOUSECTL, &the_mouse); /* * We're only interested if the button is pressed or released. * FIXME: implement continuous event-tracking. */ - if (SP->_sysmouse_new_buttons != SP->_sysmouse_old_buttons) { - SP->_sysmouse_tail += 1; + if (sp->_sysmouse_new_buttons != sp->_sysmouse_old_buttons) { + sp->_sysmouse_tail += 1; } - work->x = the_mouse.u.data.x / SP->_sysmouse_char_width; - work->y = the_mouse.u.data.y / SP->_sysmouse_char_height; + work->x = the_mouse.u.data.x / sp->_sysmouse_char_width; + work->y = the_mouse.u.data.y / sp->_sysmouse_char_height; } } + +static void +handle_sysmouse(int sig GCC_UNUSED) +{ + sysmouse_server(CURRENT_SCREEN); +} #endif /* USE_SYSMOUSE */ +#ifndef USE_TERM_DRIVER +#define xterm_kmous "\033[M" + static void -init_xterm_mouse(void) +init_xterm_mouse(SCREEN *sp) { - SP->_mouse_type = M_XTERM; - SP->_mouse_xtermcap = tigetstr("XM"); - if (!VALID_STRING(SP->_mouse_xtermcap)) - SP->_mouse_xtermcap = "\033[?1000%?%p1%{1}%=%th%el%;"; + sp->_mouse_type = M_XTERM; + sp->_mouse_xtermcap = tigetstr("XM"); + if (!VALID_STRING(sp->_mouse_xtermcap)) + sp->_mouse_xtermcap = "\033[?1000%?%p1%{1}%=%th%el%;"; } +#endif static void -enable_xterm_mouse(int enable) +enable_xterm_mouse(SCREEN *sp, int enable) { #if USE_EMX_MOUSE - SP->_emxmouse_activated = enable; + sp->_emxmouse_activated = enable; #else - putp(TPARM_1(SP->_mouse_xtermcap, enable)); + NCURSES_SP_NAME(_nc_putp) (NCURSES_SP_ARGx + "xterm-mouse", + TPARM_1(sp->_mouse_xtermcap, enable)); #endif - SP->_mouse_active = enable; + sp->_mouse_active = enable; } #if USE_GPM_SUPPORT -static int +static bool allow_gpm_mouse(void) { + bool result = FALSE; + /* GPM does printf's without checking if stdout is a terminal */ if (isatty(fileno(stdout))) { + char *list = getenv("NCURSES_GPM_TERMS"); char *env = getenv("TERM"); - /* GPM checks the beginning of the $TERM variable to decide if - * it should pass xterm events through. There is no real advantage - * in allowing GPM to do this. - */ - if (env == 0 || strncmp(env, "xterm", 5)) - return TRUE; + if (list != 0) { + if (env != 0) { + result = _nc_name_match(list, env, "|:"); + } + } else { + /* GPM checks the beginning of the $TERM variable to decide if it + * should pass xterm events through. There is no real advantage in + * allowing GPM to do this. Recent versions relax that check, and + * pretend that GPM can work with any terminal having the kmous + * capability. Perhaps that works for someone. If so, they can + * set the environment variable (above). + */ + if (env != 0 && strstr(env, "linux") != 0) { + result = TRUE; + } + } + } + return result; +} + +#ifdef HAVE_LIBDL +static void +unload_gpm_library(SCREEN *sp) +{ + if (sp->_dlopen_gpm != 0) { + T(("unload GPM library")); + sp->_mouse_gpm_loaded = FALSE; + sp->_mouse_fd = -1; + dlclose(sp->_dlopen_gpm); + sp->_dlopen_gpm = 0; + } +} + +static void +load_gpm_library(SCREEN *sp) +{ + sp->_mouse_gpm_found = FALSE; + if ((sp->_dlopen_gpm = dlopen(LIBGPM_SONAME, my_RTLD)) != 0) { + if (GET_DLSYM(gpm_fd) == 0 || + GET_DLSYM(Gpm_Open) == 0 || + GET_DLSYM(Gpm_Close) == 0 || + GET_DLSYM(Gpm_GetEvent) == 0) { + T(("GPM initialization failed: %s", dlerror())); + unload_gpm_library(sp); + } else { + sp->_mouse_gpm_found = TRUE; + sp->_mouse_gpm_loaded = TRUE; + } } - return FALSE; } +#endif static bool -enable_gpm_mouse(int enable) +enable_gpm_mouse(SCREEN *sp, bool enable) { bool result; T((T_CALLED("enable_gpm_mouse(%d)"), enable)); - if (enable && !SP->_mouse_active) { - /* GPM: initialize connection to gpm server */ - SP->_mouse_gpm_connect.eventMask = GPM_DOWN | GPM_UP; - SP->_mouse_gpm_connect.defaultMask = - ~(SP->_mouse_gpm_connect.eventMask | GPM_HARD); - SP->_mouse_gpm_connect.minMod = 0; - SP->_mouse_gpm_connect.maxMod = - (unsigned short) (~((1 << KG_SHIFT) | - (1 << KG_SHIFTL) | - (1 << KG_SHIFTR))); - /* - * Note: GPM hardcodes \E[?1001s and \E[?1000h during its open. - * The former is recognized by wscons (SunOS), and the latter by - * xterm. Those will not show up in ncurses' traces. - */ - result = (my_Gpm_Open(&SP->_mouse_gpm_connect, 0) >= 0); - SP->_mouse_active = result; + if (enable && !sp->_mouse_active) { +#ifdef HAVE_LIBDL + if (sp->_mouse_gpm_found && !sp->_mouse_gpm_loaded) { + load_gpm_library(sp); + } +#endif + if (sp->_mouse_gpm_loaded) { + int code; + + /* GPM: initialize connection to gpm server */ + sp->_mouse_gpm_connect.eventMask = GPM_DOWN | GPM_UP; + sp->_mouse_gpm_connect.defaultMask = + (unsigned short) (~(sp->_mouse_gpm_connect.eventMask | GPM_HARD)); + sp->_mouse_gpm_connect.minMod = 0; + sp->_mouse_gpm_connect.maxMod = + (unsigned short) (~((1 << KG_SHIFT) | + (1 << KG_SHIFTL) | + (1 << KG_SHIFTR))); + /* + * Note: GPM hardcodes \E[?1001s and \E[?1000h during its open. + * The former is recognized by wscons (SunOS), and the latter by + * xterm. Those will not show up in ncurses' traces. + */ + code = my_Gpm_Open(&sp->_mouse_gpm_connect, 0); + result = (code >= 0); + + /* + * GPM can return a -2 if it is trying to do something with xterm. + * Ignore that, since it conflicts with our use of stdin. + */ + if (code == -2) { + my_Gpm_Close(); + } + } else { + result = FALSE; + } + sp->_mouse_active = result; T(("GPM open %s", result ? "succeeded" : "failed")); } else { - if (!enable && SP->_mouse_active) { + if (!enable && sp->_mouse_active) { /* GPM: close connection to gpm server */ my_Gpm_Close(); - SP->_mouse_active = FALSE; + sp->_mouse_active = FALSE; T(("GPM closed")); } - result = FALSE; + result = enable; } +#ifdef HAVE_LIBDL + if (!result) { + unload_gpm_library(sp); + } +#endif returnBool(result); } #endif /* USE_GPM_SUPPORT */ -#define xterm_kmous "\033[M" - static void -initialize_mousetype(void) +initialize_mousetype(SCREEN *sp) { T((T_CALLED("initialize_mousetype()"))); /* Try gpm first, because gpm may be configured to run in xterm */ #if USE_GPM_SUPPORT if (allow_gpm_mouse()) { - if (!SP->_mouse_gpm_loaded) { + if (!sp->_mouse_gpm_loaded) { #ifdef HAVE_LIBDL - void *obj; - - if ((obj = dlopen(LIBGPM_SONAME, my_RTLD)) != 0) { - if (GET_DLSYM(gpm_fd) == 0 || - GET_DLSYM(Gpm_Open) == 0 || - GET_DLSYM(Gpm_Close) == 0 || - GET_DLSYM(Gpm_GetEvent) == 0) { - T(("GPM initialization failed: %s", dlerror())); - dlclose(obj); - } else { - SP->_mouse_gpm_found = TRUE; - } - } + load_gpm_library(sp); #else /* !HAVE_LIBDL */ - SP->_mouse_gpm_found = TRUE; + sp->_mouse_gpm_found = TRUE; + sp->_mouse_gpm_loaded = TRUE; #endif - SP->_mouse_gpm_loaded = TRUE; } /* @@ -439,10 +521,10 @@ initialize_mousetype(void) * maintain our notion of whether the mouse connection is active * without testing the file-descriptor. */ - if (SP->_mouse_gpm_found && enable_gpm_mouse(TRUE)) { - SP->_mouse_type = M_GPM; - SP->_mouse_fd = *(my_gpm_fd); - T(("GPM mouse_fd %d", SP->_mouse_fd)); + if (sp->_mouse_gpm_found && enable_gpm_mouse(sp, TRUE)) { + sp->_mouse_type = M_GPM; + sp->_mouse_fd = *(my_gpm_fd); + T(("GPM mouse_fd %d", sp->_mouse_fd)); returnVoid; } } @@ -450,8 +532,8 @@ initialize_mousetype(void) /* OS/2 VIO */ #if USE_EMX_MOUSE - if (!SP->_emxmouse_thread - && strstr(cur_term->type.term_names, "xterm") == 0 + if (!sp->_emxmouse_thread + && strstr(TerminalOf(sp)->type.term_names, "xterm") == 0 && key_mouse) { int handles[2]; @@ -461,32 +543,32 @@ initialize_mousetype(void) } else { int rc; - if (!SP->_emxmouse_buttons[0]) { + if (!sp->_emxmouse_buttons[0]) { char *s = getenv("MOUSE_BUTTONS_123"); - SP->_emxmouse_buttons[0] = 1; + sp->_emxmouse_buttons[0] = 1; if (s && strlen(s) >= 3) { - SP->_emxmouse_buttons[1] = s[0] - '0'; - SP->_emxmouse_buttons[2] = s[1] - '0'; - SP->_emxmouse_buttons[3] = s[2] - '0'; + sp->_emxmouse_buttons[1] = s[0] - '0'; + sp->_emxmouse_buttons[2] = s[1] - '0'; + sp->_emxmouse_buttons[3] = s[2] - '0'; } else { - SP->_emxmouse_buttons[1] = 1; - SP->_emxmouse_buttons[2] = 3; - SP->_emxmouse_buttons[3] = 2; + sp->_emxmouse_buttons[1] = 1; + sp->_emxmouse_buttons[2] = 3; + sp->_emxmouse_buttons[3] = 2; } } - SP->_emxmouse_wfd = handles[1]; - M_FD(SP) = handles[0]; + sp->_emxmouse_wfd = handles[1]; + M_FD(sp) = handles[0]; /* Needed? */ setmode(handles[0], O_BINARY); setmode(handles[1], O_BINARY); /* Do not use CRT functions, we may single-threaded. */ - rc = DosCreateThread((unsigned long *) &SP->_emxmouse_thread, - mouse_server, 0, 0, 8192); + rc = DosCreateThread((unsigned long *) &sp->_emxmouse_thread, + mouse_server, (long) sp, 0, 8192); if (rc) { printf("mouse thread error %d=%#x", rc, rc); } else { - SP->_mouse_type = M_XTERM; + sp->_mouse_type = M_XTERM; } returnVoid; } @@ -498,14 +580,14 @@ initialize_mousetype(void) struct mouse_info the_mouse; char *the_device = 0; - if (isatty(SP->_ifd)) - the_device = ttyname(SP->_ifd); + if (isatty(sp->_ifd)) + the_device = ttyname(sp->_ifd); if (the_device == 0) the_device = "/dev/tty"; - SP->_mouse_fd = open(the_device, O_RDWR); + sp->_mouse_fd = open(the_device, O_RDWR); - if (SP->_mouse_fd >= 0) { + if (sp->_mouse_fd >= 0) { /* * sysmouse does not have a usable user interface for obtaining * mouse events. The logical way to proceed (reading data on a @@ -522,10 +604,10 @@ initialize_mousetype(void) the_mouse.operation = MOUSE_MODE; the_mouse.u.mode.mode = 0; the_mouse.u.mode.signal = SIGUSR2; - if (ioctl(SP->_mouse_fd, CONS_MOUSECTL, &the_mouse) != -1) { + if (ioctl(sp->_mouse_fd, CONS_MOUSECTL, &the_mouse) != -1) { signal(SIGUSR2, handle_sysmouse); the_mouse.operation = MOUSE_SHOW; - ioctl(SP->_mouse_fd, CONS_MOUSECTL, &the_mouse); + ioctl(sp->_mouse_fd, CONS_MOUSECTL, &the_mouse); #if defined(FBIO_MODEINFO) || defined(CONS_MODEINFO) /* FreeBSD > 2.x */ { @@ -535,64 +617,69 @@ initialize_mousetype(void) #endif /* FBIO_GETMODE */ video_info_t the_video; - if (ioctl(SP->_mouse_fd, + if (ioctl(sp->_mouse_fd, FBIO_GETMODE, &the_video.vi_mode) != -1 - && ioctl(SP->_mouse_fd, + && ioctl(sp->_mouse_fd, FBIO_MODEINFO, &the_video) != -1) { - SP->_sysmouse_char_width = the_video.vi_cwidth; - SP->_sysmouse_char_height = the_video.vi_cheight; + sp->_sysmouse_char_width = the_video.vi_cwidth; + sp->_sysmouse_char_height = the_video.vi_cheight; } } #endif /* defined(FBIO_MODEINFO) || defined(CONS_MODEINFO) */ - if (SP->_sysmouse_char_width <= 0) - SP->_sysmouse_char_width = 8; - if (SP->_sysmouse_char_height <= 0) - SP->_sysmouse_char_height = 16; - SP->_mouse_type = M_SYSMOUSE; + if (sp->_sysmouse_char_width <= 0) + sp->_sysmouse_char_width = 8; + if (sp->_sysmouse_char_height <= 0) + sp->_sysmouse_char_height = 16; + sp->_mouse_type = M_SYSMOUSE; returnVoid; } } } #endif /* USE_SYSMOUSE */ +#ifdef USE_TERM_DRIVER + CallDriver(sp, initmouse); +#else /* we know how to recognize mouse events under "xterm" */ if (key_mouse != 0) { if (!strcmp(key_mouse, xterm_kmous) - || strstr(cur_term->type.term_names, "xterm") != 0) { - init_xterm_mouse(); + || strstr(TerminalOf(sp)->type.term_names, "xterm") != 0) { + init_xterm_mouse(sp); } - } else if (strstr(cur_term->type.term_names, "xterm") != 0) { - if (_nc_add_to_try(&(SP->_keytry), xterm_kmous, KEY_MOUSE) == OK) - init_xterm_mouse(); + } else if (strstr(TerminalOf(sp)->type.term_names, "xterm") != 0) { + if (_nc_add_to_try(&(sp->_keytry), xterm_kmous, KEY_MOUSE) == OK) + init_xterm_mouse(sp); } +#endif + returnVoid; } static bool -_nc_mouse_init(void) +_nc_mouse_init(SCREEN *sp) /* initialize the mouse */ { bool result = FALSE; int i; - if (SP != 0) { - if (!SP->_mouse_initialized) { - SP->_mouse_initialized = TRUE; + if (sp != 0) { + if (!sp->_mouse_initialized) { + sp->_mouse_initialized = TRUE; TR(MY_TRACE, ("_nc_mouse_init() called")); - SP->_mouse_eventp = SP->_mouse_events; + sp->_mouse_eventp = FirstEV(sp); for (i = 0; i < EV_MAX; i++) - SP->_mouse_events[i].id = INVALID_EVENT; + sp->_mouse_events[i].id = INVALID_EVENT; - initialize_mousetype(); + initialize_mousetype(sp); - T(("_nc_mouse_init() set mousetype to %d", SP->_mouse_type)); + T(("_nc_mouse_init() set mousetype to %d", sp->_mouse_type)); } - result = SP->_mouse_initialized; + result = sp->_mouse_initialized; } return result; } @@ -602,14 +689,14 @@ _nc_mouse_init(void) * fifo_push() in lib_getch.c */ static bool -_nc_mouse_event(SCREEN *sp GCC_UNUSED) +_nc_mouse_event(SCREEN *sp) { - MEVENT *eventp = SP->_mouse_eventp; + MEVENT *eventp = sp->_mouse_eventp; bool result = FALSE; (void) eventp; - switch (SP->_mouse_type) { + switch (sp->_mouse_type) { case M_XTERM: /* xterm: never have to query, mouse events are in the keyboard stream */ #if USE_EMX_MOUSE @@ -631,11 +718,16 @@ _nc_mouse_event(SCREEN *sp GCC_UNUSED) #if USE_GPM_SUPPORT case M_GPM: - { + if (sp->_mouse_fd >= 0) { /* query server for event, return TRUE if we find one */ Gpm_Event ev; - if (my_Gpm_GetEvent(&ev) == 1) { + switch (my_Gpm_GetEvent(&ev)) { + case 0: + /* Connection closed, drop the mouse. */ + sp->_mouse_fd = -1; + break; + case 1: /* there's only one mouse... */ eventp->id = NORMAL_EVENT; @@ -658,6 +750,7 @@ _nc_mouse_event(SCREEN *sp GCC_UNUSED) eventp->bstate |= BUTTON3_RELEASED; break; default: + eventp->bstate |= REPORT_MOUSE_POSITION; break; } @@ -666,8 +759,9 @@ _nc_mouse_event(SCREEN *sp GCC_UNUSED) eventp->z = 0; /* bump the next-free pointer into the circular list */ - SP->_mouse_eventp = eventp = NEXT(eventp); + sp->_mouse_eventp = NEXT(eventp); result = TRUE; + break; } } break; @@ -675,27 +769,49 @@ _nc_mouse_event(SCREEN *sp GCC_UNUSED) #if USE_SYSMOUSE case M_SYSMOUSE: - if (SP->_sysmouse_head < SP->_sysmouse_tail) { - *eventp = SP->_sysmouse_fifo[SP->_sysmouse_head]; + if (sp->_sysmouse_head < sp->_sysmouse_tail) { + *eventp = sp->_sysmouse_fifo[sp->_sysmouse_head]; /* * Point the fifo-head to the next possible location. If there * are none, reset the indices. This may be interrupted by the * signal handler, doing essentially the same reset. */ - SP->_sysmouse_head += 1; - if (SP->_sysmouse_head == SP->_sysmouse_tail) { - SP->_sysmouse_tail = 0; - SP->_sysmouse_head = 0; + sp->_sysmouse_head += 1; + if (sp->_sysmouse_head == sp->_sysmouse_tail) { + sp->_sysmouse_tail = 0; + sp->_sysmouse_head = 0; } /* bump the next-free pointer into the circular list */ - SP->_mouse_eventp = eventp = NEXT(eventp); + sp->_mouse_eventp = eventp = NEXT(eventp); result = TRUE; } break; #endif /* USE_SYSMOUSE */ +#ifdef USE_TERM_DRIVER + case M_TERM_DRIVER: + while (sp->_drv_mouse_head < sp->_drv_mouse_tail) { + *eventp = sp->_drv_mouse_fifo[sp->_drv_mouse_head]; + + /* + * Point the fifo-head to the next possible location. If there + * are none, reset the indices. + */ + sp->_drv_mouse_head += 1; + if (sp->_drv_mouse_head == sp->_drv_mouse_tail) { + sp->_drv_mouse_tail = 0; + sp->_drv_mouse_head = 0; + } + + /* bump the next-free pointer into the circular list */ + sp->_mouse_eventp = eventp = NEXT(eventp); + result = TRUE; + } + break; +#endif + case M_NONE: break; } @@ -709,13 +825,12 @@ _nc_mouse_inline(SCREEN *sp) { int b; bool result = FALSE; - MEVENT *eventp = SP->_mouse_eventp; + MEVENT *eventp = sp->_mouse_eventp; TR(MY_TRACE, ("_nc_mouse_inline() called")); - if (SP->_mouse_type == M_XTERM) { + if (sp->_mouse_type == M_XTERM) { unsigned char kbuf[4]; - mmask_t prev; size_t grabbed; int res; @@ -751,17 +866,26 @@ _nc_mouse_inline(SCREEN *sp) * Wheel mice may return buttons 4 and 5 when the wheel is turned. * We encode those as button presses. */ - for (grabbed = 0; grabbed < 3; grabbed += res) { +# if USE_PTHREADS_EINTR +# if USE_WEAK_SYMBOLS + if ((pthread_self) && (pthread_kill) && (pthread_equal)) +# endif + _nc_globals.read_thread = pthread_self(); +# endif + for (grabbed = 0; grabbed < 3; grabbed += (size_t) res) { /* For VIO mouse we add extra bit 64 to disambiguate button-up. */ #if USE_EMX_MOUSE - res = read(M_FD(sp) >= 0 ? M_FD(sp) : sp->_ifd, &kbuf, 3); + res = (int) read(M_FD(sp) >= 0 ? M_FD(sp) : sp->_ifd, &kbuf, 3); #else - res = read(sp->_ifd, kbuf + grabbed, 3 - grabbed); + res = (int) read(sp->_ifd, kbuf + grabbed, 3 - grabbed); #endif if (res == -1) break; } +#if USE_PTHREADS_EINTR + _nc_globals.read_thread = 0; +#endif kbuf[3] = '\0'; TR(TRACE_IEVENT, @@ -772,35 +896,51 @@ _nc_mouse_inline(SCREEN *sp) /* processing code goes here */ eventp->bstate = 0; - prev = PREV(eventp)->bstate; #if USE_EMX_MOUSE #define PRESS_POSITION(n) \ - eventp->bstate = MASK_PRESS(n); \ - if (kbuf[0] & 0x40) \ - eventp->bstate = MASK_RELEASE(n) + do { \ + eventp->bstate = MASK_PRESS(n); \ + sp->_mouse_bstate |= MASK_PRESS(n); \ + if (kbuf[0] & 0x40) { \ + eventp->bstate = MASK_RELEASE(n); \ + sp->_mouse_bstate &= ~MASK_PRESS(n); \ + } \ + } while (0) #else #define PRESS_POSITION(n) \ - eventp->bstate = (prev & MASK_PRESS(n) \ - ? REPORT_MOUSE_POSITION \ - : MASK_PRESS(n)) + do { \ + eventp->bstate = (mmask_t) (sp->_mouse_bstate & MASK_PRESS(n) \ + ? REPORT_MOUSE_POSITION \ + : MASK_PRESS(n)); \ + sp->_mouse_bstate |= MASK_PRESS(n); \ + } while (0) #endif switch (kbuf[0] & 0x3) { case 0x0: - if (kbuf[0] & 64) + if ((kbuf[0] & 96) == 96) { eventp->bstate = MASK_PRESS(4); - else + /* Do not record in sp->_mouse_bstate; there will be no + * corresponding release event. + */ + } else { PRESS_POSITION(1); + } break; case 0x1: + if ((kbuf[0] & 96) == 96) { #if NCURSES_MOUSE_VERSION == 2 - if (kbuf[0] & 64) eventp->bstate = MASK_PRESS(5); - else + /* See comment above for button 4 */ +#else + /* Ignore this event as it is not a true press of the button */ + eventp->bstate = REPORT_MOUSE_POSITION; #endif + } else { PRESS_POSITION(2); + } break; case 0x2: @@ -815,12 +955,13 @@ _nc_mouse_inline(SCREEN *sp) * release, we can infer the button actually released by looking at * the previous event. */ - if (prev & (BUTTON_PRESSED | BUTTON_RELEASED)) { + if (sp->_mouse_bstate & BUTTON_PRESSED) { eventp->bstate = BUTTON_RELEASED; for (b = 1; b <= MAX_BUTTONS; ++b) { - if (!(prev & MASK_PRESS(b))) + if (!(sp->_mouse_bstate & MASK_PRESS(b))) eventp->bstate &= ~MASK_RELEASE(b); } + sp->_mouse_bstate = 0; } else { /* * XFree86 xterm will return a stream of release-events to @@ -847,11 +988,11 @@ _nc_mouse_inline(SCREEN *sp) eventp->y = (kbuf[2] - ' ') - 1; TR(MY_TRACE, ("_nc_mouse_inline: primitive mouse-event %s has slot %ld", - _tracemouse(eventp), - (long) (eventp - SP->_mouse_events))); + _nc_tracemouse(sp, eventp), + (long) IndexEV(sp, eventp))); /* bump the next-free pointer into the circular list */ - SP->_mouse_eventp = NEXT(eventp); + sp->_mouse_eventp = NEXT(eventp); #if 0 /* this return would be needed for QNX's mods to lib_getch.c */ return (TRUE); #endif @@ -861,36 +1002,41 @@ _nc_mouse_inline(SCREEN *sp) } static void -mouse_activate(bool on) +mouse_activate(SCREEN *sp, bool on) { - if (!on && !SP->_mouse_initialized) + if (!on && !sp->_mouse_initialized) return; - if (!_nc_mouse_init()) + if (!_nc_mouse_init(sp)) return; if (on) { - - switch (SP->_mouse_type) { + sp->_mouse_bstate = 0; + switch (sp->_mouse_type) { case M_XTERM: #if NCURSES_EXT_FUNCS - keyok(KEY_MOUSE, on); + NCURSES_SP_NAME(keyok) (NCURSES_SP_ARGx KEY_MOUSE, on); #endif TPUTS_TRACE("xterm mouse initialization"); - enable_xterm_mouse(1); + enable_xterm_mouse(sp, 1); break; #if USE_GPM_SUPPORT case M_GPM: - if (enable_gpm_mouse(1)) { - SP->_mouse_fd = *(my_gpm_fd); - T(("GPM mouse_fd %d", SP->_mouse_fd)); + if (enable_gpm_mouse(sp, TRUE)) { + sp->_mouse_fd = *(my_gpm_fd); + T(("GPM mouse_fd %d", sp->_mouse_fd)); } break; #endif #if USE_SYSMOUSE case M_SYSMOUSE: signal(SIGUSR2, handle_sysmouse); - SP->_mouse_active = TRUE; + sp->_mouse_active = TRUE; + break; +#endif +#ifdef USE_TERM_DRIVER + case M_TERM_DRIVER: + sp->_mouse_active = TRUE; break; #endif case M_NONE: @@ -899,34 +1045,39 @@ mouse_activate(bool on) /* Make runtime binding to cut down on object size of applications that * do not use the mouse (e.g., 'clear'). */ - SP->_mouse_event = _nc_mouse_event; - SP->_mouse_inline = _nc_mouse_inline; - SP->_mouse_parse = _nc_mouse_parse; - SP->_mouse_resume = _nc_mouse_resume; - SP->_mouse_wrap = _nc_mouse_wrap; + sp->_mouse_event = _nc_mouse_event; + sp->_mouse_inline = _nc_mouse_inline; + sp->_mouse_parse = _nc_mouse_parse; + sp->_mouse_resume = _nc_mouse_resume; + sp->_mouse_wrap = _nc_mouse_wrap; } else { - switch (SP->_mouse_type) { + switch (sp->_mouse_type) { case M_XTERM: TPUTS_TRACE("xterm mouse deinitialization"); - enable_xterm_mouse(0); + enable_xterm_mouse(sp, 0); break; #if USE_GPM_SUPPORT case M_GPM: - enable_gpm_mouse(0); + enable_gpm_mouse(sp, FALSE); break; #endif #if USE_SYSMOUSE case M_SYSMOUSE: signal(SIGUSR2, SIG_IGN); - SP->_mouse_active = FALSE; + sp->_mouse_active = FALSE; + break; +#endif +#ifdef USE_TERM_DRIVER + case M_TERM_DRIVER: + sp->_mouse_active = FALSE; break; #endif case M_NONE: return; } } - _nc_flush(); + NCURSES_SP_NAME(_nc_flush) (NCURSES_SP_ARG); } /************************************************************************** @@ -936,14 +1087,17 @@ mouse_activate(bool on) **************************************************************************/ static bool -_nc_mouse_parse(int runcount) +_nc_mouse_parse(SCREEN *sp, int runcount) /* parse a run of atomic mouse events into a gesture */ { - MEVENT *eventp = SP->_mouse_eventp; - MEVENT *ep, *runp, *next, *prev = PREV(eventp); + MEVENT *eventp = sp->_mouse_eventp; + MEVENT *next, *ep; + MEVENT *first_valid = NULL; + MEVENT *first_invalid = NULL; int n; int b; bool merge; + bool endLoop; TR(MY_TRACE, ("_nc_mouse_parse(%d) called", runcount)); @@ -960,7 +1114,8 @@ _nc_mouse_parse(int runcount) * * It's possible that the run may not resolve to a single event (for * example, if the user quadruple-clicks). If so, leading events - * in the run are ignored. + * in the run are ignored if user does not call getmouse in a loop (getting + * them from newest to older). * * Note that this routine is independent of the format of the specific * format of the pointing-device's reports. We can use it to parse @@ -968,81 +1123,109 @@ _nc_mouse_parse(int runcount) * button basis, as long as the device-dependent mouse code puts stuff * on the queue in MEVENT format. */ - if (runcount == 1) { - TR(MY_TRACE, - ("_nc_mouse_parse: returning simple mouse event %s at slot %ld", - _tracemouse(prev), - (long) (prev - SP->_mouse_events))); - return (prev->id >= NORMAL_EVENT) - ? ((prev->bstate & SP->_mouse_mask) ? TRUE : FALSE) - : FALSE; - } - /* find the start of the run */ - runp = eventp; - for (n = runcount; n > 0; n--) { - runp = PREV(runp); + /* + * Reset all events that were not set, in case the user sometimes calls + * getmouse only once and other times until there are no more events in + * queue. + * + * This also allows reaching the beginning of the run. + */ + ep = eventp; + for (n = runcount; n < EV_MAX; n++) { + ep->id = INVALID_EVENT; + ep = NEXT(ep); } #ifdef TRACE if (USE_TRACEF(TRACE_IEVENT)) { - _trace_slot("before mouse press/release merge:"); + _trace_slot(sp, "before mouse press/release merge:"); _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", - (long) (runp - SP->_mouse_events), - (long) ((eventp - SP->_mouse_events) + (EV_MAX - 1)) % EV_MAX, + RunParams(sp, eventp, ep), runcount); _nc_unlock_global(tracef); } #endif /* TRACE */ /* first pass; merge press/release pairs */ - do { - merge = FALSE; - for (ep = runp; (next = NEXT(ep)) != eventp; ep = next) { + endLoop = FALSE; + while (!endLoop) { + next = NEXT(ep); + if (next == eventp) { + /* Will end the loop, but compact before */ + endLoop = TRUE; + } else { #define MASK_CHANGED(x) (!(ep->bstate & MASK_PRESS(x)) \ == !(next->bstate & MASK_RELEASE(x))) - if (ep->x == next->x && ep->y == next->y + if (ep->id != INVALID_EVENT && next->id != INVALID_EVENT + && ep->x == next->x && ep->y == next->y && (ep->bstate & BUTTON_PRESSED) - && MASK_CHANGED(1) - && MASK_CHANGED(2) - && MASK_CHANGED(3) - && MASK_CHANGED(4) -#if NCURSES_MOUSE_VERSION == 2 - && MASK_CHANGED(5) -#endif - ) { + && (!(next->bstate & BUTTON_PRESSED))) { + bool changed = TRUE; + for (b = 1; b <= MAX_BUTTONS; ++b) { - if ((SP->_mouse_mask & MASK_CLICK(b)) - && (ep->bstate & MASK_PRESS(b))) { - ep->bstate &= ~MASK_PRESS(b); - ep->bstate |= MASK_CLICK(b); - merge = TRUE; + if (!MASK_CHANGED(b)) { + changed = FALSE; + break; } } - if (merge) - next->id = INVALID_EVENT; + + if (changed) { + merge = FALSE; + for (b = 1; b <= MAX_BUTTONS; ++b) { + if ((sp->_mouse_mask & MASK_CLICK(b)) + && (ep->bstate & MASK_PRESS(b))) { + next->bstate &= ~MASK_RELEASE(b); + next->bstate |= MASK_CLICK(b); + merge = TRUE; + } + } + if (merge) + ep->id = INVALID_EVENT; + } } } - } while - (merge); + /* Compact valid events */ + if (ep->id == INVALID_EVENT) { + if ((first_valid != NULL) && (first_invalid == NULL)) { + first_invalid = ep; + } + } else { + if (first_valid == NULL) { + first_valid = ep; + } else if (first_invalid != NULL) { + *first_invalid = *ep; + ep->id = INVALID_EVENT; + first_invalid = NEXT(first_invalid); + } + } + + ep = next; + } + + if (first_invalid != NULL) { + eventp = first_invalid; + } #ifdef TRACE if (USE_TRACEF(TRACE_IEVENT)) { - _trace_slot("before mouse click merge:"); - _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", - (long) (runp - SP->_mouse_events), - (long) ((eventp - SP->_mouse_events) + (EV_MAX - 1)) % EV_MAX, - runcount); - _nc_unlock_global(tracef); + _trace_slot(sp, "before mouse click merge:"); + if (first_valid == NULL) { + _tracef("_nc_mouse_parse: no valid event"); + } else { + _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", + RunParams(sp, eventp, first_valid), + runcount); + _nc_unlock_global(tracef); + } } #endif /* TRACE */ /* - * Second pass; merge click runs. At this point, click events are - * each followed by one invalid event. We merge click events - * forward in the queue. + * Second pass; merge click runs. We merge click events forward in the + * queue. For example, double click can be changed to triple click. * * NOTE: There is a problem with this design! If the application * allows enough click events to pile up in the circular queue so @@ -1055,112 +1238,126 @@ _nc_mouse_parse(int runcount) * but the timer element would have to have sub-second resolution, * which would get us into portability trouble. */ - do { - MEVENT *follower; - - merge = FALSE; - for (ep = runp; (next = NEXT(ep)) != eventp; ep = next) - if (ep->id != INVALID_EVENT) { - if (next->id != INVALID_EVENT) - continue; - follower = NEXT(next); - if (follower->id == INVALID_EVENT) - continue; - - /* merge click events forward */ - if ((ep->bstate & BUTTON_CLICKED) - && (follower->bstate & BUTTON_CLICKED)) { - for (b = 1; b <= MAX_BUTTONS; ++b) { - if ((SP->_mouse_mask & MASK_DOUBLE_CLICK(b)) - && (follower->bstate & MASK_CLICK(b))) { - follower->bstate &= ~MASK_CLICK(b); - follower->bstate |= MASK_DOUBLE_CLICK(b); - merge = TRUE; - } + first_invalid = NULL; + endLoop = (first_valid == NULL); + ep = first_valid; + while (!endLoop) { + next = NEXT(ep); + + if (next == eventp) { + /* Will end the loop, but check event type and compact before */ + endLoop = true; + } else { + /* merge click events forward */ + if ((ep->bstate & BUTTON_CLICKED) + && (next->bstate & BUTTON_CLICKED)) { + merge = FALSE; + for (b = 1; b <= MAX_BUTTONS; ++b) { + if ((sp->_mouse_mask & MASK_DOUBLE_CLICK(b)) + && (ep->bstate & MASK_CLICK(b)) + && (next->bstate & MASK_CLICK(b))) { + next->bstate &= ~MASK_CLICK(b); + next->bstate |= MASK_DOUBLE_CLICK(b); + merge = TRUE; } - if (merge) - ep->id = INVALID_EVENT; } + if (merge) + ep->id = INVALID_EVENT; + } - /* merge double-click events forward */ - if ((ep->bstate & BUTTON_DOUBLE_CLICKED) - && (follower->bstate & BUTTON_CLICKED)) { - for (b = 1; b <= MAX_BUTTONS; ++b) { - if ((SP->_mouse_mask & MASK_TRIPLE_CLICK(b)) - && (follower->bstate & MASK_CLICK(b))) { - follower->bstate &= ~MASK_CLICK(b); - follower->bstate |= MASK_TRIPLE_CLICK(b); - merge = TRUE; - } + /* merge double-click events forward */ + if ((ep->bstate & BUTTON_DOUBLE_CLICKED) + && (next->bstate & BUTTON_CLICKED)) { + merge = FALSE; + for (b = 1; b <= MAX_BUTTONS; ++b) { + if ((sp->_mouse_mask & MASK_TRIPLE_CLICK(b)) + && (ep->bstate & MASK_DOUBLE_CLICK(b)) + && (next->bstate & MASK_CLICK(b))) { + next->bstate &= ~MASK_CLICK(b); + next->bstate |= MASK_TRIPLE_CLICK(b); + merge = TRUE; } - if (merge) - ep->id = INVALID_EVENT; } + if (merge) + ep->id = INVALID_EVENT; } - } while - (merge); + } -#ifdef TRACE - if (USE_TRACEF(TRACE_IEVENT)) { - _trace_slot("before mouse event queue compaction:"); - _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", - (long) (runp - SP->_mouse_events), - (long) ((eventp - SP->_mouse_events) + (EV_MAX - 1)) % EV_MAX, - runcount); - _nc_unlock_global(tracef); - } -#endif /* TRACE */ + /* Discard event if it does not match event mask */ + if (!(ep->bstate & sp->_mouse_mask)) { + ep->id = INVALID_EVENT; + } - /* - * Now try to throw away trailing events flagged invalid, or that - * don't match the current event mask. - */ - for (; runcount; prev = PREV(eventp), runcount--) - if (prev->id == INVALID_EVENT || !(prev->bstate & SP->_mouse_mask)) { - SP->_mouse_eventp = eventp = prev; + /* Compact valid events */ + if (ep->id == INVALID_EVENT) { + if (ep == first_valid) { + first_valid = next; + } else if (first_invalid == NULL) { + first_invalid = ep; + } + } else if (first_invalid != NULL) { + *first_invalid = *ep; + ep->id = INVALID_EVENT; + first_invalid = NEXT(first_invalid); } + + ep = next; + } + + if (first_invalid == NULL) { + first_invalid = eventp; + } + sp->_mouse_eventp = first_invalid; + #ifdef TRACE - if (USE_TRACEF(TRACE_IEVENT)) { - _trace_slot("after mouse event queue compaction:"); - _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", - (long) (runp - SP->_mouse_events), - (long) ((eventp - SP->_mouse_events) + (EV_MAX - 1)) % EV_MAX, - runcount); - _nc_unlock_global(tracef); + if (first_valid != NULL) { + if (USE_TRACEF(TRACE_IEVENT)) { + _trace_slot(sp, "after mouse event queue compaction:"); + _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", + RunParams(sp, first_invalid, first_valid), + runcount); + _nc_unlock_global(tracef); + } + for (ep = first_valid; ep != first_invalid; ep = NEXT(ep)) { + if (ep->id != INVALID_EVENT) + TR(MY_TRACE, + ("_nc_mouse_parse: returning composite mouse event %s at slot %ld", + _nc_tracemouse(sp, ep), + (long) IndexEV(sp, ep))); + } } - for (ep = runp; ep != eventp; ep = NEXT(ep)) - if (ep->id != INVALID_EVENT) - TR(MY_TRACE, - ("_nc_mouse_parse: returning composite mouse event %s at slot %ld", - _tracemouse(ep), - (long) (ep - SP->_mouse_events))); #endif /* TRACE */ /* after all this, do we have a valid event? */ - return (PREV(eventp)->id != INVALID_EVENT); + return (PREV(first_invalid)->id != INVALID_EVENT); } static void -_nc_mouse_wrap(SCREEN *sp GCC_UNUSED) +_nc_mouse_wrap(SCREEN *sp) /* release mouse -- called by endwin() before shellout/exit */ { TR(MY_TRACE, ("_nc_mouse_wrap() called")); - switch (SP->_mouse_type) { + switch (sp->_mouse_type) { case M_XTERM: - if (SP->_mouse_mask) - mouse_activate(FALSE); + if (sp->_mouse_mask) + mouse_activate(sp, FALSE); break; #if USE_GPM_SUPPORT /* GPM: pass all mouse events to next client */ case M_GPM: - if (SP->_mouse_mask) - mouse_activate(FALSE); + if (sp->_mouse_mask) + mouse_activate(sp, FALSE); break; #endif #if USE_SYSMOUSE case M_SYSMOUSE: - mouse_activate(FALSE); + mouse_activate(sp, FALSE); + break; +#endif +#ifdef USE_TERM_DRIVER + case M_TERM_DRIVER: + mouse_activate(sp, FALSE); break; #endif case M_NONE: @@ -1169,31 +1366,38 @@ _nc_mouse_wrap(SCREEN *sp GCC_UNUSED) } static void -_nc_mouse_resume(SCREEN *sp GCC_UNUSED) +_nc_mouse_resume(SCREEN *sp) /* re-connect to mouse -- called by doupdate() after shellout */ { TR(MY_TRACE, ("_nc_mouse_resume() called")); - switch (SP->_mouse_type) { + switch (sp->_mouse_type) { case M_XTERM: /* xterm: re-enable reporting */ - if (SP->_mouse_mask) - mouse_activate(TRUE); + if (sp->_mouse_mask) + mouse_activate(sp, TRUE); break; #if USE_GPM_SUPPORT case M_GPM: /* GPM: reclaim our event set */ - if (SP->_mouse_mask) - mouse_activate(TRUE); + if (sp->_mouse_mask) + mouse_activate(sp, TRUE); break; #endif #if USE_SYSMOUSE case M_SYSMOUSE: - mouse_activate(TRUE); + mouse_activate(sp, TRUE); break; #endif + +#ifdef USE_TERM_DRIVER + case M_TERM_DRIVER: + mouse_activate(sp, TRUE); + break; +#endif + case M_NONE: break; } @@ -1206,67 +1410,107 @@ _nc_mouse_resume(SCREEN *sp GCC_UNUSED) **************************************************************************/ NCURSES_EXPORT(int) -getmouse(MEVENT * aevent) -/* grab a copy of the current mouse event */ +NCURSES_SP_NAME(getmouse) (NCURSES_SP_DCLx MEVENT * aevent) { - T((T_CALLED("getmouse(%p)"), aevent)); + int result = ERR; + + T((T_CALLED("getmouse(%p,%p)"), (void *) SP_PARM, (void *) aevent)); - if ((aevent != 0) && (SP != 0) && (SP->_mouse_type != M_NONE)) { - MEVENT *eventp = SP->_mouse_eventp; + if ((aevent != 0) && (SP_PARM != 0) && (SP_PARM->_mouse_type != M_NONE)) { + MEVENT *eventp = SP_PARM->_mouse_eventp; /* compute the current-event pointer */ MEVENT *prev = PREV(eventp); - /* copy the event we find there */ - *aevent = *prev; + /* + * Discard events not matching mask (there could be still some if + * _nc_mouse_parse was not called, e.g., when _nc_mouse_inline returns + * false). + */ + while ((prev->id != INVALID_EVENT) && (!(prev->bstate & SP_PARM->_mouse_mask))) { + prev->id = INVALID_EVENT; + prev = PREV(prev); + } + if (prev->id != INVALID_EVENT) { + /* copy the event we find there */ + *aevent = *prev; - TR(TRACE_IEVENT, ("getmouse: returning event %s from slot %ld", - _tracemouse(prev), - (long) (prev - SP->_mouse_events))); + TR(TRACE_IEVENT, ("getmouse: returning event %s from slot %ld", + _nc_tracemouse(SP_PARM, prev), + (long) IndexEV(SP_PARM, prev))); - prev->id = INVALID_EVENT; /* so the queue slot becomes free */ - returnCode(OK); + prev->id = INVALID_EVENT; /* so the queue slot becomes free */ + SP_PARM->_mouse_eventp = prev; + result = OK; + } else { + /* Reset the provided event */ + aevent->bstate = 0; + aevent->id = INVALID_EVENT; + aevent->x = 0; + aevent->y = 0; + aevent->z = 0; + } } - returnCode(ERR); + returnCode(result); } +#if NCURSES_SP_FUNCS +/* grab a copy of the current mouse event */ NCURSES_EXPORT(int) -ungetmouse(MEVENT * aevent) -/* enqueue a synthesized mouse event to be seen by the next wgetch() */ +getmouse(MEVENT * aevent) +{ + return NCURSES_SP_NAME(getmouse) (CURRENT_SCREEN, aevent); +} +#endif + +NCURSES_EXPORT(int) +NCURSES_SP_NAME(ungetmouse) (NCURSES_SP_DCLx MEVENT * aevent) { int result = ERR; - T((T_CALLED("ungetmouse(%p)"), aevent)); + T((T_CALLED("ungetmouse(%p,%p)"), (void *) SP_PARM, (void *) aevent)); - if (aevent != 0 && SP != 0) { - MEVENT *eventp = SP->_mouse_eventp; + if (aevent != 0 && SP_PARM != 0) { + MEVENT *eventp = SP_PARM->_mouse_eventp; /* stick the given event in the next-free slot */ *eventp = *aevent; /* bump the next-free pointer into the circular list */ - SP->_mouse_eventp = NEXT(eventp); + SP_PARM->_mouse_eventp = NEXT(eventp); /* push back the notification event on the keyboard queue */ - result = ungetch(KEY_MOUSE); + result = NCURSES_SP_NAME(ungetch) (NCURSES_SP_ARGx KEY_MOUSE); } returnCode(result); } +#if NCURSES_SP_FUNCS +/* enqueue a synthesized mouse event to be seen by the next wgetch() */ +NCURSES_EXPORT(int) +ungetmouse(MEVENT * aevent) +{ + return NCURSES_SP_NAME(ungetmouse) (CURRENT_SCREEN, aevent); +} +#endif + NCURSES_EXPORT(mmask_t) -mousemask(mmask_t newmask, mmask_t * oldmask) +NCURSES_SP_NAME(mousemask) (NCURSES_SP_DCLx mmask_t newmask, mmask_t * oldmask) /* set the mouse event mask */ { mmask_t result = 0; - T((T_CALLED("mousemask(%#lx,%p)"), (unsigned long) newmask, oldmask)); + T((T_CALLED("mousemask(%p,%#lx,%p)"), + (void *) SP_PARM, + (unsigned long) newmask, + (void *) oldmask)); - if (SP != 0) { + if (SP_PARM != 0) { if (oldmask) - *oldmask = SP->_mouse_mask; + *oldmask = SP_PARM->_mouse_mask; - if (newmask || SP->_mouse_initialized) { - _nc_mouse_init(); - if (SP->_mouse_type != M_NONE) { + if (newmask || SP_PARM->_mouse_initialized) { + _nc_mouse_init(SP_PARM); + if (SP_PARM->_mouse_type != M_NONE) { result = newmask & (REPORT_MOUSE_POSITION | BUTTON_ALT @@ -1278,17 +1522,22 @@ mousemask(mmask_t newmask, mmask_t * oldmask) | BUTTON_DOUBLE_CLICKED | BUTTON_TRIPLE_CLICKED); - mouse_activate((bool) (result != 0)); + mouse_activate(SP_PARM, (bool) (result != 0)); - SP->_mouse_mask = result; + SP_PARM->_mouse_mask = result; } } - } else { - if (oldmask) - *oldmask = SP->_mouse_mask; } - returnBits(result); + returnMMask(result); +} + +#if NCURSES_SP_FUNCS +NCURSES_EXPORT(mmask_t) +mousemask(mmask_t newmask, mmask_t * oldmask) +{ + return NCURSES_SP_NAME(mousemask) (CURRENT_SCREEN, newmask, oldmask); } +#endif NCURSES_EXPORT(bool) wenclose(const WINDOW *win, int y, int x) @@ -1296,7 +1545,7 @@ wenclose(const WINDOW *win, int y, int x) { bool result = FALSE; - T((T_CALLED("wenclose(%p,%d,%d)"), win, y, x)); + T((T_CALLED("wenclose(%p,%d,%d)"), (const void *) win, y, x)); if (win != 0) { y -= win->_yoffset; @@ -1309,17 +1558,17 @@ wenclose(const WINDOW *win, int y, int x) } NCURSES_EXPORT(int) -mouseinterval(int maxclick) +NCURSES_SP_NAME(mouseinterval) (NCURSES_SP_DCLx int maxclick) /* set the maximum mouse interval within which to recognize a click */ { int oldval; - T((T_CALLED("mouseinterval(%d)"), maxclick)); + T((T_CALLED("mouseinterval(%p,%d)"), (void *) SP_PARM, maxclick)); - if (SP != 0) { - oldval = SP->_maxclick; + if (SP_PARM != 0) { + oldval = SP_PARM->_maxclick; if (maxclick >= 0) - SP->_maxclick = maxclick; + SP_PARM->_maxclick = maxclick; } else { oldval = DEFAULT_MAXCLICK; } @@ -1327,20 +1576,46 @@ mouseinterval(int maxclick) returnCode(oldval); } +#if NCURSES_SP_FUNCS +NCURSES_EXPORT(int) +mouseinterval(int maxclick) +{ + return NCURSES_SP_NAME(mouseinterval) (CURRENT_SCREEN, maxclick); +} +#endif + /* This may be used by other routines to ask for the existence of mouse support */ -NCURSES_EXPORT(int) -_nc_has_mouse(void) +NCURSES_EXPORT(bool) +_nc_has_mouse(SCREEN *sp) { - return (SP->_mouse_type == M_NONE ? 0 : 1); + return (((0 == sp) || (sp->_mouse_type == M_NONE)) ? FALSE : TRUE); } +NCURSES_EXPORT(bool) +NCURSES_SP_NAME(has_mouse) (NCURSES_SP_DCL0) +{ + return _nc_has_mouse(SP_PARM); +} + +#if NCURSES_SP_FUNCS +NCURSES_EXPORT(bool) +has_mouse(void) +{ + return _nc_has_mouse(CURRENT_SCREEN); +} +#endif + NCURSES_EXPORT(bool) wmouse_trafo(const WINDOW *win, int *pY, int *pX, bool to_screen) { bool result = FALSE; - T((T_CALLED("wmouse_trafo(%p,%p,%p,%d)"), win, pY, pX, to_screen)); + T((T_CALLED("wmouse_trafo(%p,%p,%p,%d)"), + (const void *) win, + (void *) pY, + (void *) pX, + to_screen)); if (win && pY && pX) { int y = *pY;