Imported Upstream version 15.8a
[platform/upstream/cscope.git] / src / mouse.c
1 /*===========================================================================
2  Copyright (c) 1998-2000, The Santa Cruz Operation 
3  All rights reserved.
4  
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are met:
7
8  *Redistributions of source code must retain the above copyright notice,
9  this list of conditions and the following disclaimer.
10
11  *Redistributions in binary form must reproduce the above copyright notice,
12  this list of conditions and the following disclaimer in the documentation
13  and/or other materials provided with the distribution.
14
15  *Neither name of The Santa Cruz Operation nor the names of its contributors
16  may be used to endorse or promote products derived from this software
17  without specific prior written permission. 
18
19  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
20  IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
23  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  INTERRUPTION)
27  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
30  DAMAGE. 
31  =========================================================================*/
32
33 /*      cscope - interactive C symbol cross-reference
34  *
35  *      mouse functions
36  */
37
38 #include "global.h"
39
40 BOOL    mouse = NO;                     /* mouse interface */
41
42 #ifdef UNIXPC   /* build command requires #ifdef instead of #if */
43 #include <sys/window.h>
44 BOOL    unixpcmouse = NO;       /* running with a mouse on the Unix PC? */
45 static int uw_hs, uw_vs;        /* character height and width */
46 #endif
47
48 static char const rcsid[] = "$Id: mouse.c,v 1.4 2001/07/05 14:31:00 broeker Exp $";
49
50 typedef struct {                        /* menu */
51         char    *text;
52         char    *value;
53 } MENU;
54
55 static  MENU    mainmenu[] = {          /* main menu */
56         {"Send",        "##\033s##\r"},
57         {"Repeat",      "\031"},
58         {"Edit All",    "\05"},
59         {"Rebuild",     "\022"},
60         {"Shell",       "!"},
61         {"Redraw",      "\f"},
62         {"Help",        "?"},
63         {"Exit",        "\04"},
64         {NULL,          NULL}
65 };
66
67 static  MENU    changemenu[] = {        /* change mode menu */
68         {"Mark Screen", "*"},
69         {"Mark All",    "a"},
70         {"Change",      "\04"},
71         {"No Change",   "\033"},
72         {"Shell",       "!"},
73         {"Redraw",      "\f"},
74         {"Help",        "?"},
75         {NULL,          NULL}
76 };
77
78 static  MENU    *loaded;                /* menu loaded */
79 static  BOOL    emacsviterm = NO;       /* terminal type */
80
81 static  void    loadmenu(MENU *menu);
82 static  int     getcoordinate(void);
83 static  int     getpercent(void);
84
85 /* see if there is a mouse interface */
86
87 void
88 mouseinit(void)
89 {
90         char    *term;
91
92         /* see if this is emacsterm or viterm */
93         term = mygetenv("TERM", "");
94         if (strcmp(term, "emacsterm") == 0 || 
95             strcmp(term, "viterm") == 0) {
96                 emacsviterm = YES;
97                 mouse = YES;
98         }
99         /* the MOUSE enviroment variable is for 5620 terminal programs that have
100            mouse support but the TERM environment variable is the same as a
101            terminal without a mouse, such as myx */
102         else if (strcmp(mygetenv("MOUSE", ""), "myx") == 0) {
103                 mouse = YES;
104         }
105 #if UNIXPC
106         else if (strcmp(term,"s4") == 0 || 
107                  strcmp(term,"s120") == 0 ||
108                  strcmp(term,"s90") == 0) {
109                 int retval;
110                 struct uwdata uwd;      /* Window data structure */
111                 struct umdata umd;      /* Mouse data structure */
112
113                 /* Ask for character size info */
114                         
115                 retval = ioctl(1,WIOCGETD,&uwd);
116                 if(retval || uwd.uw_hs <= 0 || uwd.uw_vs <= 0) {
117                         /**************************************************
118                          * something wrong with the kernel, so fake it... 
119                          **************************************************/
120                         if(!strcmp(term,"s4")) {
121                                 uw_hs = 9;
122                                 uw_vs = 12;
123                         }
124                         else {
125                                 uw_hs = 6;
126                                 uw_vs = 10;
127                         }
128                 }
129                 else {
130                         /* Kernel is working and knows about this font */
131                         uw_hs = uwd.uw_hs;
132                         uw_vs = uwd.uw_vs;
133                 }
134                 
135                 /**************************************************
136                  * Now turn on mouse reporting so we can actually
137                  * make use of all this stuff.
138                  **************************************************/
139                 if((retval = ioctl(1,WIOCGETMOUSE,&umd)) != -1) {
140                         umd.um_flags= MSDOWN+MSUP;
141                         ioctl(1,WIOCSETMOUSE,&umd);
142                 }
143                 unixpcmouse = YES;
144         }
145 #endif
146         if (mouse == YES) {
147                 loadmenu(mainmenu);
148         }
149 }
150
151 /* load the correct mouse menu */
152
153 void
154 mousemenu(void)
155 {
156         if (mouse == YES) {
157                 if (changing == YES) {
158                         loadmenu(changemenu);
159                 }
160                 else {
161                         loadmenu(mainmenu);
162                 }
163         }
164 }
165
166 /* download a menu */
167
168 static void
169 loadmenu(MENU *menu)
170 {
171         int     i;
172
173         if (emacsviterm == YES) {
174                 mousereinit();
175                 (void) printf("\033V1");        /* display the scrollbar */
176                 (void) printf("\033M0@%s@%s@", menu[0].text, menu[0].value);
177                 for (i = 1; menu[i].text != NULL; ++i) {
178                         (void) printf("\033M@%s@%s@", menu[i].text, menu[i].value);
179                 }
180         }
181         else {  /* myx */
182                 int     len;
183                 
184                 mousecleanup();
185                 (void) printf("\033[6;1X\033[9;1X");
186                 for (i = 0; menu[i].text != NULL; ++i) {
187                         len = strlen(menu[i].text);
188                         (void) printf("\033[%d;%dx%s%s", len,
189                                       (int) (len + strlen(menu[i].value)), 
190                                       menu[i].text, menu[i].value);
191                 }
192                 loaded = menu;
193         }
194         (void) fflush(stdout);
195 }
196
197 /* reinitialize the mouse in case curses changed the attributes */
198
199 void
200 mousereinit(void)
201 {
202         if (emacsviterm == YES) {
203
204                 /* enable the mouse click and sweep coordinate control sequence */
205                 /* and switch to menu 2 */
206                 (void) printf("\033{2\033#2");
207                 (void) fflush(stdout);
208         }
209 }
210
211 /* restore the mouse attributes */
212
213 void
214 mousecleanup(void)
215 {
216         int     i;
217
218         if (loaded != NULL) {   /* only true for myx */
219                 
220                 /* remove the mouse menu */
221                 (void) printf("\033[6;0X\033[9;0X");
222                 for (i = 0; loaded[i].text != NULL; ++i) {
223                         (void) printf("\033[0;0x");
224                 }
225                 loaded = NULL;
226         }
227 }
228
229 /* draw the scrollbar */
230
231 void
232 drawscrollbar(int top, int bot)
233 {
234         int p1, p2;
235
236         if (emacsviterm == YES) {
237                 if (bot > top) {
238                         p1 = 16 + (top - 1) * 100 / totallines;
239                         p2 = 16 + (bot - 1) * 100 / totallines;
240                         if (p2 > 116) {
241                                 p2 = 116;
242                         }
243                         if (p1 < 16) {
244                                 p1 = 16;
245                         }
246                         /* don't send ^S or ^Q because it will hang a layer using cu(1) */
247                         if (p1 == ctrl('Q') || p1 == ctrl('S')) {
248                                 ++p1;
249                         }
250                         if (p2 == ctrl('Q') || p2 == ctrl('S')) {
251                                 ++p2;
252                         }
253                 }
254                 else {
255                         p1 = p2 = 16;
256                 }
257                 (void) printf("\033W%c%c", p1, p2);
258         }
259 }
260
261 /* get the mouse information */
262
263 MOUSE *
264 getmouseaction(char leading_char)
265 {
266         static  MOUSE   m;
267
268 #if UNIXPC
269
270         if(unixpcmouse == YES && leading_char == ESC) {
271
272                 /* Called if cscope received an ESC character.  See if it is
273                  * a mouse report and if so, decipher it.  A mouse report
274                  * looks like: "<ESC>[?xx;yy;b;rM"
275                  */
276                 int x = 0, y = 0, button = 0, reason = 0;
277                 int i;
278         
279                 /* Get a mouse report.  The form is: XX;YY;B;RM where
280                  * XX is 1,2, or 3 decimal digits with the X pixel position.
281                  * Similarly for YY.  B is a single decimal digit with the
282                  * button number (4 for one, 2 for two, and 1 for three).
283                  * R is the reason for the mouse report.
284                  *
285                  * In general, the input is read until the mouse report has
286                  * been completely read in or we have discovered that this
287                  * escape sequence is NOT a mouse report.  In the latter case
288                  * return the last character read to the input stream with
289                  * myungetch().
290                  */
291                 
292                 /* Check for "[?" being next 2 chars */
293                 if(((i = mygetch()) != '[') || ((i = mygetch()) != '?')) {
294                         myungetch(i);
295                         return(NULL);
296                 }
297         
298                 /* Grab the X position (in pixels) */
299                 while(isdigit(i = mygetch())) {
300                         x = (x*10) + (i - '0');
301                 }
302                 if(i != ';') {
303                         myungetch(i);
304                         return(NULL);   /* not a mouse report after all */
305                 }
306         
307                 /* Grab the Y position (in pixels) */
308                 while(isdigit(i = mygetch())) {
309                         y = (y*10) + (i - '0');
310                 }
311                 if(i != ';') {
312                         myungetch(i);
313                         return(NULL);
314                 }
315         
316                 /* Get which button */
317                 if((button = mygetch()) > '4') {
318                         myungetch(button);
319                         return(NULL);
320                 }
321                 if((i = mygetch()) != ';') {
322                         myungetch(i);
323                         return(NULL);
324                 }
325                 
326                 /* Get the reason for this mouse report */
327                 if((reason = mygetch()) > '8') {
328                         myungetch(reason);
329                         return(NULL);
330                 }
331                 
332                 /* sequence should terminate with an 'M' */
333                 if((i = mygetch()) != 'M') {
334                         myungetch(i);
335                         return(NULL);
336                 }
337         
338         
339                 /* OK.  We get a mouse report whenever a button is depressed
340                  * or released.  Let's ignore the report whenever the button
341                  * is depressed until when I am ready to implement sweeping.
342                  */
343                 if(reason != '2') {
344                         return(NULL);   /* '2' means button is released */
345                 }
346         
347                 /************************************************************
348                  * Always indicate button 1 irregardless of which button was
349                  * really pushed.
350                  ************************************************************/
351                 m.button = 1;
352         
353                 /************************************************************
354                  * Convert pixel coordinates to line and column coords.
355                  * The height and width are obtained using an ioctl() call
356                  * in mouseinit().  This assumes that variable width chars
357                  * are not being used ('though it would probably work anyway).
358                  ************************************************************/
359                 
360                 m.x1 = x/uw_hs; /* pixel/horizontal_spacing */
361                 m.y1 = y/uw_vs; /* pixel/vertical_spacing   */
362         
363                 /* "null" out the other fields */
364                 m.percent = m.x2 = m.y2 = -1;
365         }
366         else
367 #endif  /* not UNIXPC */
368
369         if (mouse == YES && leading_char == ctrl('X')) {
370         
371                 switch (mygetch()) {
372                 case ctrl('_'):         /* click */
373                         if ((m.button = mygetch()) == '0') {    /* if scrollbar */
374                                 m.percent = getpercent();
375                         }
376                         else {
377                                 m.x1 = getcoordinate();
378                                 m.y1 = getcoordinate();
379                                 m.x2 = m.y2 = -1;
380                         }
381                         break;
382         
383                 case ctrl(']'):         /* sweep */
384                         m.button = mygetch();
385                         m.x1 = getcoordinate();
386                         m.y1 = getcoordinate();
387                         m.x2 = getcoordinate();
388                         m.y2 = getcoordinate();
389                         break;
390                 default:
391                         return(NULL);
392                 }
393         }
394         else return(NULL);
395
396         return(&m);
397 }
398
399 /* get a row or column coordinate from a mouse button click or sweep */
400
401 static int
402 getcoordinate(void)
403 {
404         int  c, next;
405
406         c = mygetch();
407         next = 0;
408         if (c == ctrl('A')) {
409                 next = 95;
410                 c = mygetch();
411         }
412         if (c < ' ') {
413                 return (0);
414         }
415         return (next + c - ' ');
416 }
417
418 /* get a percentage */
419
420 static int
421 getpercent(void)
422 {
423         int c;
424
425         c = mygetch();
426         if (c < 16) {
427                 return(0);
428         }
429         if (c > 120) {
430                 return(100);
431         }
432         return(c - 16);
433 }