gedit-tab.c 74.6 KB
Newer Older
Paolo Borelli's avatar
Paolo Borelli committed
1 2 3 4
/*
 * gedit-tab.c
 * This file is part of gedit
 *
5
 * Copyright (C) 2005 - Paolo Maggi
6
 * Copyright (C) 2014, 2015 - Sébastien Wilmet
Paolo Borelli's avatar
Paolo Borelli committed
7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
Paolo Borelli's avatar
Paolo Borelli committed
20
 */
21

22
#include "gedit-tab.h"
23
#include "gedit-tab-private.h"
24

25
#include <stdlib.h>
Paolo Borelli's avatar
Paolo Borelli committed
26 27
#include <glib/gi18n.h>

28
#include "gedit-app.h"
29
#include "gedit-app-private.h"
30
#include "gedit-recent.h"
Paolo Borelli's avatar
Paolo Borelli committed
31
#include "gedit-utils.h"
32
#include "gedit-io-error-info-bar.h"
33 34
#include "gedit-print-job.h"
#include "gedit-print-preview.h"
35
#include "gedit-progress-info-bar.h"
Paolo Borelli's avatar
Paolo Borelli committed
36
#include "gedit-debug.h"
37 38
#include "gedit-document.h"
#include "gedit-document-private.h"
39
#include "gedit-enum-types.h"
40
#include "gedit-settings.h"
41
#include "gedit-view-frame.h"
Paolo Borelli's avatar
Paolo Borelli committed
42 43 44

#define GEDIT_TAB_KEY "GEDIT_TAB_KEY"

45
struct _GeditTab
Paolo Borelli's avatar
Paolo Borelli committed
46
{
47
	GtkBox parent_instance;
48

49
	GeditTabState state;
Paolo Borelli's avatar
Paolo Borelli committed
50

51
	GSettings *editor_settings;
Paolo Borelli's avatar
Paolo Borelli committed
52

53
	GeditViewFrame *frame;
Paolo Borelli's avatar
Paolo Borelli committed
54

55 56 57 58 59 60
	GtkWidget *info_bar;
	GtkWidget *info_bar_hidden;

	GeditPrintJob *print_job;
	GtkWidget *print_preview;

61
	GtkSourceFileSaverFlags save_flags;
Paolo Borelli's avatar
Paolo Borelli committed
62

63
	guint idle_scroll;
64

65 66
	gint auto_save_interval;
	guint auto_save_timeout;
67

68 69
	guint editable : 1;
	guint auto_save : 1;
70

71
	guint ask_if_externally_modified : 1;
72 73 74
};

typedef struct _SaverData SaverData;
75
typedef struct _LoaderData LoaderData;
76 77 78 79 80

struct _SaverData
{
	GtkSourceFileSaver *saver;

81 82
	GTimer *timer;

83
	/* Notes about the create_backup saver flag:
84 85 86
	 * - At the beginning of a new file saving, force_no_backup is FALSE.
	 *   The create_backup flag is set to the saver if it is enabled in
	 *   GSettings and if it isn't an auto-save.
87 88 89 90 91 92 93 94 95 96 97 98 99 100
	 * - If creating the backup gives an error, and if the user wants to
	 *   save the file without the backup, force_no_backup is set to TRUE
	 *   and the create_backup flag is removed from the saver.
	 *   force_no_backup as TRUE means that the create_backup flag should
	 *   never be added again to the saver (for the current file saving).
	 * - When another error occurs and if the user explicitly retry again
	 *   the file saving, the create_backup flag is added to the saver if
	 *   (1) it is enabled in GSettings, (2) if force_no_backup is FALSE.
	 * - The create_backup flag is added when the user expressed his or her
	 *   willing to save the file, by pressing a button for example. For an
	 *   auto-save, the create_backup flag is thus not added initially, but
	 *   can be added later when an error occurs and the user clicks on a
	 *   button in the info bar to retry the file saving.
	 */
101
	guint force_no_backup : 1;
Paolo Borelli's avatar
Paolo Borelli committed
102 103
};

104 105 106
struct _LoaderData
{
	GtkSourceFileLoader *loader;
107
	GTimer *timer;
108 109 110 111 112
	gint line_pos;
	gint column_pos;
	guint user_requested_encoding : 1;
};

113
G_DEFINE_TYPE (GeditTab, gedit_tab, GTK_TYPE_BOX)
Paolo Borelli's avatar
Paolo Borelli committed
114 115 116 117 118

enum
{
	PROP_0,
	PROP_NAME,
119 120
	PROP_STATE,
	PROP_AUTO_SAVE,
121
	PROP_AUTO_SAVE_INTERVAL,
122 123
	PROP_CAN_CLOSE,
	LAST_PROP
Paolo Borelli's avatar
Paolo Borelli committed
124 125
};

126 127
static GParamSpec *properties[LAST_PROP];

128 129 130 131 132 133
enum
{
	DROP_URIS,
	LAST_SIGNAL
};

134
static guint signals[LAST_SIGNAL];
135

136 137
static gboolean gedit_tab_auto_save (GeditTab *tab);

138 139
static void launch_loader (GTask                   *loading_task,
			   const GtkSourceEncoding *encoding);
140

141
static void launch_saver (GTask *saving_task);
142

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
static SaverData *
saver_data_new (void)
{
	return g_slice_new0 (SaverData);
}

static void
saver_data_free (SaverData *data)
{
	if (data != NULL)
	{
		if (data->saver != NULL)
		{
			g_object_unref (data->saver);
		}

159 160 161 162 163
		if (data->timer != NULL)
		{
			g_timer_destroy (data->timer);
		}

164 165 166 167
		g_slice_free (SaverData, data);
	}
}

168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
static LoaderData *
loader_data_new (void)
{
	return g_slice_new0 (LoaderData);
}

static void
loader_data_free (LoaderData *data)
{
	if (data != NULL)
	{
		if (data->loader != NULL)
		{
			g_object_unref (data->loader);
		}

184 185 186 187 188
		if (data->timer != NULL)
		{
			g_timer_destroy (data->timer);
		}

189 190 191 192
		g_slice_free (LoaderData, data);
	}
}

