home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 mARCH / PCWK3A99.iso / Linux / DDD331 / DDD-3_1_.000 / DDD-3_1_ / ddd-3.1.1 / ddd / editing.C < prev    next >
C/C++ Source or Header  |  1998-11-19  |  23KB  |  924 lines

  1. // $Id: editing.C,v 1.46 1998/11/19 10:06:45 zeller Exp $ -*- C++ -*-
  2. // DDD command-line actions
  3.  
  4. // Copyright (C) 1996-1998 Technische Universitaet Braunschweig, Germany.
  5. // Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
  6. // 
  7. // This file is part of DDD.
  8. // 
  9. // DDD is free software; you can redistribute it and/or
  10. // modify it under the terms of the GNU General Public
  11. // License as published by the Free Software Foundation; either
  12. // version 2 of the License, or (at your option) any later version.
  13. // 
  14. // DDD is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. // See the GNU General Public License for more details.
  18. // 
  19. // You should have received a copy of the GNU General Public
  20. // License along with DDD -- see the file COPYING.
  21. // If not, write to the Free Software Foundation, Inc.,
  22. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. // 
  24. // DDD is the data display debugger.
  25. // For details, see the DDD World-Wide-Web page, 
  26. // `http://www.cs.tu-bs.de/softech/ddd/',
  27. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  28.  
  29. char editing_rcsid[] = 
  30.     "$Id: editing.C,v 1.46 1998/11/19 10:06:45 zeller Exp $";
  31.  
  32. #ifdef __GNUG__
  33. #pragma implementation
  34. #endif
  35.  
  36. #include "editing.h"
  37.  
  38. #include "AppData.h"
  39. #include "ArgField.h"
  40. #include "Command.h"
  41. #include "DataDisp.h"
  42. #include "SourceView.h"
  43. #include "TimeOut.h"
  44. #include "args.h"
  45. #include "cmdtty.h"
  46. #include "complete.h"
  47. #include "cook.h"
  48. #include "ctrl.h"
  49. #include "ddd.h"
  50. #include "history.h"
  51. #include "misc.h"
  52. #include "post.h"
  53. #include "regexps.h"
  54. #include "status.h"
  55. #include "string-fun.h"
  56.  
  57. #include <iostream.h>
  58. #include <Xm/Xm.h>
  59. #include <Xm/Text.h>
  60. #include <Xm/TextF.h>
  61. #include <Xm/RowColumn.h>    // XmMenuPosition()
  62.  
  63. // ANSI C++ doesn't like the XtIsRealized() macro
  64. #ifdef XtIsRealized
  65. #undef XtIsRealized
  66. #endif
  67.  
  68. // True if last input was at gdb prompt
  69. bool gdb_input_at_prompt = true;
  70.  
  71.  
  72. //-----------------------------------------------------------------------------
  73. // Helpers
  74. //-----------------------------------------------------------------------------
  75.  
  76. static void move_to_end_of_line(XtPointer, XtIntervalId *)
  77. {
  78.     XmTextPosition pos = XmTextGetLastPosition(gdb_w);
  79.     XmTextSetInsertionPosition(gdb_w, pos);
  80.     XmTextShowPosition(gdb_w, pos);
  81. }
  82.  
  83. static XmTextPosition start_of_line()
  84. {
  85.     String str = XmTextGetString(gdb_w);
  86.     string s = str;
  87.     XtFree(str);
  88.  
  89.     int start = s.index("\n(", -1);
  90.     if (start < 0)
  91.     start = s.index("\n>", -1);
  92.     if (start < 0 && !s.contains('(', 0) && !s.contains('>', 0))
  93.     return XmTextPosition(-1);
  94.  
  95.     return start + 1;
  96. }
  97.  
  98.  
  99. //-----------------------------------------------------------------------------
  100. // Incremental search
  101. //-----------------------------------------------------------------------------
  102.  
  103. enum ISearchState { ISEARCH_NONE = 0, ISEARCH_NEXT = 1, ISEARCH_PREV = -1 };
  104. static ISearchState isearch_state = ISEARCH_NONE;
  105. static string isearch_string = "";
  106. static string isearch_line = "";
  107. static bool have_isearch_line = false;
  108. static bool isearch_motion_ok = false;
  109.  
  110. static char isearch_prompt[]         = "(i-search)";
  111. static char reverse_isearch_prompt[] = "(reverse-i-search)";
  112.  
  113.  
  114. // Return current line
  115. string current_line()
  116. {
  117.     if (have_isearch_line)
  118.     return isearch_line;
  119.  
  120.     String str = XmTextGetString(gdb_w);
  121.     string input(str + promptPosition, 
  122.          XmTextGetLastPosition(gdb_w) - promptPosition);
  123.     XtFree(str);
  124.     return input;
  125. }
  126.  
  127. // Helpers
  128. static void clear_isearch_after_motion(XtPointer, XtIntervalId *)
  129. {
  130.     clear_isearch(false);
  131. }
  132.  
  133. static void set_isearch_motion_ok(XtPointer client_data, XtIntervalId *)
  134. {
  135.     isearch_motion_ok = bool((long)client_data);
  136. }
  137.  
  138. // Show prompt according to current mode
  139. static void show_isearch()
  140. {
  141.     XmTextPosition start = start_of_line();
  142.     if (start == XmTextPosition(-1))
  143.     return;
  144.  
  145.     string prompt;
  146.     switch (isearch_state)
  147.     {
  148.     case ISEARCH_NONE:
  149.     prompt = gdb->prompt();
  150.     break;
  151.  
  152.     case ISEARCH_NEXT:
  153.     prompt = isearch_prompt;
  154.     break;
  155.  
  156.     case ISEARCH_PREV:
  157.     prompt = reverse_isearch_prompt;
  158.     break;
  159.     }
  160.  
  161.     if (isearch_state != ISEARCH_NONE)
  162.     prompt += "`" + cook(isearch_string) + "': ";
  163.     string input = current_line();
  164.     string line  = prompt + input;
  165.  
  166.     bool old_private_gdb_output = private_gdb_output;
  167.     private_gdb_output = true;
  168.     XmTextReplace(gdb_w, start, XmTextGetLastPosition(gdb_w), (String)line);
  169.     promptPosition = start + prompt.length();
  170.  
  171.     XmTextPosition pos = promptPosition;
  172.     int index = input.index(isearch_string);
  173.     if (isearch_state == ISEARCH_NONE || index < 0)
  174.     {
  175.     XmTextSetHighlight(gdb_w, 0, XmTextGetLastPosition(gdb_w),
  176.                XmHIGHLIGHT_NORMAL);
  177.     }
  178.     else
  179.     {
  180.     XmTextSetHighlight(gdb_w,
  181.                0,
  182.                pos + index,
  183.                XmHIGHLIGHT_NORMAL);
  184.     XmTextSetHighlight(gdb_w,
  185.                pos + index, 
  186.                pos + index + isearch_string.length(),
  187.                XmHIGHLIGHT_SECONDARY_SELECTED);
  188.     XmTextSetHighlight(gdb_w, 
  189.                pos + index + isearch_string.length(),
  190.                XmTextGetLastPosition(gdb_w),
  191.                XmHIGHLIGHT_NORMAL);
  192.     }
  193.  
  194.     if (index >= 0)
  195.     pos += index;
  196.  
  197.     XmTextSetInsertionPosition(gdb_w, pos);
  198.     XmTextShowPosition(gdb_w, pos);
  199.     have_isearch_line = false;
  200.     private_gdb_output = old_private_gdb_output;
  201. }
  202.  
  203. // When i-search is done, show history position given in client_data
  204. static void isearch_done(XtPointer client_data, XtIntervalId *)
  205. {
  206.     int history = (int)(long)client_data;
  207.  
  208.     if (history >= 0)
  209.     {
  210.     bool old_private_gdb_output = private_gdb_output;
  211.     private_gdb_output = true;
  212.     goto_history(history);
  213.     have_isearch_line = false;
  214.     private_gdb_output = old_private_gdb_output;
  215.     }
  216.  
  217.     show_isearch();
  218. }
  219.  
  220. void isearch_again(ISearchState new_isearch_state, XEvent *event)
  221. {
  222.     if (!gdb->isReadyWithPrompt())
  223.     return;
  224.  
  225.     if (isearch_state == ISEARCH_NONE)
  226.         isearch_string = "";
  227.  
  228.     if (isearch_state == new_isearch_state)
  229.     {
  230.     // Same state - search again
  231.     int history = search_history(isearch_string, int(isearch_state), true);
  232.     if (history < 0)
  233.         XtCallActionProc(gdb_w, "beep", event, 0, 0);
  234.     else
  235.         isearch_done(XtPointer(history), 0);
  236.     }
  237.     else
  238.     {
  239.     isearch_state = new_isearch_state;
  240.     show_isearch();
  241.     }
  242. }
  243.  
  244. // Action: enter reverse i-search
  245. void isearch_prevAct(Widget, XEvent *event, String *, Cardinal *)
  246. {
  247.     isearch_again(ISEARCH_PREV, event);
  248. }
  249.  
  250. // Action: enter forward i-search
  251. void isearch_nextAct(Widget, XEvent *event, String *, Cardinal *)
  252. {
  253.     isearch_again(ISEARCH_NEXT, event);
  254. }
  255.  
  256. // Action: exit i-search
  257. void isearch_exitAct(Widget, XEvent *, String *, Cardinal *)
  258. {
  259.     clear_isearch();
  260. }
  261.  
  262. // Exit i-search mode and return to normal mode
  263. void clear_isearch(bool reset, bool show)
  264. {
  265.     if (!gdb->isReadyWithPrompt())
  266.     return;
  267.  
  268.     if (isearch_state != ISEARCH_NONE)
  269.     {
  270.     isearch_state = ISEARCH_NONE;
  271.     if (show)
  272.         show_isearch();
  273.  
  274.     if (reset)
  275.     {
  276.         set_history_from_line(current_line());
  277.         goto_history();
  278.     }
  279.     }
  280.  
  281.     isearch_motion_ok = false;
  282. }
  283.  
  284. void interruptAct(Widget w, XEvent*, String *, Cardinal *)
  285. {
  286.     if (isearch_state != ISEARCH_NONE)
  287.     {
  288.     clear_isearch();
  289.     }
  290.     else
  291.     {
  292.     gdb_keyboard_command = true;
  293.     gdb_command("\003", w);
  294.     gdb_keyboard_command = true;
  295.     }
  296. }
  297.  
  298. // Handle incremental searches; return true if processed
  299. static bool do_isearch(Widget, XmTextVerifyCallbackStruct *change)
  300. {
  301.     if (isearch_state == ISEARCH_NONE)
  302.     return false;
  303.  
  304.     string saved_isearch_string = isearch_string;
  305.     bool processed = false;
  306.  
  307.     if (change->startPos == change->endPos)
  308.     {
  309.     // Character insertion
  310.     string input = string(change->text->ptr, change->text->length);
  311.     if (!input.contains('\n', -1))
  312.     {
  313.         // Add to current search string
  314.         isearch_string += input;
  315.         processed = true;
  316.     }
  317.     }
  318.     else if (change->endPos - change->startPos == 1)
  319.     {
  320.     // Backspace - remove last character from search string
  321.     if (isearch_string != "")
  322.         isearch_string.after(int(isearch_string.length()) - 2) = "";
  323.     else
  324.         clear_isearch(true, false);
  325.  
  326.     processed = true;
  327.     }
  328.  
  329.     if (processed)
  330.     {
  331.     int history = -1;
  332.     if (isearch_string == "" || current_line().contains(isearch_string))
  333.     {
  334.         // Search string found in current line
  335.         history = -1;
  336.     }
  337.     else
  338.     {
  339.         history = search_history(isearch_string, int(isearch_state));
  340.         if (history < 0)
  341.         {
  342.         // Search string not found in history
  343.         if (change->event != 0)
  344.             XtCallActionProc(gdb_w, "beep", change->event, 0, 0);
  345.         isearch_string = saved_isearch_string;
  346.         }
  347.     }
  348.  
  349.     // Make this a no-op
  350.     if (!have_isearch_line)
  351.     {
  352.         isearch_line = current_line();
  353.         have_isearch_line = true;
  354.     }
  355.  
  356.     // Redraw current line with appropriate prompt.
  357.     XtAppAddTimeOut(XtWidgetToApplicationContext(gdb_w), 0, 
  358.             isearch_done, XtPointer(history));
  359.  
  360.     // Upon the next call to gdbMotionCB(), clear ISearch mode,
  361.     // unless it immediately follows this one.
  362.     isearch_motion_ok = true;
  363.     XtAppAddTimeOut(XtWidgetToApplicationContext(gdb_w), 10,
  364.             set_isearch_motion_ok, XtPointer(false));
  365.     }
  366.  
  367.     return processed;
  368. }
  369.  
  370.  
  371. //-----------------------------------------------------------------------------
  372. // Misc actions
  373. //-----------------------------------------------------------------------------
  374.  
  375. static bool from_keyboard(XEvent *ev)
  376. {
  377.     return ev == 0 || (ev->type != ButtonPress && ev->type != ButtonRelease);
  378. }
  379.  
  380. void controlAct(Widget w, XEvent *ev, String *params, Cardinal *num_params)
  381. {
  382.     clear_isearch();
  383.  
  384.     if (*num_params != 1)
  385.     {
  386.     cerr << "gdb-control: usage: gdb-control(CONTROL-CHARACTER)\n";
  387.     return;
  388.     }
  389.  
  390.     gdb_keyboard_command = from_keyboard(ev);
  391.     gdb_command(ctrl(params[0]), w);
  392.     gdb_keyboard_command = from_keyboard(ev);
  393. }
  394.  
  395. void commandAct(Widget w, XEvent *ev, String *params, Cardinal *num_params)
  396. {
  397.     clear_isearch();
  398.  
  399.     if (*num_params != 1)
  400.     {
  401.     cerr << "gdb-command: usage: gdb-command(COMMAND)\n";
  402.     return;
  403.     }
  404.  
  405.     gdb_keyboard_command = from_keyboard(ev);
  406.     gdb_button_command(params[0], w);
  407.     gdb_keyboard_command = from_keyboard(ev);
  408. }
  409.  
  410. void processAct(Widget w, XEvent *e, String *params, Cardinal *num_params)
  411. {
  412.     if (app_data.source_editing && w == source_view->source())
  413.     {
  414.     // Process event in source window
  415.     string action = "self-insert";   // Default action
  416.     String *action_params      = 0;
  417.     Cardinal num_action_params = 0;
  418.     if (num_params != 0 && *num_params > 0)
  419.     {
  420.         action = params[0];
  421.         action_params = params + 1;
  422.         num_action_params = *num_params - 1;
  423.     }
  424.  
  425.     XtCallActionProc(w, action, e, action_params, num_action_params);
  426.     return;
  427.     }
  428.  
  429.     if (e->type != KeyPress && e->type != KeyRelease)
  430.     return;
  431.  
  432.     static bool running = false;
  433.  
  434.     if (running || !XtIsRealized(gdb_w))
  435.     {
  436.     // Ignore event
  437.     return;
  438.     }
  439.  
  440.     running = true;
  441.  
  442. #if 0
  443.     clear_isearch();        // Why would this be needed???  -AZ
  444. #endif
  445.  
  446.     // Give focus to GDB console
  447.     XmProcessTraversal(gdb_w, XmTRAVERSE_CURRENT);
  448.  
  449.     // Forward event to GDB console
  450.     Window old_window = e->xkey.window;
  451.     e->xkey.window = XtWindow(gdb_w);
  452.     XtDispatchEvent(e);
  453.     e->xkey.window = old_window;
  454.  
  455.     // Return focus to original widget
  456.     XmProcessTraversal(w, XmTRAVERSE_CURRENT);
  457.  
  458.     running = false;
  459. }
  460.  
  461. void insert_source_argAct(Widget w, XEvent*, String*, Cardinal*)
  462. {
  463.     clear_isearch();
  464.  
  465.     string arg = source_arg->get_string();
  466.     if (XmIsText(w)) {
  467.     if (XmTextGetEditable(w)) {
  468.         XmTextPosition pos = XmTextGetInsertionPosition(w);
  469.         XmTextReplace(w, pos, pos, (String)arg);
  470.     }
  471.     }
  472.     else if (XmIsTextField(w)) {
  473.     if (XmTextFieldGetEditable(w)) {
  474.         XmTextPosition pos = XmTextFieldGetInsertionPosition(w);
  475.         XmTextFieldReplace(w, pos, pos, (String)arg);
  476.     }
  477.     }
  478. }
  479.  
  480. void insert_graph_argAct (Widget w, XEvent *ev, 
  481.               String *args, Cardinal *num_args)
  482. {
  483.     // Since both fields are synchronized, it doesn't matter which one
  484.     // we insert.
  485.     insert_source_argAct(w, ev, args, num_args);
  486. }
  487.  
  488. void next_tab_groupAct (Widget w, XEvent*, String*, Cardinal*)
  489. {
  490.     XmProcessTraversal(w, XmTRAVERSE_NEXT_TAB_GROUP);
  491. }
  492.  
  493. void prev_tab_groupAct (Widget w, XEvent*, String*, Cardinal*)
  494. {
  495.     XmProcessTraversal(w, XmTRAVERSE_PREV_TAB_GROUP);
  496. }
  497.  
  498. void get_focusAct (Widget w, XEvent*, String*, Cardinal*)
  499. {
  500.     XmProcessTraversal(w, XmTRAVERSE_CURRENT);
  501. }
  502.  
  503. void select_allAct (Widget w, XEvent *e, String *params, Cardinal *num_params)
  504. {
  505.     switch (app_data.select_all_bindings)
  506.     {
  507.     case KDEBindings:
  508.     XtCallActionProc(w, "select-all", e, params, *num_params);
  509.     break;
  510.  
  511.     case MotifBindings:
  512.     if (w == gdb_w)
  513.         XtCallActionProc(w, "gdb-beginning-of-line", 
  514.                  e, params, *num_params);
  515.     else
  516.         XtCallActionProc(w, "beginning-of-line", e, params, *num_params);
  517.     break;
  518.     }
  519. }
  520.  
  521.  
  522. //-----------------------------------------------------------------------------
  523. // Editing actions
  524. //-----------------------------------------------------------------------------
  525.  
  526. void beginning_of_lineAct(Widget, XEvent*, String*, Cardinal*)
  527. {
  528.     clear_isearch();
  529.     XmTextSetInsertionPosition(gdb_w, promptPosition);
  530. }
  531.  
  532. void end_of_lineAct(Widget, XEvent*, String*, Cardinal*)
  533. {
  534.     clear_isearch();
  535.     XmTextSetInsertionPosition(gdb_w, XmTextGetLastPosition(gdb_w));
  536. }
  537.  
  538. void forward_characterAct(Widget, XEvent *e, 
  539.               String *params, Cardinal *num_params)
  540. {
  541.     clear_isearch();
  542.     XtCallActionProc(gdb_w, "forward-character", e, params, *num_params);
  543. }
  544.  
  545. void backward_characterAct(Widget, XEvent*, String*, Cardinal*)
  546. {
  547.     clear_isearch();
  548.     XmTextPosition pos = XmTextGetInsertionPosition(gdb_w);
  549.     if (pos > promptPosition)
  550.     XmTextSetInsertionPosition(gdb_w, pos - 1);
  551. }
  552.  
  553. void set_current_line(const string& input)
  554. {
  555.     XmTextReplace(gdb_w, promptPosition, XmTextGetLastPosition(gdb_w), 
  556.           (String)input);
  557. }
  558.  
  559. void set_lineAct(Widget, XEvent*, String* params, Cardinal* num_params)
  560. {
  561.     clear_isearch();
  562.     string input = "";
  563.     if (num_params && *num_params > 0)
  564.     input = params[0];
  565.     set_current_line(input);
  566. }
  567.  
  568. void delete_or_controlAct(Widget, XEvent *e, 
  569.               String *params, Cardinal *num_params)
  570. {
  571.     clear_isearch();
  572.     string input = current_line();
  573.     strip_trailing_newlines(input);
  574.     if (input == "")
  575.     XtCallActionProc(gdb_w, "gdb-control", e, params, *num_params);
  576.     else
  577.     XtCallActionProc(gdb_w, "delete-next-character", e, params, *num_params);
  578. }
  579.  
  580. //-----------------------------------------------------------------------------
  581. // Popup menus
  582. //-----------------------------------------------------------------------------
  583.  
  584. static MMDesc gdb_popup[] =
  585. {
  586.     {"clear_line",   MMPush, { gdbClearCB, 0 }, 0, 0, 0, 0},
  587.     {"clear_window", MMPush, { gdbClearWindowCB, 0 }, 0, 0, 0, 0},
  588.     MMEnd
  589. };
  590.  
  591. void popupAct(Widget, XEvent *event, String*, Cardinal*)
  592. {
  593.     static Widget gdb_popup_w = 0;
  594.  
  595.     if (gdb_popup_w == 0)
  596.     {
  597.     gdb_popup_w = MMcreatePopupMenu(gdb_w, "gdb_popup", gdb_popup);
  598.     MMaddCallbacks(gdb_popup);
  599.     MMaddHelpCallback(gdb_popup, ImmediateHelpCB);
  600.     InstallButtonTips(gdb_popup_w);
  601.     }
  602.  
  603.     XmMenuPosition(gdb_popup_w, &event->xbutton);
  604.     XtManageChild(gdb_popup_w);
  605. }
  606.  
  607. //-----------------------------------------------------------------------------
  608. // Callbacks
  609. //-----------------------------------------------------------------------------
  610.  
  611. // Veto changes before the current input line
  612. void gdbModifyCB(Widget gdb_w, XtPointer, XtPointer call_data)
  613. {
  614.     if (private_gdb_output)
  615.     return;
  616.  
  617.     XmTextVerifyCallbackStruct *change = 
  618.     (XmTextVerifyCallbackStruct *)call_data;
  619.  
  620.     if (do_isearch(gdb_w, change))
  621.     return;
  622.  
  623.     clear_isearch();
  624.  
  625.     if (change->startPos < promptPosition)
  626.     {
  627.     // Attempt to change text before prompt
  628. #if 0
  629.     // With Motif, this causes a core dump on Solaris.  - AZ
  630.     change->doit = false;
  631. #else
  632.     // Make it a no-op
  633.     XmTextPosition lastPos = XmTextGetLastPosition(gdb_w);
  634.     change->startPos = promptPosition;
  635.     change->endPos = change->newInsert = change->currInsert = lastPos;
  636.     if (change->text->length == 0 && change->event != 0)
  637.         XtCallActionProc(gdb_w, "beep", change->event, 0, 0);
  638.     XtAppAddTimeOut(XtWidgetToApplicationContext(gdb_w), 0, 
  639.             move_to_end_of_line, XtPointer(0));
  640. #endif
  641.     return;
  642.     }
  643.  
  644.     // Make sure newlines are always inserted at the end of the line
  645.     if (change->startPos == change->endPos &&
  646.     (change->startPos < promptPosition || 
  647.      (change->text->length == 1 && change->text->ptr[0] == '\n')))
  648.     {
  649.     // Add any text at end of text window
  650.     XmTextPosition lastPos = XmTextGetLastPosition(gdb_w);
  651.     change->newInsert = change->startPos = change->endPos = lastPos;
  652.     
  653.     XtAppAddTimeOut(XtWidgetToApplicationContext(gdb_w), 0, 
  654.             move_to_end_of_line, XtPointer(0));
  655.     }
  656. }
  657.  
  658. // Veto key-based cursor movements before current line
  659. void gdbMotionCB(Widget, XtPointer, XtPointer call_data)
  660. {
  661.     if (private_gdb_output)
  662.     return;
  663.  
  664.     XmTextVerifyCallbackStruct *change = 
  665.     (XmTextVerifyCallbackStruct *)call_data;
  666.  
  667.     if (isearch_state != ISEARCH_NONE)
  668.     {
  669.     if (!isearch_motion_ok)
  670.     {
  671.         XtAppAddTimeOut(XtWidgetToApplicationContext(gdb_w), 0, 
  672.                 clear_isearch_after_motion, XtPointer(0));
  673.     }
  674.     isearch_motion_ok = false;
  675.     }
  676.  
  677.     if (change->event != 0
  678.     && (change->event->type == KeyPress 
  679.         || change->event->type == KeyRelease))
  680.     {
  681.     if (change->newInsert < promptPosition)
  682.     {
  683.         // We are before the current prompt: don't change the cursor
  684.         // position if a key was pressed.
  685. #if 0
  686.         // With Motif, this causes a core dump on Solaris.  - AZ
  687.         change->doit = false;
  688. #else
  689.         // Make it a no-op.
  690.         XtCallActionProc(gdb_w, "beep", change->event, 0, 0);
  691.         XtAppAddTimeOut(XtWidgetToApplicationContext(gdb_w), 0, 
  692.                 move_to_end_of_line, 0);
  693. #endif
  694.     }
  695.     }
  696. }
  697.  
  698. // Send completed lines to GDB
  699. void gdbChangeCB(Widget w, XtPointer, XtPointer)
  700. {
  701.     if (private_gdb_output)
  702.     return;
  703.  
  704.     string input = current_line();
  705.  
  706.     bool at_prompt = gdb_input_at_prompt;
  707.     if (at_prompt)
  708.     input.gsub("\\\n", "");
  709.  
  710.     int newlines = input.freq('\n');
  711.     string *lines = new string[newlines + 1];
  712.     split(input, lines, newlines, '\n');
  713.  
  714.     private_gdb_input = true;
  715.  
  716.     if (newlines == 0 || (gdb_input_at_prompt && input.contains('\\', -1)))
  717.     {
  718.     // No newline found - line is still incomplete
  719.     set_history_from_line(input, true);
  720.     }
  721.     else
  722.     {
  723.     // Process entered lines
  724.     clear_isearch();
  725.     promptPosition = XmTextGetLastPosition(w);
  726.     for (int i = 0; i < newlines; i++)
  727.     {
  728.         string cmd = lines[i];
  729.         tty_out(cmd + "\n");
  730.  
  731.         if (gdb_input_at_prompt)
  732.         {
  733.         if (cmd.matches(rxwhite) || cmd == "")
  734.         {
  735.             // Empty line: repeat last command
  736.             cmd = last_command_from_history();
  737.         }
  738.         else
  739.         {
  740.             // Add new command to history
  741.             add_to_history(cmd);
  742.         }
  743.         }
  744.  
  745.         if (at_prompt)
  746.         {
  747.         // We're typing at the GDB prompt: place CMD in command queue
  748.         gdb_command(cmd, w);
  749.         }
  750.         else
  751.         {
  752.         // Pass anything else right to GDB, clearing the command queue.
  753.         clearCommandQueue();
  754.         gdb->send_user_ctrl_cmd(cmd + "\n");
  755.         }
  756.     }
  757.     }
  758.  
  759.     private_gdb_input = false;
  760.  
  761.     delete[] lines;
  762. }
  763.  
  764. //-----------------------------------------------------------------------------
  765. // Callbacks
  766. //-----------------------------------------------------------------------------
  767.  
  768. void gdbCommandCB(Widget w, XtPointer client_data, XtPointer call_data)
  769. {
  770.     clear_isearch();
  771.     XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *)call_data;
  772.     if (cbs->event == 0)
  773.     return;
  774.  
  775.     gdb_button_command((String)client_data, w);
  776.  
  777.     gdb_keyboard_command = from_keyboard(cbs->event);
  778. }
  779.  
  780. void gdb_button_command(const string& command, Widget origin)
  781. {
  782.     if (command.contains("..."))
  783.     {
  784.     set_current_line(command.before("...") + " ");
  785.     }
  786.     else
  787.     {
  788.     string c = command;
  789.     c.gsub("()", source_arg->get_string());
  790.     add_running_arguments(c);
  791.     gdb_command(c, origin);
  792.     }
  793. }
  794.  
  795. void gdbPrevCB  (Widget w, XtPointer, XtPointer call_data)
  796. {
  797.     XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *)call_data;
  798.     if (cbs->event == 0)
  799.     return;
  800.  
  801.     Cardinal zero = 0;
  802.     prev_historyAct(w, cbs->event, 0, &zero);
  803. }
  804.  
  805. void gdbNextCB  (Widget w, XtPointer, XtPointer call_data)
  806. {
  807.     XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *)call_data;
  808.     if (cbs->event == 0)
  809.     return;
  810.  
  811.     Cardinal zero = 0;
  812.     next_historyAct(w, cbs->event, 0, &zero);
  813. }
  814.  
  815. void gdbISearchPrevCB  (Widget w, XtPointer, XtPointer call_data)
  816. {
  817.     XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *)call_data;
  818.     if (cbs->event == 0)
  819.     return;
  820.  
  821.     Cardinal zero = 0;
  822.     isearch_prevAct(w, cbs->event, 0, &zero);
  823. }
  824.  
  825. void gdbISearchNextCB  (Widget w, XtPointer, XtPointer call_data)
  826. {
  827.     XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *)call_data;
  828.     if (cbs->event == 0)
  829.     return;
  830.  
  831.     Cardinal zero = 0;
  832.     isearch_nextAct(w, cbs->event, 0, &zero);
  833. }
  834.  
  835. void gdbISearchExitCB  (Widget w, XtPointer, XtPointer call_data)
  836. {
  837.     XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *)call_data;
  838.     if (cbs->event == 0)
  839.     return;
  840.  
  841.     Cardinal zero = 0;
  842.     isearch_exitAct(w, cbs->event, 0, &zero);
  843. }
  844.  
  845. void gdbClearCB  (Widget, XtPointer, XtPointer)
  846. {
  847.     set_current_line("");
  848. }
  849.  
  850. // Remove any text up to the last GDB prompt
  851. void gdbClearWindowCB(Widget, XtPointer, XtPointer)
  852. {
  853.     XmTextPosition start = start_of_line();
  854.     if (start == XmTextPosition(-1))
  855.     return;
  856.  
  857.     private_gdb_output = true;
  858.  
  859.     XmTextReplace(gdb_w, 0, start, "");
  860.  
  861.     promptPosition  -= start;
  862.     messagePosition -= start;
  863.     XmTextSetInsertionPosition(gdb_w, XmTextGetLastPosition(gdb_w));
  864.  
  865.     private_gdb_output = false;
  866. }
  867.  
  868. void gdbCompleteCB  (Widget w, XtPointer, XtPointer call_data)
  869. {
  870.     if (!gdb->isReadyWithPrompt())
  871.     {
  872.     post_gdb_busy(w);
  873.     return;
  874.     }
  875.  
  876.     clear_isearch();
  877.     XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *)call_data;
  878.     if (cbs->event == 0)
  879.     return;
  880.  
  881.     Cardinal zero = 0;
  882.     end_of_lineAct(gdb_w, cbs->event, 0, &zero);
  883.     complete_commandAct(gdb_w, cbs->event, 0, &zero);
  884. }
  885.  
  886. // Use this for push buttons
  887. void gdbApplyCB(Widget w, XtPointer, XtPointer call_data)
  888. {
  889.     if (!gdb->isReadyWithPrompt())
  890.     {
  891.     post_gdb_busy(w);
  892.     return;
  893.     }
  894.  
  895.     clear_isearch();
  896.     XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *)call_data;
  897.     if (cbs->event == 0)
  898.     return;
  899.  
  900.     Cardinal zero = 0;
  901.     end_of_lineAct(gdb_w, cbs->event, 0, &zero);
  902.     XtCallActionProc(gdb_w, "process-return", cbs->event, 0, zero);
  903. }
  904.  
  905. // Use this for selection boxes
  906. void gdbApplySelectionCB(Widget w, XtPointer, XtPointer call_data)
  907. {
  908.     if (!gdb->isReadyWithPrompt())
  909.     {
  910.     post_gdb_busy(w);
  911.     return;
  912.     }
  913.  
  914.     clear_isearch();
  915.     XmSelectionBoxCallbackStruct *cbs = 
  916.     (XmSelectionBoxCallbackStruct *)call_data;
  917.     if (cbs->event == 0)
  918.     return;
  919.  
  920.     Cardinal zero = 0;
  921.     end_of_lineAct(gdb_w, cbs->event, 0, &zero);
  922.     XtCallActionProc(gdb_w, "process-return", cbs->event, 0, zero);
  923. }
  924.