1 /*
2  *      plugin.c
3  *
4  *      Copyright 2010 Alexander Petukhov <devel(at)apetukhov.ru>
5  *
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.
10  *
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.
15  *
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,
19  *      MA 02110-1301, USA.
20  */
21 
22 /*
23  * 		geany debugger plugin
24  */
25 
26 #ifdef HAVE_CONFIG_H
27 	#include "config.h"
28 #endif
29 #include <geanyplugin.h>
30 
31 #include "breakpoints.h"
32 #include "callbacks.h"
33 #include "debug.h"
34 #include "tpage.h"
35 #include "utils.h"
36 #include "btnpanel.h"
37 #include "keys.h"
38 #include "dconfig.h"
39 #include "dpaned.h"
40 #include "tabs.h"
41 #include "envtree.h"
42 #include "pixbuf.h"
43 
44 /* These items are set by Geany before plugin_init() is called. */
45 GeanyPlugin		*geany_plugin;
46 GeanyData			*geany_data;
47 
48 /* vbox for keeping breaks/stack/watch notebook */
49 static GtkWidget *hbox = NULL;
50 
51 static PluginCallback plugin_debugger_callbacks[] =
52 {
53 	/* Set 'after' (third field) to TRUE to run the callback @a after the default handler.
54 	 * If 'after' is FALSE, the callback is run @a before the default handler, so the plugin
55 	 * can prevent Geany from processing the notification. Use this with care. */
56 	{ "editor-notify", (GCallback) &on_editor_notify, FALSE, NULL },
57 	{ "document_open", (GCallback) &on_document_open, FALSE, NULL },
58 	{ "document_save", (GCallback) &on_document_save, FALSE, NULL },
59 	{ "document_before_save", (GCallback) &on_document_before_save, FALSE, NULL },
60 	{ "project_open", (GCallback) &config_on_project_open, FALSE, NULL },
61 	{ "project_close", (GCallback) &config_on_project_close, FALSE, NULL },
62 	{ "project_save", (GCallback) &config_on_project_save, FALSE, NULL },
63 
64 	{ NULL, NULL, FALSE, NULL }
65 };
66 
on_paned_mode_changed(GtkToggleButton * button,gpointer user_data)67 static void on_paned_mode_changed(GtkToggleButton *button, gpointer user_data)
68 {
69 	gboolean state = gtk_toggle_button_get_active(button);
70 	dpaned_set_tabbed(state);
71 	tpage_pack_widgets(state);
72 }
73 
74 /* Called by Geany to initialize the plugin.
75  * Note: data is the same as geany_data. */
plugin_debugger_init(GeanyPlugin * plugin,G_GNUC_UNUSED gpointer pdata)76 static gboolean plugin_debugger_init(GeanyPlugin *plugin, G_GNUC_UNUSED gpointer pdata)
77 {
78 	GtkWidget* vbox;
79 	guint i;
80 
81 	geany_plugin = plugin;
82 	geany_data = plugin->geany_data;
83 
84 	plugin_module_make_resident(geany_plugin);
85 
86 	keys_init();
87 
88 	pixbufs_init();
89 
90 	/* main box */
91 #if GTK_CHECK_VERSION(3, 0, 0)
92 	hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 7);
93 #else
94 	hbox = gtk_hbox_new(FALSE, 7);
95 #endif
96 	gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
97 
98 	/* add target page */
99 	tpage_init();
100 
101 	/* init brekpoints */
102 	breaks_init(editor_open_position);
103 
104 	/* init markers */
105 	markers_init();
106 
107 	/* init debug */
108 	debug_init();
109 
110 	/* load config */
111 	config_init();
112 
113 	/* init paned */
114 	dpaned_init();
115 	tpage_pack_widgets(config_get_tabbed());
116 
117 	vbox = btnpanel_create(on_paned_mode_changed);
118 
119 	gtk_box_pack_start(GTK_BOX(hbox), dpaned_get_paned(), TRUE, TRUE, 0);
120 	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
121 
122 	gtk_widget_show_all(hbox);
123 
124 	gtk_notebook_append_page(
125 		GTK_NOTEBOOK(geany->main_widgets->message_window_notebook),
126 		hbox,
127 		gtk_label_new(_("Debug")));
128 
129 	if (geany_data->app->project)
130 	{
131 		config_update_project_keyfile();
132 	}
133 	config_set_debug_store(
134 		config_get_save_to_project() && geany_data->app->project ? DEBUG_STORE_PROJECT : DEBUG_STORE_PLUGIN
135 	);
136 
137 	/* set calltips for all currently opened documents */
138 	foreach_document(i)
139 	{
140 		scintilla_send_message(document_index(i)->editor->sci, SCI_SETMOUSEDWELLTIME, 500, 0);
141 		scintilla_send_message(document_index(i)->editor->sci, SCI_CALLTIPUSESTYLE, 20, (long)NULL);
142 	}
143 
144 	return TRUE;
145 }
146 
147 /* Called by Geany to show the plugin's configure dialog. This function is always called after
148  * plugin_init() was called.
149  * You can omit this function if the plugin doesn't need to be configured.
150  * Note: parent is the parent window which can be used as the transient window for the created
151  *       dialog. */
plugin_debugger_configure(G_GNUC_UNUSED GeanyPlugin * plugin,GtkDialog * dialog,G_GNUC_UNUSED gpointer pdata)152 static GtkWidget *plugin_debugger_configure(G_GNUC_UNUSED GeanyPlugin *plugin, GtkDialog *dialog, G_GNUC_UNUSED gpointer pdata)
153 {
154 	return config_plugin_configure(dialog);
155 }
156 
157 
158 /* Called by Geany before unloading the plugin.
159  * Here any UI changes should be removed, memory freed and any other finalization done.
160  * Be sure to leave Geany as it was before plugin_init(). */
plugin_debugger_cleanup(G_GNUC_UNUSED GeanyPlugin * plugin,G_GNUC_UNUSED gpointer pdata)161 static void plugin_debugger_cleanup(G_GNUC_UNUSED GeanyPlugin *plugin, G_GNUC_UNUSED gpointer pdata)
162 {
163 	/* stop debugger if running */
164 	if (DBS_IDLE != debug_get_state())
165 	{
166 		debug_stop();
167 		while (DBS_IDLE != debug_get_state())
168 			g_main_context_iteration(NULL,FALSE);
169 	}
170 
171 	config_destroy();
172 	pixbufs_destroy();
173 	debug_destroy();
174 	breaks_destroy();
175 	dpaned_destroy();
176 	envtree_destroy();
177 
178 	/* release other allocated strings and objects */
179 	gtk_widget_destroy(hbox);
180 }
181 
182 
183 /* Show help */
plugin_debugger_help(G_GNUC_UNUSED GeanyPlugin * plugin,G_GNUC_UNUSED gpointer pdata)184 static void plugin_debugger_help (G_GNUC_UNUSED GeanyPlugin *plugin, G_GNUC_UNUSED gpointer pdata)
185 {
186 	utils_open_browser("https://plugins.geany.org/debugger.html");
187 }
188 
189 
190 /* Load module */
191 G_MODULE_EXPORT
geany_load_module(GeanyPlugin * plugin)192 void geany_load_module(GeanyPlugin *plugin)
193 {
194 	/* Setup translation */
195 	main_locale_init(LOCALEDIR, GETTEXT_PACKAGE);
196 
197 	/* Set metadata */
198 	plugin->info->name = _("Debugger");
199 	plugin->info->description = _("Various debuggers integration.");
200 	plugin->info->version = VERSION;
201 	plugin->info->author = "Alexander Petukhov <devel@apetukhov.ru>";
202 
203 	/* Set functions */
204 	plugin->funcs->init = plugin_debugger_init;
205 	plugin->funcs->cleanup = plugin_debugger_cleanup;
206 	plugin->funcs->help = plugin_debugger_help;
207 	plugin->funcs->configure = plugin_debugger_configure;
208 	plugin->funcs->callbacks = plugin_debugger_callbacks;
209 
210 	/* Register! */
211 	GEANY_PLUGIN_REGISTER(plugin, 226);
212 }
213