Update of Italian translation
[geany-mirror.git] / src / notebook.c
blobcea60e82987bdcc1cfada86223e2b22a2aabf5f0
1 /*
2 * notebook.c - this file is part of Geany, a fast and lightweight IDE
4 * Copyright 2006-2012 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
5 * Copyright 2006-2012 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
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.
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.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 * Notebook tab Drag 'n' Drop reordering and tab management.
26 #include "geany.h"
28 #include <gdk/gdkkeysyms.h>
30 #include "notebook.h"
31 #include "document.h"
32 #include "editor.h"
33 #include "documentprivate.h"
34 #include "ui_utils.h"
35 #include "sidebar.h"
36 #include "support.h"
37 #include "callbacks.h"
38 #include "utils.h"
39 #include "keybindings.h"
40 #include "main.h"
41 #include "gtkcompat.h"
43 #define GEANY_DND_NOTEBOOK_TAB_TYPE "geany_dnd_notebook_tab"
45 static const GtkTargetEntry drag_targets[] =
47 {GEANY_DND_NOTEBOOK_TAB_TYPE, GTK_TARGET_SAME_APP | GTK_TARGET_SAME_WIDGET, 0}
50 static GtkTargetEntry files_drop_targets[] = {
51 { "STRING", 0, 0 },
52 { "UTF8_STRING", 0, 0 },
53 { "text/plain", 0, 0 },
54 { "text/uri-list", 0, 0 }
57 static const gsize MAX_MRU_DOCS = 20;
58 static GQueue *mru_docs = NULL;
59 static guint mru_pos = 0;
61 static gboolean switch_in_progress = FALSE;
62 static GtkWidget *switch_dialog = NULL;
63 static GtkWidget *switch_dialog_label = NULL;
66 static void
67 notebook_page_reordered_cb(GtkNotebook *notebook, GtkWidget *child, guint page_num,
68 gpointer user_data);
70 static void
71 on_window_drag_data_received(GtkWidget *widget, GdkDragContext *drag_context,
72 gint x, gint y, GtkSelectionData *data, guint target_type,
73 guint event_time, gpointer user_data);
75 static void
76 notebook_tab_close_clicked_cb(GtkButton *button, gpointer user_data);
78 static void setup_tab_dnd(void);
81 static void update_mru_docs_head(GeanyDocument *doc)
83 if (doc)
85 g_queue_remove(mru_docs, doc);
86 g_queue_push_head(mru_docs, doc);
88 if (g_queue_get_length(mru_docs) > MAX_MRU_DOCS)
89 g_queue_pop_tail(mru_docs);
94 /* before the tab changes, add the current document to the MRU list */
95 static void on_notebook_switch_page(GtkNotebook *notebook,
96 gpointer page, guint page_num, gpointer user_data)
98 GeanyDocument *new;
100 new = document_get_from_page(page_num);
102 /* insert the very first document (when adding the second document
103 * and switching to it) */
104 if (g_queue_get_length(mru_docs) == 0 && gtk_notebook_get_n_pages(notebook) == 2)
105 update_mru_docs_head(document_get_current());
107 if (!switch_in_progress)
108 update_mru_docs_head(new);
112 static void on_document_close(GObject *obj, GeanyDocument *doc)
114 if (! main_status.quitting)
116 g_queue_remove(mru_docs, doc);
117 /* this prevents the pop up window from showing when there's a single
118 * document */
119 if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(main_widgets.notebook)) == 2)
120 g_queue_clear(mru_docs);
125 static GtkWidget *ui_minimal_dialog_new(GtkWindow *parent, const gchar *title)
127 GtkWidget *dialog;
129 dialog = gtk_window_new(GTK_WINDOW_POPUP);
131 if (parent)
133 gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);
134 gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE);
136 gtk_window_set_title(GTK_WINDOW(dialog), title);
137 gtk_window_set_type_hint(GTK_WINDOW(dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
138 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
140 gtk_widget_set_name(dialog, "GeanyDialog");
141 return dialog;
145 static gboolean is_modifier_key(guint keyval)
147 switch (keyval)
149 case GDK_Shift_L:
150 case GDK_Shift_R:
151 case GDK_Control_L:
152 case GDK_Control_R:
153 case GDK_Meta_L:
154 case GDK_Meta_R:
155 case GDK_Alt_L:
156 case GDK_Alt_R:
157 case GDK_Super_L:
158 case GDK_Super_R:
159 case GDK_Hyper_L:
160 case GDK_Hyper_R:
161 return TRUE;
162 default:
163 return FALSE;
168 static gboolean on_key_release_event(GtkWidget *widget, GdkEventKey *ev, gpointer user_data)
170 /* user may have rebound keybinding to a different modifier than Ctrl, so check all */
171 if (switch_in_progress && is_modifier_key(ev->keyval))
173 GeanyDocument *doc;
175 switch_in_progress = FALSE;
177 if (switch_dialog)
179 gtk_widget_destroy(switch_dialog);
180 switch_dialog = NULL;
183 doc = document_get_current();
184 update_mru_docs_head(doc);
185 mru_pos = 0;
186 document_check_disk_status(doc, TRUE);
188 return FALSE;
192 static GtkWidget *create_switch_dialog(void)
194 GtkWidget *dialog, *widget, *vbox;
196 dialog = ui_minimal_dialog_new(GTK_WINDOW(main_widgets.window), _("Switch to Document"));
197 gtk_window_set_decorated(GTK_WINDOW(dialog), FALSE);
198 gtk_window_set_default_size(GTK_WINDOW(dialog), 200, -1);
200 vbox = gtk_vbox_new(FALSE, 6);
201 gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
202 gtk_container_add(GTK_CONTAINER(dialog), vbox);
204 widget = gtk_image_new_from_stock(GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_BUTTON);
205 gtk_container_add(GTK_CONTAINER(vbox), widget);
207 widget = gtk_label_new(NULL);
208 gtk_label_set_justify(GTK_LABEL(widget), GTK_JUSTIFY_CENTER);
209 gtk_container_add(GTK_CONTAINER(vbox), widget);
210 switch_dialog_label = widget;
212 g_signal_connect(dialog, "key-release-event", G_CALLBACK(on_key_release_event), NULL);
213 return dialog;
217 static void update_filename_label(void)
219 guint i;
220 gchar *msg = NULL;
221 guint queue_length;
222 GeanyDocument *doc;
224 if (!switch_dialog)
226 switch_dialog = create_switch_dialog();
227 gtk_widget_show_all(switch_dialog);
230 queue_length = g_queue_get_length(mru_docs);
231 for (i = mru_pos; (i <= mru_pos + 3) && (doc = g_queue_peek_nth(mru_docs, i % queue_length)); i++)
233 gchar *basename;
235 basename = g_path_get_basename(DOC_FILENAME(doc));
236 if (i == mru_pos)
237 msg = g_markup_printf_escaped ("<b>%s</b>", basename);
238 else if (i % queue_length == mru_pos) /* && i != mru_pos */
240 /* We have wrapped around and got to the starting document again */
241 g_free(basename);
242 break;
244 else
246 SETPTR(basename, g_markup_printf_escaped ("\n%s", basename));
247 SETPTR(msg, g_strconcat(msg, basename, NULL));
249 g_free(basename);
251 gtk_label_set_markup(GTK_LABEL(switch_dialog_label), msg);
252 g_free(msg);
256 static gboolean on_switch_timeout(G_GNUC_UNUSED gpointer data)
258 if (!switch_in_progress || switch_dialog)
260 return FALSE;
263 update_filename_label();
264 return FALSE;
268 void notebook_switch_tablastused(void)
270 GeanyDocument *last_doc;
271 gboolean switch_start = !switch_in_progress;
273 mru_pos += 1;
274 last_doc = g_queue_peek_nth(mru_docs, mru_pos);
276 if (! DOC_VALID(last_doc))
278 utils_beep();
279 mru_pos = 0;
280 last_doc = g_queue_peek_nth(mru_docs, mru_pos);
282 if (! DOC_VALID(last_doc))
283 return;
285 switch_in_progress = TRUE;
286 document_show_tab(last_doc);
288 /* if there's a modifier key, we can switch back in MRU order each time unless
289 * the key is released */
290 if (switch_start)
291 g_timeout_add(600, on_switch_timeout, NULL);
292 else
293 update_filename_label();
297 gboolean notebook_switch_in_progress(void)
299 return switch_in_progress;
303 static gboolean focus_sci(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
305 GeanyDocument *doc = document_get_current();
307 if (doc != NULL && event->button == 1)
308 gtk_widget_grab_focus(GTK_WIDGET(doc->editor->sci));
310 return FALSE;
314 static gboolean gtk_notebook_show_arrows(GtkNotebook *notebook)
316 return gtk_notebook_get_scrollable(notebook);
317 #if 0
318 /* To get this working we would need to define at least the first two fields of
319 * GtkNotebookPage since it is a private field. The better way would be to
320 * subclass GtkNotebook.
321 struct _FakeGtkNotebookPage
323 GtkWidget *child;
324 GtkWidget *tab_label;
327 gboolean show_arrow = FALSE;
328 GList *children;
330 if (! notebook->scrollable)
331 return FALSE;
333 children = notebook->children;
334 while (children)
336 struct _FakeGtkNotebookPage *page = children->data;
338 if (page->tab_label && ! gtk_widget_get_child_visible(page->tab_label))
339 show_arrow = TRUE;
341 children = children->next;
343 return show_arrow;
344 #endif
348 static gboolean is_position_on_tab_bar(GtkNotebook *notebook, GdkEventButton *event)
350 GtkWidget *page;
351 GtkWidget *tab;
352 GtkWidget *nb;
353 GtkPositionType tab_pos;
354 gint scroll_arrow_hlength, scroll_arrow_vlength;
355 gdouble x, y;
357 page = gtk_notebook_get_nth_page(notebook, 0);
358 g_return_val_if_fail(page != NULL, FALSE);
360 tab = gtk_notebook_get_tab_label(notebook, page);
361 g_return_val_if_fail(tab != NULL, FALSE);
363 tab_pos = gtk_notebook_get_tab_pos(notebook);
364 nb = GTK_WIDGET(notebook);
366 gtk_widget_style_get(GTK_WIDGET(notebook), "scroll-arrow-hlength", &scroll_arrow_hlength,
367 "scroll-arrow-vlength", &scroll_arrow_vlength, NULL);
369 if (! gdk_event_get_coords((GdkEvent*) event, &x, &y))
371 x = event->x;
372 y = event->y;
375 switch (tab_pos)
377 case GTK_POS_TOP:
378 case GTK_POS_BOTTOM:
380 if (event->y >= 0 && event->y <= gtk_widget_get_allocated_height(tab))
382 if (! gtk_notebook_show_arrows(notebook) || (
383 x > scroll_arrow_hlength &&
384 x < gtk_widget_get_allocated_width(nb) - scroll_arrow_hlength))
385 return TRUE;
387 break;
389 case GTK_POS_LEFT:
390 case GTK_POS_RIGHT:
392 if (event->x >= 0 && event->x <= gtk_widget_get_allocated_width(tab))
394 if (! gtk_notebook_show_arrows(notebook) || (
395 y > scroll_arrow_vlength &&
396 y < gtk_widget_get_allocated_height(nb) - scroll_arrow_vlength))
397 return TRUE;
402 return FALSE;
406 static void tab_bar_menu_activate_cb(GtkMenuItem *menuitem, gpointer data)
408 GeanyDocument *doc = data;
410 if (! DOC_VALID(doc))
411 return;
413 document_show_tab(doc);
417 static void on_open_in_new_window_activate(GtkMenuItem *menuitem, gpointer user_data)
419 gchar *geany_path;
420 GeanyDocument *doc = user_data;
422 g_return_if_fail(doc->is_valid);
424 geany_path = g_find_program_in_path("geany");
426 if (geany_path)
428 gchar *doc_path = utils_get_locale_from_utf8(doc->file_name);
429 gchar *argv[] = {geany_path, "-i", doc_path, NULL};
430 GError *err = NULL;
432 if (!utils_spawn_async(NULL, argv, NULL, 0, NULL, NULL, NULL, &err))
434 g_printerr("Unable to open new window: %s", err->message);
435 g_error_free(err);
437 g_free(doc_path);
438 g_free(geany_path);
440 else
441 g_printerr("Unable to find 'geany'");
445 static void show_tab_bar_popup_menu(GdkEventButton *event, GtkWidget *page)
447 GtkWidget *menu_item;
448 static GtkWidget *menu = NULL;
449 GeanyDocument *doc = NULL;
450 gint page_num;
452 if (menu == NULL)
453 menu = gtk_menu_new();
455 /* clear the old menu items */
456 gtk_container_foreach(GTK_CONTAINER(menu), (GtkCallback) gtk_widget_destroy, NULL);
458 ui_menu_add_document_items(GTK_MENU(menu), document_get_current(),
459 G_CALLBACK(tab_bar_menu_activate_cb));
461 menu_item = gtk_separator_menu_item_new();
462 gtk_widget_show(menu_item);
463 gtk_container_add(GTK_CONTAINER(menu), menu_item);
465 if (page != NULL)
467 page_num = gtk_notebook_page_num(GTK_NOTEBOOK(main_widgets.notebook), page);
468 doc = document_get_from_page(page_num);
471 menu_item = ui_image_menu_item_new(GTK_STOCK_OPEN, "Open in New _Window");
472 gtk_widget_show(menu_item);
473 gtk_container_add(GTK_CONTAINER(menu), menu_item);
474 g_signal_connect(menu_item, "activate",
475 G_CALLBACK(on_open_in_new_window_activate), doc);
476 /* disable if not on disk */
477 if (doc == NULL || !doc->real_path)
478 gtk_widget_set_sensitive(menu_item, FALSE);
480 menu_item = gtk_separator_menu_item_new();
481 gtk_widget_show(menu_item);
482 gtk_container_add(GTK_CONTAINER(menu), menu_item);
484 menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CLOSE, NULL);
485 gtk_widget_show(menu_item);
486 gtk_container_add(GTK_CONTAINER(menu), menu_item);
487 g_signal_connect(menu_item, "activate", G_CALLBACK(notebook_tab_close_clicked_cb), page);
488 gtk_widget_set_sensitive(GTK_WIDGET(menu_item), (page != NULL));
490 menu_item = ui_image_menu_item_new(GTK_STOCK_CLOSE, _("Close Ot_her Documents"));
491 gtk_widget_show(menu_item);
492 gtk_container_add(GTK_CONTAINER(menu), menu_item);
493 g_signal_connect(menu_item, "activate", G_CALLBACK(on_close_other_documents1_activate), page);
494 gtk_widget_set_sensitive(GTK_WIDGET(menu_item), (page != NULL));
496 menu_item = ui_image_menu_item_new(GTK_STOCK_CLOSE, _("C_lose All"));
497 gtk_widget_show(menu_item);
498 gtk_container_add(GTK_CONTAINER(menu), menu_item);
499 g_signal_connect(menu_item, "activate", G_CALLBACK(on_close_all1_activate), NULL);
501 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time);
505 static gboolean notebook_tab_bar_click_cb(GtkWidget *widget, GdkEventButton *event,
506 gpointer user_data)
508 if (event->type == GDK_2BUTTON_PRESS)
510 GtkNotebook *notebook = GTK_NOTEBOOK(widget);
511 GtkWidget *event_widget = gtk_get_event_widget((GdkEvent *) event);
512 GtkWidget *child = gtk_notebook_get_nth_page(notebook, gtk_notebook_get_current_page(notebook));
514 /* ignore events from the content of the page (impl. stolen from GTK2 tab scrolling)
515 * TODO: we should also ignore notebook's action widgets, but that's more work and
516 * we don't have any of them yet anyway -- and GTK 2.16 don't have those actions. */
517 if (event_widget == NULL || event_widget == child || gtk_widget_is_ancestor(event_widget, child))
518 return FALSE;
520 if (is_position_on_tab_bar(notebook, event))
522 document_new_file(NULL, NULL, NULL);
523 return TRUE;
526 /* right-click is also handled here if it happened on the notebook tab bar but not
527 * on a tab directly */
528 else if (event->button == 3)
530 show_tab_bar_popup_menu(event, NULL);
531 return TRUE;
533 return FALSE;
537 void notebook_init()
539 g_signal_connect_after(main_widgets.notebook, "button-press-event",
540 G_CALLBACK(notebook_tab_bar_click_cb), NULL);
542 g_signal_connect(main_widgets.notebook, "drag-data-received",
543 G_CALLBACK(on_window_drag_data_received), NULL);
545 mru_docs = g_queue_new();
546 g_signal_connect(main_widgets.notebook, "switch-page",
547 G_CALLBACK(on_notebook_switch_page), NULL);
548 g_signal_connect(geany_object, "document-close",
549 G_CALLBACK(on_document_close), NULL);
551 /* in case the switch dialog misses an event while drawing the dialog */
552 g_signal_connect(main_widgets.window, "key-release-event", G_CALLBACK(on_key_release_event), NULL);
554 setup_tab_dnd();
558 void notebook_free(void)
560 g_queue_free(mru_docs);
564 static void setup_tab_dnd()
566 GtkWidget *notebook = main_widgets.notebook;
568 g_signal_connect(notebook, "page-reordered", G_CALLBACK(notebook_page_reordered_cb), NULL);
572 static void
573 notebook_page_reordered_cb(GtkNotebook *notebook, GtkWidget *child, guint page_num,
574 gpointer user_data)
576 /* Not necessary to update open files treeview if it's sorted.
577 * Note: if enabled, it's best to move the item instead of recreating all items. */
578 /*sidebar_openfiles_update_all();*/
582 /* call this after the number of tabs in main_widgets.notebook changes. */
583 static void tab_count_changed(void)
585 switch (gtk_notebook_get_n_pages(GTK_NOTEBOOK(main_widgets.notebook)))
587 case 0:
588 /* Enables DnD for dropping files into the empty notebook widget */
589 gtk_drag_dest_set(main_widgets.notebook, GTK_DEST_DEFAULT_ALL,
590 files_drop_targets, G_N_ELEMENTS(files_drop_targets),
591 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK);
592 break;
594 case 1:
595 /* Disables DnD for dropping files into the notebook widget and enables the DnD for moving file
596 * tabs. Files can still be dropped into the notebook widget because it will be handled by the
597 * active Scintilla Widget (only dropping to the tab bar is not possible but it should be ok) */
598 gtk_drag_dest_set(main_widgets.notebook, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
599 drag_targets, G_N_ELEMENTS(drag_targets), GDK_ACTION_MOVE);
600 break;
605 static gboolean notebook_tab_click(GtkWidget *widget, GdkEventButton *event, gpointer data)
607 guint state;
609 /* toggle additional widgets on double click */
610 if (event->type == GDK_2BUTTON_PRESS)
612 if (interface_prefs.notebook_double_click_hides_widgets)
613 on_menu_toggle_all_additional_widgets1_activate(NULL, NULL);
615 return TRUE; /* stop other handlers like notebook_tab_bar_click_cb() */
617 /* close tab on middle click */
618 if (event->button == 2)
620 document_remove_page(gtk_notebook_page_num(GTK_NOTEBOOK(main_widgets.notebook),
621 GTK_WIDGET(data)));
622 return TRUE; /* stop other handlers like notebook_tab_bar_click_cb() */
624 /* switch last used tab on ctrl-click */
625 state = event->state & gtk_accelerator_get_default_mod_mask();
626 if (event->button == 1 && state == GDK_CONTROL_MASK)
628 keybindings_send_command(GEANY_KEY_GROUP_NOTEBOOK,
629 GEANY_KEYS_NOTEBOOK_SWITCHTABLASTUSED);
630 return TRUE;
632 /* right-click is first handled here if it happened on a notebook tab */
633 if (event->button == 3)
635 show_tab_bar_popup_menu(event, data);
636 return TRUE;
639 return FALSE;
643 static void notebook_tab_close_button_style_set(GtkWidget *btn, GtkRcStyle *prev_style,
644 gpointer data)
646 gint w, h;
648 gtk_icon_size_lookup_for_settings(gtk_widget_get_settings(btn), GTK_ICON_SIZE_MENU, &w, &h);
649 gtk_widget_set_size_request(btn, w + 2, h + 2);
653 /* Returns page number of notebook page, or -1 on error */
654 gint notebook_new_tab(GeanyDocument *this)
656 GtkWidget *hbox, *ebox;
657 gint tabnum;
658 GtkWidget *page;
659 gint cur_page;
661 g_return_val_if_fail(this != NULL, -1);
663 page = GTK_WIDGET(this->editor->sci);
665 this->priv->tab_label = gtk_label_new(NULL);
667 /* get button press events for the tab label and the space between it and
668 * the close button, if any */
669 ebox = gtk_event_box_new();
670 gtk_widget_set_has_window(ebox, FALSE);
671 g_signal_connect(ebox, "button-press-event", G_CALLBACK(notebook_tab_click), page);
672 /* focus the current document after clicking on a tab */
673 g_signal_connect_after(ebox, "button-release-event",
674 G_CALLBACK(focus_sci), NULL);
676 hbox = gtk_hbox_new(FALSE, 2);
677 gtk_box_pack_start(GTK_BOX(hbox), this->priv->tab_label, FALSE, FALSE, 0);
678 gtk_container_add(GTK_CONTAINER(ebox), hbox);
680 if (file_prefs.show_tab_cross)
682 GtkWidget *image, *btn, *align;
684 btn = gtk_button_new();
685 gtk_button_set_relief(GTK_BUTTON(btn), GTK_RELIEF_NONE);
686 gtk_button_set_focus_on_click(GTK_BUTTON(btn), FALSE);
687 gtk_widget_set_name(btn, "geany-close-tab-button");
689 image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
690 gtk_container_add(GTK_CONTAINER(btn), image);
692 align = gtk_alignment_new(1.0, 0.5, 0.0, 0.0);
693 gtk_container_add(GTK_CONTAINER(align), btn);
694 gtk_box_pack_start(GTK_BOX(hbox), align, TRUE, TRUE, 0);
696 g_signal_connect(btn, "clicked", G_CALLBACK(notebook_tab_close_clicked_cb), page);
697 /* button overrides event box, so make middle click on button also close tab */
698 g_signal_connect(btn, "button-press-event", G_CALLBACK(notebook_tab_click), page);
699 /* handle style modification to keep button small as possible even when theme change */
700 g_signal_connect(btn, "style-set", G_CALLBACK(notebook_tab_close_button_style_set), NULL);
703 gtk_widget_show_all(ebox);
705 document_update_tab_label(this);
707 if (file_prefs.tab_order_beside)
708 cur_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(main_widgets.notebook));
709 else
710 cur_page = file_prefs.tab_order_ltr ? -2 /* hack: -2 + 1 = -1, last page */ : 0;
711 if (file_prefs.tab_order_ltr)
712 tabnum = gtk_notebook_insert_page_menu(GTK_NOTEBOOK(main_widgets.notebook), page,
713 ebox, NULL, cur_page + 1);
714 else
715 tabnum = gtk_notebook_insert_page_menu(GTK_NOTEBOOK(main_widgets.notebook), page,
716 ebox, NULL, cur_page);
718 tab_count_changed();
720 /* enable tab DnD */
721 gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(main_widgets.notebook), page, TRUE);
723 return tabnum;
727 static void
728 notebook_tab_close_clicked_cb(GtkButton *button, gpointer user_data)
730 gint cur_page = gtk_notebook_page_num(GTK_NOTEBOOK(main_widgets.notebook),
731 GTK_WIDGET(user_data));
733 document_remove_page(cur_page);
737 /* Always use this instead of gtk_notebook_remove_page(). */
738 void notebook_remove_page(gint page_num)
740 gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(main_widgets.notebook));
742 if (page_num == page)
744 if (file_prefs.tab_order_ltr)
745 page += 1;
746 else if (page > 0) /* never go negative, it would select the last page */
747 page -= 1;
749 if (file_prefs.tab_close_switch_to_mru)
751 GeanyDocument *last_doc;
753 last_doc = g_queue_peek_nth(mru_docs, 0);
754 if (DOC_VALID(last_doc))
755 page = document_get_notebook_page(last_doc);
758 gtk_notebook_set_current_page(GTK_NOTEBOOK(main_widgets.notebook), page);
761 /* now remove the page (so we don't temporarily switch to the previous page) */
762 gtk_notebook_remove_page(GTK_NOTEBOOK(main_widgets.notebook), page_num);
764 tab_count_changed();
768 static void
769 on_window_drag_data_received(GtkWidget *widget, GdkDragContext *drag_context,
770 gint x, gint y, GtkSelectionData *data, guint target_type,
771 guint event_time, gpointer user_data)
773 gboolean success = FALSE;
774 gint length = gtk_selection_data_get_length(data);
776 if (length > 0 && gtk_selection_data_get_format(data) == 8)
778 document_open_file_list((const gchar *)gtk_selection_data_get_data(data), length);
780 success = TRUE;
782 gtk_drag_finish(drag_context, success, FALSE, event_time);