1 /*
2 * gedit-multi-notebook.c
3 * This file is part of gedit
4 *
5 * Copyright (C) 2010 - Ignacio Casal Quinteiro
6 *
7 * gedit 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 * gedit 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 gedit; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301 USA
21 */
22
23 #include "gedit-multi-notebook.h"
24
25 #include "gedit-enum-types-private.h"
26 #include "gedit-settings.h"
27 #include "gedit-tab-private.h"
28 #include "gedit-tab.h"
29
30 struct _GeditMultiNotebookPrivate
31 {
32 GtkWidget *active_notebook;
33 GList *notebooks;
34 gint total_tabs;
35
36 GeditTab *active_tab;
37
38 GeditNotebookShowTabsModeType show_tabs_mode;
39 GSettings *ui_settings;
40
41 guint show_tabs : 1;
42 guint removing_notebook : 1;
43 };
44
45 enum
46 {
47 PROP_0,
48 PROP_ACTIVE_NOTEBOOK,
49 PROP_ACTIVE_TAB,
50 PROP_SHOW_TABS_MODE,
51 LAST_PROP
52 };
53
54 static GParamSpec *properties[LAST_PROP];
55
56 enum
57 {
58 NOTEBOOK_ADDED,
59 NOTEBOOK_REMOVED,
60 TAB_ADDED,
61 TAB_REMOVED,
62 SWITCH_TAB,
63 TAB_CLOSE_REQUEST,
64 CREATE_WINDOW,
65 PAGE_REORDERED,
66 SHOW_POPUP_MENU,
67 LAST_SIGNAL
68 };
69
70 static guint signals[LAST_SIGNAL];
71
72 G_DEFINE_TYPE_WITH_PRIVATE (GeditMultiNotebook, gedit_multi_notebook, GTK_TYPE_GRID)
73
74 static void remove_notebook (GeditMultiNotebook *mnb,
75 GtkWidget *notebook);
76
77 static void update_tabs_visibility (GeditMultiNotebook *mnb);
78
79 static void
gedit_multi_notebook_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)80 gedit_multi_notebook_get_property (GObject *object,
81 guint prop_id,
82 GValue *value,
83 GParamSpec *pspec)
84 {
85 GeditMultiNotebook *mnb = GEDIT_MULTI_NOTEBOOK (object);
86
87 switch (prop_id)
88 {
89 case PROP_ACTIVE_NOTEBOOK:
90 g_value_set_object (value,
91 mnb->priv->active_notebook);
92 break;
93 case PROP_ACTIVE_TAB:
94 g_value_set_object (value,
95 mnb->priv->active_tab);
96 break;
97 case PROP_SHOW_TABS_MODE:
98 g_value_set_enum (value,
99 mnb->priv->show_tabs_mode);
100 break;
101 default:
102 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
103 break;
104 }
105 }
106
107 static void
gedit_multi_notebook_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)108 gedit_multi_notebook_set_property (GObject *object,
109 guint prop_id,
110 const GValue *value,
111 GParamSpec *pspec)
112 {
113 GeditMultiNotebook *mnb = GEDIT_MULTI_NOTEBOOK (object);
114
115 switch (prop_id)
116 {
117 case PROP_SHOW_TABS_MODE:
118 mnb->priv->show_tabs_mode = g_value_get_enum (value);
119 update_tabs_visibility (mnb);
120 break;
121 default:
122 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
123 break;
124 }
125 }
126
127 static void
gedit_multi_notebook_dispose(GObject * object)128 gedit_multi_notebook_dispose (GObject *object)
129 {
130 GeditMultiNotebook *mnb = GEDIT_MULTI_NOTEBOOK (object);
131
132 g_clear_object (&mnb->priv->ui_settings);
133
134 G_OBJECT_CLASS (gedit_multi_notebook_parent_class)->dispose (object);
135 }
136
137 static void
gedit_multi_notebook_finalize(GObject * object)138 gedit_multi_notebook_finalize (GObject *object)
139 {
140 GeditMultiNotebook *mnb = GEDIT_MULTI_NOTEBOOK (object);
141
142 g_list_free (mnb->priv->notebooks);
143
144 G_OBJECT_CLASS (gedit_multi_notebook_parent_class)->finalize (object);
145 }
146
147 static void
gedit_multi_notebook_class_init(GeditMultiNotebookClass * klass)148 gedit_multi_notebook_class_init (GeditMultiNotebookClass *klass)
149 {
150 GObjectClass *object_class = G_OBJECT_CLASS (klass);
151
152 object_class->dispose = gedit_multi_notebook_dispose;
153 object_class->finalize = gedit_multi_notebook_finalize;
154 object_class->get_property = gedit_multi_notebook_get_property;
155 object_class->set_property = gedit_multi_notebook_set_property;
156
157 properties[PROP_ACTIVE_NOTEBOOK] =
158 g_param_spec_object ("active-notebook",
159 "Active Notebook",
160 "The Active Notebook",
161 GEDIT_TYPE_NOTEBOOK,
162 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
163 properties[PROP_ACTIVE_TAB] =
164 g_param_spec_object ("active-tab",
165 "Active Tab",
166 "The Active Tab",
167 GEDIT_TYPE_TAB,
168 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
169 properties[PROP_SHOW_TABS_MODE] =
170 g_param_spec_enum ("show-tabs-mode",
171 "Show Tabs Mode",
172 "When tabs should be shown",
173 GEDIT_TYPE_NOTEBOOK_SHOW_TABS_MODE_TYPE,
174 GEDIT_NOTEBOOK_SHOW_TABS_ALWAYS,
175 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
176
177 g_object_class_install_properties (object_class, LAST_PROP, properties);
178
179 signals[NOTEBOOK_ADDED] =
180 g_signal_new ("notebook-added",
181 G_OBJECT_CLASS_TYPE (object_class),
182 G_SIGNAL_RUN_FIRST,
183 G_STRUCT_OFFSET (GeditMultiNotebookClass, notebook_added),
184 NULL, NULL, NULL,
185 G_TYPE_NONE,
186 1,
187 GEDIT_TYPE_NOTEBOOK);
188 signals[NOTEBOOK_REMOVED] =
189 g_signal_new ("notebook-removed",
190 G_OBJECT_CLASS_TYPE (object_class),
191 G_SIGNAL_RUN_FIRST,
192 G_STRUCT_OFFSET (GeditMultiNotebookClass, notebook_removed),
193 NULL, NULL, NULL,
194 G_TYPE_NONE,
195 1,
196 GEDIT_TYPE_NOTEBOOK);
197 signals[TAB_ADDED] =
198 g_signal_new ("tab-added",
199 G_OBJECT_CLASS_TYPE (object_class),
200 G_SIGNAL_RUN_FIRST,
201 G_STRUCT_OFFSET (GeditMultiNotebookClass, tab_added),
202 NULL, NULL, NULL,
203 G_TYPE_NONE,
204 2,
205 GEDIT_TYPE_NOTEBOOK,
206 GEDIT_TYPE_TAB);
207 signals[TAB_REMOVED] =
208 g_signal_new ("tab-removed",
209 G_OBJECT_CLASS_TYPE (object_class),
210 G_SIGNAL_RUN_FIRST,
211 G_STRUCT_OFFSET (GeditMultiNotebookClass, tab_removed),
212 NULL, NULL, NULL,
213 G_TYPE_NONE,
214 2,
215 GEDIT_TYPE_NOTEBOOK,
216 GEDIT_TYPE_TAB);
217 signals[SWITCH_TAB] =
218 g_signal_new ("switch-tab",
219 G_OBJECT_CLASS_TYPE (object_class),
220 G_SIGNAL_RUN_FIRST,
221 G_STRUCT_OFFSET (GeditMultiNotebookClass, switch_tab),
222 NULL, NULL, NULL,
223 G_TYPE_NONE,
224 4,
225 GEDIT_TYPE_NOTEBOOK,
226 GEDIT_TYPE_TAB,
227 GEDIT_TYPE_NOTEBOOK,
228 GEDIT_TYPE_TAB);
229 signals[TAB_CLOSE_REQUEST] =
230 g_signal_new ("tab-close-request",
231 G_OBJECT_CLASS_TYPE (object_class),
232 G_SIGNAL_RUN_FIRST,
233 G_STRUCT_OFFSET (GeditMultiNotebookClass, tab_close_request),
234 NULL, NULL, NULL,
235 G_TYPE_NONE,
236 2,
237 GEDIT_TYPE_NOTEBOOK,
238 GEDIT_TYPE_TAB);
239 signals[CREATE_WINDOW] =
240 g_signal_new ("create-window",
241 G_TYPE_FROM_CLASS (object_class),
242 G_SIGNAL_RUN_LAST,
243 G_STRUCT_OFFSET (GeditMultiNotebookClass, create_window),
244 NULL, NULL, NULL,
245 GTK_TYPE_NOTEBOOK, 4,
246 GEDIT_TYPE_NOTEBOOK, GTK_TYPE_WIDGET,
247 G_TYPE_INT, G_TYPE_INT);
248 signals[PAGE_REORDERED] =
249 g_signal_new ("page-reordered",
250 G_OBJECT_CLASS_TYPE (object_class),
251 G_SIGNAL_RUN_FIRST,
252 G_STRUCT_OFFSET (GeditMultiNotebookClass, page_reordered),
253 NULL, NULL, NULL,
254 G_TYPE_NONE,
255 3,
256 GEDIT_TYPE_NOTEBOOK, GTK_TYPE_WIDGET,
257 G_TYPE_INT);
258 signals[SHOW_POPUP_MENU] =
259 g_signal_new ("show-popup-menu",
260 G_OBJECT_CLASS_TYPE (object_class),
261 G_SIGNAL_RUN_FIRST,
262 G_STRUCT_OFFSET (GeditMultiNotebookClass, show_popup_menu),
263 NULL, NULL, NULL,
264 G_TYPE_NONE,
265 2,
266 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE,
267 GEDIT_TYPE_TAB);
268 }
269
270 static void
notebook_show_popup_menu(GtkNotebook * notebook,GdkEvent * event,GeditTab * tab,GeditMultiNotebook * mnb)271 notebook_show_popup_menu (GtkNotebook *notebook,
272 GdkEvent *event,
273 GeditTab *tab,
274 GeditMultiNotebook *mnb)
275 {
276 g_signal_emit (G_OBJECT (mnb), signals[SHOW_POPUP_MENU], 0, event, tab);
277 }
278
279 static void
notebook_tab_close_request(GeditNotebook * notebook,GeditTab * tab,GeditMultiNotebook * mnb)280 notebook_tab_close_request (GeditNotebook *notebook,
281 GeditTab *tab,
282 GeditMultiNotebook *mnb)
283 {
284 g_signal_emit (G_OBJECT (mnb), signals[TAB_CLOSE_REQUEST], 0,
285 notebook, tab);
286 }
287
288 static GtkNotebook *
notebook_create_window(GeditNotebook * notebook,GtkWidget * child,gint x,gint y,GeditMultiNotebook * mnb)289 notebook_create_window (GeditNotebook *notebook,
290 GtkWidget *child,
291 gint x,
292 gint y,
293 GeditMultiNotebook *mnb)
294 {
295 GtkNotebook *dest_notebook;
296
297 g_signal_emit (G_OBJECT (mnb), signals[CREATE_WINDOW], 0,
298 notebook, child, x, y, &dest_notebook);
299
300 return dest_notebook;
301 }
302
303 static void
notebook_page_reordered(GeditNotebook * notebook,GtkWidget * child,guint page_num,GeditMultiNotebook * mnb)304 notebook_page_reordered (GeditNotebook *notebook,
305 GtkWidget *child,
306 guint page_num,
307 GeditMultiNotebook *mnb)
308 {
309 g_signal_emit (G_OBJECT (mnb), signals[PAGE_REORDERED], 0, notebook,
310 child, page_num);
311 }
312
313 static void
set_active_tab(GeditMultiNotebook * mnb,GeditTab * tab)314 set_active_tab (GeditMultiNotebook *mnb,
315 GeditTab *tab)
316 {
317 mnb->priv->active_tab = tab;
318 g_object_notify_by_pspec (G_OBJECT (mnb), properties[PROP_ACTIVE_TAB]);
319 }
320
321 static void
notebook_page_removed(GtkNotebook * notebook,GtkWidget * child,guint page_num,GeditMultiNotebook * mnb)322 notebook_page_removed (GtkNotebook *notebook,
323 GtkWidget *child,
324 guint page_num,
325 GeditMultiNotebook *mnb)
326 {
327 GeditTab *tab = GEDIT_TAB (child);
328 guint num_tabs;
329 gboolean last_notebook;
330
331 --mnb->priv->total_tabs;
332 num_tabs = gtk_notebook_get_n_pages (notebook);
333 last_notebook = (mnb->priv->notebooks->next == NULL);
334
335 if (mnb->priv->total_tabs == 0)
336 {
337 set_active_tab (mnb, NULL);
338 }
339
340 g_signal_emit (G_OBJECT (mnb), signals[TAB_REMOVED], 0, notebook, tab);
341
342 /* Not last notebook but last tab of the notebook, this means we have
343 to remove the current notebook */
344 if (num_tabs == 0 && !mnb->priv->removing_notebook &&
345 !last_notebook)
346 {
347 remove_notebook (mnb, GTK_WIDGET (notebook));
348 }
349
350 update_tabs_visibility (mnb);
351 }
352
353 static void
notebook_page_added(GtkNotebook * notebook,GtkWidget * child,guint page_num,GeditMultiNotebook * mnb)354 notebook_page_added (GtkNotebook *notebook,
355 GtkWidget *child,
356 guint page_num,
357 GeditMultiNotebook *mnb)
358 {
359 GeditTab *tab = GEDIT_TAB (child);
360
361 ++mnb->priv->total_tabs;
362
363 update_tabs_visibility (mnb);
364
365 g_signal_emit (G_OBJECT (mnb), signals[TAB_ADDED], 0, notebook, tab);
366 }
367
368 static void
notebook_switch_page(GtkNotebook * book,GtkWidget * pg,gint page_num,GeditMultiNotebook * mnb)369 notebook_switch_page (GtkNotebook *book,
370 GtkWidget *pg,
371 gint page_num,
372 GeditMultiNotebook *mnb)
373 {
374 GeditTab *tab;
375
376 /* When we switch a tab from a notebook that it is not the active one
377 the switch page is emitted before the set focus, so we do this check
378 and we avoid to call switch page twice */
379 if (GTK_WIDGET (book) != mnb->priv->active_notebook)
380 return;
381
382 /* CHECK: I don't know why but it seems notebook_switch_page is called
383 two times every time the user change the active tab */
384 tab = GEDIT_TAB (gtk_notebook_get_nth_page (book, page_num));
385 if (tab != mnb->priv->active_tab)
386 {
387 GeditTab *old_tab;
388
389 old_tab = mnb->priv->active_tab;
390 set_active_tab (mnb, tab);
391 g_signal_emit (G_OBJECT (mnb), signals[SWITCH_TAB], 0,
392 mnb->priv->active_notebook, old_tab,
393 book, tab);
394 }
395 }
396
397 /* We need to figure out if the any of the internal widget of the notebook
398 has got the focus to set the active notebook */
399 static void
notebook_set_focus(GtkContainer * container,GtkWidget * widget,GeditMultiNotebook * mnb)400 notebook_set_focus (GtkContainer *container,
401 GtkWidget *widget,
402 GeditMultiNotebook *mnb)
403 {
404 if (GEDIT_IS_NOTEBOOK (container) &&
405 GTK_WIDGET (container) != mnb->priv->active_notebook)
406 {
407 gint page_num;
408
409 mnb->priv->active_notebook = GTK_WIDGET (container);
410
411 page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (container));
412 notebook_switch_page (GTK_NOTEBOOK (container), NULL,
413 page_num, mnb);
414
415 g_object_notify_by_pspec (G_OBJECT (mnb), properties[PROP_ACTIVE_NOTEBOOK]);
416 }
417 }
418
419 static void
show_tabs_changed(GObject * object,GParamSpec * pspec,gpointer * data)420 show_tabs_changed (GObject *object,
421 GParamSpec *pspec,
422 gpointer *data)
423 {
424 update_tabs_visibility (GEDIT_MULTI_NOTEBOOK (data));
425 }
426
427 static void
update_tabs_visibility(GeditMultiNotebook * mnb)428 update_tabs_visibility (GeditMultiNotebook *mnb)
429 {
430 gboolean show_tabs;
431 GList *l;
432
433 if (mnb->priv->notebooks == NULL)
434 return;
435
436 if (!mnb->priv->show_tabs)
437 {
438 show_tabs = FALSE;
439 }
440 else if (mnb->priv->notebooks->next == NULL) /* only one notebook */
441 {
442 switch (mnb->priv->show_tabs_mode)
443 {
444 case GEDIT_NOTEBOOK_SHOW_TABS_NEVER:
445 show_tabs = FALSE;
446 break;
447 case GEDIT_NOTEBOOK_SHOW_TABS_AUTO:
448 show_tabs = gtk_notebook_get_n_pages (GTK_NOTEBOOK (mnb->priv->notebooks->data)) > 1;
449 break;
450 case GEDIT_NOTEBOOK_SHOW_TABS_ALWAYS:
451 default:
452 show_tabs = TRUE;
453 break;
454 }
455 }
456 else
457 {
458 show_tabs = (mnb->priv->show_tabs_mode != GEDIT_NOTEBOOK_SHOW_TABS_NEVER);
459 }
460
461 g_signal_handlers_block_by_func (mnb, show_tabs_changed, NULL);
462
463 for (l = mnb->priv->notebooks; l != NULL; l = l->next)
464 {
465 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (l->data), show_tabs);
466 }
467
468 g_signal_handlers_unblock_by_func (mnb, show_tabs_changed, NULL);
469 }
470
471 static void
connect_notebook_signals(GeditMultiNotebook * mnb,GtkWidget * notebook)472 connect_notebook_signals (GeditMultiNotebook *mnb,
473 GtkWidget *notebook)
474 {
475 g_signal_connect (notebook,
476 "set-focus-child",
477 G_CALLBACK (notebook_set_focus),
478 mnb);
479 g_signal_connect (notebook,
480 "page-added",
481 G_CALLBACK (notebook_page_added),
482 mnb);
483 g_signal_connect (notebook,
484 "page-removed",
485 G_CALLBACK (notebook_page_removed),
486 mnb);
487 g_signal_connect (notebook,
488 "switch-page",
489 G_CALLBACK (notebook_switch_page),
490 mnb);
491 g_signal_connect (notebook,
492 "page-reordered",
493 G_CALLBACK (notebook_page_reordered),
494 mnb);
495 g_signal_connect (notebook,
496 "create-window",
497 G_CALLBACK (notebook_create_window),
498 mnb);
499 g_signal_connect (notebook,
500 "tab-close-request",
501 G_CALLBACK (notebook_tab_close_request),
502 mnb);
503 g_signal_connect (notebook,
504 "show-popup-menu",
505 G_CALLBACK (notebook_show_popup_menu),
506 mnb);
507 g_signal_connect (notebook,
508 "notify::show-tabs",
509 G_CALLBACK (show_tabs_changed),
510 mnb);
511 }
512
513 static void
disconnect_notebook_signals(GeditMultiNotebook * mnb,GtkWidget * notebook)514 disconnect_notebook_signals (GeditMultiNotebook *mnb,
515 GtkWidget *notebook)
516 {
517 g_signal_handlers_disconnect_by_func (notebook, notebook_set_focus,
518 mnb);
519 g_signal_handlers_disconnect_by_func (notebook, notebook_switch_page,
520 mnb);
521 g_signal_handlers_disconnect_by_func (notebook, notebook_page_added,
522 mnb);
523 g_signal_handlers_disconnect_by_func (notebook, notebook_page_removed,
524 mnb);
525 g_signal_handlers_disconnect_by_func (notebook, notebook_page_reordered,
526 mnb);
527 g_signal_handlers_disconnect_by_func (notebook, notebook_create_window,
528 mnb);
529 g_signal_handlers_disconnect_by_func (notebook, notebook_tab_close_request,
530 mnb);
531 g_signal_handlers_disconnect_by_func (notebook, notebook_show_popup_menu,
532 mnb);
533 g_signal_handlers_disconnect_by_func (notebook, show_tabs_changed,
534 mnb);
535 }
536
537 static void
add_notebook(GeditMultiNotebook * mnb,GtkWidget * notebook,gboolean main_container)538 add_notebook (GeditMultiNotebook *mnb,
539 GtkWidget *notebook,
540 gboolean main_container)
541 {
542 gtk_widget_set_hexpand (notebook, TRUE);
543 gtk_widget_set_vexpand (notebook, TRUE);
544
545 if (main_container)
546 {
547 gtk_container_add (GTK_CONTAINER (mnb), notebook);
548
549 mnb->priv->notebooks = g_list_append (mnb->priv->notebooks,
550 notebook);
551 }
552 else
553 {
554 GtkWidget *paned;
555 GtkWidget *parent;
556 GtkAllocation allocation;
557 GtkWidget *active_notebook = mnb->priv->active_notebook;
558 gint active_nb_pos;
559
560 paned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
561 gtk_widget_show (paned);
562
563 /* First we remove the active container from its parent to make
564 this we add a ref to it*/
565 g_object_ref (active_notebook);
566 parent = gtk_widget_get_parent (active_notebook);
567 gtk_widget_get_allocation (active_notebook, &allocation);
568
569 gtk_container_remove (GTK_CONTAINER (parent), active_notebook);
570 gtk_container_add (GTK_CONTAINER (parent), paned);
571
572 gtk_paned_pack1 (GTK_PANED (paned), active_notebook, TRUE, FALSE);
573 g_object_unref (active_notebook);
574
575 gtk_paned_pack2 (GTK_PANED (paned), notebook, FALSE, FALSE);
576
577 /* We need to set the new paned in the right place */
578 gtk_paned_set_position (GTK_PANED (paned),
579 allocation.width / 2);
580
581 active_nb_pos = g_list_index (mnb->priv->notebooks,
582 active_notebook);
583 mnb->priv->notebooks = g_list_insert (mnb->priv->notebooks,
584 notebook,
585 active_nb_pos + 1);
586 }
587
588 gtk_widget_show (notebook);
589
590 connect_notebook_signals (mnb, notebook);
591
592 g_signal_emit (G_OBJECT (mnb), signals[NOTEBOOK_ADDED], 0, notebook);
593 }
594
595 static void
remove_notebook(GeditMultiNotebook * mnb,GtkWidget * notebook)596 remove_notebook (GeditMultiNotebook *mnb,
597 GtkWidget *notebook)
598 {
599 GtkWidget *parent;
600 GtkWidget *grandpa;
601 GList *children;
602 GtkWidget *new_notebook;
603 GList *current;
604
605 if (mnb->priv->notebooks->next == NULL)
606 {
607 g_warning ("You are trying to remove the main notebook");
608 return;
609 }
610
611 current = g_list_find (mnb->priv->notebooks,
612 notebook);
613
614 if (current->next != NULL)
615 {
616 new_notebook = GTK_WIDGET (current->next->data);
617 }
618 else
619 {
620 new_notebook = GTK_WIDGET (mnb->priv->notebooks->data);
621 }
622
623 parent = gtk_widget_get_parent (notebook);
624
625 /* Now we destroy the widget, we get the children of parent and we destroy
626 parent too as the parent is an useless paned. Finally we add the child
627 into the grand parent */
628 g_object_ref (notebook);
629 mnb->priv->removing_notebook = TRUE;
630
631 gtk_widget_destroy (notebook);
632
633 mnb->priv->notebooks = g_list_remove (mnb->priv->notebooks,
634 notebook);
635
636 mnb->priv->removing_notebook = FALSE;
637
638 children = gtk_container_get_children (GTK_CONTAINER (parent));
639 if (children->next != NULL)
640 {
641 g_warning ("The parent is not a paned");
642 return;
643 }
644 grandpa = gtk_widget_get_parent (parent);
645
646 g_object_ref (children->data);
647 gtk_container_remove (GTK_CONTAINER (parent),
648 GTK_WIDGET (children->data));
649 gtk_widget_destroy (parent);
650 gtk_container_add (GTK_CONTAINER (grandpa),
651 GTK_WIDGET (children->data));
652 g_object_unref (children->data);
653 g_list_free (children);
654
655 disconnect_notebook_signals (mnb, notebook);
656
657 g_signal_emit (G_OBJECT (mnb), signals[NOTEBOOK_REMOVED], 0, notebook);
658 g_object_unref (notebook);
659
660 /* Let's make the active notebook grab the focus */
661 gtk_widget_grab_focus (new_notebook);
662 }
663
664 static void
gedit_multi_notebook_init(GeditMultiNotebook * mnb)665 gedit_multi_notebook_init (GeditMultiNotebook *mnb)
666 {
667 GeditMultiNotebookPrivate *priv;
668
669 mnb->priv = gedit_multi_notebook_get_instance_private (mnb);
670 priv = mnb->priv;
671
672 priv->removing_notebook = FALSE;
673
674 gtk_orientable_set_orientation (GTK_ORIENTABLE (mnb),
675 GTK_ORIENTATION_VERTICAL);
676
677 priv->show_tabs_mode = GEDIT_NOTEBOOK_SHOW_TABS_ALWAYS;
678 priv->show_tabs = TRUE;
679
680 priv->ui_settings = g_settings_new ("org.gnome.gedit.preferences.ui");
681 g_settings_bind (priv->ui_settings,
682 GEDIT_SETTINGS_SHOW_TABS_MODE,
683 mnb,
684 "show-tabs-mode",
685 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
686
687 priv->active_notebook = gedit_notebook_new ();
688 add_notebook (mnb, priv->active_notebook, TRUE);
689 }
690
691 GeditMultiNotebook *
gedit_multi_notebook_new()692 gedit_multi_notebook_new ()
693 {
694 return g_object_new (GEDIT_TYPE_MULTI_NOTEBOOK, NULL);
695 }
696
697 GeditNotebook *
gedit_multi_notebook_get_active_notebook(GeditMultiNotebook * mnb)698 gedit_multi_notebook_get_active_notebook (GeditMultiNotebook *mnb)
699 {
700 g_return_val_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb), NULL);
701
702 return GEDIT_NOTEBOOK (mnb->priv->active_notebook);
703 }
704
705 gint
gedit_multi_notebook_get_n_notebooks(GeditMultiNotebook * mnb)706 gedit_multi_notebook_get_n_notebooks (GeditMultiNotebook *mnb)
707 {
708 g_return_val_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb), 0);
709
710 return g_list_length (mnb->priv->notebooks);
711 }
712
713 GeditNotebook *
gedit_multi_notebook_get_nth_notebook(GeditMultiNotebook * mnb,gint notebook_num)714 gedit_multi_notebook_get_nth_notebook (GeditMultiNotebook *mnb,
715 gint notebook_num)
716 {
717 g_return_val_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb), NULL);
718
719 return g_list_nth_data (mnb->priv->notebooks, notebook_num);
720 }
721
722 GeditNotebook *
gedit_multi_notebook_get_notebook_for_tab(GeditMultiNotebook * mnb,GeditTab * tab)723 gedit_multi_notebook_get_notebook_for_tab (GeditMultiNotebook *mnb,
724 GeditTab *tab)
725 {
726 GList *l;
727 gint page_num;
728
729 g_return_val_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb), NULL);
730 g_return_val_if_fail (GEDIT_IS_TAB (tab), NULL);
731
732 l = mnb->priv->notebooks;
733
734 do
735 {
736 page_num = gtk_notebook_page_num (GTK_NOTEBOOK (l->data),
737 GTK_WIDGET (tab));
738 if (page_num != -1)
739 break;
740
741 l = g_list_next (l);
742 } while (l != NULL && page_num == -1);
743
744 g_return_val_if_fail (page_num != -1, NULL);
745
746 return GEDIT_NOTEBOOK (l->data);
747 }
748
749 gint
gedit_multi_notebook_get_notebook_num(GeditMultiNotebook * mnb,GeditNotebook * notebook)750 gedit_multi_notebook_get_notebook_num (GeditMultiNotebook *mnb,
751 GeditNotebook *notebook)
752 {
753 g_return_val_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb), -1);
754 g_return_val_if_fail (GEDIT_IS_NOTEBOOK (notebook), -1);
755
756 return g_list_index (mnb->priv->notebooks, notebook);
757 }
758
759 gint
gedit_multi_notebook_get_n_tabs(GeditMultiNotebook * mnb)760 gedit_multi_notebook_get_n_tabs (GeditMultiNotebook *mnb)
761 {
762 g_return_val_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb), 0);
763
764 return mnb->priv->total_tabs;
765 }
766
767 gint
gedit_multi_notebook_get_page_num(GeditMultiNotebook * mnb,GeditTab * tab)768 gedit_multi_notebook_get_page_num (GeditMultiNotebook *mnb,
769 GeditTab *tab)
770 {
771 GList *l;
772 gint real_page_num = 0;
773
774 for (l = mnb->priv->notebooks; l != NULL; l = g_list_next (l))
775 {
776 gint page_num;
777
778 page_num = gtk_notebook_page_num (GTK_NOTEBOOK (l->data),
779 GTK_WIDGET (tab));
780
781 if (page_num != -1)
782 {
783 real_page_num += page_num;
784 break;
785 }
786
787 real_page_num += gtk_notebook_get_n_pages (GTK_NOTEBOOK (l->data));
788 }
789
790 return real_page_num;
791 }
792
793 GeditTab *
gedit_multi_notebook_get_active_tab(GeditMultiNotebook * mnb)794 gedit_multi_notebook_get_active_tab (GeditMultiNotebook *mnb)
795 {
796 g_return_val_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb), NULL);
797
798 return (mnb->priv->active_tab == NULL) ?
799 NULL : GEDIT_TAB (mnb->priv->active_tab);
800 }
801
802 void
gedit_multi_notebook_set_active_tab(GeditMultiNotebook * mnb,GeditTab * tab)803 gedit_multi_notebook_set_active_tab (GeditMultiNotebook *mnb,
804 GeditTab *tab)
805 {
806 GList *l;
807 gint page_num;
808
809 g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb));
810 g_return_if_fail (GEDIT_IS_TAB (tab) || tab == NULL);
811
812 /* use plain C cast since the active tab can be null */
813 if (tab == (GeditTab *) mnb->priv->active_tab)
814 {
815 return;
816 }
817
818 if (tab == NULL)
819 {
820 set_active_tab (mnb, NULL);
821 return;
822 }
823
824 l = mnb->priv->notebooks;
825
826 do
827 {
828 page_num = gtk_notebook_page_num (GTK_NOTEBOOK (l->data),
829 GTK_WIDGET (tab));
830 if (page_num != -1)
831 break;
832
833 l = g_list_next (l);
834 } while (l != NULL && page_num == -1);
835
836 g_return_if_fail (page_num != -1);
837
838 gtk_notebook_set_current_page (GTK_NOTEBOOK (l->data), page_num);
839
840 if (GTK_WIDGET (l->data) != mnb->priv->active_notebook)
841 {
842 gtk_widget_grab_focus (GTK_WIDGET (l->data));
843 }
844 }
845
846 void
gedit_multi_notebook_set_current_page(GeditMultiNotebook * mnb,gint page_num)847 gedit_multi_notebook_set_current_page (GeditMultiNotebook *mnb,
848 gint page_num)
849 {
850 GList *l;
851 gint pages = 0;
852 gint single_num = page_num;
853
854 g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb));
855
856 for (l = mnb->priv->notebooks; l != NULL; l = g_list_next (l))
857 {
858 gint p;
859
860 p = gtk_notebook_get_n_pages (GTK_NOTEBOOK (l->data));
861 pages += p;
862
863 if ((pages - 1) >= page_num)
864 break;
865
866 single_num -= p;
867 }
868
869 if (l == NULL)
870 return;
871
872 if (GTK_WIDGET (l->data) != mnb->priv->active_notebook)
873 {
874 gtk_widget_grab_focus (GTK_WIDGET (l->data));
875 }
876
877 gtk_notebook_set_current_page (GTK_NOTEBOOK (l->data), single_num);
878 }
879
880 GList *
gedit_multi_notebook_get_all_tabs(GeditMultiNotebook * mnb)881 gedit_multi_notebook_get_all_tabs (GeditMultiNotebook *mnb)
882 {
883 GList *nbs;
884 GList *ret = NULL;
885
886 g_return_val_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb), NULL);
887
888 for (nbs = mnb->priv->notebooks; nbs != NULL; nbs = g_list_next (nbs))
889 {
890 GList *l, *children;
891
892 children = gtk_container_get_children (GTK_CONTAINER (nbs->data));
893
894 for (l = children; l != NULL; l = g_list_next (l))
895 {
896 ret = g_list_prepend (ret, l->data);
897 }
898
899 g_list_free (children);
900 }
901
902 ret = g_list_reverse (ret);
903
904 return ret;
905 }
906
907 void
gedit_multi_notebook_close_tabs(GeditMultiNotebook * mnb,const GList * tabs)908 gedit_multi_notebook_close_tabs (GeditMultiNotebook *mnb,
909 const GList *tabs)
910 {
911 GList *l;
912
913 g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb));
914
915 for (l = (GList *)tabs; l != NULL; l = g_list_next (l))
916 {
917 GList *nbs;
918
919 for (nbs = mnb->priv->notebooks; nbs != NULL; nbs = g_list_next (nbs))
920 {
921 gint n;
922
923 n = gtk_notebook_page_num (GTK_NOTEBOOK (nbs->data),
924 GTK_WIDGET (l->data));
925
926 if (n != -1)
927 {
928 gtk_container_remove (GTK_CONTAINER (nbs->data),
929 GTK_WIDGET (l->data));
930 break;
931 }
932 }
933 }
934 }
935
936 /**
937 * gedit_multi_notebook_close_all_tabs:
938 * @mnb: a #GeditMultiNotebook
939 *
940 * Closes all opened tabs.
941 */
942 void
gedit_multi_notebook_close_all_tabs(GeditMultiNotebook * mnb)943 gedit_multi_notebook_close_all_tabs (GeditMultiNotebook *mnb)
944 {
945 GList *nbs, *l;
946
947 g_return_if_fail (GEDIT_MULTI_NOTEBOOK (mnb));
948
949 /* We copy the list because the main one is going to have the items
950 removed */
951 nbs = g_list_copy (mnb->priv->notebooks);
952
953 for (l = nbs; l != NULL; l = g_list_next (l))
954 {
955 gedit_notebook_remove_all_tabs (GEDIT_NOTEBOOK (l->data));
956 }
957
958 g_list_free (nbs);
959 }
960
961 void
gedit_multi_notebook_add_new_notebook(GeditMultiNotebook * mnb)962 gedit_multi_notebook_add_new_notebook (GeditMultiNotebook *mnb)
963 {
964 GtkWidget *notebook;
965 GeditTab *tab;
966
967 g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb));
968
969 notebook = gedit_notebook_new ();
970 add_notebook (mnb, notebook, FALSE);
971
972 tab = _gedit_tab_new ();
973 gtk_widget_show (GTK_WIDGET (tab));
974
975 /* When gtk_notebook_insert_page is called the focus is set in
976 the notebook, we don't want this to happen until the page is added.
977 Also we don't want to call switch_page when we add the tab
978 but when we switch the notebook. */
979 g_signal_handlers_block_by_func (notebook, notebook_set_focus, mnb);
980 g_signal_handlers_block_by_func (notebook, notebook_switch_page, mnb);
981
982 gedit_notebook_add_tab (GEDIT_NOTEBOOK (notebook),
983 tab,
984 -1,
985 TRUE);
986
987 g_signal_handlers_unblock_by_func (notebook, notebook_switch_page, mnb);
988 g_signal_handlers_unblock_by_func (notebook, notebook_set_focus, mnb);
989
990 notebook_set_focus (GTK_CONTAINER (notebook), NULL, mnb);
991 }
992
993 void
gedit_multi_notebook_add_new_notebook_with_tab(GeditMultiNotebook * mnb,GeditTab * tab)994 gedit_multi_notebook_add_new_notebook_with_tab (GeditMultiNotebook *mnb,
995 GeditTab *tab)
996 {
997 GtkWidget *notebook;
998 GeditNotebook *old_notebook;
999
1000 g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb));
1001 g_return_if_fail (GEDIT_IS_TAB (tab));
1002
1003 notebook = gedit_notebook_new ();
1004 add_notebook (mnb, notebook, FALSE);
1005
1006 old_notebook = gedit_multi_notebook_get_notebook_for_tab (mnb, tab);
1007
1008 /* When gtk_notebook_insert_page is called the focus is set in
1009 the notebook, we don't want this to happen until the page is added.
1010 Also we don't want to call switch_page when we add the tab
1011 but when we switch the notebook. */
1012 g_signal_handlers_block_by_func (old_notebook, notebook_set_focus, mnb);
1013 g_signal_handlers_block_by_func (old_notebook, notebook_switch_page, mnb);
1014
1015 gedit_notebook_move_tab (old_notebook,
1016 GEDIT_NOTEBOOK (notebook),
1017 tab,
1018 -1);
1019
1020 g_signal_handlers_unblock_by_func (old_notebook, notebook_switch_page, mnb);
1021 g_signal_handlers_unblock_by_func (old_notebook, notebook_set_focus, mnb);
1022
1023 notebook_set_focus (GTK_CONTAINER (notebook), NULL, mnb);
1024 }
1025
1026 void
gedit_multi_notebook_remove_active_notebook(GeditMultiNotebook * mnb)1027 gedit_multi_notebook_remove_active_notebook (GeditMultiNotebook *mnb)
1028 {
1029 g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb));
1030
1031 gedit_notebook_remove_all_tabs (GEDIT_NOTEBOOK (mnb->priv->active_notebook));
1032 }
1033
1034 void
gedit_multi_notebook_previous_notebook(GeditMultiNotebook * mnb)1035 gedit_multi_notebook_previous_notebook (GeditMultiNotebook *mnb)
1036 {
1037 GList *current;
1038 GtkWidget *notebook;
1039
1040 g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb));
1041
1042 current = g_list_find (mnb->priv->notebooks,
1043 mnb->priv->active_notebook);
1044
1045 if (current->prev != NULL)
1046 notebook = GTK_WIDGET (current->prev->data);
1047 else
1048 notebook = GTK_WIDGET (g_list_last (mnb->priv->notebooks)->data);
1049
1050 gtk_widget_grab_focus (notebook);
1051 }
1052
1053 void
gedit_multi_notebook_next_notebook(GeditMultiNotebook * mnb)1054 gedit_multi_notebook_next_notebook (GeditMultiNotebook *mnb)
1055 {
1056 GList *current;
1057 GtkWidget *notebook;
1058
1059 g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb));
1060
1061 current = g_list_find (mnb->priv->notebooks,
1062 mnb->priv->active_notebook);
1063
1064 if (current->next != NULL)
1065 notebook = GTK_WIDGET (current->next->data);
1066 else
1067 notebook = GTK_WIDGET (mnb->priv->notebooks->data);
1068
1069 gtk_widget_grab_focus (notebook);
1070 }
1071
1072 void
gedit_multi_notebook_foreach_notebook(GeditMultiNotebook * mnb,GtkCallback callback,gpointer callback_data)1073 gedit_multi_notebook_foreach_notebook (GeditMultiNotebook *mnb,
1074 GtkCallback callback,
1075 gpointer callback_data)
1076 {
1077 GList *l;
1078
1079 g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb));
1080
1081 for (l = mnb->priv->notebooks; l != NULL; l = g_list_next (l))
1082 {
1083 callback (GTK_WIDGET (l->data), callback_data);
1084 }
1085 }
1086
1087 void
gedit_multi_notebook_foreach_tab(GeditMultiNotebook * mnb,GtkCallback callback,gpointer callback_data)1088 gedit_multi_notebook_foreach_tab (GeditMultiNotebook *mnb,
1089 GtkCallback callback,
1090 gpointer callback_data)
1091 {
1092 GList *nb;
1093
1094 g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb));
1095
1096 for (nb = mnb->priv->notebooks; nb != NULL; nb = g_list_next (nb))
1097 {
1098 GList *l, *children;
1099
1100 children = gtk_container_get_children (GTK_CONTAINER (nb->data));
1101
1102 for (l = children; l != NULL; l = g_list_next (l))
1103 {
1104 callback (GTK_WIDGET (l->data), callback_data);
1105 }
1106
1107 g_list_free (children);
1108 }
1109 }
1110
1111 /* We only use this to hide tabs in fullscreen mode so for now
1112 * we do not have a real property etc.
1113 */
1114 void
_gedit_multi_notebook_set_show_tabs(GeditMultiNotebook * mnb,gboolean show)1115 _gedit_multi_notebook_set_show_tabs (GeditMultiNotebook *mnb,
1116 gboolean show)
1117 {
1118 g_return_if_fail (GEDIT_IS_MULTI_NOTEBOOK (mnb));
1119
1120 mnb->priv->show_tabs = show != FALSE;
1121
1122 update_tabs_visibility (mnb);
1123 }
1124
1125 /* ex:set ts=8 noet: */
1126