1 /*
2 *
3 * dpaned.c
4 *
5 * Copyright 2010 Alexander Petukhov <devel(at)apetukhov.ru>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20 * MA 02110-1301, USA.
21 */
22
23 /*
24 * Working with debug paned.
25 */
26
27 #include <sys/stat.h>
28
29 #include <memory.h>
30 #include <string.h>
31
32 #include <geanyplugin.h>
33 extern GeanyData *geany_data;
34
35 #include "dpaned.h"
36 #include "tabs.h"
37 #include "breakpoints.h"
38 #include "debug.h"
39 #include "btnpanel.h"
40 #include "stree.h"
41 #include "dconfig.h"
42
43 #define NOTEBOOK_GROUP "notebook-438948394"
44 #define HPANED_BORDER_WIDTH 4
45
46 #define CONNECT_PAGE_SIGNALS(X) \
47 switch_left_handler_id = g_signal_connect(G_OBJECT(debug_notebook_left), "switch-page", G_CALLBACK(on_change_current_page), NULL); \
48 switch_right_handler_id = g_signal_connect(G_OBJECT(debug_notebook_right), "switch-page", G_CALLBACK(on_change_current_page), NULL); \
49 reorder_left_handler_id = g_signal_connect(G_OBJECT(debug_notebook_left), "page-reordered", G_CALLBACK(on_page_reordered), NULL); \
50 reorder_right_handler_id = g_signal_connect(G_OBJECT(debug_notebook_right), "page-reordered", G_CALLBACK(on_page_reordered), NULL); \
51 add_left_handler_id = g_signal_connect(G_OBJECT(debug_notebook_left), "page-added", G_CALLBACK(on_page_added), NULL); \
52 add_right_handler_id = g_signal_connect(G_OBJECT(debug_notebook_right), "page-added", G_CALLBACK(on_page_added), NULL); \
53 remove_left_handler_id = g_signal_connect(G_OBJECT(debug_notebook_left), "page-removed", G_CALLBACK(on_page_removed), NULL); \
54 remove_right_handler_id = g_signal_connect(G_OBJECT(debug_notebook_right), "page-removed", G_CALLBACK(on_page_removed), NULL);
55
56 #define DISCONNECT_PAGE_SIGNALS(X) \
57 g_signal_handler_disconnect(G_OBJECT(debug_notebook_left), switch_left_handler_id); \
58 g_signal_handler_disconnect(G_OBJECT(debug_notebook_right), switch_right_handler_id); \
59 g_signal_handler_disconnect(G_OBJECT(debug_notebook_left), reorder_left_handler_id); \
60 g_signal_handler_disconnect(G_OBJECT(debug_notebook_right), reorder_right_handler_id); \
61 g_signal_handler_disconnect(G_OBJECT(debug_notebook_left), add_left_handler_id); \
62 g_signal_handler_disconnect(G_OBJECT(debug_notebook_right), add_right_handler_id); \
63 g_signal_handler_disconnect(G_OBJECT(debug_notebook_left), remove_left_handler_id); \
64 g_signal_handler_disconnect(G_OBJECT(debug_notebook_right), remove_right_handler_id);
65
66 #define CONNECT_ALLOCATED_PAGE_SIGNALS(X) \
67 allocate_handler_id = g_signal_connect(G_OBJECT(hpaned), "size-allocate", G_CALLBACK(on_size_allocate), NULL);
68
69 #define DISCONNECT_ALLOCATED_PAGE_SIGNALS(X) \
70 g_signal_handler_disconnect(G_OBJECT(hpaned), allocate_handler_id); \
71
72 /* pane */
73 static GtkWidget *hpaned = NULL;
74
75 /* left and right notebooks */
76 static GtkWidget *debug_notebook_left = NULL;
77 static GtkWidget *debug_notebook_right = NULL;
78
79 /* notebook signal handler ids */
80 static gulong allocate_handler_id;
81 static gulong switch_left_handler_id;
82 static gulong switch_right_handler_id;
83 static gulong reorder_left_handler_id;
84 static gulong reorder_right_handler_id;
85 static gulong add_left_handler_id;
86 static gulong add_right_handler_id;
87 static gulong remove_left_handler_id;
88 static gulong remove_right_handler_id;
89
90 /*
91 * first allocation handler to properly set paned position
92 */
on_size_allocate(GtkWidget * widget,GdkRectangle * allocation,gpointer user_data)93 static void on_size_allocate(GtkWidget *widget,GdkRectangle *allocation, gpointer user_data)
94 {
95 int position;
96
97 DISCONNECT_ALLOCATED_PAGE_SIGNALS();
98
99 position = (allocation->width - 2 * HPANED_BORDER_WIDTH) * 0.5;
100 gtk_paned_set_position(GTK_PANED(hpaned), position);
101 }
102
103 /*
104 * page added event handler
105 */
on_page_added(GtkNotebook * notebook,GtkWidget * child,guint page_num,gpointer user_data)106 static void on_page_added(GtkNotebook *notebook, GtkWidget *child, guint page_num, gpointer user_data)
107 {
108 gboolean is_left = (GTK_NOTEBOOK(debug_notebook_left) == notebook);
109 gboolean is_tabbed = config_get_tabbed();
110 int *tabs = NULL, *array, *new_tabs;
111 gsize length;
112 GtkWidget *page;
113 tab_id id;
114 int config_part;
115
116 if (!is_tabbed)
117 tabs = config_get_tabs(&length);
118 else if (is_left)
119 tabs = config_get_left_tabs(&length);
120 else
121 tabs = config_get_right_tabs(&length);
122
123 array = g_malloc((length + 2) * sizeof(int));
124 new_tabs = array + 1;
125 memcpy(new_tabs, tabs, length * sizeof(int));
126 memmove(new_tabs + page_num + 1, new_tabs + page_num, (length - page_num) * sizeof(int));
127
128 page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(is_left ? debug_notebook_left : debug_notebook_right), page_num);
129 id = tabs_get_tab_id(page);
130 new_tabs[page_num] = id;
131
132 if (!is_tabbed)
133 config_part = CP_OT_TABS;
134 else if (is_left)
135 config_part = CP_TT_LTABS;
136 else
137 config_part = CP_TT_RTABS;
138
139 array[0] = length + 1;
140 memcpy(array + 1, new_tabs, length + 1);
141 config_set_panel(config_part, array, 0);
142
143 g_free(tabs);
144 g_free(array);
145 }
146
147 /*
148 * page reordered event handler
149 */
on_page_reordered(GtkNotebook * notebook,GtkWidget * child,guint page_num,gpointer user_data)150 static void on_page_reordered(GtkNotebook *notebook, GtkWidget *child, guint page_num, gpointer user_data)
151 {
152 gboolean is_left = (GTK_NOTEBOOK(debug_notebook_left) == notebook);
153 gboolean is_tabbed = config_get_tabbed();
154 int *tabs = NULL;
155 gsize length;
156 gsize prev_index, min, max;
157 GtkWidget *page;
158 tab_id id;
159 int i;
160 int config_part_tabs;
161 int config_part_selected_index;
162 int *array;
163
164 if (!is_tabbed)
165 tabs = config_get_tabs(&length);
166 else if (is_left)
167 tabs = config_get_left_tabs(&length);
168 else
169 tabs = config_get_right_tabs(&length);
170
171 page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(is_left ? debug_notebook_left : debug_notebook_right), page_num);
172 id = tabs_get_tab_id(page);
173 for (prev_index = 0; prev_index < length; prev_index++)
174 {
175 if (id == tabs[prev_index])
176 {
177 break;
178 }
179 }
180
181 min = MIN(prev_index, page_num);
182 max = MAX(prev_index, page_num);
183 for (i = min; i < max; i++)
184 {
185 int tmp = tabs[i];
186 tabs[i] = tabs[i + 1];
187 tabs[i + 1] = tmp;
188 }
189
190 if (!is_tabbed)
191 {
192 config_part_tabs = CP_OT_TABS;
193 config_part_selected_index = CP_OT_SELECTED;
194 }
195 else if (is_left)
196 {
197 config_part_tabs = CP_TT_LTABS;
198 config_part_selected_index = CP_TT_LSELECTED;
199 }
200 else
201 {
202 config_part_tabs = CP_TT_RTABS;
203 config_part_selected_index = CP_TT_RSELECTED;
204 }
205
206 array = g_malloc((length + 1) * sizeof(int));
207 array[0] = length;
208 memcpy(array + 1, tabs, length * sizeof(int));
209
210 config_set_panel(
211 config_part_tabs, array,
212 config_part_selected_index, &page_num,
213 0
214 );
215
216 g_free(tabs);
217 g_free(array);
218 }
219
220 /*
221 * page removed event handler
222 */
on_page_removed(GtkNotebook * notebook,GtkWidget * child,guint page_num,gpointer user_data)223 static void on_page_removed(GtkNotebook *notebook, GtkWidget *child, guint page_num, gpointer user_data)
224 {
225 gboolean is_left = (GTK_NOTEBOOK(debug_notebook_left) == notebook);
226 gboolean is_tabbed = config_get_tabbed();
227 int *tabs = NULL;
228 gsize length;
229 int config_part;
230
231 if (!is_tabbed)
232 tabs = config_get_tabs(&length);
233 else if (is_left)
234 tabs = config_get_left_tabs(&length);
235 else
236 tabs = config_get_right_tabs(&length);
237
238 memmove(tabs + page_num, tabs + page_num + 1, (length - page_num - 1) * sizeof(int));
239 memmove(tabs + 1, tabs, (length - 1) * sizeof(int));
240 tabs[0] = length - 1;
241
242 if (!is_tabbed)
243 config_part = CP_OT_TABS;
244 else if (is_left)
245 config_part = CP_TT_LTABS;
246 else
247 config_part = CP_TT_RTABS;
248
249 config_set_panel(config_part, tabs, 0);
250
251 g_free(tabs);
252 }
253
254 /*
255 * active page changed event handler
256 */
on_change_current_page(GtkNotebook * notebook,gpointer arg1,guint arg2,gpointer user_data)257 static gboolean on_change_current_page(GtkNotebook *notebook, gpointer arg1, guint arg2, gpointer user_data)
258 {
259 gboolean is_left = (GTK_NOTEBOOK(debug_notebook_left) == notebook);
260 gboolean is_tabbed = config_get_tabbed();
261
262 int config_part;
263 if (!is_tabbed)
264 config_part = CP_OT_SELECTED;
265 else if (is_left)
266 config_part = CP_TT_LSELECTED;
267 else
268 config_part = CP_TT_RSELECTED;
269
270 config_set_panel(config_part, (gpointer)&arg2, 0);
271
272 return TRUE;
273 }
274
275 /*
276 * create GUI and check config
277 */
dpaned_init(void)278 void dpaned_init(void)
279 {
280 /* create paned */
281 hpaned = gtk_hpaned_new();
282
283 /* create notebooks */
284 debug_notebook_left = gtk_notebook_new();
285 debug_notebook_right = gtk_notebook_new();
286
287 /* setup notebooks */
288 gtk_notebook_set_scrollable(GTK_NOTEBOOK(debug_notebook_left), TRUE);
289 gtk_notebook_set_scrollable(GTK_NOTEBOOK(debug_notebook_right), TRUE);
290 gtk_notebook_set_group_name(GTK_NOTEBOOK(debug_notebook_left), NOTEBOOK_GROUP);
291 gtk_notebook_set_group_name(GTK_NOTEBOOK(debug_notebook_right), NOTEBOOK_GROUP);
292 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(debug_notebook_left), GTK_POS_TOP);
293 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(debug_notebook_right), GTK_POS_TOP);
294
295 /* add notebooks */
296 gtk_paned_add1(GTK_PANED(hpaned), debug_notebook_left);
297 gtk_paned_add2(GTK_PANED(hpaned), debug_notebook_right);
298
299 if (config_get_tabbed())
300 {
301 gsize length;
302 int *tab_ids, i;
303
304 /* left */
305 tab_ids = config_get_left_tabs(&length);
306 for (i = 0; i < length; i++)
307 {
308 GtkWidget *tab = tabs_get_tab((tab_id)tab_ids[i]);
309 gtk_notebook_append_page(GTK_NOTEBOOK(debug_notebook_left),
310 tab,
311 gtk_label_new(tabs_get_label(tab_ids[i])));
312 gtk_notebook_set_tab_detachable(GTK_NOTEBOOK(debug_notebook_left), tab, TRUE);
313 gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(debug_notebook_left), tab, TRUE);
314 }
315 g_free(tab_ids);
316
317 /* right */
318 tab_ids = config_get_right_tabs(&length);
319 for (i = 0; i < length; i++)
320 {
321 GtkWidget *tab = tabs_get_tab((tab_id)tab_ids[i]);
322 gtk_notebook_append_page(GTK_NOTEBOOK(debug_notebook_right),
323 tab,
324 gtk_label_new(tabs_get_label(tab_ids[i])));
325 gtk_notebook_set_tab_detachable(GTK_NOTEBOOK(debug_notebook_right), tab, TRUE);
326 gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(debug_notebook_right), tab, TRUE);
327 }
328 g_free(tab_ids);
329
330 gtk_widget_show_all(hpaned);
331
332 gtk_notebook_set_current_page(GTK_NOTEBOOK(debug_notebook_left), config_get_left_selected_tab_index());
333 gtk_notebook_set_current_page(GTK_NOTEBOOK(debug_notebook_right),config_get_right_selected_tab_index());
334 }
335 else
336 {
337 gsize i, length;
338 int *tab_ids;
339
340 g_object_ref(debug_notebook_right);
341 gtk_container_remove(GTK_CONTAINER(hpaned), debug_notebook_right);
342
343 tab_ids = config_get_tabs(&length);
344 for (i = 0; i < length; i++)
345 {
346 GtkWidget *tab = tabs_get_tab((tab_id)tab_ids[i]);
347 gtk_notebook_append_page(GTK_NOTEBOOK(debug_notebook_left),
348 tab,
349 gtk_label_new(tabs_get_label(tab_ids[i])));
350 gtk_notebook_set_tab_detachable(GTK_NOTEBOOK(debug_notebook_left), tab, TRUE);
351 gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(debug_notebook_left), tab, TRUE);
352 }
353 g_free(tab_ids);
354
355 gtk_widget_show_all(hpaned);
356 gtk_notebook_set_current_page(GTK_NOTEBOOK(debug_notebook_left), config_get_selected_tab_index());
357 }
358
359 CONNECT_PAGE_SIGNALS();
360 CONNECT_ALLOCATED_PAGE_SIGNALS();
361 }
362
363 /*
364 * free local data, disconnect signals
365 */
dpaned_destroy(void)366 void dpaned_destroy(void)
367 {
368 DISCONNECT_PAGE_SIGNALS();
369 }
370
371 /*
372 * gets widget
373 */
dpaned_get_paned(void)374 GtkWidget* dpaned_get_paned(void)
375 {
376 return hpaned;
377 }
378
379 /*
380 * sets tabs mode
381 */
dpaned_set_tabbed(gboolean tabbed)382 void dpaned_set_tabbed(gboolean tabbed)
383 {
384 DISCONNECT_PAGE_SIGNALS();
385
386 if (!tabbed)
387 {
388 gsize length;
389 int *tab_ids;
390 int i;
391
392 g_object_ref(debug_notebook_right);
393 gtk_container_remove(GTK_CONTAINER(hpaned), debug_notebook_right);
394
395 tab_ids = config_get_tabs(&length);
396 for (i = 0; i < length; i++)
397 {
398 GtkWidget *tab = tabs_get_tab((tab_id)tab_ids[i]);
399 if (-1 == gtk_notebook_page_num(GTK_NOTEBOOK(debug_notebook_left), tab))
400 {
401 g_object_ref(tab);
402 gtk_container_remove(GTK_CONTAINER(debug_notebook_right), tab);
403 gtk_notebook_insert_page(GTK_NOTEBOOK(debug_notebook_left), tab, gtk_label_new(tabs_get_label(tab_ids[i])), i);
404 g_object_unref(tab);
405 gtk_notebook_set_tab_detachable(GTK_NOTEBOOK(debug_notebook_left), tab, TRUE);
406 gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(debug_notebook_left), tab, TRUE);
407 }
408 }
409 g_free(tab_ids);
410
411 gtk_notebook_set_current_page(GTK_NOTEBOOK(debug_notebook_left), config_get_selected_tab_index());
412
413 gtk_widget_show_all(hpaned);
414 }
415 else
416 {
417 gsize length;
418 int i;
419 int *tab_ids;
420
421 gtk_paned_add2(GTK_PANED(hpaned), debug_notebook_right);
422 g_object_unref(debug_notebook_right);
423
424 tab_ids = config_get_right_tabs(&length);
425 for (i = 0; i < length; i++)
426 {
427 GtkWidget *tab = tabs_get_tab((tab_id)tab_ids[i]);
428 g_object_ref(tab);
429 gtk_container_remove(GTK_CONTAINER(debug_notebook_left), tab);
430 gtk_notebook_insert_page(GTK_NOTEBOOK(debug_notebook_right), tab, gtk_label_new(tabs_get_label(tab_ids[i])), i);
431 g_object_unref(tab);
432 gtk_notebook_set_tab_detachable(GTK_NOTEBOOK(debug_notebook_right), tab, TRUE);
433 gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(debug_notebook_right), tab, TRUE);
434 }
435 g_free(tab_ids);
436
437 gtk_notebook_set_current_page(GTK_NOTEBOOK(debug_notebook_left), config_get_left_selected_tab_index());
438 gtk_notebook_set_current_page(GTK_NOTEBOOK(debug_notebook_right), config_get_right_selected_tab_index());
439
440 gtk_widget_show_all(hpaned);
441 }
442
443 CONNECT_PAGE_SIGNALS();
444
445 config_set_panel(CP_TABBED_MODE, (gpointer)&tabbed, 0);
446 }
447