* plugins/debug-manager/disassemble.c,
[anjuta-git-plugin.git] / plugins / debug-manager / breakpoints.c
blobad08435dd1d8d6d95dffb6b6a62eb3bdda64f0f7
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 breakpoints.c
4 Copyright (C) 2007 Sébastien Granjoux
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 * Handle breakpoints, mainly the graphical interface as the communication
23 * with the debugger is handled by the corresponding debugger plugin. The
24 * grahical interface includes:
25 * - A dialog including a tree view with all breakpoints
26 * - Several associated dialog (create a new breakpoints, confirmation...)
27 * - The markers in the editor plugin
29 * The list of breakpoints is kept in the tree view (GtkTreeModel).
31 * The AnjutaDebuggerBreakpoint object is used to communicate with the debugger plugin,
32 * it includes all useful information for a breakpoint. Part of this structure
33 * is filled by the debugger plugin, another part by the debug manager plugin.
34 * This object is normally created and destroyed by the debug manager, but
35 * the debugger plugin could create one too (but never destroy it).
37 * The BreakpointItem object includes a AnjutaDebuggerBreakpoint and adds all useful
38 * information for the graphical interface (pointer to the editor...)
39 *---------------------------------------------------------------------------*/
41 #ifdef HAVE_CONFIG_H
42 # include <config.h>
43 #endif
45 /*#define DEBUG*/
47 #include <sys/stat.h>
48 #include <unistd.h>
49 #include <string.h>
50 #include <ctype.h>
52 #include <gnome.h>
53 #include <libgnomevfs/gnome-vfs-utils.h>
55 #include <libanjuta/resources.h>
56 #include <libanjuta/anjuta-debug.h>
57 #include <libanjuta/interfaces/ianjuta-document-manager.h>
58 #include <libanjuta/interfaces/ianjuta-markable.h>
59 #include <libanjuta/interfaces/ianjuta-file.h>
60 #include <libanjuta/interfaces/ianjuta-debugger-breakpoint.h>
62 #include "breakpoints.h"
63 #include "utilities.h"
64 #include "queue.h"
66 /* Markers definition */
67 #define BREAKPOINT_ENABLED IANJUTA_MARKABLE_BREAKPOINT_ENABLED
68 #define BREAKPOINT_DISABLED IANJUTA_MARKABLE_BREAKPOINT_DISABLED
69 #define BREAKPOINT_NONE -1
71 typedef struct _BreakpointItem BreakpointItem;
72 typedef struct _BreakpointPacket BreakpointPacket;
74 /* Breakpoint data */
75 struct _BreakpointItem
77 IAnjutaDebuggerBreakpointItem bp; /* Breakpoint data */
78 guint ref;
80 gint handle; /* Handle to mark in editor */
81 IAnjutaEditor *editor;
82 gchar* uri;
84 gint changed; /* Bit field tagging change in breakpoint */
87 GtkTreeIter iter;
89 BreakpointsDBase *bd;
92 struct _BreakpointsDBase
94 DebugManagerPlugin *plugin;
95 DmaDebuggerQueue *debugger;
97 GtkListStore *model;
99 GladeXML *gxml;
100 gchar *cond_history, *loc_history;
102 /* Widgets */
103 GtkWidget *window;
104 GtkTreeView *treeview;
105 GtkWidget *add_button;
106 GtkWidget *remove_button;
107 GtkWidget *jumpto_button;
108 GtkWidget *properties_button;
109 GtkWidget *removeall_button;
110 GtkWidget *enableall_button;
111 GtkWidget *disableall_button;
113 /* Menu action */
114 GtkActionGroup *debugger_group;
115 GtkActionGroup *permanent_group;
117 /* Editor watch id */
118 guint editor_watch;
122 enum {
123 ENABLED_COLUMN,
124 LOCATION_COLUMN,
125 ADDRESS_COLUMN,
126 TYPE_COLUMN,
127 CONDITION_COLUMN,
128 PASS_COLUMN,
129 STATE_COLUMN,
130 DATA_COLUMN,
131 COLUMNS_NB
134 /* Helper functions
135 *---------------------------------------------------------------------------*/
137 /* BreakItem functions
138 *---------------------------------------------------------------------------*/
140 static void
141 breakpoint_item_update_from_debugger (BreakpointItem *bi, const IAnjutaDebuggerBreakpointItem* bp)
143 if (bp == NULL) return;
145 bi->bp.id = bp->id;
146 if (bp->type & IANJUTA_DEBUGGER_BREAKPOINT_REMOVED)
148 bi->bp.type |= IANJUTA_DEBUGGER_BREAKPOINT_REMOVED;
149 return;
151 if (bp->type & IANJUTA_DEBUGGER_BREAKPOINT_ON_LINE)
153 bi->bp.type |= IANJUTA_DEBUGGER_BREAKPOINT_ON_LINE;
154 g_free (bi->bp.file);
155 bi->bp.file = g_strdup (bp->file);
156 bi->bp.line = bp->line;
157 if ((bi->uri == NULL) && (g_path_is_absolute (bp->file)))
158 bi->uri = gnome_vfs_get_uri_from_local_path (bp->file);
160 if (bp->type & IANJUTA_DEBUGGER_BREAKPOINT_ON_FUNCTION)
162 bi->bp.type |= IANJUTA_DEBUGGER_BREAKPOINT_ON_FUNCTION;
163 g_free (bi->bp.function);
164 bi->bp.function = g_strdup (bp->function);
166 if (bp->type & IANJUTA_DEBUGGER_BREAKPOINT_ON_ADDRESS)
168 bi->bp.type |= IANJUTA_DEBUGGER_BREAKPOINT_ON_ADDRESS;
169 bi->bp.address = bp->address;
171 if (bp->type & IANJUTA_DEBUGGER_BREAKPOINT_WITH_TIME)
173 bi->bp.times = bp->times;
175 if (bp->type & IANJUTA_DEBUGGER_BREAKPOINT_WITH_TEMPORARY)
177 bi->bp.temporary = bp->temporary;
179 if ((bp->type & IANJUTA_DEBUGGER_BREAKPOINT_WITH_ENABLE) &&
180 !(bi->changed & IANJUTA_DEBUGGER_BREAKPOINT_WITH_ENABLE))
182 bi->bp.enable = bp->enable;
184 if ((bp->type & IANJUTA_DEBUGGER_BREAKPOINT_WITH_CONDITION) &&
185 !(bi->changed & IANJUTA_DEBUGGER_BREAKPOINT_WITH_CONDITION))
187 g_free (bi->bp.condition);
188 bi->bp.condition = bp->condition == NULL ? NULL : g_strdup (bp->condition);
190 if ((bp->type & IANJUTA_DEBUGGER_BREAKPOINT_WITH_IGNORE) &&
191 !(bi->changed & IANJUTA_DEBUGGER_BREAKPOINT_WITH_IGNORE))
193 bi->bp.ignore = bp->ignore;
197 static void
198 breakpoint_item_ref (BreakpointItem *bi)
200 bi->ref++;
203 static gboolean
204 breakpoint_item_unref (BreakpointItem *bi)
206 g_return_val_if_fail (bi != NULL, FALSE);
208 bi->ref--;
209 if (bi->ref > 0) return FALSE;
211 /* Remove from list */
212 gtk_list_store_remove (bi->bd->model, &bi->iter);
214 if (bi->editor != NULL)
216 g_object_remove_weak_pointer (G_OBJECT (bi->editor), (gpointer *)(gpointer)&bi->editor);
217 bi->editor = NULL;
220 g_free ((char *)bi->bp.file);
221 bi->bp.file = NULL;
222 g_free ((char *)bi->bp.function);
223 bi->bp.function = NULL;
224 g_free ((char *)bi->bp.condition);
225 bi->bp.condition = NULL;
227 return TRUE;
230 /* BreakItem constructor & destructor
231 *---------------------------------------------------------------------------*/
233 static BreakpointItem *
234 breakpoint_item_new (BreakpointsDBase *bd)
236 BreakpointItem *bi;
237 bi = g_new0 (BreakpointItem, 1);
238 bi->ref = 1;
239 bi->bd = bd;
240 bi->editor = NULL;
241 bi->handle = -1;
243 bi->bp.type = 0;
245 gtk_list_store_append (bd->model, &bi->iter);
246 gtk_list_store_set (bd->model, &bi->iter, DATA_COLUMN, bi, -1);
248 return bi;
251 static BreakpointItem *
252 breakpoint_item_new_from_uri (BreakpointsDBase *bd, const gchar* uri, guint line, gboolean enable)
254 BreakpointItem *bi;
256 g_return_val_if_fail (uri != NULL, NULL);
258 bi = breakpoint_item_new (bd);
260 bi->uri = g_strdup (uri);
261 bi->bp.type = IANJUTA_DEBUGGER_BREAKPOINT_ON_LINE | IANJUTA_DEBUGGER_BREAKPOINT_WITH_ENABLE;
262 bi->bp.file = gnome_vfs_get_local_path_from_uri (uri);
263 bi->bp.line = line;
264 bi->bp.enable = enable;
266 return bi;
269 static BreakpointItem *
270 breakpoint_item_new_from_string (BreakpointsDBase *bd, const gchar* string, const gchar* uri)
272 BreakpointItem *bi;
274 bi = breakpoint_item_new (bd);
276 if (*string == '*')
278 /* break at address */
279 if ((string[1] == '0') && ((string[2] == 'x') || (string[2] == 'X')))
281 bi->bp.address = strtoul (string + 3, NULL, 16);
283 else
285 bi->bp.address = strtoul (string + 3, NULL, 10);
287 bi->bp.type = IANJUTA_DEBUGGER_BREAKPOINT_ON_ADDRESS;
289 else if ((uri != NULL) && isdigit (*string))
291 bi->uri = g_strdup (uri);
292 bi->bp.file = gnome_vfs_get_local_path_from_uri (uri);
293 bi->bp.line = strtoul (string, NULL, 10);
294 bi->bp.type = IANJUTA_DEBUGGER_BREAKPOINT_ON_LINE;
296 else
298 const gchar *ptr;
300 ptr = strchr (string, ':');
302 if (ptr == NULL)
304 /* break on function */
305 bi->bp.function = g_strdup (string);
306 bi->bp.type = IANJUTA_DEBUGGER_BREAKPOINT_ON_FUNCTION;
308 else
310 if (isdigit (ptr[1]))
312 bi->bp.line = strtoul (ptr + 1, NULL, 10);
313 bi->bp.type = IANJUTA_DEBUGGER_BREAKPOINT_ON_LINE;
315 else
317 bi->bp.function = g_strdup (ptr + 1);
318 bi->bp.type = IANJUTA_DEBUGGER_BREAKPOINT_ON_FUNCTION;
320 bi->bp.file = g_strndup (string, ptr - string);
321 bi->uri = gnome_vfs_get_uri_from_local_path (bi->bp.file);
325 bi->bp.enable = TRUE;
326 bi->bp.type |= IANJUTA_DEBUGGER_BREAKPOINT_WITH_ENABLE;
328 return bi;
331 /* User interface functions
332 *---------------------------------------------------------------------------*/
334 static void
335 breakpoints_dbase_set_in_editor (BreakpointsDBase *bd, BreakpointItem *bi)
337 IAnjutaMarkable *ed = NULL;
338 gint line = -1;
340 g_return_if_fail (bi != NULL);
342 if (bi->editor == NULL)
344 return;
347 ed = IANJUTA_MARKABLE (bi->editor);
348 if (bi->handle != -1)
350 line = ianjuta_markable_location_from_handle (ed, bi->handle, NULL);
352 /* Remove old mark */
353 ianjuta_markable_unmark (ed, line, BREAKPOINT_ENABLED, NULL);
354 ianjuta_markable_unmark (ed, line, BREAKPOINT_DISABLED,NULL);
356 else
358 line = bi->bp.line;
361 /* Add new mark */
362 bi->handle = ianjuta_markable_mark (ed, line, bi->bp.enable ? BREAKPOINT_ENABLED : BREAKPOINT_DISABLED, NULL);
365 static void
366 breakpoints_dbase_clear_in_editor (BreakpointsDBase *bd, BreakpointItem *bi)
368 IAnjutaMarkable *ed;
369 gint line = -1;
371 g_return_if_fail (bi != NULL);
373 if (bi->editor == NULL)
375 /* No editor, no need to remove marker */
376 return;
378 else
380 ed = IANJUTA_MARKABLE (bi->editor);
381 line = ianjuta_markable_location_from_handle (ed, bi->handle, NULL);
383 /* Remove old mark */
384 ianjuta_markable_unmark (ed, line, BREAKPOINT_ENABLED, NULL);
385 ianjuta_markable_unmark (ed, line, BREAKPOINT_DISABLED,NULL);
386 bi->bp.line = line;
387 bi->handle = -1;
391 static void
392 breakpoints_dbase_update_in_treeview (BreakpointsDBase *bd, BreakpointItem *bi)
394 gchar *adr;
395 gchar *location;
396 gchar *pass;
397 gchar *state;
398 const gchar *filename;
399 const gchar *format;
401 adr = g_strdup_printf ("0x%lx", bi->bp.address);
402 if (bi->bp.file != NULL)
404 filename = strrchr(bi->bp.file, G_DIR_SEPARATOR);
405 filename = filename == NULL ? bi->bp.file : filename + 1; /* display name only */
406 format = bi->bp.function == NULL ? "%s:%d" : "%s:%d in %s";
408 else
410 filename = bi->bp.function;
411 format = filename == NULL ? "??" : "%s";
413 location = g_strdup_printf (format, filename, bi->bp.line, bi->bp.function);
414 if (bi->bp.id == 0)
416 pass = g_strdup_printf ("%d", bi->bp.ignore);
418 else if (bi->bp.ignore)
420 pass = g_strdup_printf ("%d of %d", bi->bp.times, bi->bp.ignore);
422 else
424 pass = g_strdup_printf ("%d", bi->bp.times);
426 if (bi->bp.id == 0)
428 format = "pending";
430 else if (bi->bp.temporary)
432 format = "temporary (%d)";
434 else
436 format = "permanent (%d)";
438 state = g_strdup_printf (format, bi->bp.id);
440 gtk_list_store_set (bd->model, &bi->iter,
441 ENABLED_COLUMN, bi->bp.enable,
442 LOCATION_COLUMN, location,
443 ADDRESS_COLUMN, adr,
444 TYPE_COLUMN, "breakpoint",
445 CONDITION_COLUMN, bi->bp.condition,
446 PASS_COLUMN, pass,
447 STATE_COLUMN, state,
448 -1);
449 g_free (state);
450 g_free (pass);
451 g_free (location);
452 g_free (adr);
455 static void
456 breakpoints_dbase_breakpoint_removed (BreakpointsDBase *bd, BreakpointItem *bi)
458 /* Delete maker */
459 breakpoints_dbase_clear_in_editor (bd, bi);
461 /* Emit signal */
462 bi->bp.type |= IANJUTA_DEBUGGER_BREAKPOINT_REMOVED;
463 g_signal_emit_by_name (bd->plugin, "breakpoint-changed", &bi->bp);
465 breakpoint_item_unref (bi);
468 static void
469 breakpoints_dbase_breakpoint_updated (BreakpointsDBase *bd, BreakpointItem *bi)
471 if ((bi->bp.id == 0) && (bi->bp.temporary))
473 /* Temporary breakpoint are never pending */
474 breakpoints_dbase_breakpoint_removed (bd, bi);
476 else
478 /* Update treeview and marker */
479 breakpoints_dbase_update_in_treeview (bd, bi);
481 breakpoints_dbase_set_in_editor (bd, bi);
483 /* Emit signal */
484 g_signal_emit_by_name (bi->bd->plugin, "breakpoint-changed", &bi->bp);
488 static void
489 on_editor_saved (IAnjutaEditor *editor, const gchar* uri, BreakpointsDBase *bd)
491 GtkTreeIter iter;
492 GtkTreeModel *model = GTK_TREE_MODEL (bd->model);
494 g_return_if_fail (model != NULL);
495 /* Update breakpoint position */
496 if (gtk_tree_model_get_iter_first (model, &iter))
500 BreakpointItem *bi;
502 gtk_tree_model_get (GTK_TREE_MODEL (bd->model), &iter, DATA_COLUMN, &bi, -1);
504 if ((bi->editor == editor) && (bi->handle != -1))
506 gint line;
508 line = ianjuta_markable_location_from_handle (IANJUTA_MARKABLE (editor), bi->handle, NULL);
509 if (line != bi->bp.line)
511 bi->bp.line = line;
512 breakpoints_dbase_breakpoint_updated (bd, bi);
515 } while (gtk_tree_model_iter_next (model, &iter));
519 static void
520 breakpoints_dbase_connect_to_editor (BreakpointsDBase *bd, IAnjutaEditor* ed)
522 if (!g_signal_handler_find (ed, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, bd))
524 /* signal is not already connected */
525 g_signal_connect (ed, "saved", G_CALLBACK (on_editor_saved), bd);
529 static void
530 breakpoints_dbase_disconnect_from_editors (BreakpointsDBase *bd)
532 GtkTreeIter iter;
533 GtkTreeModel *model = GTK_TREE_MODEL (bd->model);
535 if (gtk_tree_model_get_iter_first (model, &iter))
539 BreakpointItem *bi;
541 gtk_tree_model_get (model, &iter, DATA_COLUMN, &bi, -1);
543 if (bi->editor != NULL)
545 g_signal_handlers_disconnect_matched (bi->editor, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, bd);
547 } while (gtk_tree_model_iter_next (model, &iter));
551 static void
552 breakpoints_dbase_set_all_in_editor (BreakpointsDBase* bd, IAnjutaEditor* te)
554 GtkTreeModel *model;
555 GtkTreeIter iter;
556 gchar *uri;
558 g_return_if_fail (te != NULL);
559 g_return_if_fail (bd != NULL);
560 g_return_if_fail (bd->treeview != NULL);
562 uri = ianjuta_file_get_uri (IANJUTA_FILE (te), NULL);
563 if (uri == NULL)
564 return;
566 if (!IANJUTA_IS_MARKABLE (te))
568 /* Nothing to do, editor does not support mark */
569 return;
572 model = gtk_tree_view_get_model (bd->treeview);
574 if (gtk_tree_model_get_iter_first (model, &iter))
578 BreakpointItem *bi;
580 gtk_tree_model_get (model, &iter, DATA_COLUMN, &bi, -1);
582 if ((bi->editor == NULL) && (strcmp (uri, bi->uri) == 0))
584 bi->editor = te;
585 bi->handle = -1;
586 g_object_add_weak_pointer (G_OBJECT (te), (gpointer)&bi->editor);
587 breakpoints_dbase_connect_to_editor (bd, te);
589 if (bi->editor == te)
591 breakpoints_dbase_set_in_editor (bd, bi);
593 } while (gtk_tree_model_iter_next (model, &iter));
595 g_free (uri);
598 static void
599 on_added_current_editor (AnjutaPlugin *plugin, const char *name,
600 const GValue *value, gpointer user_data)
602 BreakpointsDBase *bd = (BreakpointsDBase *)user_data;
603 GObject *editor;
605 editor = g_value_get_object (value);
607 /* Restore breakpoints */
608 if (IANJUTA_IS_EDITOR (editor))
609 breakpoints_dbase_set_all_in_editor (bd, IANJUTA_EDITOR (editor));
612 static void
613 on_removed_current_editor (AnjutaPlugin *plugin,
614 const char *name, gpointer data)
616 /* Nothing do to here */
619 /* Private functions
620 *---------------------------------------------------------------------------*/
622 static gboolean
623 ianjuta_debugger_breakpoint_is_equal (const IAnjutaDebuggerBreakpointItem *bpa, const IAnjutaDebuggerBreakpointItem *bpb)
625 g_return_val_if_fail ((bpa != NULL) && (bpb != NULL), FALSE);
627 /* Special case if both pointer are equal */
628 if (bpa == bpb) return TRUE;
630 /* Compare their id */
631 if (bpa->id == bpb->id) return TRUE;
633 /* If both breakpoint id are define (!=0) and different */
634 if ((bpa->id != 0) && (bpb->id != 0)) return FALSE;
636 /* Check line and file */
637 if (bpa->type & bpb->type & IANJUTA_DEBUGGER_BREAKPOINT_ON_LINE)
639 if (bpa->line != bpb->line) return FALSE;
640 if (strcmp(bpa->file, bpb->file) != 0) return FALSE;
643 /* Check function name */
644 if (bpa->type & bpb->type & IANJUTA_DEBUGGER_BREAKPOINT_ON_FUNCTION)
646 if (strcmp(bpa->function, bpb->function) != 0) return FALSE;
649 /* Check address */
650 if (bpa->type & bpb->type & IANJUTA_DEBUGGER_BREAKPOINT_ON_ADDRESS)
652 if (bpa->address != bpb->address) return FALSE;
655 /* Check conditions */
656 if (bpa->type & bpb->type & IANJUTA_DEBUGGER_BREAKPOINT_WITH_CONDITION)
658 if (strcmp(bpa->condition, bpb->condition) != 0) return FALSE;
661 return TRUE;
664 static BreakpointItem*
665 breakpoints_dbase_find_breakpoint (BreakpointsDBase *bd, const IAnjutaDebuggerBreakpointItem *bp)
667 GtkTreeModel *model;
668 GtkTreeIter iter;
670 g_return_val_if_fail (bd->treeview != NULL, NULL);
672 model = gtk_tree_view_get_model (bd->treeview);
674 if (gtk_tree_model_get_iter_first (model, &iter))
678 BreakpointItem *bi;
680 gtk_tree_model_get (model, &iter, DATA_COLUMN, &bi, -1);
682 if (ianjuta_debugger_breakpoint_is_equal (&bi->bp, bp)) return bi;
683 } while (gtk_tree_model_iter_next (model, &iter));
686 return NULL;
689 /* Debugger functions
690 *---------------------------------------------------------------------------*/
692 static void
693 on_breakpoint_callback (const gpointer data, gpointer breakpoint, GError* err);
695 static gboolean
696 breakpoints_dbase_remove_in_debugger (BreakpointsDBase *bd, BreakpointItem *bi)
698 gboolean ok;
700 /* Remove breakpoint in debugger */
701 breakpoint_item_ref (bi);
702 ok = dma_queue_remove_breakpoint (
703 bd->debugger,
704 bi->bp.id,
705 on_breakpoint_callback,
706 bi);
707 if (!ok) breakpoint_item_unref (bi);
709 return ok;
712 static gboolean
713 breakpoints_dbase_add_in_debugger (BreakpointsDBase *bd, BreakpointItem *bi)
715 gboolean ok = TRUE;
717 if (bi->bp.id != 0)
719 /* Breakpoint already exist, remove it first */
720 breakpoint_item_ref (bi);
721 ok = dma_queue_remove_breakpoint (
722 bd->debugger,
723 bi->bp.id,
724 on_breakpoint_callback,
725 bi);
726 if (!ok) breakpoint_item_unref (bi);
727 ok = TRUE;
730 if (bi->bp.condition != NULL)
732 bi->changed = IANJUTA_DEBUGGER_BREAKPOINT_WITH_CONDITION;
734 if (bi->bp.ignore != 0)
736 bi->changed = IANJUTA_DEBUGGER_BREAKPOINT_WITH_IGNORE;
738 if (bi->bp.enable != TRUE)
740 bi->changed = IANJUTA_DEBUGGER_BREAKPOINT_WITH_ENABLE;
743 /* Add breakpoint in debugger */
744 if (bi->bp.type & IANJUTA_DEBUGGER_BREAKPOINT_ON_LINE)
746 breakpoint_item_ref (bi);
747 ok = dma_queue_add_breakpoint_at_line (
748 bd->debugger,
749 bi->bp.file,
750 bi->bp.line,
751 on_breakpoint_callback,
752 bi);
754 else if (bi->bp.type & IANJUTA_DEBUGGER_BREAKPOINT_ON_FUNCTION)
756 breakpoint_item_ref (bi);
757 ok = dma_queue_add_breakpoint_at_function (
758 bd->debugger,
759 bi->bp.file == NULL ? "" : bi->bp.file,
760 bi->bp.function,
761 on_breakpoint_callback,
762 bi);
764 else if ((bi->bp.type & IANJUTA_DEBUGGER_BREAKPOINT_ON_ADDRESS)
765 && dma_debugger_queue_is_supported(bd->debugger, HAS_ADDRESS_BREAKPOINT))
767 breakpoint_item_ref (bi);
768 ok = dma_queue_add_breakpoint_at_address (
769 bd->debugger,
770 bi->bp.address,
771 on_breakpoint_callback,
772 bi);
774 if (!ok) breakpoint_item_unref (bi);
776 return ok;
779 static void
780 breakpoints_dbase_update_in_debugger (BreakpointsDBase *bd, BreakpointItem *bi)
782 gboolean ok;
784 if (bi->changed & IANJUTA_DEBUGGER_BREAKPOINT_WITH_ENABLE)
786 bi->changed &= ~IANJUTA_DEBUGGER_BREAKPOINT_WITH_ENABLE;
787 breakpoint_item_ref (bi);
788 ok = dma_queue_enable_breakpoint (
789 bd->debugger,
790 bi->bp.id,
791 bi->bp.enable,
792 on_breakpoint_callback,
793 bi);
794 if (!ok) breakpoint_item_unref (bi);
797 if ((bi->changed & IANJUTA_DEBUGGER_BREAKPOINT_WITH_CONDITION)
798 && dma_debugger_queue_is_supported(bd->debugger, HAS_CONDITION_BREAKPOINT))
800 bi->changed &= ~IANJUTA_DEBUGGER_BREAKPOINT_WITH_CONDITION;
801 breakpoint_item_ref (bi);
802 ok = dma_queue_condition_breakpoint (
803 bd->debugger,
804 bi->bp.id,
805 bi->bp.condition,
806 on_breakpoint_callback,
807 bi);
808 if (!ok) breakpoint_item_unref (bi);
810 if ((bi->changed & IANJUTA_DEBUGGER_BREAKPOINT_WITH_IGNORE)
811 && dma_debugger_queue_is_supported(bd->debugger, HAS_IGNORE_BREAKPOINT))
813 bi->changed &= ~IANJUTA_DEBUGGER_BREAKPOINT_WITH_IGNORE;
814 breakpoint_item_ref (bi);
815 ok = dma_queue_ignore_breakpoint (
816 bd->debugger,
817 bi->bp.id,
818 bi->bp.ignore,
819 on_breakpoint_callback,
820 bi);
821 if (!ok) breakpoint_item_unref (bi);
825 static void
826 on_breakpoint_callback (const gpointer data, gpointer user_data, GError* err)
828 const IAnjutaDebuggerBreakpointItem* bp = (const IAnjutaDebuggerBreakpointItem*)data;
829 BreakpointItem *bi = (BreakpointItem *)user_data;
830 BreakpointsDBase *bd = bi->bd;
832 if (breakpoint_item_unref (bi))
834 /* Breakpoint item has been destroyed */
835 return;
838 if (err == NULL)
840 if ((bp != NULL) && (bp->type & IANJUTA_DEBUGGER_BREAKPOINT_REMOVED))
842 breakpoints_dbase_breakpoint_removed (bd, bi);
844 else
846 breakpoint_item_update_from_debugger (bi, bp);
847 breakpoints_dbase_update_in_debugger (bd, bi);
848 breakpoints_dbase_breakpoint_updated (bd, bi);
853 static
854 void on_update_breakpoint_from_debugger (gpointer data, gpointer user_data)
856 IAnjutaDebuggerBreakpointItem *bp = (IAnjutaDebuggerBreakpointItem *)data;
857 BreakpointsDBase *bd = (BreakpointsDBase *)user_data;
858 BreakpointItem *bi;
860 bi = breakpoints_dbase_find_breakpoint (bd, bp);
862 if (bi == NULL)
864 /* Breakpoint exist in the debugger but not in the manager, create it */
865 bi = breakpoint_item_new (bd);
867 breakpoint_item_update_from_debugger (bi, bp);
868 bi->changed |= IANJUTA_DEBUGGER_BREAKPOINT_UPDATED;
871 static
872 gboolean on_update_breakpoint_in_ui (GtkTreeModel *model, GtkTreePath *path,
873 GtkTreeIter *iter, gpointer user_data)
875 BreakpointItem *bi;
876 BreakpointsDBase *bd;
878 gtk_tree_model_get (model, iter, DATA_COLUMN, &bi, -1);
879 bd = bi->bd;
881 if (bi->changed & IANJUTA_DEBUGGER_BREAKPOINT_UPDATED)
883 /* Breakpoint is present in debugger */
884 bi->changed &= ~IANJUTA_DEBUGGER_BREAKPOINT_UPDATED;
886 else
888 /* Breakpoint is not present in debugger */
889 bi->bp.id = 0;
891 breakpoints_dbase_breakpoint_updated (bd, bi);
893 return FALSE;
896 static void
897 on_breakpoint_list_callback (const gpointer data, gpointer user_data, GError* err)
899 GList *list = (GList *)data;
900 BreakpointsDBase *bd = (BreakpointsDBase *)user_data;
902 /* Update all breakpoints */
903 g_list_foreach (list, on_update_breakpoint_from_debugger, bd);
905 /* Remove all not updated breakpoints */
906 gtk_tree_model_foreach (GTK_TREE_MODEL (bd->model), on_update_breakpoint_in_ui, bd);
909 static void
910 breakpoints_dbase_list_all_in_debugger (BreakpointsDBase *bd)
912 g_return_if_fail (bd->debugger != NULL);
914 dma_queue_list_breakpoint (bd->debugger, on_breakpoint_list_callback, bd);
917 /* Private functions
918 *---------------------------------------------------------------------------*/
920 /* Send all breakpoints in debugger */
922 static void
923 breakpoints_dbase_add_all_in_debugger (BreakpointsDBase *bd)
925 GtkTreeIter iter;
926 GtkTreeModel *model = GTK_TREE_MODEL (bd->model);
928 g_return_if_fail (bd->treeview != NULL);
930 if (gtk_tree_model_get_iter_first (model, &iter))
934 BreakpointItem *bi;
936 gtk_tree_model_get (model, &iter, DATA_COLUMN, &bi, -1);
937 breakpoints_dbase_add_in_debugger (bd, bi);
938 } while (gtk_tree_model_iter_next (model, &iter));
942 /* Send all pending breakpoints in debugger */
944 static void
945 breakpoints_dbase_add_all_pending_in_debugger (BreakpointsDBase *bd)
947 GtkTreeIter iter;
948 GtkTreeModel *model = GTK_TREE_MODEL (bd->model);
950 if (gtk_tree_model_get_iter_first (model, &iter))
954 BreakpointItem *bi;
956 gtk_tree_model_get (model, &iter, DATA_COLUMN, &bi, -1);
958 if (bi->bp.id == 0)
960 breakpoints_dbase_add_in_debugger (bd, bi);
962 } while (gtk_tree_model_iter_next (model, &iter));
966 /* Remove all breakpoints in debugger but do not delete them */
968 static void
969 breakpoints_dbase_remove_all_in_debugger (BreakpointsDBase *bd)
971 GtkTreeIter iter;
972 GtkTreeModel *model = GTK_TREE_MODEL (bd->model);
974 if (gtk_tree_model_get_iter_first (model, &iter))
976 gboolean next;
980 BreakpointItem *bi;
982 gtk_tree_model_get (model, &iter, DATA_COLUMN, &bi, -1);
983 next = gtk_tree_model_iter_next (model, &iter);
985 bi->bp.id = 0;
986 breakpoints_dbase_breakpoint_updated (bd, bi);
987 /* breakpoints_dbase_breakpoint_updated can delete pending breakpoints
988 * the iterator of the breakpoint can be invalidated */
989 } while (next);
993 /* Add breakpoint in tree view, in editor and in debugger */
995 static void
996 breakpoints_dbase_add_breakpoint (BreakpointsDBase *bd, BreakpointItem *bi)
998 IAnjutaEditor* ed;
1000 /* Add in current editor if possible */
1001 ed = dma_get_current_editor (ANJUTA_PLUGIN(bd->plugin));
1002 if ((ed != NULL) && IANJUTA_IS_MARKABLE (ed))
1004 gchar *uri;
1006 uri = ianjuta_file_get_uri (IANJUTA_FILE (ed), NULL);
1007 if ((uri != NULL) && (strcmp (uri, bi->uri) == 0))
1009 bi->editor = ed;
1010 bi->handle = -1;
1011 g_object_add_weak_pointer (G_OBJECT (ed), (gpointer)&bi->editor);
1012 breakpoints_dbase_connect_to_editor (bd, ed);
1014 g_free (uri);
1017 if (bd->debugger != NULL)
1019 breakpoints_dbase_add_in_debugger (bd, bi);
1021 else
1023 breakpoints_dbase_breakpoint_updated (bd, bi);
1027 /* Remove breakpoint in tree view, in editor and in debugger */
1029 static void
1030 breakpoints_dbase_remove_breakpoint (BreakpointsDBase *bd, BreakpointItem *bi)
1032 if (bd->debugger != NULL)
1034 if (breakpoints_dbase_remove_in_debugger (bd, bi)) return;
1036 breakpoints_dbase_breakpoint_removed (bd, bi);
1039 /* Enable or disable breakpoint in tree view, in editor and in debugger */
1041 static void
1042 breakpoints_dbase_enable_breakpoint (BreakpointsDBase *bd, BreakpointItem *bi, gboolean enable)
1044 bi->bp.enable = enable;
1045 bi->changed |= IANJUTA_DEBUGGER_BREAKPOINT_WITH_ENABLE;
1047 if (bd->debugger != NULL)
1049 breakpoints_dbase_update_in_debugger (bd, bi);
1051 else
1053 breakpoints_dbase_breakpoint_updated (bd, bi);
1057 /* Toggle breakpoint enable in tree view, in editor and in debugger */
1059 static void
1060 breakpoints_dbase_toggle_enable (BreakpointsDBase *bd, GtkTreeModel *model, GtkTreeIter iter)
1062 BreakpointItem *bi;
1064 gtk_tree_model_get (model, &iter, DATA_COLUMN, &bi, -1);
1066 breakpoints_dbase_enable_breakpoint (bd, bi, bi->bp.enable ? FALSE : TRUE);
1069 /* Update breakpoint in tree view, in editor and in debugger */
1071 static void
1072 breakpoints_dbase_update_breakpoint (BreakpointsDBase *bd, BreakpointItem *bi)
1074 if (bd->debugger != NULL)
1076 breakpoints_dbase_update_in_debugger (bd, bi);
1078 else
1080 breakpoints_dbase_breakpoint_updated (bd, bi);
1084 /* Remove all breakpoints in tree view, in editor and in debugger */
1086 static void
1087 breakpoints_dbase_remove_all (BreakpointsDBase *bd)
1089 GtkTreeIter iter;
1090 GtkTreeModel *model = GTK_TREE_MODEL (bd->model);
1093 if (gtk_tree_model_get_iter_first (model, &iter))
1095 gboolean next;
1099 BreakpointItem *bi;
1101 gtk_tree_model_get (model, &iter, DATA_COLUMN, &bi, -1);
1102 next = gtk_tree_model_iter_next (model, &iter);
1104 breakpoints_dbase_remove_breakpoint (bd, bi);
1105 /* Avoid an infinite loop if the breakpoint is not removed due to
1106 * an error */
1107 } while (next);
1111 /* Enable or disable all breakpoints in tree view, in editor and in debugger */
1113 static void
1114 breakpoints_dbase_enable_all (BreakpointsDBase *bd, gboolean enable)
1116 GtkTreeIter iter;
1117 GtkTreeModel *model = GTK_TREE_MODEL (bd->model);
1119 if (gtk_tree_model_get_iter_first (model, &iter))
1123 BreakpointItem *bi;
1125 gtk_tree_model_get (GTK_TREE_MODEL (bd->model), &iter, DATA_COLUMN, &bi, -1);
1127 breakpoints_dbase_enable_breakpoint (bd, bi, enable);
1128 } while (gtk_tree_model_iter_next (model, &iter));
1132 static BreakpointItem*
1133 breakpoints_dbase_find_breakpoint_from_mark (BreakpointsDBase *bd, IAnjutaEditor *ed, guint line)
1135 GtkTreeIter iter;
1136 GtkTreeModel *model = GTK_TREE_MODEL (bd->model);
1138 if (gtk_tree_model_get_iter_first (model, &iter))
1142 BreakpointItem *bi;
1144 gtk_tree_model_get (model, &iter, DATA_COLUMN, &bi, -1);
1146 if ((bi->editor == ed) && (bi->handle != -1)
1147 && (ianjuta_markable_location_from_handle (IANJUTA_MARKABLE(ed), bi->handle, NULL) == line))
1149 return bi;
1151 } while (gtk_tree_model_iter_next (model, &iter));
1154 return NULL;
1157 static BreakpointItem*
1158 breakpoints_dbase_find_breakpoint_from_line (BreakpointsDBase *bd, const gchar* uri, guint line)
1160 GtkTreeIter iter;
1161 GtkTreeModel *model = GTK_TREE_MODEL (bd->model);
1163 if (gtk_tree_model_get_iter_first (model, &iter))
1167 BreakpointItem *bi;
1169 gtk_tree_model_get (model, &iter, DATA_COLUMN, &bi, -1);
1171 if ((line == bi->bp.line) && (strcmp (uri, bi->uri) == 0)) return bi;
1172 } while (gtk_tree_model_iter_next (model, &iter));
1175 return NULL;
1178 static GList*
1179 breakpoints_dbase_get_breakpoint_list (BreakpointsDBase *bd)
1181 GList* list = NULL;
1182 GtkTreeIter iter;
1183 GtkTreeModel *model = GTK_TREE_MODEL (bd->model);
1185 if (gtk_tree_model_get_iter_first (model, &iter))
1189 BreakpointItem *bi;
1191 gtk_tree_model_get (GTK_TREE_MODEL (bd->model), &iter, DATA_COLUMN, &bi, -1);
1193 if ((bi->bp.type & (IANJUTA_DEBUGGER_BREAKPOINT_ON_LINE | IANJUTA_DEBUGGER_BREAKPOINT_ON_FUNCTION))
1194 && (bi->bp.temporary == FALSE))
1196 /* Only permanent breakpoint are saved */
1197 list = g_list_prepend (list, g_strdup_printf("%d:%s:%u:%u:%s", bi->bp.enable ? 1 : 0, bi->uri, bi->bp.line, bi->bp.ignore, bi->bp.condition == NULL ? "" : bi->bp.condition));
1199 } while (gtk_tree_model_iter_next (model, &iter));
1202 list = g_list_reverse (list);
1204 return list;
1207 static void
1208 on_add_breakpoint_list (gpointer data, gpointer user_data)
1210 BreakpointsDBase* bd = (BreakpointsDBase *)user_data;
1211 BreakpointItem *bi;
1212 gchar *uri = (gchar *)data;
1213 gchar *pos;
1214 guint line;
1215 gchar *cond;
1216 guint ignore;
1217 gboolean enable;
1219 pos = strrchr (uri, ':');
1220 *pos = '\0';
1221 cond = pos + 1;
1222 pos = strrchr (uri, ':');
1223 *pos = '\0';
1224 ignore = strtoul (pos + 1, NULL, 10);
1225 pos = strrchr (uri, ':');
1226 *pos = '\0';
1227 line = strtoul (pos + 1, NULL, 10);
1228 enable = uri[0] == '0' ? FALSE : TRUE;
1229 bi = breakpoint_item_new_from_uri (bd, uri + 2, line, enable);
1231 if (*cond != '\0')
1233 bi->bp.condition = g_strdup (cond);
1235 bi->bp.ignore = ignore;
1237 breakpoints_dbase_add_breakpoint (bd, bi);
1240 static void
1241 breakpoints_dbase_add_breakpoint_list (BreakpointsDBase *bd, GList *list)
1243 g_list_foreach (list, on_add_breakpoint_list, bd);
1246 /* Debugger Callbacks
1247 *---------------------------------------------------------------------------*/
1249 static void
1250 on_breakpoint_sharedlib_event (BreakpointsDBase *bd)
1252 breakpoints_dbase_add_all_pending_in_debugger (bd);
1255 static void
1256 on_program_running (BreakpointsDBase *bd)
1258 /* Deactivate breakpoint functions */
1259 gtk_action_group_set_sensitive (bd->debugger_group, FALSE);
1262 static void
1263 on_program_stopped (BreakpointsDBase *bd)
1265 g_return_if_fail (bd->debugger != NULL);
1267 gtk_action_group_set_sensitive (bd->debugger_group, TRUE);
1269 /* Refresh breakpoint
1270 * Hit count could have changed by example */
1271 breakpoints_dbase_list_all_in_debugger (bd);
1274 static void
1275 on_program_exited (BreakpointsDBase *bd)
1277 g_return_if_fail (bd->debugger != NULL);
1279 gtk_action_group_set_sensitive (bd->debugger_group, TRUE);
1282 static void
1283 on_program_unloaded (BreakpointsDBase *bd)
1285 g_return_if_fail (bd->debugger != NULL);
1287 breakpoints_dbase_remove_all_in_debugger (bd);
1288 bd->debugger = NULL;
1289 gtk_action_group_set_sensitive (bd->debugger_group, TRUE);
1291 /* Disconnect from other debugger signal */
1292 g_signal_handlers_disconnect_by_func (bd->plugin, G_CALLBACK (on_breakpoint_sharedlib_event), bd);
1293 g_signal_handlers_disconnect_by_func (bd->plugin, G_CALLBACK (on_program_stopped), bd);
1294 g_signal_handlers_disconnect_by_func (bd->plugin, G_CALLBACK (on_program_running), bd);
1295 g_signal_handlers_disconnect_by_func (bd->plugin, G_CALLBACK (on_program_exited), bd);
1296 g_signal_handlers_disconnect_by_func (bd->plugin, G_CALLBACK (on_program_unloaded), bd);
1299 static void
1300 on_program_loaded (BreakpointsDBase *bd)
1302 DmaDebuggerQueue* debugger;
1304 DEBUG_PRINT("on program loaded in breakpoints %p bd %p", bd->debugger, bd);
1305 /* Debugger shouldn't be connected */
1306 g_return_if_fail (bd->debugger == NULL);
1308 debugger = dma_debug_manager_get_queue (ANJUTA_PLUGIN_DEBUG_MANAGER (bd->plugin));
1309 if (!dma_debugger_queue_is_supported (debugger, HAS_BREAKPOINT)) return;
1311 bd->debugger = debugger;
1312 breakpoints_dbase_add_all_in_debugger (bd);
1314 /* Connect to other debugger signal */
1315 g_signal_connect_swapped (bd->plugin, "sharedlib-event", G_CALLBACK (on_breakpoint_sharedlib_event), bd);
1316 g_signal_connect_swapped (bd->plugin, "program-unloaded", G_CALLBACK (on_program_unloaded), bd);
1317 g_signal_connect_swapped (bd->plugin, "program-stopped", G_CALLBACK (on_program_stopped), bd);
1318 g_signal_connect_swapped (bd->plugin, "program-exited", G_CALLBACK (on_program_exited), bd);
1319 g_signal_connect_swapped (bd->plugin, "program-running", G_CALLBACK (on_program_running), bd);
1322 static void
1323 on_debugger_started (BreakpointsDBase *bd)
1325 GtkTreeViewColumn *column;
1326 DmaDebuggerQueue* debugger;
1328 debugger = dma_debug_manager_get_queue (ANJUTA_PLUGIN_DEBUG_MANAGER (bd->plugin));
1330 /* Remove breakpoint attributes not supported by current debugger */
1331 if (!dma_debugger_queue_is_supported(debugger, HAS_ADDRESS_BREAKPOINT))
1333 column = gtk_tree_view_get_column (bd->treeview, ADDRESS_COLUMN);
1334 gtk_tree_view_column_set_visible (column, FALSE);
1336 if (!dma_debugger_queue_is_supported(debugger, HAS_IGNORE_BREAKPOINT))
1338 column = gtk_tree_view_get_column (bd->treeview, PASS_COLUMN);
1339 gtk_tree_view_column_set_visible (column, FALSE);
1341 if (!dma_debugger_queue_is_supported(debugger, HAS_CONDITION_BREAKPOINT))
1343 column = gtk_tree_view_get_column (bd->treeview, CONDITION_COLUMN);
1344 gtk_tree_view_column_set_visible (column, FALSE);
1348 static void
1349 on_debugger_stopped (BreakpointsDBase *bd)
1351 /* Restore breakpoint attributes not supported by current debugger */
1352 GtkTreeViewColumn *column;
1354 column = gtk_tree_view_get_column (bd->treeview, ADDRESS_COLUMN);
1355 gtk_tree_view_column_set_visible (column, TRUE);
1356 column = gtk_tree_view_get_column (bd->treeview, PASS_COLUMN);
1357 gtk_tree_view_column_set_visible (column, TRUE);
1358 column = gtk_tree_view_get_column (bd->treeview, CONDITION_COLUMN);
1359 gtk_tree_view_column_set_visible (column, TRUE);
1363 /* Saving preferences callbacks
1364 *---------------------------------------------------------------------------*/
1366 static void
1367 on_session_save (AnjutaShell *shell, AnjutaSessionPhase phase, AnjutaSession *session, BreakpointsDBase *bd)
1369 GList *list;
1371 if (phase != ANJUTA_SESSION_PHASE_NORMAL)
1372 return;
1374 list = breakpoints_dbase_get_breakpoint_list (bd);
1375 if (list != NULL)
1376 anjuta_session_set_string_list (session, "Debugger", "Breakpoint", list);
1379 static void
1380 on_session_load (AnjutaShell *shell, AnjutaSessionPhase phase, AnjutaSession *session, BreakpointsDBase *bd)
1382 GList *list;
1384 if (phase != ANJUTA_SESSION_PHASE_NORMAL)
1385 return;
1387 breakpoints_dbase_remove_all (bd);
1388 list = anjuta_session_get_string_list (session, "Debugger", "Breakpoint");
1389 if (list != NULL)
1390 breakpoints_dbase_add_breakpoint_list (bd, list);
1393 /* Breakpoint edit dialog
1394 *---------------------------------------------------------------------------*/
1396 static void
1397 breakpoints_dbase_edit_breakpoint (BreakpointsDBase *bd, BreakpointItem *bi)
1399 GladeXML *gxml;
1400 GtkWidget *dialog;
1401 GtkWidget *location_label, *location_entry;
1402 GtkWidget *condition_entry, *condition_label;
1403 GtkWidget *pass_entry, *pass_label;
1404 gchar *buff;
1405 gchar *location = NULL;
1406 gchar *uri = NULL;
1407 gboolean new_break = FALSE;
1409 gxml = glade_xml_new (GLADE_FILE,
1410 "breakpoint_properties_dialog", NULL);
1411 dialog = glade_xml_get_widget (gxml, "breakpoint_properties_dialog");
1412 gtk_window_set_transient_for (GTK_WINDOW (dialog),
1413 GTK_WINDOW (ANJUTA_PLUGIN (bd->plugin)->shell));
1414 location_label = glade_xml_get_widget (gxml, "breakpoint_location_label");
1415 location_entry = glade_xml_get_widget (gxml, "breakpoint_location_entry");
1416 condition_entry = glade_xml_get_widget (gxml, "breakpoint_condition_entry");
1417 condition_label = glade_xml_get_widget (gxml, "breakpoint_condition_label");
1418 pass_entry = glade_xml_get_widget (gxml, "breakpoint_pass_entry");
1419 pass_label = glade_xml_get_widget (gxml, "breakpoint_pass_label");
1421 if (!dma_debugger_queue_is_supported(bd->debugger, HAS_IGNORE_BREAKPOINT))
1423 gtk_widget_hide (pass_entry);
1424 gtk_widget_hide (pass_label);
1426 if (!dma_debugger_queue_is_supported(bd->debugger, HAS_CONDITION_BREAKPOINT))
1428 gtk_widget_hide (condition_entry);
1429 gtk_widget_hide (condition_label);
1432 if (bi == NULL)
1434 IAnjutaEditor *te;
1435 guint line = 0;
1437 /* New breakpoint */
1438 gtk_widget_show (location_entry);
1439 gtk_widget_hide (location_label);
1441 /* Get current editor and line */
1442 te = dma_get_current_editor (ANJUTA_PLUGIN(bd->plugin));
1443 if (te != NULL)
1445 uri = ianjuta_file_get_uri (IANJUTA_FILE (te), NULL);
1446 line = ianjuta_editor_get_lineno (te, NULL);
1448 //NULL uri ia ok here
1449 bi = breakpoint_item_new_from_uri (bd, uri, line, TRUE);
1450 new_break = TRUE;
1452 else
1454 /* Update breakpoint */
1455 gtk_widget_hide (location_entry);
1456 gtk_widget_show (location_label);
1459 if (bi->uri != NULL)
1461 if (bi->bp.line != 0)
1463 // file and line
1464 location = g_strdup_printf ("%s:%d", bi->bp.file, bi->bp.line);
1466 else
1468 // file and function
1469 location = g_strdup_printf ("%s:%s", bi->bp.file, bi->bp.function);
1472 else if (bi->bp.address != 0)
1474 // address
1475 location = g_strdup_printf ("*%lx", bi->bp.address);
1478 if (GTK_WIDGET_VISIBLE(location_entry))
1480 gtk_entry_set_text (GTK_ENTRY (location_entry), location == NULL ? "" : location);
1482 else
1484 gtk_label_set_text (GTK_LABEL (location_label), location == NULL ? "" : location);
1487 if (bi->bp.condition && strlen (bi->bp.condition) > 0)
1488 gtk_entry_set_text (GTK_ENTRY (condition_entry), bi->bp.condition);
1490 buff = g_strdup_printf ("%d", bi->bp.ignore);
1491 gtk_entry_set_text (GTK_ENTRY (pass_entry), buff);
1492 g_free (buff);
1494 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
1496 const gchar *condition;
1497 guint ignore;
1498 const gchar *new_location;
1500 ignore = atoi (gtk_entry_get_text (GTK_ENTRY (pass_entry)));
1501 condition = gtk_entry_get_text (GTK_ENTRY (condition_entry));
1502 while (isspace(*condition)) condition++;
1503 if (*condition == '\0') condition = NULL;
1505 if (GTK_WIDGET_VISIBLE(location_entry))
1507 new_location = gtk_entry_get_text (GTK_ENTRY (location_entry));
1508 while (isspace(*new_location)) new_location++;
1510 if ((location == NULL) || (strcmp (new_location, location) != 0))
1512 /* location has been changed, create a new breakpoint */
1513 breakpoint_item_unref (bi);
1514 bi = NULL;
1516 if (*new_location != '\0')
1518 bi = breakpoint_item_new_from_string (bd, new_location, uri);
1522 else
1524 new_location = NULL;
1527 if (bi != NULL)
1529 if (bi->bp.ignore != ignore)
1531 bi->bp.ignore = ignore;
1532 bi->changed |= IANJUTA_DEBUGGER_BREAKPOINT_WITH_IGNORE;
1534 if ((condition != bi->bp.condition) && ((condition == NULL) || (bi->bp.condition == NULL) || (strcmp (bi->bp.condition, condition) != 0)))
1536 if (bi->bp.condition) g_free ((char *)bi->bp.condition);
1537 bi->bp.condition = condition != NULL ? g_strdup (condition) : NULL;
1538 bi->changed |= IANJUTA_DEBUGGER_BREAKPOINT_WITH_CONDITION;
1540 if (new_location != NULL)
1542 breakpoints_dbase_add_breakpoint (bd, bi);
1544 else
1546 breakpoints_dbase_update_breakpoint (bd, bi);
1550 else if (new_break)
1552 /* Remove breakpoint if a new one has been created */
1553 breakpoint_item_unref (bi);
1555 g_free (uri);
1556 g_free (location);
1557 gtk_widget_destroy (dialog);
1558 g_object_unref (gxml);
1561 /* Breakpoint actions list
1562 *---------------------------------------------------------------------------*/
1564 static void
1565 on_jump_to_breakpoint_activate (GtkAction * action, BreakpointsDBase *bd)
1567 GtkTreeModel *model;
1568 GtkTreeSelection *selection;
1569 GtkTreeIter iter;
1570 gboolean valid;
1572 selection = gtk_tree_view_get_selection (bd->treeview);
1573 valid = gtk_tree_selection_get_selected (selection, &model, &iter);
1574 if (valid)
1576 BreakpointItem *bi;
1578 gtk_tree_model_get (model, &iter, DATA_COLUMN, &bi, -1);
1580 g_signal_emit_by_name (bd->plugin, "location-changed", bi->bp.address, bi->uri, bi->bp.line);
1584 static void
1585 on_toggle_breakpoint_activate (GtkAction * action, BreakpointsDBase *bd)
1587 IAnjutaEditor *te;
1588 BreakpointItem *bi;
1589 gchar *uri;
1590 guint line;
1592 /* Get current editor and line */
1593 te = dma_get_current_editor (ANJUTA_PLUGIN (bd->plugin));
1594 if (te == NULL) return; /* Missing editor */
1595 uri = ianjuta_file_get_uri (IANJUTA_FILE (te), NULL);
1596 if (uri == NULL) return; /* File not saved yet, it's not possible to put a breakpoint in it */
1597 line = ianjuta_editor_get_lineno (te, NULL);
1599 /* Find corresponding breakpoint
1600 * Try to find right mark (it could have moved) first */
1601 bi = breakpoints_dbase_find_breakpoint_from_mark (bd, te, line);
1602 if (bi == NULL)
1604 bi = breakpoints_dbase_find_breakpoint_from_line (bd, uri, line);
1607 if (bi == NULL)
1609 bi = breakpoint_item_new_from_uri (bd, uri, line, TRUE);
1611 breakpoints_dbase_add_breakpoint (bd, bi);
1613 else
1615 breakpoints_dbase_remove_breakpoint (bd, bi);
1617 g_free (uri);
1620 static void
1621 on_disable_all_breakpoints_activate (GtkAction * action, BreakpointsDBase *bd)
1623 breakpoints_dbase_enable_all (bd, FALSE);
1626 static void
1627 on_clear_all_breakpoints_activate (GtkAction * action, BreakpointsDBase *bd)
1629 GtkWidget *dialog;
1631 dialog = gtk_message_dialog_new (GTK_WINDOW (ANJUTA_PLUGIN (bd->plugin)->shell),
1632 GTK_DIALOG_DESTROY_WITH_PARENT,
1633 GTK_MESSAGE_QUESTION,
1634 GTK_BUTTONS_NONE,
1635 _("Are you sure you want to delete all the breakpoints?"));
1636 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
1637 GTK_STOCK_CANCEL, GTK_RESPONSE_NO,
1638 GTK_STOCK_DELETE, GTK_RESPONSE_YES,
1639 NULL);
1641 gtk_window_set_transient_for (GTK_WINDOW (dialog),
1642 GTK_WINDOW (ANJUTA_PLUGIN (bd->plugin)->shell) );
1644 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES)
1646 breakpoints_dbase_remove_all (bd);
1648 gtk_widget_destroy (dialog);
1651 static void
1652 on_add_breakpoint_activate (GtkAction * action, BreakpointsDBase *bd)
1654 breakpoints_dbase_edit_breakpoint (bd, NULL);
1657 static void
1658 on_remove_breakpoint_activate (GtkAction * action, BreakpointsDBase *bd)
1660 GtkTreeModel *model;
1661 GtkTreeSelection *selection;
1662 GtkTreeIter iter;
1663 gboolean valid;
1665 selection = gtk_tree_view_get_selection (bd->treeview);
1666 valid = gtk_tree_selection_get_selected (selection, &model, &iter);
1667 if (valid)
1669 BreakpointItem *bi;
1671 gtk_tree_model_get (model, &iter, DATA_COLUMN, &bi, -1);
1672 breakpoints_dbase_remove_breakpoint (bd, bi);
1676 static void
1677 on_edit_breakpoint_activate (GtkAction * action, BreakpointsDBase *bd)
1679 GtkTreeModel *model;
1680 GtkTreeSelection *selection;
1681 GtkTreeIter iter;
1682 gboolean valid;
1684 selection = gtk_tree_view_get_selection (bd->treeview);
1685 valid = gtk_tree_selection_get_selected (selection, &model, &iter);
1686 if (valid)
1688 BreakpointItem *bi;
1690 gtk_tree_model_get (model, &iter, DATA_COLUMN, &bi, -1);
1691 breakpoints_dbase_edit_breakpoint (bd, bi);
1695 static void
1696 on_treeview_enabled_toggled (GtkCellRendererToggle *cell,
1697 gchar *path_str,
1698 BreakpointsDBase *bd)
1700 GtkTreeModel *model;
1701 GtkTreeIter iter;
1702 GtkTreePath *path;
1704 path = gtk_tree_path_new_from_string (path_str);
1706 model = gtk_tree_view_get_model (bd->treeview);
1707 gtk_tree_model_get_iter (model, &iter, path);
1709 breakpoints_dbase_toggle_enable (bd, model, iter);
1712 static void
1713 on_enable_breakpoint_activate (GtkAction * action, BreakpointsDBase *bd)
1715 GtkTreeModel *model;
1716 GtkTreeSelection *selection;
1717 GtkTreeIter iter;
1718 gboolean valid;
1720 selection = gtk_tree_view_get_selection (bd->treeview);
1721 valid = gtk_tree_selection_get_selected (selection, &model, &iter);
1722 if (valid)
1724 breakpoints_dbase_toggle_enable (bd, model, iter);
1728 static GtkActionEntry actions_debugger_breakpoints[] = {
1730 "ActionMenuDmaBreakpoints", /* Action name */
1731 NULL, /* Stock icon, if any */
1732 N_("_Breakpoints"), /* Display label */
1733 NULL, /* short-cut */
1734 NULL, /* Tooltip */
1735 NULL /* action callback */
1738 "ActionDmaToggleBreakpoint", /* Action name */
1739 ANJUTA_STOCK_BREAKPOINT_TOGGLE, /* Stock icon, if any */
1740 N_("Toggle Breakpoint"), /* Display label */
1741 "<control>b", /* short-cut */
1742 N_("Toggle breakpoint at the current location"), /* Tooltip */
1743 G_CALLBACK (on_toggle_breakpoint_activate) /* action callback */
1746 "ActionDmaSetBreakpoint", /* Action name */
1747 ANJUTA_STOCK_BREAKPOINT_ENABLED, /* Stock icon, if any */
1748 N_("Add Breakpoint..."), /* Display label */
1749 NULL, /* short-cut */
1750 N_("Add a breakpoint"), /* Tooltip */
1751 G_CALLBACK (on_add_breakpoint_activate) /* action callback */
1754 "ActionDmaClearBreakpoint", /* Action name */
1755 ANJUTA_STOCK_BREAKPOINT_CLEAR, /* Stock icon, if any */
1756 N_("Remove Breakpoint"), /* Display label */
1757 NULL, /* short-cut */
1758 N_("Remove a breakpoint"), /* Tooltip */
1759 G_CALLBACK (on_remove_breakpoint_activate) /* action callback */
1762 "ActionDmaEditBreakpoint", /* Action name */
1763 NULL, /* Stock icon, if any */
1764 N_("Edit Breakpoint"), /* Display label */
1765 NULL, /* short-cut */
1766 N_("Edit breakpoint properties"), /* Tooltip */
1767 G_CALLBACK (on_edit_breakpoint_activate) /* action callback */
1770 "ActionDmaEnableDisableBreakpoint", /* Action name */
1771 NULL, /* Stock icon, if any */
1772 N_("Enable Breakpoint"), /* Display label */
1773 NULL, /* short-cut */
1774 N_("Enable a breakpoint"), /* Tooltip */
1775 G_CALLBACK (on_enable_breakpoint_activate) /* action callback */
1778 "ActionDmaDisableAllBreakpoints", /* Action name */
1779 ANJUTA_STOCK_BREAKPOINT_DISABLED, /* Stock icon, if any */
1780 N_("Disable All Breakpoints"), /* Display label */
1781 NULL, /* short-cut */
1782 N_("Deactivate all breakpoints"), /* Tooltip */
1783 G_CALLBACK (on_disable_all_breakpoints_activate)/* action callback */
1786 "ActionDmaClearAllBreakpoints", /* Action name */
1787 ANJUTA_STOCK_BREAKPOINT_CLEAR, /* Stock icon, if any */
1788 N_("C_lear All Breakpoints"), /* Display label */
1789 NULL, /* short-cut */
1790 N_("Delete all breakpoints"), /* Tooltip */
1791 G_CALLBACK (on_clear_all_breakpoints_activate)/* action callback */
1795 static GtkActionEntry actions_permanent_breakpoints[] = {
1797 "ActionDmaJumpToBreakpoint", /* Action name */
1798 NULL, /* Stock icon, if any */
1799 N_("Jump to Breakpoint"), /* Display label */
1800 NULL, /* short-cut */
1801 N_("Jump to breakpoint location"), /* Tooltip */
1802 G_CALLBACK (on_jump_to_breakpoint_activate) /* action callback */
1806 /* Breakpoint list window
1807 *---------------------------------------------------------------------------*/
1809 static gboolean
1810 on_breakpoints_button_press (GtkWidget * widget, GdkEventButton * bevent, BreakpointsDBase *bd)
1812 if (bevent->button == 3)
1814 AnjutaUI *ui;
1815 GtkMenu *popup;
1816 GtkTreeModel *model;
1817 GtkTreeSelection *selection;
1818 GtkTreeIter iter;
1819 gboolean valid;
1821 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN(bd->plugin)->shell, NULL);
1822 popup = GTK_MENU (gtk_ui_manager_get_widget (GTK_UI_MANAGER (ui), "/PopupBreakpoint"));
1824 selection = gtk_tree_view_get_selection (bd->treeview);
1825 valid = gtk_tree_selection_get_selected (selection, &model, &iter);
1826 if (valid)
1828 BreakpointItem *bi;
1829 GtkAction *action;
1830 const gchar* label;
1831 const gchar* tooltip;
1833 gtk_tree_model_get (model, &iter, DATA_COLUMN, &bi, -1);
1834 action = gtk_action_group_get_action (bd->debugger_group, "ActionDmaEnableDisableBreakpoint");
1835 g_return_val_if_fail (action != NULL, FALSE);
1836 if (bi->bp.enable)
1838 label = N_("Disable Breakpoint");
1839 tooltip = N_("Disable a breakpoint");
1841 else
1843 label = N_("Enable Breakpoint");
1844 tooltip = N_("Enable a breakpoint");
1847 g_object_set (G_OBJECT (action),
1848 "label", label,
1849 "tooltip", tooltip,
1850 NULL);
1853 gtk_menu_popup (popup, NULL, NULL, NULL, NULL,
1854 bevent->button, bevent->time);
1856 else if ((bevent->type == GDK_2BUTTON_PRESS) && (bevent->button == 1))
1858 /* Double left mouse click */
1859 on_jump_to_breakpoint_activate (NULL, bd);
1862 return FALSE;
1865 static void
1866 create_breakpoint_gui(BreakpointsDBase *bd)
1868 static const gchar *column_names[COLUMNS_NB] = {
1869 N_("Enabled"), N_("Location"), N_("Address"), N_("Type"),
1870 N_("Condition"), N_("Pass count"), N_("State")};
1871 static GType column_type[COLUMNS_NB] = {
1872 G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
1873 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER};
1874 AnjutaUI *ui;
1875 GtkCellRenderer *renderer;
1876 GtkTreeViewColumn *column;
1877 GtkTreeModel *model;
1878 int i;
1880 g_return_if_fail (bd->treeview == NULL);
1881 g_return_if_fail (bd->window == NULL);
1882 g_return_if_fail (bd->debugger_group == NULL);
1883 g_return_if_fail (bd->permanent_group == NULL);
1885 /* breakpoints window */
1886 bd->model = gtk_list_store_newv (COLUMNS_NB, column_type);
1887 model = GTK_TREE_MODEL (bd->model);
1888 bd->treeview = GTK_TREE_VIEW (gtk_tree_view_new_with_model (model));
1889 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (bd->treeview),
1890 GTK_SELECTION_SINGLE);
1891 g_object_unref (G_OBJECT (model));
1893 renderer = gtk_cell_renderer_toggle_new ();
1894 column = gtk_tree_view_column_new_with_attributes (_(column_names[0]),
1895 renderer,
1896 "active",
1897 ENABLED_COLUMN,
1898 NULL);
1899 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1900 gtk_tree_view_append_column (bd->treeview, column);
1901 g_signal_connect (renderer, "toggled",
1902 G_CALLBACK (on_treeview_enabled_toggled), bd);
1904 renderer = gtk_cell_renderer_text_new ();
1905 for (i = ENABLED_COLUMN + 1; i < (COLUMNS_NB - 1); i++)
1907 column =
1908 gtk_tree_view_column_new_with_attributes (_(column_names[i]),
1909 renderer, "text", i, NULL);
1910 gtk_tree_view_column_set_sizing (column,
1911 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1912 gtk_tree_view_append_column (bd->treeview, column);
1915 /* Register menu actions */
1916 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN(bd->plugin)->shell, NULL);
1917 bd->debugger_group =
1918 anjuta_ui_add_action_group_entries (ui, "ActionGroupBreakpoint",
1919 _("Breakpoint operations"),
1920 actions_debugger_breakpoints,
1921 G_N_ELEMENTS (actions_debugger_breakpoints),
1922 GETTEXT_PACKAGE, TRUE, bd);
1923 bd->permanent_group =
1924 anjuta_ui_add_action_group_entries (ui, "ActionGroupBreakpoint",
1925 _("Breakpoint operations"),
1926 actions_permanent_breakpoints,
1927 G_N_ELEMENTS (actions_permanent_breakpoints),
1928 GETTEXT_PACKAGE, TRUE, bd);
1930 /* Add breakpoint window */
1931 bd->window = gtk_scrolled_window_new (NULL, NULL);
1932 gtk_widget_show (bd->window);
1933 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (bd->window),
1934 GTK_POLICY_AUTOMATIC,
1935 GTK_POLICY_AUTOMATIC);
1936 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (bd->window),
1937 GTK_SHADOW_IN);
1938 gtk_container_add (GTK_CONTAINER (bd->window), GTK_WIDGET (bd->treeview));
1939 gtk_widget_show_all (bd->window);
1940 anjuta_shell_add_widget (ANJUTA_PLUGIN(bd->plugin)->shell,
1941 bd->window,
1942 "AnjutaDebuggerBreakpoints", _("Breakpoints"),
1943 ANJUTA_STOCK_BREAKPOINT_ENABLED, ANJUTA_SHELL_PLACEMENT_BOTTOM,
1944 NULL);
1946 /* Add popup menu */
1947 g_signal_connect (bd->treeview, "button-press-event", G_CALLBACK (on_breakpoints_button_press), bd);
1950 static void
1951 destroy_breakpoint_gui (BreakpointsDBase *bd)
1953 AnjutaUI *ui;
1955 /* Remove menu actions */
1956 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN (bd->plugin)->shell, NULL);
1957 if (bd->debugger_group)
1959 anjuta_ui_remove_action_group (ui, bd->debugger_group);
1960 bd->debugger_group = NULL;
1962 if (bd->permanent_group)
1964 anjuta_ui_remove_action_group (ui, bd->permanent_group);
1965 bd->permanent_group = NULL;
1968 /* Destroy breakpoint window */
1969 if (bd->window != NULL)
1971 gtk_widget_destroy (bd->window);
1972 bd->window = NULL;
1976 /* Constructor & Destructor
1977 *---------------------------------------------------------------------------*/
1979 BreakpointsDBase *
1980 breakpoints_dbase_new (DebugManagerPlugin *plugin)
1982 BreakpointsDBase *bd;
1984 bd = g_new0 (BreakpointsDBase, 1);
1986 bd->plugin = plugin;
1988 /* Create graphical user inteface */
1989 create_breakpoint_gui (bd);
1991 /* Connect to Load and Save event */
1992 g_signal_connect (ANJUTA_PLUGIN(bd->plugin)->shell, "save-session",
1993 G_CALLBACK (on_session_save), bd);
1994 g_signal_connect (ANJUTA_PLUGIN(bd->plugin)->shell, "load-session",
1995 G_CALLBACK (on_session_load), bd);
1997 /* Connect on load program */
1998 g_signal_connect_swapped (bd->plugin, "program-loaded", G_CALLBACK (on_program_loaded), bd);
1999 g_signal_connect_swapped (bd->plugin, "debugger-started", G_CALLBACK (on_debugger_started), bd);
2000 g_signal_connect_swapped (bd->plugin, "debugger-stopped", G_CALLBACK (on_debugger_stopped), bd);
2002 bd->editor_watch =
2003 anjuta_plugin_add_watch (ANJUTA_PLUGIN(bd->plugin), "document_manager_current_editor",
2004 on_added_current_editor,
2005 on_removed_current_editor, bd);
2008 return bd;
2011 void
2012 breakpoints_dbase_destroy (BreakpointsDBase * bd)
2014 g_return_if_fail (bd != NULL);
2016 /* Disconnect all signal */
2017 g_signal_handlers_disconnect_matched (ANJUTA_PLUGIN(bd->plugin)->shell, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, bd);
2018 g_signal_handlers_disconnect_matched (bd->plugin, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, bd);
2019 breakpoints_dbase_disconnect_from_editors (bd);
2020 anjuta_plugin_remove_watch (ANJUTA_PLUGIN(bd->plugin), bd->editor_watch, FALSE);
2022 /* This is necessary to clear the editor of breakpoint markers */
2023 breakpoints_dbase_remove_all (bd);
2025 /* Destroy graphical user interface */
2026 destroy_breakpoint_gui (bd);
2028 g_free (bd->cond_history);
2029 g_free (bd->loc_history);
2031 g_free (bd);