Integrate adding files with the file manager
[anjuta-git-plugin.git] / plugins / debug-manager / start.c
blobe4d01f8eddf18127f33d0cdc2ea72bbb963a5a60
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/interfaces/ianjuta-document-manager.h>
41 #include <libanjuta/interfaces/ianjuta-builder.h>
42 #include <libanjuta/interfaces/ianjuta-file-savable.h>
43 #include <libanjuta/anjuta-utils.h>
45 #include <libgnomevfs/gnome-vfs-mime-utils.h>
46 #include <libgnomevfs/gnome-vfs-utils.h>
48 #include <glade/glade-xml.h>
50 #include <errno.h>
51 #include <sys/stat.h>
52 #include <ctype.h>
53 #include <sys/wait.h>
54 #include <unistd.h>
55 #include <string.h>
57 /* Types
58 *---------------------------------------------------------------------------*/
60 typedef struct _AttachProcess AttachProcess;
61 typedef struct _AddSourceDialog AddSourceDialog;
62 typedef struct _LoadFileCallBack LoadFileCallBack;
64 enum
66 CLEAR_INITIAL,
67 CLEAR_UPDATE,
68 CLEAR_REVIEW,
69 CLEAR_FINAL
72 struct _AttachProcess
74 GtkWidget* dialog;
75 GtkWidget* treeview;
76 gint pid;
78 gboolean hide_paths;
79 gboolean hide_params;
80 gboolean process_tree;
82 gchar* ps_output;
83 GSList* iter_stack;
84 gint iter_stack_level;
85 gint num_spaces_to_skip;
86 gint num_spaces_per_level;
89 enum {
90 PID_COLUMN,
91 USER_COLUMN,
92 START_COLUMN,
93 COMMAND_COLUMN,
94 COLUMNS_NB
97 static char *column_names[COLUMNS_NB] = {
98 N_("Pid"), N_("User"), N_("Time"), N_("Command")
101 enum {
102 VARIABLE_COLUMN,
103 VALUE_COLUMN,
104 VAR_COLUMNS_NB
107 struct _AddSourceDialog
109 GtkTreeView *tree;
110 GtkFileChooser *entry;
111 GtkListStore *model;
114 struct _LoadFileCallBack
116 AnjutaPlugin *plugin;
117 DmaDebuggerQueue *debugger;
120 struct _DmaStart
122 AnjutaPlugin *plugin;
124 DmaDebuggerQueue *debugger;
126 gboolean stop_at_beginning;
127 GList *source_dirs;
129 gchar *build_target;
130 IAnjutaBuilderHandle build_handle;
133 /* Widgets found in glade file
134 *---------------------------------------------------------------------------*/
136 #define ADD_SOURCE_DIALOG "source_paths_dialog"
137 #define SOURCE_ENTRY "src_entry"
138 #define SOURCE_LIST "src_clist"
139 #define ADD_BUTTON "add_button"
140 #define REMOVE_BUTTON "remove_button"
141 #define UP_BUTTON "up_button"
142 #define DOWN_BUTTON "down_button"
144 /* Constants
145 *---------------------------------------------------------------------------*/
147 #define RUN_PROGRAM_URI "run_program_uri"
148 #define RUN_PROGRAM_ARGS "run_program_args"
149 #define RUN_PROGRAM_DIR "run_program_directory"
150 #define RUN_PROGRAM_ENV "run_program_environment"
151 #define RUN_PROGRAM_NEED_TERM "run_program_need_terminal"
153 #define RUN_PROGRAM_ACTION_GROUP "ActionGroupRun"
154 #define RUN_PROGRAM_PARAMETER_ACTION "ActionProgramParameters"
156 static void attach_process_clear (AttachProcess * ap, gint ClearRequest);
158 /* Helper functions
159 *---------------------------------------------------------------------------*/
161 /* This functions get all directories of the current project containing
162 * static or shared library. Perhaps a more reliable way to find these
163 * directories is to really get the directories of all source files */
165 static GList*
166 get_source_directories (AnjutaPlugin *plugin)
168 gchar *cwd;
169 GList *node, *search_dirs = NULL;
170 GList *slibs_dirs = NULL;
171 GList *libs_dirs = NULL;
172 GValue value = {0,};
174 return NULL;
175 cwd = g_get_current_dir();
176 search_dirs = g_list_prepend (search_dirs, gnome_vfs_get_uri_from_local_path(cwd));
177 g_free (cwd);
179 /* Check if a project is already open */
180 anjuta_shell_get_value (plugin->shell, "project_root_uri", &value, NULL);
182 /* Set source file search directories */
183 if (g_value_get_string (&value) != NULL)
185 IAnjutaProjectManager *pm;
186 pm = anjuta_shell_get_interface (plugin->shell,
187 IAnjutaProjectManager, NULL);
188 if (pm)
190 slibs_dirs =
191 ianjuta_project_manager_get_targets (pm,
192 IANJUTA_PROJECT_MANAGER_TARGET_SHAREDLIB,
193 NULL);
194 libs_dirs =
195 ianjuta_project_manager_get_targets (pm,
196 IANJUTA_PROJECT_MANAGER_TARGET_STATICLIB,
197 NULL);
200 slibs_dirs = g_list_reverse (slibs_dirs);
201 libs_dirs = g_list_reverse (libs_dirs);
203 node = slibs_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 node = libs_dirs;
213 while (node)
215 gchar *dir_uri;
216 dir_uri = g_path_get_dirname (node->data);
217 search_dirs = g_list_prepend (search_dirs, dir_uri);
218 node = g_list_next (node);
221 g_list_foreach (slibs_dirs, (GFunc)g_free, NULL);
222 g_list_free (slibs_dirs);
223 g_list_foreach (libs_dirs, (GFunc)g_free, NULL);
224 g_list_free (libs_dirs);
226 return g_list_reverse (search_dirs);
229 static void
230 free_source_directories (GList *dirs)
232 g_list_foreach (dirs, (GFunc)g_free, NULL);
233 g_list_free (dirs);
236 /* Callback for saving session
237 *---------------------------------------------------------------------------*/
239 static void
240 on_session_save (AnjutaShell *shell, AnjutaSessionPhase phase, AnjutaSession *session, DmaStart *self)
242 if (phase != ANJUTA_SESSION_PHASE_NORMAL)
243 return;
245 anjuta_session_set_string_list (session, "Debugger", "Source directories", self->source_dirs);
246 anjuta_session_set_int (session, "Debugger", "Stop at beginning", self->stop_at_beginning + 1);
249 static void on_session_load (AnjutaShell *shell, AnjutaSessionPhase phase, AnjutaSession *session, DmaStart *self)
251 gint stop_at_beginning;
253 if (phase != ANJUTA_SESSION_PHASE_NORMAL)
254 return;
256 /* Initialize source_dirs */
257 if (self->source_dirs != NULL)
259 g_list_foreach (self->source_dirs, (GFunc)g_free, NULL);
260 g_list_free (self->source_dirs);
262 self->source_dirs = anjuta_session_get_string_list (session, "Debugger", "Source directories");
264 stop_at_beginning = anjuta_session_get_int (session, "Debugger", "Stop at beginning");
265 if (stop_at_beginning == 0)
266 self->stop_at_beginning = TRUE; /* Default value */
267 else
268 self->stop_at_beginning = stop_at_beginning - 1;
271 /* Attach to process private functions
272 *---------------------------------------------------------------------------*/
274 static AttachProcess *
275 attach_process_new ()
277 AttachProcess *ap;
278 ap = g_new0 (AttachProcess, 1);
279 attach_process_clear (ap, CLEAR_INITIAL);
280 return ap;
283 static void
284 attach_process_clear (AttachProcess * ap, gint ClearRequest)
286 GtkTreeModel *model;
288 // latest ps output
289 switch (ClearRequest)
291 case CLEAR_UPDATE:
292 case CLEAR_FINAL:
293 if (ap->ps_output)
295 g_free (ap->ps_output);
297 case CLEAR_INITIAL:
298 ap->ps_output = NULL;
301 // helper variables
302 switch (ClearRequest)
304 case CLEAR_INITIAL:
305 case CLEAR_UPDATE:
306 case CLEAR_REVIEW:
307 ap->pid = -1L;
308 ap->iter_stack = NULL;
309 ap->iter_stack_level = -1;
310 ap->num_spaces_to_skip = -1;
313 // tree model
314 switch (ClearRequest)
316 case CLEAR_UPDATE:
317 case CLEAR_REVIEW:
318 case CLEAR_FINAL:
319 model = gtk_tree_view_get_model (GTK_TREE_VIEW (ap->treeview));
320 gtk_tree_store_clear (GTK_TREE_STORE (model));
323 // dialog widget
324 if (ClearRequest == CLEAR_FINAL)
326 gtk_widget_destroy (ap->dialog);
327 ap->dialog = NULL;
331 static inline gchar *
332 skip_spaces (gchar *pos)
334 while (*pos == ' ')
335 pos++;
336 return pos;
339 static inline gchar *
340 skip_token (gchar *pos)
342 while (*pos != ' ')
343 pos++;
344 *pos++ = '\0';
345 return pos;
348 static gchar *
349 skip_token_and_spaces (gchar *pos)
351 pos = skip_token (pos);
352 return skip_spaces (pos);
355 static GtkTreeIter *
356 iter_stack_push_new (AttachProcess *ap, GtkTreeStore *store)
358 GtkTreeIter *new_iter, *top_iter;
359 new_iter = g_new (GtkTreeIter, 1);
360 top_iter = (GtkTreeIter *) (g_slist_nth_data (ap->iter_stack, 0));
361 ap->iter_stack =
362 g_slist_prepend (ap->iter_stack, (gpointer) (new_iter));
363 gtk_tree_store_append (store, new_iter, top_iter);
364 ap->iter_stack_level++;
365 return new_iter;
368 static gboolean
369 iter_stack_pop (AttachProcess *ap)
371 if (ap->iter_stack_level < 0)
372 return FALSE;
374 GtkTreeIter *iter =
375 (GtkTreeIter *) (g_slist_nth_data (ap->iter_stack, 0));
376 ap->iter_stack =
377 g_slist_delete_link (ap->iter_stack, ap->iter_stack);
378 g_free (iter);
379 ap->iter_stack_level--;
380 return TRUE;
383 static void
384 iter_stack_clear (AttachProcess *ap)
386 while (iter_stack_pop (ap));
389 static gchar *
390 calc_depth_and_get_iter (AttachProcess *ap, GtkTreeStore *store,
391 GtkTreeIter **iter, gchar *pos)
393 gchar *orig_pos;
394 guint num_spaces, depth, i;
396 // count spaces
397 orig_pos = pos;
398 while (*pos == ' ')
399 pos++;
400 num_spaces = pos - orig_pos;
402 if (ap->process_tree)
404 if (ap->num_spaces_to_skip < 0)
406 // first process to be inserted
407 ap->num_spaces_to_skip = num_spaces;
408 ap->num_spaces_per_level = -1;
409 *iter = iter_stack_push_new (ap, store);
411 else
413 if (ap->num_spaces_per_level < 0)
415 if (num_spaces == ap->num_spaces_to_skip)
417 // num_spaces_per_level still unknown
418 iter_stack_pop (ap);
419 *iter = iter_stack_push_new (ap, store);
421 else
423 // first time at level 1
424 ap->num_spaces_per_level =
425 num_spaces - ap->num_spaces_to_skip;
426 *iter = iter_stack_push_new (ap, store);
429 else
431 depth = (num_spaces - ap->num_spaces_to_skip) /
432 ap->num_spaces_per_level;
433 if (depth == ap->iter_stack_level)
435 // level not changed
436 iter_stack_pop (ap);
437 *iter = iter_stack_push_new (ap, store);
439 else
440 if (depth == ap->iter_stack_level + 1)
441 *iter = iter_stack_push_new (ap, store);
442 else
443 if (depth < ap->iter_stack_level)
445 // jump some levels backward
446 depth = ap->iter_stack_level - depth;
447 for (i = 0; i <= depth; i++)
448 iter_stack_pop (ap);
449 *iter = iter_stack_push_new (ap, store);
451 else
453 // should never get here
454 g_warning("Unknown error");
455 iter_stack_pop (ap);
456 *iter = iter_stack_push_new (ap, store);
461 else
463 iter_stack_pop (ap);
464 *iter = iter_stack_push_new (ap, store);
467 return pos;
470 static gchar *
471 skip_path (gchar *pos)
473 /* can't use g_path_get_basename() - wouldn't work for a processes
474 started with parameters containing '/' */
475 gchar c, *final_pos = pos;
477 if (*pos == G_DIR_SEPARATOR)
480 c = *pos;
481 if (c == G_DIR_SEPARATOR)
483 final_pos = ++pos;
484 continue;
486 else
487 if (c == ' ' || c == '\0')
488 break;
489 else
490 ++pos;
492 while (1);
494 return final_pos;
497 static inline void
498 remove_params (gchar *pos)
502 if (*(++pos) == ' ')
503 *pos = '\0';
505 while (*pos);
508 static void
509 attach_process_add_line (AttachProcess *ap, GtkTreeStore *store, gchar *line)
511 gchar *pid, *user, *start, *command, *tmp;
512 // guint i, level;
513 GtkTreeIter *iter;
515 pid = skip_spaces (line); // skip leading spaces
516 user = skip_token_and_spaces (pid); // skip PID
517 start = skip_token_and_spaces (user); // skip USER
518 tmp = skip_token (start); // skip START (do not skip spaces)
520 command = calc_depth_and_get_iter (ap, store, &iter, tmp);
522 if (ap->hide_paths)
524 command = skip_path (command);
527 if (ap->hide_params)
529 remove_params(command);
532 gtk_tree_store_set (store, iter,
533 PID_COLUMN, pid,
534 USER_COLUMN, user,
535 START_COLUMN, start,
536 COMMAND_COLUMN, command,
537 -1);
540 static void
541 attach_process_review (AttachProcess *ap)
543 gchar *ps_output, *begin, *end;
544 guint line_num = 0;
545 GtkTreeStore *store;
547 g_return_if_fail (ap);
548 g_return_if_fail (ap->ps_output);
549 store = GTK_TREE_STORE (gtk_tree_view_get_model
550 (GTK_TREE_VIEW (ap->treeview)));
551 g_return_if_fail (store);
553 ps_output = g_strdup (ap->ps_output);
554 end = ps_output;
555 while (*end)
557 begin = end;
558 while (*end && *end != '\n') end++;
559 if (++line_num > 2) // skip description line & process 'init'
561 *end = '\0';
562 attach_process_add_line (ap, store, begin);
564 end++;
566 g_free (ps_output);
568 iter_stack_clear (ap);
569 gtk_tree_view_expand_all (GTK_TREE_VIEW (ap->treeview));
572 static void
573 attach_process_update (AttachProcess * ap)
575 gchar *tmp, *tmp1, *cmd;
576 gint ch_pid;
577 gchar *shell;
578 GtkTreeStore *store;
579 gboolean result;
581 g_return_if_fail (ap);
582 store = GTK_TREE_STORE (gtk_tree_view_get_model
583 (GTK_TREE_VIEW (ap->treeview)));
584 g_return_if_fail (store);
586 if (anjuta_util_prog_is_installed ("ps", TRUE) == FALSE)
587 return;
589 tmp = anjuta_util_get_a_tmp_file ();
590 #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
591 cmd = g_strconcat ("ps axw -o pid,user,lstart,args > ", tmp, NULL);
592 #else
593 cmd = g_strconcat ("ps axw -H -o pid,user,start_time,args > ", tmp, NULL);
594 #endif
595 shell = anjuta_util_user_shell ();
596 ch_pid = fork ();
597 if (ch_pid == 0)
599 execlp (shell, shell, "-c", cmd, NULL);
601 if (ch_pid < 0)
603 anjuta_util_dialog_error_system (NULL, errno,
604 _("Unable to execute: %s."), cmd);
605 g_free (tmp);
606 g_free (cmd);
607 return;
609 waitpid (ch_pid, NULL, 0);
610 g_free (cmd);
612 result = g_file_get_contents (tmp, &tmp1, NULL, NULL);
613 remove (tmp);
614 g_free (tmp);
615 if (! result)
617 anjuta_util_dialog_error_system (NULL, errno,
618 _("Unable to open the file: %s\n"),
619 tmp);
620 return;
623 attach_process_clear (ap, CLEAR_UPDATE);
624 ap->ps_output = anjuta_util_convert_to_utf8 (tmp1);
625 g_free (tmp1);
626 if (ap->ps_output)
628 attach_process_review (ap);
632 static void
633 on_selection_changed (GtkTreeSelection *selection, AttachProcess *ap)
635 GtkTreeModel *model;
636 GtkTreeIter iter;
638 g_return_if_fail (ap);
639 if (gtk_tree_selection_get_selected (selection, &model, &iter))
641 gchar* text;
642 gtk_tree_model_get (model, &iter, PID_COLUMN, &text, -1);
643 ap->pid = atoi (text);
644 gtk_dialog_set_response_sensitive (GTK_DIALOG (ap->dialog),
645 GTK_RESPONSE_OK, TRUE);
647 else
649 gtk_dialog_set_response_sensitive (GTK_DIALOG (ap->dialog),
650 GTK_RESPONSE_OK, FALSE);
651 ap->pid = -1L;
655 static gboolean
656 on_delete_event (GtkWidget *dialog, GdkEvent *event, AttachProcess *ap)
658 g_return_val_if_fail (ap, FALSE);
659 attach_process_clear (ap, CLEAR_FINAL);
660 return FALSE;
663 static gint
664 sort_pid (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
665 gpointer user_data)
667 gchar *nptr;
668 gint pid1, pid2;
670 gtk_tree_model_get (model, a, PID_COLUMN, &nptr, -1);
671 pid1 = atoi (nptr);
673 gtk_tree_model_get (model, b, PID_COLUMN, &nptr, -1);
674 pid2 = atoi (nptr);
676 return pid1 - pid2;
679 static void
680 on_toggle_hide_paths (GtkToggleButton *togglebutton, AttachProcess * ap)
682 ap->hide_paths = gtk_toggle_button_get_active (togglebutton);
683 attach_process_clear (ap, CLEAR_REVIEW);
684 attach_process_review (ap);
687 static void
688 on_toggle_hide_params (GtkToggleButton *togglebutton, AttachProcess * ap)
690 ap->hide_params = gtk_toggle_button_get_active (togglebutton);
691 attach_process_clear (ap, CLEAR_REVIEW);
692 attach_process_review (ap);
695 static void
696 on_toggle_process_tree (GtkToggleButton *togglebutton, AttachProcess * ap)
698 ap->process_tree = gtk_toggle_button_get_active (togglebutton);
699 attach_process_clear (ap, CLEAR_REVIEW);
700 attach_process_review (ap);
703 static pid_t
704 attach_process_show (AttachProcess * ap, GtkWindow *parent)
706 GladeXML *gxml;
707 GtkTreeView *view;
708 GtkTreeStore *store;
709 GtkCellRenderer *renderer;
710 GtkTreeSelection *selection;
711 GtkCheckButton *checkb_hide_paths;
712 GtkCheckButton *checkb_hide_params;
713 GtkCheckButton *checkb_process_tree;
714 gint i, res;
715 pid_t selected_pid = -1;
717 g_return_val_if_fail (ap != NULL, -1);
719 if (!ap->dialog)
721 gxml = glade_xml_new (GLADE_FILE, "attach_process_dialog", NULL);
722 ap->dialog = glade_xml_get_widget (gxml, "attach_process_dialog");
723 ap->treeview = glade_xml_get_widget (gxml, "attach_process_tv");
724 checkb_hide_paths = GTK_CHECK_BUTTON (
725 glade_xml_get_widget (gxml, "checkb_hide_paths"));
726 checkb_hide_params = GTK_CHECK_BUTTON (
727 glade_xml_get_widget (gxml, "checkb_hide_params"));
728 checkb_process_tree = GTK_CHECK_BUTTON (
729 glade_xml_get_widget (gxml, "checkb_process_tree"));
730 g_object_unref (gxml);
732 view = GTK_TREE_VIEW (ap->treeview);
733 store = gtk_tree_store_new (COLUMNS_NB,
734 G_TYPE_STRING,
735 G_TYPE_STRING,
736 G_TYPE_STRING,
737 G_TYPE_STRING);
738 gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
739 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (view),
740 GTK_SELECTION_SINGLE);
741 g_object_unref (G_OBJECT (store));
743 renderer = gtk_cell_renderer_text_new ();
745 for (i = PID_COLUMN; i < COLUMNS_NB; i++) {
746 GtkTreeViewColumn *column;
748 column = gtk_tree_view_column_new_with_attributes (column_names[i],
749 renderer, "text", i, NULL);
750 gtk_tree_view_column_set_sort_column_id(column, i);
751 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
752 gtk_tree_view_append_column (view, column);
753 if (i == COMMAND_COLUMN)
754 gtk_tree_view_set_expander_column(view, column);
756 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store), PID_COLUMN,
757 sort_pid, NULL, NULL);
758 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
759 START_COLUMN, GTK_SORT_DESCENDING);
761 ap->hide_paths = gtk_toggle_button_get_active (
762 GTK_TOGGLE_BUTTON (checkb_hide_paths));
763 ap->hide_params = gtk_toggle_button_get_active (
764 GTK_TOGGLE_BUTTON (checkb_hide_params));
765 ap->process_tree = gtk_toggle_button_get_active (
766 GTK_TOGGLE_BUTTON (checkb_process_tree));
768 attach_process_update (ap);
770 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ap->treeview));
771 g_signal_connect (G_OBJECT (selection), "changed",
772 G_CALLBACK (on_selection_changed), ap);
773 g_signal_connect (G_OBJECT (ap->dialog), "delete_event",
774 G_CALLBACK (on_delete_event), ap);
775 g_signal_connect (GTK_OBJECT (checkb_hide_paths), "toggled",
776 G_CALLBACK (on_toggle_hide_paths), ap);
777 g_signal_connect (GTK_OBJECT (checkb_hide_params), "toggled",
778 G_CALLBACK (on_toggle_hide_params), ap);
779 g_signal_connect (GTK_OBJECT (checkb_process_tree), "toggled",
780 G_CALLBACK (on_toggle_process_tree), ap);
783 gtk_window_set_transient_for (GTK_WINDOW (ap->dialog),
784 GTK_WINDOW (parent));
785 /* gtk_widget_show (ap->dialog); */
786 res = gtk_dialog_run (GTK_DIALOG (ap->dialog));
787 while (res == GTK_RESPONSE_APPLY)
789 attach_process_update (ap);
790 res = gtk_dialog_run (GTK_DIALOG (ap->dialog));
792 if (res == GTK_RESPONSE_OK)
794 selected_pid = ap->pid;
796 attach_process_clear (ap, CLEAR_FINAL);
797 return selected_pid;
800 static void
801 attach_process_destroy (AttachProcess * ap)
803 g_return_if_fail (ap);
804 g_free (ap);
807 /* Load file private functions
808 *---------------------------------------------------------------------------*/
810 static void
811 show_parameters_dialog (DmaStart *this)
813 AnjutaUI *ui;
814 GtkAction *action;
816 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN (this->plugin)->shell, NULL);
817 action = anjuta_ui_get_action (ui, RUN_PROGRAM_ACTION_GROUP, RUN_PROGRAM_PARAMETER_ACTION);
818 if (action != NULL)
820 gtk_action_activate (action);
824 static gboolean
825 start_target (DmaStart *this)
827 gchar *dir_uri;
828 gchar *dir;
829 gchar **env;
830 gchar *args;
831 gboolean run_in_terminal;
833 anjuta_shell_get (ANJUTA_PLUGIN (this->plugin)->shell,
834 RUN_PROGRAM_DIR, G_TYPE_STRING, &dir_uri,
835 RUN_PROGRAM_ARGS, G_TYPE_STRING, &args,
836 RUN_PROGRAM_ENV, G_TYPE_STRV, &env,
837 RUN_PROGRAM_NEED_TERM, G_TYPE_BOOLEAN, &run_in_terminal,
838 NULL);
840 if (dir_uri != NULL)
842 dir = gnome_vfs_get_local_path_from_uri (dir_uri);
843 g_free (dir_uri);
845 else
847 dir = NULL;
850 dma_queue_set_working_directory (this->debugger, dir);
851 g_free (dir);
853 dma_queue_set_environment (this->debugger, env);
854 g_strfreev (env);
856 dma_queue_start (this->debugger, args, run_in_terminal, FALSE);
857 g_free (args);
859 return TRUE;
863 static gboolean
864 load_target (DmaStart *this, const gchar *target)
866 gchar *mime_type;
867 gchar *filename;
869 mime_type = gnome_vfs_get_mime_type ((const gchar *)target);
870 if (mime_type == NULL)
872 anjuta_util_dialog_error(GTK_WINDOW (this->plugin->shell),
873 _("Unable to open %s. Debugger cannot start."), target);
874 return FALSE;
876 filename = gnome_vfs_get_local_path_from_uri (target);
878 dma_queue_load (this->debugger, filename, mime_type, this->source_dirs);
880 g_free (filename);
881 g_free (mime_type);
883 return start_target (this);
886 static void
887 on_build_finished (GObject *builder, IAnjutaBuilderHandle handle, GError *err, gpointer user_data)
889 DmaStart *this = (DmaStart *)user_data;
891 if (err == NULL)
893 /* Up to date, start debugger */
894 load_target (this, this->build_target);
897 g_free (this->build_target);
898 this->build_target = NULL;
901 static void
902 on_is_built_finished (GObject *builder, IAnjutaBuilderHandle handle, GError *err, gpointer user_data)
904 DmaStart *this = (DmaStart *)user_data;
906 if (err == NULL)
908 /* Up to date, start debugger */
909 load_target (this, this->build_target);
911 else if (err->code == IANJUTA_BUILDER_FAILED)
913 /* Target is not up to date */
914 this->build_handle = ianjuta_builder_build (IANJUTA_BUILDER (builder), this->build_target, on_build_finished, this, NULL);
915 return;
918 g_free (this->build_target);
919 this->build_target = NULL;
922 static gboolean
923 check_target (DmaStart *this, const gchar *target)
925 IAnjutaBuilder *builder;
927 builder = anjuta_shell_get_interface (this->plugin->shell, IAnjutaBuilder, NULL);
928 if (builder != NULL)
930 if (this->build_target)
932 /* a build operation is currently running */
933 if (strcmp (this->build_target, target) == 0)
935 /* It is the same one, just ignore */
936 return TRUE;
938 else
940 /* Cancel old operation */
941 ianjuta_builder_cancel (builder, this->build_handle, NULL);
945 this->build_target = g_strdup (target);
947 /* Check if target is up to date */
948 this->build_handle = ianjuta_builder_is_built (builder, target, on_is_built_finished, this, NULL);
949 return this->build_handle != 0;
951 else
953 /* Unable to build target, just launch debugger */
954 return load_target (this, target);
958 static gboolean
959 dma_start_load_and_start_uri (DmaStart *this, const gchar *target)
961 GnomeVFSURI *vfs_uri;
963 if (!dma_quit_debugger (this)) return FALSE;
965 vfs_uri = gnome_vfs_uri_new (target);
966 g_return_val_if_fail (vfs_uri != NULL, TRUE);
967 if (!gnome_vfs_uri_is_local (vfs_uri)) return FALSE;
968 gnome_vfs_uri_unref (vfs_uri);
970 return check_target (this, target);
973 /* Add source dialog
974 *---------------------------------------------------------------------------*/
976 static void
977 on_add_uri_in_model (gpointer data, gpointer user_data)
979 GtkListStore* model = (GtkListStore *)user_data;
980 GtkTreeIter iter;
981 gchar *local;
983 local = gnome_vfs_get_local_path_from_uri ((const char *)data);
984 gtk_list_store_append (model, &iter);
985 gtk_list_store_set (model, &iter, 0, local, -1);
986 g_free (local);
989 static gboolean
990 on_add_source_in_list (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
992 GList** list = (GList **)user_data;
993 gchar* dir;
994 gchar* uri;
996 gtk_tree_model_get (model, iter, 0, &dir, -1);
997 uri = gnome_vfs_get_uri_from_local_path (dir);
998 *list = g_list_prepend (*list, uri);
999 g_free (dir);
1001 return FALSE;
1004 static void
1005 on_source_add_button (GtkButton *button, AddSourceDialog *dlg)
1007 GtkTreeIter iter;
1008 const gchar *path;
1010 path = gtk_file_chooser_get_filename (dlg->entry);
1011 if ((path != NULL) && (*path != '\0'))
1013 gtk_list_store_append (dlg->model, &iter);
1014 gtk_list_store_set (dlg->model, &iter, 0, path, -1);
1018 static void
1019 on_source_remove_button (GtkButton *button, AddSourceDialog *dlg)
1021 GtkTreeIter iter;
1022 GtkTreeSelection* sel;
1024 sel = gtk_tree_view_get_selection (dlg->tree);
1025 if (gtk_tree_selection_get_selected (sel, NULL, &iter))
1027 gtk_list_store_remove (dlg->model, &iter);
1031 static void
1032 on_source_up_button (GtkButton *button, AddSourceDialog *dlg)
1034 GtkTreeIter iter;
1035 GtkTreeSelection* sel;
1037 sel = gtk_tree_view_get_selection (dlg->tree);
1038 if (gtk_tree_selection_get_selected (sel, NULL, &iter))
1040 GtkTreePath *path;
1042 path = gtk_tree_model_get_path(GTK_TREE_MODEL (dlg->model), &iter);
1043 if (gtk_tree_path_prev(path))
1045 GtkTreeIter pos;
1047 gtk_tree_model_get_iter(GTK_TREE_MODEL (dlg->model), &pos, path);
1048 gtk_list_store_move_before (dlg->model, &iter, &pos);
1053 static void
1054 on_source_down_button (GtkButton *button, AddSourceDialog *dlg)
1056 GtkTreeIter iter;
1057 GtkTreeSelection* sel;
1059 sel = gtk_tree_view_get_selection (dlg->tree);
1060 if (gtk_tree_selection_get_selected (sel, NULL, &iter))
1062 GtkTreeIter pos = iter;
1064 if (gtk_tree_model_iter_next (GTK_TREE_MODEL (dlg->model), &pos))
1066 gtk_list_store_move_after (dlg->model, &iter, &pos);
1071 static void
1072 add_source_show (DmaStart *this)
1074 AddSourceDialog dlg;
1075 GladeXML *gxml;
1076 GtkWidget *widget;
1077 GtkWindow *parent;
1078 GtkCellRenderer *renderer;
1079 GtkTreeViewColumn *column;
1080 GObject *button;
1082 parent = GTK_WINDOW (this->plugin->shell);
1083 gxml = glade_xml_new (GLADE_FILE, ADD_SOURCE_DIALOG, NULL);
1084 if (gxml == NULL)
1086 anjuta_util_dialog_error(parent, _("Missing file %s"), GLADE_FILE);
1087 return;
1090 widget = glade_xml_get_widget (gxml, ADD_SOURCE_DIALOG);
1091 dlg.tree = GTK_TREE_VIEW (glade_xml_get_widget (gxml, SOURCE_LIST));
1092 dlg.entry = GTK_FILE_CHOOSER (glade_xml_get_widget (gxml, SOURCE_ENTRY));
1094 /* Connect signals */
1095 button = G_OBJECT (glade_xml_get_widget (gxml, ADD_BUTTON));
1096 g_signal_connect (button, "clicked", G_CALLBACK (on_source_add_button), &dlg);
1097 button = G_OBJECT (glade_xml_get_widget (gxml, REMOVE_BUTTON));
1098 g_signal_connect (button, "clicked", G_CALLBACK (on_source_remove_button), &dlg);
1099 button = G_OBJECT (glade_xml_get_widget (gxml, UP_BUTTON));
1100 g_signal_connect (button, "clicked", G_CALLBACK (on_source_up_button), &dlg);
1101 button = G_OBJECT (glade_xml_get_widget (gxml, DOWN_BUTTON));
1102 g_signal_connect (button, "clicked", G_CALLBACK (on_source_down_button), &dlg);
1104 g_object_unref (gxml);
1106 renderer = gtk_cell_renderer_text_new ();
1107 column = gtk_tree_view_column_new_with_attributes (_("Path"), renderer, "text", 0, NULL);
1108 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1109 gtk_tree_view_append_column (dlg.tree, column);
1110 gtk_tree_view_set_expander_column(dlg.tree, column);
1112 dlg.model = gtk_list_store_new (1, GTK_TYPE_STRING);
1113 gtk_tree_view_set_model (dlg.tree, GTK_TREE_MODEL (dlg.model));
1115 gtk_window_set_transient_for (GTK_WINDOW (widget), parent);
1117 /* Initialize source path list */
1118 g_list_foreach (this->source_dirs, on_add_uri_in_model, dlg.model);
1120 /* Run dialog */
1121 for (;;)
1123 gint response = gtk_dialog_run (GTK_DIALOG (widget));
1125 switch (response)
1127 case GTK_RESPONSE_DELETE_EVENT:
1128 case GTK_RESPONSE_CLOSE:
1129 g_list_foreach (this->source_dirs, (GFunc)g_free, NULL);
1130 g_list_free (this->source_dirs);
1131 this->source_dirs = NULL;
1132 gtk_tree_model_foreach (GTK_TREE_MODEL (dlg.model), on_add_source_in_list, &this->source_dirs);
1133 this->source_dirs = g_list_reverse (this->source_dirs);
1134 break;
1135 case GTK_RESPONSE_CANCEL:
1136 gtk_list_store_clear (dlg.model);
1137 g_list_foreach (this->source_dirs, on_add_uri_in_model, dlg.model);
1138 continue;
1139 default:
1140 break;
1142 break;
1144 gtk_widget_destroy (widget);
1147 /* Public functions
1148 *---------------------------------------------------------------------------*/
1150 gboolean
1151 dma_quit_debugger (DmaStart* this)
1153 if (dma_debugger_queue_get_state (this->debugger) > IANJUTA_DEBUGGER_PROGRAM_LOADED)
1155 gchar *msg = _("The program is running.\n"
1156 "Do you still want to stop the debugger?");
1158 if (!anjuta_util_dialog_boolean_question (GTK_WINDOW (this->plugin->shell), msg)) return FALSE;
1161 dma_queue_interrupt (this->debugger);
1162 dma_queue_quit (this->debugger);
1164 return TRUE;
1167 void
1168 dma_add_source_path (DmaStart *self)
1170 add_source_show (self);
1173 void
1174 dma_attach_to_process (DmaStart* this)
1176 pid_t selected_pid;
1177 GtkWindow *parent;
1178 AttachProcess *attach_process = NULL;
1180 if (!dma_quit_debugger (this)) return;
1182 parent = GTK_WINDOW (ANJUTA_PLUGIN (this->plugin)->shell);
1183 attach_process = attach_process_new();
1185 selected_pid = attach_process_show (attach_process, parent);
1186 if (selected_pid > 0)
1188 long lpid = selected_pid;
1189 GList *search_dirs;
1191 search_dirs = get_source_directories (this->plugin);
1193 dma_queue_attach (this->debugger, lpid, this->source_dirs);
1194 free_source_directories (search_dirs);
1196 attach_process_destroy(attach_process);
1199 gboolean
1200 dma_run_target (DmaStart *this)
1202 gchar *target;
1204 anjuta_shell_get (ANJUTA_PLUGIN (this->plugin)->shell,
1205 RUN_PROGRAM_URI, G_TYPE_STRING, &target, NULL);
1207 if (target == NULL)
1209 /* Launch parameter dialog to get a target name */
1210 show_parameters_dialog (this);
1211 anjuta_shell_get (ANJUTA_PLUGIN (this->plugin)->shell,
1212 RUN_PROGRAM_URI, G_TYPE_STRING, &target, NULL);
1213 /* No target set by user */
1214 if (target == NULL) return FALSE;
1217 if (!dma_start_load_and_start_uri (this, target)) return FALSE;
1218 g_free (target);
1220 return TRUE;
1223 /* Constructor & Destructor
1224 *---------------------------------------------------------------------------*/
1226 DmaStart *
1227 dma_start_new (DebugManagerPlugin *plugin)
1229 DmaStart *self;
1231 self = g_new0 (DmaStart, 1);
1233 self->plugin = ANJUTA_PLUGIN (plugin);
1234 self->debugger = dma_debug_manager_get_queue (plugin);
1235 self->source_dirs = NULL;
1236 self->build_target = NULL;
1238 g_signal_connect (self->plugin->shell, "save-session",
1239 G_CALLBACK (on_session_save), self);
1240 g_signal_connect (self->plugin->shell, "load-session",
1241 G_CALLBACK (on_session_load), self);
1243 return self;
1246 void
1247 dma_start_free (DmaStart *this)
1249 g_signal_handlers_disconnect_by_func (this->plugin->shell, G_CALLBACK (on_session_save), this);
1250 g_signal_handlers_disconnect_by_func (this->plugin->shell, G_CALLBACK (on_session_load), this);
1251 g_list_foreach (this->source_dirs, (GFunc)g_free, NULL);
1252 g_list_free (this->source_dirs);
1253 g_free (this);