xref: /minix/external/bsd/nvi/dist/motif_l/m_menu.c (revision 0a6a1f1d)
1 /*-
2  * Copyright (c) 1996
3  *	Rob Zimmermann.  All rights reserved.
4  * Copyright (c) 1996
5  *	Keith Bostic.  All rights reserved.
6  *
7  * See the LICENSE file for redistribution information.
8  */
9 
10 #include "config.h"
11 
12 #include <sys/cdefs.h>
13 #if 0
14 #ifndef lint
15 static const char sccsid[] = "Id: m_menu.c,v 8.26 2003/11/05 17:09:59 skimo Exp  (Berkeley) Date: 2003/11/05 17:09:59 ";
16 #endif /* not lint */
17 #else
18 __RCSID("$NetBSD: m_menu.c,v 1.2 2014/01/26 21:43:45 christos Exp $");
19 #endif
20 
21 #include <sys/queue.h>
22 
23 #include <X11/Intrinsic.h>
24 #include <X11/StringDefs.h>
25 #include <Xm/PushB.h>
26 #include <Xm/CascadeB.h>
27 #include <Xm/RowColumn.h>
28 #include <Xm/Separator.h>
29 #include <Xm/FileSB.h>
30 #include <Xm/SelectioB.h>
31 
32 #include <bitstring.h>
33 #include <stdio.h>
34 
35 #undef LOCK_SUCCESS
36 #include "../common/common.h"
37 #include "../ipc/ip.h"
38 #include "m_motif.h"
39 
40 extern int vi_ofd;
41 
42 /* save this for creation of children */
43 static	Widget	main_widget = NULL;
44 
45 /* This module defines the menu structure for vi.  Each menu
46  * item has an action routine associated with it.  For the most
47  * part, those actions will simply call vi_send with vi commands.
48  * others will pop up file selection dialogs and use them for
49  * vi commands, and other will have to have special actions.
50  *
51  * Future:
52  *	vi core will have to let us know when to be sensitive
53  *	change VI_STRING to VI_COMMAND so that menu actions cannot
54  *		be confusing when in insert mode
55  *	need VI_CUT, VI_COPY, and VI_PASTE to perform the appropriate
56  *		operations on the visible text of yank buffer.  VI_COPY
57  *		is likely a NOP, but it will make users happy
58  *	add mnemonics
59  *	add accelerators
60  *	implement file selection dialog boxes
61  *	implement string prompt dialog boxes (e.g. for 'find')
62  *
63  * Interface:
64  *	Widget	create_menubar( Widget parent ) creates and returns the
65  *		X menu structure.  The caller can place this
66  *		anywhere in the widget heirarchy.
67  */
68 
69 #define	BufferSize	1024
70 
71 /*
72  * __vi_send_command_string --
73  *	Utility:  Send a menu command to vi
74  *
75  * Future:
76  * Change VI_STRING to VI_COMMAND so that menu actions cannot be confusing
77  * when in insert mode.
78  *
79  * XXX
80  * THIS SHOULD GO AWAY -- WE SHOULDN'T SEND UNINTERPRETED STRINGS TO THE
81  * CORE.
82  *
83  * PUBLIC: void __vi_send_command_string __P((String));
84  */
85 void
__vi_send_command_string(String str)86 __vi_send_command_string(String str)
87 {
88     IP_BUF	ipb;
89     char	buffer[BufferSize];
90 
91     /* Future:  Need VI_COMMAND so vi knows this is not text to insert
92      * At that point, appending a cr/lf will not be necessary.  For now,
93      * append iff we are a colon or slash command.  Of course, if we are in
94      * insert mode, all bets are off.
95      */
96     strcpy( buffer, str );
97     switch ( *str ) {
98 	case ':':
99 	case '/':
100 	    strcat( buffer, "\n" );
101 	    break;
102     }
103 
104     ipb.code = VI_STRING;
105     ipb.str1 = buffer;
106     ipb.len1 = strlen(buffer);
107     vi_send(vi_ofd, "a", &ipb);
108 }
109 
110 
111 /* Utility:  beep for unimplemented command */
112 
113 #if defined(__STDC__)
send_beep(Widget w)114 static	void	send_beep( Widget w )
115 #else
116 static	void	send_beep( w )
117 	Widget	w;
118 #endif
119 {
120     XBell( XtDisplay(w), 0 );
121 }
122 
123 
124 /*
125  * __vi_cancel_cb --
126  *	Utility:  make a dialog box go Modal
127  *
128  * PUBLIC: void __vi_cancel_cb __P((Widget, XtPointer, XtPointer));
129  */
130 static	Bool	have_answer;
131 void
__vi_cancel_cb(Widget w,XtPointer client_data,XtPointer call_data)132 __vi_cancel_cb(Widget w, XtPointer client_data, XtPointer call_data)
133 {
134 	have_answer = True;
135 }
136 
137 /*
138  * PUBLIC: void __vi_modal_dialog __P((Widget));
139  */
140 void
__vi_modal_dialog(Widget db)141 __vi_modal_dialog(Widget db)
142 {
143     XtAppContext	ctx;
144 
145     /* post the dialog */
146     XtManageChild( db );
147     XtPopup( XtParent(db), XtGrabExclusive );
148 
149     /* wait for a response */
150     ctx = XtWidgetToApplicationContext(db);
151     XtAddGrab( XtParent(db), TRUE, FALSE );
152     for ( have_answer = False; ! have_answer; )
153 	XtAppProcessEvent( ctx, XtIMAll );
154 
155     /* done with db */
156     XtPopdown( XtParent(db) );
157     XtRemoveGrab( XtParent(db) );
158 }
159 
160 
161 /* Utility:  Get a file (using standard File Selection Dialog Box) */
162 
163 static	String	file_name;
164 
165 
166 #if defined(__STDC__)
ok_file_name(Widget w,XtPointer client_data,XtPointer call_data)167 static	void		ok_file_name( Widget w,
168 				      XtPointer client_data,
169 				      XtPointer call_data
170 				      )
171 #else
172 static	void		ok_file_name( w, client_data, call_data )
173 	Widget		w;
174 	XtPointer	client_data;
175 	XtPointer	call_data;
176 #endif
177 {
178     XmFileSelectionBoxCallbackStruct	*cbs;
179 
180     cbs = (XmFileSelectionBoxCallbackStruct *) call_data;
181     XmStringGetLtoR( cbs->value, XmSTRING_DEFAULT_CHARSET, &file_name );
182 
183     have_answer = True;
184 }
185 
186 
187 #if defined(__STDC__)
get_file(Widget w,String prompt)188 static	String	get_file( Widget w, String prompt )
189 #else
190 static	String	get_file( w, prompt )
191 	Widget	w;
192 	String	prompt;
193 #endif
194 {
195     /* make it static so we can reuse it */
196     static	Widget	db;
197 
198     /* our return parameter */
199     if ( file_name != NULL ) {
200 	XtFree( file_name );
201 	file_name = NULL;
202     }
203 
204     /* create one? */
205     if ( db == NULL ){
206 	db = XmCreateFileSelectionDialog( main_widget, "file", NULL, 0 );
207 	XtAddCallback( db, XmNokCallback, ok_file_name, NULL );
208 	XtAddCallback( db, XmNcancelCallback, __vi_cancel_cb, NULL );
209     }
210 
211     /* use the title as a prompt */
212     XtVaSetValues( XtParent(db), XmNtitle, prompt, 0 );
213 
214     /* wait for a response */
215     __vi_modal_dialog( db );
216 
217     /* done */
218     return file_name;
219 }
220 
221 
222 /*
223  * file_command --
224  *	Get a file name and send it with the command to the core.
225  */
226 static void
file_command(Widget w,int code,String prompt)227 file_command(Widget w, int code, String prompt)
228 {
229 	IP_BUF ipb;
230 	char *file;
231 
232 	if ((file = get_file(w, prompt)) != NULL) {
233 		ipb.code = code;
234 		ipb.str1 = file;
235 		ipb.len1 = strlen(file);
236 		vi_send(vi_ofd, "a", &ipb);
237 	}
238 }
239 
240 
241 /*
242  * Menu action routines (one per menu entry)
243  *
244  * These are in the order in which they appear in the menu structure.
245  */
246 static void
ma_edit_file(Widget w,XtPointer call_data,XtPointer client_data)247 ma_edit_file(Widget w, XtPointer call_data, XtPointer client_data)
248 {
249 	file_command(w, VI_EDIT, "Edit");
250 }
251 
252 static void
ma_split(Widget w,XtPointer call_data,XtPointer client_data)253 ma_split(Widget w, XtPointer call_data, XtPointer client_data)
254 {
255 	file_command(w, VI_EDITSPLIT, "Edit");
256 }
257 
258 static void
ma_save(Widget w,XtPointer call_data,XtPointer client_data)259 ma_save(Widget w, XtPointer call_data, XtPointer client_data)
260 {
261 	IP_BUF ipb;
262 
263 	ipb.code = VI_WRITE;
264 	(void)vi_send(vi_ofd, NULL, &ipb);
265 }
266 
267 static void
ma_save_as(Widget w,XtPointer call_data,XtPointer client_data)268 ma_save_as(Widget w, XtPointer call_data, XtPointer client_data)
269 {
270 	file_command(w, VI_WRITEAS, "Save As");
271 }
272 
273 static void
ma_wq(Widget w,XtPointer call_data,XtPointer client_data)274 ma_wq(Widget w, XtPointer call_data, XtPointer client_data)
275 {
276 	IP_BUF ipb;
277 
278 	ipb.code = VI_WQ;
279 	(void)vi_send(vi_ofd, NULL, &ipb);
280 }
281 
282 static void
ma_quit(Widget w,XtPointer call_data,XtPointer client_data)283 ma_quit(Widget w, XtPointer call_data, XtPointer client_data)
284 {
285 	IP_BUF ipb;
286 
287 	ipb.code = VI_QUIT;
288 	(void)vi_send(vi_ofd, NULL, &ipb);
289 }
290 
291 static void
ma_undo(Widget w,XtPointer call_data,XtPointer client_data)292 ma_undo(Widget w, XtPointer call_data, XtPointer client_data)
293 {
294 	IP_BUF ipb;
295 
296 	ipb.code = VI_UNDO;
297 	(void)vi_send(vi_ofd, NULL, &ipb);
298 }
299 
300 #if defined(__STDC__)
ma_cut(Widget w,XtPointer call_data,XtPointer client_data)301 static void	ma_cut(	Widget w,
302 			XtPointer call_data,
303 			XtPointer client_data
304 			)
305 #else
306 static	void		ma_cut( w, call_data, client_data )
307 	Widget		w;
308 	XtPointer	call_data;
309 	XtPointer	client_data;
310 #endif
311 {
312     /* future */
313     send_beep( w );
314 }
315 
316 
317 #if defined(__STDC__)
ma_copy(Widget w,XtPointer call_data,XtPointer client_data)318 static	void	ma_copy(	Widget w,
319 				XtPointer call_data,
320 				XtPointer client_data
321 				)
322 #else
323 static	void		ma_copy( w, call_data, client_data )
324 	Widget		w;
325 	XtPointer	call_data;
326 	XtPointer	client_data;
327 #endif
328 {
329     /* future */
330     send_beep( w );
331 }
332 
333 
334 #if defined(__STDC__)
ma_paste(Widget w,XtPointer call_data,XtPointer client_data)335 static	void	ma_paste(	Widget w,
336 				XtPointer call_data,
337 				XtPointer client_data
338 				)
339 #else
340 static	void		ma_paste( w, call_data, client_data )
341 	Widget		w;
342 	XtPointer	call_data;
343 	XtPointer	client_data;
344 #endif
345 {
346     /* future */
347     send_beep( w );
348 }
349 
350 static void
ma_find(Widget w,XtPointer call_data,XtPointer client_data)351 ma_find(Widget w, XtPointer call_data, XtPointer client_data)
352 {
353 	__vi_show_search_dialog( main_widget, "Find" );
354 }
355 
356 static void
ma_find_next(Widget w,XtPointer call_data,XtPointer client_data)357 ma_find_next(Widget w, XtPointer call_data, XtPointer client_data)
358 {
359 	__vi_search( w );
360 }
361 
362 static void
ma_tags(Widget w,XtPointer call_data,XtPointer client_data)363 ma_tags(Widget w, XtPointer call_data, XtPointer client_data)
364 {
365 	__vi_show_tags_dialog( main_widget, "Tag Stack" );
366 }
367 
368 static void
ma_tagpop(Widget w,XtPointer call_data,XtPointer client_data)369 ma_tagpop(Widget w, XtPointer call_data, XtPointer client_data)
370 {
371 	__vi_send_command_string( "\024" );
372 }
373 
374 static void
ma_tagtop(Widget w,XtPointer call_data,XtPointer client_data)375 ma_tagtop(Widget w, XtPointer call_data, XtPointer client_data)
376 {
377 	__vi_send_command_string( ":tagtop" );
378 }
379 
380 #if defined(__STDC__)
ma_preferences(Widget w,XtPointer call_data,XtPointer client_data)381 static void	ma_preferences(	Widget w,
382 				XtPointer call_data,
383 				XtPointer client_data
384 				)
385 #else
386 static	void		ma_preferences( w, call_data, client_data )
387 	Widget		w;
388 	XtPointer	call_data;
389 	XtPointer	client_data;
390 #endif
391 {
392 	__vi_show_options_dialog( main_widget, "Preferences" );
393 }
394 
395 
396 /* Menu construction routines */
397 
398 typedef	struct {
399     String	title;
400     void	(*action)();
401     String	accel;		/* for Motif */
402     String	accel_text;	/* for the user */
403 } pull_down;
404 
405 typedef	struct {
406     char	mnemonic;
407     String	title;
408     pull_down	*actions;
409 } menu_bar;
410 
411 static	pull_down	file_menu[] = {
412     { "Edit File...",		ma_edit_file,	"Alt<Key>e",	"Alt+E"	},
413     { "",			NULL,		NULL,	NULL	},
414     { "Split Window...",	ma_split,	NULL,	NULL	},
415     { "",			NULL,		NULL,	NULL	},
416     { "Save ",			ma_save,	"Alt<Key>s",	"Alt+S"	},
417     { "Save As...",		ma_save_as,	"Shift Alt<Key>s",	"Shift+Alt+S"	},
418     { "",			NULL,		NULL,	NULL	},
419     { "Write and Quit",		ma_wq,		"Shift Alt<Key>q",	"Shift+Alt+Q"	},
420     { "Quit",			ma_quit,	"Alt<Key>q",	"Alt+Q"	},
421     { NULL,			NULL,		NULL,	NULL	},
422 };
423 
424 static	pull_down	edit_menu[] = {
425     { "Undo",			ma_undo,	NULL,	NULL	},
426     { "",			NULL,		NULL,	NULL	},
427     { "Cut",			ma_cut,		"Alt<Key>x",	"Alt+X"	},
428     { "Copy",			ma_copy,	"Alt<Key>c",	"Alt+C"	},
429     { "Paste",			ma_paste,	"Alt<Key>v",	"Alt+V"	},
430     { "",			NULL,		NULL,	NULL	},
431     { "Find",			ma_find,	"Alt<Key>f",	"Alt+F"	},
432     { "Find Next",		ma_find_next,	"Alt<Key>g",	"Alt+G"	},
433     { NULL,			NULL,		NULL,	NULL	},
434 };
435 
436 static	pull_down	options_menu[] = {
437     { "Preferences",		ma_preferences,	NULL,	NULL	},
438     { "Command Mode Maps",	NULL,		NULL,	NULL	},
439     { "Insert Mode Maps",	NULL,		NULL,	NULL	},
440     { NULL,			NULL,		NULL,	NULL	},
441 };
442 
443 static	pull_down	tag_menu[] = {
444     { "Show Tag Stack",		ma_tags,	"Alt<Key>t",	"Alt+T"	},
445     { "",			NULL,		NULL,	NULL	},
446     { "Pop Tag",		ma_tagpop,	NULL,	NULL	},
447     { "Clear Stack",		ma_tagtop,	NULL,	NULL	},
448     { NULL,			NULL,		NULL,	NULL	},
449 };
450 
451 static	pull_down	help_menu[] = {
452     { NULL,			NULL,		NULL,	NULL	},
453 };
454 
455 static	menu_bar	main_menu[] = {
456     { 'F',	"File",		file_menu	},
457     { 'E',	"Edit", 	edit_menu	},
458     { 'O',	"Options",	options_menu	},
459     { 'T',	"Tag",		tag_menu	},
460     { 'H',	"Help",		help_menu	},
461     { 0,	NULL,		NULL		},
462 };
463 
464 
465 #if defined(__STDC__)
add_entries(Widget parent,pull_down * actions)466 static	void	add_entries( Widget parent, pull_down *actions )
467 #else
468 static	void		add_entries( parent, actions )
469 	Widget		parent;
470 	pull_down	*actions;
471 #endif
472 {
473     Widget	w;
474     XmString	str;
475 
476     for ( ; actions->title != NULL; actions++ ) {
477 
478 	/* a separator? */
479 	if ( *actions->title != '\0' ) {
480 	    w = XmCreatePushButton( parent, actions->title, NULL, 0 );
481 	    if ( actions->action == NULL )
482 		XtSetSensitive( w, False );
483 	    else
484 		XtAddCallback(  w,
485 				XmNactivateCallback,
486 				(XtCallbackProc) actions->action,
487 				actions
488 				);
489 	    if ( actions->accel != NULL ) {
490 		str = XmStringCreateSimple( actions->accel_text );
491 		XtVaSetValues(	w,
492 				XmNaccelerator,		actions->accel,
493 				XmNacceleratorText,	str,
494 				0
495 				);
496 		XmStringFree( str );
497 	    }
498 	}
499 	else {
500 	    w = XmCreateSeparator( parent, "separator", NULL, 0 );
501 	}
502 
503 	XtManageChild( w );
504 
505     }
506 }
507 
508 /*
509  * vi_create_menubar --
510  *
511  * PUBLIC: Widget vi_create_menubar __P((Widget));
512  */
513 Widget
vi_create_menubar(Widget parent)514 vi_create_menubar(Widget parent)
515 {
516     Widget	menu, pull, button;
517     menu_bar	*ptr;
518 
519     /* save this for creation of children */
520     main_widget = parent;
521 
522     menu = XmCreateMenuBar( parent, "Menu", NULL, 0 );
523 
524     for ( ptr=main_menu; ptr->title != NULL; ptr++ ) {
525 
526 	pull = XmCreatePulldownMenu( menu, "pull", NULL, 0 );
527 	add_entries( pull, ptr->actions );
528 	button = XmCreateCascadeButton( menu, ptr->title, NULL, 0 );
529 	XtVaSetValues( button, XmNsubMenuId, pull, 0 );
530 
531 	if ( strcmp( ptr->title, "Help" ) == 0 )
532 	    XtVaSetValues( menu, XmNmenuHelpWidget, button, 0 );
533 
534 #if 0
535 	/* These screw up accelerator processing.  Punt for now */
536 	if ( ptr->mnemonic )
537 	    XtVaSetValues( button, XmNmnemonic, ptr->mnemonic, 0 );
538 #endif
539 
540 	XtManageChild( button );
541     }
542 
543     return menu;
544 }
545