|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T x
Length: 15985 (0x3e71) Types: TextFile Names: »xgdb.c«
└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89 └─⟦9ba874778⟧ »./gdb-3.4.tar.Z« └─⟦d4a85eeeb⟧ └─⟦this⟧ »dist-gdb/xgdb.c«
/* 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) any later version. 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 "defs.h" #include "param.h" #include "symtab.h" #include "frame.h" #include <X11/IntrinsicP.h> #include <X11/StringDefs.h> #include <X11/Label.h> #include <X11/Command.h> #include <X11/AsciiText.h> #include <X11/Box.h> #include <X11/VPaned.h> #include <stdio.h> /*#define XtNfunction "function"*/ /* Cursor used in GDB window. */ #define gdb_width 16 #define gdb_height 16 #define gdb_x_hot 7 #define gdb_y_hot 0 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 #define gdb_mask_x_hot 7 #define gdb_mask_y_hot 0 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. */ Display *screen_display; #if 0 /* The graphics context. */ GC default_gc; #endif /* 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 (); \f /* Display an appropriate piece of source code in the source window. */ xgdb_display_source () { char *filename; static Arg labelArgs[1]; int linenumbers_changed = 0; static int new = 1; struct symtab_and_line get_selected_frame_sal (); struct symtab_and_line sal; struct frame_info *fi; /* Do nothing if called before we are initialized or when there is nothing to show. */ 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 */ if (sal.symtab == NULL) { 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. */ if (sal.symtab) linenumbers_changed = get_filename_and_charpos (sal.symtab, sal.line, &filename); 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) { static Arg fileArgs[1]; XtTextSource src; new = 1; 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; int current_top; Arg textArgs[1]; if (! new) { int new_top; /* 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 || new) { /* 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)); } } \f /* Display FILENAME in the title bar at bottom of window. */ xgdb_display_exec_file (filename) char *filename; { static Arg labelArgs[1]; XtSetArg (labelArgs[0], XtNlabel, filename); XtSetValues (exec_name_widget, labelArgs, XtNumber (labelArgs)); } /* Do any necessary prompting, etc. */ static char *prompt_string; static void print_prompt () { if (prompt_string) printf ("%s", prompt_string); fflush (stdout); } /* 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. */ static void print_button(w, starflag, call_data) Widget w; int starflag; caddr_t call_data; { int selected_length; char *selected_text; char *cmd = starflag ? "print * " : "print "; register int cmdlen = strlen (cmd); selected_text = XFetchBytes (screen_display, &selected_length); if (selected_length) { char *line = xmalloc (cmdlen + selected_length + 1); strcpy (line, cmd); strncpy (line + cmdlen, selected_text, selected_length); line[cmdlen + selected_length] = 0; execute_command (line, 0); free (selected_text); free (line); } print_prompt (); } \f /* 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. */ static void breakpoint_button(w, runflag, call_data) Widget w; int runflag; caddr_t call_data; { XtTextPosition start, finish; XtTextGetSelectionPos (source_text_widget, &start, &finish); if (!source_window_symtab) printf ("No source file displayed.\n"); else { set_breakpoint (source_window_symtab, source_charpos_line (source_window_symtab, start), runflag); if (runflag) { cont_command (0, 1); xgdb_display_source (); } } print_prompt (); } /* decide if a character is trash */ static int garbage (c) char c; { if ('a' <= c && c <= 'z') return 0; if ('A' <= c && c <= 'Z') return 0; if ('0' <= c && c <= '9') return 0; if (c == '_') return 0; return 1; } /* Set a breakpoint at the place specified by the "selection" in X. */ static void explicit_breakpoint_button () { int selected_length; char *selected_text; selected_text = XFetchBytes (screen_display, &selected_length); if (selected_length) { char *line = (char *) xmalloc (selected_length + 6); register char *p, *sp, *end; strcpy (line, "break "); /* Copy selection but exclude "garbage" characters. */ p = selected_text; end = p + selected_length; sp = line + strlen (line); while (garbage (*p) && p != end) p++; while (!garbage (*p) && p != end) *sp++ = *p++; *sp = 0; execute_command (line, 0); free (selected_text); free (line); } print_prompt (); } \f static void do_command(w, command, call_data) Widget w; char *command; caddr_t call_data; { char *copy = (char *) xmalloc (strlen (command) + 1); strcpy (copy, command); execute_command (copy, 0); xgdb_display_source (); print_prompt (); free (copy); } static void redisplay_button() { xgdb_display_source(); } \f /* Define and display all the buttons. */ static void addbutton (parent, name, function, closure) Widget parent; char *name; void (*function) (); caddr_t closure; { static XtCallbackRec Callback[] = { {NULL, (caddr_t)NULL}, {NULL, (caddr_t)NULL}, }; 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'. */ static void create_buttons (parent) Widget parent; { 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); } \f /* Create a "label window" that just displays the string LABEL. */ static Widget create_label (name, label) char *name, *label; { static Arg labelArgs[2]; 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 of file FILENAME. */ static Widget create_text_widget (parent, filename) Widget parent; char *filename; { static Arg fileArgs[3]; XtTextSource src; XtTextSink sink; Widget text_widget; text_widget = XtCreateManagedWidget ("disk", textWidgetClass, parent, NULL, 0); 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)); return text_widget; } \f /* Entry point to create the widgets representing our display. */ int xgdb_create_window () { static Arg frameArgs[]= { {XtNwidth, (XtArgVal) 600}, {XtNheight, (XtArgVal) 700}, }; { char *dummy1[2]; int dummy2 = 1; dummy1[0] = "xgdb"; dummy1[1] = NULL; 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 */ source_name_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); #if 0 default_gc = XCreateGC (screen_display, XtWindow(containing_widget), 0, NULL); /* Create icon window. */ { static Arg iconArgs[2]; 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. */ { Pixmap pm1, pm2; XImage image; Cursor curse; image.width = gdb_width; image.height = gdb_height; image.xoffset = 0; image.format = XYBitmap; image.byte_order = LSBFirst; image.bitmap_unit = 16; image.bitmap_bit_order = LSBFirst; image.depth = 1; 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, gdb_width, gdb_height); image.data = (char *) gdb_mask_bits; XPutImage (screen_display, pm2, default_gc, &image, 0, 0, 0, 0, gdb_width, gdb_height); curse = XCreatePixmapCursor (screen_display, pm1, pm2, BlackPixel (screen_display, DefaultScreen (screen_display)), WhitePixel (screen_display, DefaultScreen (screen_display)), gdb_x_hot, gdb_y_hot); XFreePixmap (screen_display, pm1); XFreePixmap (screen_display, pm2); XDefineCursor (screen_display, containing_widget, curse); XDefineCursor (screen_display, icon_window, curse); } #endif 0 XFlush (screen_display); return 1; } \f /* 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. */ void xgdb_dispatch (fp) FILE *fp; { int inmask = 1 << fileno (fp); int xmask = 1 << ConnectionNumber (screen_display); int rfds = 0; int nfds; XEvent ev; int pend; while (! (rfds & inmask)) { pend = XPending (screen_display); if (!pend) { rfds = inmask | xmask; /* 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); XtDispatchEvent (&ev); } } } \f /* 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. */ void xgdb_window_hook (infile, prompt) FILE *infile; char *prompt; { prompt_string = prompt; xgdb_display_source (); xgdb_dispatch (infile); } _initialize_xgdb () { 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); } }