1 /*
2 **
3 ** miscmenu.c
4 **
5 ** Copyright (C) 1995, 1996, 1997 Johannes Plass
6 ** Copyright (C) 2004 Jose E. Marchesi
7 **
8 ** This program is free software; you can redistribute it and/or modify
9 ** it under the terms of the GNU General Public License as published by
10 ** the Free Software Foundation; either version 3 of the License, or
11 ** (at your option) any later version.
12 **
13 ** This program is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ** GNU General Public License for more details.
17 **
18 ** You should have received a copy of the GNU General Public License
19 ** along with GNU gv; see the file COPYING.  If not, write to
20 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 ** Boston, MA 02111-1307, USA.
22 **
23 ** Author:   Johannes Plass (plass@thep.physik.uni-mainz.de)
24 **           Department of Physics
25 **           Johannes Gutenberg-University
26 **           Mainz, Germany
27 **
28 **           Jose E. Marchesi (jemarch@gnu.org)
29 **           GNU Project
30 **
31 */
32 #include "ac_config.h"
33 
34 /*
35 #define MESSAGES
36 */
37 #include "message.h"
38 
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <math.h>
42 
43 #include "paths.h"
44 #include INC_X11(Intrinsic.h)
45 #include INC_X11(StringDefs.h)
46 #include INC_XAW(SimpleMenu.h)
47 #include INC_XAW(SmeBSB.h)
48 #include INC_XAW(SmeLine.h)
49 #include INC_XAW(Cardinals.h)
50 #include INC_XAW(Scrollbar.h)
51 
52 #include "types.h"
53 #include "actions.h"
54 #include "callbacks.h"
55 #include "miscmenu.h"
56 #include "options.h"
57 #include "main_resources.h"
58 #include "main_globals.h"
59 
60 #include <string.h>
61 
62 static MiscMenuEntryStruct miscmenu_entries[] = {
63   { "update",cb_checkFile,(XtPointer)CHECK_FILE_DATE,2 },
64   { "redisplay",cb_redisplay,NULL,3 },
65   { "toggle_current" , cb_setPageMark, (XtPointer)(SPM_CURRENT|SPM_TOGGLE),1 },
66   { "toggle_even"    , cb_setPageMark, (XtPointer)(SPM_EVEN|SPM_TOGGLE),1 },
67   { "toggle_odd"     , cb_setPageMark, (XtPointer)(SPM_ODD|SPM_TOGGLE),1 },
68   { "unmark",cb_setPageMark,(XtPointer)(SPM_ALL|SPM_UNMARK),1 },
69   { "stop",cb_stopInterpreter,NULL,0 },
70   { "print_all", cb_print, (XtPointer)PAGE_MODE_ALL,3 },
71   { "print_marked",cb_print , (XtPointer)(PAGE_MODE_MARKED|PAGE_MODE_CURRENT),1 },
72   { "save_all", cb_save, (XtPointer)PAGE_MODE_ALL, 3 },
73   { "save_marked",cb_save , (XtPointer)(PAGE_MODE_MARKED|PAGE_MODE_CURRENT),1 },
74   { "line",NULL,NULL,0 },
75   { NULL,NULL,NULL,0 }
76 };
77 
78 /*##################################################
79   miscmenu_freeMiscMenuEntries
80 ##################################################*/
81 
miscmenu_freeMiscMenuEntries(entries)82 void miscmenu_freeMiscMenuEntries(entries)
83   MiscMenuEntry *entries;
84 {
85   int i=0;
86   BEGINMESSAGE(miscmenu_freeMiscMenuEntries)
87   while (entries[i]) {
88     XtFree((XtPointer)entries[i]);
89     i++;
90   }
91   XtFree((XtPointer)entries);
92   ENDMESSAGE(miscmenu_freeMiscMenuEntries)
93 }
94 
95 /*##################################################
96   miscmenu_parseMiscMenuEntries
97 ##################################################*/
98 
miscmenu_mallocMiscMenuEntry(void)99 static MiscMenuEntry miscmenu_mallocMiscMenuEntry(void)
100 {
101   MiscMenuEntry entry;
102   entry = (MiscMenuEntry) XtMalloc(sizeof(MiscMenuEntryStruct));
103   memset((void*)entry ,0,sizeof(MiscMenuEntryStruct));
104   return entry;
105 }
106 
miscmenu_parseMiscMenuEntries(s)107 MiscMenuEntry *miscmenu_parseMiscMenuEntries(s)
108   char *s;
109 {
110   char *c,*nl;
111   MiscMenuEntry *entries,*mentries,entry;
112   int i,j,n,have_entry=0;
113   char name[100];
114 
115   BEGINMESSAGE(miscmenu_parseMiscMenuEntries)
116   if (!s) s = "";
117   s =options_squeezeMultiline(s);
118   for (n=1,c=s; (c = strchr(c,'\n')); n++, c++);
119   INFIMESSAGE(number of entries,n)
120   mentries = entries = (MiscMenuEntry*) XtMalloc((n+2)*sizeof(MiscMenuEntry));
121   c=s;
122   if (*s) while (n>0) {
123     nl = strchr(c,'\n');
124     if (nl) *nl='\0';
125     name[0]='\0';
126     if (*c == '#' || *c == '!') i=0;
127     else i=sscanf(c," %99s ",name);
128     if (i==1) {
129       for (j=0; miscmenu_entries[j].name; j++)
130 	if (!strcasecmp(miscmenu_entries[j].name,name)) {
131 	  entry = miscmenu_mallocMiscMenuEntry();
132 	  *entry = miscmenu_entries[j];
133 	  have_entry = 1;
134 	  *entries++ = entry;
135 	}
136     }
137     n--;
138     if (!nl) break;
139     c=++nl;
140   }
141   if (!have_entry) {
142     entry = miscmenu_mallocMiscMenuEntry();
143     *entry = miscmenu_entries[0];
144     *entries++ = entry;
145   }
146   *entries = (MiscMenuEntry) NULL;
147   XtFree(s);
148   ENDMESSAGE(miscmenu_parseMiscMenuEntries)
149   return(mentries);
150 }
151 
152 /*############################################################*/
153 /* miscmenu_a_miscMenu */
154 /*############################################################*/
155 
156 #define MISC_MENU_IDLE		(1<<0)
157 #define MISC_MENU_STATE_1	(1<<1)
158 #define MISC_MENU_STATE_2	(1<<2)
159 #define MISC_MENU_INIT		(1<<3)
160 #define MISC_MENU_POPUP		(1<<4)
161 #define MISC_MENU_RESET		(1<<5)
162 #define MISC_MENU_CHECK		(1<<6)
163 
miscmenu_a_miscMenu(w,event,params,num_params)164 void miscmenu_a_miscMenu(w, event, params, num_params)
165   Widget w;
166   XEvent *event;
167   String *params;
168   Cardinal *num_params;
169 {
170   static int mode = MISC_MENU_IDLE;
171   static Widget gvw = (Widget)NULL;
172   static Widget menuwidget = (Widget)NULL;
173   static int xo=0,yo=0;
174   int x,y;
175 
176   BEGINMESSAGE(miscmenu_a_miscMenu)
177 
178   if (!event) {
179     INFMESSAGE(received reset request)
180     if (menuwidget) XtDestroyWidget(menuwidget);
181     menuwidget = (Widget)NULL;
182     gvw = (Widget)NULL;
183     mode = MISC_MENU_IDLE;
184     ENDMESSAGE(miscmenu_a_miscMenu)
185     return;
186   }
187 
188   if (*num_params < 1) {
189     INFMESSAGE(no parameter)
190     ENDMESSAGE(miscmenu_a_miscMenu)
191     return;
192   }
193 
194 # define MISC_MENU_HAVE(aaa,bbb) (!strcmp(params[0],(aaa)) && mode&(bbb))
195   if      MISC_MENU_HAVE("init" ,  MISC_MENU_IDLE)    mode = (MISC_MENU_INIT	| MISC_MENU_STATE_1);
196   else if MISC_MENU_HAVE("popup" , MISC_MENU_STATE_1) mode = (MISC_MENU_POPUP	| MISC_MENU_STATE_2);
197   else if MISC_MENU_HAVE("check" , MISC_MENU_STATE_2) mode = (MISC_MENU_CHECK	| MISC_MENU_STATE_2);
198   else if MISC_MENU_HAVE("reset" , (MISC_MENU_IDLE|MISC_MENU_STATE_1|MISC_MENU_STATE_2))
199                                                       mode = (MISC_MENU_RESET	| MISC_MENU_STATE_2);
200   else {
201     INFMESSAGE(no mode)
202     ENDMESSAGE(miscmenu_a_miscMenu)
203     return;
204   }
205 #   undef MISC_MENU_HAVE
206 
207   if (mode & MISC_MENU_INIT) {
208     INFMESSAGE(MISC_MENU_INIT)
209     if (w==page && (event->type == ButtonRelease || event->type == ButtonPress)) {
210       xo = (int) event->xbutton.x_root;
211       yo = (int) event->xbutton.y_root;
212       gvw = w;
213     } else {
214       INFMESSAGE(event not in main window or not a button press or button release)
215       mode = MISC_MENU_IDLE;
216     }
217     ENDMESSAGE(miscmenu_a_miscMenu)
218     return;
219   }
220 
221   if (mode & MISC_MENU_POPUP) {
222     Arg args[4];
223     Cardinal n;
224     Widget entry=NULL;
225 
226     INFMESSAGE(MISC_MENU_POPUP)
227 
228     if (event->type != ButtonRelease && event->type != ButtonPress) {
229       INFMESSAGE(event not a button press or button release)
230       miscmenu_a_miscMenu(gvw,(XEvent*)NULL,NULL,NULL);
231       ENDMESSAGE(miscmenu_a_miscMenu)
232       return;
233     }
234     x = (int) event->xbutton.x_root;
235     y = (int) event->xbutton.y_root;
236     if (abs(x-xo)>1 || abs(y-yo)>1) {
237       INFMESSAGE(succesive  events are unrelated)
238       miscmenu_a_miscMenu(gvw,(XEvent*)NULL,NULL,NULL);
239       ENDMESSAGE(miscmenu_a_miscMenu)
240       return;
241     }
242     menuwidget = XtCreatePopupShell("miscMenu", simpleMenuWidgetClass,w,NULL,(Cardinal)0);
243     {
244       int i;
245       MiscMenuEntry e;
246       int menu_x, menu_y;
247       Dimension menu_width,menu_height,entry_height,menu_border;
248       Dimension screen_width,screen_height;
249       Position button_x, button_y;
250       for (i=0; gv_miscmenu_entries[i]; i++) {
251         e = gv_miscmenu_entries[i];
252         SMESSAGE(e->name)
253 	if (strcasecmp(e->name,"line")) {
254 	  entry = XtCreateManagedWidget(e->name, smeBSBObjectClass,menuwidget,NULL,(Cardinal)0);
255 	  if (e->cb) XtAddCallback(entry,XtNcallback,e->cb,e->client_data);
256 	  if (e->sensitivity_type)  {
257 	    Boolean b;
258 	    if      (e->sensitivity_type==1) b = (toc_text != NULL);
259 	    else if (e->sensitivity_type==2) b = (gv_filename != NULL);
260 	    else    b = (gv_psfile != NULL || (gv_gs_arguments && *gv_gs_arguments));
261 	    XtSetSensitive(entry,b);
262 	  }
263 	} else {
264 	  XtCreateManagedWidget("line", smeLineObjectClass,menuwidget,NULL,(Cardinal)0);
265 	}
266       }
267 
268       if (!XtIsRealized(menuwidget)) XtRealizeWidget(menuwidget);
269 
270                                                         n=0;
271       XtSetArg(args[n], XtNheight, &entry_height);      ++n;
272       XtGetValues(entry, args, n);
273 
274                                                         n=0;
275       XtSetArg(args[n], XtNwidth, &menu_width);         ++n;
276       XtSetArg(args[n], XtNheight, &menu_height);       ++n;
277       XtSetArg(args[n], XtNborderWidth, &menu_border);  ++n;
278       XtGetValues(menuwidget, args, n);
279 
280       XtTranslateCoords(w, event->xbutton.x, event->xbutton.y, &button_x, &button_y);
281       menu_x = button_x-menu_width/2 -menu_border;
282       menu_y = button_y-entry_height/2;
283 
284       screen_width = WidthOfScreen(XtScreen(menuwidget));
285       screen_height = HeightOfScreen(XtScreen(menuwidget));
286 
287       if( menu_x + menu_width > screen_width && menu_width < screen_width )
288 	menu_x = screen_width - menu_width;
289       if( menu_y + menu_height > screen_height && menu_height < screen_height )
290 	menu_y = screen_height - menu_height;
291 
292       n=0;
293       XtSetArg(args[n], XtNx, menu_x);                  n++;
294       XtSetArg(args[n], XtNy, menu_y);                  n++;
295       XtSetValues(menuwidget, args, n);
296       XtPopup(menuwidget,XtGrabExclusive);
297     }
298     ENDMESSAGE(miscmenu_a_miscMenu)
299     return;
300   }
301 
302   if (mode & MISC_MENU_CHECK) {
303     INFMESSAGE(MISC_MENU_CHECK)
304     if (menuwidget) {
305       Arg args[5];
306       Cardinal n;
307       Position ulx,uly,lrx,lry,evx,evy;
308       int rx,ry;
309       Dimension width,height;
310                                                          n=0;
311       XtSetArg(args[n], XtNwidth,  &width);              n++;
312       XtSetArg(args[n], XtNheight, &height);             n++;
313       XtGetValues(menuwidget, args, n);
314       XtTranslateCoords(menuwidget, 0, 0, &ulx, &uly);
315       XtTranslateCoords(menuwidget, (Position)width, (Position)height, &lrx, &lry);
316       IIMESSAGE(ulx,uly)
317       IIMESSAGE(lrx,lry)
318       {
319 	Window root, child;
320 	int dummyx, dummyy;
321 	unsigned int dummymask;
322 	XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child, &rx, &ry,
323 		      &dummyx, &dummyy, &dummymask);
324       }
325       evx = (Position)rx;
326       evy = (Position)ry;
327       IIMESSAGE(evx,evy)
328       if (evx<=ulx || evx >= lrx || evy <= uly || evy >= lry) {
329 	INFMESSAGE(pointer outside window)
330         mode = mode | MISC_MENU_RESET;
331       }
332     }
333   }
334 
335   if (mode & MISC_MENU_RESET) {
336     INFMESSAGE(MISC_MENU_RESET)
337     miscmenu_a_miscMenu(gvw,(XEvent*)NULL,NULL,NULL);
338   }
339 
340   ENDMESSAGE(miscmenu_a_miscMenu)
341 }
342 
343 
344 
345 
346 
347 
348 
349 
350 
351 
352 
353 
354 
355 
356 
357 
358 
359 
360 
361 
362 
363 
364 
365 
366