* plugins/debug-manager/start.c:
[anjuta-git-plugin.git] / plugins / debug-manager / start.c
blob3e8629382e269ad592c86abd0697f15ff41d6909
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 start.c
4 Copyright (C) 2000 Kh. Naba Kumar Singh
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 start of debugger. It can be done in three ways:
23 * - Load a target of the current project_root_uri
24 * - Load a executable file
25 * - Attach to an already running program
26 *---------------------------------------------------------------------------*/
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
32 #include "start.h"
34 #include "queue.h"
36 /*#define DEBUG*/
37 #include <libanjuta/anjuta-debug.h>
38 #include <libanjuta/resources.h>
39 #include <libanjuta/interfaces/ianjuta-project-manager.h>
40 #include <libanjuta/anjuta-utils.h>
42 #include <libgnomevfs/gnome-vfs-mime-utils.h>
43 #include <libgnomevfs/gnome-vfs-utils.h>
45 #include <gnome.h>
47 #include <glade/glade-xml.h>
49 #include <errno.h>
50 #include <sys/stat.h>
51 #include <ctype.h>
52 #include <sys/wait.h>
53 #include <unistd.h>
54 #include <string.h>
56 /* Types
57 *---------------------------------------------------------------------------*/
59 typedef struct _AttachProcess AttachProcess;
60 typedef struct _AddSourceDialog AddSourceDialog;
61 typedef struct _LoadFileCallBack LoadFileCallBack;
63 enum
65 CLEAR_INITIAL,
66 CLEAR_UPDATE,
67 CLEAR_REVIEW,
68 CLEAR_FINAL
71 struct _AttachProcess
73 GtkWidget* dialog;
74 GtkWidget* treeview;
75 gint pid;
77 gboolean hide_paths;
78 gboolean hide_params;
79 gboolean process_tree;
81 gchar* ps_output;
82 GSList* iter_stack;
83 gint iter_stack_level;
84 gint num_spaces_to_skip;
85 gint num_spaces_per_level;
88 enum {
89 PID_COLUMN,
90 USER_COLUMN,
91 START_COLUMN,
92 COMMAND_COLUMN,
93 COLUMNS_NB
96 static char *column_names[COLUMNS_NB] = {
97 N_("Pid"), N_("User"), N_("Time"), N_("Command")
100 struct _AddSourceDialog
102 GtkTreeView *tree;
103 GtkFileChooser *entry;
104 GtkListStore *model;
107 struct _LoadFileCallBack
109 AnjutaPlugin *plugin;
110 DmaDebuggerQueue *debugger;
113 struct _DmaStart
115 AnjutaPlugin *plugin;
117 DmaDebuggerQueue *debugger;
119 gchar* target_uri;
120 gchar* program_args;
121 gboolean run_in_terminal;
122 gboolean stop_at_beginning;
124 GList *source_dirs;
127 /* Widgets found in glade file
128 *---------------------------------------------------------------------------*/
130 #define PARAMETER_DIALOG "parameter_dialog"
131 #define TERMINAL_CHECK_BUTTON "parameter_run_in_term_check"
132 #define STOP_AT_BEGINNING_CHECK_BUTTON "stop_at_beginning_check"
133 #define PARAMETER_COMBO "parameter_combo"
134 #define TARGET_COMBO "target_combo"
135 #define TARGET_SELECT_SIGNAL "on_select_target_clicked"
137 #define ADD_SOURCE_DIALOG "source_paths_dialog"
138 #define SOURCE_ENTRY "src_entry"
139 #define SOURCE_LIST "src_clist"
140 #define ADD_BUTTON "add_button"
141 #define REMOVE_BUTTON "remove_button"
142 #define UP_BUTTON "up_button"
143 #define DOWN_BUTTON "down_button"
145 #define ANJUTA_RESPONSE_SELECT_TARGET 0
147 static void attach_process_clear (AttachProcess * ap, gint ClearRequest);
149 /* Helper functions
150 *---------------------------------------------------------------------------*/
152 /* This functions get all directories of the current project containing
153 * static or shared library. Perhaps a more reliable way to find these
154 * directories is to really get the directories of all source files */
156 static GList*
157 get_source_directories (AnjutaPlugin *plugin)
159 gchar *cwd;
160 GList *node, *search_dirs = NULL;
161 GList *slibs_dirs = NULL;
162 GList *libs_dirs = NULL;
163 GValue value = {0,};
165 return NULL;
166 cwd = g_get_current_dir();
167 search_dirs = g_list_prepend (search_dirs, gnome_vfs_get_uri_from_local_path(cwd));
168 g_free (cwd);
170 /* Check if a project is already open */
171 anjuta_shell_get_value (plugin->shell, "project_root_uri", &value, NULL);
173 /* Set source file search directories */
174 if (g_value_get_string (&value) != NULL)
176 IAnjutaProjectManager *pm;
177 pm = anjuta_shell_get_interface (plugin->shell,
178 IAnjutaProjectManager, NULL);
179 if (pm)
181 slibs_dirs =
182 ianjuta_project_manager_get_targets (pm,
183 IANJUTA_PROJECT_MANAGER_TARGET_SHAREDLIB,
184 NULL);
185 libs_dirs =
186 ianjuta_project_manager_get_targets (pm,
187 IANJUTA_PROJECT_MANAGER_TARGET_STATICLIB,
188 NULL);
191 slibs_dirs = g_list_reverse (slibs_dirs);
192 libs_dirs = g_list_reverse (libs_dirs);
194 node = slibs_dirs;
195 while (node)
197 gchar *dir_uri;
198 dir_uri = g_path_get_dirname (node->data);
199 search_dirs = g_list_prepend (search_dirs, dir_uri);
200 node = g_list_next (node);
203 node = libs_dirs;
204 while (node)
206 gchar *dir_uri;
207 dir_uri = g_path_get_dirname (node->data);
208 search_dirs = g_list_prepend (search_dirs, dir_uri);
209 node = g_list_next (node);
212 g_list_foreach (slibs_dirs, (GFunc)g_free, NULL);
213 g_list_free (slibs_dirs);
214 g_list_foreach (libs_dirs, (GFunc)g_free, NULL);
215 g_list_free (libs_dirs);
217 return g_list_reverse (search_dirs);
220 static void
221 free_source_directories (GList *dirs)
223 g_list_foreach (dirs, (GFunc)g_free, NULL);
224 g_list_free (dirs);
227 /* Callback for saving session
228 *---------------------------------------------------------------------------*/
230 static void
231 on_session_save (AnjutaShell *shell, AnjutaSessionPhase phase, AnjutaSession *session, DmaStart *this)
233 if (phase != ANJUTA_SESSION_PHASE_NORMAL)
234 return;
236 if (this->program_args)
238 gchar *arg;
239 anjuta_session_set_string (session, "Execution", "Program arguments", this->program_args);
240 arg = anjuta_session_get_string (session, "Execution", "Program arguments");
242 if (this->target_uri)
244 gchar *uri;
245 anjuta_session_set_string (session, "Execution", "Program uri", this->target_uri);
246 uri = anjuta_session_get_string (session, "Execution", "Program uri");
248 anjuta_session_set_int (session, "Execution", "Run in terminal", this->run_in_terminal + 1);
249 anjuta_session_set_int (session, "Execution", "Stop at beginning", this->stop_at_beginning + 1);
250 if (this->source_dirs)
252 anjuta_session_set_string_list (session, "Debugger", "Source directories", this->source_dirs);
256 static void on_session_load (AnjutaShell *shell, AnjutaSessionPhase phase, AnjutaSession *session, DmaStart *this)
258 gchar *program_args;
259 gchar *target_uri;
260 gint run_in_terminal;
261 gint stop_at_beginning;
263 if (phase != ANJUTA_SESSION_PHASE_NORMAL)
264 return;
266 program_args = anjuta_session_get_string (session, "Execution", "Program arguments");
267 if (this->program_args)
269 g_free (this->program_args);
270 this->program_args = NULL;
272 if (program_args)
274 this->program_args = program_args;
277 target_uri = anjuta_session_get_string (session, "Execution", "Program uri");
278 if (this->target_uri)
280 g_free (this->target_uri);
281 this->target_uri = NULL;
283 if (target_uri)
285 this->target_uri = target_uri;
288 /* The flag is store as 1 == FALSE, 2 == TRUE */
289 run_in_terminal = anjuta_session_get_int (session, "Execution", "Run in terminal");
290 if (run_in_terminal == 0)
291 this->run_in_terminal = TRUE; /* Default value */
292 else
293 this->run_in_terminal = run_in_terminal - 1;
295 stop_at_beginning = anjuta_session_get_int (session, "Execution", "Stop at beginning");
296 if (stop_at_beginning == 0)
297 this->stop_at_beginning = TRUE; /* Default value */
298 else
299 this->stop_at_beginning = stop_at_beginning - 1;
300 /* Initialize source_dirs */
301 if (this->source_dirs != NULL)
303 g_list_foreach (this->source_dirs, (GFunc)g_free, NULL);
304 g_list_free (this->source_dirs);
306 this->source_dirs = anjuta_session_get_string_list (session, "Debugger", "Source directories");
309 /* Attach to process private functions
310 *---------------------------------------------------------------------------*/
312 static AttachProcess *
313 attach_process_new ()
315 AttachProcess *ap;
316 ap = g_new0 (AttachProcess, 1);
317 attach_process_clear (ap, CLEAR_INITIAL);
318 return ap;
321 static void
322 attach_process_clear (AttachProcess * ap, gint ClearRequest)
324 GtkTreeModel *model;
326 // latest ps output
327 switch (ClearRequest)
329 case CLEAR_UPDATE:
330 case CLEAR_FINAL:
331 if (ap->ps_output)
333 g_free (ap->ps_output);
335 case CLEAR_INITIAL:
336 ap->ps_output = NULL;
339 // helper variables
340 switch (ClearRequest)
342 case CLEAR_INITIAL:
343 case CLEAR_UPDATE:
344 case CLEAR_REVIEW:
345 ap->pid = -1L;
346 ap->iter_stack = NULL;
347 ap->iter_stack_level = -1;
348 ap->num_spaces_to_skip = -1;
351 // tree model
352 switch (ClearRequest)
354 case CLEAR_UPDATE:
355 case CLEAR_REVIEW:
356 case CLEAR_FINAL:
357 model = gtk_tree_view_get_model (GTK_TREE_VIEW (ap->treeview));
358 gtk_tree_store_clear (GTK_TREE_STORE (model));
361 // dialog widget
362 if (ClearRequest == CLEAR_FINAL)
364 gtk_widget_destroy (ap->dialog);
365 ap->dialog = NULL;
369 static inline gchar *
370 skip_spaces (gchar *pos)
372 while (*pos == ' ')
373 pos++;
374 return pos;
377 static inline gchar *
378 skip_token (gchar *pos)
380 while (*pos != ' ')
381 pos++;
382 *pos++ = '\0';
383 return pos;
386 static gchar *
387 skip_token_and_spaces (gchar *pos)
389 pos = skip_token (pos);
390 return skip_spaces (pos);
393 static GtkTreeIter *
394 iter_stack_push_new (AttachProcess *ap, GtkTreeStore *store)
396 GtkTreeIter *new_iter, *top_iter;
397 new_iter = g_new (GtkTreeIter, 1);
398 top_iter = (GtkTreeIter *) (g_slist_nth_data (ap->iter_stack, 0));
399 ap->iter_stack =
400 g_slist_prepend (ap->iter_stack, (gpointer) (new_iter));
401 gtk_tree_store_append (store, new_iter, top_iter);
402 ap->iter_stack_level++;
403 return new_iter;
406 static gboolean
407 iter_stack_pop (AttachProcess *ap)
409 if (ap->iter_stack_level < 0)
410 return FALSE;
412 GtkTreeIter *iter =
413 (GtkTreeIter *) (g_slist_nth_data (ap->iter_stack, 0));
414 ap->iter_stack =
415 g_slist_delete_link (ap->iter_stack, ap->iter_stack);
416 g_free (iter);
417 ap->iter_stack_level--;
418 return TRUE;
421 static void
422 iter_stack_clear (AttachProcess *ap)
424 while (iter_stack_pop (ap));
427 static gchar *
428 calc_depth_and_get_iter (AttachProcess *ap, GtkTreeStore *store,
429 GtkTreeIter **iter, gchar *pos)
431 gchar *orig_pos;
432 guint num_spaces, depth, i;
434 // count spaces
435 orig_pos = pos;
436 while (*pos == ' ')
437 pos++;
438 num_spaces = pos - orig_pos;
440 if (ap->process_tree)
442 if (ap->num_spaces_to_skip < 0)
444 // first process to be inserted
445 ap->num_spaces_to_skip = num_spaces;
446 ap->num_spaces_per_level = -1;
447 *iter = iter_stack_push_new (ap, store);
449 else
451 if (ap->num_spaces_per_level < 0)
453 if (num_spaces == ap->num_spaces_to_skip)
455 // num_spaces_per_level still unknown
456 iter_stack_pop (ap);
457 *iter = iter_stack_push_new (ap, store);
459 else
461 // first time at level 1
462 ap->num_spaces_per_level =
463 num_spaces - ap->num_spaces_to_skip;
464 *iter = iter_stack_push_new (ap, store);
467 else
469 depth = (num_spaces - ap->num_spaces_to_skip) /
470 ap->num_spaces_per_level;
471 if (depth == ap->iter_stack_level)
473 // level not changed
474 iter_stack_pop (ap);
475 *iter = iter_stack_push_new (ap, store);
477 else
478 if (depth == ap->iter_stack_level + 1)
479 *iter = iter_stack_push_new (ap, store);
480 else
481 if (depth < ap->iter_stack_level)
483 // jump some levels backward
484 depth = ap->iter_stack_level - depth;
485 for (i = 0; i <= depth; i++)
486 iter_stack_pop (ap);
487 *iter = iter_stack_push_new (ap, store);
489 else
491 // should never get here
492 g_warning("Unknown error");
493 iter_stack_pop (ap);
494 *iter = iter_stack_push_new (ap, store);
499 else
501 iter_stack_pop (ap);
502 *iter = iter_stack_push_new (ap, store);
505 return pos;
508 static gchar *
509 skip_path (gchar *pos)
511 /* can't use g_path_get_basename() - wouldn't work for a processes
512 started with parameters containing '/' */
513 gchar c, *final_pos = pos;
515 if (*pos == G_DIR_SEPARATOR)
518 c = *pos;
519 if (c == G_DIR_SEPARATOR)
521 final_pos = ++pos;
522 continue;
524 else
525 if (c == ' ' || c == '\0')
526 break;
527 else
528 ++pos;
530 while (1);
532 return final_pos;
535 static inline void
536 remove_params (gchar *pos)
540 if (*(++pos) == ' ')
541 *pos = '\0';
543 while (*pos);
546 static void
547 attach_process_add_line (AttachProcess *ap, GtkTreeStore *store, gchar *line)
549 gchar *pid, *user, *start, *command, *tmp;
550 // guint i, level;
551 GtkTreeIter *iter;
553 pid = skip_spaces (line); // skip leading spaces
554 user = skip_token_and_spaces (pid); // skip PID
555 start = skip_token_and_spaces (user); // skip USER
556 tmp = skip_token (start); // skip START (do not skip spaces)
558 command = calc_depth_and_get_iter (ap, store, &iter, tmp);
560 if (ap->hide_paths)
562 command = skip_path (command);
565 if (ap->hide_params)
567 remove_params(command);
570 gtk_tree_store_set (store, iter,
571 PID_COLUMN, pid,
572 USER_COLUMN, user,
573 START_COLUMN, start,
574 COMMAND_COLUMN, command,
575 -1);
578 static void
579 attach_process_review (AttachProcess *ap)
581 gchar *ps_output, *begin, *end;
582 guint line_num = 0;
583 GtkTreeStore *store;
585 g_return_if_fail (ap);
586 g_return_if_fail (ap->ps_output);
587 store = GTK_TREE_STORE (gtk_tree_view_get_model
588 (GTK_TREE_VIEW (ap->treeview)));
589 g_return_if_fail (store);
591 ps_output = g_strdup (ap->ps_output);
592 end = ps_output;
593 while (*end)
595 begin = end;
596 while (*end && *end != '\n') end++;
597 if (++line_num > 2) // skip description line & process 'init'
599 *end = '\0';
600 attach_process_add_line (ap, store, begin);
602 end++;
604 g_free (ps_output);
606 iter_stack_clear (ap);
607 gtk_tree_view_expand_all (GTK_TREE_VIEW (ap->treeview));
610 static void
611 attach_process_update (AttachProcess * ap)
613 gchar *tmp, *tmp1, *cmd;
614 gint ch_pid;
615 gchar *shell;
616 GtkTreeStore *store;
617 gboolean result;
619 g_return_if_fail (ap);
620 store = GTK_TREE_STORE (gtk_tree_view_get_model
621 (GTK_TREE_VIEW (ap->treeview)));
622 g_return_if_fail (store);
624 if (anjuta_util_prog_is_installed ("ps", TRUE) == FALSE)
625 return;
627 tmp = anjuta_util_get_a_tmp_file ();
628 cmd = g_strconcat ("ps axw -H -o pid,user,start_time,args > ", tmp, NULL);
629 shell = gnome_util_user_shell ();
630 ch_pid = fork ();
631 if (ch_pid == 0)
633 execlp (shell, shell, "-c", cmd, NULL);
635 if (ch_pid < 0)
637 anjuta_util_dialog_error_system (NULL, errno,
638 _("Unable to execute: %s."), cmd);
639 g_free (tmp);
640 g_free (cmd);
641 return;
643 waitpid (ch_pid, NULL, 0);
644 g_free (cmd);
646 result = g_file_get_contents (tmp, &tmp1, NULL, NULL);
647 remove (tmp);
648 g_free (tmp);
649 if (! result)
651 anjuta_util_dialog_error_system (NULL, errno,
652 _("Unable to open the file: %s\n"),
653 tmp);
654 return;
657 attach_process_clear (ap, CLEAR_UPDATE);
658 ap->ps_output = anjuta_util_convert_to_utf8 (tmp1);
659 g_free (tmp1);
660 if (ap->ps_output)
662 attach_process_review (ap);
666 static void
667 on_selection_changed (GtkTreeSelection *selection, AttachProcess *ap)
669 GtkTreeModel *model;
670 GtkTreeIter iter;
672 g_return_if_fail (ap);
673 if (gtk_tree_selection_get_selected (selection, &model, &iter))
675 gchar* text;
676 gtk_tree_model_get (model, &iter, PID_COLUMN, &text, -1);
677 ap->pid = atoi (text);
678 gtk_dialog_set_response_sensitive (GTK_DIALOG (ap->dialog),
679 GTK_RESPONSE_OK, TRUE);
681 else
683 gtk_dialog_set_response_sensitive (GTK_DIALOG (ap->dialog),
684 GTK_RESPONSE_OK, FALSE);
685 ap->pid = -1L;
689 static gboolean
690 on_delete_event (GtkWidget *dialog, GdkEvent *event, AttachProcess *ap)
692 g_return_val_if_fail (ap, FALSE);
693 attach_process_clear (ap, CLEAR_FINAL);
694 return FALSE;
697 static gint
698 sort_pid (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
699 gpointer user_data)
701 gchar *nptr;
702 gint pid1, pid2;
704 gtk_tree_model_get (model, a, PID_COLUMN, &nptr, -1);
705 pid1 = atoi (nptr);
707 gtk_tree_model_get (model, b, PID_COLUMN, &nptr, -1);
708 pid2 = atoi (nptr);
710 return pid1 - pid2;
713 static void
714 on_toggle_hide_paths (GtkToggleButton *togglebutton, AttachProcess * ap)
716 ap->hide_paths = gtk_toggle_button_get_active (togglebutton);
717 attach_process_clear (ap, CLEAR_REVIEW);
718 attach_process_review (ap);
721 static void
722 on_toggle_hide_params (GtkToggleButton *togglebutton, AttachProcess * ap)
724 ap->hide_params = gtk_toggle_button_get_active (togglebutton);
725 attach_process_clear (ap, CLEAR_REVIEW);
726 attach_process_review (ap);
729 static void
730 on_toggle_process_tree (GtkToggleButton *togglebutton, AttachProcess * ap)
732 ap->process_tree = gtk_toggle_button_get_active (togglebutton);
733 attach_process_clear (ap, CLEAR_REVIEW);
734 attach_process_review (ap);
737 static pid_t
738 attach_process_show (AttachProcess * ap, GtkWindow *parent)
740 GladeXML *gxml;
741 GtkTreeView *view;
742 GtkTreeStore *store;
743 GtkCellRenderer *renderer;
744 GtkTreeSelection *selection;
745 GtkCheckButton *checkb_hide_paths;
746 GtkCheckButton *checkb_hide_params;
747 GtkCheckButton *checkb_process_tree;
748 gint i, res;
749 pid_t selected_pid = -1;
751 g_return_val_if_fail (ap != NULL, -1);
753 if (!ap->dialog)
755 gxml = glade_xml_new (GLADE_FILE, "attach_process_dialog", NULL);
756 ap->dialog = glade_xml_get_widget (gxml, "attach_process_dialog");
757 ap->treeview = glade_xml_get_widget (gxml, "attach_process_tv");
758 checkb_hide_paths = GTK_CHECK_BUTTON (
759 glade_xml_get_widget (gxml, "checkb_hide_paths"));
760 checkb_hide_params = GTK_CHECK_BUTTON (
761 glade_xml_get_widget (gxml, "checkb_hide_params"));
762 checkb_process_tree = GTK_CHECK_BUTTON (
763 glade_xml_get_widget (gxml, "checkb_process_tree"));
764 g_object_unref (gxml);
766 view = GTK_TREE_VIEW (ap->treeview);
767 store = gtk_tree_store_new (COLUMNS_NB,
768 G_TYPE_STRING,
769 G_TYPE_STRING,
770 G_TYPE_STRING,
771 G_TYPE_STRING);
772 gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
773 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (view),
774 GTK_SELECTION_SINGLE);
775 g_object_unref (G_OBJECT (store));
777 renderer = gtk_cell_renderer_text_new ();
779 for (i = PID_COLUMN; i < COLUMNS_NB; i++) {
780 GtkTreeViewColumn *column;
782 column = gtk_tree_view_column_new_with_attributes (column_names[i],
783 renderer, "text", i, NULL);
784 gtk_tree_view_column_set_sort_column_id(column, i);
785 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
786 gtk_tree_view_append_column (view, column);
787 if (i == COMMAND_COLUMN)
788 gtk_tree_view_set_expander_column(view, column);
790 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store), PID_COLUMN,
791 sort_pid, NULL, NULL);
792 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
793 START_COLUMN, GTK_SORT_DESCENDING);
795 ap->hide_paths = gtk_toggle_button_get_active (
796 GTK_TOGGLE_BUTTON (checkb_hide_paths));
797 ap->hide_params = gtk_toggle_button_get_active (
798 GTK_TOGGLE_BUTTON (checkb_hide_params));
799 ap->process_tree = gtk_toggle_button_get_active (
800 GTK_TOGGLE_BUTTON (checkb_process_tree));
802 attach_process_update (ap);
804 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ap->treeview));
805 g_signal_connect (G_OBJECT (selection), "changed",
806 G_CALLBACK (on_selection_changed), ap);
807 g_signal_connect (G_OBJECT (ap->dialog), "delete_event",
808 G_CALLBACK (on_delete_event), ap);
809 g_signal_connect (GTK_OBJECT (checkb_hide_paths), "toggled",
810 G_CALLBACK (on_toggle_hide_paths), ap);
811 g_signal_connect (GTK_OBJECT (checkb_hide_params), "toggled",
812 G_CALLBACK (on_toggle_hide_params), ap);
813 g_signal_connect (GTK_OBJECT (checkb_process_tree), "toggled",
814 G_CALLBACK (on_toggle_process_tree), ap);
817 gtk_window_set_transient_for (GTK_WINDOW (ap->dialog),
818 GTK_WINDOW (parent));
819 /* gtk_widget_show (ap->dialog); */
820 res = gtk_dialog_run (GTK_DIALOG (ap->dialog));
821 while (res == GTK_RESPONSE_APPLY)
823 attach_process_update (ap);
824 res = gtk_dialog_run (GTK_DIALOG (ap->dialog));
826 if (res == GTK_RESPONSE_OK)
828 selected_pid = ap->pid;
830 attach_process_clear (ap, CLEAR_FINAL);
831 return selected_pid;
834 static void
835 attach_process_destroy (AttachProcess * ap)
837 g_return_if_fail (ap);
838 g_free (ap);
841 /* Load file private functions
842 *---------------------------------------------------------------------------*/
844 static void
845 on_select_target (GtkButton *button, gpointer user_data)
847 gtk_dialog_response (GTK_DIALOG (user_data), ANJUTA_RESPONSE_SELECT_TARGET);
850 static void
851 dma_start_load_uri (DmaStart *this)
853 GList *search_dirs;
854 GnomeVFSURI *vfs_uri;
855 gchar *mime_type;
856 gchar *filename;
858 if (!dma_quit_debugger (this)) return;
860 if ((this->target_uri != NULL) && (*(this->target_uri) != '\0'))
862 vfs_uri = gnome_vfs_uri_new (this->target_uri);
864 g_return_if_fail (vfs_uri != NULL);
866 if (!gnome_vfs_uri_is_local (vfs_uri)) return;
868 search_dirs = get_source_directories (this->plugin);
870 mime_type = gnome_vfs_get_mime_type (this->target_uri);
871 filename = gnome_vfs_get_local_path_from_uri (this->target_uri);
873 dma_queue_load (this->debugger, filename, mime_type, this->source_dirs);
875 g_free (filename);
876 g_free (mime_type);
877 gnome_vfs_uri_unref (vfs_uri);
878 free_source_directories (search_dirs);
883 static gboolean
884 dma_set_parameters (DmaStart *this)
886 GladeXML *gxml;
887 GtkWidget *dlg;
888 GtkWindow *parent;
889 GtkToggleButton *term;
890 GtkToggleButton *stop_at_beginning;
891 GtkComboBox *params;
892 GtkComboBox *target;
893 gint response;
894 GtkTreeModel* model;
895 GtkTreeIter iter;
896 GValue value = {0,};
897 const gchar *project_root_uri;
899 parent = GTK_WINDOW (this->plugin->shell);
900 gxml = glade_xml_new (GLADE_FILE, PARAMETER_DIALOG, NULL);
901 if (gxml == NULL)
903 anjuta_util_dialog_error(parent, _("Missing file %s"), GLADE_FILE);
904 return FALSE;
907 dlg = glade_xml_get_widget (gxml, PARAMETER_DIALOG);
908 term = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gxml, TERMINAL_CHECK_BUTTON));
909 stop_at_beginning = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gxml, STOP_AT_BEGINNING_CHECK_BUTTON));
910 params = GTK_COMBO_BOX (glade_xml_get_widget (gxml, PARAMETER_COMBO));
911 target = GTK_COMBO_BOX (glade_xml_get_widget (gxml, TARGET_COMBO));
912 glade_xml_signal_connect_data (gxml, TARGET_SELECT_SIGNAL, GTK_SIGNAL_FUNC (on_select_target), dlg);
913 g_object_unref (gxml);
915 /* Fill parameter combo box */
916 model = GTK_TREE_MODEL (gtk_list_store_new (1, GTK_TYPE_STRING));
917 gtk_combo_box_set_model (params, model);
918 gtk_combo_box_entry_set_text_column( GTK_COMBO_BOX_ENTRY(params), 0);
919 if (this->program_args != NULL)
921 gtk_list_store_append (GTK_LIST_STORE (model), &iter);
922 gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, this->program_args, -1);
923 gtk_entry_set_text (GTK_ENTRY (GTK_BIN (params)->child), this->program_args);
925 g_object_unref (model);
927 /* Fill target combo box */
928 model = GTK_TREE_MODEL (gtk_list_store_new (1, GTK_TYPE_STRING));
929 gtk_combo_box_set_model (target, model);
930 gtk_combo_box_entry_set_text_column( GTK_COMBO_BOX_ENTRY(target), 0);
932 anjuta_shell_get_value (this->plugin->shell, "project_root_uri", &value, NULL);
933 project_root_uri = G_VALUE_HOLDS_STRING (&value) ? g_value_get_string (&value) : NULL;
934 if (project_root_uri != NULL)
936 /* One project loaded, get all executable target */
937 IAnjutaProjectManager *pm;
938 GList *exec_targets = NULL;
940 pm = anjuta_shell_get_interface (this->plugin->shell,
941 IAnjutaProjectManager, NULL);
942 if (pm != NULL)
944 exec_targets = ianjuta_project_manager_get_targets (pm,
945 IANJUTA_PROJECT_MANAGER_TARGET_EXECUTABLE,
946 NULL);
948 if (exec_targets != NULL)
950 GList *node;
952 for (node = exec_targets; node; node = g_list_next (node))
954 if ((this->target_uri == NULL) || (strcmp(this->target_uri, node->data) != 0))
956 gtk_list_store_append (GTK_LIST_STORE (model), &iter);
957 gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, node->data, -1);
959 g_free (node->data);
961 g_list_free (exec_targets);
964 g_object_unref (model);
966 if (this->target_uri != NULL)
968 gtk_list_store_prepend (GTK_LIST_STORE (model), &iter);
969 gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, this->target_uri, -1);
970 gtk_entry_set_text (GTK_ENTRY (GTK_BIN (target)->child), this->target_uri);
972 else if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter))
974 gchar *txt;
976 gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &txt, -1);
977 gtk_entry_set_text (GTK_ENTRY (GTK_BIN (target)->child), txt);
978 g_free (txt);
981 /* Set terminal option */
982 if (this->run_in_terminal) gtk_toggle_button_set_active (term, TRUE);
983 if (this->stop_at_beginning) gtk_toggle_button_set_active (stop_at_beginning, TRUE);
985 gtk_window_set_transient_for (GTK_WINDOW (dlg), parent);
987 /* Run dialog */
988 for (;;)
990 response = gtk_dialog_run (GTK_DIALOG (dlg));
991 switch (response)
993 case GTK_RESPONSE_OK:
994 case GTK_RESPONSE_APPLY:
996 const gchar *arg;
997 const gchar *uri;
999 if (this->program_args != NULL) g_free (this->program_args);
1000 arg = gtk_entry_get_text (GTK_ENTRY (GTK_BIN (params)->child));
1001 this->program_args = g_strdup (arg);
1003 uri = gtk_entry_get_text (GTK_ENTRY (GTK_BIN (target)->child));
1004 if (this->target_uri != NULL)
1006 if (strcmp(uri, this->target_uri) != 0)
1008 g_free (this->target_uri);
1009 this->target_uri = g_strdup (uri);
1012 else
1014 this->target_uri = g_strdup (uri);
1017 this->run_in_terminal = gtk_toggle_button_get_active (term);
1018 this->stop_at_beginning = gtk_toggle_button_get_active (stop_at_beginning);
1019 break;
1021 case ANJUTA_RESPONSE_SELECT_TARGET:
1023 GtkWidget *sel_dlg = gtk_file_chooser_dialog_new (
1024 _("Load Target to debug"), GTK_WINDOW (dlg),
1025 GTK_FILE_CHOOSER_ACTION_OPEN,
1026 GTK_STOCK_OPEN, GTK_RESPONSE_OK,
1027 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
1028 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(sel_dlg), FALSE);
1029 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (sel_dlg), TRUE);
1031 GtkFileFilter *filter = gtk_file_filter_new ();
1032 gtk_file_filter_set_name (filter, _("All files"));
1033 gtk_file_filter_add_pattern (filter, "*");
1034 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (sel_dlg), filter);
1036 //gtk_window_set_transient_for (GTK_WINDOW (dlg), parent);
1038 response = gtk_dialog_run (GTK_DIALOG (sel_dlg));
1040 if (response == GTK_RESPONSE_OK)
1042 gchar* uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (sel_dlg));
1044 if (this->target_uri != NULL)
1046 if (strcmp(uri, this->target_uri) != 0)
1048 g_free (this->target_uri);
1049 this->target_uri = uri;
1051 else
1053 g_free (uri);
1056 else
1058 this->target_uri = uri;
1061 gtk_entry_set_text (GTK_ENTRY (GTK_BIN (target)->child), this->target_uri);
1064 gtk_widget_destroy (GTK_WIDGET (sel_dlg));
1066 continue;
1068 default:
1069 break;
1071 break;
1073 gtk_widget_destroy (dlg);
1075 return response == GTK_RESPONSE_OK;
1078 /* Add source dialog
1079 *---------------------------------------------------------------------------*/
1081 static gboolean
1082 on_add_source_in_list (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
1084 GList** list = (GList **)user_data;
1085 gchar* dir;
1086 gchar* uri;
1088 gtk_tree_model_get (model, iter, 0, &dir, -1);
1089 uri = gnome_vfs_get_uri_from_local_path (dir);
1090 *list = g_list_prepend (*list, uri);
1091 g_free (dir);
1093 return FALSE;
1096 static void
1097 on_add_source_in_model (gpointer data, gpointer user_data)
1099 GtkListStore* model = (GtkListStore *)user_data;
1100 GtkTreeIter iter;
1101 gchar *local;
1103 local = gnome_vfs_get_local_path_from_uri ((const char *)data);
1104 gtk_list_store_append (model, &iter);
1105 gtk_list_store_set (model, &iter, 0, local, -1);
1106 g_free (local);
1109 static void
1110 on_source_add_button (GtkButton *button, AddSourceDialog *dlg)
1112 GtkTreeIter iter;
1113 const gchar *path;
1115 path = gtk_file_chooser_get_filename (dlg->entry);
1116 if ((path != NULL) && (*path != '\0'))
1118 gtk_list_store_append (dlg->model, &iter);
1119 gtk_list_store_set (dlg->model, &iter, 0, path, -1);
1123 static void
1124 on_source_remove_button (GtkButton *button, AddSourceDialog *dlg)
1126 GtkTreeIter iter;
1127 GtkTreeSelection* sel;
1129 sel = gtk_tree_view_get_selection (dlg->tree);
1130 if (gtk_tree_selection_get_selected (sel, NULL, &iter))
1132 gtk_list_store_remove (dlg->model, &iter);
1136 static void
1137 on_source_up_button (GtkButton *button, AddSourceDialog *dlg)
1139 GtkTreeIter iter;
1140 GtkTreeSelection* sel;
1142 sel = gtk_tree_view_get_selection (dlg->tree);
1143 if (gtk_tree_selection_get_selected (sel, NULL, &iter))
1145 GtkTreePath *path;
1147 path = gtk_tree_model_get_path(GTK_TREE_MODEL (dlg->model), &iter);
1148 if (gtk_tree_path_prev(path))
1150 GtkTreeIter pos;
1152 gtk_tree_model_get_iter(GTK_TREE_MODEL (dlg->model), &pos, path);
1153 gtk_list_store_move_before (dlg->model, &iter, &pos);
1158 static void
1159 on_source_down_button (GtkButton *button, AddSourceDialog *dlg)
1161 GtkTreeIter iter;
1162 GtkTreeSelection* sel;
1164 sel = gtk_tree_view_get_selection (dlg->tree);
1165 if (gtk_tree_selection_get_selected (sel, NULL, &iter))
1167 GtkTreeIter pos = iter;
1169 if (gtk_tree_model_iter_next (GTK_TREE_MODEL (dlg->model), &pos))
1171 gtk_list_store_move_after (dlg->model, &iter, &pos);
1176 static void
1177 add_source_show (DmaStart *this)
1179 AddSourceDialog dlg;
1180 GladeXML *gxml;
1181 GtkWidget *widget;
1182 GtkWindow *parent;
1183 GtkCellRenderer *renderer;
1184 GtkTreeViewColumn *column;
1185 GObject *button;
1187 parent = GTK_WINDOW (this->plugin->shell);
1188 gxml = glade_xml_new (GLADE_FILE, ADD_SOURCE_DIALOG, NULL);
1189 if (gxml == NULL)
1191 anjuta_util_dialog_error(parent, _("Missing file %s"), GLADE_FILE);
1192 return;
1195 widget = glade_xml_get_widget (gxml, ADD_SOURCE_DIALOG);
1196 dlg.tree = GTK_TREE_VIEW (glade_xml_get_widget (gxml, SOURCE_LIST));
1197 dlg.entry = GTK_FILE_CHOOSER (glade_xml_get_widget (gxml, SOURCE_ENTRY));
1199 /* Connect signals */
1200 button = G_OBJECT (glade_xml_get_widget (gxml, ADD_BUTTON));
1201 g_signal_connect (button, "clicked", G_CALLBACK (on_source_add_button), &dlg);
1202 button = G_OBJECT (glade_xml_get_widget (gxml, REMOVE_BUTTON));
1203 g_signal_connect (button, "clicked", G_CALLBACK (on_source_remove_button), &dlg);
1204 button = G_OBJECT (glade_xml_get_widget (gxml, UP_BUTTON));
1205 g_signal_connect (button, "clicked", G_CALLBACK (on_source_up_button), &dlg);
1206 button = G_OBJECT (glade_xml_get_widget (gxml, DOWN_BUTTON));
1207 g_signal_connect (button, "clicked", G_CALLBACK (on_source_down_button), &dlg);
1209 g_object_unref (gxml);
1211 renderer = gtk_cell_renderer_text_new ();
1212 column = gtk_tree_view_column_new_with_attributes (_("Path"), renderer, "text", 0, NULL);
1213 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1214 gtk_tree_view_append_column (dlg.tree, column);
1215 gtk_tree_view_set_expander_column(dlg.tree, column);
1217 dlg.model = gtk_list_store_new (1, GTK_TYPE_STRING);
1218 gtk_tree_view_set_model (dlg.tree, GTK_TREE_MODEL (dlg.model));
1220 gtk_window_set_transient_for (GTK_WINDOW (widget), parent);
1222 /* Initialize source path list */
1223 g_list_foreach (this->source_dirs, on_add_source_in_model, dlg.model);
1225 /* Run dialog */
1226 for (;;)
1228 gint response = gtk_dialog_run (GTK_DIALOG (widget));
1230 switch (response)
1232 case GTK_RESPONSE_DELETE_EVENT:
1233 case GTK_RESPONSE_CLOSE:
1234 g_list_foreach (this->source_dirs, (GFunc)g_free, NULL);
1235 g_list_free (this->source_dirs);
1236 this->source_dirs = NULL;
1237 gtk_tree_model_foreach (GTK_TREE_MODEL (dlg.model), on_add_source_in_list, &this->source_dirs);
1238 this->source_dirs = g_list_reverse (this->source_dirs);
1239 break;
1240 case GTK_RESPONSE_CANCEL:
1241 gtk_list_store_clear (dlg.model);
1242 g_list_foreach (this->source_dirs, on_add_source_in_model, dlg.model);
1243 continue;
1244 default:
1245 break;
1247 break;
1249 gtk_widget_destroy (widget);
1252 /* Public functions
1253 *---------------------------------------------------------------------------*/
1255 gboolean
1256 dma_quit_debugger (DmaStart* this)
1258 if (dma_debugger_queue_get_state (this->debugger) > IANJUTA_DEBUGGER_PROGRAM_LOADED)
1260 gchar *msg = _("The program is running.\n"
1261 "Do you still want to stop the debugger?");
1263 if (!anjuta_util_dialog_boolean_question (GTK_WINDOW (this->plugin->shell), msg)) return FALSE;
1266 dma_queue_interrupt (this->debugger);
1267 dma_queue_quit (this->debugger);
1269 return TRUE;
1272 void
1273 dma_add_source_path (DmaStart *self)
1275 add_source_show (self);
1278 void
1279 dma_attach_to_process (DmaStart* this)
1281 pid_t selected_pid;
1282 GtkWindow *parent;
1283 AttachProcess *attach_process = NULL;
1285 if (!dma_quit_debugger (this)) return;
1287 parent = GTK_WINDOW (ANJUTA_PLUGIN (this->plugin)->shell);
1288 attach_process = attach_process_new();
1290 selected_pid = attach_process_show (attach_process, parent);
1291 if (selected_pid > 0)
1293 long lpid = selected_pid;
1294 GList *search_dirs;
1296 search_dirs = get_source_directories (this->plugin);
1298 dma_queue_attach (this->debugger, lpid, this->source_dirs);
1299 free_source_directories (search_dirs);
1301 attach_process_destroy(attach_process);
1304 gboolean
1305 dma_run_target (DmaStart *this)
1307 if (dma_set_parameters (this) == TRUE)
1309 dma_start_load_uri (this);
1310 dma_queue_start (this->debugger, this->program_args == NULL ? "" : this->program_args, this->run_in_terminal, this->stop_at_beginning);
1313 return this->target_uri != NULL;
1316 gboolean
1317 dma_rerun_target (DmaStart *this)
1319 if (this->target_uri == NULL) return FALSE;
1321 dma_start_load_uri (this);
1322 dma_queue_start (this->debugger, this->program_args == NULL ? "" : this->program_args, this->run_in_terminal, this->stop_at_beginning);
1324 return TRUE;
1327 /* Constructor & Destructor
1328 *---------------------------------------------------------------------------*/
1330 DmaStart *
1331 dma_start_new (DebugManagerPlugin *plugin)
1333 DmaStart *self;
1335 self = g_new0 (DmaStart, 1);
1337 self->plugin = ANJUTA_PLUGIN (plugin);
1338 self->debugger = dma_debug_manager_get_queue (plugin);
1339 self->source_dirs = NULL;
1341 g_signal_connect (self->plugin->shell, "save-session",
1342 G_CALLBACK (on_session_save), self);
1343 g_signal_connect (self->plugin->shell, "load-session",
1344 G_CALLBACK (on_session_load), self);
1346 return self;
1349 void
1350 dma_start_free (DmaStart *this)
1352 g_signal_handlers_disconnect_by_func (this->plugin->shell, G_CALLBACK (on_session_save), this);
1353 g_signal_handlers_disconnect_by_func (this->plugin->shell, G_CALLBACK (on_session_load), this);
1354 if (this->source_dirs != NULL)
1356 g_list_foreach (this->source_dirs, (GFunc)g_free, NULL);
1357 g_list_free (this->source_dirs);
1359 if (this->program_args != NULL) g_free (this->program_args);
1360 if (this->target_uri != NULL) g_free (this->target_uri);
1361 g_free (this);