193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
static void
set_editable (GeditTab *tab,
	      gboolean  editable)
{
	GeditView *view;
	gboolean val;

	tab->editable = editable != FALSE;

	view = gedit_tab_get_view (tab);

	val = (tab->state == GEDIT_TAB_STATE_NORMAL &&
	       tab->editable);

	gtk_text_view_set_editable (GTK_TEXT_VIEW (view), val);
}

210
static void
211
install_auto_save_timeout (GeditTab *tab)
212
{
213
	if (tab->auto_save_timeout == 0)
214
	{
215
		g_return_if_fail (tab->auto_save_interval > 0);
216

217 218 219
		tab->auto_save_timeout = g_timeout_add_seconds (tab->auto_save_interval * 60,
		                                                (GSourceFunc) gedit_tab_auto_save,
		                                                tab);
220
	}
221 222 223 224 225 226 227
}

static void
remove_auto_save_timeout (GeditTab *tab)
{
	gedit_debug (DEBUG_TAB);

228
	if (tab->auto_save_timeout > 0)
229
	{
230 231
		g_source_remove (tab->auto_save_timeout);
		tab->auto_save_timeout = 0;
232
	}
233 234
}

235 236 237 238
static void
update_auto_save_timeout (GeditTab *tab)
{
	GeditDocument *doc;
239
	GtkSourceFile *file;
240 241 242 243

	gedit_debug (DEBUG_TAB);

	doc = gedit_tab_get_document (tab);
244
	file = gedit_document_get_file (doc);
245

246 247
	if (tab->state == GEDIT_TAB_STATE_NORMAL &&
	    tab->auto_save &&
248
	    !gedit_document_is_untitled (doc) &&
249
	    !gtk_source_file_is_readonly (file))
250 251 252 253 254 255 256 257 258
	{
		install_auto_save_timeout (tab);
	}
	else
	{
		remove_auto_save_timeout (tab);
	}
}

Paolo Borelli's avatar
Paolo Borelli committed
259 260 261 262 263 264 265 266 267 268 269
static void
gedit_tab_get_property (GObject    *object,
		        guint       prop_id,
		        GValue     *value,
		        GParamSpec *pspec)
{
	GeditTab *tab = GEDIT_TAB (object);

	switch (prop_id)
	{
		case PROP_NAME:
Sébastien Wilmet's avatar
Sébastien Wilmet committed
270
			g_value_take_string (value, _gedit_tab_get_name (tab));
Paolo Borelli's avatar
Paolo Borelli committed
271
			break;
Sébastien Wilmet's avatar
Sébastien Wilmet committed
272

Paolo Borelli's avatar
Paolo Borelli committed
273
		case PROP_STATE:
Sébastien Wilmet's avatar
Sébastien Wilmet committed
274
			g_value_set_enum (value, gedit_tab_get_state (tab));
275
			break;
Sébastien Wilmet's avatar
Sébastien Wilmet committed
276

277
		case PROP_AUTO_SAVE:
Sébastien Wilmet's avatar
Sébastien Wilmet committed
278
			g_value_set_boolean (value, gedit_tab_get_auto_save_enabled (tab));
279
			break;
Sébastien Wilmet's avatar
Sébastien Wilmet committed
280

281
		case PROP_AUTO_SAVE_INTERVAL:
Sébastien Wilmet's avatar
Sébastien Wilmet committed
282
			g_value_set_int (value, gedit_tab_get_auto_save_interval (tab));
283
			break;
Sébastien Wilmet's avatar
Sébastien Wilmet committed
284

285
		case PROP_CAN_CLOSE:
Sébastien Wilmet's avatar
Sébastien Wilmet committed
286
			g_value_set_boolean (value, _gedit_tab_get_can_close (tab));
287
			break;
Sébastien Wilmet's avatar
Sébastien Wilmet committed
288

289 290
		default:
			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
291
			break;
292 293 294 295 296 297 298 299 300 301 302 303 304 305
	}
}

static void
gedit_tab_set_property (GObject      *object,
		        guint         prop_id,
		        const GValue *value,
		        GParamSpec   *pspec)
{
	GeditTab *tab = GEDIT_TAB (object);

	switch (prop_id)
	{
		case PROP_AUTO_SAVE:
Sébastien Wilmet's avatar
Sébastien Wilmet committed
306
			gedit_tab_set_auto_save_enabled (tab, g_value_get_boolean (value));
307
			break;
Sébastien Wilmet's avatar
Sébastien Wilmet committed
308

309
		case PROP_AUTO_SAVE_INTERVAL:
Sébastien Wilmet's avatar
Sébastien Wilmet committed
310
			gedit_tab_set_auto_save_interval (tab, g_value_get_int (value));
311
			break;
Sébastien Wilmet's avatar
Sébastien Wilmet committed
312

Paolo Borelli's avatar
Paolo Borelli committed
313 314
		default:
			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
315
			break;
Paolo Borelli's avatar
Paolo Borelli committed
316 317 318
	}
}

319 320 321 322 323
static void
gedit_tab_dispose (GObject *object)
{
	GeditTab *tab = GEDIT_TAB (object);

324
	g_clear_object (&tab->editor_settings);
325 326
	g_clear_object (&tab->print_job);
	g_clear_object (&tab->print_preview);
327

328
	remove_auto_save_timeout (tab);
329

330
	if (tab->idle_scroll != 0)
331
	{
332 333
		g_source_remove (tab->idle_scroll);
		tab->idle_scroll = 0;
334 335
	}

336
	G_OBJECT_CLASS (gedit_tab_parent_class)->dispose (object);
Paolo Borelli's avatar
Paolo Borelli committed
337 338
}

339 340 341 342
static void
gedit_tab_grab_focus (GtkWidget *widget)
{
	GeditTab *tab = GEDIT_TAB (widget);
343

344
	GTK_WIDGET_CLASS (gedit_tab_parent_class)->grab_focus (widget);
345

346
	if (tab->info_bar != NULL)
347
	{
348
		gtk_widget_grab_focus (tab->info_bar);
349 350 351
	}
	else
	{
352
		GeditView *view = gedit_tab_get_view (tab);
353
		gtk_widget_grab_focus (GTK_WIDGET (view));
354 355 356
	}
}

357 358 359 360 361 362 363
static void
gedit_tab_drop_uris (GeditTab  *tab,
                     gchar    **uri_list)
{
	gedit_debug (DEBUG_TAB);
}

