1 /*
2 * scope.c
3 *
4 * Copyright 2012 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
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, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include <stdlib.h>
25
26 #include "common.h"
27
28 #include <gp_gtkcompat.h>
29
30 GeanyPlugin *geany_plugin;
31 GeanyData *geany_data;
32
33 PLUGIN_VERSION_CHECK(224)
34
35 PLUGIN_SET_TRANSLATABLE_INFO(LOCALEDIR, GETTEXT_PACKAGE, _("Scope Debugger"),
36 _("Relatively simple GDB front-end."), "0.94",
37 "Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>, LarsGit223")
38
39 /* Keybinding(s) */
40 enum
41 { /* Note: must match debug_menu_keys/items */
42 SET_PROGRAM_KB,
43 RUN_CONTINUE_KB,
44 GOTO_CURSOR_KB,
45 GOTO_SOURCE_KB,
46 STEP_INTO_KB,
47 STEP_OVER_KB,
48 STEP_OUT_KB,
49 TERMINATE_KB,
50 BREAKPOINT_KB,
51 GDB_COMMAND_KB,
52 #ifdef G_OS_UNIX
53 SHOW_TERMINAL_KB,
54 #endif
55 EVALUATE_KB,
56 WATCH_KB,
57 INSPECT_KB,
58 COUNT_KB
59 };
60
61 static MenuKey debug_menu_keys[EVALUATE_KB] =
62 {
63 { "setup_program", N_("Setup program") },
64 { "run_continue", N_("Run/continue") },
65 { "goto_cursor", N_("Run to cursor") },
66 { "goto_source", N_("Run to source") },
67 { "step_into", N_("Step into") },
68 { "step_over", N_("Step over") },
69 { "step_out", N_("Step out") },
70 { "terminate", N_("Terminate") },
71 { "breakpoint", N_("Toggle breakpoint") },
72 #ifdef G_OS_UNIX
73 { "gdb_command", N_("GDB command") },
74 { "show_terminal", N_("Show terminal") }
75 #else
76 { "gdb_command", N_("GDB command") }
77 #endif
78 };
79
on_scope_gdb_command(G_GNUC_UNUSED const MenuItem * menu_item)80 static void on_scope_gdb_command(G_GNUC_UNUSED const MenuItem *menu_item)
81 {
82 view_command_line(NULL, NULL, NULL, FALSE);
83 }
84
on_scope_reset_markers(G_GNUC_UNUSED const MenuItem * menu_item)85 static void on_scope_reset_markers(G_GNUC_UNUSED const MenuItem *menu_item)
86 {
87 utils_remark(document_get_current());
88 }
89
on_scope_cleanup_files(G_GNUC_UNUSED const MenuItem * menu_item)90 static void on_scope_cleanup_files(G_GNUC_UNUSED const MenuItem *menu_item)
91 {
92 guint i = 0;
93
94 foreach_document(i)
95 {
96 if (utils_attrib(documents[i], SCOPE_OPEN))
97 document_close(documents[i]);
98 }
99 }
100
on_scope_recent_item(G_GNUC_UNUSED const MenuItem * menu_item)101 static void on_scope_recent_item(G_GNUC_UNUSED const MenuItem *menu_item)
102 {
103 }
104
105 /* Menu item(s) */
106 #define DS_RUNNABLE (DS_INACTIVE | DS_DEBUG | DS_HANGING)
107 #define DS_JUMPABLE (DS_DEBUG | DS_EXTRA_2)
108 #define DS_SOURCABLE (DS_DEBUG | DS_EXTRA_3)
109 #define DS_STEPABLE (DS_DEBUG | DS_EXTRA_1)
110 #define DS_BREAKABLE (DS_NOT_BUSY | DS_EXTRA_2)
111 #define DS_RECENT (DS_INACTIVE | DS_EXTRA_4)
112
113 static MenuItem debug_menu_items[] =
114 {
115 { "program_setup", on_program_setup, 0, NULL, NULL },
116 { "debug_run_continue", on_debug_run_continue, DS_RUNNABLE, NULL, NULL },
117 { "debug_goto_cursor", on_debug_goto_cursor, DS_JUMPABLE, NULL, NULL },
118 { "debug_goto_source", on_debug_goto_source, DS_SOURCABLE, NULL, NULL },
119 { "debug_step_into", on_debug_step_into, DS_STEPABLE, NULL, NULL },
120 { "debug_step_over", on_debug_step_over, DS_STEPABLE, NULL, NULL },
121 { "debug_step_out", on_debug_step_out, DS_DEBUG, NULL, NULL },
122 { "debug_terminate", on_debug_terminate, DS_ACTIVE, NULL, NULL },
123 { "break_toggle", on_break_toggle, DS_BREAKABLE, NULL, NULL },
124 { "scope_gdb_command", on_scope_gdb_command, DS_ACTIVE, NULL, NULL },
125 #ifdef G_OS_UNIX
126 { "terminal_show", on_terminal_show, 0, NULL, NULL },
127 #endif
128 { "scope_reset_markers", on_scope_reset_markers, 0, NULL, NULL },
129 { "scope_cleanup_files", on_scope_cleanup_files, 0, NULL, NULL },
130 { "scope_recent_item", on_scope_recent_item, DS_RECENT, NULL, NULL },
131 { NULL, NULL, 0, NULL, NULL }
132 };
133
debug_menu_extra_state(void)134 static guint debug_menu_extra_state(void)
135 {
136 GeanyDocument *doc = document_get_current();
137
138 return ((thread_state >= THREAD_AT_SOURCE) << DS_INDEX_1) |
139 ((doc && utils_source_document(doc)) << DS_INDEX_2) |
140 ((thread_state == THREAD_AT_ASSEMBLER) << DS_INDEX_3) |
141 (recent_menu_items() << DS_INDEX_4);
142 }
143
144 static MenuInfo debug_menu_info = { debug_menu_items, debug_menu_extra_state, 0 };
145
on_scope_key(guint key_id)146 static void on_scope_key(guint key_id)
147 {
148 menu_item_execute(&debug_menu_info, debug_menu_items + key_id, FALSE);
149 }
150
151 typedef struct _ToolItem
152 {
153 gint index;
154 const char *icon[2];
155 GtkWidget *widget;
156 const char *tooltip_text;
157 } ToolItem;
158
159 static ToolItem toolbar_items[] =
160 {
161 { RUN_CONTINUE_KB, { "small_run_continue_icon", "large_run_continue_icon" }, NULL, N_("Run/continue") },
162 { GOTO_CURSOR_KB, { "small_goto_cursor_icon", "large_goto_cursor_icon" }, NULL, N_("Run to cursor") },
163 { GOTO_SOURCE_KB, { "small_goto_source_icon", "large_goto_source_icon" }, NULL, N_("Run to source") },
164 { STEP_INTO_KB, { "small_step_into_icon", "large_step_into_icon" }, NULL, N_("Step into") },
165 { STEP_OVER_KB, { "small_step_over_icon", "large_step_over_icon" }, NULL, N_("Step over") },
166 { STEP_OUT_KB, { "small_step_out_icon", "large_step_out_icon" }, NULL, N_("Step out") },
167 { TERMINATE_KB, { "small_terminate_icon", "large_terminate_icon" }, NULL, N_("Terminate") },
168 { BREAKPOINT_KB, { "small_breakpoint_icon", "large_breakpoint_icon", }, NULL, N_("Toggle breakpoint") },
169 { -1, { NULL, NULL }, NULL, NULL }
170 };
171
on_toolbar_button_clicked(G_GNUC_UNUSED GtkToolButton * toolbutton,gpointer gdata)172 static void on_toolbar_button_clicked(G_GNUC_UNUSED GtkToolButton *toolbutton, gpointer gdata)
173 {
174 menu_item_execute(&debug_menu_info, debug_menu_items + GPOINTER_TO_INT(gdata), TRUE);
175 }
176
on_toolbar_reconfigured(GtkToolItem * tool_item,ToolItem * item)177 static void on_toolbar_reconfigured(GtkToolItem *tool_item, ToolItem *item)
178 {
179 GtkToolShell *shell = GTK_TOOL_SHELL(gtk_widget_get_parent(item->widget));
180 gboolean large = gtk_tool_shell_get_icon_size(shell) > GTK_ICON_SIZE_MENU;
181 gchar *tooltip = NULL;
182
183 if (gtk_tool_shell_get_style(shell) == GTK_TOOLBAR_ICONS)
184 {
185 GtkMenuItem *menu_item = GTK_MENU_ITEM(debug_menu_items[item->index].widget);
186 tooltip = g_strdup(gtk_menu_item_get_label(menu_item));
187 utils_str_remove_chars(tooltip, "_");
188 }
189
190 gtk_tool_item_set_tooltip_text(tool_item, tooltip);
191 g_free(tooltip);
192 gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(tool_item),
193 get_widget(item->icon[large]));
194 }
195
toolbar_update_state(DebugState state)196 static void toolbar_update_state(DebugState state)
197 {
198 static DebugState last_state = 0;
199 state |= debug_menu_extra_state();
200
201 if (state != last_state)
202 {
203 ToolItem *item;
204
205 for (item = toolbar_items; item->index != -1; item++)
206 {
207 gtk_widget_set_sensitive(item->widget,
208 menu_item_matches_state(debug_menu_items + item->index, state));
209 }
210
211 last_state = state;
212 }
213 }
214
215 static GtkStatusbar *geany_statusbar;
216 static GtkWidget *debug_statusbar;
217 static GtkLabel *debug_state_label;
218
statusbar_update_state(DebugState state)219 void statusbar_update_state(DebugState state)
220 {
221 static DebugState last_state = DS_INACTIVE;
222
223 if (thread_state == THREAD_AT_ASSEMBLER)
224 state = DS_EXTRA_1;
225
226 if (state != last_state)
227 {
228 static const char *const states[] = { N_("Busy"), N_("Ready"), N_("Debug"),
229 N_("Hang"), N_("Assem"), N_("Load"), NULL };
230 guint i;
231
232 for (i = 0; states[i]; i++)
233 if (state & (DS_BUSY << i))
234 break;
235
236 gtk_label_set_text(debug_state_label, _(states[i]));
237
238 if (state == DS_INACTIVE)
239 {
240 gtk_widget_hide(debug_statusbar);
241 #if GTK_CHECK_VERSION(3, 0, 0)
242 gtk_window_set_has_resize_grip(GTK_WINDOW(geany->main_widgets->window), TRUE);
243 #else
244 gtk_statusbar_set_has_resize_grip(geany_statusbar, TRUE);
245 #endif
246 }
247 else if (last_state == DS_INACTIVE)
248 {
249 #if GTK_CHECK_VERSION(3, 0, 0)
250 gtk_window_set_has_resize_grip(GTK_WINDOW(geany->main_widgets->window), FALSE);
251 #else
252 gtk_statusbar_set_has_resize_grip(geany_statusbar, FALSE);
253 #endif
254 gtk_widget_show(debug_statusbar);
255 }
256
257 last_state = state;
258 }
259 }
260
261 static guint blink_id = 0;
262
plugin_unblink(G_GNUC_UNUSED gpointer gdata)263 static gboolean plugin_unblink(G_GNUC_UNUSED gpointer gdata)
264 {
265 gtk_widget_set_state(debug_statusbar, GTK_STATE_NORMAL);
266 blink_id = 0;
267 return FALSE;
268 }
269
plugin_blink(void)270 void plugin_blink(void)
271 {
272 if (pref_visual_beep_length)
273 {
274 if (blink_id)
275 g_source_remove(blink_id);
276 else
277 gtk_widget_set_state(debug_statusbar, GTK_STATE_SELECTED);
278
279 blink_id = plugin_timeout_add(geany_plugin, pref_visual_beep_length * 10,
280 plugin_unblink, NULL);
281 }
282 }
283
plugin_beep(void)284 void plugin_beep(void)
285 {
286 if (geany_data->prefs->beep_on_errors)
287 gdk_beep();
288 else
289 plugin_blink();
290 }
291
update_state(DebugState state)292 void update_state(DebugState state)
293 {
294 menu_update_state(state);
295 program_update_state(state);
296 toolbar_update_state(state);
297 statusbar_update_state(state);
298 views_update_state(state);
299 }
300
on_document_new(G_GNUC_UNUSED GObject * obj,GeanyDocument * doc,G_GNUC_UNUSED gpointer gdata)301 static void on_document_new(G_GNUC_UNUSED GObject *obj, GeanyDocument *doc,
302 G_GNUC_UNUSED gpointer gdata)
303 {
304 prefs_apply(doc);
305 }
306
on_document_open(G_GNUC_UNUSED GObject * obj,GeanyDocument * doc,G_GNUC_UNUSED gpointer gdata)307 static void on_document_open(G_GNUC_UNUSED GObject *obj, GeanyDocument *doc,
308 G_GNUC_UNUSED gpointer gdata)
309 {
310 prefs_apply(doc);
311 breaks_mark(doc);
312
313 if (debug_state() != DS_INACTIVE)
314 threads_mark(doc);
315 }
316
settings_saved(gpointer gdata)317 static gboolean settings_saved(gpointer gdata)
318 {
319 guint i = 0;
320
321 foreach_document(i)
322 {
323 documents[i]->readonly = scintilla_send_message(documents[i]->editor->sci,
324 SCI_GETREADONLY, 0, 0);
325 }
326
327 if (gdata)
328 {
329 conterm_load_config();
330 conterm_apply_config();
331 }
332
333 return FALSE;
334 }
335
schedule_settings_saved(gboolean conterm)336 static void schedule_settings_saved(gboolean conterm)
337 {
338 guint i = 0;
339
340 plugin_idle_add(geany_plugin, settings_saved, GINT_TO_POINTER(conterm));
341
342 foreach_document(i)
343 {
344 if (utils_attrib(documents[i], SCOPE_LOCK))
345 documents[i]->readonly = FALSE;
346 }
347 }
348
on_settings_save(G_GNUC_UNUSED GObject * obj,G_GNUC_UNUSED GKeyFile * keyfile,G_GNUC_UNUSED gpointer gdata)349 static void on_settings_save(G_GNUC_UNUSED GObject *obj, G_GNUC_UNUSED GKeyFile *keyfile,
350 G_GNUC_UNUSED gpointer gdata)
351 {
352 configure_panel();
353 schedule_settings_saved(TRUE);
354 }
355
on_editor_notify(G_GNUC_UNUSED GObject * obj,GeanyEditor * editor,SCNotification * nt,G_GNUC_UNUSED gpointer gdata)356 static gboolean on_editor_notify(G_GNUC_UNUSED GObject *obj, GeanyEditor *editor,
357 SCNotification *nt, G_GNUC_UNUSED gpointer gdata)
358 {
359 GeanyDocument *doc = editor->document;
360
361 if (nt->nmhdr.code == SCN_MODIFIED && nt->linesAdded && utils_source_document(doc))
362 {
363 gboolean active = debug_state() != DS_INACTIVE;
364 ScintillaObject *sci = editor->sci;
365 gint start = sci_get_line_from_position(sci, nt->position);
366
367 if (active)
368 threads_delta(sci, doc->real_path, start, nt->linesAdded);
369
370 breaks_delta(sci, doc->real_path, start, nt->linesAdded, active);
371 }
372
373 return FALSE;
374 }
375
on_document_filetype_set(G_GNUC_UNUSED GObject * obj,GeanyDocument * doc,G_GNUC_UNUSED GeanyFiletype * filetype_old,G_GNUC_UNUSED gpointer gdata)376 static void on_document_filetype_set(G_GNUC_UNUSED GObject *obj, GeanyDocument *doc,
377 G_GNUC_UNUSED GeanyFiletype *filetype_old, G_GNUC_UNUSED gpointer gdata)
378 {
379 DebugState state = debug_state();
380 utils_lock_unlock(doc, state != DS_INACTIVE && utils_source_document(doc));
381 toolbar_update_state(state);
382 }
383
on_document_activate(G_GNUC_UNUSED GObject * obj,G_GNUC_UNUSED GeanyDocument * doc,G_GNUC_UNUSED gpointer user_data)384 static void on_document_activate(G_GNUC_UNUSED GObject *obj, G_GNUC_UNUSED GeanyDocument *doc,
385 G_GNUC_UNUSED gpointer user_data)
386 {
387 toolbar_update_state(debug_state());
388 }
389
on_project_open(G_GNUC_UNUSED GObject * obj,G_GNUC_UNUSED GKeyFile * config)390 static void on_project_open(G_GNUC_UNUSED GObject *obj, G_GNUC_UNUSED GKeyFile *config)
391 {
392 program_context_changed();
393 }
394
change_context(G_GNUC_UNUSED gpointer gdata)395 static gboolean change_context(G_GNUC_UNUSED gpointer gdata)
396 {
397 program_context_changed();
398 return FALSE;
399 }
400
on_project_close(G_GNUC_UNUSED GObject * obj,G_GNUC_UNUSED GKeyFile * config)401 static void on_project_close(G_GNUC_UNUSED GObject *obj, G_GNUC_UNUSED GKeyFile *config)
402 {
403 plugin_idle_add(geany_plugin, change_context, NULL);
404 }
405
on_geany_startup_complete(G_GNUC_UNUSED GObject * obj,G_GNUC_UNUSED gpointer gdata)406 static void on_geany_startup_complete(G_GNUC_UNUSED GObject *obj, G_GNUC_UNUSED gpointer gdata)
407 {
408 if (!geany->app->project)
409 program_context_changed();
410 }
411
on_build_start(G_GNUC_UNUSED GObject * obj,G_GNUC_UNUSED gpointer gdata)412 static void on_build_start(G_GNUC_UNUSED GObject *obj, G_GNUC_UNUSED gpointer gdata)
413 {
414 if (debug_state() != DS_INACTIVE && dialogs_show_question(_("Build action activated. "
415 "Terminate debugging?")))
416 {
417 on_debug_terminate(NULL);
418 }
419 }
420
421 typedef struct _ScopeCallback /* we don't want callbacks on builder init failure */
422 {
423 const char *name;
424 GCallback callback;
425 } ScopeCallback;
426
427 static const ScopeCallback scope_callbacks[] =
428 {
429 { "document-new", G_CALLBACK(on_document_new) },
430 { "document-open", G_CALLBACK(on_document_open) },
431 { "document-reload", G_CALLBACK(on_document_open) },
432 { "save-settings", G_CALLBACK(on_settings_save) },
433 { "editor-notify", G_CALLBACK(on_editor_notify) },
434 { "document-filetype-set", G_CALLBACK(on_document_filetype_set) },
435 { "document-activate", G_CALLBACK(on_document_activate) },
436 { "document-save", G_CALLBACK(on_document_activate) },
437 { "project-open", G_CALLBACK(on_project_open) },
438 { "project-close", G_CALLBACK(on_project_close) },
439 { "geany-startup-complete", G_CALLBACK(on_geany_startup_complete) },
440 { "build-start", G_CALLBACK(on_build_start) },
441 { NULL, NULL }
442 };
443
444 static GtkBuilder *builder;
445
get_object(const char * name)446 GObject *get_object(const char *name)
447 {
448 #ifdef G_DISABLE_ASSERT
449 return gtk_builder_get_object(builder, name);
450 #else /* G_DISABLE_ASSERT */
451 GObject *object = gtk_builder_get_object(builder, name);
452
453 if (!object)
454 {
455 fprintf(stderr, "Scope: object %s is missing\n", name);
456 abort();
457 }
458
459 return object;
460 #endif /* G_DISABLE_ASSERT */
461 }
462
get_widget(const char * name)463 GtkWidget *get_widget(const char *name)
464 {
465 #ifdef G_DISABLE_ASSERT
466 return GTK_WIDGET(get_object(name));
467 #else /* !SC_DISABLE_ASSERT */
468 GObject *object = get_object(name);
469
470 if (!GTK_IS_WIDGET(object))
471 {
472 fprintf(stderr, "Scope: object %s is not a widget\n", name);
473 abort();
474 }
475
476 return GTK_WIDGET(object);
477 #endif /* G_DISABLE_ASSERT */
478 }
479
configure_toolbar(void)480 void configure_toolbar(void)
481 {
482 guint item;
483 ToolItem *tool_item = toolbar_items;
484
485 for (item = 0; tool_item->index != -1; item++, tool_item++)
486 gtk_widget_set_visible(tool_item->widget, pref_show_toolbar_items & (1 << item));
487 }
488
plugin_help()489 void plugin_help()
490 {
491 char *helpfile = g_build_filename(PLUGINHTMLDOCDIR, "scope.html", NULL);
492 utils_open_browser(helpfile);
493 g_free(helpfile);
494 }
495
496 #define DEBUG_MENU_ITEM_POS 7
497 static GtkWidget *debug_item;
498 static GtkWidget *debug_panel;
499
open_debug_panel(void)500 void open_debug_panel(void)
501 {
502 GtkNotebook *notebook = GTK_NOTEBOOK(geany->main_widgets->message_window_notebook);
503 msgwin_switch_tab(gtk_notebook_page_num(notebook, debug_panel), TRUE);
504 gtk_widget_grab_focus(debug_panel);
505 }
506
configure_panel(void)507 void configure_panel(void)
508 {
509 gboolean short_tab_names = pref_panel_tab_pos == GTK_POS_LEFT ||
510 pref_panel_tab_pos == GTK_POS_RIGHT ||
511 geany_data->interface_prefs->msgwin_orientation == GTK_ORIENTATION_HORIZONTAL;
512
513 gtk_label_set_label(GTK_LABEL(get_widget("program_terminal_label")),
514 short_tab_names ? _("Program") : _("Program Terminal"));
515 gtk_label_set_label(GTK_LABEL(get_widget("break_view_label")),
516 short_tab_names ? _("Breaks") : _("Breakpoints"));
517 gtk_label_set_label(GTK_LABEL(get_widget("debug_console_label")),
518 short_tab_names ? _("Console") : _("Debug Console"));
519
520 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(debug_panel), pref_panel_tab_pos);
521 }
522
get_data_dir_path(const gchar * filename)523 static gchar *get_data_dir_path(const gchar *filename)
524 {
525 gchar *prefix = NULL;
526 gchar *path;
527
528 #ifdef G_OS_WIN32
529 prefix = g_win32_get_package_installation_directory_of_module(NULL);
530 #elif defined(__APPLE__)
531 if (g_getenv("GEANY_PLUGINS_SHARE_PATH"))
532 return g_build_filename(g_getenv("GEANY_PLUGINS_SHARE_PATH"),
533 PLUGIN, filename, NULL);
534 #endif
535 path = g_build_filename(prefix ? prefix : "", PLUGINDATADIR, filename, NULL);
536 g_free(prefix);
537 return path;
538 }
539
plugin_init(G_GNUC_UNUSED GeanyData * gdata)540 void plugin_init(G_GNUC_UNUSED GeanyData *gdata)
541 {
542 GeanyKeyGroup *scope_key_group;
543 #if GTK_CHECK_VERSION(3, 0, 0)
544 char *gladefile = get_data_dir_path("scope_gtk3.glade");
545 #else
546 char *gladefile = get_data_dir_path("scope.glade");
547 #endif
548 GError *gerror = NULL;
549 GtkWidget *menubar1 = ui_lookup_widget(geany->main_widgets->window, "menubar1");
550 guint item;
551 const MenuKey *menu_key = debug_menu_keys;
552 ToolItem *tool_item = toolbar_items;
553 const ScopeCallback *scb;
554
555 scope_key_group = plugin_set_key_group(geany_plugin, "scope", COUNT_KB, NULL);
556 builder = gtk_builder_new();
557 gtk_builder_set_translation_domain(builder, GETTEXT_PACKAGE);
558 scp_tree_store_register_dynamic();
559
560 if (!gtk_builder_add_from_file(builder, gladefile, &gerror))
561 {
562 msgwin_status_add(_("Scope: %s."), gerror->message);
563 g_warning(_("Scope: %s."), gerror->message);
564 g_error_free(gerror);
565 g_object_unref(builder);
566 builder = NULL;
567 }
568
569 g_free(gladefile);
570 if (!builder)
571 return;
572
573 /* interface */
574 #ifndef G_OS_UNIX
575 gtk_widget_hide(get_widget("terminal_show"));
576 #endif
577 debug_item = get_widget("debug_item");
578 if (menubar1)
579 {
580 GList *children = gtk_container_get_children(GTK_CONTAINER(menubar1));
581 GtkWidget *menu_build1 = ui_lookup_widget(menubar1, "menu_build1");
582
583 gtk_menu_shell_insert(GTK_MENU_SHELL(menubar1), debug_item,
584 menu_build1 ? g_list_index(children, menu_build1) + 1 : DEBUG_MENU_ITEM_POS);
585 }
586 else
587 gtk_container_add(GTK_CONTAINER(geany->main_widgets->tools_menu), debug_item);
588
589 menu_connect("debug_menu", &debug_menu_info, NULL);
590 ui_add_document_sensitive(get_widget("scope_reset_markers"));
591 ui_add_document_sensitive(get_widget("scope_cleanup_files"));
592
593 for (item = 0; item < EVALUATE_KB; item++, menu_key++)
594 {
595 keybindings_set_item(scope_key_group, item, on_scope_key, 0, 0, menu_key->name,
596 _(menu_key->label), debug_menu_items[item].widget);
597 }
598
599 geany_statusbar = GTK_STATUSBAR(gtk_widget_get_parent(geany->main_widgets->progressbar));
600 debug_statusbar = get_widget("debug_statusbar");
601 debug_state_label = GTK_LABEL(get_widget("debug_state_label"));
602 gtk_box_pack_end(GTK_BOX(geany_statusbar), debug_statusbar, FALSE, FALSE, 0);
603
604 debug_panel = get_widget("debug_panel");
605 gtk_notebook_append_page(GTK_NOTEBOOK(geany->main_widgets->message_window_notebook),
606 debug_panel, get_widget("debug_label"));
607
608 /* startup */
609 program_init();
610 prefs_init();
611 conterm_init();
612 inspect_init();
613 register_init();
614 parse_init();
615 utils_init();
616 debug_init();
617 views_init();
618 thread_init();
619 break_init();
620 watch_init();
621 stack_init();
622 local_init();
623 memory_init();
624 menu_init();
625 menu_set_popup_keybindings(scope_key_group, item);
626
627 for (item = 0; tool_item->index != -1; item++, tool_item++)
628 {
629 GtkMenuItem *menu_item = GTK_MENU_ITEM(debug_menu_items[tool_item->index].widget);
630 GtkToolItem *button = gtk_tool_button_new(NULL, gtk_menu_item_get_label(menu_item));
631
632 gtk_widget_set_tooltip_text (GTK_WIDGET (button), _(tool_item->tooltip_text));
633 gtk_tool_button_set_use_underline(GTK_TOOL_BUTTON(button),
634 gtk_menu_item_get_use_underline(menu_item));
635 g_signal_connect(button, "clicked", G_CALLBACK(on_toolbar_button_clicked),
636 GINT_TO_POINTER(tool_item->index));
637 g_signal_connect(button, "toolbar-reconfigured",
638 G_CALLBACK(on_toolbar_reconfigured), tool_item);
639 tool_item->widget = GTK_WIDGET(button);
640 plugin_add_toolbar_item(geany_plugin, button);
641 }
642
643 toolbar_update_state(DS_INACTIVE);
644 views_update_state(DS_INACTIVE);
645 configure_toolbar();
646
647 g_signal_connect(debug_panel, "switch-page", G_CALLBACK(on_view_changed), NULL);
648 for (scb = scope_callbacks; scb->name; scb++)
649 plugin_signal_connect(geany_plugin, NULL, scb->name, FALSE, scb->callback, NULL);
650 }
651
plugin_cleanup(void)652 void plugin_cleanup(void)
653 {
654 ToolItem *item;
655
656 if (!builder)
657 return;
658
659 gtk_widget_destroy(debug_item);
660 gtk_widget_destroy(debug_panel);
661
662 for (item = toolbar_items; item->index != -1; item++)
663 gtk_widget_destroy(item->widget);
664
665 /* shutdown */
666 tooltip_finalize();
667 program_finalize();
668 conterm_finalize();
669 registers_finalize();
670 inspect_finalize();
671 thread_finalize();
672 break_finalize();
673 memory_finalize();
674 menu_finalize();
675 views_finalize();
676 utils_finalize();
677 parse_finalize();
678 prefs_finalize();
679 debug_finalize();
680
681 gtk_widget_destroy(debug_statusbar);
682 g_object_unref(builder);
683 }
684