configure.in: specify config_aux_dir
[nvi.git] / motif_l / m_menu.c
blob360b40b81b9be7896ae7f8c5a4984c53b8b0698a
1 /*-
2 * Copyright (c) 1996
3 * Rob Zimmermann. All rights reserved.
4 * Copyright (c) 1996
5 * Keith Bostic. All rights reserved.
7 * See the LICENSE file for redistribution information.
8 */
10 #include "config.h"
12 #ifndef lint
13 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 $";
14 #endif /* not lint */
16 #include <sys/queue.h>
18 #include <X11/Intrinsic.h>
19 #include <X11/StringDefs.h>
20 #include <Xm/PushB.h>
21 #include <Xm/CascadeB.h>
22 #include <Xm/RowColumn.h>
23 #include <Xm/Separator.h>
24 #include <Xm/FileSB.h>
25 #include <Xm/SelectioB.h>
27 #include <bitstring.h>
28 #include <stdio.h>
30 #undef LOCK_SUCCESS
31 #include "../common/common.h"
32 #include "../ipc/ip.h"
33 #include "m_motif.h"
35 extern int vi_ofd;
37 /* save this for creation of children */
38 static Widget main_widget = NULL;
40 /* This module defines the menu structure for vi. Each menu
41 * item has an action routine associated with it. For the most
42 * part, those actions will simply call vi_send with vi commands.
43 * others will pop up file selection dialogs and use them for
44 * vi commands, and other will have to have special actions.
46 * Future:
47 * vi core will have to let us know when to be sensitive
48 * change VI_STRING to VI_COMMAND so that menu actions cannot
49 * be confusing when in insert mode
50 * need VI_CUT, VI_COPY, and VI_PASTE to perform the appropriate
51 * operations on the visible text of yank buffer. VI_COPY
52 * is likely a NOP, but it will make users happy
53 * add mnemonics
54 * add accelerators
55 * implement file selection dialog boxes
56 * implement string prompt dialog boxes (e.g. for 'find')
58 * Interface:
59 * Widget create_menubar( Widget parent ) creates and returns the
60 * X menu structure. The caller can place this
61 * anywhere in the widget heirarchy.
64 #define BufferSize 1024
67 * __vi_send_command_string --
68 * Utility: Send a menu command to vi
70 * Future:
71 * Change VI_STRING to VI_COMMAND so that menu actions cannot be confusing
72 * when in insert mode.
74 * XXX
75 * THIS SHOULD GO AWAY -- WE SHOULDN'T SEND UNINTERPRETED STRINGS TO THE
76 * CORE.
78 * PUBLIC: void __vi_send_command_string __P((String));
80 void
81 __vi_send_command_string(String str)
83 IP_BUF ipb;
84 char buffer[BufferSize];
86 /* Future: Need VI_COMMAND so vi knows this is not text to insert
87 * At that point, appending a cr/lf will not be necessary. For now,
88 * append iff we are a colon or slash command. Of course, if we are in
89 * insert mode, all bets are off.
91 strcpy( buffer, str );
92 switch ( *str ) {
93 case ':':
94 case '/':
95 strcat( buffer, "\n" );
96 break;
99 ipb.code = VI_STRING;
100 ipb.str1 = buffer;
101 ipb.len1 = strlen(buffer);
102 vi_send(vi_ofd, "a", &ipb);
106 /* Utility: beep for unimplemented command */
108 #if defined(__STDC__)
109 static void send_beep( Widget w )
110 #else
111 static void send_beep( w )
112 Widget w;
113 #endif
115 XBell( XtDisplay(w), 0 );
120 * __vi_cancel_cb --
121 * Utility: make a dialog box go Modal
123 * PUBLIC: void __vi_cancel_cb __P((Widget, XtPointer, XtPointer));
125 static Bool have_answer;
126 void
127 __vi_cancel_cb(Widget w, XtPointer client_data, XtPointer call_data)
129 have_answer = True;
133 * PUBLIC: void __vi_modal_dialog __P((Widget));
135 void
136 __vi_modal_dialog(Widget db)
138 XtAppContext ctx;
140 /* post the dialog */
141 XtManageChild( db );
142 XtPopup( XtParent(db), XtGrabExclusive );
144 /* wait for a response */
145 ctx = XtWidgetToApplicationContext(db);
146 XtAddGrab( XtParent(db), TRUE, FALSE );
147 for ( have_answer = False; ! have_answer; )
148 XtAppProcessEvent( ctx, XtIMAll );
150 /* done with db */
151 XtPopdown( XtParent(db) );
152 XtRemoveGrab( XtParent(db) );
156 /* Utility: Get a file (using standard File Selection Dialog Box) */
158 static String file_name;
161 #if defined(__STDC__)
162 static void ok_file_name( Widget w,
163 XtPointer client_data,
164 XtPointer call_data
166 #else
167 static void ok_file_name( w, client_data, call_data )
168 Widget w;
169 XtPointer client_data;
170 XtPointer call_data;
171 #endif
173 XmFileSelectionBoxCallbackStruct *cbs;
175 cbs = (XmFileSelectionBoxCallbackStruct *) call_data;
176 XmStringGetLtoR( cbs->value, XmSTRING_DEFAULT_CHARSET, &file_name );
178 have_answer = True;
182 #if defined(__STDC__)
183 static String get_file( Widget w, String prompt )
184 #else
185 static String get_file( w, prompt )
186 Widget w;
187 String prompt;
188 #endif
190 /* make it static so we can reuse it */
191 static Widget db;
193 /* our return parameter */
194 if ( file_name != NULL ) {
195 XtFree( file_name );
196 file_name = NULL;
199 /* create one? */
200 if ( db == NULL ){
201 db = XmCreateFileSelectionDialog( main_widget, "file", NULL, 0 );
202 XtAddCallback( db, XmNokCallback, ok_file_name, NULL );
203 XtAddCallback( db, XmNcancelCallback, __vi_cancel_cb, NULL );
206 /* use the title as a prompt */
207 XtVaSetValues( XtParent(db), XmNtitle, prompt, 0 );
209 /* wait for a response */
210 __vi_modal_dialog( db );
212 /* done */
213 return file_name;
218 * file_command --
219 * Get a file name and send it with the command to the core.
221 static void
222 file_command(Widget w, int code, String prompt)
224 IP_BUF ipb;
225 char *file;
227 if ((file = get_file(w, prompt)) != NULL) {
228 ipb.code = code;
229 ipb.str1 = file;
230 ipb.len1 = strlen(file);
231 vi_send(vi_ofd, "a", &ipb);
237 * Menu action routines (one per menu entry)
239 * These are in the order in which they appear in the menu structure.
241 static void
242 ma_edit_file(Widget w, XtPointer call_data, XtPointer client_data)
244 file_command(w, VI_EDIT, "Edit");
247 static void
248 ma_split(Widget w, XtPointer call_data, XtPointer client_data)
250 file_command(w, VI_EDITSPLIT, "Edit");
253 static void
254 ma_save(Widget w, XtPointer call_data, XtPointer client_data)
256 IP_BUF ipb;
258 ipb.code = VI_WRITE;
259 (void)vi_send(vi_ofd, NULL, &ipb);
262 static void
263 ma_save_as(Widget w, XtPointer call_data, XtPointer client_data)
265 file_command(w, VI_WRITEAS, "Save As");
268 static void
269 ma_wq(Widget w, XtPointer call_data, XtPointer client_data)
271 IP_BUF ipb;
273 ipb.code = VI_WQ;
274 (void)vi_send(vi_ofd, NULL, &ipb);
277 static void
278 ma_quit(Widget w, XtPointer call_data, XtPointer client_data)
280 IP_BUF ipb;
282 ipb.code = VI_QUIT;
283 (void)vi_send(vi_ofd, NULL, &ipb);
286 static void
287 ma_undo(Widget w, XtPointer call_data, XtPointer client_data)
289 IP_BUF ipb;
291 ipb.code = VI_UNDO;
292 (void)vi_send(vi_ofd, NULL, &ipb);
295 #if defined(__STDC__)
296 static void ma_cut( Widget w,
297 XtPointer call_data,
298 XtPointer client_data
300 #else
301 static void ma_cut( w, call_data, client_data )
302 Widget w;
303 XtPointer call_data;
304 XtPointer client_data;
305 #endif
307 /* future */
308 send_beep( w );
312 #if defined(__STDC__)
313 static void ma_copy( Widget w,
314 XtPointer call_data,
315 XtPointer client_data
317 #else
318 static void ma_copy( w, call_data, client_data )
319 Widget w;
320 XtPointer call_data;
321 XtPointer client_data;
322 #endif
324 /* future */
325 send_beep( w );
329 #if defined(__STDC__)
330 static void ma_paste( Widget w,
331 XtPointer call_data,
332 XtPointer client_data
334 #else
335 static void ma_paste( w, call_data, client_data )
336 Widget w;
337 XtPointer call_data;
338 XtPointer client_data;
339 #endif
341 /* future */
342 send_beep( w );
345 static void
346 ma_find(Widget w, XtPointer call_data, XtPointer client_data)
348 __vi_show_search_dialog( main_widget, "Find" );
351 static void
352 ma_find_next(Widget w, XtPointer call_data, XtPointer client_data)
354 __vi_search( w );
357 static void
358 ma_tags(Widget w, XtPointer call_data, XtPointer client_data)
360 __vi_show_tags_dialog( main_widget, "Tag Stack" );
363 static void
364 ma_tagpop(Widget w, XtPointer call_data, XtPointer client_data)
366 __vi_send_command_string( "\024" );
369 static void
370 ma_tagtop(Widget w, XtPointer call_data, XtPointer client_data)
372 __vi_send_command_string( ":tagtop" );
375 #if defined(__STDC__)
376 static void ma_preferences( Widget w,
377 XtPointer call_data,
378 XtPointer client_data
380 #else
381 static void ma_preferences( w, call_data, client_data )
382 Widget w;
383 XtPointer call_data;
384 XtPointer client_data;
385 #endif
387 __vi_show_options_dialog( main_widget, "Preferences" );
391 /* Menu construction routines */
393 typedef struct {
394 String title;
395 void (*action)();
396 String accel; /* for Motif */
397 String accel_text; /* for the user */
398 } pull_down;
400 typedef struct {
401 char mnemonic;
402 String title;
403 pull_down *actions;
404 } menu_bar;
406 static pull_down file_menu[] = {
407 { "Edit File...", ma_edit_file, "Alt<Key>e", "Alt+E" },
408 { "", NULL, NULL, NULL },
409 { "Split Window...", ma_split, NULL, NULL },
410 { "", NULL, NULL, NULL },
411 { "Save ", ma_save, "Alt<Key>s", "Alt+S" },
412 { "Save As...", ma_save_as, "Shift Alt<Key>s", "Shift+Alt+S" },
413 { "", NULL, NULL, NULL },
414 { "Write and Quit", ma_wq, "Shift Alt<Key>q", "Shift+Alt+Q" },
415 { "Quit", ma_quit, "Alt<Key>q", "Alt+Q" },
416 { NULL, NULL, NULL, NULL },
419 static pull_down edit_menu[] = {
420 { "Undo", ma_undo, NULL, NULL },
421 { "", NULL, NULL, NULL },
422 { "Cut", ma_cut, "Alt<Key>x", "Alt+X" },
423 { "Copy", ma_copy, "Alt<Key>c", "Alt+C" },
424 { "Paste", ma_paste, "Alt<Key>v", "Alt+V" },
425 { "", NULL, NULL, NULL },
426 { "Find", ma_find, "Alt<Key>f", "Alt+F" },
427 { "Find Next", ma_find_next, "Alt<Key>g", "Alt+G" },
428 { NULL, NULL, NULL, NULL },
431 static pull_down options_menu[] = {
432 { "Preferences", ma_preferences, NULL, NULL },
433 { "Command Mode Maps", NULL, NULL, NULL },
434 { "Insert Mode Maps", NULL, NULL, NULL },
435 { NULL, NULL, NULL, NULL },
438 static pull_down tag_menu[] = {
439 { "Show Tag Stack", ma_tags, "Alt<Key>t", "Alt+T" },
440 { "", NULL, NULL, NULL },
441 { "Pop Tag", ma_tagpop, NULL, NULL },
442 { "Clear Stack", ma_tagtop, NULL, NULL },
443 { NULL, NULL, NULL, NULL },
446 static pull_down help_menu[] = {
447 { NULL, NULL, NULL, NULL },
450 static menu_bar main_menu[] = {
451 { 'F', "File", file_menu },
452 { 'E', "Edit", edit_menu },
453 { 'O', "Options", options_menu },
454 { 'T', "Tag", tag_menu },
455 { 'H', "Help", help_menu },
456 { 0, NULL, NULL },
460 #if defined(__STDC__)
461 static void add_entries( Widget parent, pull_down *actions )
462 #else
463 static void add_entries( parent, actions )
464 Widget parent;
465 pull_down *actions;
466 #endif
468 Widget w;
469 XmString str;
471 for ( ; actions->title != NULL; actions++ ) {
473 /* a separator? */
474 if ( *actions->title != '\0' ) {
475 w = XmCreatePushButton( parent, actions->title, NULL, 0 );
476 if ( actions->action == NULL )
477 XtSetSensitive( w, False );
478 else
479 XtAddCallback( w,
480 XmNactivateCallback,
481 (XtCallbackProc) actions->action,
482 actions
484 if ( actions->accel != NULL ) {
485 str = XmStringCreateSimple( actions->accel_text );
486 XtVaSetValues( w,
487 XmNaccelerator, actions->accel,
488 XmNacceleratorText, str,
491 XmStringFree( str );
494 else {
495 w = XmCreateSeparator( parent, "separator", NULL, 0 );
498 XtManageChild( w );
504 * vi_create_menubar --
506 * PUBLIC: Widget vi_create_menubar __P((Widget));
508 Widget
509 vi_create_menubar(Widget parent)
511 Widget menu, pull, button;
512 menu_bar *ptr;
514 /* save this for creation of children */
515 main_widget = parent;
517 menu = XmCreateMenuBar( parent, "Menu", NULL, 0 );
519 for ( ptr=main_menu; ptr->title != NULL; ptr++ ) {
521 pull = XmCreatePulldownMenu( menu, "pull", NULL, 0 );
522 add_entries( pull, ptr->actions );
523 button = XmCreateCascadeButton( menu, ptr->title, NULL, 0 );
524 XtVaSetValues( button, XmNsubMenuId, pull, 0 );
526 if ( strcmp( ptr->title, "Help" ) == 0 )
527 XtVaSetValues( menu, XmNmenuHelpWidget, button, 0 );
529 #if 0
530 /* These screw up accelerator processing. Punt for now */
531 if ( ptr->mnemonic )
532 XtVaSetValues( button, XmNmnemonic, ptr->mnemonic, 0 );
533 #endif
535 XtManageChild( button );
538 return menu;