/* Interface from GDB to X windows.
Copyright (C) 1987, 1989 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Original version was contributed by Derek Beatty, 30 June 87. */
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/AsciiText.h>
/*#define XtNfunction "function"*/
/* Cursor used in GDB window. */
static short gdb_bits[] = {
0x0000, 0x0140, 0x0220, 0x0220,
0x23e2, 0x13e4, 0x09c8, 0x0ff8,
0x0220, 0x3ffe, 0x0630, 0x03e0,
0x0220, 0x1ffc, 0x2632, 0x01c0};
#define gdb_mask_width 16
#define gdb_mask_height 16
static short gdb_mask_bits[] = {
0x0360, 0x07f0, 0x07f0, 0x77f7,
0x7fff, 0x7fff, 0x1ffc, 0x1ffc,
0x7fff, 0x7fff, 0x7fff, 0x0ff8,
0x3ffe, 0x7fff, 0x7fff, 0x7fff};
/* The X display on which the window appears. */
/* The graphics context. */
/* Windows manipulated by this package. */
static Window icon_window;
static Widget main_widget;
static Widget containing_widget;
static Widget source_name_widget;
static Widget source_text_widget;
static Widget exec_name_widget;
static Widget button_box_widget;
/* Source text display. */
static struct symtab *source_window_symtab = 0;
/* Forward declarations */
static Widget create_text_widget ();
/* Display an appropriate piece of source code in the source window. */
int linenumbers_changed = 0;
struct symtab_and_line get_selected_frame_sal ();
struct symtab_and_line sal;
/* Do nothing if called before we are initialized or when there
if (!containing_widget || !selected_frame) return;
/* Get the symtab and line number of the selected frame. */
fi = get_frame_info (selected_frame);
sal = find_pc_line (fi->pc, fi->next_frame);
/* Strictly this is wrong, but better than a blank display */
sal.symtab = current_source_symtab;
/* current_source_line may be off by a small number like 4 */
sal.line = current_source_line;
/* Do a path search and get the exact filename of this source file.
Also scan it and find its source lines if not already done. */
linenumbers_changed = get_filename_and_charpos (sal.symtab, sal.line,
if (!filename) sal.symtab = NULL;
/* If the source window may be wrong, destroy it (and make a new one). */
if (linenumbers_changed || source_window_symtab != sal.symtab)
source_window_symtab = sal.symtab;
src = XtTextGetSource(source_text_widget);
XtDiskSourceDestroy(src);
XtSetArg (fileArgs[0], XtNfile, filename);
src = XtDiskSourceCreate(source_text_widget->core.parent, fileArgs, 1);
XtTextSetSource(source_text_widget, src, 0);
XtSetArg (labelArgs[0], XtNlabel,
filename ? filename : "No source displayed.");
XtSetValues (source_name_widget, labelArgs, XtNumber (labelArgs));
if (filename) free (filename);
/* Update display and cursor positions as necessary.
Cursor should be placed on line sal.line. */
static int top_line_number, bottom_line_number;
/* Get positions of start of display, and caret */
XtSetArg (textArgs[0], XtNdisplayPosition, NULL);
XtGetValues (source_text_widget, textArgs, XtNumber (textArgs));
new_top = source_charpos_line (source_window_symtab,
(int) textArgs[0].value);
bottom_line_number += new_top - top_line_number;
top_line_number = new_top;
/* If appropriate, scroll the text display. */
if (sal.line < top_line_number
|| sal.line > bottom_line_number
/* yes, these magic numbers are ugly, but I don't know how
* to get the height of a text widget in a V11-portable way
top_line_number = (sal.line > 15) ? sal.line - 15 : 0;
bottom_line_number = top_line_number + 35;
XtSetArg (textArgs[0], XtNdisplayPosition,
source_line_charpos (source_window_symtab, top_line_number));
XtSetValues (source_text_widget, textArgs, XtNumber (textArgs));
/* Set the text display cursor position within the text. */
XtSetArg (textArgs[0], XtNinsertPosition,
source_line_charpos (source_window_symtab, sal.line));
XtSetValues (source_text_widget, textArgs, XtNumber (textArgs));
/* Display FILENAME in the title bar at bottom of window. */
xgdb_display_exec_file (filename)
XtSetArg (labelArgs[0], XtNlabel, filename);
XtSetValues (exec_name_widget, labelArgs, XtNumber (labelArgs));
/* Do any necessary prompting, etc. */
static char *prompt_string;
printf ("%s", prompt_string);
/* Handlers for buttons. */
/* Subroutine used by "print" and "print*" buttons.
STARFLAG is 1 for print*, 0 for print.
Get the "selection" from X and use it as the operand of a print command. */
print_button(w, starflag, call_data)
char *cmd = starflag ? "print * " : "print ";
register int cmdlen = strlen (cmd);
selected_text = XFetchBytes (screen_display, &selected_length);
char *line = xmalloc (cmdlen + selected_length + 1);
strncpy (line + cmdlen, selected_text, selected_length);
line[cmdlen + selected_length] = 0;
execute_command (line, 0);
/* Subroutine used by "stop at" and "go till" buttons.
Set a breakpoint at the position indicated by the "selection"
in the source window, and, if RUNFLAG is nonzero, continue. */
breakpoint_button(w, runflag, call_data)
XtTextPosition start, finish;
XtTextGetSelectionPos (source_text_widget, &start, &finish);
if (!source_window_symtab)
printf ("No source file displayed.\n");
set_breakpoint (source_window_symtab,
source_charpos_line (source_window_symtab, start),
/* decide if a character is trash */
if ('a' <= c && c <= 'z') return 0;
if ('A' <= c && c <= 'Z') return 0;
if ('0' <= c && c <= '9') return 0;
/* Set a breakpoint at the place specified by the "selection" in X. */
explicit_breakpoint_button ()
selected_text = XFetchBytes (screen_display, &selected_length);
char *line = (char *) xmalloc (selected_length + 6);
register char *p, *sp, *end;
/* Copy selection but exclude "garbage" characters. */
end = p + selected_length;
sp = line + strlen (line);
while (garbage (*p) && p != end) p++;
while (!garbage (*p) && p != end)
execute_command (line, 0);
do_command(w, command, call_data)
char *copy = (char *) xmalloc (strlen (command) + 1);
execute_command (copy, 0);
/* Define and display all the buttons. */
addbutton (parent, name, function, closure)
static XtCallbackRec Callback[] = {
static Arg commandArgs[] = {
{XtNlabel, (XtArgVal)NULL},
{XtNcallback, (XtArgVal)Callback},
Callback[0].callback = (XtCallbackProc)function;
Callback[0].closure = (caddr_t)closure;
commandArgs[0].value = (XtArgVal)name;
XtCreateManagedWidget (name, commandWidgetClass, parent,
commandArgs, XtNumber(commandArgs));
/* Create the button windows and store them in `buttons'. */
addbutton (parent, "run", do_command, "run");
addbutton (parent, "quit", do_command, "quit");
addbutton (parent, "break in", explicit_breakpoint_button, NULL);
addbutton (parent, "break at", breakpoint_button, 0);
addbutton (parent, "go until", breakpoint_button, 1);
addbutton (parent, "print", print_button, 0);
addbutton (parent, "print*", print_button, 1);
addbutton (parent, "next", do_command, "next");
addbutton (parent, "step", do_command, "step");
addbutton (parent, "cont", do_command, "cont");
addbutton (parent, "finish", do_command, "finish");
addbutton (parent, "up", do_command, "up");
addbutton (parent, "down", do_command, "down");
addbutton (parent, "redisplay", redisplay_button, NULL);
/* Create a "label window" that just displays the string LABEL. */
create_label (name, label)
XtSetArg (labelArgs[0], XtNname, name);
XtSetArg (labelArgs[1], XtNlabel, label);
return XtCreateManagedWidget ("label", labelWidgetClass, containing_widget,
labelArgs, XtNumber (labelArgs));
/* Create a subwindow of PARENT that displays and scrolls the contents
create_text_widget (parent, filename)
text_widget = XtCreateManagedWidget ("disk", textWidgetClass,
XtSetArg (fileArgs[0], XtNfile, filename);
src = XtDiskSourceCreate(parent, fileArgs, 1);
sink = XtAsciiSinkCreate(parent, NULL, 0);
XtSetArg (fileArgs[0], XtNtextOptions, scrollVertical);
XtSetArg (fileArgs[1], XtNtextSource, src);
XtSetArg (fileArgs[2], XtNtextSink, sink);
XtSetValues (text_widget, fileArgs, XtNumber (fileArgs));
/* Entry point to create the widgets representing our display. */
static Arg frameArgs[]= {
{XtNwidth, (XtArgVal) 600},
{XtNheight, (XtArgVal) 700},
main_widget = XtInitialize ("xgdb", "XGdb", 0, 0, &dummy2, dummy1);
screen_display = XtDisplay(main_widget);
/* Create the containing_widget. */
containing_widget = XtCreateManagedWidget ("frame", vPanedWidgetClass, main_widget,
frameArgs, XtNumber (frameArgs));
/* Create source file name window and add to containing_widget */
= create_label ("Source File", "No source file yet.");
/* Create exec file name window and add */
exec_name_widget = create_label ("Executable", "No executable specified.");
/* Create window full of buttons. */
button_box_widget = XtCreateManagedWidget ("buttonbox", boxWidgetClass,
containing_widget, NULL, 0);
create_buttons (button_box_widget);
/* Create an empty source-display window and add to containing_widget */
source_text_widget = create_text_widget (containing_widget, "/dev/null");
XSync(screen_display, 0);
XtRealizeWidget(main_widget);
default_gc = XCreateGC (screen_display, XtWindow(containing_widget), 0, NULL);
/* Create icon window. */
void (*compiler_bug) () = deiconify_button;
XtSetArg (iconArgs[0], XtNlabel, "(gdb)");
XtSetArg (iconArgs[1], XtNfunction, compiler_bug);
icon_window = XtCreateWidget ("Icon", commandWidgetClass,
iconArgs, XtNumber (iconArgs));
XMoveWindow (screen_display, icon_window, 100, 100); /* HACK */
XSetIconWindow (screen_display, containing_widget, icon_window);
/* Now make the whole thing appear on the display. */
image.height = gdb_height;
image.byte_order = LSBFirst;
image.bitmap_bit_order = LSBFirst;
image.bytes_per_line = 2;
image.bits_per_pixel = 1;
pm1 = XCreatePixmap (screen_display, DefaultScreen (screen_display),
gdb_width, gdb_height, 1);
pm2 = XCreatePixmap (screen_display, DefaultScreen (screen_display),
gdb_width, gdb_height, 1);
image.data = (char *) gdb_bits;
XPutImage (screen_display, pm1, default_gc, &image, 0, 0, 0, 0,
image.data = (char *) gdb_mask_bits;
XPutImage (screen_display, pm2, default_gc, &image, 0, 0, 0, 0,
curse = XCreatePixmapCursor (screen_display, pm1, pm2,
BlackPixel (screen_display,
DefaultScreen (screen_display)),
WhitePixel (screen_display,
DefaultScreen (screen_display)),
XFreePixmap (screen_display, pm1);
XFreePixmap (screen_display, pm2);
XDefineCursor (screen_display, containing_widget, curse);
XDefineCursor (screen_display, icon_window, curse);
/* xgdb_dispatch -- Loop, dispatching on window events,
until data is available on FP (which is normally stdin).
Then return, so the data on FP can be processed. */
int inmask = 1 << fileno (fp);
int xmask = 1 << ConnectionNumber (screen_display);
while (! (rfds & inmask))
pend = XPending (screen_display);
/* this isn't right for 4.3 but it works 'cuz of 4.2 compatibility */
nfds = select (32, &rfds, 0, 0, (struct timeval *) 0);
if (pend || rfds & xmask)
XNextEvent (screen_display, &ev);
/* If we use an X window, the GDB command loop is told to call this function
before reading a command from stdin.
PROMPT is saved for later use so buttons can print a prompt-string. */
xgdb_window_hook (infile, prompt)
extern void (*window_hook) ();
extern int inhibit_windows;
if (getenv ("DISPLAY") && ! inhibit_windows)
if (xgdb_create_window ())
window_hook = xgdb_window_hook;
specify_exec_file_hook (xgdb_display_exec_file);