csope/source/mouse.c
2023-09-26 09:29:23 +02:00

428 lines
11 KiB
C

/*===========================================================================
Copyright (c) 1998-2000, The Santa Cruz Operation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
*Neither name of The Santa Cruz Operation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT falseT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT falseT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
=========================================================================*/
/* cscope - interactive C symbol cross-reference
*
* mouse functions
*/
extern int LINES;
#define FLDLINE (LINES - FIELDS - 1 - 1) /* first input field line */
#include "global.h"
bool mouse = false; /* mouse interface */
#ifdef UNIXPC /* build command requires #ifdef instead of #if */
# include <sys/window.h>
bool unixpcmouse = false; /* running with a mouse on the Unix PC? */
static int uw_hs, uw_vs; /* character height and width */
#endif
typedef struct { /* menu */
char *text;
char *value;
} MENU;
static MENU mainmenu[] = {
/* main menu */
{"Send", "##\033s##\r"},
{"Repeat", "\031" },
{"Edit All", "\05" },
{"Rebuild", "\022" },
{"Shell", "!" },
{"Redraw", "\f" },
{"Help", "?" },
{"Exit", "\04" },
{NULL, NULL }
};
static MENU changemenu[] = {
/* change mode menu */
{"Mark Screen", "*" },
{"Mark All", "a" },
{"Change", "\04" },
{"No Change", "\033"},
{"Shell", "!" },
{"Redraw", "\f" },
{"Help", "?" },
{NULL, NULL }
};
static MENU *loaded; /* menu loaded */
static bool emacsviterm = false; /* terminal type */
static void loadmenu(MENU *menu);
static int getcoordinate(void);
static int getpercent(void);
/* see if there is a mouse interface */
void mouseinit(void) {
char *term;
/* see if this is emacsterm or viterm */
term = mygetenv("TERM", "");
if(strcmp(term, "emacsterm") == 0 || strcmp(term, "viterm") == 0) {
emacsviterm = true;
mouse = true;
}
/* the MOUSE enviroment variable is for 5620 terminal programs that have
mouse support but the TERM environment variable is the same as a
terminal without a mouse, such as myx */
else if(strcmp(mygetenv("MOUSE", ""), "myx") == 0) {
mouse = true;
}
#if UNIXPC
else if(strcmp(term, "s4") == 0 || strcmp(term, "s120") == 0 ||
strcmp(term, "s90") == 0) {
int retval;
struct uwdata uwd; /* Window data structure */
struct umdata umd; /* Mouse data structure */
/* Ask for character size info */
retval = ioctl(1, WIOCGETD, &uwd);
if(retval || uwd.uw_hs <= 0 || uwd.uw_vs <= 0) {
/**************************************************
* something wrong with the kernel, so fake it...
**************************************************/
if(!strcmp(term, "s4")) {
uw_hs = 9;
uw_vs = 12;
} else {
uw_hs = 6;
uw_vs = 10;
}
} else {
/* Kernel is working and knows about this font */
uw_hs = uwd.uw_hs;
uw_vs = uwd.uw_vs;
}
/**************************************************
* Now turn on mouse reporting so we can actually
* make use of all this stuff.
**************************************************/
if((retval = ioctl(1, WIOCGETMOUSE, &umd)) != -1) {
umd.um_flags = MSDOWN + MSUP;
ioctl(1, WIOCSETMOUSE, &umd);
}
unixpcmouse = true;
}
#endif
if(mouse == true) { loadmenu(mainmenu); }
}
/* load the correct mouse menu */
void mousemenu(void) {
if(mouse == true) {
if(input_mode == INPUT_CHANGE) {
loadmenu(changemenu);
} else {
loadmenu(mainmenu);
}
}
}
/* download a menu */
static void loadmenu(MENU *menu) {
int i;
if(emacsviterm == true) {
mousereinit();
(void)printf("\033V1"); /* display the scrollbar */
(void)printf("\033M0@%s@%s@", menu[0].text, menu[0].value);
for(i = 1; menu[i].text != NULL; ++i) {
(void)printf("\033M@%s@%s@", menu[i].text, menu[i].value);
}
} else { /* myx */
int len;
mousecleanup();
(void)printf("\033[6;1X\033[9;1X");
for(i = 0; menu[i].text != NULL; ++i) {
len = strlen(menu[i].text);
(void)printf("\033[%d;%dx%s%s",
len,
(int)(len + strlen(menu[i].value)),
menu[i].text,
menu[i].value);
}
loaded = menu;
}
(void)fflush(stdout);
}
/* reinitialize the mouse in case curses changed the attributes */
void mousereinit(void) {
if(emacsviterm == true) {
/* enable the mouse click and sweep coordinate control sequence */
/* and switch to menu 2 */
(void)printf("\033{2\033#2");
(void)fflush(stdout);
}
}
/* restore the mouse attributes */
void mousecleanup(void) {
int i;
if(loaded != NULL) { /* only true for myx */
/* remove the mouse menu */
(void)printf("\033[6;0X\033[9;0X");
for(i = 0; loaded[i].text != NULL; ++i) {
(void)printf("\033[0;0x");
}
loaded = NULL;
}
}
/* draw the scrollbar */
void drawscrollbar(int top, int bot) {
int p1, p2;
if(emacsviterm == true) {
if(bot > top) {
p1 = 16 + (top - 1) * 100 / totallines;
p2 = 16 + (bot - 1) * 100 / totallines;
if(p2 > 116) { p2 = 116; }
if(p1 < 16) { p1 = 16; }
/* don't send ^S or ^Q because it will hang a layer using cu(1) */
if(p1 == ctrl('Q') || p1 == ctrl('S')) { ++p1; }
if(p2 == ctrl('Q') || p2 == ctrl('S')) { ++p2; }
} else {
p1 = p2 = 16;
}
(void)printf("\033W%c%c", p1, p2);
}
}
/* get the mouse information */
MOUSE *getmouseaction(char leading_char) {
static MOUSE m;
#if UNIXPC
if(unixpcmouse == true && leading_char == ESC) {
/* Called if cscope received an ESC character. See if it is
* a mouse report and if so, decipher it. A mouse report
* looks like: "<ESC>[?xx;yy;b;rM"
*/
int x = 0, y = 0, button = 0, reason = 0;
int i;
/* Get a mouse report. The form is: XX;YY;B;RM where
* XX is 1,2, or 3 decimal digits with the X pixel position.
* Similarly for YY. B is a single decimal digit with the
* button number (4 for one, 2 for two, and 1 for three).
* R is the reason for the mouse report.
*
* In general, the input is read until the mouse report has
* been completely read in or we have discovered that this
* escape sequence is falseT a mouse report. In the latter case
* return the last character read to the input stream with
* myungetch().
*/
/* Check for "[?" being next 2 chars */
if(((i = getch()) != '[') || ((i = getch()) != '?')) {
myungetch(i);
return (NULL);
}
/* Grab the X position (in pixels) */
while(isdigit(i = getch())) {
x = (x * 10) + (i - '0');
}
if(i != ';') {
myungetch(i);
return (NULL); /* not a mouse report after all */
}
/* Grab the Y position (in pixels) */
while(isdigit(i = getch())) {
y = (y * 10) + (i - '0');
}
if(i != ';') {
myungetch(i);
return (NULL);
}
/* Get which button */
if((button = getch()) > '4') {
myungetch(button);
return (NULL);
}
if((i = getch()) != ';') {
myungetch(i);
return (NULL);
}
/* Get the reason for this mouse report */
if((reason = getch()) > '8') {
myungetch(reason);
return (NULL);
}
/* sequence should terminate with an 'M' */
if((i = getch()) != 'M') {
myungetch(i);
return (NULL);
}
/* OK. We get a mouse report whenever a button is depressed
* or released. Let's ignore the report whenever the button
* is depressed until when I am ready to implement sweeping.
*/
if(reason != '2') { return (NULL); /* '2' means button is released */ }
/************************************************************
* Always indicate button 1 irregardless of which button was
* really pushed.
************************************************************/
m.button = 1;
/************************************************************
* Convert pixel coordinates to line and column coords.
* The height and width are obtained using an ioctl() call
* in mouseinit(). This assumes that variable width chars
* are not being used ('though it would probably work anyway).
************************************************************/
m.x1 = x / uw_hs; /* pixel/horizontal_spacing */
m.y1 = y / uw_vs; /* pixel/vertical_spacing */
/* "null" out the other fields */
m.percent = m.x2 = m.y2 = -1;
} else
#endif /* not UNIXPC */
if(mouse == true && leading_char == ctrl('X')) {
switch(getch()) {
case ctrl('_'): /* click */
if((m.button = getch()) == '0') { /* if scrollbar */
m.percent = getpercent();
} else {
m.x1 = getcoordinate();
m.y1 = getcoordinate();
m.x2 = m.y2 = -1;
}
break;
case ctrl(']'): /* sweep */
m.button = getch();
m.x1 = getcoordinate();
m.y1 = getcoordinate();
m.x2 = getcoordinate();
m.y2 = getcoordinate();
break;
default:
return (NULL);
}
} else
return (NULL);
return (&m);
}
/* get a row or column coordinate from a mouse button click or sweep */
static int getcoordinate(void) {
int c, next;
c = getch();
next = 0;
if(c == ctrl('A')) {
next = 95;
c = getch();
}
if(c < ' ') { return (0); }
return (next + c - ' ');
}
/* get a percentage */
static int getpercent(void) {
int c;
c = getch();
if(c < 16) { return (0); }
if(c > 120) { return (100); }
return (c - 16);
}
int process_mouse() {
int i;
MOUSE *p;
if((p = getmouseaction(DUMMYCHAR)) == NULL) {
return (false); /* unknown control sequence */
}
/* if the button number is a scrollbar tag */
if(p->button == '0') {
// scrollbar(p); // XXX
return (false);
}
/* ignore a sweep */
if(p->x2 >= 0) { return (false); }
/* if this is a line selection */
if(p->y1 > FLDLINE) {
/* find the selected line */
/* note: the selection is forced into range */
for(i = disprefs - 1; i > 0; --i) {
if(p->y1 >= displine[i]) { return (false); }
}
/* display it in the file with the editor */
editref(i);
} else { /* this is an input field selection */
field = p->y1 - FLDLINE;
/* force it into range */
if(field >= FIELDS) { field = FIELDS - 1; }
return (false);
}
return false;
}