| Commit | Line | Data |
|---|---|---|
| 7a90c402 | 1 | ;;;; -*- Mode: Lisp ; Package: Debug -*- |
| 2 | ;;; | |
| 0f6159f4 | 3 | ;;; ********************************************************************** |
| 4 | ;;; This code was written as part of the CMU Common Lisp project at | |
| 5 | ;;; Carnegie Mellon University, and has been placed in the public domain. | |
| dae4cf60 | 6 | ;;; |
| 7 | (ext:file-comment | |
| 99a5797f | 8 | "$Header: src/interface/debug.lisp $") |
| 0f6159f4 | 9 | ;;; |
| 10 | ;;; ********************************************************************** | |
| 11 | ;;; | |
| 12 | ;;; Written by Michael Garland | |
| 13 | ;;; | |
| 14 | ;;; This file implements the graphical interface to the debugger. | |
| 15 | ;;; | |
| 7a90c402 | 16 | |
| 17 | (in-package "DEBUG") | |
| a176515c RT |
18 | (eval-when (:compile-toplevel :load-toplevel :execute) |
| 19 | (use-package '("TOOLKIT" "INTERFACE"))) | |
| 7a90c402 | 20 | |
| fe121aad | 21 | ;;; We need to record three things globally: |
| 22 | ;;; - The structure decribing the current debugger display | |
| 23 | ;;; - The frame displays which are currently active (ie. visible) | |
| 24 | ;;; - The husks of old debugger displays for reuse | |
| 25 | ;;; | |
| 7a90c402 | 26 | (defvar *current-debug-display* nil) |
| 27 | (defvar *debug-active-frames* nil) | |
| 28 | (defvar *old-display-frames* nil) | |
| 29 | ||
| 30 | \f | |
| 31 | ||
| 32 | ;;;; Structures used by the graphical debugger | |
| 33 | ||
| 34 | (defstruct (debug-display | |
| 35 | (:conc-name dd-info-) | |
| 36 | (:print-function print-debug-display) | |
| 37 | (:constructor make-debug-display | |
| 0f6159f4 | 38 | (debug-pane errmsg restarts backtrace))) |
| 7a90c402 | 39 | (debug-pane nil :type (or null widget)) |
| 0f6159f4 | 40 | (errmsg nil :type (or null widget)) |
| 7a90c402 | 41 | (restarts nil :type (or null widget)) |
| 42 | (backtrace nil :type (or null widget)) | |
| 43 | (level 0 :type fixnum) | |
| 44 | (connection nil :type (or null xt::motif-connection))) | |
| 45 | ||
| 46 | (defun print-debug-display (info stream d) | |
| 47 | (declare (ignore d)) | |
| 48 | (format stream "#<Debugger Display Info level ~d" (dd-info-level info))) | |
| 49 | ||
| 50 | \f | |
| 51 | ||
| fe121aad | 52 | ;;;; Callback functions used by debugger |
| 7a90c402 | 53 | |
| 0f6159f4 | 54 | (defun quit-debugger-callback (widget call-data) |
| 7a90c402 | 55 | (declare (ignore widget call-data)) |
| 0f6159f4 | 56 | (close-motif-debugger *debug-condition*) |
| 7a90c402 | 57 | (throw 'lisp::top-level-catcher nil)) |
| 58 | ||
| 59 | (defun restart-callback (widget call-data restart) | |
| 60 | (declare (ignore widget call-data)) | |
| 61 | (invoke-restart-interactively restart)) | |
| 62 | ||
| 63 | (defun stack-frame-callback (widget call-data frame) | |
| 64 | (declare (ignore widget call-data)) | |
| 65 | (unless (assoc frame *debug-active-frames*) | |
| 66 | ;; Should wrap this in a busy cursor | |
| 67 | (debug-display-frame frame))) | |
| 68 | ||
| 7a90c402 | 69 | (defun close-all-callback (widget call-data) |
| 70 | (declare (ignore widget call-data)) | |
| 71 | (dolist (info *debug-active-frames*) | |
| 72 | (destroy-widget (cdr info))) | |
| 73 | (setf *debug-active-frames* nil)) | |
| 74 | ||
| fe121aad | 75 | ;;; This is to provide a means for recording the stack backtrace. In |
| 76 | ;;; particular, this is important for sending bug reports. | |
| 77 | ;;; | |
| 78 | (defun dump-backtrace-callback (widget call-data) | |
| 79 | (declare (ignore widget call-data)) | |
| 80 | (let ((*current-frame* (di:top-frame))) | |
| 81 | (format t "~%Stack Backtrace:~%") | |
| 82 | (backtrace))) | |
| 83 | ||
| 7a90c402 | 84 | (defun frame-view-callback (widget call-data thing) |
| 85 | (declare (ignore widget call-data)) | |
| 86 | ;; Should wrap this in a busy cursor | |
| 87 | (inspect thing)) | |
| 88 | ||
| 89 | (defun close-frame-callback (widget call-data frame) | |
| 90 | (declare (ignore widget call-data)) | |
| 91 | (setf *debug-active-frames* | |
| 92 | (delete frame *debug-active-frames* | |
| 93 | :test #'(lambda (a b) (eql a (car b))))) | |
| 94 | (destroy-interface-pane frame)) | |
| 95 | ||
| fe121aad | 96 | (defun edit-source-callback (widget call-data frame) |
| 7a90c402 | 97 | (declare (ignore widget call-data)) |
| fe121aad | 98 | (handler-case |
| 99 | (let ((*current-frame* frame)) | |
| 100 | (funcall (debug-command-p :edit-source))) | |
| 101 | (error (cond) | |
| 92dc7a2d | 102 | (interface-error (safe-condition-message cond))))) |
| 7a90c402 | 103 | |
| 104 | (defun frame-eval-callback (widget call-data frame output) | |
| 105 | (declare (ignore call-data)) | |
| 106 | (let* ((input (car (get-values widget :value))) | |
| 107 | (mark (text-get-last-position output)) | |
| 108 | (response | |
| 109 | (format nil "Eval>> ~a~%~a--------------------~%" | |
| 110 | input | |
| 111 | (handler-case | |
| 112 | (multiple-value-bind | |
| 113 | (out val) | |
| 114 | (let ((*current-frame* frame)) | |
| 115 | (grab-output-as-string | |
| 116 | (di:eval-in-frame frame (read-from-string input)))) | |
| 117 | (format nil "~a~s~%" out val)) | |
| 118 | (error (cond) | |
| 92dc7a2d | 119 | (safe-condition-message cond))))) |
| 120 | (length (length response))) | |
| 7a90c402 | 121 | (declare (simple-string response)) |
| 122 | ||
| 123 | (text-set-string widget "") | |
| 124 | (text-insert output mark response) | |
| 125 | ;; This is to make sure that things stay visible | |
| 126 | (text-set-insertion-position output (+ length mark)))) | |
| 127 | ||
| 128 | (defun source-verbosity-callback (widget call-data frame srcview delta) | |
| 129 | (declare (ignore widget call-data)) | |
| 130 | (let* ((current (car (get-values srcview :user-data))) | |
| 131 | (new (+ current delta))) | |
| 132 | (when (minusp new) | |
| 133 | (setf new 0)) | |
| 134 | (let ((source (handler-case | |
| 135 | (grab-output-as-string | |
| 136 | (print-code-location-source-form | |
| 137 | (di:frame-code-location frame) new)) | |
| 138 | (di:debug-condition (cond) | |
| 139 | (declare (ignore cond)) | |
| 140 | "Source form not available.")))) | |
| 141 | (set-values srcview | |
| 142 | :label-string source | |
| 143 | :user-data new)))) | |
| 144 | ||
| 145 | \f | |
| 146 | ||
| fe121aad | 147 | ;;; DEBUG-DISPLAY-FRAME-LOCALS -- Internal |
| 148 | ;;; | |
| 149 | ;;; This sets up the display of the available local variables for the given | |
| 150 | ;;; stack frame. | |
| 151 | ;;; | |
| 7a90c402 | 152 | (defun debug-display-frame-locals (frame debug-fun location frame-view) |
| 153 | (let (widgets) | |
| 154 | (if (di:debug-variable-info-available debug-fun) | |
| 155 | (let ((any-p nil) | |
| 156 | (any-valid-p nil)) | |
| 157 | (di:do-debug-function-variables (v debug-fun) | |
| 158 | (unless any-p | |
| 159 | (setf any-p t) | |
| cfa32fc4 | 160 | (push (create-label frame-view "localsLabel" |
| 7a90c402 | 161 | :font-list *header-font* |
| 162 | :label-string "Local variables:") | |
| 163 | widgets)) | |
| 164 | (when (eq (di:debug-variable-validity v location) :valid) | |
| 165 | (let ((value (di:debug-variable-value v frame)) | |
| 166 | (id (di:debug-variable-id v))) | |
| 167 | (setf any-valid-p t) | |
| 168 | (push | |
| 169 | (create-value-box frame-view | |
| 170 | (format nil " ~A~:[#~D~;~*~]:" | |
| 171 | (di:debug-variable-name v) | |
| 172 | (zerop id) id) | |
| 173 | value | |
| 174 | :callback 'frame-view-callback) | |
| 175 | widgets)))) | |
| 176 | (cond | |
| 177 | ((not any-p) | |
| 178 | (push | |
| cfa32fc4 | 179 | (create-label frame-view "noLocals" |
| 7a90c402 | 180 | :font-list *italic-font* |
| 181 | :label-string | |
| 182 | " No local variables in function.") | |
| 183 | widgets)) | |
| 184 | ((not any-valid-p) | |
| 185 | (push | |
| cfa32fc4 | 186 | (create-label frame-view "noValidLocals" |
| 7a90c402 | 187 | :font-list *italic-font* |
| 188 | :label-string | |
| 189 | " All variables have invalid values.") | |
| 190 | widgets)))) | |
| 191 | ||
| cfa32fc4 | 192 | (push (create-label frame-view "noVariableInfo" |
| 7a90c402 | 193 | :font-list *italic-font* |
| 194 | :label-string | |
| 195 | " No variable information available.") | |
| 196 | widgets)) | |
| 197 | (apply #'manage-children widgets))) | |
| 198 | ||
| fe121aad | 199 | ;;; DEBUG-DISPLAY-FRAME-PROMPT -- Internal |
| 200 | ;;; | |
| 201 | ;;; Every frame window has a Frame Eval area. This function creates the | |
| 202 | ;;; Eval area and attaches the necessary callbacks. | |
| 203 | ;;; | |
| 7a90c402 | 204 | (defun debug-display-frame-prompt (frame frame-view) |
| 205 | (let* ((form (create-form frame-view "promptForm")) | |
| cfa32fc4 | 206 | (label (create-label form "framePrompt" |
| 7a90c402 | 207 | :label-string "Frame Eval:" |
| 208 | :font-list *header-font*)) | |
| 209 | (entry (create-text form "frameEval" | |
| 210 | :top-attachment :attach-widget | |
| 211 | :top-widget label | |
| 212 | :left-attachment :attach-form | |
| 213 | :right-attachment :attach-form)) | |
| 214 | (output (create-text form "frameOutput" | |
| 215 | :edit-mode :multi-line-edit | |
| 216 | :editable nil | |
| 217 | :rows 8 | |
| 218 | :columns 40 | |
| 219 | :top-attachment :attach-widget | |
| 220 | :top-widget entry | |
| 221 | :bottom-attachment :attach-form | |
| 222 | :left-attachment :attach-form | |
| 223 | :right-attachment :attach-form))) | |
| 224 | ||
| 225 | (manage-child form) | |
| 226 | (manage-children label entry output) | |
| 227 | (add-callback entry :activate-callback 'frame-eval-callback | |
| 228 | frame output))) | |
| 229 | ||
| fe121aad | 230 | ;;; DEBUG-DISPLAY-FRAME -- Internal |
| 231 | ;;; | |
| 232 | ;;; Function to generate the graphical display for the given frame. Each | |
| 233 | ;;; frame window is composed of the following parts: | |
| 234 | ;;; - The function called | |
| 235 | ;;; - The source form | |
| 236 | ;;; - Local variables | |
| 237 | ;;; - Frame Eval window | |
| 238 | ;;; | |
| 7a90c402 | 239 | (defun debug-display-frame (frame) |
| 240 | (let* ((debug-fun (di:frame-debug-function frame)) | |
| 241 | (location (di:frame-code-location frame)) | |
| 242 | (name (di:debug-function-name debug-fun)) | |
| 243 | (title (format nil "Stack Frame: ~A" name)) | |
| 244 | (frame-shell (create-interface-pane-shell title frame)) | |
| 245 | (frame-view (create-row-column frame-shell "debugFrameView")) | |
| 246 | (menu-bar (create-menu-bar frame-view "frameMenu")) | |
| cfa32fc4 | 247 | (fcall (create-label frame-view "frameCall" |
| 7a90c402 | 248 | :label-string |
| 249 | (format nil "Frame Call: ~a" | |
| 250 | (grab-output-as-string | |
| 251 | (print-frame-call frame))))) | |
| 252 | (fbox (create-value-box frame-view "Function:" | |
| 253 | name | |
| 254 | :callback 'frame-view-callback | |
| 255 | :client-data | |
| 256 | (di:debug-function-function debug-fun))) | |
| cfa32fc4 | 257 | (slabel (create-label frame-view "sourceLabel" |
| 7a90c402 | 258 | :font-list *header-font* |
| 259 | :label-string "Source form:")) | |
| 260 | (swindow (create-scrolled-window frame-view "frameSourceWindow" | |
| 261 | :scrolling-policy :automatic | |
| 262 | :scroll-bar-placement :bottom-right)) | |
| 263 | ||
| 264 | (source (handler-case | |
| 265 | (grab-output-as-string | |
| 266 | (print-code-location-source-form location 0)) | |
| 267 | (di:debug-condition (cond) | |
| 268 | (declare (ignore cond)) | |
| 269 | "Source form not available."))) | |
| cfa32fc4 | 270 | (srcview (create-label swindow "sourceForm" |
| 271 | :alignment :alignment-beginning | |
| 272 | :user-data 0 | |
| 273 | :label-string source)) | |
| 7a90c402 | 274 | (cascade1 |
| 275 | (create-interface-menu menu-bar "Frame" | |
| fe121aad | 276 | `(("Edit Source" edit-source-callback ,frame) |
| 7a90c402 | 277 | ("Expand Source Form" source-verbosity-callback ,frame ,srcview 1) |
| 278 | ("Shrink Source Form" source-verbosity-callback ,frame ,srcview -1) | |
| 279 | ("Close Frame" close-frame-callback ,frame)))) | |
| 280 | (cascade2 (create-cached-menu menu-bar "Debug"))) | |
| 281 | ||
| 282 | (manage-child frame-view) | |
| 283 | (manage-children menu-bar fcall fbox slabel swindow) | |
| 284 | (manage-child srcview) | |
| 285 | (manage-children cascade1 cascade2) | |
| 286 | ||
| 287 | (debug-display-frame-locals frame debug-fun location frame-view) | |
| 288 | (debug-display-frame-prompt frame frame-view) | |
| 289 | ||
| 290 | (popup-interface-pane frame-shell) | |
| 291 | (push (cons frame frame-shell) *debug-active-frames*))) | |
| 292 | ||
| 293 | \f | |
| 294 | ||
| 295 | ;;;; Functions to display the debugger control panel | |
| 296 | ||
| fe121aad | 297 | ;;; DEBUG-DISPLAY-ERROR -- Internal |
| 298 | ;;; | |
| 299 | ;;; Fills in the given widget with the error message for the given | |
| 300 | ;;; condition. | |
| 301 | ;;; | |
| 7a90c402 | 302 | (defun debug-display-error (errmsg condition) |
| 92dc7a2d | 303 | (set-values errmsg :label-string (safe-condition-message condition))) |
| 7a90c402 | 304 | |
| fe121aad | 305 | ;;; DEBUG-DISPLAY-RESTARTS -- Internal |
| 306 | ;;; | |
| 307 | ;;; Fills in a RowColumn box with buttons corresponding to the currently | |
| 308 | ;;; active restarts. | |
| 309 | ;;; | |
| 0f6159f4 | 310 | (defun debug-display-restarts (restart-view) |
| 311 | (let ((widgets (reverse (xti:widget-children restart-view))) | |
| 312 | (used-ones)) | |
| 313 | ||
| 7a90c402 | 314 | (dolist (r *debug-restarts*) |
| 0f6159f4 | 315 | (let* ((label (format nil "~A" r)) |
| 316 | (button (if widgets | |
| 317 | (let ((w (pop widgets))) | |
| 318 | (set-values w :label-string label) | |
| 319 | (remove-all-callbacks w :activate-callback) | |
| 320 | w) | |
| 321 | (create-highlight-button restart-view | |
| 322 | "restartButton" | |
| 323 | label)))) | |
| 324 | ||
| 7a90c402 | 325 | (add-callback button :activate-callback 'restart-callback r) |
| 0f6159f4 | 326 | (push button used-ones))) |
| 327 | (apply #'manage-children used-ones) | |
| 328 | (when widgets | |
| 329 | (apply #'unmanage-children widgets)))) | |
| 7a90c402 | 330 | |
| fe121aad | 331 | ;;; DEBUG-DISPLAY-STACK -- Internal |
| 332 | ;;; | |
| 333 | ;;; Fills in a RowColumn box with buttons corresponding to the stack frames | |
| 334 | ;;; found on the stack. | |
| 335 | ;;; | |
| 7a90c402 | 336 | (defun debug-display-stack (backtrace) |
| 0f6159f4 | 337 | (let ((widgets (reverse (xti:widget-children backtrace))) |
| 338 | (used-ones) | |
| 339 | (frames)) | |
| 340 | ||
| 7a90c402 | 341 | (do ((frame *current-frame* (di:frame-down frame))) |
| 342 | ((null frame)) | |
| 0f6159f4 | 343 | (push frame frames)) |
| 344 | (setf frames (nreverse frames)) | |
| 345 | ||
| 346 | (dolist (frame frames) | |
| 347 | (let* ((label (grab-output-as-string | |
| 348 | (print-frame-call frame))) | |
| 349 | (button (if widgets | |
| 350 | (let ((w (pop widgets))) | |
| 351 | (set-values w :label-string label) | |
| 352 | (remove-all-callbacks w :activate-callback) | |
| 353 | w) | |
| 354 | (create-highlight-button | |
| 355 | backtrace "stackFrame" label)))) | |
| 7a90c402 | 356 | (add-callback button :activate-callback 'stack-frame-callback frame) |
| 0f6159f4 | 357 | (push button used-ones))) |
| 358 | (apply #'manage-children used-ones) | |
| 359 | (when widgets | |
| 360 | (apply #'unmanage-children widgets)))) | |
| 7a90c402 | 361 | |
| fe121aad | 362 | ;;; REALLY-CREATE-DEBUGGER -- Internal |
| 363 | ;;; | |
| 364 | ;;; This creates all the widgets used by the main debugger window. It | |
| 365 | ;;; calls various sub-functions such as DEBUG-DISPLAY-STACK to fill in the | |
| 366 | ;;; various display sections. It should only be called if there are no old | |
| 367 | ;;; debugger panes available for recycling. | |
| 368 | ;;; | |
| 0f6159f4 | 369 | (defun really-create-debugger (condition) |
| 7a90c402 | 370 | (let* ((debug-pane (create-interface-pane-shell "Debugger" condition)) |
| 371 | (frame (create-frame debug-pane "debugFrame")) | |
| 372 | (form (create-form frame "debugForm")) | |
| 373 | (menu-bar (create-menu-bar form "debugMenu" | |
| 374 | :left-attachment :attach-form | |
| 375 | :right-attachment :attach-form)) | |
| 376 | (cascade (create-cached-menu | |
| 377 | menu-bar "Debug" | |
| 0f6159f4 | 378 | '(("Close All Frames" close-all-callback) |
| fe121aad | 379 | ("Dump Backtrace" dump-backtrace-callback) |
| 0f6159f4 | 380 | ("Quit Debugger" quit-debugger-callback)))) |
| cfa32fc4 | 381 | (errlabel (create-label form "errorLabel" |
| 7a90c402 | 382 | :top-attachment :attach-widget |
| 383 | :top-widget menu-bar | |
| 384 | :left-attachment :attach-form | |
| 385 | :font-list *header-font* | |
| 386 | :label-string "Error Message:")) | |
| cfa32fc4 | 387 | (errmsg (create-label form "errorMessage" |
| 7a90c402 | 388 | :top-attachment :attach-widget |
| 389 | :top-widget errlabel | |
| 390 | :left-attachment :attach-form | |
| 391 | :right-attachment :attach-form)) | |
| cfa32fc4 | 392 | (rlabel (create-label form "restartLabel" |
| 7a90c402 | 393 | :top-attachment :attach-widget |
| 394 | :top-widget errmsg | |
| 395 | :left-attachment :attach-form | |
| 396 | :font-list *header-font*)) | |
| 397 | (restarts (create-row-column form "debugRestarts" | |
| 398 | :adjust-last nil | |
| 399 | :top-attachment :widget | |
| 400 | :top-widget rlabel | |
| 401 | :left-attachment :attach-form | |
| 402 | :right-attachment :attach-form | |
| 403 | :left-offset 10)) | |
| cfa32fc4 | 404 | (btlabel (create-label form "backtraceLabel" |
| 7a90c402 | 405 | :label-string "Stack Backtrace:" |
| 406 | :font-list *header-font* | |
| 407 | :top-attachment :attach-widget | |
| 408 | :top-widget restarts | |
| 409 | :left-attachment :attach-form)) | |
| 410 | (btwindow (create-scrolled-window form "backtraceWindow" | |
| 411 | :scrolling-policy :automatic | |
| 412 | :scroll-bar-placement :bottom-right | |
| 413 | :left-attachment :attach-form | |
| 414 | :right-attachment :attach-form | |
| 415 | :left-offset 4 | |
| 416 | :right-offset 4 | |
| 417 | :bottom-offset 4 | |
| 418 | :bottom-attachment :attach-form | |
| 419 | :top-attachment :attach-widget | |
| 420 | :top-widget btlabel)) | |
| 421 | (backtrace (create-row-column btwindow "debugBacktrace" | |
| 422 | :adjust-last nil | |
| 423 | :spacing 1))) | |
| 424 | ||
| 425 | (manage-child frame) (manage-child form) | |
| 426 | (manage-children menu-bar errlabel errmsg rlabel restarts btlabel btwindow) | |
| 427 | (manage-child backtrace) | |
| 428 | (manage-child cascade) | |
| 429 | ||
| 430 | (debug-display-error errmsg condition) | |
| 431 | ||
| 432 | (if *debug-restarts* | |
| 433 | (progn | |
| 434 | (set-values rlabel :label-string "Restarts:") | |
| 435 | (debug-display-restarts restarts)) | |
| 436 | (set-values rlabel :label-string "No restarts available")) | |
| 437 | ||
| 0f6159f4 | 438 | (let ((quick-stack (create-highlight-button backtrace "quickStack" |
| 439 | "Display Stack"))) | |
| 440 | (add-callback quick-stack :activate-callback | |
| 441 | #'(lambda (w c) (declare (ignore w c)) | |
| 442 | (debug-display-stack backtrace))) | |
| 443 | (manage-child quick-stack)) | |
| 444 | ||
| 7a90c402 | 445 | |
| 446 | (setf *current-debug-display* | |
| 0f6159f4 | 447 | (make-debug-display debug-pane errmsg restarts backtrace)) |
| 7a90c402 | 448 | |
| 449 | (popup-interface-pane debug-pane) | |
| 450 | debug-pane)) | |
| 0f6159f4 | 451 | |
| fe121aad | 452 | ;;; REUSE-DEBUGGER -- Internal |
| 453 | ;;; | |
| 454 | ;;; Takes an old debugger pane and a new condition. It renovates the old | |
| 455 | ;;; display to reflect the current debugging state. This should be used | |
| 456 | ;;; whenever possible since it is quite a bit faster than creating a new | |
| 457 | ;;; debugger pane from scratch. | |
| 458 | ;;; | |
| 0f6159f4 | 459 | (defun reuse-debugger (condition info) |
| 460 | (let ((debug-pane (dd-info-debug-pane info)) | |
| 461 | (errmsg (dd-info-errmsg info)) | |
| 462 | (restarts (dd-info-restarts info)) | |
| 463 | (backtrace (dd-info-backtrace info))) | |
| 464 | ||
| 465 | (debug-display-error errmsg condition) | |
| 466 | (debug-display-restarts restarts) | |
| 467 | ||
| 468 | (let* ((buttons (xti:widget-children backtrace)) | |
| 469 | (quick-stack (car buttons))) | |
| 470 | (remove-all-callbacks quick-stack :activate-callback) | |
| 471 | (set-values quick-stack :label-string "Display Stack") | |
| 472 | (add-callback quick-stack :activate-callback | |
| 473 | #'(lambda (w c) (declare (ignore w c)) | |
| 474 | (debug-display-stack backtrace))) | |
| 475 | (manage-child quick-stack) | |
| 476 | (apply #'unmanage-children (cdr buttons))) | |
| 477 | ||
| 478 | (setf *current-debug-display* info) | |
| 479 | (popup-interface-pane debug-pane) | |
| 480 | debug-pane)) | |
| 481 | ||
| fe121aad | 482 | ;;; CREATE-DEBUGGER -- Internal |
| 483 | ;;; | |
| 484 | ;;; Creates a graphical debugger display for the given condition. It will | |
| 485 | ;;; attempt to reuse any available old panes. However, if none are | |
| 486 | ;;; available, it will create a new display frame. | |
| 487 | ;;; | |
| 0f6159f4 | 488 | (defun create-debugger (condition) |
| 489 | (if *old-display-frames* | |
| 490 | (reuse-debugger condition (pop *old-display-frames*)) | |
| 491 | (really-create-debugger condition))) | |
| 492 | ||
| fe121aad | 493 | ;;; CLOSE-MOTIF-DEBUGGER -- Internal |
| 494 | ;;; | |
| 495 | ;;; This function should always be called before leaving the context of the | |
| 496 | ;;; debugger. It closes down the frame windows and marks the main debug | |
| 497 | ;;; display pane as ready for recycling. | |
| 498 | ;;; | |
| 7a90c402 | 499 | (defun close-motif-debugger (condition) |
| 0f6159f4 | 500 | (declare (ignore condition)) |
| 7a90c402 | 501 | (push *current-debug-display* *old-display-frames*) |
| 502 | ;; | |
| 503 | ;; Destroy all frame panes | |
| 504 | (dolist (info *debug-active-frames*) | |
| 505 | (destroy-widget (cdr info))) | |
| 506 | (setf *debug-active-frames* nil) | |
| 507 | ;; | |
| 0f6159f4 | 508 | ;; Remove the restart/backtrace window |
| 509 | (popdown (dd-info-debug-pane *current-debug-display*)) | |
| 7a90c402 | 510 | (setf *current-debug-display* nil) |
| 7a90c402 | 511 | |
| 512 | (format t "Leaving debugger.~%")) | |
| 513 | ||
| fe121aad | 514 | ;;; INVOKE-MOTIF-DEBUGGER -- Internal |
| 515 | ;;; | |
| 516 | ;;; This function essentially mimics the functions which manage the TTY | |
| 517 | ;;; debugger, but uses a graphical debugging display instead. | |
| 518 | ;;; | |
| 7a90c402 | 519 | (defun invoke-motif-debugger (condition) |
| fe121aad | 520 | (let* ((*in-the-debugger* t) |
| 521 | (frame (di:top-frame)) | |
| 7a90c402 | 522 | (previous-display *current-debug-display*) |
| 523 | (*current-debug-display* nil) | |
| 524 | (*debug-active-frames* nil)) | |
| 525 | (declare (ignore previous-display)) | |
| 526 | (verify-system-server-exists) | |
| 527 | (multiple-value-bind (shell connection) | |
| 528 | (create-interface-shell) | |
| 529 | (declare (ignore shell)) | |
| 9befdffb | 530 | (if connection |
| 531 | (with-motif-connection (connection) | |
| 532 | (let ((pane (find-interface-pane condition)) | |
| 533 | (*current-frame* frame)) | |
| 534 | (unless pane | |
| 535 | (setf pane (create-debugger condition))) | |
| 536 | (unless (is-managed pane) | |
| 537 | (popup-interface-pane pane)) | |
| 538 | (setf (dd-info-level *current-debug-display*) | |
| 539 | *debug-command-level*) | |
| 540 | (setf (dd-info-connection *current-debug-display*) connection) | |
| 541 | (unwind-protect | |
| 542 | (handler-case | |
| 543 | (loop | |
| 544 | (system:serve-event)) | |
| 545 | (error (err) | |
| 546 | (if *flush-debug-errors* | |
| 92dc7a2d | 547 | (interface-error (safe-condition-message err) |
| 548 | pane) | |
| 9befdffb | 549 | (interface-error |
| 550 | "Do not yet support recursive debugging" | |
| 551 | pane)))) | |
| 552 | (when (and connection *current-debug-display*) | |
| 553 | (with-motif-connection (connection) | |
| 554 | (close-motif-debugger condition)))))) | |
| 555 | (invoke-tty-debugger condition))))) | |
| 7a90c402 | 556 | |
| 557 | \f | |
| 558 | ||
| a64ae2c1 | 559 | ;;; Used to prevent recursive invocations of the windowing debugger. |
| 560 | ;;; | |
| 561 | (defvar *in-windowing-debugger* nil) | |
| 562 | ||
| 9befdffb | 563 | |
| 92dc7a2d | 564 | ;;; REAL-INVOKE-DEBUGGER -- Internal |
| 565 | ;;; | |
| 566 | ;;; Invokes the Lisp debugger. It decides whether to invoke the TTY | |
| 567 | ;;; debugger or the Motif debugger. | |
| 568 | ;;; | |
| 569 | (defun real-invoke-debugger (condition) | |
| 570 | (if (or (not (use-graphics-interface)) | |
| 571 | *in-windowing-debugger* | |
| 572 | (typep condition 'xti:toolkit-error)) | |
| 573 | (invoke-tty-debugger condition) | |
| 574 | (let ((*in-windowing-debugger* t)) | |
| 575 | (write-line "Invoking debugger...") | |
| 576 | (invoke-motif-debugger condition)))) |