364
static void
Paolo Borelli's avatar
Paolo Borelli committed
365 366 367
gedit_tab_class_init (GeditTabClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
368
	GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (klass);
Paolo Borelli's avatar
Paolo Borelli committed
369

370
	object_class->dispose = gedit_tab_dispose;
Paolo Borelli's avatar
Paolo Borelli committed
371
	object_class->get_property = gedit_tab_get_property;
372
	object_class->set_property = gedit_tab_set_property;
373

374
	gtkwidget_class->grab_focus = gedit_tab_grab_focus;
375

376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
	properties[PROP_NAME] =
		g_param_spec_string ("name",
		                     "Name",
		                     "The tab's name",
		                     NULL,
		                     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);

	properties[PROP_STATE] =
		g_param_spec_enum ("state",
		                   "State",
		                   "The tab's state",
		                   GEDIT_TYPE_TAB_STATE,
		                   GEDIT_TAB_STATE_NORMAL,
		                   G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);

	properties[PROP_AUTO_SAVE] =
		g_param_spec_boolean ("autosave",
		                      "Autosave",
		                      "Autosave feature",
		                      TRUE,
		                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);

	properties[PROP_AUTO_SAVE_INTERVAL] =
		g_param_spec_int ("autosave-interval",
		                  "AutosaveInterval",
		                  "Time between two autosaves",
		                  0,
		                  G_MAXINT,
		                  0,
		                  G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);

	properties[PROP_CAN_CLOSE] =
		g_param_spec_boolean ("can-close",
		                      "Can close",
		                      "Whether the tab can be closed",
		                      TRUE,
		                      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);

	g_object_class_install_properties (object_class, LAST_PROP, properties);
415

416
	signals[DROP_URIS] =
417 418 419 420 421 422 423 424
		g_signal_new_class_handler ("drop-uris",
		                            G_TYPE_FROM_CLASS (klass),
		                            G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
		                            G_CALLBACK (gedit_tab_drop_uris),
		                            NULL, NULL, NULL,
		                            G_TYPE_NONE,
		                            1,
		                            G_TYPE_STRV);
Paolo Borelli's avatar
Paolo Borelli committed
425 426
}

427 428 429 430 431 432 433 434
/**
 * gedit_tab_get_state:
 * @tab: a #GeditTab
 *
 * Gets the #GeditTabState of @tab.
 *
 * Returns: the #GeditTabState of @tab
 */
Paolo Borelli's avatar
Paolo Borelli committed
435 436 437 438
GeditTabState
gedit_tab_get_state (GeditTab *tab)
{
	g_return_val_if_fail (GEDIT_IS_TAB (tab), GEDIT_TAB_STATE_NORMAL);
439

440
	return tab->state;
Paolo Borelli's avatar
Paolo Borelli committed
441 442 443 444 445 446
}

static void
set_cursor_according_to_state (GtkTextView   *view,
			       GeditTabState  state)
{
447
	GdkDisplay *display;
Paolo Borelli's avatar
Paolo Borelli committed
448 449 450 451
	GdkCursor *cursor;
	GdkWindow *text_window;
	GdkWindow *left_window;

452 453
	display = gtk_widget_get_display (GTK_WIDGET (view));

Paolo Borelli's avatar
Paolo Borelli committed
454 455 456 457 458 459 460 461 462
	text_window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_TEXT);
	left_window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_LEFT);

	if ((state == GEDIT_TAB_STATE_LOADING)          ||
	    (state == GEDIT_TAB_STATE_REVERTING)        ||
	    (state == GEDIT_TAB_STATE_SAVING)           ||
	    (state == GEDIT_TAB_STATE_PRINTING)         ||
	    (state == GEDIT_TAB_STATE_CLOSING))
	{
463
		cursor = gdk_cursor_new_from_name (display, "progress");
Paolo Borelli's avatar
Paolo Borelli committed
464 465 466 467 468 469

		if (text_window != NULL)
			gdk_window_set_cursor (text_window, cursor);
		if (left_window != NULL)
			gdk_window_set_cursor (left_window, cursor);

470
		g_clear_object (&cursor);
Paolo Borelli's avatar
Paolo Borelli committed
471 472 473
	}
	else
	{
474
		cursor = gdk_cursor_new_from_name (display, "text");
Paolo Borelli's avatar
Paolo Borelli committed
475 476 477 478 479 480

		if (text_window != NULL)
			gdk_window_set_cursor (text_window, cursor);
		if (left_window != NULL)
			gdk_window_set_cursor (left_window, NULL);

481
		g_clear_object (&cursor);
Paolo Borelli's avatar
Paolo Borelli committed
482 483 484 485 486 487 488
	}
}

static void
view_realized (GtkTextView *view,
	       GeditTab    *tab)
{
489
	set_cursor_according_to_state (view, tab->state);
Paolo Borelli's avatar
Paolo Borelli committed
490 491 492 493 494 495
}

static void
set_view_properties_according_to_state (GeditTab      *tab,
					GeditTabState  state)
{
496
	GeditView *view;
Paolo Borelli's avatar
Paolo Borelli committed
497
	gboolean val;
498
	gboolean hl_current_line;
499

500
	hl_current_line = g_settings_get_boolean (tab->editor_settings,
501
						  GEDIT_SETTINGS_HIGHLIGHT_CURRENT_LINE);
Paolo Borelli's avatar
Paolo Borelli committed
502

503
	view = gedit_tab_get_view (tab);
504

Paolo Borelli's avatar
Paolo Borelli committed
505
	val = ((state == GEDIT_TAB_STATE_NORMAL) &&
506
	       tab->editable);
507
	gtk_text_view_set_editable (GTK_TEXT_VIEW (view), val);
Paolo Borelli's avatar
Paolo Borelli committed
508 509 510

	val = ((state != GEDIT_TAB_STATE_LOADING) &&
	       (state != GEDIT_TAB_STATE_CLOSING));
511
	gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), val);
Paolo Borelli's avatar
Paolo Borelli committed
512 513 514

	val = ((state != GEDIT_TAB_STATE_LOADING) &&
	       (state != GEDIT_TAB_STATE_CLOSING) &&
515
	       (hl_current_line));
516
	gtk_source_view_set_highlight_current_line (GTK_SOURCE_VIEW (view), val);
