3 * Rob Zimmermann. All rights reserved.
5 * Keith Bostic. All rights reserved.
7 * See the LICENSE file for redistribution information.
12 #include <sys/cdefs.h>
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 ";
18 __RCSID("$NetBSD: m_menu.c,v 1.2 2014/01/26 21:43:45 christos Exp $");
21 #include <sys/queue.h>
23 #include <X11/Intrinsic.h>
24 #include <X11/StringDefs.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>
32 #include <bitstring.h>
36 #include "../common/common.h"
37 #include "../ipc/ip.h"
42 /* save this for creation of children */
43 static Widget main_widget
= NULL
;
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.
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
60 * implement file selection dialog boxes
61 * implement string prompt dialog boxes (e.g. for 'find')
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.
69 #define BufferSize 1024
72 * __vi_send_command_string --
73 * Utility: Send a menu command to vi
76 * Change VI_STRING to VI_COMMAND so that menu actions cannot be confusing
77 * when in insert mode.
80 * THIS SHOULD GO AWAY -- WE SHOULDN'T SEND UNINTERPRETED STRINGS TO THE
83 * PUBLIC: void __vi_send_command_string __P((String));
86 __vi_send_command_string(String str
)
89 char buffer
[BufferSize
];
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.
96 strcpy( buffer
, str
);
100 strcat( buffer
, "\n" );
104 ipb
.code
= VI_STRING
;
106 ipb
.len1
= strlen(buffer
);
107 vi_send(vi_ofd
, "a", &ipb
);
111 /* Utility: beep for unimplemented command */
113 #if defined(__STDC__)
114 static void send_beep( Widget w
)
116 static void send_beep( w
)
120 XBell( XtDisplay(w
), 0 );
126 * Utility: make a dialog box go Modal
128 * PUBLIC: void __vi_cancel_cb __P((Widget, XtPointer, XtPointer));
130 static Bool have_answer
;
132 __vi_cancel_cb(Widget w
, XtPointer client_data
, XtPointer call_data
)
138 * PUBLIC: void __vi_modal_dialog __P((Widget));
141 __vi_modal_dialog(Widget db
)
145 /* post the dialog */
147 XtPopup( XtParent(db
), XtGrabExclusive
);
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
);
156 XtPopdown( XtParent(db
) );
157 XtRemoveGrab( XtParent(db
) );
161 /* Utility: Get a file (using standard File Selection Dialog Box) */
163 static String file_name
;
166 #if defined(__STDC__)
167 static void ok_file_name( Widget w
,
168 XtPointer client_data
,
172 static void ok_file_name( w
, client_data
, call_data
)
174 XtPointer client_data
;
178 XmFileSelectionBoxCallbackStruct
*cbs
;
180 cbs
= (XmFileSelectionBoxCallbackStruct
*) call_data
;
181 XmStringGetLtoR( cbs
->value
, XmSTRING_DEFAULT_CHARSET
, &file_name
);
187 #if defined(__STDC__)
188 static String
get_file( Widget w
, String prompt
)
190 static String
get_file( w
, prompt
)
195 /* make it static so we can reuse it */
198 /* our return parameter */
199 if ( file_name
!= 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
);
211 /* use the title as a prompt */
212 XtVaSetValues( XtParent(db
), XmNtitle
, prompt
, 0 );
214 /* wait for a response */
215 __vi_modal_dialog( db
);
224 * Get a file name and send it with the command to the core.
227 file_command(Widget w
, int code
, String prompt
)
232 if ((file
= get_file(w
, prompt
)) != NULL
) {
235 ipb
.len1
= strlen(file
);
236 vi_send(vi_ofd
, "a", &ipb
);
242 * Menu action routines (one per menu entry)
244 * These are in the order in which they appear in the menu structure.
247 ma_edit_file(Widget w
, XtPointer call_data
, XtPointer client_data
)
249 file_command(w
, VI_EDIT
, "Edit");
253 ma_split(Widget w
, XtPointer call_data
, XtPointer client_data
)
255 file_command(w
, VI_EDITSPLIT
, "Edit");
259 ma_save(Widget w
, XtPointer call_data
, XtPointer client_data
)
264 (void)vi_send(vi_ofd
, NULL
, &ipb
);
268 ma_save_as(Widget w
, XtPointer call_data
, XtPointer client_data
)
270 file_command(w
, VI_WRITEAS
, "Save As");
274 ma_wq(Widget w
, XtPointer call_data
, XtPointer client_data
)
279 (void)vi_send(vi_ofd
, NULL
, &ipb
);
283 ma_quit(Widget w
, XtPointer call_data
, XtPointer client_data
)
288 (void)vi_send(vi_ofd
, NULL
, &ipb
);
292 ma_undo(Widget w
, XtPointer call_data
, XtPointer client_data
)
297 (void)vi_send(vi_ofd
, NULL
, &ipb
);
300 #if defined(__STDC__)
301 static void ma_cut( Widget w
,
303 XtPointer client_data
306 static void ma_cut( w
, call_data
, client_data
)
309 XtPointer client_data
;
317 #if defined(__STDC__)
318 static void ma_copy( Widget w
,
320 XtPointer client_data
323 static void ma_copy( w
, call_data
, client_data
)
326 XtPointer client_data
;
334 #if defined(__STDC__)
335 static void ma_paste( Widget w
,
337 XtPointer client_data
340 static void ma_paste( w
, call_data
, client_data
)
343 XtPointer client_data
;
351 ma_find(Widget w
, XtPointer call_data
, XtPointer client_data
)
353 __vi_show_search_dialog( main_widget
, "Find" );
357 ma_find_next(Widget w
, XtPointer call_data
, XtPointer client_data
)
363 ma_tags(Widget w
, XtPointer call_data
, XtPointer client_data
)
365 __vi_show_tags_dialog( main_widget
, "Tag Stack" );
369 ma_tagpop(Widget w
, XtPointer call_data
, XtPointer client_data
)
371 __vi_send_command_string( "\024" );
375 ma_tagtop(Widget w
, XtPointer call_data
, XtPointer client_data
)
377 __vi_send_command_string( ":tagtop" );
380 #if defined(__STDC__)
381 static void ma_preferences( Widget w
,
383 XtPointer client_data
386 static void ma_preferences( w
, call_data
, client_data
)
389 XtPointer client_data
;
392 __vi_show_options_dialog( main_widget
, "Preferences" );
396 /* Menu construction routines */
401 String accel
; /* for Motif */
402 String accel_text
; /* for the user */
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
},
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
},
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
},
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
},
451 static pull_down help_menu
[] = {
452 { NULL
, NULL
, NULL
, NULL
},
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
},
465 #if defined(__STDC__)
466 static void add_entries( Widget parent
, pull_down
*actions
)
468 static void add_entries( parent
, actions
)
476 for ( ; actions
->title
!= NULL
; actions
++ ) {
479 if ( *actions
->title
!= '\0' ) {
480 w
= XmCreatePushButton( parent
, actions
->title
, NULL
, 0 );
481 if ( actions
->action
== NULL
)
482 XtSetSensitive( w
, False
);
486 (XtCallbackProc
) actions
->action
,
489 if ( actions
->accel
!= NULL
) {
490 str
= XmStringCreateSimple( actions
->accel_text
);
492 XmNaccelerator
, actions
->accel
,
493 XmNacceleratorText
, str
,
500 w
= XmCreateSeparator( parent
, "separator", NULL
, 0 );
509 * vi_create_menubar --
511 * PUBLIC: Widget vi_create_menubar __P((Widget));
514 vi_create_menubar(Widget parent
)
516 Widget menu
, pull
, button
;
519 /* save this for creation of children */
520 main_widget
= parent
;
522 menu
= XmCreateMenuBar( parent
, "Menu", NULL
, 0 );
524 for ( ptr
=main_menu
; ptr
->title
!= NULL
; ptr
++ ) {
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 );
531 if ( strcmp( ptr
->title
, "Help" ) == 0 )
532 XtVaSetValues( menu
, XmNmenuHelpWidget
, button
, 0 );
535 /* These screw up accelerator processing. Punt for now */
537 XtVaSetValues( button
, XmNmnemonic
, ptr
->mnemonic
, 0 );
540 XtManageChild( button
);