/* * mouse.c - mouse support for cdialog * * Copyright 1994 rubini@ipvvis.unipv.it (Alessandro Rubini) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ********/ #include "dialog.h" #include static Gpm_Connect connectInfo; static Gpm_Handler mouse_handler; static int basex, basey; typedef struct Region { int x, y, X, Y, code; struct Region *next; } Region; static Region *regionList = NULL; static struct bigRegion { int x, y, X, Y; int height, nitems; int xth; int step, mode; } bigRegion; /* have a static one */ static int bigregionFlag = 0; /* no bigRegion at startup */ /*==================== simple functions =============*/ void mouse_open (void) { gpm_zerobased = gpm_visiblepointer = 1; connectInfo.eventMask = ~0; connectInfo.defaultMask = GPM_MOVE & GPM_HARD; connectInfo.minMod = connectInfo.maxMod = 0; Gpm_Open (&connectInfo, 0); gpm_handler = mouse_handler; } void mouse_close (void) { Gpm_Close (); } void mouse_setbase (int x, int y) { basex = x; basey = y; } /*=========== region related functions =============*/ void mouse_mkbigregion (int y, int x, int height, int width, int nitems, int th, int mode) { bigRegion.x = basex + x; bigRegion.X = basex + x + width; bigRegion.y = basey + y; bigRegion.Y = basey + y + height; bigRegion.height = height - 3; bigRegion.nitems = nitems; bigRegion.xth = basex + th; bigRegion.step = nitems > height ? nitems / height : 1; if (mode == 2) /* text box */ bigRegion.step = height - 3; bigRegion.mode = mode; bigregionFlag++; } void mouse_mkregion (int y, int x, int height, int width, int code) { Region *butPtr; butPtr = malloc (sizeof (Region)); if (!butPtr) return; /* WARN */ butPtr->y = basey + y; butPtr->Y = basey + y + height; butPtr->x = basex + x; butPtr->X = basex + x + width; butPtr->code = code; butPtr->next = regionList; regionList = butPtr; } /*=================================================== the mouse handler ====*/ #include /* select(); */ #include /* timeval */ /* * This is the mouse handler. * It generates integer numbers, to simulate keys */ int mouse_handler (Gpm_Event * event, void *unused) { static Region *prevPtr; Region *butPtr; static int grabkey = 0; static int reptkey = 0; static int dragging = 0; static int prevY; static int prevMouseDown; /* xterm gives only generic up events */ #define CURRENT_POS (M_EVENT+event->y-bigRegion.y-1) #if 0 fprintf (stderr, "grab %i, more %i, drag %i, x %i, y %i, butt %i, type %x\n", grabkey, gpm_morekeys, dragging, event->x, event->y, event->buttons, event->type); #endif if (grabkey) { /* return key or 0 */ if (Gpm_Repeat (100)) return grabkey; /* go on (slow to ease xterm( */ else return grabkey = gpm_morekeys = 0; /* no more grab */ } if (gpm_morekeys) { /* repeat a key */ gpm_morekeys--; return reptkey; } if (dragging) { /* respond to motions, independently of where they are */ int delta; if (!(event->type & GPM_DRAG)) { dragging--; return CURRENT_POS; } delta = event->y - prevY; if (!delta) return 0; prevY = event->y; reptkey = (delta > 0 ? KEY_DOWN : KEY_UP); gpm_morekeys = bigRegion.step * abs (delta); return (reptkey == KEY_UP ? M_EVENT : M_EVENT + bigRegion.height); } /* the big region */ if (bigregionFlag && event->y >= bigRegion.y && event->y < bigRegion.Y && event->x >= bigRegion.x && event->x < bigRegion.X) { /* top border */ if (event->y == bigRegion.y) { if ((event->type & GPM_DOWN) && (event->buttons & GPM_B_LEFT)) { grabkey = KEY_UP; gpm_morekeys = 1; return KEY_UP; } else return 0; } /* bottom border */ if (event->y + 1 == bigRegion.Y) { if ((event->type & GPM_DOWN) && (event->buttons & GPM_B_LEFT)) { grabkey = KEY_DOWN; gpm_morekeys = 1; return KEY_DOWN; } else return 0; } /* right half */ reptkey = 0; if (event->x > bigRegion.xth) { if (event->type & GPM_DOWN) switch (event->buttons) { case GPM_B_LEFT: reptkey = KEY_DOWN - KEY_UP; /* FALLTHRU */ case GPM_B_RIGHT: reptkey += KEY_UP; gpm_morekeys = event->y - bigRegion.y; return (reptkey == KEY_UP ? M_EVENT : M_EVENT + bigRegion.height); case GPM_B_MIDDLE: prevY = event->y; dragging++; return 0; } return CURRENT_POS; } /* left half */ else { /* WARN *//* check down events as well */ if ((event->type & GPM_UP) && (event->buttons & GPM_B_LEFT)) { if (event->type & GPM_SINGLE) { reptkey = ' '; gpm_morekeys = (bigRegion.mode == 0); return M_EVENT + 'o'; } return '\n'; } return CURRENT_POS; } } /* smaller regions */ /* retrieve the frame under the pointer */ for (butPtr = regionList; butPtr; butPtr = butPtr->next) { if (event->y < butPtr->y || event->y >= butPtr->Y) continue; if (event->x < butPtr->x || event->x >= butPtr->X) continue; break; /* found */ } switch (GPM_BARE_EVENTS (event->type)) { case GPM_MOVE: if (butPtr && butPtr != prevPtr) { /* enter event */ prevPtr = butPtr; return M_EVENT + butPtr->code; } break; case GPM_DRAG: if (butPtr && butPtr != prevPtr) /* enter event (with button) */ return M_EVENT + butPtr->code; break; case GPM_DOWN: /* down: remember where */ prevPtr = butPtr; prevMouseDown = event->buttons; /* to handle xterm b-up event */ break; case GPM_UP: /* WARN multiple presses are bad-behaving */ switch (prevMouseDown) { /* event->buttons doesn't run with xterm */ case GPM_B_RIGHT: return '\n'; case GPM_B_MIDDLE: return '\t'; case GPM_B_LEFT: if (butPtr && butPtr == prevPtr) { /* complete button press *//* return two keys... */ gpm_morekeys++; reptkey = butPtr->code; return M_EVENT + toupper (butPtr->code); } prevPtr = butPtr; return M_EVENT + butPtr->code; /* no, only an enter event */ } } return 0; /* nothing relevant */ }