Paolo Borelli's avatar
Paolo Borelli committed
517 518 519 520 521 522 523 524
}

static void
gedit_tab_set_state (GeditTab      *tab,
		     GeditTabState  state)
{
	g_return_if_fail ((state >= 0) && (state < GEDIT_TAB_NUM_OF_STATES));

525
	if (tab->state == state)
Sébastien Wilmet's avatar
Sébastien Wilmet committed
526
	{
Paolo Borelli's avatar
Paolo Borelli committed
527
		return;
Sébastien Wilmet's avatar
Sébastien Wilmet committed
528
	}
Paolo Borelli's avatar
Paolo Borelli committed
529

530
	tab->state = state;
Paolo Borelli's avatar
Paolo Borelli committed
531 532 533

	set_view_properties_according_to_state (tab, state);

534 535 536 537 538
	/* Hide or show the document.
	 * For GEDIT_TAB_STATE_LOADING_ERROR, tab->frame is either shown or
	 * hidden, depending on the error.
	 */
	if (state == GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW)
Paolo Borelli's avatar
Paolo Borelli committed
539
	{
540
		gtk_widget_hide (GTK_WIDGET (tab->frame));
Paolo Borelli's avatar
Paolo Borelli committed
541
	}
542
	else if (state != GEDIT_TAB_STATE_LOADING_ERROR)
Paolo Borelli's avatar
Paolo Borelli committed
543
	{
544
		gtk_widget_show (GTK_WIDGET (tab->frame));
Paolo Borelli's avatar
Paolo Borelli committed
545 546
	}

Sébastien Wilmet's avatar
Sébastien Wilmet committed
547
	set_cursor_according_to_state (GTK_TEXT_VIEW (gedit_tab_get_view (tab)),
Paolo Borelli's avatar
Paolo Borelli committed
548 549
				       state);

550 551
	update_auto_save_timeout (tab);

552 553
	g_object_notify_by_pspec (G_OBJECT (tab), properties[PROP_STATE]);
	g_object_notify_by_pspec (G_OBJECT (tab), properties[PROP_CAN_CLOSE]);
Paolo Borelli's avatar
Paolo Borelli committed
554 555
}

556
static void
557
document_location_notify_handler (GtkSourceFile *file,
558 559
				  GParamSpec    *pspec,
				  GeditTab      *tab)
Paolo Borelli's avatar
Paolo Borelli committed
560
{
561
	gedit_debug (DEBUG_TAB);
562

563
	/* Notify the change in the location */
564
	g_object_notify_by_pspec (G_OBJECT (tab), properties[PROP_NAME]);
Paolo Borelli's avatar
Paolo Borelli committed
565 566
}

567
static void
568 569 570 571 572
document_shortname_notify_handler (GeditDocument *document,
				   GParamSpec    *pspec,
				   GeditTab      *tab)
{
	gedit_debug (DEBUG_TAB);
573

574
	/* Notify the change in the shortname */
575
	g_object_notify_by_pspec (G_OBJECT (tab), properties[PROP_NAME]);
576 577
}

Paolo Borelli's avatar
Paolo Borelli committed
578 579 580 581
static void
document_modified_changed (GtkTextBuffer *document,
			   GeditTab      *tab)
{
582 583
	g_object_notify_by_pspec (G_OBJECT (tab), properties[PROP_NAME]);
	g_object_notify_by_pspec (G_OBJECT (tab), properties[PROP_CAN_CLOSE]);
Paolo Borelli's avatar
Paolo Borelli committed
584 585 586
}

static void
587 588 589
set_info_bar (GeditTab        *tab,
              GtkWidget       *info_bar,
              GtkResponseType  default_response)
Paolo Borelli's avatar
Paolo Borelli committed
590
{
591 592
	gedit_debug (DEBUG_TAB);

593
	if (tab->info_bar == info_bar)
Sébastien Wilmet's avatar
Sébastien Wilmet committed
594
	{
Paolo Borelli's avatar
Paolo Borelli committed
595
		return;
Sébastien Wilmet's avatar
Sébastien Wilmet committed
596
	}
Paolo Borelli's avatar
Paolo Borelli committed
597

598
	if (info_bar == NULL)
599
	{
Sébastien Wilmet's avatar
Sébastien Wilmet committed
600 601
		/* Don't destroy the old info_bar right away,
		   we want the hide animation. */
602
		if (tab->info_bar_hidden != NULL)
603
		{
604
			gtk_widget_destroy (tab->info_bar_hidden);
Sébastien Wilmet's avatar
Sébastien Wilmet committed
605
		}
606

607 608
		tab->info_bar_hidden = tab->info_bar;
		gtk_widget_hide (tab->info_bar_hidden);
609

610
		tab->info_bar = NULL;
611 612 613
	}
	else
	{
614
		if (tab->info_bar != NULL)
615
		{
616
			gedit_debug_message (DEBUG_TAB, "Replacing existing notification");
617
			gtk_widget_destroy (tab->info_bar);
618 619
		}

620
		/* Make sure to stop a possibly still ongoing hiding animation. */
621
		if (tab->info_bar_hidden != NULL)
622
		{
623 624
			gtk_widget_destroy (tab->info_bar_hidden);
			tab->info_bar_hidden = NULL;
625
		}
626

627
		tab->info_bar = info_bar;
628
		gtk_box_pack_start (GTK_BOX (tab), info_bar, FALSE, FALSE, 0);
629 630 631 632 633 634 635 636

		/* Note this must be done after the info bar is added to the window */
		if (default_response != GTK_RESPONSE_NONE)
		{
			gtk_info_bar_set_default_response (GTK_INFO_BAR (info_bar),
			                                   default_response);
		}

637
		gtk_widget_show (info_bar);
638
	}
Paolo Borelli's avatar
Paolo Borelli committed
639 640 641 642 643
}

static void
remove_tab (GeditTab *tab)
{
644
	GtkWidget *notebook;
Paolo Borelli's avatar
Paolo Borelli committed
645

646 647
	notebook = gtk_widget_get_parent (GTK_WIDGET (tab));
	gtk_container_remove (GTK_CONTAINER (notebook), GTK_WIDGET (tab));
Paolo Borelli's avatar
Paolo Borelli committed
648 649
}

