1 /* Interface from GDB to X windows.
2 Copyright (C) 1987, 1989 Free Software Foundation, Inc.
4 This file is part of GDB.
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)
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.
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. */
20 /* Original version was contributed by Derek Beatty, 30 June 87. */
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>
34 #include <X11/VPaned.h>
37 /*#define XtNfunction "function"*/
39 /* Cursor used in GDB window. */
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};
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};
61 /* The X display on which the window appears. */
63 Display
*screen_display
;
66 /* The graphics context. */
70 /* Windows manipulated by this package. */
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
;
80 /* Source text display. */
82 static struct symtab
*source_window_symtab
= 0;
84 /* Forward declarations */
86 static Widget
create_text_widget ();
88 /* Display an appropriate piece of source code in the source window. */
90 xgdb_display_source ()
93 static Arg labelArgs
[1];
94 int linenumbers_changed
= 0;
97 struct symtab_and_line
get_selected_frame_sal ();
98 struct symtab_and_line sal
;
99 struct frame_info
*fi
;
101 /* Do nothing if called before we are initialized or when there
102 is nothing to show. */
104 if (!containing_widget
|| !selected_frame
) return;
106 /* Get the symtab and line number of the selected frame. */
108 fi
= get_frame_info (selected_frame
);
109 sal
= find_pc_line (fi
->pc
, fi
->next_frame
);
111 /* Strictly this is wrong, but better than a blank display */
113 if (sal
.symtab
== NULL
)
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
;
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. */
124 linenumbers_changed
= get_filename_and_charpos (sal
.symtab
, sal
.line
,
127 if (!filename
) sal
.symtab
= NULL
;
129 /* If the source window may be wrong, destroy it (and make a new one). */
131 if (linenumbers_changed
|| source_window_symtab
!= sal
.symtab
)
133 static Arg fileArgs
[1];
136 source_window_symtab
= sal
.symtab
;
138 src
= XtTextGetSource(source_text_widget
);
139 XtDiskSourceDestroy(src
);
141 XtSetArg (fileArgs
[0], XtNfile
, filename
);
142 src
= XtDiskSourceCreate(source_text_widget
->core
.parent
, fileArgs
, 1);
143 XtTextSetSource(source_text_widget
, src
, 0);
145 XtSetArg (labelArgs
[0], XtNlabel
,
146 filename
? filename
: "No source displayed.");
147 XtSetValues (source_name_widget
, labelArgs
, XtNumber (labelArgs
));
148 if (filename
) free (filename
);
151 /* Update display and cursor positions as necessary.
152 Cursor should be placed on line sal.line. */
155 static int top_line_number
, bottom_line_number
;
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
;
172 /* If appropriate, scroll the text display. */
173 if (sal
.line
< top_line_number
174 || sal
.line
> bottom_line_number
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
180 top_line_number
= (sal
.line
> 15) ? sal
.line
- 15 : 0;
181 bottom_line_number
= top_line_number
+ 35;
183 XtSetArg (textArgs
[0], XtNdisplayPosition
,
184 source_line_charpos (source_window_symtab
, top_line_number
));
185 XtSetValues (source_text_widget
, textArgs
, XtNumber (textArgs
));
188 /* Set the text display cursor position within the text. */
190 XtSetArg (textArgs
[0], XtNinsertPosition
,
191 source_line_charpos (source_window_symtab
, sal
.line
));
192 XtSetValues (source_text_widget
, textArgs
, XtNumber (textArgs
));
196 /* Display FILENAME in the title bar at bottom of window. */
198 xgdb_display_exec_file (filename
)
201 static Arg labelArgs
[1];
203 XtSetArg (labelArgs
[0], XtNlabel
, filename
);
204 XtSetValues (exec_name_widget
, labelArgs
, XtNumber (labelArgs
));
207 /* Do any necessary prompting, etc. */
209 static char *prompt_string
;
215 printf ("%s", prompt_string
);
219 /* Handlers for buttons. */
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. */
226 print_button(w
, starflag
, call_data
)
233 char *cmd
= starflag
? "print * " : "print ";
234 register int cmdlen
= strlen (cmd
);
236 selected_text
= XFetchBytes (screen_display
, &selected_length
);
239 char *line
= xmalloc (cmdlen
+ selected_length
+ 1);
241 strncpy (line
+ cmdlen
, selected_text
, selected_length
);
242 line
[cmdlen
+ selected_length
] = 0;
244 execute_command (line
, 0);
246 free (selected_text
);
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. */
259 breakpoint_button(w
, runflag
, call_data
)
264 XtTextPosition start
, finish
;
266 XtTextGetSelectionPos (source_text_widget
, &start
, &finish
);
267 if (!source_window_symtab
)
268 printf ("No source file displayed.\n");
271 set_breakpoint (source_window_symtab
,
272 source_charpos_line (source_window_symtab
, start
),
277 xgdb_display_source ();
283 /* decide if a character is trash */
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;
295 /* Set a breakpoint at the place specified by the "selection" in X. */
298 explicit_breakpoint_button ()
303 selected_text
= XFetchBytes (screen_display
, &selected_length
);
306 char *line
= (char *) xmalloc (selected_length
+ 6);
307 register char *p
, *sp
, *end
;
309 strcpy (line
, "break ");
311 /* Copy selection but exclude "garbage" characters. */
314 end
= p
+ selected_length
;
315 sp
= line
+ strlen (line
);
317 while (garbage (*p
) && p
!= end
) p
++;
318 while (!garbage (*p
) && p
!= end
)
322 execute_command (line
, 0);
323 free (selected_text
);
331 do_command(w
, command
, call_data
)
336 char *copy
= (char *) xmalloc (strlen (command
) + 1);
337 strcpy (copy
, command
);
338 execute_command (copy
, 0);
339 xgdb_display_source ();
347 xgdb_display_source();
350 /* Define and display all the buttons. */
353 addbutton (parent
, name
, function
, closure
)
359 static XtCallbackRec Callback
[] = {
360 {NULL
, (caddr_t
)NULL
},
361 {NULL
, (caddr_t
)NULL
},
363 static Arg commandArgs
[] = {
364 {XtNlabel
, (XtArgVal
)NULL
},
365 {XtNcallback
, (XtArgVal
)Callback
},
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
));
375 /* Create the button windows and store them in `buttons'. */
378 create_buttons (parent
)
381 addbutton (parent
, "run", do_command
, "run");
382 addbutton (parent
, "quit", do_command
, "quit");
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);
388 addbutton (parent
, "print", print_button
, 0);
389 addbutton (parent
, "print*", print_button
, 1);
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");
396 addbutton (parent
, "up", do_command
, "up");
397 addbutton (parent
, "down", do_command
, "down");
399 addbutton (parent
, "redisplay", redisplay_button
, NULL
);
402 /* Create a "label window" that just displays the string LABEL. */
405 create_label (name
, label
)
408 static Arg labelArgs
[2];
410 XtSetArg (labelArgs
[0], XtNname
, name
);
412 XtSetArg (labelArgs
[1], XtNlabel
, label
);
413 return XtCreateManagedWidget ("label", labelWidgetClass
, containing_widget
,
414 labelArgs
, XtNumber (labelArgs
));
417 /* Create a subwindow of PARENT that displays and scrolls the contents
421 create_text_widget (parent
, filename
)
425 static Arg fileArgs
[3];
430 text_widget
= XtCreateManagedWidget ("disk", textWidgetClass
,
433 XtSetArg (fileArgs
[0], XtNfile
, filename
);
434 src
= XtDiskSourceCreate(parent
, fileArgs
, 1);
435 sink
= XtAsciiSinkCreate(parent
, NULL
, 0);
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
));
444 /* Entry point to create the widgets representing our display. */
447 xgdb_create_window ()
449 static Arg frameArgs
[]= {
450 {XtNwidth
, (XtArgVal
) 600},
451 {XtNheight
, (XtArgVal
) 700},
459 main_widget
= XtInitialize ("xgdb", "XGdb", 0, 0, &dummy2
, dummy1
);
462 screen_display
= XtDisplay(main_widget
);
464 /* Create the containing_widget. */
466 containing_widget
= XtCreateManagedWidget ("frame", vPanedWidgetClass
, main_widget
,
467 frameArgs
, XtNumber (frameArgs
));
468 /* Create source file name window and add to containing_widget */
470 = create_label ("Source File", "No source file yet.");
472 /* Create exec file name window and add */
473 exec_name_widget
= create_label ("Executable", "No executable specified.");
475 /* Create window full of buttons. */
476 button_box_widget
= XtCreateManagedWidget ("buttonbox", boxWidgetClass
,
477 containing_widget
, NULL
, 0);
478 create_buttons (button_box_widget
);
480 /* Create an empty source-display window and add to containing_widget */
481 source_text_widget
= create_text_widget (containing_widget
, "/dev/null");
483 XSync(screen_display
, 0);
484 XtRealizeWidget(main_widget
);
487 default_gc
= XCreateGC (screen_display
, XtWindow(containing_widget
), 0, NULL
);
488 /* Create icon window. */
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
);
500 /* Now make the whole thing appear on the display. */
506 image
.width
= gdb_width
;
507 image
.height
= gdb_height
;
509 image
.format
= XYBitmap
;
510 image
.byte_order
= LSBFirst
;
511 image
.bitmap_unit
= 16;
512 image
.bitmap_bit_order
= LSBFirst
;
514 image
.bytes_per_line
= 2;
515 image
.bits_per_pixel
= 1;
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);
522 image
.data
= (char *) gdb_bits
;
523 XPutImage (screen_display
, pm1
, default_gc
, &image
, 0, 0, 0, 0,
524 gdb_width
, gdb_height
);
526 image
.data
= (char *) gdb_mask_bits
;
527 XPutImage (screen_display
, pm2
, default_gc
, &image
, 0, 0, 0, 0,
528 gdb_width
, gdb_height
);
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
);
537 XFreePixmap (screen_display
, pm1
);
538 XFreePixmap (screen_display
, pm2
);
540 XDefineCursor (screen_display
, containing_widget
, curse
);
541 XDefineCursor (screen_display
, icon_window
, curse
);
545 XFlush (screen_display
);
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. */
558 int inmask
= 1 << fileno (fp
);
559 int xmask
= 1 << ConnectionNumber (screen_display
);
565 while (! (rfds
& inmask
))
567 pend
= XPending (screen_display
);
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);
574 if (pend
|| rfds
& xmask
)
576 XNextEvent (screen_display
, &ev
);
577 XtDispatchEvent (&ev
);
582 /* If we use an X window, the GDB command loop is told to call this function
584 before reading a command from stdin.
585 PROMPT is saved for later use so buttons can print a prompt-string. */
588 xgdb_window_hook (infile
, prompt
)
592 prompt_string
= prompt
;
593 xgdb_display_source ();
594 xgdb_dispatch (infile
);
599 extern void (*window_hook
) ();
600 extern int inhibit_windows
;
602 if (getenv ("DISPLAY") && ! inhibit_windows
)
604 if (xgdb_create_window ())
605 window_hook
= xgdb_window_hook
;
607 specify_exec_file_hook (xgdb_display_exec_file
);