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_tags.c,v 8.9 2003/11/05 17:10:00 skimo Exp (Berkeley) Date: 2003/11/05 17:10:00 ";
16 #endif /* not lint */
17 #else
18 __RCSID("$NetBSD: m_tags.c,v 1.2 2014/01/26 21:43:45 christos Exp $");
19 #endif
20
21 /*
22 * This module implements a dialog for navigating the tag stack
23 *
24 * Interface:
25 * void __vi_show_tags_dialog( Widget parent, String title )
26 * Pops up a Tags dialog. We allow one per session. It is not modal.
27 *
28 * void __vi_push_tag( String text )
29 * void __vi_pop_tag()
30 * void __vi_clear_tag()
31 * When core changes the tag stack we will change our representation
32 * of it. When this dialog appears, we need core to send a slew of
33 * messages so we can display the current tag stack.
34 *
35 * void __vi_set_tag_text( String text )
36 * the text field in the dialog is set to the string. ideally,
37 * this should be kept in sync with the word following the caret
38 * in the current editor window
39 *
40 * To Do:
41 * The push-buttons should activate and deactivate according to
42 * the state of the tag stack and the text field.
43 *
44 * Need to send VI commands rather than strings
45 *
46 * Need IPO command to start/stop asking for the current tag stack
47 */
48
49
50 /* context */
51 #include <X11/X.h>
52 #include <X11/Intrinsic.h>
53 #include <Xm/DialogS.h>
54 #include <Xm/Form.h>
55 #include <Xm/LabelG.h>
56 #include <Xm/TextF.h>
57 #include <Xm/List.h>
58 #include <Xm/RowColumn.h>
59 #include <Xm/PushBG.h>
60
61 #if ! defined(SelfTest)
62 #include <sys/types.h>
63 #include <sys/queue.h>
64
65 #include <bitstring.h>
66 #include <stdio.h>
67 #include <string.h>
68
69 #undef LOCK_SUCCESS
70 #include "../common/common.h"
71 #include "../ipc/ip.h"
72 #include "m_motif.h"
73 #endif
74
75 extern int vi_ofd;
76
77
78 /* globals */
79
80 static Widget db_tabs = NULL,
81 db_text,
82 db_list;
83
84 static Boolean active = False;
85
86 typedef struct {
87 String name;
88 Boolean is_default;
89 void (*cb)();
90 } ButtonData;
91
92 static void go_to_tag(Widget w);
93 static void split_to_tag(Widget w);
94 static void pop_tag(Widget w);
95
96 static ButtonData button_data[] = {
97 { "Go To Tag", True, go_to_tag },
98 { "Split To Tag", False, split_to_tag },
99 { "Pop Tag", False, pop_tag },
100 };
101
102
103 /* manage the tags stack list */
104
__vi_pop_tag(void)105 void __vi_pop_tag(void)
106 {
107 if ( ! active ) return;
108
109 XmListDeletePos( db_list, 1 );
110 }
111
112
__vi_clear_tag(void)113 void __vi_clear_tag(void)
114 {
115 if ( ! active ) return;
116
117 XmListDeleteAllItems( db_list );
118 }
119
120
__vi_push_tag(String text)121 void __vi_push_tag(String text)
122 {
123 XmString str;
124
125 if ( ! active ) return;
126
127 str = XmStringCreateSimple( text );
128 XmListAddItem( db_list, str, 1 );
129 XmStringFree( str );
130 }
131
132
133 /* create a set of push buttons */
134
135 #define SpacingRatio 4 /* 3:1 button to spaces */
136
137 #if defined(__STDC__)
create_push_buttons(Widget parent,ButtonData * data,int count)138 static Widget create_push_buttons( Widget parent,
139 ButtonData *data,
140 int count
141 )
142 #else
143 static Widget create_push_buttons( parent, data, count )
144 Widget parent;
145 ButtonData *data;
146 int count;
147 #endif
148 {
149 Widget w, form;
150 int pos = 1, base;
151
152 base = SpacingRatio*count + 1;
153 form = XtVaCreateManagedWidget( "buttons",
154 xmFormWidgetClass,
155 parent,
156 XmNleftAttachment, XmATTACH_FORM,
157 XmNrightAttachment, XmATTACH_FORM,
158 XmNfractionBase, base,
159 XmNshadowType, XmSHADOW_ETCHED_IN,
160 XmNshadowThickness, 2,
161 XmNverticalSpacing, 4,
162 0
163 );
164
165 while ( count-- > 0 ) {
166 w = XtVaCreateManagedWidget(data->name,
167 xmPushButtonGadgetClass,
168 form,
169 XmNtopAttachment, XmATTACH_FORM,
170 XmNbottomAttachment,XmATTACH_FORM,
171 XmNleftAttachment, XmATTACH_POSITION,
172 XmNleftPosition, pos,
173 XmNshowAsDefault, data->is_default,
174 XmNdefaultButtonShadowThickness, data->is_default,
175 XmNrightAttachment, XmATTACH_POSITION,
176 XmNrightPosition, pos+SpacingRatio-1,
177 0
178 );
179 if ( data->is_default )
180 XtVaSetValues( form, XmNdefaultButton, w, 0 );
181 XtAddCallback( w, XmNactivateCallback, data->cb, 0 );
182 pos += SpacingRatio;
183 data++;
184 }
185
186 return form;
187 }
188
189
190 /* callbacks */
191
192 static void
cancel_cb(void)193 cancel_cb(void)
194 {
195 #if defined(SelfTest)
196 puts( "cancelled" );
197 #endif
198 active = False;
199 }
200
201
set_text_field(Widget w,XtPointer ptr,XmListCallbackStruct * cbs)202 static void set_text_field(Widget w, XtPointer ptr, XmListCallbackStruct *cbs)
203 {
204 String str;
205
206 XmStringGetLtoR( cbs->item, XmSTRING_DEFAULT_CHARSET, &str );
207 XmTextFieldSetString( db_text, str );
208 XtFree( str );
209 }
210
211
__vi_set_tag_text(String text)212 void __vi_set_tag_text(String text)
213 {
214 if ( active ) XmTextFieldSetString( db_text, text );
215 }
216
217
destroyed(void)218 static void destroyed(void)
219 {
220 #if defined(SelfTest)
221 puts( "destroyed" );
222 #endif
223
224 /* some window managers destroy us upon popdown */
225 db_tabs = NULL;
226 active = False;
227 }
228
229
230 #if defined(__STDC__)
pop_tag(Widget w)231 static void pop_tag( Widget w )
232 #else
233 static void pop_tag( w )
234 Widget w;
235 #endif
236 {
237 static String buffer = ":tagpop";
238
239 #if defined(SelfTest)
240 printf( "sending command <<%s>>\n", buffer );
241 __vi_pop_tag();
242 #else
243 __vi_send_command_string( buffer );
244 #endif
245 }
246
247
248 #if defined(__STDC__)
split_to_tag(Widget w)249 static void split_to_tag( Widget w )
250 #else
251 static void split_to_tag( w )
252 Widget w;
253 #endif
254 {
255 IP_BUF ipb;
256 String str;
257
258 str = XmTextFieldGetString( db_text );
259
260 #if defined(SelfTest)
261 printf( "sending command <<:Tag %s>>\n", str );
262 #else
263 /*
264 * XXX
265 * This is REALLY sleazy. We pass the nul along with the
266 * string so that the core editor doesn't have to copy the
267 * string to get a nul termination. This should be fixed
268 * as part of making the editor fully 8-bit clean.
269 */
270 ipb.code = VI_TAGSPLIT;
271 ipb.str1 = str;
272 ipb.len1 = strlen(str) + 1;
273 vi_send(vi_ofd, "a", &ipb);
274 #endif
275
276 XtFree( str );
277 }
278
279
280 #if defined(__STDC__)
go_to_tag(Widget w)281 static void go_to_tag( Widget w )
282 #else
283 static void go_to_tag( w )
284 Widget w;
285 #endif
286 {
287 IP_BUF ipb;
288 String str;
289
290 str = XmTextFieldGetString( db_text );
291
292 #if defined(SelfTest)
293 printf( "sending command <<:tag %s>>\n", str );
294 #else
295 /*
296 * XXX
297 * This is REALLY sleazy. We pass the nul along with the
298 * string so that the core editor doesn't have to copy the
299 * string to get a nul termination. This should be fixed
300 * as part of making the editor fully 8-bit clean.
301 */
302 ipb.code = VI_TAGAS;
303 ipb.str1 = str;
304 ipb.len1 = strlen(str) + 1;
305 vi_send(vi_ofd, "a", &ipb);
306 #endif
307
308 XtFree( str );
309 }
310
311
312
313 /* Draw and display a dialog the describes nvi options */
314
315 #if defined(__STDC__)
create_tags_dialog(Widget parent,String title)316 static Widget create_tags_dialog( Widget parent, String title )
317 #else
318 static Widget create_tags_dialog( parent, title )
319 Widget parent;
320 String title;
321 #endif
322 {
323 Widget box, form, form2, form3, buttons;
324
325 /* already built? */
326 if ( db_tabs != NULL ) return db_tabs;
327
328 box = XtVaCreatePopupShell( title,
329 xmDialogShellWidgetClass,
330 parent,
331 XmNtitle, title,
332 XmNallowShellResize, False,
333 0
334 );
335 XtAddCallback( box, XmNpopdownCallback, cancel_cb, 0 );
336 XtAddCallback( box, XmNdestroyCallback, destroyed, 0 );
337
338 form = XtVaCreateWidget( "Tags",
339 xmFormWidgetClass,
340 box,
341 0
342 );
343
344 buttons = create_push_buttons( form, button_data, XtNumber(button_data) );
345 XtVaSetValues( buttons,
346 XmNbottomAttachment, XmATTACH_FORM,
347 0
348 );
349
350 form3 = XtVaCreateWidget( "form",
351 xmFormWidgetClass,
352 form,
353 XmNleftAttachment, XmATTACH_FORM,
354 XmNrightAttachment, XmATTACH_FORM,
355 XmNbottomAttachment, XmATTACH_WIDGET,
356 XmNbottomWidget, buttons,
357 0
358 );
359
360 form2 = XtVaCreateWidget( "form",
361 xmFormWidgetClass,
362 form,
363 XmNtopAttachment, XmATTACH_FORM,
364 XmNleftAttachment, XmATTACH_FORM,
365 XmNrightAttachment, XmATTACH_FORM,
366 XmNbottomAttachment, XmATTACH_WIDGET,
367 XmNbottomWidget, form3,
368 0
369 );
370
371 db_list = XtVaCreateManagedWidget( "list",
372 xmListWidgetClass,
373 form2,
374 XmNtopAttachment, XmATTACH_FORM,
375 XmNleftAttachment, XmATTACH_POSITION,
376 XmNleftPosition, 20,
377 XmNrightAttachment, XmATTACH_FORM,
378 XmNbottomAttachment, XmATTACH_FORM,
379 #if defined(SelfTest)
380 XmNvisibleItemCount, 5,
381 #endif
382 XmNselectionPolicy, XmSINGLE_SELECT,
383 0
384 );
385 XtAddCallback( db_list, XmNsingleSelectionCallback, set_text_field, 0 );
386 XtAddCallback( db_list, XmNdefaultActionCallback, go_to_tag, 0 );
387
388 XtVaCreateManagedWidget( "Tag Stack",
389 xmLabelGadgetClass,
390 form2,
391 XmNtopAttachment, XmATTACH_FORM,
392 XmNbottomAttachment, XmATTACH_FORM,
393 XmNleftAttachment, XmATTACH_FORM,
394 XmNrightAttachment, XmATTACH_POSITION,
395 XmNrightPosition, 20,
396 XmNalignment, XmALIGNMENT_END,
397 0
398 );
399
400 XtVaCreateManagedWidget( "Tag",
401 xmLabelGadgetClass,
402 form3,
403 XmNtopAttachment, XmATTACH_FORM,
404 XmNbottomAttachment, XmATTACH_FORM,
405 XmNleftAttachment, XmATTACH_FORM,
406 XmNrightAttachment, XmATTACH_POSITION,
407 XmNrightPosition, 20,
408 XmNalignment, XmALIGNMENT_END,
409 0
410 );
411
412 db_text = XtVaCreateManagedWidget( "text",
413 xmTextFieldWidgetClass,
414 form3,
415 XmNtopAttachment, XmATTACH_FORM,
416 XmNbottomAttachment, XmATTACH_FORM,
417 XmNrightAttachment, XmATTACH_FORM,
418 XmNleftAttachment, XmATTACH_POSITION,
419 XmNleftPosition, 20,
420 0
421 );
422 XtAddCallback( db_text, XmNactivateCallback, go_to_tag, 0 );
423
424 /* keep this global, we might destroy it later */
425 db_tabs = form;
426
427 /* done */
428 XtManageChild( form3 );
429 XtManageChild( form2 );
430 return form;
431 }
432
433
434
435 /* module entry point
436 * __vi_show_tags_dialog( parent, title )
437 */
438
439 #if defined(__STDC__)
__vi_show_tags_dialog(Widget parent,String title)440 void __vi_show_tags_dialog( Widget parent, String title )
441 #else
442 void __vi_show_tags_dialog( parent, title )
443 Widget parent;
444 String title;
445 #endif
446 {
447 Widget db = create_tags_dialog( parent, title ),
448 shell = XtParent(db);
449
450 XtManageChild( db );
451
452 /* get the current window's text */
453 __vi_set_tag_text( (String) __vi_get_word_at_caret( NULL ) );
454
455 /* TODO: ask vi core for the current tag stack now */
456
457 /* leave this guy up (or just raise it) */
458 XtPopup( shell, XtGrabNone );
459 XMapRaised( XtDisplay( shell ), XtWindow( shell ) );
460
461 active = True;
462 }
463
464
465
466 #if defined(SelfTest)
467
468 #if XtSpecificationRelease == 4
469 #define ArgcType Cardinal *
470 #else
471 #define ArgcType int *
472 #endif
473
add_a_tag(Widget w)474 static void add_a_tag( Widget w )
475 {
476 static String tags[] = { "first", "second", "this is the third" };
477 static int i = 0;
478
479 __vi_push_tag( tags[i] );
480 i = (i+1) % XtNumber(tags);
481 }
482
483 #if defined(__STDC__)
show_tags(Widget w,XtPointer data,XtPointer cbs)484 static void show_tags( Widget w, XtPointer data, XtPointer cbs )
485 #else
486 static void show_tags( w, data, cbs )
487 Widget w;
488 XtPointer data;
489 XtPointer cbs;
490 #endif
491 {
492 __vi_show_tags_dialog( data, "Tags" );
493 }
494
main(int argc,char * argv[])495 main( int argc, char *argv[] )
496 {
497 XtAppContext ctx;
498 Widget top_level, rc, button;
499 extern exit();
500
501 /* create a top-level shell for the window manager */
502 top_level = XtVaAppInitialize( &ctx,
503 argv[0],
504 NULL, 0, /* options */
505 (ArgcType) &argc,
506 argv, /* might get modified */
507 NULL,
508 NULL
509 );
510
511 rc = XtVaCreateManagedWidget( "rc",
512 xmRowColumnWidgetClass,
513 top_level,
514 0
515 );
516
517 button = XtVaCreateManagedWidget( "Pop up tags dialog",
518 xmPushButtonGadgetClass,
519 rc,
520 0
521 );
522 XtAddCallback( button, XmNactivateCallback, show_tags, rc );
523
524 button = XtVaCreateManagedWidget( "Add a tag",
525 xmPushButtonGadgetClass,
526 rc,
527 0
528 );
529 XtAddCallback( button, XmNactivateCallback, add_a_tag, rc );
530
531 button = XtVaCreateManagedWidget( "Quit",
532 xmPushButtonGadgetClass,
533 rc,
534 0
535 );
536 XtAddCallback( button, XmNactivateCallback, exit, 0 );
537
538 XtRealizeWidget(top_level);
539 XtAppMainLoop(ctx);
540 }
541 #endif
542