650
static void
651 652
io_loading_error_info_bar_response (GtkWidget *info_bar,
				    gint       response_id,
653
				    GTask     *loading_task)
Paolo Borelli's avatar
Paolo Borelli committed
654
{
655 656
	GeditTab *tab = g_task_get_source_object (loading_task);
	LoaderData *data = g_task_get_task_data (loading_task);
657
	GFile *location;
658
	const GtkSourceEncoding *encoding;
Paolo Borelli's avatar
Paolo Borelli committed
659

660
	location = gtk_source_file_loader_get_location (data->loader);
Paolo Borelli's avatar
Paolo Borelli committed
661

662
	switch (response_id)
Paolo Borelli's avatar
Paolo Borelli committed
663
	{
664
		case GTK_RESPONSE_OK:
Sébastien Wilmet's avatar
Sébastien Wilmet committed
665
			encoding = gedit_conversion_error_info_bar_get_encoding (GTK_WIDGET (info_bar));
Paolo Borelli's avatar
Paolo Borelli committed
666

667
			set_info_bar (tab, NULL, GTK_RESPONSE_NONE);
668
			gedit_tab_set_state (tab, GEDIT_TAB_STATE_LOADING);
669

670
			launch_loader (loading_task, encoding);
671
			break;
Sébastien Wilmet's avatar
Sébastien Wilmet committed
672

673 674
		case GTK_RESPONSE_YES:
			/* This means that we want to edit the document anyway */
675
			set_editable (tab, TRUE);
676
			set_info_bar (tab, NULL, GTK_RESPONSE_NONE);
677
			gedit_tab_set_state (tab, GEDIT_TAB_STATE_NORMAL);
678 679 680

			g_task_return_boolean (loading_task, TRUE);
			g_object_unref (loading_task);
681
			break;
Sébastien Wilmet's avatar
Sébastien Wilmet committed
682

683
		default:
684 685
			if (location != NULL)
			{
686
				gedit_recent_remove_if_local (location);
687
			}
Paolo Borelli's avatar
Paolo Borelli committed
688

689 690 691
			g_task_return_boolean (loading_task, FALSE);
			g_object_unref (loading_task);

692 693
			remove_tab (tab);
			break;
Paolo Borelli's avatar
Paolo Borelli committed
694 695 696
	}
}

697
static void
Sébastien Wilmet's avatar
Sébastien Wilmet committed
698 699 700
file_already_open_warning_info_bar_response (GtkWidget *info_bar,
					     gint       response_id,
					     GeditTab  *tab)
Paolo Borelli's avatar
Paolo Borelli committed
701
{
702
	GeditView *view = gedit_tab_get_view (tab);
703

Paolo Borelli's avatar
Paolo Borelli committed
704 705
	if (response_id == GTK_RESPONSE_YES)
	{
706
		set_editable (tab, TRUE);
Paolo Borelli's avatar
Paolo Borelli committed
707 708
	}

709
	set_info_bar (tab, NULL, GTK_RESPONSE_NONE);
Paolo Borelli's avatar
Paolo Borelli committed
710

711
	gtk_widget_grab_focus (GTK_WIDGET (view));
Paolo Borelli's avatar
Paolo Borelli committed
712 713 714
}

static void
Sébastien Wilmet's avatar
Sébastien Wilmet committed
715 716
load_cancelled (GtkWidget *bar,
		gint       response_id,
717
		GTask     *loading_task)
Paolo Borelli's avatar
Paolo Borelli committed
718
{
719 720
	GeditTab *tab = g_task_get_source_object (loading_task);

721
	g_return_if_fail (GEDIT_IS_PROGRESS_INFO_BAR (tab->info_bar));
722

723
	g_cancellable_cancel (g_task_get_cancellable (loading_task));
Paolo Borelli's avatar
Paolo Borelli committed
724 725
}

726
static void
Sébastien Wilmet's avatar
Sébastien Wilmet committed
727 728
unrecoverable_reverting_error_info_bar_response (GtkWidget *info_bar,
						 gint       response_id,
729
						 GTask     *loading_task)
Paolo Borelli's avatar
Paolo Borelli committed
730
{
731
	GeditTab *tab = g_task_get_source_object (loading_task);
Paolo Borelli's avatar
Paolo Borelli committed
732
	GeditView *view;
733

Sébastien Wilmet's avatar
Sébastien Wilmet committed
734
	gedit_tab_set_state (tab, GEDIT_TAB_STATE_NORMAL);
Paolo Borelli's avatar
Paolo Borelli committed
735

736
	set_info_bar (tab, NULL, GTK_RESPONSE_NONE);
Paolo Borelli's avatar
Paolo Borelli committed
737

738
	view = gedit_tab_get_view (tab);
739
	gtk_widget_grab_focus (GTK_WIDGET (view));
740 741 742

	g_task_return_boolean (loading_task, FALSE);
	g_object_unref (loading_task);
Paolo Borelli's avatar
Paolo Borelli committed
743 744 745 746 747
}

#define MAX_MSG_LENGTH 100

