gdb-3.5
[deliverable/binutils-gdb.git] / gdb / xgdb.c
CommitLineData
7b4ac7e1 1/* Interface from GDB to X windows.
4187119d 2 Copyright (C) 1987, 1989 Free Software Foundation, Inc.
7b4ac7e1 3
4187119d 4This file is part of GDB.
7b4ac7e1 5
4187119d 6GDB is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
7b4ac7e1 10
4187119d 11GDB is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GDB; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
7b4ac7e1 19
20/* Original version was contributed by Derek Beatty, 30 June 87. */
21
7a67dd45 22#include <stdio.h>
7b4ac7e1 23#include "defs.h"
7b4ac7e1 24#include "param.h"
25#include "symtab.h"
26#include "frame.h"
27
3bf57d21 28#include <X11/IntrinsicP.h>
29#include <X11/StringDefs.h>
7b4ac7e1 30#include <X11/Label.h>
7b4ac7e1 31#include <X11/Command.h>
e91b87a3 32#include <X11/AsciiText.h>
3bf57d21 33#include <X11/Box.h>
34#include <X11/VPaned.h>
7b4ac7e1 35
7b4ac7e1 36
e91b87a3 37/*#define XtNfunction "function"*/
38
7b4ac7e1 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
45static 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
55static 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
e91b87a3 63Display *screen_display;
64
65#if 0
66/* The graphics context. */
67GC default_gc;
68#endif
7b4ac7e1 69
70/* Windows manipulated by this package. */
71
e91b87a3 72static Window icon_window;
3bf57d21 73static Widget main_widget;
7b4ac7e1 74static Widget containing_widget;
75static Widget source_name_widget;
76static Widget source_text_widget;
77static Widget exec_name_widget;
78static Widget button_box_widget;
79
80/* Source text display. */
81
82static struct symtab *source_window_symtab = 0;
83
84/* Forward declarations */
85
86static Widget create_text_widget ();
7b4ac7e1 87\f
88/* Display an appropriate piece of source code in the source window. */
89
90xgdb_display_source ()
91{
92 char *filename;
e91b87a3 93 static Arg labelArgs[1];
7b4ac7e1 94 int linenumbers_changed = 0;
e91b87a3 95 static int new = 1;
7b4ac7e1 96
97 struct symtab_and_line get_selected_frame_sal ();
98 struct symtab_and_line sal;
e91b87a3 99 struct frame_info *fi;
7b4ac7e1 100
e91b87a3 101 /* Do nothing if called before we are initialized or when there
102 is nothing to show. */
7b4ac7e1 103
e91b87a3 104 if (!containing_widget || !selected_frame) return;
7b4ac7e1 105
106 /* Get the symtab and line number of the selected frame. */
107
108 fi = get_frame_info (selected_frame);
e91b87a3 109 sal = find_pc_line (fi->pc, fi->next_frame);
7b4ac7e1 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 {
e91b87a3 133 static Arg fileArgs[1];
134 XtTextSource src;
135 new = 1;
7b4ac7e1 136 source_window_symtab = sal.symtab;
137
e91b87a3 138 src = XtTextGetSource(source_text_widget);
139 XtDiskSourceDestroy(src);
3bf57d21 140
7b4ac7e1 141 XtSetArg (fileArgs[0], XtNfile, filename);
e91b87a3 142 src = XtDiskSourceCreate(source_text_widget->core.parent, fileArgs, 1);
143 XtTextSetSource(source_text_widget, src, 0);
7b4ac7e1 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
e91b87a3 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 }
3bf57d21 187
e91b87a3 188 /* Set the text display cursor position within the text. */
3bf57d21 189
e91b87a3 190 XtSetArg (textArgs[0], XtNinsertPosition,
191 source_line_charpos (source_window_symtab, sal.line));
192 XtSetValues (source_text_widget, textArgs, XtNumber (textArgs));
193 }
7b4ac7e1 194}
195\f
196/* Display FILENAME in the title bar at bottom of window. */
197
198xgdb_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
209static char *prompt_string;
210
211static void
212print_prompt ()
213{
214 if (prompt_string)
e91b87a3 215 printf ("%s", prompt_string);
4187119d 216 fflush (stdout);
7b4ac7e1 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
225static void
e91b87a3 226print_button(w, starflag, call_data)
227Widget w;
228int starflag;
229caddr_t call_data;
7b4ac7e1 230{
231 int selected_length;
232 char *selected_text;
7b4ac7e1 233 char *cmd = starflag ? "print * " : "print ";
234 register int cmdlen = strlen (cmd);
235
3bf57d21 236 selected_text = XFetchBytes (screen_display, &selected_length);
7b4ac7e1 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
7b4ac7e1 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
258static void
e91b87a3 259breakpoint_button(w, runflag, call_data)
260Widget w;
261int runflag;
262caddr_t call_data;
7b4ac7e1 263{
264 XtTextPosition start, finish;
265
3bf57d21 266 XtTextGetSelectionPos (source_text_widget, &start, &finish);
7b4ac7e1 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
7b4ac7e1 283/* decide if a character is trash */
284static int
285garbage (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
297static void
298explicit_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
7b4ac7e1 329
330static void
e91b87a3 331do_command(w, command, call_data)
332Widget w;
333char *command;
334caddr_t call_data;
7b4ac7e1 335{
4187119d 336 char *copy = (char *) xmalloc (strlen (command) + 1);
337 strcpy (copy, command);
338 execute_command (copy, 0);
7b4ac7e1 339 xgdb_display_source ();
340 print_prompt ();
4187119d 341 free (copy);
7b4ac7e1 342}
343
7b4ac7e1 344static void
3bf57d21 345redisplay_button()
7b4ac7e1 346{
e91b87a3 347 xgdb_display_source();
7b4ac7e1 348}
349\f
350/* Define and display all the buttons. */
351
352static void
3bf57d21 353addbutton (parent, name, function, closure)
e91b87a3 354Widget parent;
355char *name;
356void (*function) ();
357caddr_t closure;
7b4ac7e1 358{
e91b87a3 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));
7b4ac7e1 373}
374
375/* Create the button windows and store them in `buttons'. */
376
377static void
378create_buttons (parent)
379 Widget parent;
380{
3bf57d21 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);
7b4ac7e1 387
3bf57d21 388 addbutton (parent, "print", print_button, 0);
389 addbutton (parent, "print*", print_button, 1);
7b4ac7e1 390
3bf57d21 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");
7b4ac7e1 395
3bf57d21 396 addbutton (parent, "up", do_command, "up");
397 addbutton (parent, "down", do_command, "down");
7b4ac7e1 398
3bf57d21 399 addbutton (parent, "redisplay", redisplay_button, NULL);
7b4ac7e1 400}
401\f
402/* Create a "label window" that just displays the string LABEL. */
403
404static Widget
405create_label (name, label)
406 char *name, *label;
407{
e91b87a3 408 static Arg labelArgs[2];
7b4ac7e1 409
410 XtSetArg (labelArgs[0], XtNname, name);
3bf57d21 411
e91b87a3 412 XtSetArg (labelArgs[1], XtNlabel, label);
413 return XtCreateManagedWidget ("label", labelWidgetClass, containing_widget,
414 labelArgs, XtNumber (labelArgs));
7b4ac7e1 415}
416
417/* Create a subwindow of PARENT that displays and scrolls the contents
418 of file FILENAME. */
419
420static Widget
421create_text_widget (parent, filename)
3bf57d21 422 Widget parent;
7b4ac7e1 423 char *filename;
424{
3bf57d21 425 static Arg fileArgs[3];
426 XtTextSource src;
427 XtTextSink sink;
4187119d 428 Widget text_widget;
429
430 text_widget = XtCreateManagedWidget ("disk", textWidgetClass,
431 parent, NULL, 0);
3bf57d21 432
7b4ac7e1 433 XtSetArg (fileArgs[0], XtNfile, filename);
3bf57d21 434 src = XtDiskSourceCreate(parent, fileArgs, 1);
435 sink = XtAsciiSinkCreate(parent, NULL, 0);
e91b87a3 436
3bf57d21 437 XtSetArg (fileArgs[0], XtNtextOptions, scrollVertical);
438 XtSetArg (fileArgs[1], XtNtextSource, src);
439 XtSetArg (fileArgs[2], XtNtextSink, sink);
4187119d 440 XtSetValues (text_widget, fileArgs, XtNumber (fileArgs));
441 return text_widget;
7b4ac7e1 442}
443\f
3bf57d21 444/* Entry point to create the widgets representing our display. */
e91b87a3 445
7b4ac7e1 446int
447xgdb_create_window ()
448{
e91b87a3 449 static Arg frameArgs[]= {
450 {XtNwidth, (XtArgVal) 600},
451 {XtNheight, (XtArgVal) 700},
452 };
3bf57d21 453 {
e91b87a3 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);
3bf57d21 460 }
7b4ac7e1 461
e91b87a3 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
3bf57d21 472 /* Create exec file name window and add */
e91b87a3 473 exec_name_widget = create_label ("Executable", "No executable specified.");
3bf57d21 474
475 /* Create window full of buttons. */
e91b87a3 476 button_box_widget = XtCreateManagedWidget ("buttonbox", boxWidgetClass,
477 containing_widget, NULL, 0);
3bf57d21 478 create_buttons (button_box_widget);
7b4ac7e1 479
7b4ac7e1 480 /* Create an empty source-display window and add to containing_widget */
481 source_text_widget = create_text_widget (containing_widget, "/dev/null");
482
e91b87a3 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. */
7b4ac7e1 489 {
e91b87a3 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);
7b4ac7e1 498 }
7b4ac7e1 499
e91b87a3 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
7b4ac7e1 544
7b4ac7e1 545 XFlush (screen_display);
e91b87a3 546
7b4ac7e1 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
554void
555xgdb_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;
e91b87a3 564
7b4ac7e1 565 while (! (rfds & inmask))
566 {
3bf57d21 567 pend = XPending (screen_display);
7b4ac7e1 568 if (!pend)
569 {
e91b87a3 570 rfds = inmask | xmask;
7b4ac7e1 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
e91b87a3 583
7b4ac7e1 584 before reading a command from stdin.
585 PROMPT is saved for later use so buttons can print a prompt-string. */
586
587void
588xgdb_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
e91b87a3 597_initialize_xgdb ()
7b4ac7e1 598{
599 extern void (*window_hook) ();
600 extern int inhibit_windows;
601
602 if (getenv ("DISPLAY") && ! inhibit_windows)
4187119d 603 {
604 if (xgdb_create_window ())
605 window_hook = xgdb_window_hook;
7b4ac7e1 606
4187119d 607 specify_exec_file_hook (xgdb_display_exec_file);
608 }
7b4ac7e1 609}
610
3bf57d21 611
This page took 0.047984 seconds and 4 git commands to generate.