Commit | Line | Data |
---|---|---|
708cba75 WJ |
1 | /*- |
2 | * This code is derived from software copyrighted by the Free Software | |
3 | * Foundation. | |
4 | * | |
5 | * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. | |
6 | * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. | |
7 | * | |
8 | * static char rcsid[] = "$Header: xgdb.c,v 1.9 90/12/16 16:01:05 van Exp $"; | |
9 | */ | |
10 | ||
11 | #ifndef lint | |
12 | static char sccsid[] = "@(#)xgdb.c 6.3 (Berkeley) 5/8/91"; | |
13 | #endif /* not lint */ | |
14 | ||
15 | /* | |
16 | * Interface from GDB to X windows. Copyright (C) 1987 Free Software | |
17 | * Foundation, Inc. | |
18 | * | |
19 | * GDB is distributed in the hope that it will be useful, but WITHOUT ANY | |
20 | * WARRANTY. No author or distributor accepts responsibility to anyone for | |
21 | * the consequences of using it or for whether it serves any particular | |
22 | * purpose or works at all, unless he says so in writing. Refer to the GDB | |
23 | * General Public License for full details. | |
24 | * | |
25 | * Everyone is granted permission to copy, modify and redistribute GDB, but only | |
26 | * under the conditions described in the GDB General Public License. A copy | |
27 | * of this license is supposed to have been given to you along with GDB so | |
28 | * you can know your rights and responsibilities. It should be in a file | |
29 | * named COPYING. Among other things, the copyright notice and this notice | |
30 | * must be preserved on all copies. | |
31 | * | |
32 | * In other words, go ahead and share GDB, but don't try to stop anyone else | |
33 | * from sharing it farther. Help stamp out software hoarding! | |
34 | */ | |
35 | ||
36 | /* | |
37 | * Original version was contributed by Derek Beatty, 30 June 87. | |
38 | * This version is essentially a re-write of the original by Van | |
39 | * Jacobson (van@helios.ee.lbl.gov), Nov, 90. | |
40 | */ | |
41 | ||
42 | #include "defs.h" | |
43 | #include "param.h" | |
44 | #include "symtab.h" | |
45 | #include "frame.h" | |
46 | ||
47 | extern int stop_breakpoint; | |
48 | ||
49 | #include <X11/IntrinsicP.h> | |
50 | #include <X11/StringDefs.h> | |
51 | #include <X11/Xaw/AsciiSink.h> | |
52 | #include <X11/Xaw/AsciiText.h> | |
53 | #include <X11/Xaw/Box.h> | |
54 | #include <X11/Xaw/Command.h> | |
55 | #include <X11/Xaw/Label.h> | |
56 | #include <X11/Xaw/Paned.h> | |
57 | #include <X11/Xaw/Text.h> | |
58 | ||
59 | #include <stdio.h> | |
60 | #include <ctype.h> | |
61 | #include <sys/file.h> | |
62 | #include <sys/errno.h> | |
63 | ||
64 | extern int errno; | |
65 | extern char *getenv(); | |
66 | extern char *malloc(); | |
67 | extern void bcopy(); | |
68 | extern int select(); | |
69 | ||
70 | extern int get_filename_and_charpos(); | |
71 | extern int source_line_charpos(); | |
72 | extern int source_charpos_line(); | |
73 | extern void execute_command(); | |
74 | extern void error_no_arg(); | |
75 | extern void add_com(); | |
76 | ||
77 | /* The X display where the window appears. */ | |
78 | ||
79 | static char *displayname; | |
80 | static Display *display; | |
81 | ||
82 | static XtAppContext app_context; | |
83 | ||
84 | /* Windows manipulated by this package. */ | |
85 | ||
86 | static Widget main_widget; | |
87 | static Widget containing_widget; | |
88 | static Widget source_name_widget; | |
89 | static Widget source_text_widget; | |
90 | static Widget button_box_widget; | |
91 | ||
92 | /* Source text display. */ | |
93 | ||
94 | static struct frame_info *last_fi; | |
95 | static CORE_ADDR last_pc; | |
96 | static struct symtab *last_cur_symtab; | |
97 | static int last_cur_line; | |
98 | ||
99 | static int source_window_line; | |
100 | static char *source_window_file; | |
101 | static struct symtab *source_window_symtab; | |
102 | ||
103 | static char version_label[64]; | |
104 | extern char *version; | |
105 | ||
106 | /* Forward declarations */ | |
107 | ||
108 | static Widget create_text_widget(); | |
109 | ||
110 | static int | |
111 | safe_strcmp(a, b) | |
112 | register char *a, *b; | |
113 | { | |
114 | register int i; | |
115 | ||
116 | if (a == b) | |
117 | return (0); | |
118 | if (!a && b) | |
119 | return (1); | |
120 | if (a && !b) | |
121 | return (-1); | |
122 | return (strcmp(a, b)); | |
123 | } | |
124 | ||
125 | ||
126 | /* Display an appropriate piece of source code in the source window. */ | |
127 | ||
128 | void | |
129 | xgdb_display_source() | |
130 | { | |
131 | char *filename = NULL; | |
132 | struct symtab_and_line get_selected_frame_sal(); | |
133 | struct symtab_and_line sal; | |
134 | struct frame_info *fi; | |
135 | ||
136 | /* Do nothing if called before we are initialized */ | |
137 | ||
138 | if (!containing_widget) | |
139 | return; | |
140 | ||
141 | /* | |
142 | * Figure out what to display (the appropriate hooks to tell | |
143 | * us don't exist so we guess): If there's a current frame | |
144 | * and it or its pc changed from the last time we were here, | |
145 | * display appropriate source line. Otherwise if the current | |
146 | * source symtab or line is different, display that line. | |
147 | * Otherwise nothing changed so leave the display alone. | |
148 | */ | |
149 | fi = get_frame_info(selected_frame); | |
150 | if (fi && (fi != last_fi || fi->pc != last_pc)) { | |
151 | last_fi = fi; | |
152 | last_pc = fi->pc; | |
153 | sal = find_pc_line(fi->pc, fi->next_frame); | |
154 | if (sal.symtab == NULL) { /* XXX */ | |
155 | sal.symtab = current_source_symtab; | |
156 | sal.line = current_source_line; | |
157 | } | |
158 | current_source_symtab = sal.symtab; | |
159 | current_source_line = sal.line; | |
160 | } else if (current_source_symtab != last_cur_symtab || | |
161 | current_source_line != last_cur_line) { | |
162 | sal.symtab = last_cur_symtab = current_source_symtab; | |
163 | sal.line = last_cur_line = current_source_line; | |
164 | } else | |
165 | return; | |
166 | /* | |
167 | * Do a path search and get the exact filename of this source file. | |
168 | * Also scan it and find its source lines if not already done. | |
169 | */ | |
170 | if (sal.symtab && filename == NULL) { | |
171 | if (get_filename_and_charpos(sal.symtab, sal.line, &filename)) | |
172 | /* line numbers may have changed - force highlight */ | |
173 | source_window_line = -1; | |
174 | } | |
175 | ||
176 | /* | |
177 | * If the source window is wrong, destroy it and make a new one. | |
178 | */ | |
179 | if (safe_strcmp(filename, source_window_file)) { | |
180 | Arg args[1]; | |
181 | Widget src = XawTextGetSource(source_text_widget); | |
182 | ||
183 | if (filename) { | |
184 | XtSetArg(args[0], XtNstring, filename); | |
185 | XtSetValues(src, args, XtNumber(args)); | |
186 | args[0].name = XtNlabel; | |
187 | XtSetValues(source_name_widget, args, XtNumber(args)); | |
188 | } else { | |
189 | XtSetArg(args[0], XtNstring, "/dev/null"); | |
190 | XtSetValues(src, args, XtNumber(args)); | |
191 | XtSetArg(args[0], XtNlabel, ""); | |
192 | XtSetValues(source_name_widget, args, XtNumber(args)); | |
193 | } | |
194 | if (source_window_file) | |
195 | free(source_window_file); | |
196 | source_window_file = filename; | |
197 | source_window_line = sal.line + 1; /* force highlight */ | |
198 | } | |
199 | if (sal.symtab && source_window_line != sal.line) { | |
200 | /* | |
201 | * Update display and cursor positions as necessary. | |
202 | * Cursor should be placed on line sal.line. | |
203 | */ | |
204 | XawTextPosition l, r; | |
205 | ||
206 | source_window_symtab = sal.symtab; | |
207 | source_window_line = sal.line; | |
208 | l = source_line_charpos(source_window_symtab, sal.line); | |
209 | r = source_line_charpos(source_window_symtab, sal.line + 1); | |
210 | if (r < l) | |
211 | r = l + 1; | |
212 | XawTextSetSelection(source_text_widget, l, r); | |
213 | XawTextScrollToLine(source_text_widget, l, 10, 3); | |
214 | XawTextSetInsertionPoint(source_text_widget, l); | |
215 | } | |
216 | } | |
217 | ||
218 | ||
219 | /* | |
220 | * Handlers for buttons. | |
221 | */ | |
222 | ||
223 | static int | |
224 | current_lineno() | |
225 | { | |
226 | XawTextPosition start, finish; | |
227 | ||
228 | XawTextGetSelectionPos(source_text_widget, &start, &finish); | |
229 | if (start >= finish) | |
230 | start = XawTextGetInsertionPoint(source_text_widget); | |
231 | ||
232 | return (source_charpos_line(source_window_symtab, start)); | |
233 | } | |
234 | ||
235 | static char * | |
236 | append_selection(cp) | |
237 | char *cp; | |
238 | { | |
239 | int len; | |
240 | XawTextPosition l, r; | |
241 | ||
242 | XawTextGetSelectionPos(source_text_widget, &l, &r); | |
243 | if ((len = r - l) > 0) { | |
244 | Widget src = XawTextGetSource(source_text_widget); | |
245 | ||
246 | while (len > 0) { | |
247 | XawTextBlock tb; | |
248 | ||
249 | XawTextSourceRead(src, l, &tb, len); | |
250 | bcopy(tb.ptr, cp, tb.length); | |
251 | cp += tb.length; | |
252 | len -= tb.length; | |
253 | } | |
254 | if (cp[-1] == 0) | |
255 | --cp; | |
256 | } | |
257 | return (cp); | |
258 | } | |
259 | ||
260 | static char * | |
261 | append_selection_word(cp) | |
262 | register char *cp; | |
263 | { | |
264 | register int len; | |
265 | XawTextPosition l, r; | |
266 | XawTextBlock tb; | |
267 | register char c; | |
268 | register Widget src = XawTextGetSource(source_text_widget); | |
269 | ||
270 | XawTextGetSelectionPos(source_text_widget, &l, &r); | |
271 | if ((len = r - l) <= 0) { | |
272 | l = XawTextGetInsertionPoint(source_text_widget); | |
273 | len = 128; /* XXX */ | |
274 | ||
275 | /* might have clicked in middle of word -- back up to start */ | |
276 | for ( ; l > 0; --l) { | |
277 | XawTextSourceRead(src, l - 1, &tb, 1); | |
278 | c = tb.ptr[0]; | |
279 | if (! isalnum(c) && c != '_' && c != '$') | |
280 | break; | |
281 | } | |
282 | } | |
283 | while (len > 0) { | |
284 | char *sp; | |
285 | int i; | |
286 | ||
287 | XawTextSourceRead(src, l, &tb, len); | |
288 | for (sp = tb.ptr, i = tb.length; --i >= 0; ) { | |
289 | c = *sp++; | |
290 | if (!isalnum(c) && c != '_' && c != '$') | |
291 | return (cp); | |
292 | *cp++ = c; | |
293 | } | |
294 | len -= tb.length; | |
295 | } | |
296 | return (cp); | |
297 | } | |
298 | ||
299 | static char * | |
300 | append_selection_expr(cp) | |
301 | char *cp; | |
302 | { | |
303 | int len; | |
304 | XawTextPosition l, r; | |
305 | Widget src = XawTextGetSource(source_text_widget); | |
306 | XawTextBlock tb; | |
307 | char *sp; | |
308 | char c; | |
309 | ||
310 | XawTextGetSelectionPos(source_text_widget, &l, &r); | |
311 | if (r > l) | |
312 | return (append_selection(cp)); | |
313 | ||
314 | l = XawTextGetInsertionPoint(source_text_widget); | |
315 | ||
316 | /* might have clicked in middle of word -- back up to start */ | |
317 | for ( ; l > 0; --l) { | |
318 | XawTextSourceRead(src, l - 1, &tb, 1); | |
319 | c = tb.ptr[0]; | |
320 | if (! isalnum(c) && c != '_' && c != '$') | |
321 | break; | |
322 | } | |
323 | ||
324 | len = 128; /* XXX */ | |
325 | while (len > 0) { | |
326 | int i; | |
327 | char pstack[64]; | |
328 | int pcnt = 0; | |
329 | ||
330 | XawTextSourceRead(src, l, &tb, len); | |
331 | for (sp = tb.ptr, i = tb.length; --i >= 0; ) { | |
332 | switch (c = *sp++) { | |
333 | case '\n': | |
334 | case ';': | |
335 | return (cp); | |
336 | case '=': | |
337 | if (cp[-1] != '=') | |
338 | return (cp - 1); | |
339 | if (len == 128) | |
340 | return (cp); | |
341 | break; | |
342 | case ',': | |
343 | if (pcnt <= 0) | |
344 | return (cp); | |
345 | break; | |
346 | case '(': | |
347 | pstack[pcnt] = ')'; | |
348 | if (++pcnt >= sizeof(pstack)) | |
349 | return (cp); | |
350 | break; | |
351 | case '[': | |
352 | pstack[pcnt] = ']'; | |
353 | if (++pcnt >= sizeof(pstack)) | |
354 | return (cp); | |
355 | break; | |
356 | case ')': | |
357 | case ']': | |
358 | if (--pcnt < 0 || pstack[pcnt] != c) | |
359 | return (cp); | |
360 | break; | |
361 | } | |
362 | *cp++ = c; | |
363 | } | |
364 | len -= tb.length; | |
365 | } | |
366 | return (cp); | |
367 | } | |
368 | ||
369 | static int input_avail; /* XXX kluge: do_command sets this when command | |
370 | * data from button is avaialble to force top level | |
371 | * to break out of its loop. */ | |
372 | /* | |
373 | * Handle a button by running the command COMMAND. | |
374 | */ | |
375 | static void | |
376 | do_command(w, command, call_data) | |
377 | Widget w; | |
378 | register char *command; | |
379 | caddr_t call_data; | |
380 | { | |
381 | char cmd_line[256]; | |
382 | char buf[256]; | |
383 | register char *out = cmd_line; | |
384 | char *cp; | |
385 | register char c; | |
386 | extern char *finish_command_input(); | |
387 | ||
388 | while (c = *command++) { | |
389 | if (c == '%') { | |
390 | switch (*command++) { | |
391 | case 's': /* current selection */ | |
392 | out = append_selection(out); | |
393 | break; | |
394 | case 'S': /* 1st selected "word" at curor */ | |
395 | out = append_selection_word(out); | |
396 | break; | |
397 | case 'e': /* echo cmd before executing */ | |
398 | break; | |
399 | case 'E': /* 1st selected expression at curor */ | |
400 | out = append_selection_expr(out); | |
401 | break; | |
402 | ||
403 | case 'l': /* current line number */ | |
404 | (void) sprintf(buf, "%d", current_lineno()); | |
405 | for (cp = buf; c = *cp++; *out++ = c) | |
406 | ; | |
407 | break; | |
408 | case 'L': /* line we're stopped at */ | |
409 | (void) sprintf(buf, "%d", source_window_line); | |
410 | for (cp = buf; c = *cp++; *out++ = c) | |
411 | ; | |
412 | break; | |
413 | case 'f': /* current file name */ | |
414 | for (cp = source_window_symtab->filename; | |
415 | c = *cp++; *out++ = c) | |
416 | ; | |
417 | break; | |
418 | case 'b': /* break # we're stopped at */ | |
419 | if (stop_breakpoint <= 0) | |
420 | /* if no breakpoint, don't do cmd */ | |
421 | return; | |
422 | ||
423 | (void) sprintf(buf, "%d", stop_breakpoint); | |
424 | for (cp = buf; c = *cp++; *out++ = c) | |
425 | ; | |
426 | break; | |
427 | } | |
428 | } else | |
429 | *out++ = c; | |
430 | } | |
431 | *out = 0; | |
432 | reinitialize_more_filter(); | |
433 | /* have to exit via readline or tty modes stay messed up */ | |
434 | for (cp = cmd_line; c = *cp++; ) | |
435 | rl_stuff_char(c); | |
436 | rl_stuff_char('\n'); | |
437 | input_avail = 1; | |
438 | } | |
439 | ||
440 | /* | |
441 | * Define and display all the buttons. | |
442 | */ | |
443 | static void | |
444 | addbutton(parent, name, function, closure) | |
445 | Widget parent; | |
446 | char *name; | |
447 | void (*function) (); | |
448 | caddr_t closure; | |
449 | { | |
450 | static XtCallbackRec Callback[] = { | |
451 | {NULL, (caddr_t) NULL}, | |
452 | {NULL, (caddr_t) NULL}, | |
453 | }; | |
454 | static Arg commandArgs[] = { | |
455 | {XtNlabel, (XtArgVal) NULL}, | |
456 | {XtNcallback, (XtArgVal) Callback}, | |
457 | }; | |
458 | Widget w; | |
459 | char wname[128]; | |
460 | register char *cp; | |
461 | ||
462 | strcpy(wname, name); | |
463 | while ((cp = index(wname, '*')) || (cp = index(wname, '.'))) | |
464 | *cp -= 0x10; | |
465 | ||
466 | if (w = XtNameToWidget(parent, wname)) | |
467 | XtDestroyWidget(w); | |
468 | ||
469 | Callback[0].callback = (XtCallbackProc) function; | |
470 | Callback[0].closure = (caddr_t) closure; | |
471 | commandArgs[0].value = (XtArgVal) name; | |
472 | XtCreateManagedWidget(wname, commandWidgetClass, parent, | |
473 | commandArgs, XtNumber(commandArgs)); | |
474 | } | |
475 | ||
476 | /* | |
477 | * Create the button windows and store them in `buttons'. | |
478 | */ | |
479 | static void | |
480 | create_buttons(parent) | |
481 | Widget parent; | |
482 | { | |
483 | addbutton(parent, "quit", do_command, "quit"); | |
484 | } | |
485 | ||
486 | static void | |
487 | button_command(arg) | |
488 | char *arg; | |
489 | { | |
490 | char *label; | |
491 | unsigned int len; | |
492 | ||
493 | if (! arg) | |
494 | error_no_arg("button label and command"); | |
495 | ||
496 | for (len = strlen(arg); len > 0 && isspace(arg[len - 1]); --len) | |
497 | ; | |
498 | if (len == 0) | |
499 | error_no_arg("button label and command"); | |
500 | arg[len] = 0; | |
501 | ||
502 | /* make a copy of button label & command for toolkit to use */ | |
503 | label = malloc(len + 1); | |
504 | strcpy(label, arg); | |
505 | ||
506 | /* find the end of the label */ | |
507 | if (*label == '"') { | |
508 | if ((arg = index(++label, '"')) == 0) { | |
509 | printf("button label missing closing quote\n"); | |
510 | return; | |
511 | } | |
512 | *arg++ = 0; | |
513 | } else if (arg = index(label, ' ')) | |
514 | *arg++ = 0; | |
515 | else | |
516 | arg = label; | |
517 | ||
518 | while (*arg && isspace(*arg)) | |
519 | ++arg; | |
520 | ||
521 | addbutton(button_box_widget, label, do_command, arg); | |
522 | } | |
523 | ||
524 | static void | |
525 | button_delete_command(arg) | |
526 | char *arg; | |
527 | { | |
528 | unsigned int len; | |
529 | Widget w; | |
530 | register char *cp; | |
531 | ||
532 | if (! arg) | |
533 | error_no_arg("button name"); | |
534 | ||
535 | for (len = strlen(arg); len > 0 && isspace(arg[len - 1]); --len) | |
536 | ; | |
537 | if (len == 0) | |
538 | error_no_arg("button name"); | |
539 | arg[len] = 0; | |
540 | ||
541 | /* find the end of the label */ | |
542 | if (*arg == '"') { | |
543 | if ((cp = index(++arg, '"')) == 0) { | |
544 | printf("button label missing closing quote\n"); | |
545 | return; | |
546 | } | |
547 | *cp++ = 0; | |
548 | } | |
549 | while ((cp = index(arg, '*')) || (cp = index(arg, '.'))) | |
550 | *cp -= 0x10; | |
551 | ||
552 | if (w = XtNameToWidget(button_box_widget, arg)) | |
553 | XtDestroyWidget(w); | |
554 | } | |
555 | ||
556 | /* | |
557 | * Create a "label window" that just displays the string LABEL. | |
558 | */ | |
559 | static Widget | |
560 | create_label(name, label) | |
561 | char *name, *label; | |
562 | { | |
563 | Arg args[1]; | |
564 | Widget w; | |
565 | ||
566 | XtSetArg(args[0], XtNlabel, label); | |
567 | w = XtCreateManagedWidget(name, labelWidgetClass, containing_widget, | |
568 | args, XtNumber(args)); | |
569 | return (w); | |
570 | } | |
571 | ||
572 | /* | |
573 | * Create a subwindow of PARENT that displays and scrolls the contents of | |
574 | * file FILENAME. | |
575 | */ | |
576 | static Widget | |
577 | create_text_widget(parent, filename) | |
578 | Widget parent; | |
579 | char *filename; | |
580 | { | |
581 | static Arg arg[] = { | |
582 | {XtNstring, NULL}, | |
583 | {XtNtype, XawAsciiFile}, | |
584 | {XtNcursor, None}, | |
585 | }; | |
586 | Widget text_widget; | |
587 | ||
588 | arg[0].value = (XtArgVal)filename; | |
589 | text_widget = XtCreateManagedWidget("src", asciiTextWidgetClass, | |
590 | parent, arg, XtNumber(arg)); | |
591 | return (text_widget); | |
592 | } | |
593 | ||
594 | /* | |
595 | * Entry point to create the widgets representing our display. | |
596 | */ | |
597 | void | |
598 | xgdb_create_window() | |
599 | { | |
600 | /* initialize toolkit, setup defaults */ | |
601 | #ifdef notyet | |
602 | main_widget = XtAppInitialize(&app_context, "Xgdb", NULL, 0, | |
603 | argcptr, argv, NULL, NULL, 0); | |
604 | #else | |
605 | char *dummy_argv[] = { "xgdb", 0 }; | |
606 | int dummy_argc = 1; | |
607 | main_widget = XtAppInitialize(&app_context, "Xgdb", NULL, 0, | |
608 | &dummy_argc, dummy_argv, NULL, NULL, 0); | |
609 | #endif | |
610 | display = XtDisplay(main_widget); | |
611 | containing_widget = XtCreateManagedWidget("frame", panedWidgetClass, | |
612 | main_widget, NULL, 0); | |
613 | ||
614 | sprintf(version_label, "XGDB %s", version); | |
615 | button_box_widget = XtCreateManagedWidget("buttons", boxWidgetClass, | |
616 | containing_widget, NULL, 0); | |
617 | create_buttons(button_box_widget); | |
618 | source_name_widget = create_label("srcLabel", "No source file yet."); | |
619 | source_text_widget = create_text_widget(containing_widget, "/dev/null"); | |
620 | ||
621 | XtRealizeWidget(main_widget); | |
622 | XFlush(display); | |
623 | } | |
624 | ||
625 | /* | |
626 | * If we use an X window, the readline input loop is told to call | |
627 | * this function before reading a character from stdin. | |
628 | */ | |
629 | /*ARGSUSED*/ | |
630 | static void | |
631 | xgdb_window_hook() | |
632 | { | |
633 | register int inmask = 1 << fileno(stdin); | |
634 | register int xmask = 1 << ConnectionNumber(display); | |
635 | register int nfds, pend; | |
636 | int input_rfds; | |
637 | XEvent ev; | |
638 | ||
639 | /* | |
640 | * Display our current idea of the `interesting' source file then | |
641 | * loop, dispatching window events until data is available on | |
642 | * stdin. Then return so the input data can be processed. | |
643 | */ | |
644 | input_avail = 0; | |
645 | xgdb_display_source(); | |
646 | ||
647 | input_rfds = 0; | |
648 | while (input_avail == 0 && (input_rfds & inmask) == 0) { | |
649 | pend = XPending(display); | |
650 | if (!pend) { | |
651 | input_rfds = inmask | xmask; | |
652 | nfds = select(32, &input_rfds, 0, 0, | |
653 | (struct timeval *)0); | |
654 | if (nfds == -1 && errno == EINTR) | |
655 | continue; | |
656 | } | |
657 | if (pend || (input_rfds & xmask)) { | |
658 | XNextEvent(display, &ev); | |
659 | XtDispatchEvent(&ev); | |
660 | } | |
661 | } | |
662 | } | |
663 | ||
664 | void | |
665 | _initialize_xgdb() | |
666 | { | |
667 | extern void (*window_hook) (); | |
668 | extern int inhibit_windows; | |
669 | extern struct cmd_list_element *deletelist; | |
670 | ||
671 | if (inhibit_windows) | |
672 | return; | |
673 | ||
674 | if (! displayname) { | |
675 | displayname = getenv("DISPLAY"); | |
676 | if (! displayname) { | |
677 | fprintf(stderr, "xgdb: no display name\n"); | |
678 | inhibit_windows = 1; | |
679 | return; | |
680 | } | |
681 | } | |
682 | xgdb_create_window(); | |
683 | window_hook = xgdb_window_hook; | |
684 | add_com("button", class_support, button_command, | |
685 | "Add command button to xgdb window. First argument is button\n\ | |
686 | label, second is command associated with button. Command can\n\ | |
687 | include printf-like escapes:\n\ | |
688 | %s for current selection,\n\ | |
689 | %S for first 'word' of current selection,\n\ | |
690 | %e for current selection or expression at insertion pt,\n\ | |
691 | %E for current selection or expression at insertion pt,\n\ | |
692 | %l for current line number,\n\ | |
693 | %L for line program stopped at,\n\ | |
694 | %f for current file name,\n\ | |
695 | %b for current breakpoint number."); | |
696 | add_cmd("button", class_support, button_delete_command, | |
697 | "Delete a button from the xgdb window.\n\ | |
698 | Argument is name of button to be deleted.", | |
699 | &deletelist); | |
700 | } |