static void
748
show_loading_info_bar (GTask *loading_task)
Paolo Borelli's avatar
Paolo Borelli committed
749
{
750
	GeditTab *tab = g_task_get_source_object (loading_task);
751
	GtkWidget *bar;
752
	GeditDocument *doc;
Paolo Borelli's avatar
Paolo Borelli committed
753 754 755
	gchar *name;
	gchar *dirname = NULL;
	gchar *msg = NULL;
756 757
	gchar *name_markup;
	gchar *dirname_markup;
Paolo Borelli's avatar
Paolo Borelli committed
758
	gint len;
759

760
	if (tab->info_bar != NULL)
761
	{
Paolo Borelli's avatar
Paolo Borelli committed
762
		return;
763
	}
764

765
	gedit_debug (DEBUG_TAB);
766

767
	doc = gedit_tab_get_document (tab);
Paolo Borelli's avatar
Paolo Borelli committed
768

769 770
	name = gedit_document_get_short_name_for_display (doc);
	len = g_utf8_strlen (name, -1);
Paolo Borelli's avatar
Paolo Borelli committed
771 772 773 774 775 776

	/* if the name is awfully long, truncate it and be done with it,
	 * otherwise also show the directory (ellipsized if needed)
	 */
	if (len > MAX_MSG_LENGTH)
	{
777 778 779 780 781
		gchar *str;

		str = gedit_utils_str_middle_truncate (name, MAX_MSG_LENGTH);
		g_free (name);
		name = str;
Paolo Borelli's avatar
Paolo Borelli committed
782 783 784
	}
	else
	{
785 786
		GtkSourceFile *file = gedit_document_get_file (doc);
		GFile *location = gtk_source_file_get_location (file);
Paolo Borelli's avatar
Paolo Borelli committed
787

788
		if (location != NULL)
Paolo Borelli's avatar
Paolo Borelli committed
789
		{
790
			gchar *str = gedit_utils_location_get_dirname_for_display (location);
791

Paolo Borelli's avatar
Paolo Borelli committed
792 793 794 795 796 797
			/* use the remaining space for the dir, but use a min of 20 chars
			 * so that we do not end up with a dirname like "(a...b)".
			 * This means that in the worst case when the filename is long 99
			 * we have a title long 99 + 20, but I think it's a rare enough
			 * case to be acceptable. It's justa darn title afterall :)
			 */
798
			dirname = gedit_utils_str_middle_truncate (str,
Paolo Borelli's avatar
Paolo Borelli committed
799 800 801 802 803
								   MAX (20, MAX_MSG_LENGTH - len));
			g_free (str);
		}
	}

804
	name_markup = g_markup_printf_escaped ("<b>%s</b>", name);
805

806
	if (tab->state == GEDIT_TAB_STATE_REVERTING)
Paolo Borelli's avatar
Paolo Borelli committed
807 808 809
	{
		if (dirname != NULL)
		{
810
			dirname_markup = g_markup_printf_escaped ("<b>%s</b>", dirname);
811

Paolo Borelli's avatar
Paolo Borelli committed
812 813
			/* Translators: the first %s is a file name (e.g. test.txt) the second one
			   is a directory (e.g. ssh://master.gnome.org/home/users/paolo) */
814 815 816
			msg = g_strdup_printf (_("Reverting %s from %s"),
					       name_markup,
					       dirname_markup);
817
			g_free (dirname_markup);
Paolo Borelli's avatar
Paolo Borelli committed
818 819 820
		}
		else
		{
821
			msg = g_strdup_printf (_("Reverting %s"), name_markup);
Paolo Borelli's avatar
Paolo Borelli committed
822
		}
823

824
		bar = gedit_progress_info_bar_new ("document-revert", msg, TRUE);
Paolo Borelli's avatar
Paolo Borelli committed
825 826 827 828 829
	}
	else
	{
		if (dirname != NULL)
		{
830
			dirname_markup = g_markup_printf_escaped ("<b>%s</b>", dirname);
831

Paolo Borelli's avatar
Paolo Borelli committed
832 833
			/* Translators: the first %s is a file name (e.g. test.txt) the second one
			   is a directory (e.g. ssh://master.gnome.org/home/users/paolo) */
834 835 836
			msg = g_strdup_printf (_("Loading %s from %s"),
					       name_markup,
					       dirname_markup);
837
			g_free (dirname_markup);
Paolo Borelli's avatar
Paolo Borelli committed
838 839 840
		}
		else
		{
841
			msg = g_strdup_printf (_("Loading %s"), name_markup);
Paolo Borelli's avatar
Paolo Borelli committed
842 843
		}

844
		bar = gedit_progress_info_bar_new ("document-open", msg, TRUE);
Paolo Borelli's avatar
Paolo Borelli committed
845 846
	}

847 848 849 850 851
	g_signal_connect_object (bar,
				 "response",
				 G_CALLBACK (load_cancelled),
				 loading_task,
				 0);
852

853
	set_info_bar (tab, bar, GTK_RESPONSE_NONE);
Paolo Borelli's avatar
Paolo Borelli committed
854 855 856

	g_free (msg);
	g_free (name);
857
	g_free (name_markup);
Paolo Borelli's avatar
Paolo Borelli committed
858 859 860 861
	g_free (dirname);
}

static void
862
show_saving_info_bar (GTask *saving_task)
Paolo Borelli's avatar
Paolo Borelli committed
863
{
864
	GeditTab *tab = g_task_get_source_object (saving_task);
865
	GtkWidget *bar;
866
	GeditDocument *doc;
Paolo Borelli's avatar
Paolo Borelli committed
867 868 869
	gchar *short_name;
	gchar *from;
	gchar *to = NULL;
870 871
	gchar *from_markup;
	gchar *to_markup;
Paolo Borelli's avatar
Paolo Borelli committed
872 873 874
	gchar *msg = NULL;
	gint len;

875
	if (tab->info_bar != NULL)
876
	{
Paolo Borelli's avatar
Paolo Borelli committed
877
		return;
878
	}
879

880
	gedit_debug (DEBUG_TAB);
881

882
	doc = gedit_tab_get_document (tab);
Paolo Borelli's avatar
Paolo Borelli committed
883 884 885 886 887 888 889 890 891 892

	short_name = gedit_document_get_short_name_for_display (doc);

	len = g_utf8_strlen (short_name, -1);

	/* if the name is awfully long, truncate it and be done with it,
	 * otherwise also show the directory (ellipsized if needed)
	 */
	if (len > MAX_MSG_LENGTH)
	{
893
		from = gedit_utils_str_middle_truncate (short_name, MAX_MSG_LENGTH);
Paolo Borelli's avatar
Paolo Borelli committed
894 895 896 897 898
		g_free (short_name);
	}
	else
	{
		gchar *str;
899 900 901
		SaverData *data;
		GFile *location;

902
		data = g_task_get_task_data (saving_task);
903
		location = gtk_source_file_saver_get_location (data->saver);
Paolo Borelli's avatar
Paolo Borelli committed
904 905

		from = short_name;
906 907
		to = g_file_get_parse_name (location);
		str = gedit_utils_str_middle_truncate (to, MAX (20, MAX_MSG_LENGTH - len));
Paolo Borelli's avatar
Paolo Borelli committed
908
		g_free (to);
909

Paolo Borelli's avatar
Paolo Borelli committed
910 911 912
		to = str;
	}

913
	from_markup = g_markup_printf_escaped ("<b>%s</b>", from);
914

Paolo Borelli's avatar
Paolo Borelli committed
915 916
	if (to != NULL)
	{
917
		to_markup = g_markup_printf_escaped ("<b>%s</b>", to);
918

Paolo Borelli's avatar
Paolo Borelli committed
919 920
		/* Translators: the first %s is a file name (e.g. test.txt) the second one
		   is a directory (e.g. ssh://master.gnome.org/home/users/paolo) */
921
		msg = g_strdup_printf (_("Saving %s to %s"), from_markup, to_markup);
922
		g_free (to_markup);
Paolo Borelli's avatar
Paolo Borelli committed
923 924 925
	}
	else
	{
926
		msg = g_strdup_printf (_("Saving %s"), from_markup);
Paolo Borelli's avatar
Paolo Borelli committed
927 928
	}

929
	bar = gedit_progress_info_bar_new ("document-save", msg, FALSE);
Paolo Borelli's avatar
Paolo Borelli committed
930

931
	set_info_bar (tab, bar, GTK_RESPONSE_NONE);
Paolo Borelli's avatar
Paolo Borelli committed
932 933 934 935

	g_free (msg);
	g_free (to);
	g_free (from);
936
	g_free (from_markup);
Paolo Borelli's avatar
Paolo Borelli committed
937 938 939
}

