gdb-3.5
[deliverable/binutils-gdb.git] / gdb / xgdb.c
1 /* Interface from GDB to X windows.
2 Copyright (C) 1987, 1989 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
6 GDB is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
10
11 GDB is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GDB; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 /* Original version was contributed by Derek Beatty, 30 June 87. */
21
22 #include <stdio.h>
23 #include "defs.h"
24 #include "param.h"
25 #include "symtab.h"
26 #include "frame.h"
27
28 #include <X11/IntrinsicP.h>
29 #include <X11/StringDefs.h>
30 #include <X11/Label.h>
31 #include <X11/Command.h>
32 #include <X11/AsciiText.h>
33 #include <X11/Box.h>
34 #include <X11/VPaned.h>
35
36
37 /*#define XtNfunction "function"*/
38
39 /* Cursor used in GDB window. */
40
41 #define gdb_width 16
42 #define gdb_height 16
43 #define gdb_x_hot 7
44 #define gdb_y_hot 0
45 static short gdb_bits[] = {
46 0x0000, 0x0140, 0x0220, 0x0220,
47 0x23e2, 0x13e4, 0x09c8, 0x0ff8,
48 0x0220, 0x3ffe, 0x0630, 0x03e0,
49 0x0220, 0x1ffc, 0x2632, 0x01c0};
50
51 #define gdb_mask_width 16
52 #define gdb_mask_height 16
53 #define gdb_mask_x_hot 7
54 #define gdb_mask_y_hot 0
55 static short gdb_mask_bits[] = {
56 0x0360, 0x07f0, 0x07f0, 0x77f7,
57 0x7fff, 0x7fff, 0x1ffc, 0x1ffc,
58 0x7fff, 0x7fff, 0x7fff, 0x0ff8,
59 0x3ffe, 0x7fff, 0x7fff, 0x7fff};
60
61 /* The X display on which the window appears. */
62
63 Display *screen_display;
64
65 #if 0
66 /* The graphics context. */
67 GC default_gc;
68 #endif
69
70 /* Windows manipulated by this package. */
71
72 static Window icon_window;
73 static Widget main_widget;
74 static Widget containing_widget;
75 static Widget source_name_widget;
76 static Widget source_text_widget;
77 static Widget exec_name_widget;
78 static Widget button_box_widget;
79
80 /* Source text display. */
81
82 static struct symtab *source_window_symtab = 0;
83
84 /* Forward declarations */
85
86 static Widget create_text_widget ();
87 \f
88 /* Display an appropriate piece of source code in the source window. */
89
90 xgdb_display_source ()
91 {
92 char *filename;
93 static Arg labelArgs[1];
94 int linenumbers_changed = 0;
95 static int new = 1;
96
97 struct symtab_and_line get_selected_frame_sal ();
98 struct symtab_and_line sal;
99 struct frame_info *fi;
100
101 /* Do nothing if called before we are initialized or when there
102 is nothing to show. */
103
104 if (!containing_widget || !selected_frame) return;
105
106 /* Get the symtab and line number of the selected frame. */
107
108 fi = get_frame_info (selected_frame);
109 sal = find_pc_line (fi->pc, fi->next_frame);
110
111 /* Strictly this is wrong, but better than a blank display */
112
113 if (sal.symtab == NULL)
114 {
115 sal.symtab = current_source_symtab;
116 /* current_source_line may be off by a small number like 4 */
117 sal.line = current_source_line;
118 }
119
120 /* Do a path search and get the exact filename of this source file.
121 Also scan it and find its source lines if not already done. */
122
123 if (sal.symtab)
124 linenumbers_changed = get_filename_and_charpos (sal.symtab, sal.line,
125 &filename);
126
127 if (!filename) sal.symtab = NULL;
128
129 /* If the source window may be wrong, destroy it (and make a new one). */
130
131 if (linenumbers_changed || source_window_symtab != sal.symtab)
132 {
133 static Arg fileArgs[1];
134 XtTextSource src;
135 new = 1;
136 source_window_symtab = sal.symtab;
137
138 src = XtTextGetSource(source_text_widget);
139 XtDiskSourceDestroy(src);
140
141 XtSetArg (fileArgs[0], XtNfile, filename);
142 src = XtDiskSourceCreate(source_text_widget->core.parent, fileArgs, 1);
143 XtTextSetSource(source_text_widget, src, 0);
144
145 XtSetArg (labelArgs[0], XtNlabel,
146 filename ? filename : "No source displayed.");
147 XtSetValues (source_name_widget, labelArgs, XtNumber (labelArgs));
148 if (filename) free (filename);
149 }
150
151 /* Update display and cursor positions as necessary.
152 Cursor should be placed on line sal.line. */
153
154 {
155 static int top_line_number, bottom_line_number;
156 int current_top;
157 Arg textArgs[1];
158
159 if (! new)
160 {
161 int new_top;
162
163 /* Get positions of start of display, and caret */
164 XtSetArg (textArgs[0], XtNdisplayPosition, NULL);
165 XtGetValues (source_text_widget, textArgs, XtNumber (textArgs));
166 new_top = source_charpos_line (source_window_symtab,
167 (int) textArgs[0].value);
168 bottom_line_number += new_top - top_line_number;
169 top_line_number = new_top;
170 }
171
172 /* If appropriate, scroll the text display. */
173 if (sal.line < top_line_number
174 || sal.line > bottom_line_number
175 || new)
176 {
177 /* yes, these magic numbers are ugly, but I don't know how
178 * to get the height of a text widget in a V11-portable way
179 */
180 top_line_number = (sal.line > 15) ? sal.line - 15 : 0;
181 bottom_line_number = top_line_number + 35;
182
183 XtSetArg (textArgs[0], XtNdisplayPosition,
184 source_line_charpos (source_window_symtab, top_line_number));
185 XtSetValues (source_text_widget, textArgs, XtNumber (textArgs));
186 }
187
188 /* Set the text display cursor position within the text. */
189
190 XtSetArg (textArgs[0], XtNinsertPosition,
191 source_line_charpos (source_window_symtab, sal.line));
192 XtSetValues (source_text_widget, textArgs, XtNumber (textArgs));
193 }
194 }
195 \f
196 /* Display FILENAME in the title bar at bottom of window. */
197
198 xgdb_display_exec_file (filename)
199 char *filename;
200 {
201 static Arg labelArgs[1];
202
203 XtSetArg (labelArgs[0], XtNlabel, filename);
204 XtSetValues (exec_name_widget, labelArgs, XtNumber (labelArgs));
205 }
206
207 /* Do any necessary prompting, etc. */
208
209 static char *prompt_string;
210
211 static void
212 print_prompt ()
213 {
214 if (prompt_string)
215 printf ("%s", prompt_string);
216 fflush (stdout);
217 }
218
219 /* Handlers for buttons. */
220
221 /* Subroutine used by "print" and "print*" buttons.
222 STARFLAG is 1 for print*, 0 for print.
223 Get the "selection" from X and use it as the operand of a print command. */
224
225 static void
226 print_button(w, starflag, call_data)
227 Widget w;
228 int starflag;
229 caddr_t call_data;
230 {
231 int selected_length;
232 char *selected_text;
233 char *cmd = starflag ? "print * " : "print ";
234 register int cmdlen = strlen (cmd);
235
236 selected_text = XFetchBytes (screen_display, &selected_length);
237 if (selected_length)
238 {
239 char *line = xmalloc (cmdlen + selected_length + 1);
240 strcpy (line, cmd);
241 strncpy (line + cmdlen, selected_text, selected_length);
242 line[cmdlen + selected_length] = 0;
243
244 execute_command (line, 0);
245
246 free (selected_text);
247 free (line);
248 }
249
250 print_prompt ();
251 }
252
253 \f
254 /* Subroutine used by "stop at" and "go till" buttons.
255 Set a breakpoint at the position indicated by the "selection"
256 in the source window, and, if RUNFLAG is nonzero, continue. */
257
258 static void
259 breakpoint_button(w, runflag, call_data)
260 Widget w;
261 int runflag;
262 caddr_t call_data;
263 {
264 XtTextPosition start, finish;
265
266 XtTextGetSelectionPos (source_text_widget, &start, &finish);
267 if (!source_window_symtab)
268 printf ("No source file displayed.\n");
269 else
270 {
271 set_breakpoint (source_window_symtab,
272 source_charpos_line (source_window_symtab, start),
273 runflag);
274 if (runflag)
275 {
276 cont_command (0, 1);
277 xgdb_display_source ();
278 }
279 }
280 print_prompt ();
281 }
282
283 /* decide if a character is trash */
284 static int
285 garbage (c)
286 char c;
287 {
288 if ('a' <= c && c <= 'z') return 0;
289 if ('A' <= c && c <= 'Z') return 0;
290 if ('0' <= c && c <= '9') return 0;
291 if (c == '_') return 0;
292 return 1;
293 }
294
295 /* Set a breakpoint at the place specified by the "selection" in X. */
296
297 static void
298 explicit_breakpoint_button ()
299 {
300 int selected_length;
301 char *selected_text;
302
303 selected_text = XFetchBytes (screen_display, &selected_length);
304 if (selected_length)
305 {
306 char *line = (char *) xmalloc (selected_length + 6);
307 register char *p, *sp, *end;
308
309 strcpy (line, "break ");
310
311 /* Copy selection but exclude "garbage" characters. */
312
313 p = selected_text;
314 end = p + selected_length;
315 sp = line + strlen (line);
316
317 while (garbage (*p) && p != end) p++;
318 while (!garbage (*p) && p != end)
319 *sp++ = *p++;
320 *sp = 0;
321
322 execute_command (line, 0);
323 free (selected_text);
324 free (line);
325 }
326 print_prompt ();
327 }
328 \f
329
330 static void
331 do_command(w, command, call_data)
332 Widget w;
333 char *command;
334 caddr_t call_data;
335 {
336 char *copy = (char *) xmalloc (strlen (command) + 1);
337 strcpy (copy, command);
338 execute_command (copy, 0);
339 xgdb_display_source ();
340 print_prompt ();
341 free (copy);
342 }
343
344 static void
345 redisplay_button()
346 {
347 xgdb_display_source();
348 }
349 \f
350 /* Define and display all the buttons. */
351
352 static void
353 addbutton (parent, name, function, closure)
354 Widget parent;
355 char *name;
356 void (*function) ();
357 caddr_t closure;
358 {
359 static XtCallbackRec Callback[] = {
360 {NULL, (caddr_t)NULL},
361 {NULL, (caddr_t)NULL},
362 };
363 static Arg commandArgs[] = {
364 {XtNlabel, (XtArgVal)NULL},
365 {XtNcallback, (XtArgVal)Callback},
366 };
367
368 Callback[0].callback = (XtCallbackProc)function;
369 Callback[0].closure = (caddr_t)closure;
370 commandArgs[0].value = (XtArgVal)name;
371 XtCreateManagedWidget (name, commandWidgetClass, parent,
372 commandArgs, XtNumber(commandArgs));
373 }
374
375 /* Create the button windows and store them in `buttons'. */
376
377 static void
378 create_buttons (parent)
379 Widget parent;
380 {
381 addbutton (parent, "run", do_command, "run");
382 addbutton (parent, "quit", do_command, "quit");
383
384 addbutton (parent, "break in", explicit_breakpoint_button, NULL);
385 addbutton (parent, "break at", breakpoint_button, 0);
386 addbutton (parent, "go until", breakpoint_button, 1);
387
388 addbutton (parent, "print", print_button, 0);
389 addbutton (parent, "print*", print_button, 1);
390
391 addbutton (parent, "next", do_command, "next");
392 addbutton (parent, "step", do_command, "step");
393 addbutton (parent, "cont", do_command, "cont");
394 addbutton (parent, "finish", do_command, "finish");
395
396 addbutton (parent, "up", do_command, "up");
397 addbutton (parent, "down", do_command, "down");
398
399 addbutton (parent, "redisplay", redisplay_button, NULL);
400 }
401 \f
402 /* Create a "label window" that just displays the string LABEL. */
403
404 static Widget
405 create_label (name, label)
406 char *name, *label;
407 {
408 static Arg labelArgs[2];
409
410 XtSetArg (labelArgs[0], XtNname, name);
411
412 XtSetArg (labelArgs[1], XtNlabel, label);
413 return XtCreateManagedWidget ("label", labelWidgetClass, containing_widget,
414 labelArgs, XtNumber (labelArgs));
415 }
416
417 /* Create a subwindow of PARENT that displays and scrolls the contents
418 of file FILENAME. */
419
420 static Widget
421 create_text_widget (parent, filename)
422 Widget parent;
423 char *filename;
424 {
425 static Arg fileArgs[3];
426 XtTextSource src;
427 XtTextSink sink;
428 Widget text_widget;
429
430 text_widget = XtCreateManagedWidget ("disk", textWidgetClass,
431 parent, NULL, 0);
432
433 XtSetArg (fileArgs[0], XtNfile, filename);
434 src = XtDiskSourceCreate(parent, fileArgs, 1);
435 sink = XtAsciiSinkCreate(parent, NULL, 0);
436
437 XtSetArg (fileArgs[0], XtNtextOptions, scrollVertical);
438 XtSetArg (fileArgs[1], XtNtextSource, src);
439 XtSetArg (fileArgs[2], XtNtextSink, sink);
440 XtSetValues (text_widget, fileArgs, XtNumber (fileArgs));
441 return text_widget;
442 }
443 \f
444 /* Entry point to create the widgets representing our display. */
445
446 int
447 xgdb_create_window ()
448 {
449 static Arg frameArgs[]= {
450 {XtNwidth, (XtArgVal) 600},
451 {XtNheight, (XtArgVal) 700},
452 };
453 {
454 char *dummy1[2];
455 int dummy2 = 1;
456
457 dummy1[0] = "xgdb";
458 dummy1[1] = NULL;
459 main_widget = XtInitialize ("xgdb", "XGdb", 0, 0, &dummy2, dummy1);
460 }
461
462 screen_display = XtDisplay(main_widget);
463
464 /* Create the containing_widget. */
465
466 containing_widget = XtCreateManagedWidget ("frame", vPanedWidgetClass, main_widget,
467 frameArgs, XtNumber (frameArgs));
468 /* Create source file name window and add to containing_widget */
469 source_name_widget
470 = create_label ("Source File", "No source file yet.");
471
472 /* Create exec file name window and add */
473 exec_name_widget = create_label ("Executable", "No executable specified.");
474
475 /* Create window full of buttons. */
476 button_box_widget = XtCreateManagedWidget ("buttonbox", boxWidgetClass,
477 containing_widget, NULL, 0);
478 create_buttons (button_box_widget);
479
480 /* Create an empty source-display window and add to containing_widget */
481 source_text_widget = create_text_widget (containing_widget, "/dev/null");
482
483 XSync(screen_display, 0);
484 XtRealizeWidget(main_widget);
485
486 #if 0
487 default_gc = XCreateGC (screen_display, XtWindow(containing_widget), 0, NULL);
488 /* Create icon window. */
489 {
490 static Arg iconArgs[2];
491 void (*compiler_bug) () = deiconify_button;
492 XtSetArg (iconArgs[0], XtNlabel, "(gdb)");
493 XtSetArg (iconArgs[1], XtNfunction, compiler_bug);
494 icon_window = XtCreateWidget ("Icon", commandWidgetClass,
495 iconArgs, XtNumber (iconArgs));
496 XMoveWindow (screen_display, icon_window, 100, 100); /* HACK */
497 XSetIconWindow (screen_display, containing_widget, icon_window);
498 }
499
500 /* Now make the whole thing appear on the display. */
501 {
502 Pixmap pm1, pm2;
503 XImage image;
504 Cursor curse;
505
506 image.width = gdb_width;
507 image.height = gdb_height;
508 image.xoffset = 0;
509 image.format = XYBitmap;
510 image.byte_order = LSBFirst;
511 image.bitmap_unit = 16;
512 image.bitmap_bit_order = LSBFirst;
513 image.depth = 1;
514 image.bytes_per_line = 2;
515 image.bits_per_pixel = 1;
516
517 pm1 = XCreatePixmap (screen_display, DefaultScreen (screen_display),
518 gdb_width, gdb_height, 1);
519 pm2 = XCreatePixmap (screen_display, DefaultScreen (screen_display),
520 gdb_width, gdb_height, 1);
521
522 image.data = (char *) gdb_bits;
523 XPutImage (screen_display, pm1, default_gc, &image, 0, 0, 0, 0,
524 gdb_width, gdb_height);
525
526 image.data = (char *) gdb_mask_bits;
527 XPutImage (screen_display, pm2, default_gc, &image, 0, 0, 0, 0,
528 gdb_width, gdb_height);
529
530 curse = XCreatePixmapCursor (screen_display, pm1, pm2,
531 BlackPixel (screen_display,
532 DefaultScreen (screen_display)),
533 WhitePixel (screen_display,
534 DefaultScreen (screen_display)),
535 gdb_x_hot, gdb_y_hot);
536
537 XFreePixmap (screen_display, pm1);
538 XFreePixmap (screen_display, pm2);
539
540 XDefineCursor (screen_display, containing_widget, curse);
541 XDefineCursor (screen_display, icon_window, curse);
542 }
543 #endif 0
544
545 XFlush (screen_display);
546
547 return 1;
548 }
549 \f
550 /* xgdb_dispatch -- Loop, dispatching on window events,
551 until data is available on FP (which is normally stdin).
552 Then return, so the data on FP can be processed. */
553
554 void
555 xgdb_dispatch (fp)
556 FILE *fp;
557 {
558 int inmask = 1 << fileno (fp);
559 int xmask = 1 << ConnectionNumber (screen_display);
560 int rfds = 0;
561 int nfds;
562 XEvent ev;
563 int pend;
564
565 while (! (rfds & inmask))
566 {
567 pend = XPending (screen_display);
568 if (!pend)
569 {
570 rfds = inmask | xmask;
571 /* this isn't right for 4.3 but it works 'cuz of 4.2 compatibility */
572 nfds = select (32, &rfds, 0, 0, (struct timeval *) 0);
573 }
574 if (pend || rfds & xmask)
575 {
576 XNextEvent (screen_display, &ev);
577 XtDispatchEvent (&ev);
578 }
579 }
580 }
581 \f
582 /* If we use an X window, the GDB command loop is told to call this function
583
584 before reading a command from stdin.
585 PROMPT is saved for later use so buttons can print a prompt-string. */
586
587 void
588 xgdb_window_hook (infile, prompt)
589 FILE *infile;
590 char *prompt;
591 {
592 prompt_string = prompt;
593 xgdb_display_source ();
594 xgdb_dispatch (infile);
595 }
596
597 _initialize_xgdb ()
598 {
599 extern void (*window_hook) ();
600 extern int inhibit_windows;
601
602 if (getenv ("DISPLAY") && ! inhibit_windows)
603 {
604 if (xgdb_create_window ())
605 window_hook = xgdb_window_hook;
606
607 specify_exec_file_hook (xgdb_display_exec_file);
608 }
609 }
610
611
This page took 0.044042 seconds and 4 git commands to generate.