home *** CD-ROM | disk | FTP | other *** search
- // $Id: buttons.C,v 1.123 1998/11/24 15:08:29 zeller Exp $ -*- C++ -*-
- // DDD buttons
-
- // Copyright (C) 1996-1998 Technische Universitaet Braunschweig, Germany.
- // Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
- //
- // This file is part of DDD.
- //
- // DDD 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 2 of the License, or (at your option) any later version.
- //
- // DDD 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 DDD -- see the file COPYING.
- // If not, write to the Free Software Foundation, Inc.,
- // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- //
- // DDD is the data display debugger.
- // For details, see the DDD World-Wide-Web page,
- // `http://www.cs.tu-bs.de/softech/ddd/',
- // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
-
- char buttons_rcsid[] =
- "$Id: buttons.C,v 1.123 1998/11/24 15:08:29 zeller Exp $";
-
- #ifdef __GNUG__
- #pragma implementation
- #endif
-
- #include "buttons.h"
-
- #include "AppData.h"
- #include "Command.h"
- #include "DataDisp.h"
- #include "Delay.h"
- #include "DestroyCB.h"
- #include "GDBAgent.h"
- #include "HelpCB.h"
- #include "LessTifH.h"
- #include "MakeMenu.h"
- #include "SourceView.h"
- #include "StringSA.h"
- #include "TimeOut.h"
- #include "UndoBuffer.h"
- #include "args.h"
- #include "bool.h"
- #include "charsets.h"
- #include "comm-manag.h"
- #include "cook.h"
- #include "ctrl.h"
- #include "ddd.h"
- #include "disp-read.h"
- #include "editing.h"
- #include "fortranize.h"
- #include "history.h"
- #include "isid.h"
- #include "question.h"
- #include "regexps.h"
- #include "select.h"
- #include "settings.h"
- #include "shorten.h"
- #include "source.h"
- #include "status.h"
- #include "string-fun.h"
- #include "verify.h"
- #include "windows.h"
- #include "wm.h"
-
- #include <Xm/Xm.h>
- #include <Xm/Label.h>
- #include <Xm/Frame.h>
- #include <Xm/RowColumn.h>
- #include <Xm/SelectioB.h>
- #include <Xm/PushB.h>
- #include <Xm/ToggleB.h>
- #include <Xm/Text.h>
- #include <ctype.h>
-
-
- //-----------------------------------------------------------------------------
- // Data
- //-----------------------------------------------------------------------------
-
- // Maximum length of value in value tip and in status line
- int max_value_tip_length = 20;
- int max_value_doc_length = 128;
-
-
- //-----------------------------------------------------------------------------
- // Button callbacks
- //-----------------------------------------------------------------------------
-
- static void YnButtonCB(Widget dialog,
- XtPointer client_data,
- XtPointer call_data)
- {
- _gdb_out(string((char *)client_data) + '\n');
- gdbCommandCB(dialog, client_data, call_data);
- gdb_keyboard_command = true;
- }
-
-
-
- //-----------------------------------------------------------------------------
- // Version stuff
- //-----------------------------------------------------------------------------
-
- // Return true iff old button separators (`:') are used. These were
- // introduced in DDD 1997-10 or 2.1.
- static bool old_button_format()
- {
- if (app_data.dddinit_version == 0)
- return true;
- string v = app_data.dddinit_version;
- int major = atoi(v);
-
- if (major > 1900)
- {
- // YYYY-MM-DD format
- if (major <= 1996)
- return true; // 1996 or earlier
- if (major >= 1998)
- return false; // 1998 or later
-
- assert(major == 1997);
- string v2 = v.after('-');
- int minor = atoi(v2);
- if (minor <= 9) // 1997-09 or earlier
- return true;
-
- return false; // 1997-10 or later
- }
- else
- {
- // MAJOR.MINOR format
- if (major <= 1)
- return true; // 1.x or earlier
- if (major >= 3)
- return false; // 3.x or later
-
- assert(major == 2);
- string v2 = v.after('.');
- int minor = atoi(v2);
- if (minor <= 1)
- return true; // 2.1 or earlier
-
- return false; // 2.2 or later
- }
- }
-
-
- //-----------------------------------------------------------------------------
- // Show documentation string in status line
- //-----------------------------------------------------------------------------
-
- static void showDocumentationInStatusLine(const MString& doc)
- {
- static MString current_status_message(0, true);
- static MString saved_status_message(0, true);
- static bool doc_shown_in_status = false;
-
- if (doc.isNull() || doc.isEmpty())
- {
- // Button has been left - restore previous message unless overwritten
- if (!current_status_message.isNull())
- {
- // Button has been left
- if (current_status_message == current_status())
- {
- // Restore previous message
- set_status_mstring(saved_status_message, true);
- }
- else
- {
- // Message has been overwritten.
- #if 0
- // This is a button effect, hence clear the message.
- set_status("");
- #endif
- }
- static MString empty(0, true);
- current_status_message = empty;
- }
-
- doc_shown_in_status = false;
- }
- else
- {
- // Button has been entered - save old message
- if (!doc_shown_in_status)
- {
- saved_status_message = current_status();
- doc_shown_in_status = true;
- }
-
- set_status_mstring(doc, true);
- current_status_message = doc;
- }
- }
-
-
- //-----------------------------------------------------------------------------
- // Default help texts (especially buttons)
- //-----------------------------------------------------------------------------
-
- const int help_timeout = 2; // Timeout for short queries (in s)
-
- static StringStringAssoc help_cache;
-
- static string gdbHelpName(Widget widget)
- {
- string name = XtName(widget);
- name.gsub('_', ' ');
- strip_trailing_space(name);
-
- return name;
- }
-
- static string gdbHelp(string original_command)
- {
- translate_command(original_command);
-
- string command = original_command;
- if (gdb->type() == JDB && original_command == "next")
- {
- // JDB 1.1 has an undocumented `next' command. Treat it like `step'.
- command = "step";
- }
-
- if (gdb->type() == DBX && original_command == "step up")
- {
- // Don't ask for `step up'; ask for `step' instead.
- command = "step";
- }
-
- if (gdb->type() == PERL)
- {
- // Perl help has only one argument
- if (command.contains(rxwhite))
- command = command.before(rxwhite);
- }
-
- string help = NO_GDB_ANSWER;
-
- if (is_graph_cmd(command))
- {
- // Use own help texts
- string cmd = command.after("graph ") + " dummy";
- if (is_refresh_cmd(cmd))
- help = "Refresh data window.";
- else if (is_display_cmd(cmd))
- help = "Display expression in the data window.";
- }
-
- if (command == "graph" || command.contains("graph ", 0))
- help = "Data window operation.";
-
- if (help == NO_GDB_ANSWER)
- {
- // Lookup cache
- if (help_cache.has(command))
- help = help_cache[command];
- }
-
- if (help == NO_GDB_ANSWER && gdb->type() == JDB)
- {
- // JDB has a single static `help' command.
- string& all_help = help_cache["<ALL>"];
- if (all_help == NO_GDB_ANSWER || all_help == "")
- {
- all_help = gdb_question("help", -1, true);
- if (all_help == NO_GDB_ANSWER)
- return NO_GDB_ANSWER; // try again later
- }
-
- int index = all_help.index("\n" + command) + 1;
- if (all_help.contains(command, index))
- {
- help = all_help.from(index);
- help = help.after("--");
- help = help.before('\n');
- }
- else
- {
- help = "Undefined command: " + quote(command)
- + ". Try \"help\"\n";
- }
- }
-
- if (help == NO_GDB_ANSWER && gdb->type() == DBX)
- {
- string cmd = command.before(rxwhite);
- string base = command.after(rxwhite);
- base.gsub(' ', '_');
-
- if (cmd == "set" || cmd == "dbxenv")
- {
- // Ask DBX for help on DBXENV command
- help = get_dbx_help(cmd, base);
- }
- }
-
- if (help == NO_GDB_ANSWER && gdb->type() != JDB)
- {
- // Ask debugger for help
- string help_command;
- if (gdb->type() == PERL)
- help_command = "h " + command;
- else
- help_command = "help " + command;
-
- help = gdb_question(help_command, help_timeout, true);
- }
-
- strip_space(help);
-
- // `step up' help is part of `step' help.
- if (original_command == "step up" && !help.contains(original_command))
- return "undefined command";
-
- if (help != NO_GDB_ANSWER)
- help_cache[command] = help;
-
- return help;
- }
-
- void clear_help_cache(const string& command)
- {
- if (help_cache.has(command))
- help_cache.remove(command);
- }
-
-
- // Return DBX 3.2 one-liner help.
- static string gdbTip(string command)
- {
- static bool entered = false;
- if (entered)
- return NO_GDB_ANSWER;
- entered = true;
-
- string tip = NO_GDB_ANSWER;
-
- if (gdb->type() == DBX)
- {
- static string commands = NO_GDB_ANSWER;
- if (commands == NO_GDB_ANSWER)
- {
- commands = gdb_question("commands", -1, true);
- if (!is_known_command(commands))
- commands = "";
- }
-
- int start = 0;
- for (;;)
- {
- int i = commands.index(command, start);
- if (i < 0)
- break;
- while (i > 0
- && commands[i - 1] != '\n'
- && isspace(commands[i - 1]))
- i--;
- if (i == 0 || commands[i - 1] == '\n')
- {
- string t = commands.from(i);
- t = t.before('\n');
- strip_space(t);
-
- if (t.length() > command.length()) // Simple sanity check
- tip = t;
- break;
- }
-
- start = i + 1;
- }
- }
-
- entered = false;
- return tip;
- }
-
-
- static string gdbSettingsValue(string command)
- {
- switch (gdb->type())
- {
- case GDB:
- if (command.contains("set ", 0))
- {
- string value = gdb_question("show " + command.after(rxwhite));
- if (!value.contains("current"))
- value.gsub(" is ", " is currently ");
- strip_trailing_space(value);
- return value;
- }
- break;
-
- case DBX:
- case XDB:
- case JDB:
- case PYDB:
- case PERL:
- return NO_GDB_ANSWER; // FIXME
- }
-
- return NO_GDB_ANSWER;
- }
-
- static MString gdbDefaultHelpText(Widget widget)
- {
- const string name = gdbHelpName(widget);
-
- MString msg;
- if (name != "" && islower(name[0]))
- msg = bf(toupper(name[0]) + name.after(0));
- else
- msg = bf(name);
- msg += cr();
- msg += cr();
-
- string help = gdbHelp(name);
- if (help == NO_GDB_ANSWER)
- {
- msg += rm("No help available now.") + cr();
- msg += rm("Please try again when " + gdb->title() + " is ready.");
- }
- else
- {
- msg += rm(help);
-
- // Add current settings state, if any
- string state = gdbSettingsValue(name);
- if (state != NO_GDB_ANSWER)
- {
- msg += cr();
- msg += cr();
- msg += rm(state);
- }
- }
-
- return msg;
- }
-
-
- static StringStringAssoc value_cache;
-
- void clear_value_cache()
- {
- static StringStringAssoc empty;
- value_cache = empty;
- }
-
- string gdbValue(const string& expr)
- {
- if (undo_buffer.showing_earlier_state())
- return NO_GDB_ANSWER; // We don't know about earlier values
-
- string value = NO_GDB_ANSWER;
- if (value == NO_GDB_ANSWER)
- {
- // Lookup cache
- if (value_cache.has(expr))
- value = value_cache[expr];
- }
-
- if (value == NO_GDB_ANSWER)
- {
- // Ask debugger for value. In case of secondary prompts, use
- // the default choice.
- gdb->removeHandler(ReplyRequired, gdb_selectHP);
- value = gdb_question(gdb->print_command(expr), help_timeout);
- if (value != NO_GDB_ANSWER)
- gdb->munch_value(value, expr);
- gdb->addHandler(ReplyRequired, gdb_selectHP);
-
- strip_space(value);
- }
-
- if (value != NO_GDB_ANSWER)
- value_cache[expr] = value;
-
- return value;
- }
-
- string assignment_value(const string& expr)
- {
- if (expr == NO_GDB_ANSWER)
- return NO_GDB_ANSWER;
-
- string value = expr;
-
- // Replace whitespace
- #if RUNTIME_REGEX
- static regex rxnl(" *\n *");
- #endif
- value.gsub(rxnl, " ");
- value.gsub("\n", " ");
- value.gsub("\t", " ");
- value.gsub(" ", " ");
-
- // Strip member name from structs
- int eq_index = -1;
- while ((eq_index = value.index(" = ")) >= 0)
- {
- int member_name_index = eq_index;
- while (member_name_index > 0 &&
- value[member_name_index - 1] != '{' &&
- value[member_name_index - 1] != '(' &&
- value[member_name_index - 1] != ',')
- member_name_index--;
-
- if (member_name_index > 0 &&
- value[member_name_index - 1] == ',')
- {
- // Keep the space after ','
- while (member_name_index < eq_index &&
- isspace(value[member_name_index]))
- member_name_index++;
- }
-
- value = value.before(member_name_index) + value.from(eq_index + 3);
- }
-
- strip_space(value);
-
- return value;
- }
-
- static void strip_through(string& s, string key)
- {
- int key_index = s.index(key);
- int nl_index = s.index('\n');
-
- if (key_index >= 0 && (nl_index < 0 || key_index < nl_index))
- s = s.from(int(key_index + key.length()));
- }
-
- static XmTextPosition textPosOfEvent(Widget widget, XEvent *event)
- {
- XmTextPosition startpos, endpos;
- string expr =
- source_view->get_word_at_event(widget, event, startpos, endpos);
-
- #if 0 // We might point at a text breakpoint
- if (expr == "")
- return XmTextPosition(-1);
- #endif
-
- return startpos;
- }
-
- // Get tip string for text widget WIDGET.
- static MString gdbDefaultValueText(Widget widget, XEvent *event,
- bool for_documentation)
- {
- assert (XmIsText(widget));
-
- XmTextPosition startpos, endpos;
- string expr =
- source_view->get_word_at_event(widget, event, startpos, endpos);
-
- #if LOG_VALUE_TIPS
- clog << "Pointing at " << quote(expr) << "\n";
- #endif
-
- // If we're at a breakpoint, return appropriate help
- MString bp_help =
- source_view->help_on_pos(widget, startpos, endpos, for_documentation);
-
- if (bp_help.xmstring() == 0 && expr == "")
- return MString(0, true); // Nothing pointed at
-
- #if RUNTIME_REGEX
- static regex rxchain("[a-zA-Z0-9_](([.]|->|::)[a-zA-Z0-9_])*");
- #endif
-
- // Don't invoke the debugger if EXPR is not an identifier.
- // Otherwise, we might point at `i++' or `f()' and have weird side
- // effects.
- MString clear = for_documentation ? rm(" ") : MString(0, true);
- if (bp_help.xmstring() == 0 && !expr.matches(rxchain))
- return clear;
-
- // Change EVENT such that the popup tip will remain at the same
- // position
- Position x, y;
- if (XmTextPosToXY(widget, endpos, &x, &y))
- {
- switch (event->type)
- {
- case MotionNotify:
- event->xmotion.x = x;
- event->xmotion.y = y;
- break;
-
- case EnterNotify:
- case LeaveNotify:
- event->xcrossing.x = x;
- event->xcrossing.y = y;
- break;
- }
- }
-
- if (bp_help.xmstring() != 0)
- return bp_help;
-
- if (gdb->program_language() == LANGUAGE_PERL)
- {
- // In Perl, all variables begin with `$', `@', or `%'.
- if (expr != "" && !is_perl_prefix(expr[0]))
- return clear;
- }
-
- // Get value of ordinary variable
- string name = fortranize(expr);
- string tip = gdbValue(name);
- if (tip == NO_GDB_ANSWER)
- return MString(0, true);
-
- if (!is_valid(tip, gdb) && widget == source_view->code())
- {
- // Get register value - look up `$pc' when pointing at `pc'
- name = expr;
- name.prepend("$");
- tip = gdbValue(name);
- if (tip == NO_GDB_ANSWER)
- return MString(0, true);
-
- if (tip.matches(rxint))
- {
- // Show hex value as well. We don't do a local
- // conversion here, but ask GDB instead, since the hex
- // format may be language-dependent.
- string hextip = gdbValue("/x " + name);
- if (hextip != NO_GDB_ANSWER)
- tip = hextip + " (" + tip + ")";
- }
- }
-
- if (!is_valid(tip, gdb))
- return clear;
-
- tip = get_disp_value_str(tip, gdb);
- if (tip == "void")
- return clear; // Empty variable
-
- #if 0
- if (gdb->program_language() == LANGUAGE_PERL && tip == "")
- tip = "undef";
- #endif
-
- if (for_documentation)
- {
- shorten(tip, max_value_doc_length - name.length());
-
- // The status line also shows the name we're pointing at
- MString mtip = tt(tip);
- mtip.prepend(rm(name + " = "));
- return mtip;
- }
- else
- {
- // The value tip just shows the value
- shorten(tip, max_value_tip_length);
- return tt(tip);
- }
- }
-
- // Get tip string for button widget WIDGET.
- static MString gdbDefaultButtonText(Widget widget, XEvent *,
- bool for_documentation)
- {
- MString bp_help = source_view->help_on_glyph(widget, for_documentation);
- if (!bp_help.isNull())
- return bp_help;
-
- MString shortcut_help = data_disp->shortcut_help(widget);
- if (!shortcut_help.isNull())
- return shortcut_help;
-
- string help_name = gdbHelpName(widget);
-
- string command = help_name;
- translate_command(command);
- string base = command;
- if (base.contains(' '))
- base = command.before(' ');
-
- if (help_name.length() == 2 &&
- help_name[0] == 'r' && isdigit(help_name[1]))
- {
- // Return help on `recent file' item
- StringArray recent_files;
- get_recent(recent_files);
- int index = help_name[1] - '1';
- if (index >= 0 && index < recent_files.size())
- return rm(recent_files[index]);
- }
-
- if (help_name == "Undo")
- {
- string action = undo_buffer.undo_action();
- if (action != NO_GDB_ANSWER)
- return rm("Undo " + action);
- else
- return rm("Undo last action");
- }
-
- if (help_name == "Redo")
- {
- string action = undo_buffer.redo_action();
- if (action != NO_GDB_ANSWER)
- return rm("Redo " + action);
- else
- return rm("Redo next action");
- }
-
- string tip = NO_GDB_ANSWER;
- if (tip == NO_GDB_ANSWER)
- tip = gdbTip(help_name);
- if (tip == NO_GDB_ANSWER)
- tip = gdbHelp(help_name);
-
- if (tip == NO_GDB_ANSWER)
- return MString(0, true);
-
- strip_leading_space(tip);
-
- if (gdb->type() == DBX)
- {
- if (!tip.contains(command, 0))
- {
- // Sometimes, multiple command are listed in one help text.
- // Be sure to fetch the correct variant.
- int index = tip.index("\n" + command);
- if (index > 0)
- tip = tip.after(index);
-
- // Fix Sun DBX `step up' help
- tip.gsub("... and ", "Step ");
- }
-
- if (tip.contains(command + " -", 0))
- {
- // Solaris DBX first describes `kill -l', then `kill'.
- // Check for this.
- string t = tip.from(command + " ", 0);
- if (t != "")
- tip = t;
- }
- }
-
- if (gdb->type() == PYDB)
- {
- // PYDB states the command in the first line
- tip = tip.after('\n');
- strip_leading_space(tip);
- }
-
- if (gdb->type() == PERL)
- {
- // In Perl, the help has the form `COMMAND\tTEXT'.
- tip = tip.after('\t');
- strip_leading_space(tip);
-
- if (tip.contains('['))
- tip = tip.before('[');
- }
-
- // DBX (and others) restate the command name at the beginning.
- if (tip.contains(command, 0))
- {
- string t = tip.after(command);
- if (t != "" && !isalpha(t[0]))
- {
- tip = t;
- strip_leading_space(tip);
- }
- }
-
- strip_through(tip, " # ");
- strip_through(tip, " - ");
-
- if (gdb->type() == DBX && tip != "" && !isupper(tip[0]))
- {
- // Avoid giving help like `step <count>' on `step'. This happens
- // with AIX DBX, where the help looks like
- // "run [<arguments>] [< <filename>] [> <filename>] \n"
- // " [>> <filename>] [>! <filename>] \n"
- // " [2> <filename>] [2>> <filename>] \n"
- // " [>& <filename>] [>>& <filename>] \n"
- // "\tStart executing the object file, passing arguments as\n"
- // "\tcommand line arguments [...]"
-
- string t = tip.from(rxuppercase);
- if (t.contains("\n" + base))
- t = t.before("\n" + base);
-
- t.gsub('\n', ' ');
- t.gsub('\t', ' ');
- t.gsub(" ", " ");
-
- if (t.contains('.'))
- t = t.before('.');
- if (t.contains(';'))
- t = t.before(';');
-
- // Fix AIX `down' help
- t.gsub(", which is used for resolving names,", "");
-
- if (t.length() > 0)
- tip = t;
- }
-
- if (gdb->type() == XDB)
- {
- // Get rid of XXX [number] as in `S [number] Single step, step...'
- // Bob Wiegand <robert.e.wiegand.1@gsfc.nasa.gov>
- strip_through(tip, "]");
- }
-
- tip = tip.from(rxalpha);
- strip_space(tip);
-
- if (tip.length() > 0)
- tip = toupper(tip[0]) + tip.after(0);
-
- if (tip.contains('\n'))
- tip = tip.before('\n');
- if (tip.contains('.'))
- tip = tip.before('.');
- if (tip.contains(';'))
- tip = tip.before(';');
-
- // Sun DBX 3.2 sometimes forgets the newline after the 80th character
- if (tip.length() > 80)
- tip = tip.before(80);
-
- return rm(tip);
- }
-
-
- static MString gdbDefaultText(Widget widget, XEvent *event,
- bool for_documentation)
- {
- if (XmIsText(widget))
- return gdbDefaultValueText(widget, event, for_documentation);
- else
- return gdbDefaultButtonText(widget, event, for_documentation);
- }
-
- static MString gdbDefaultTipText(Widget widget, XEvent *event)
- {
- return gdbDefaultText(widget, event, false);
- }
-
- static MString gdbDefaultDocumentationText(Widget widget, XEvent *event)
- {
- return gdbDefaultText(widget, event, true);
- }
-
-
- //-----------------------------------------------------------------------------
- // Button Verification
- //-----------------------------------------------------------------------------
-
- // Buttons to be verified
- static WidgetArray buttons_to_be_verified;
-
-
- static void VerifyButtonWorkProc(XtPointer client_data, XtIntervalId *id)
- {
- (void) id; // Use it
-
- XtIntervalId& verify_id = *((XtIntervalId *)client_data);
- assert(*id == verify_id);
- verify_id = 0;
-
- for (int i = 0; i < buttons_to_be_verified.size(); i++)
- {
- Widget& button = buttons_to_be_verified[i];
- if (button == 0)
- continue;
-
- XtCallbackList callbacks = 0;
- XtVaGetValues(button,
- XmNactivateCallback, &callbacks,
- NULL);
-
- for (int j = 0; callbacks != 0 && callbacks[j].callback != 0; j++)
- {
- string cmd = "";
-
- if (callbacks[j].callback == gdbCommandCB)
- {
- cmd = (String)(callbacks[j].closure);
- cmd = cmd.through(rxidentifier);
- }
-
- if (cmd != "")
- {
- int next_invocation = 0;
- XtAppContext app_context =
- XtWidgetToApplicationContext(button);
-
- string answer;
- if (!emptyCommandQueue())
- {
- // Still commands in queue - try later
- answer = NO_GDB_ANSWER;
- }
- else
- {
- answer = gdbHelp(cmd);
- }
-
- if (answer == NO_GDB_ANSWER)
- {
- // No answer -- try again later
- next_invocation = 250;
- }
- else
- {
- set_sensitive(button, is_known_command(answer));
- button = 0; // Don't process this one again
- next_invocation = 50; // Process next button in 50ms
- }
-
- verify_id = XtAppAddTimeOut(app_context, next_invocation,
- VerifyButtonWorkProc,
- client_data);
- return;
- }
- }
- }
- }
-
- static void DontVerifyButtonCB(Widget w, XtPointer, XtPointer)
- {
- // W is being destroyed - remove all references
- for (int i = 0; i < buttons_to_be_verified.size(); i++)
- if (buttons_to_be_verified[i] == w)
- buttons_to_be_verified[i] = 0;
- }
-
- // Make BUTTON insensitive if it is not supported
- void verify_button(Widget button)
- {
- if (!app_data.verify_buttons)
- return;
- if (button == 0)
- return;
- if (!XtIsSubclass(button, xmPushButtonWidgetClass))
- return;
-
- #if 0
- set_sensitive(button, False);
- #endif
-
- buttons_to_be_verified += button;
- XtAddCallback(button, XtNdestroyCallback,
- DontVerifyButtonCB, XtPointer(0));
-
- // Procedure id
- static XtIntervalId verify_id = 0;
- if (verify_id == 0)
- {
- verify_id = XtAppAddTimeOut(XtWidgetToApplicationContext(button),
- 0, VerifyButtonWorkProc,
- XtPointer(&verify_id));
- }
- }
-
-
- //-----------------------------------------------------------------------------
- // Button Creation
- //-----------------------------------------------------------------------------
-
- static WidgetArray up_buttons;
- static WidgetArray down_buttons;
- static WidgetArray undo_buttons;
- static WidgetArray redo_buttons;
- static WidgetArray edit_buttons;
-
- void refresh_buttons()
- {
- int i;
- for (i = 0; i < up_buttons.size(); i++)
- set_sensitive(up_buttons[i], source_view->can_go_up());
- for (i = 0; i < down_buttons.size(); i++)
- set_sensitive(down_buttons[i], source_view->can_go_down());
- for (i = 0; i < undo_buttons.size(); i++)
- set_sensitive(undo_buttons[i],
- undo_buffer.undo_action() != NO_GDB_ANSWER);
- for (i = 0; i < redo_buttons.size(); i++)
- set_sensitive(redo_buttons[i],
- undo_buffer.redo_action() != NO_GDB_ANSWER);
- for (i = 0; i < edit_buttons.size(); i++)
- set_sensitive(edit_buttons[i], source_view->have_source());
-
- update_edit_menus();
- }
-
- static void RemoveFromArrayCB(Widget w, XtPointer client_data, XtPointer)
- {
- WidgetArray& arr = *((WidgetArray *)client_data);
- arr -= w;
- }
-
- static void register_button(WidgetArray& arr, Widget w)
- {
- arr += w;
- XtAddCallback(w, XtNdestroyCallback, RemoveFromArrayCB, XtPointer(&arr));
- }
-
- // Create a button work area from BUTTON_LIST named NAME
- Widget make_buttons(Widget parent, const string& name,
- String button_list)
- {
- Arg args[10];
- int arg = 0;
- XtSetArg(args[arg], XmNorientation, XmHORIZONTAL); arg++;
- XtSetArg(args[arg], XmNuserData, 0); arg++;
- XtSetArg(args[arg], XmNmarginWidth, 0); arg++;
- XtSetArg(args[arg], XmNmarginHeight, 0); arg++;
- XtSetArg(args[arg], XmNspacing, 0); arg++;
- XtSetArg(args[arg], XmNborderWidth, 0); arg++;
- XtSetArg(args[arg], XmNhighlightThickness, 0); arg++;
- XtSetArg(args[arg], XmNshadowThickness, 0); arg++;
- Widget buttons = verify(XmCreateRowColumn(parent, name, args, arg));
-
- set_buttons(buttons, button_list);
-
- if (XtIsManaged(buttons))
- {
- XtWidgetGeometry size;
- size.request_mode = CWHeight;
- XtQueryGeometry(buttons, NULL, &size);
- XtVaSetValues(buttons,
- XmNpaneMaximum, size.height,
- XmNpaneMinimum, size.height,
- NULL);
- }
-
- return buttons;
- }
-
- void set_buttons(Widget buttons, String _button_list, bool manage)
- {
- XtPointer user_data = 0;
- WidgetList children = 0;
- Cardinal num_children = 0;
-
- XtVaGetValues(buttons,
- XmNuserData, &user_data,
- XtNchildren, &children,
- XtNnumChildren, &num_children,
- NULL);
-
- string *sp = (string *)user_data;
- if (sp != 0 && *sp == string(_button_list))
- {
- // Unchanged value - only re-verify all buttons
- for (int i = 0; i < int(num_children); i++)
- verify_button(children[i]);
- return;
- }
- delete sp;
-
- StatusDelay *delay = 0;
- if (gdb_initialized)
- delay = new StatusDelay("Setting buttons");
-
- // Destroy all existing children (= buttons)
- int i;
- for (i = 0; i < int(num_children); i++)
- {
- XtUnmanageChild(children[i]);
- DestroyWhenIdle(children[i]);
- }
-
- // Add new buttons
- string button_list = _button_list;
-
- if (button_list.contains(':') && old_button_format())
- {
- // DDD 2.1 and earlier used `:' to separate buttons
- button_list.gsub(':', '\n');
-
- cerr << "Warning: converting " << quote(_button_list) << "\n"
- << "to new format " << quote(button_list) << "\n";
- }
-
- int lines = button_list.freq('\n') + 1;
- string *commands = new string[lines];
- split(button_list, commands, lines, '\n');
-
- int number_of_buttons = 0;
- for (i = 0; i < lines; i++)
- {
- XtCallbackProc callback = gdbCommandCB;
-
- string name = commands[i];
- strip_space(name);
-
- if (name == "")
- continue;
-
- MString label(0, true);
- if (name.contains(app_data.label_delimiter))
- {
- string label_s = name.after(app_data.label_delimiter);
- name = name.before(app_data.label_delimiter);
- strip_space(label_s);
- strip_space(name);
- label = MString(label_s);
- }
-
- string command = name;
- if (name.contains("..."))
- {
- name = name.before("...");
- }
- else if (name.contains('^'))
- {
- command = ctrl(name.from('^'));
- name = name.before('^');
- }
- else if (name != "" && iscntrl(name[name.length() - 1]))
- {
- command = string(name[name.length() - 1]);
- name = name.before(-1);
- }
-
- if (label.isNull())
- {
- // Create default label from name
- string label_s = name;
- if (label_s != "")
- label_s[0] = toupper(label_s[0]);
- label = MString(label_s);
- }
-
- // Make sure the widget name does not contain invalid characters
- #if RUNTIME_REGEX
- static regex rxsep("[^-_a-zA-Z0-9]");
- #endif
- name.gsub(rxsep, '_');
-
- #if 0
- Widget button = verify(create_flat_button(buttons, name));
- #else
- Arg args[10];
- Cardinal arg = 0;
- XtSetArg(args[arg], XmNborderWidth, 0); arg++;
- XtSetArg(args[arg], XmNhighlightThickness, 1); arg++;
- Widget button = verify(XmCreatePushButton(buttons, name, args, arg));
- #endif
- XtManageChild(button);
- number_of_buttons++;
-
- // A user-specified labelString overrides the given label
- XmString xmlabel;
- XtVaGetValues(button, XmNlabelString, &xmlabel, NULL);
- MString foundLabel(xmlabel, true);
- XmStringFree(xmlabel);
-
- if (foundLabel.str() == name)
- {
- // User did not specify a specific labelString -
- // use the specified button command as label
- XtVaSetValues(button, XmNlabelString, label.xmstring(), NULL);
- }
-
- if (name == "Yes")
- {
- command = "yes";
- XtUnmanageChild(button);
- callback = YnButtonCB;
- }
- else if (name == "No")
- {
- command = "no";
- XtUnmanageChild(button);
- callback = YnButtonCB;
- }
- else if (name == "Prev")
- callback = gdbPrevCB;
- else if (name == "Next")
- callback = gdbNextCB;
- else if (name == "Clear")
- callback = gdbClearCB;
- else if (name == "Complete")
- callback = gdbCompleteCB;
- else if (name == "Apply")
- callback = gdbApplyCB;
- else if (name == "Make")
- callback = gdbMakeAgainCB;
- else if (name == "Undo" || name == "Back")
- {
- callback = gdbUndoCB;
- register_button(undo_buttons, button);
- }
- else if (name == "Redo" || name == "Forward")
- {
- callback = gdbRedoCB;
- register_button(redo_buttons, button);
- }
- else if (name == "Edit")
- {
- callback = gdbEditSourceCB;
- register_button(edit_buttons, button);
- }
- else if (name == "Reload")
- {
- callback = gdbReloadSourceCB;
- register_button(edit_buttons, button);
- }
-
- if (name == "up")
- register_button(up_buttons, button);
- else if (name == "down")
- register_button(down_buttons, button);
-
- // Be sure to verify whether the button actually exists
- verify_button(button);
-
- // We remove all callbacks to avoid popping down DialogShells
- XtRemoveAllCallbacks(button, XmNactivateCallback);
- XtAddCallback(button, XmNactivateCallback, callback,
- (XtPointer)XtNewString(command.chars()));
-
- // Add a help callback
- XtAddCallback(button, XmNhelpCallback, ImmediateHelpCB, XtPointer(0));
- }
- delete[] commands;
-
- if (manage)
- {
- if (number_of_buttons > 0)
- {
- // Manage buttons, giving them their preferred height
- XtWidgetGeometry size;
- size.request_mode = CWHeight;
- XtQueryGeometry(buttons, NULL, &size);
-
- XtVaSetValues(buttons,
- XmNpaneMinimum, size.height,
- XmNpaneMaximum, size.height,
- NULL);
-
- manage_paned_child(buttons);
- }
- else
- {
- // No buttons at all
- unmanage_paned_child(buttons);
- }
- }
-
- sp = new string(_button_list);
- XtVaSetValues(buttons, XmNuserData, XtPointer(sp), NULL);
-
- // Register default help command
- DefaultHelpText = gdbDefaultHelpText;
- DefaultTipText = gdbDefaultTipText;
- DefaultDocumentationText = gdbDefaultDocumentationText;
- TextPosOfEvent = textPosOfEvent;
-
- DisplayDocumentation = showDocumentationInStatusLine;
-
- // Set sensitivity
- refresh_buttons();
-
- // Install tips
- InstallButtonTips(buttons);
-
- // Update `define' panel
- UpdateDefinePanelCB();
-
- delete delay;
- }
-
-
-
- //-----------------------------------------------------------------------------
- // Button Editor
- //-----------------------------------------------------------------------------
-
- // Remove garbage from S
- static string normalize(string s)
- {
- if (s.contains(':') && old_button_format())
- {
- // DDD 2.1 and earlier used `:' to separate buttons
- s.gsub(':', '\n');
- }
-
- int lines = s.freq('\n') + 1;
- string *commands = new string[lines];
- split(s, commands, lines, '\n');
-
- string ret = "";
- for (int i = 0; i < lines; i++)
- {
- string& cmd = commands[i];
- strip_space(cmd);
- if (cmd == "")
- continue;
-
- if (ret.length() > 0)
- ret += '\n';
- ret += cmd;
- }
-
- return ret;
- }
-
- static Widget buttons_dialog = 0;
- static Widget button_box = 0;
- static Widget shortcut_label = 0;
- static Widget console_w, shortcut_w;
-
- struct ChangeTextInfo {
- String *str;
- Widget dialog;
- Widget text;
- Widget vfy;
- bool shortcuts;
- };
-
- static ChangeTextInfo *active_info = 0;
-
- static void SetTextCB(Widget, XtPointer, XtPointer)
- {
- if (active_info == 0)
- return;
-
- String _str = XmTextGetString(active_info->text);
- string str(_str);
- XtFree(_str);
-
- str = normalize(str);
-
- XmTextSetString(active_info->text, str);
-
- *active_info->str = (String)XtNewString(str.chars());
- update_user_buttons();
- }
-
- static void ResetTextCB(Widget, XtPointer, XtPointer)
- {
- if (active_info == 0)
- return;
-
- XmTextSetString(active_info->text, *active_info->str);
- update_user_buttons();
- }
-
- static void ChangeTextCB(Widget w, XtPointer client_data, XtPointer call_data)
- {
- XmToggleButtonCallbackStruct *cbs =
- (XmToggleButtonCallbackStruct *)call_data;
- ChangeTextInfo *info = (ChangeTextInfo *)client_data;
-
- if (cbs->set)
- {
- // When changing, treat like `Apply'
- SetTextCB(w, XtPointer(0), XtPointer(0));
-
- active_info = info;
-
- string str = normalize(*info->str);
- XmTextSetString(info->text, (char *)str.chars());
- XtAddCallback(info->dialog, XmNhelpCallback,
- HelpOnThisCB, XtPointer(w));
-
- if (info->shortcuts)
- XtUnmanageChild(info->vfy);
- else
- XtManageChild(info->vfy);
- }
- else
- {
- XtRemoveCallback(info->dialog, XmNhelpCallback,
- HelpOnThisCB, XtPointer(w));
- }
- }
-
- static void SetVerifyButtonsCB(Widget, XtPointer, XtPointer call_data)
- {
- XmToggleButtonCallbackStruct *cbs =
- (XmToggleButtonCallbackStruct *)call_data;
-
- app_data.verify_buttons = cbs->set;
- }
-
-
- static Widget add_button(String name,
- Widget dialog, Widget buttons,
- Widget text, Widget vfy,
- String& str, bool shortcuts = false)
- {
- Arg args[10];
- Cardinal arg = 0;
- Widget button = XmCreateToggleButton(buttons, name, args, arg);
- XtManageChild(button);
-
- ChangeTextInfo *info = new ChangeTextInfo;
- info->dialog = dialog;
- info->str = &str;
- info->text = text;
- info->vfy = vfy;
- info->shortcuts = shortcuts;
-
- XtAddCallback(button, XmNvalueChangedCallback, ChangeTextCB,
- XtPointer(info));
-
- return button;
- }
-
- static void create_buttons_dialog(Widget parent)
- {
- if (buttons_dialog != 0)
- return;
-
- Arg args[10];
- Cardinal arg = 0;
- XtSetArg(args[arg], XmNvisibleItemCount, 0); arg++;
- XtSetArg(args[arg], XmNautoUnmanage, False); arg++;
- buttons_dialog =
- verify(XmCreatePromptDialog(find_shell(parent),
- "edit_buttons", args, arg));
-
- XtAddCallback(buttons_dialog, XmNokCallback, SetTextCB, 0);
- XtAddCallback(buttons_dialog, XmNokCallback,
- UnmanageThisCB, buttons_dialog);
- XtAddCallback(buttons_dialog, XmNapplyCallback, SetTextCB, 0);
- XtAddCallback(buttons_dialog, XmNcancelCallback, ResetTextCB, 0);
-
- XtUnmanageChild(XmSelectionBoxGetChild(buttons_dialog,
- XmDIALOG_SELECTION_LABEL));
- XtUnmanageChild(XmSelectionBoxGetChild(buttons_dialog,
- XmDIALOG_TEXT));
- Delay::register_shell(buttons_dialog);
-
- arg = 0;
- XtSetArg(args[arg], XmNmarginWidth, 0); arg++;
- XtSetArg(args[arg], XmNmarginHeight, 0); arg++;
- XtSetArg(args[arg], XmNborderWidth, 0); arg++;
- XtSetArg(args[arg], XmNadjustMargin, False); arg++;
- Widget box =
- verify(XmCreateRowColumn(buttons_dialog, "box", args, arg));
- XtManageChild(box);
-
- arg = 0;
- XtSetArg(args[arg], XmNmarginWidth, 0); arg++;
- XtSetArg(args[arg], XmNmarginHeight, 0); arg++;
- XtSetArg(args[arg], XmNborderWidth, 0); arg++;
- XtSetArg(args[arg], XmNalignment, XmALIGNMENT_BEGINNING); arg++;
- shortcut_label = verify(XmCreateLabel(box, "shortcuts", args, arg));
- XtManageChild(shortcut_label);
-
- arg = 0;
- XtSetArg(args[arg], XmNmarginWidth, 0); arg++;
- XtSetArg(args[arg], XmNmarginHeight, 0); arg++;
- XtSetArg(args[arg], XmNborderWidth, 0); arg++;
- XtSetArg(args[arg], XmNorientation, XmHORIZONTAL); arg++;
- button_box =
- verify(XmCreateRadioBox(box, "buttons", args, arg));
- XtManageChild(button_box);
-
- arg = 0;
- XtSetArg(args[arg], XmNeditMode, XmMULTI_LINE_EDIT); arg++;
- Widget text = verify(XmCreateScrolledText(box, "text", args, arg));
- XtManageChild(text);
-
- arg = 0;
- XtSetArg(args[arg], XmNset, app_data.verify_buttons); arg++;
- Widget vfy = verify(XmCreateToggleButton(box, "verify", args, arg));
- XtManageChild(vfy);
- XtAddCallback(vfy, XmNvalueChangedCallback, SetVerifyButtonsCB, 0);
-
- console_w =
- add_button("console", buttons_dialog, button_box, text, vfy,
- app_data.console_buttons);
- Widget source_w =
- add_button("source", buttons_dialog, button_box, text, vfy,
- app_data.source_buttons);
- Widget data_w =
- add_button("data", buttons_dialog, button_box, text, vfy,
- app_data.data_buttons);
-
- String *str = 0;
- switch (gdb->type())
- {
- case GDB: str = &app_data.gdb_display_shortcuts; break;
- case DBX: str = &app_data.dbx_display_shortcuts; break;
- case XDB: str = &app_data.xdb_display_shortcuts; break;
- case JDB: str = &app_data.jdb_display_shortcuts; break;
- case PYDB: str = &app_data.pydb_display_shortcuts; break;
- case PERL: str = &app_data.perl_display_shortcuts; break;
- }
-
- shortcut_w =
- add_button("shortcuts", buttons_dialog, button_box, text, vfy,
- *str, true);
-
- XmToggleButtonSetState(source_w, True, False);
- (void) data_w;
- }
-
- // We use one single editor for both purposes, since this saves space.
- void dddEditButtonsCB(Widget w, XtPointer, XtPointer)
- {
- create_buttons_dialog(w);
- XtUnmanageChild(buttons_dialog);
-
- XtManageChild(button_box);
- XtManageChild(shortcut_w);
-
- XmToggleButtonSetState(console_w, True, True);
- ResetTextCB(w, 0, 0);
-
- XtManageChild(button_box);
- XtUnmanageChild(shortcut_w);
- XtUnmanageChild(shortcut_label);
-
- XtVaSetValues(XtParent(buttons_dialog), XmNtitle,
- DDD_NAME ": Button Editor", NULL);
-
- manage_and_raise(buttons_dialog);
- }
-
- void dddEditShortcutsCB(Widget w, XtPointer, XtPointer)
- {
- create_buttons_dialog(w);
- XtUnmanageChild(buttons_dialog);
-
- XtManageChild(button_box);
- XtManageChild(shortcut_w);
-
- XmToggleButtonSetState(shortcut_w, True, True);
- ResetTextCB(w, 0, 0);
-
- XtManageChild(shortcut_label);
- XtUnmanageChild(button_box);
-
- XtVaSetValues(XtParent(buttons_dialog), XmNtitle,
- DDD_NAME ": Shortcut Editor", NULL);
-
- manage_and_raise(buttons_dialog);
- }
-
- void refresh_button_editor()
- {
- StringArray exprs;
- StringArray labels;
-
- data_disp->get_shortcut_menu(exprs, labels);
- string expr;
- for (int i = 0; i < exprs.size(); i++)
- {
- if (i > 0)
- expr += '\n';
- expr += exprs[i];
- if (labels[i] != "")
- expr += string('\t') + app_data.label_delimiter + ' ' + labels[i];
- }
-
- String *str = 0;
- switch (gdb->type())
- {
- case GDB: str = &app_data.gdb_display_shortcuts; break;
- case DBX: str = &app_data.dbx_display_shortcuts; break;
- case XDB: str = &app_data.xdb_display_shortcuts; break;
- case JDB: str = &app_data.jdb_display_shortcuts; break;
- case PYDB: str = &app_data.pydb_display_shortcuts; break;
- case PERL: str = &app_data.perl_display_shortcuts; break;
- }
-
- *str = (String)XtNewString(expr.chars());
-
- if (active_info != 0 && active_info->str == str)
- XmTextSetString(active_info->text, *str);
- }
-
-
- //-----------------------------------------------------------------------------
- // Flat Buttons
- //-----------------------------------------------------------------------------
-
- static void nop(Widget, XtPointer, XtPointer) {}
-
- static MMDesc desc[] =
- {
- { "", MMFlatPush, { nop, 0 }, 0, 0, 0, 0 },
- MMEnd
- };
-
- // Create a flat PushButton named NAME
- Widget create_flat_button(Widget parent, const string& name)
- {
- desc[0].name = (char *)name;
- MMaddItems(parent, desc);
- MMaddCallbacks(desc);
- return desc[0].widget;
- }
-