static void
940
info_bar_set_progress (GeditTab *tab,
Sébastien Wilmet's avatar
Sébastien Wilmet committed
941 942
		       goffset   size,
		       goffset   total_size)
Paolo Borelli's avatar
Paolo Borelli committed
943
{
944 945
	GeditProgressInfoBar *progress_info_bar;

946 947
	if (tab->info_bar == NULL)
	{
Paolo Borelli's avatar
Paolo Borelli committed
948
		return;
949
	}
950

951
	gedit_debug_message (DEBUG_TAB, "%" G_GOFFSET_FORMAT "/%" G_GOFFSET_FORMAT, size, total_size);
952

953
	g_return_if_fail (GEDIT_IS_PROGRESS_INFO_BAR (tab->info_bar));
954

955 956 957
	progress_info_bar = GEDIT_PROGRESS_INFO_BAR (tab->info_bar);

	if (total_size != 0)
Paolo Borelli's avatar
Paolo Borelli committed
958
	{
959 960 961 962 963 964 965
		gdouble frac = (gdouble)size / (gdouble)total_size;

		gedit_progress_info_bar_set_fraction (progress_info_bar, frac);
	}
	else if (size != 0)
	{
		gedit_progress_info_bar_pulse (progress_info_bar);
Paolo Borelli's avatar
Paolo Borelli committed
966 967 968
	}
	else
	{
969
		gedit_progress_info_bar_set_fraction (progress_info_bar, 0);
Paolo Borelli's avatar
Paolo Borelli committed
970 971 972
	}
}

973 974
/* Returns whether progress info should be shown. */
static gboolean
975
should_show_progress_info (GTimer  **timer,
976 977 978 979 980 981 982
			   goffset   size,
			   goffset   total_size)
{
	gdouble elapsed_time;
	gdouble total_time;
	gdouble remaining_time;

983 984 985
	g_assert (timer != NULL);

	if (*timer == NULL)
986 987 988 989
	{
		return TRUE;
	}

990
	elapsed_time = g_timer_elapsed (*timer, NULL);
991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012

	/* Wait a little, because at the very beginning it's maybe not very
	 * accurate (it takes initially more time for the first bytes, the
	 * following chunks should arrive more quickly, as a rough guess).
	 */
	if (elapsed_time < 0.5)
	{
		return FALSE;
	}

	/* elapsed_time / total_time = size / total_size */
	total_time = (elapsed_time * total_size) / size;

	remaining_time = total_time - elapsed_time;

	/* Approximately more than 3 seconds remaining. */
	if (remaining_time > 3.0)
	{
		/* Once the progress info bar is shown, it must remain
		 * shown until the end, so we don't need the timer
		 * anymore.
		 */
1013 1014
		g_timer_destroy (*timer);
		*timer = NULL;
1015 1016 1017 1018 1019 1020 1021

		return TRUE;
	}

	return FALSE;
}

1022 1023 1024
static gboolean
scroll_to_cursor (GeditTab *tab)
{
1025 1026
	GeditView *view;

1027
	view = gedit_tab_get_view (tab);
1028
	gedit_view_scroll_to_cursor (view);
1029

1030
	tab->idle_scroll = 0;
1031
	return G_SOURCE_REMOVE;
Paolo Borelli's avatar
Paolo Borelli committed
1032 1033
}

1034
static void
Sébastien Wilmet's avatar
Sébastien Wilmet committed
1035 1036
unrecoverable_saving_error_info_bar_response (GtkWidget *info_bar,
					      gint       response_id,
1037
					      GTask     *saving_task)
Paolo Borelli's avatar
Paolo Borelli committed
1038
{
1039
	GeditTab *tab = g_task_get_source_object (saving_task);
Paolo Borelli's avatar
Paolo Borelli committed
1040
	GeditView *view;
1041

1042
	gedit_tab_set_state (tab, GEDIT_TAB_STATE_NORMAL);
Paolo Borelli's avatar
Paolo Borelli committed
1043

1044
	set_info_bar (tab, NULL, GTK_RESPONSE_NONE);
Paolo Borelli's avatar
Paolo Borelli committed
1045

1046
	view = gedit_tab_get_view (tab);
1047
	gtk_widget_grab_focus (GTK_WIDGET (view));
1048

1049 1050
	g_task_return_boolean (saving_task, FALSE);
	g_object_unref (saving_task);
Paolo Borelli's avatar
Paolo Borelli committed
1051 1052
}

