run-program: Fix a crash when destroying the plugin
[anjuta.git] / plugins / run-program / plugin.c
blob04e70a17de718b501f8d24789247f1a814a74a2e
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 plugin.c
4 Copyright (C) 2008 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 * Plugins functions
24 *---------------------------------------------------------------------------*/
26 #include <config.h>
28 #include "plugin.h"
30 #include "execute.h"
31 #include "parameters.h"
33 #include <libanjuta/anjuta-debug.h>
34 #include <libanjuta/interfaces/ianjuta-project-manager.h>
36 #include <signal.h>
38 /*---------------------------------------------------------------------------*/
40 #define UI_FILE PACKAGE_DATA_DIR"/ui/anjuta-run-program.xml"
42 #define MAX_RECENT_ITEM 10
44 /* Type defintions
45 *---------------------------------------------------------------------------*/
47 struct _RunProgramPluginClass
49 AnjutaPluginClass parent_class;
52 /* Helper functions
53 *---------------------------------------------------------------------------*/
55 static void
56 anjuta_session_set_limited_string_list (AnjutaSession *session, const gchar *section, const gchar *key, GList **value)
58 GList *node;
60 while ((node = g_list_nth (*value, MAX_RECENT_ITEM)) != NULL)
62 g_free (node->data);
63 *value = g_list_delete_link (*value, node);
65 anjuta_session_set_string_list (session, section, key, *value);
68 /* The value argument is a pointer on a GFile list */
69 static void
70 anjuta_session_set_limited_relative_file_list (AnjutaSession *session, const gchar *section, const gchar *key, GList **value)
72 GList *item;
73 GList *list = NULL;
75 while ((item = g_list_nth (*value, MAX_RECENT_ITEM)) != NULL)
77 g_object_unref (G_OBJECT (item->data));
78 *value = g_list_delete_link (*value, item);
80 for (item = *value; item != NULL; item = g_list_next (item))
82 list = g_list_prepend (list, anjuta_session_get_relative_uri_from_file (session, (GFile *)item->data, NULL));
84 list = g_list_reverse (list);
86 anjuta_session_set_string_list (session, section, key, list);
88 g_list_foreach (list, (GFunc)g_free, NULL);
89 g_list_free (list);
92 static void
93 anjuta_session_set_strv (AnjutaSession *session, const gchar *section, const gchar *key, gchar **value)
95 GList *list = NULL;
97 if (value != NULL)
99 for (; *value != NULL; value++)
101 list = g_list_append (list, *value);
103 list = g_list_reverse (list);
106 anjuta_session_set_string_list (session, section, key, list);
107 g_list_free (list);
110 static GList*
111 anjuta_session_get_relative_file_list (AnjutaSession *session, const gchar *section, const gchar *key)
113 GList *list;
114 GList *item;
116 list = anjuta_session_get_string_list (session, section, key);
117 for (item = g_list_first (list); item != NULL; item = g_list_next (item))
119 GFile *file;
121 file = anjuta_session_get_file_from_relative_uri (session, (const gchar *)item->data, NULL);
122 g_free (item->data);
123 item->data = file;
126 return list;
129 static gchar**
130 anjuta_session_get_strv (AnjutaSession *session, const gchar *section, const gchar *key)
132 GList *list;
133 gchar **value = NULL;
135 list = anjuta_session_get_string_list (session, section, key);
137 if (list != NULL)
139 gchar **var;
140 GList *node;
142 value = g_new (gchar *, g_list_length (list) + 1);
143 var = value;
144 for (node = g_list_first (list); node != NULL; node = g_list_next (node))
146 *var = (gchar *)node->data;
147 ++var;
149 *var = NULL;
152 return value;
155 /* Callback for saving session
156 *---------------------------------------------------------------------------*/
158 static void
159 on_session_save (AnjutaShell *shell, AnjutaSessionPhase phase, AnjutaSession *session, RunProgramPlugin *self)
161 if (phase != ANJUTA_SESSION_PHASE_NORMAL)
162 return;
164 anjuta_session_set_limited_string_list (session, "Execution", "Program arguments", &self->recent_args);
165 anjuta_session_set_limited_relative_file_list (session, "Execution", "Program uri", &self->recent_target);
166 anjuta_session_set_int (session, "Execution", "Run in terminal", self->run_in_terminal + 1);
167 anjuta_session_set_limited_relative_file_list (session,"Execution", "Working directories", &self->recent_dirs);
168 anjuta_session_set_strv (session, "Execution", "Environment variables", self->environment_vars);
171 static void on_session_load (AnjutaShell *shell, AnjutaSessionPhase phase, AnjutaSession *session, RunProgramPlugin *self)
173 gint run_in_terminal;
175 if (phase != ANJUTA_SESSION_PHASE_NORMAL)
176 return;
178 if (self->recent_args != NULL)
180 g_list_foreach (self->recent_args, (GFunc)g_free, NULL);
181 g_list_free (self->recent_args);
183 self->recent_args = anjuta_session_get_string_list (session, "Execution", "Program arguments");
185 g_list_foreach (self->recent_target, (GFunc)g_object_unref, NULL);
186 g_list_free (self->recent_target);
187 self->recent_target = anjuta_session_get_relative_file_list (session, "Execution", "Program uri");
189 /* The flag is store as 1 == FALSE, 2 == TRUE */
190 run_in_terminal = anjuta_session_get_int (session, "Execution", "Run in terminal");
191 if (run_in_terminal == 0)
192 self->run_in_terminal = TRUE; /* Default value */
193 else
194 self->run_in_terminal = run_in_terminal - 1;
196 g_list_foreach (self->recent_dirs, (GFunc)g_object_unref, NULL);
197 g_list_free (self->recent_dirs);
198 self->recent_dirs = anjuta_session_get_relative_file_list (session, "Execution", "Working directories");
199 if (self->recent_dirs == NULL)
201 /* Use project directory by default */
202 GValue value = {0,};
204 anjuta_shell_get_value (ANJUTA_PLUGIN(self)->shell,
205 IANJUTA_PROJECT_MANAGER_PROJECT_ROOT_URI,
206 &value,
207 NULL);
208 if (G_VALUE_HOLDS_STRING (&value))
210 self->recent_dirs = g_list_append (NULL, g_file_new_for_uri (g_value_get_string (&value)));
214 g_strfreev (self->environment_vars);
215 self->environment_vars = anjuta_session_get_strv (session, "Execution", "Environment variables");
217 run_plugin_update_shell_value (self);
220 /* Callbacks
221 *---------------------------------------------------------------------------*/
223 static void
224 on_run_program_activate (GtkAction* action, RunProgramPlugin* plugin)
226 if (plugin->child != NULL)
228 gchar *msg = _("The program is already running.\n"
229 "Do you want to stop it before restarting a new instance?");
230 if (anjuta_util_dialog_boolean_question (GTK_WINDOW ( ANJUTA_PLUGIN (plugin)->shell), msg))
232 run_plugin_kill_program (plugin, FALSE);
235 if (plugin->recent_target == NULL)
237 if (run_parameters_dialog_or_execute (plugin) != GTK_RESPONSE_APPLY)
239 return;
243 run_plugin_run_program(plugin);
246 static void
247 on_kill_program_activate (GtkAction* action, RunProgramPlugin* plugin)
249 run_plugin_kill_program (plugin, TRUE);
252 static void
253 on_program_parameters_activate (GtkAction* action, RunProgramPlugin* plugin)
255 /* Run as a modal dialog */
256 run_parameters_dialog_run (plugin);
259 /* Actions table
260 *---------------------------------------------------------------------------*/
262 static GtkActionEntry actions_run[] = {
264 "ActionMenuRun", /* Action name */
265 NULL, /* Stock icon, if any */
266 N_("_Run"), /* Display label */
267 NULL, /* short-cut */
268 NULL, /* Tooltip */
269 NULL /* action callback */
272 "ActionRunProgram",
273 GTK_STOCK_EXECUTE,
274 N_("Execute"),
275 "F3",
276 N_("Run program without debugger"),
277 G_CALLBACK (on_run_program_activate)
280 "ActionStopProgram",
281 GTK_STOCK_STOP,
282 N_("Stop Program"),
283 NULL,
284 N_("Kill program"),
285 G_CALLBACK (on_kill_program_activate)
288 "ActionProgramParameters",
289 NULL,
290 N_("Program Parameters…"),
291 NULL,
292 N_("Set current program, arguments, etc."),
293 G_CALLBACK (on_program_parameters_activate)
297 /* AnjutaPlugin functions
298 *---------------------------------------------------------------------------*/
300 static gboolean
301 run_plugin_activate (AnjutaPlugin *plugin)
303 RunProgramPlugin *self = ANJUTA_PLUGIN_RUN_PROGRAM (plugin);
304 AnjutaUI *ui;
306 DEBUG_PRINT ("%s", "Run Program Plugin: Activating plugin…");
308 /* Connect to session signal */
309 g_signal_connect (plugin->shell, "save-session",
310 G_CALLBACK (on_session_save), self);
311 g_signal_connect (plugin->shell, "load-session",
312 G_CALLBACK (on_session_load), self);
314 /* Add actions */
315 ui = anjuta_shell_get_ui (plugin->shell, NULL);
316 self->action_group = anjuta_ui_add_action_group_entries (ui,
317 "ActionGroupRun", _("Run operations"),
318 actions_run, G_N_ELEMENTS (actions_run),
319 GETTEXT_PACKAGE, TRUE, self);
321 self->uiid = anjuta_ui_merge (ui, UI_FILE);
323 run_plugin_update_menu_sensitivity (self);
325 return TRUE;
328 static gboolean
329 run_plugin_deactivate (AnjutaPlugin *plugin)
331 RunProgramPlugin *self = ANJUTA_PLUGIN_RUN_PROGRAM (plugin);
332 AnjutaUI *ui;
334 DEBUG_PRINT ("%s", "Run Program Plugin: Deactivating plugin…");
336 ui = anjuta_shell_get_ui (plugin->shell, NULL);
337 anjuta_ui_remove_action_group (ui, self->action_group);
339 anjuta_ui_unmerge (ui, self->uiid);
341 g_signal_handlers_disconnect_by_func (plugin->shell, G_CALLBACK (on_session_save), self);
342 g_signal_handlers_disconnect_by_func (plugin->shell, G_CALLBACK (on_session_load), self);
345 return TRUE;
348 /* GObject functions
349 *---------------------------------------------------------------------------*/
351 /* Used in dispose and finalize */
352 static gpointer parent_class;
354 static void
355 run_plugin_instance_init (GObject *obj)
357 RunProgramPlugin *self = ANJUTA_PLUGIN_RUN_PROGRAM (obj);
359 self->recent_target = NULL;
360 self->recent_args = NULL;
361 self->recent_dirs = NULL;
362 self->environment_vars = NULL;
364 self->child = NULL;
366 self->build_uri = NULL;
369 /* dispose is used to unref object created with instance_init */
371 static void
372 run_plugin_dispose (GObject *obj)
374 RunProgramPlugin *plugin = ANJUTA_PLUGIN_RUN_PROGRAM (obj);
376 /* Warning this function could be called several times */
378 run_free_all_children (plugin);
380 G_OBJECT_CLASS (parent_class)->dispose (obj);
383 static void
384 run_plugin_finalize (GObject *obj)
386 RunProgramPlugin *self = ANJUTA_PLUGIN_RUN_PROGRAM (obj);
388 g_list_foreach (self->recent_target, (GFunc)g_object_unref, NULL);
389 g_list_free (self->recent_target);
390 g_list_foreach (self->recent_args, (GFunc)g_free, NULL);
391 g_list_free (self->recent_args);
392 g_list_foreach (self->recent_dirs, (GFunc)g_object_unref, NULL);
393 g_list_free (self->recent_dirs);
394 g_strfreev (self->environment_vars);
396 G_OBJECT_CLASS (parent_class)->finalize (obj);
399 /* finalize used to free object created with instance init is not used */
401 static void
402 run_plugin_class_init (GObjectClass *klass)
404 AnjutaPluginClass *plugin_class = ANJUTA_PLUGIN_CLASS (klass);
406 parent_class = g_type_class_peek_parent (klass);
408 plugin_class->activate = run_plugin_activate;
409 plugin_class->deactivate = run_plugin_deactivate;
410 klass->dispose = run_plugin_dispose;
411 klass->finalize = run_plugin_finalize;
414 /* AnjutaPlugin declaration
415 *---------------------------------------------------------------------------*/
417 ANJUTA_PLUGIN_BEGIN (RunProgramPlugin, run_plugin);
418 ANJUTA_PLUGIN_END;
420 ANJUTA_SIMPLE_PLUGIN (RunProgramPlugin, run_plugin);
422 /* Public functions
423 *---------------------------------------------------------------------------*/
425 void
426 run_plugin_update_shell_value (RunProgramPlugin *plugin)
428 gchar *dir_uri;
429 gchar *target_uri;
431 /* Update Anjuta shell value */
432 target_uri = plugin->recent_target == NULL ? NULL : g_file_get_uri ((GFile *)plugin->recent_target->data);
433 dir_uri = plugin->recent_dirs == NULL ? NULL : g_file_get_uri ((GFile *)plugin->recent_dirs->data);
434 anjuta_shell_add (ANJUTA_PLUGIN (plugin)->shell,
435 RUN_PROGRAM_URI, G_TYPE_STRING, target_uri,
436 RUN_PROGRAM_ARGS, G_TYPE_STRING, plugin->recent_args == NULL ? NULL : plugin->recent_args->data,
437 RUN_PROGRAM_DIR, G_TYPE_STRING, dir_uri,
438 RUN_PROGRAM_ENV, G_TYPE_STRV, plugin->environment_vars == NULL ? NULL : plugin->environment_vars,
439 RUN_PROGRAM_NEED_TERM, G_TYPE_BOOLEAN, plugin->run_in_terminal,
440 NULL);
441 g_free (dir_uri);
442 g_free (target_uri);
445 void
446 run_plugin_update_menu_sensitivity (RunProgramPlugin *plugin)
448 GtkAction *action;
449 action = gtk_action_group_get_action (plugin->action_group, "ActionStopProgram");
451 gtk_action_set_sensitive (action, plugin->child != NULL);