only clean out gs when last window goes
[nvi.git] / motif_l / m_options.c
blob1e65b6d1e57088e5b0a207dac82651e7c19aeaf9
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_options.c,v 8.20 2000/07/05 11:33:19 skimo Exp $ (Berkeley) $Date: 2000/07/05 11:33:19 $";
14 #endif /* not lint */
16 #include <sys/types.h>
17 #include <sys/queue.h>
19 #include <X11/X.h>
20 #include <X11/Intrinsic.h>
21 #include <Xm/DialogS.h>
22 #include <Xm/Form.h>
23 #include <Xm/Frame.h>
24 #include <Xm/LabelG.h>
25 #include <Xm/PushBG.h>
26 #include <Xm/TextF.h>
27 #include <Xm/ToggleBG.h>
28 #include <Xm/RowColumn.h>
30 #include <bitstring.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
35 #include "../common/common.h"
36 #include "../ipc/ip.h"
37 #include "m_motif.h"
39 extern int vi_ofd;
41 static void set_opt __P((Widget, XtPointer, XtPointer));
44 /* constants */
46 #if defined(SelfTest)
48 /* in production, get these from the resource list */
50 #define toggleColumns 6
52 #endif
56 * global data
59 static Widget preferences = NULL;
61 static optData display[] = {
62 { optToggle, "comment", },
63 { optToggle, "flash", },
64 { optToggle, "leftright", },
65 { optToggle, "list", },
66 { optToggle, "number", },
67 { optToggle, "octal", },
68 { optToggle, "ruler", },
69 { optToggle, "showmode", },
70 { optToggle, "slowopen", },
71 { optToggle, "verbose", },
72 { optToggle, "windowname", },
73 { optTerminator, },
74 }, display_int[] = {
75 { optInteger, "report", },
76 { optInteger, "scroll", },
77 { optInteger, "shiftwidth", },
78 { optInteger, "sidescroll", },
79 { optInteger, "tabstop", },
80 { optInteger, "window", },
81 { optTerminator, },
82 }, display_str[] = {
83 { optString, "noprint", },
84 { optString, "print", },
85 { optTerminator, },
86 }, files[] = {
87 { optToggle, "autowrite", },
88 { optToggle, "lock", },
89 { optToggle, "readonly", },
90 { optToggle, "writeany", },
91 { optTerminator, },
92 }, files_str[] = {
93 { optString, "backup", },
94 { optString, "path", },
95 { optTerminator, },
96 }, general[] = {
97 { optToggle, "exrc", },
98 { optToggle, "lisp", },
99 { optToggle, "modeline", },
100 { optToggle, "sourceany", },
101 { optToggle, "tildeop", },
102 { optTerminator, },
103 }, general_int[] = {
104 { optInteger, "taglength", },
105 { optTerminator, },
106 }, general_str[] = {
107 { optString, "cdpath", },
108 { optString, "directory", },
109 { optString, "msgcat", },
110 { optString, "recdir", },
111 { optString, "shell", },
112 { optString, "shellmeta", },
113 { optString, "tags", },
114 { optTerminator, },
115 }, input[] = {
116 { optToggle, "altwerase", },
117 { optToggle, "autoindent", },
118 { optToggle, "remap", },
119 { optToggle, "showmatch", },
120 { optToggle, "ttywerase", },
121 { optTerminator, },
122 }, input_int[] = {
123 { optInteger, "escapetime", },
124 { optInteger, "keytime", },
125 { optInteger, "matchtime", },
126 { optInteger, "timeout", },
127 { optInteger, "wraplen", },
128 { optInteger, "wrapmargin", },
129 { optTerminator, },
130 }, input_str[] = {
131 { optString, "cedit", },
132 { optString, "filec", },
133 { optTerminator, },
134 }, search[] = {
135 { optToggle, "extended", },
136 { optToggle, "iclower", },
137 { optToggle, "ignorecase", },
138 { optToggle, "magic", },
139 { optToggle, "searchincr", },
140 { optToggle, "wrapscan", },
141 { optTerminator, },
142 }, search_str[] = {
143 { optString, "paragraphs", },
144 { optString, "sections", },
145 { optTerminator, },
148 /* ********* NOTE ***********
149 * Sheet 0 will always be shown first. It does not matter to the Xt code
150 * which sheet that is, so it ought to be the one users interact with most.
151 * Best guess is that's general editor options, but it might be Search/re.
152 * ********* NOTE ***********
154 static optSheet sheets[] = {
155 { "Display",
156 "These options control how text is displayed on the screen",
157 NULL,
158 display,
159 display_int,
160 display_str,
162 { "Files",
163 "These options control how the editor handles files",
164 NULL,
165 files,
166 NULL,
167 files_str,
169 { "Input",
170 "These options control text input behavior",
171 NULL,
172 input,
173 input_int,
174 input_str,
176 { "Search/RE",
177 "These options control searching and Regular Expression behavior",
178 NULL,
179 search,
180 NULL,
181 search_str,
183 { "Editor",
184 "These options control general editor configuration",
185 NULL,
186 general,
187 general_int,
188 general_str,
193 /* callbacks */
195 #if defined(SelfTest)
196 void __vi_cancel_cb()
198 puts( "cancelled" );
200 #endif
203 static void destroyed()
205 int i;
207 puts( "destroyed" );
209 /* some window managers destroy us upon popdown */
210 for (i=0; i<XtNumber(sheets); i++) {
211 sheets[i].holder = NULL;
213 preferences = NULL;
217 static void window_unmapped( w, ptr, ev, cont )
218 Widget w;
219 XtPointer ptr;
220 XEvent *ev;
221 Boolean *cont;
223 if ( ev->type == UnmapNotify ) {
224 #if defined(SelfTest)
225 puts( "unmapped" );
226 #endif
227 XtPopdown( XtParent( preferences ) );
232 * __vi_editopt --
233 * Set an edit option based on a core message.
235 * PUBLIC: int __vi_editopt __P((IPVI *, const char *, u_int32_t, const char *, u_int32_t, u_int32_t));
238 __vi_editopt(ipvi, str1, len1, str2, len2, val1)
239 IPVI *ipvi;
240 const char *str1;
241 u_int32_t len1;
242 const char *str2;
243 u_int32_t len2;
244 u_int32_t val1;
246 optData *opt;
248 #undef NSEARCH
249 #define NSEARCH(list) { \
250 for (opt = list; opt->kind != optTerminator; ++opt) \
251 if (!strcmp(opt->name, str1)) \
252 goto found; \
255 NSEARCH(display);
256 NSEARCH(display_int);
257 NSEARCH(display_str);
258 NSEARCH(files);
259 NSEARCH(files_str);
260 NSEARCH(general);
261 NSEARCH(general_int);
262 NSEARCH(general_str);
263 NSEARCH(input);
264 NSEARCH(input_int);
265 NSEARCH(input_str);
266 NSEARCH(search);
267 NSEARCH(search_str);
269 return (0);
271 found: switch (opt->kind) {
272 case optToggle:
273 opt->value = (void *)val1;
274 break;
275 case optInteger:
276 if (opt->value != NULL)
277 free(opt->value);
278 if ((opt->value = malloc(8)) != NULL)
279 (void)snprintf(opt->value,
280 8, "%lu", (u_long)val1);
281 break;
282 case optString:
283 case optFile:
284 if (opt->value != NULL)
285 free(opt->value);
286 if ((opt->value = malloc(len2)) != NULL)
287 memcpy(opt->value, str2, len2);
288 break;
289 case optTerminator:
290 abort();
292 return (0);
296 * set_opt --
297 * Send a set-edit-option message to core.
299 static void
300 set_opt(w, closure, call_data)
301 Widget w;
302 XtPointer closure, call_data;
304 optData *opt;
305 Boolean set;
306 IP_BUF ipb;
307 String str;
308 extern IPVI ipvi_motif;
310 opt = closure;
312 ipb.code = VI_EDITOPT;
313 ipb.str1 = opt->name;
314 ipb.len1 = strlen(opt->name);
316 switch (opt->kind) {
317 case optToggle:
318 XtVaGetValues(w, XmNset, &set, 0);
319 ipb.val1 = set;
320 ipb.len2 = 0;
322 vi_wsend(&ipvi_motif, "ab1", &ipb);
323 if (ipb.val1) {
324 opt->value = (void *)!set;
326 * RAZ:
327 * How do we turn off the button? We don't want to
328 * go recursive where we set it and it calls set_opt
329 * to tell the core. Is that possible?
331 XtVaSetValues(w, XmNset, &set, 0);
332 break;
335 if (strcmp(opt->name, "ruler") == 0)
336 if (set)
337 __vi_show_text_ruler_dialog(
338 __vi_screen->area, "Ruler");
339 else
340 __vi_clear_text_ruler_dialog();
341 break;
342 case optInteger:
343 str = XmTextFieldGetString(w);
344 ipb.val1 = atoi(str);
345 ipb.len2 = 0;
346 vi_send(vi_ofd, "ab1", &ipb);
347 break;
348 case optFile:
349 case optString:
350 ipb.str2 = XmTextFieldGetString(w);
351 ipb.len2 = strlen(ipb.str2);
352 vi_send(vi_ofd, "ab1", &ipb);
353 break;
354 case optTerminator:
355 abort();
360 /* add toggles to the property sheet */
362 #if defined(__STDC__)
363 static void add_toggle( Widget parent, optData *option )
364 #else
365 static void add_toggle( parent, option )
366 Widget parent;
367 optData *option;
368 #endif
370 Widget w;
372 w = XtVaCreateManagedWidget( option->name,
373 xmToggleButtonGadgetClass,
374 parent,
375 XmNset, (Boolean) option->value,
378 XtAddCallback( w, XmNvalueChangedCallback, set_opt, option );
382 static Widget create_toggles( outer, toggles )
383 Widget outer;
384 optData *toggles;
386 Widget inner;
387 int i;
389 inner = XtVaCreateWidget( "toggleOptions",
390 xmRowColumnWidgetClass,
391 outer,
392 XmNpacking, XmPACK_COLUMN,
393 XmNnumColumns, 4,
394 XmNtopAttachment, XmATTACH_FORM,
395 XmNrightAttachment, XmATTACH_FORM,
396 XmNleftAttachment, XmATTACH_FORM,
400 /* first the booleans */
401 for (i=0; toggles[i].kind != optTerminator; i++) {
402 add_toggle( inner, &toggles[i] );
404 XtManageChild( inner );
406 return inner;
410 /* draw text fields and their labels */
412 #if defined(__STDC__)
413 static void add_string_options( Widget parent,
414 optData *options
416 #else
417 static void add_string_options( parent, options )
418 Widget parent;
419 optData *options;
420 #endif
422 int i;
423 Widget f, w;
425 for ( i=0; options[i].kind != optTerminator; i++ ) {
427 f = XtVaCreateWidget( "form",
428 xmFormWidgetClass,
429 parent,
433 XtVaCreateManagedWidget( options[i].name,
434 xmLabelGadgetClass,
436 XmNtopAttachment, XmATTACH_FORM,
437 XmNbottomAttachment, XmATTACH_FORM,
438 XmNleftAttachment, XmATTACH_FORM,
439 XmNrightAttachment, XmATTACH_POSITION,
440 XmNrightPosition, 20,
441 XmNalignment, XmALIGNMENT_END,
445 w = XtVaCreateManagedWidget( "text",
446 xmTextFieldWidgetClass,
448 XmNtopAttachment, XmATTACH_FORM,
449 XmNbottomAttachment, XmATTACH_FORM,
450 XmNrightAttachment, XmATTACH_FORM,
451 XmNleftAttachment, XmATTACH_POSITION,
452 XmNleftPosition, 20,
456 XmTextFieldSetString( w, (char *) options[i].value );
457 XtAddCallback( w, XmNactivateCallback, set_opt, &options[i] );
458 XtManageChild( f );
463 /* draw and display a single page of properties */
465 #if defined(__STDC__)
466 static Widget create_sheet( Widget parent, optSheet *sheet )
467 #else
468 static Widget create_sheet( parent, sheet )
469 Widget parent;
470 optSheet *sheet;
471 #endif
473 Widget outer, inner, frame;
474 Dimension height;
475 XmString str;
477 outer = XtVaCreateWidget( sheet->name,
478 xmFormWidgetClass,
479 parent,
480 XmNtopAttachment, XmATTACH_FORM,
481 XmNrightAttachment, XmATTACH_FORM,
482 XmNbottomAttachment, XmATTACH_FORM,
483 XmNleftAttachment, XmATTACH_FORM,
484 XmNshadowType, XmSHADOW_ETCHED_IN,
485 XmNshadowThickness, 2,
486 XmNverticalSpacing, 4,
487 XmNhorizontalSpacing, 4,
491 /* add descriptive text */
492 frame = XtVaCreateManagedWidget( "frame",
493 xmFrameWidgetClass,
494 outer,
495 XmNtopAttachment, XmATTACH_FORM,
496 XmNrightAttachment, XmATTACH_FORM,
497 XmNleftAttachment, XmATTACH_FORM,
500 str = XmStringCreateLtoR( sheet->description, XmSTRING_DEFAULT_CHARSET );
501 XtVaCreateManagedWidget( "description",
502 xmLabelGadgetClass,
503 frame,
504 XmNlabelString, str,
507 XmStringFree( str );
509 /* Add the toggles. */
510 inner = create_toggles( outer, sheet->toggles );
511 XtVaSetValues( inner,
512 XmNtopAttachment, XmATTACH_WIDGET,
513 XmNtopWidget, frame,
517 /* the string options go here */
518 inner = XtVaCreateWidget( "otherOptions",
519 xmRowColumnWidgetClass,
520 outer,
521 XmNpacking, XmPACK_COLUMN,
522 XmNtopAttachment, XmATTACH_WIDGET,
523 XmNtopWidget, inner,
524 XmNrightAttachment, XmATTACH_FORM,
525 XmNbottomAttachment, XmATTACH_FORM,
526 XmNleftAttachment, XmATTACH_FORM,
530 /* Optionally, the ints. */
531 if ( sheet->ints != NULL )
532 add_string_options( inner, sheet->ints );
534 /* Optionally, the rest. */
535 if ( sheet->others != NULL )
536 add_string_options( inner, sheet->others );
538 XtManageChild( inner );
540 /* finally, force resize of the parent */
541 XtVaGetValues( outer, XmNheight, &height, 0 );
542 XtVaSetValues( parent, XmNheight, height, 0 );
544 return outer;
548 /* change preferences to another sheet */
550 static void change_sheet( parent, current )
551 Widget parent;
552 int current;
554 static int current_sheet = -1;
556 /* create a new one? */
557 if ( sheets[current].holder == NULL )
558 sheets[current].holder = create_sheet( parent, &sheets[current] );
560 /* done with the old one? */
561 if ( current_sheet != -1 && sheets[current_sheet].holder != NULL )
562 XtUnmanageChild( sheets[current_sheet].holder );
564 current_sheet = current;
565 XtManageChild( sheets[current].holder );
566 XtManageChild( parent );
570 /* Draw and display a dialog the describes vi options */
572 #if defined(__STDC__)
573 static Widget create_options_dialog( Widget parent, String title )
574 #else
575 static Widget create_options_dialog( parent, title )
576 Widget parent;
577 String title;
578 #endif
580 Widget box, form, inner;
581 int i;
582 char buffer[1024];
584 /* already built? */
585 if ( preferences != NULL ) return preferences;
587 box = XtVaCreatePopupShell( title,
588 xmDialogShellWidgetClass,
589 parent,
590 XmNtitle, title,
591 XmNallowShellResize, False,
594 XtAddCallback( box, XmNpopdownCallback, __vi_cancel_cb, 0 );
595 XtAddCallback( box, XmNdestroyCallback, destroyed, 0 );
596 XtAddEventHandler( box,
597 SubstructureNotifyMask,
598 False,
599 window_unmapped,
600 NULL
603 form = XtVaCreateWidget( "options",
604 xmFormWidgetClass,
605 box,
609 /* copy the pointers to the sheet names */
610 *buffer = '\0';
611 for (i=0; i<XtNumber(sheets); i++) {
612 strcat( buffer, "|" );
613 strcat( buffer, sheets[i].name );
616 inner = __vi_CreateTabbedFolder( "tabs",
617 form,
618 buffer,
619 XtNumber(sheets),
620 change_sheet
623 /* build the property sheets early */
624 for ( i=0; i<XtNumber(sheets); i++ )
625 change_sheet( inner, i );
627 /* manage all of the sheets right now */
628 for ( i=0; i<XtNumber(sheets); i++ )
629 XtManageChild( sheets[i].holder );
630 XtManageChild( form );
632 /* remove all but the first one */
633 for ( i=0; i<XtNumber(sheets); i++ )
634 XtUnmanageChild( sheets[i].holder );
635 change_sheet( inner, 0 ); /* show first sheet first */
637 /* keep this global, we might destroy it later */
638 preferences = form;
640 /* done */
641 return form;
647 * module entry point
649 * __vi_show_options_dialog --
652 * PUBLIC: void __vi_show_options_dialog __P((Widget, String));
654 void
655 __vi_show_options_dialog(parent, title)
656 Widget parent;
657 String title;
659 Widget db = create_options_dialog( parent, title );
660 #if defined(SelfTest)
661 Widget shell = XtParent( db );
662 #endif
664 XtManageChild( db );
666 #if defined(SelfTest)
667 /* wait until it goes away */
668 XtPopup( shell, XtGrabNone );
669 #else
670 /* wait until it goes away */
671 __vi_modal_dialog( db );
672 #endif
677 /* module entry point
678 * Utilities for the search dialog
680 * __vi_toggle --
681 * Returns the current value of a toggle.
683 * PUBLIC: int __vi_toggle __P((char *));
686 __vi_toggle(name)
687 char *name;
689 optData *opt;
691 #undef NSEARCH
692 #define NSEARCH(list) { \
693 for (opt = list; opt->kind != optTerminator; ++opt) \
694 if (!strcmp(opt->name, name)) \
695 return ((int)opt->value); \
697 NSEARCH(display);
698 NSEARCH(files);
699 NSEARCH(general);
700 NSEARCH(input);
701 NSEARCH(search);
703 return (0);
707 * __vi_create_search_toggles --
708 * Creates the search toggles. This is so the options and search widgets
709 * share their appearance.
711 * PUBLIC: Widget __vi_create_search_toggles __P((Widget, optData[]));
713 Widget
714 __vi_create_search_toggles(parent, list)
715 Widget parent;
716 optData list[];
718 optData *opt;
721 * Copy current options information into the search table.
723 * XXX
724 * This is an O(M*N) loop, but I don't think it matters.
726 for (opt = list; opt->kind != optTerminator; ++opt)
727 opt->value = (void *)__vi_toggle(opt->name);
729 return (create_toggles(parent, list));
733 #if defined(SelfTest)
735 #if defined(__STDC__)
736 static void show_options( Widget w, XtPointer data, XtPointer cbs )
737 #else
738 static void show_options( w, data, cbs )
739 Widget w;
740 XtPointer data;
741 XtPointer cbs;
742 #endif
744 __vi_show_options_dialog( data, "Preferences" );
747 main( int argc, char *argv[] )
749 XtAppContext ctx;
750 Widget top_level, rc, button;
751 extern exit();
753 /* create a top-level shell for the window manager */
754 top_level = XtVaAppInitialize( &ctx,
755 argv[0],
756 NULL, 0, /* options */
757 (ArgcType) &argc,
758 argv, /* might get modified */
759 NULL,
760 NULL
763 rc = XtVaCreateManagedWidget( "rc",
764 xmRowColumnWidgetClass,
765 top_level,
769 button = XtVaCreateManagedWidget( "Pop up options dialog",
770 xmPushButtonGadgetClass,
774 XtAddCallback( button, XmNactivateCallback, show_options, rc );
776 button = XtVaCreateManagedWidget( "Quit",
777 xmPushButtonGadgetClass,
781 XtAddCallback( button, XmNactivateCallback, exit, 0 );
783 XtRealizeWidget(top_level);
784 XtAppMainLoop(ctx);
786 #endif