1053 1054
/* Sets the save flags after an info bar response. */
static void
1055
response_set_save_flags (GTask                   *saving_task,
1056 1057
			 GtkSourceFileSaverFlags  save_flags)
{
1058 1059
	GeditTab *tab = g_task_get_source_object (saving_task);
	SaverData *data = g_task_get_task_data (saving_task);
1060 1061
	gboolean create_backup;

1062
	create_backup = g_settings_get_boolean (tab->editor_settings,
1063 1064 1065 1066 1067 1068 1069
						GEDIT_SETTINGS_CREATE_BACKUP_COPY);

	/* If we are here, it means that the user expressed his or her willing
	 * to save the file, by pressing a button in the info bar. So even if
	 * the file saving was initially an auto-save, we set the create_backup
	 * flag (if the conditions are met).
	 */
1070
	if (create_backup && !data->force_no_backup)
1071 1072 1073 1074 1075 1076 1077 1078
	{
		save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_CREATE_BACKUP;
	}
	else
	{
		save_flags &= ~GTK_SOURCE_FILE_SAVER_FLAGS_CREATE_BACKUP;
	}

1079
	gtk_source_file_saver_set_flags (data->saver, save_flags);
1080 1081
}

1082
static void
1083
invalid_character_info_bar_response (GtkWidget *info_bar,
1084
				     gint       response_id,
1085
				     GTask     *saving_task)
1086 1087 1088
{
	if (response_id == GTK_RESPONSE_YES)
	{
1089 1090
		GeditTab *tab = g_task_get_source_object (saving_task);
		SaverData *data = g_task_get_task_data (saving_task);
1091
		GtkSourceFileSaverFlags save_flags;
1092

1093
		set_info_bar (tab, NULL, GTK_RESPONSE_NONE);
1094

1095
		/* Don't bug the user again with this... */
1096
		tab->save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_INVALID_CHARS;
1097

1098
		save_flags = gtk_source_file_saver_get_flags (data->saver);
1099
		save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_INVALID_CHARS;
1100
		response_set_save_flags (saving_task, save_flags);
1101 1102

		/* Force saving */
1103
		launch_saver (saving_task);
1104 1105 1106
	}
	else
	{
1107
		unrecoverable_saving_error_info_bar_response (info_bar, response_id, saving_task);
1108 1109 1110
	}
}

1111
static void
1112
no_backup_error_info_bar_response (GtkWidget *info_bar,
Sébastien Wilmet's avatar
Sébastien Wilmet committed
1113
				   gint       response_id,
1114
				   GTask     *saving_task)
Paolo Borelli's avatar
Paolo Borelli committed
1115 1116 1117
{
	if (response_id == GTK_RESPONSE_YES)
	{
1118 1119
		GeditTab *tab = g_task_get_source_object (saving_task);
		SaverData *data = g_task_get_task_data (saving_task);
1120
		GtkSourceFileSaverFlags save_flags;
Paolo Borelli's avatar
Paolo Borelli committed
1121

1122
		set_info_bar (tab, NULL, GTK_RESPONSE_NONE);
Paolo Borelli's avatar
Paolo Borelli committed
1123

1124 1125
		data->force_no_backup = TRUE;
		save_flags = gtk_source_file_saver_get_flags (data->saver);
1126
		response_set_save_flags (saving_task, save_flags);
Paolo Borelli's avatar
Paolo Borelli committed
1127 1128

		/* Force saving */
1129
		launch_saver (saving_task);
Paolo Borelli's avatar
Paolo Borelli committed
1130 1131 1132
	}
	else
	{
1133
		unrecoverable_saving_error_info_bar_response (info_bar, response_id, saving_task);
Paolo Borelli's avatar
Paolo Borelli committed
1134 1135 1136 1137
	}
}

static void
1138
externally_modified_error_info_bar_response (GtkWidget *info_bar,
Sébastien Wilmet's avatar
Sébastien Wilmet committed
1139
					     gint       response_id,
1140
					     GTask     *saving_task)
Paolo Borelli's avatar
Paolo Borelli committed
1141 1142 1143
{
	if (response_id == GTK_RESPONSE_YES)
	{
1144 1145
		GeditTab *tab = g_task_get_source_object (saving_task);
		SaverData *data = g_task_get_task_data (saving_task);
1146
		GtkSourceFileSaverFlags save_flags;
1147

1148
		set_info_bar (tab, NULL, GTK_RESPONSE_NONE);
Paolo Borelli's avatar
Paolo Borelli committed
1149

1150
		/* ignore_modification_time should not be persisted in save
1151
		 * flags across saves (i.e. tab->save_flags is not modified).
1152
		 */
1153
		save_flags = gtk_source_file_saver_get_flags (data->saver);
1154
		save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_MODIFICATION_TIME;
1155
		response_set_save_flags (saving_task, save_flags);
Paolo Borelli's avatar
Paolo Borelli committed
1156 1157

		/* Force saving */
1158
		launch_saver (saving_task);
Paolo Borelli's avatar
Paolo Borelli committed
1159 1160
	}
	else
1161
	{
1162
		unrecoverable_saving_error_info_bar_response (info_bar, response_id, saving_task);
Paolo Borelli's avatar
Paolo Borelli committed
1163 1164 1165
	}
}

1166
static void
1167
recoverable_saving_error_info_bar_response (GtkWidget *info_bar,
Sébastien Wilmet's avatar
Sébastien Wilmet committed
1168
					    gint       response_id,
1169
					    GTask     *saving_task)
Paolo Borelli's avatar
Paolo Borelli committed
1170 1171 1172
{
	if (response_id == GTK_RESPONSE_OK)
	{
1173 1174
		GeditTab *tab = g_task_get_source_object (saving_task);
		SaverData *data = g_task_get_task_data (saving_task);
1175
		const GtkSourceEncoding *encoding;
Paolo Borelli's avatar
Paolo Borelli committed
1176

1177
		set_info_bar (tab, NULL, GTK_RESPONSE_NONE);
Paolo Borelli's avatar
Paolo Borelli committed
1178

1179 1180
		encoding = gedit_conversion_error_info_bar_get_encoding (GTK_WIDGET (info_bar));
		g_return_if_fail (encoding != NULL);
1181

1182
		gtk_source_file_saver_set_encoding (data->saver, encoding);
1183
		launch_saver (saving_task);
Paolo Borelli's avatar
Paolo Borelli committed
1184 1185
	}
	else
1186
	{
1187
		unrecoverable_saving_error_info_bar_response (info_bar, response_id, saving_task);
Paolo Borelli's avatar
Paolo Borelli committed
1188 1189 1190
	}
}

1191
static void
1192
externally_modified_notification_info_bar_response (GtkWidget *info_bar,
Sébastien Wilmet's avatar
Sébastien Wilmet committed
1193 1194
						    gint       response_id,
						    GeditTab  *tab)