From 573ee55470a9267f716ab3ded42406a4cd4041a8 Mon Sep 17 00:00:00 2001
From: CentOS Sources
Date: May 17 2022 09:16:32 +0000
Subject: import gedit-40.0-6.el9
---
diff --git a/.gedit.metadata b/.gedit.metadata
new file mode 100644
index 0000000..4959309
--- /dev/null
+++ b/.gedit.metadata
@@ -0,0 +1 @@
+8bd1e4e6b5f4d8761bdbb90ea13bc5d1e26c625e SOURCES/gedit-40.0.tar.xz
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..082979b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+SOURCES/gedit-40.0.tar.xz
diff --git a/SOURCES/0001-Add-40.0-release-info-to-appdata.patch b/SOURCES/0001-Add-40.0-release-info-to-appdata.patch
new file mode 100644
index 0000000..a9f5961
--- /dev/null
+++ b/SOURCES/0001-Add-40.0-release-info-to-appdata.patch
@@ -0,0 +1,24 @@
+From a03d70b6fb886e7c7e44775562826377fe073c27 Mon Sep 17 00:00:00 2001
+From: Kalev Lember
+Date: Fri, 2 Apr 2021 13:45:37 +0200
+Subject: [PATCH] Add 40.0 release info to appdata
+
+---
+ data/org.gnome.gedit.appdata.xml.in | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/data/org.gnome.gedit.appdata.xml.in b/data/org.gnome.gedit.appdata.xml.in
+index 5bf14503c..c5d3bdc94 100644
+--- a/data/org.gnome.gedit.appdata.xml.in
++++ b/data/org.gnome.gedit.appdata.xml.in
+@@ -36,6 +36,7 @@
+ gedit
+
+
++
+
+
+
+--
+2.30.2
+
diff --git a/SOURCES/0001-deteplification-the-mega-commit.patch b/SOURCES/0001-deteplification-the-mega-commit.patch
new file mode 100644
index 0000000..dda15b4
--- /dev/null
+++ b/SOURCES/0001-deteplification-the-mega-commit.patch
@@ -0,0 +1,20233 @@
+From b190bdb716fc8bb0cd515ee10fb3c51debede5fa Mon Sep 17 00:00:00 2001
+From: Zander Brown
+Date: Tue, 13 Apr 2021 04:53:21 +0000
+Subject: [PATCH] deteplification: the mega commit
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This commit is a reverse patch of a rebased version of gedit with
+commits related to tepl/amtk removed
+
+Sébastien Wilmet has stopped development of these libraries, relevant
+commits:
+
+https://gitlab.gnome.org/GNOME/amtk/-/commit/34a1171298808e5d9bd50540ee194b8be35bce9d
+https://gitlab.gnome.org/GNOME/tepl/-/commit/457b5c37ebcb2ebb23cae10cd47f1342db45a98e
+
+As a result usage is being dropped in favour simplifing gedit
+dependencies, because there are not enough developers, and too many bugs.
+Do you prefer a rock-solid text editor? Or a text editor with some shiny
+and non-essential dependencies that complicate the build, at the expense
+of more bugs?
+
+Tracked at: https://gitlab.gnome.org/Infrastructure/Infrastructure/-/issues/564
+
+Commits Dropped:
+cfeb7cb6c build: add Tepl dependency, second try
+872fb4809 Utils: use str truncate functions from Tepl
+9a121d523 Utils: deprecate str_end_truncate()
+e0e602799 No longer use gedit_utils_str_end_truncate()
+657ce9f7a Utils: deprecate str_middle_truncate()
+6eefa74c2 No longer use gedit_utils_str_middle_truncate()
+169c1594e main: call tepl_init() and tepl_finalize()
+ec31f0c22 snap: Fixed build failures by added tepl part
+76cf5562d Document: remove metadata implementation
+75cdb6a77 Document: second pass to remove metadata implementation
+d6b158ca6 App: remove the GeditMetadataManager
+6eccd6672 Remove GeditMetadataManager
+03929157e build: remove enable-gvfs-metadata option
+1dad3bce2 build: remove libxml dependency
+8c0825424 metadata: adapt key names for TeplFileMetadata
+c2904aa80 Document: metadata: create an internal TeplFile
+9c8ede1e2 App: setup Tepl metadata manager
+91bc04efc App: remove leftover comment
+b39dd0201 Document: use TeplFileMetadata to re-implement set/get_metadata()
+494677bfc Utils: use tepl_utils_replace_home_dir_with_tilde()
+aaaa28a87 docs: gtk-doc fixxref: fix the path for gtk and add path for tepl
+8710e89d8 Remove GeditViewCentering
+5e0909c19 ViewFrame: disable overlay scrolling for the GtkScrolledWindow
+7c7296b0e Remove overview map: remove from preferences dialog
+26899e0ba Remove overview map
+27f54a9ae replace-open-button: remove OpenDocumentSelector
+504ced5a9 replace-open-button: Window: remove open document popover
+3a8c5bbc2 replace-open-button: remove open button UI
+abab6529f replace-open-button: re-create a simple Open button
+1ee984a41 replace-open-button: re-create simple Open Recent menu button (UI)
+f1a58a70b replace-open-button: set Open Recent menu with Amtk
+020e0b340 replace-open-button: re-handle the fullscreen mode
+4dfd2104e Window: remove dead code (#defines)
+0caf371b1 Window: make the code a little clearer wrt fullscreen mode
+584aeb202 Window: rename fullscreen_controls -> fullscreen_revealer
+75705bf1d Window: some code cleanup wrt fullscreen mode
+cf0d62617 Window: simplify setting the state of the fullscreen revealer
+8706e5624 Window: fullscreen mode: remove idle function
+6361b281c Window: fullscreen mode: remove no longer needed code
+8d3e6faf2 Window: fullscreen mode: fix headerbar shown/hidden "stuttering"
+a437e5245 Window: fullscreen mode: add comment about the "stuttering" fix
+d064c5f88 Window: remove useless #include
+15833e5c7 build: list of deps: simplify
+007caff57 build: list of deps: simplify version requirements
+72dc3a477 build: avoid the use of a variable
+4a49c8562 flatpak: update Amtk to 5.0.2
+9ab7b0f0a utils: remove GBOOLEAN_TO_POINTER() and GPOINTER_TO_BOOLEAN()
+55c5f1423 Utils: deprecate gedit_warning()
+cbdd3a85d PreferencesDialog: use tepl_utils_show_warning_dialog()
+7a442c766 Utils: deprecate decode_uri(), use the tepl one
+bf3d57003 Use tepl_utils_decode_uri()
+2e45bb03f io-error-info-bar: remove useless #include's
+092411115 io-error-info-bar: use TeplInfoBar for the file_already_open_warning
+8ccb4566f io-error-info-bar: file_already_open_warning moved to Tepl
+8bfe0559a io-error-info-bar: use TeplInfoBar for no_backup_saving_error
+ca582d2c7 io-error-info-bar: fix fixme in no_backup_saving_error
+fa1758081 io-error-info-bar: no_backup_saving_error: show also error->message
+321eccdd7 io-error-info-bar: no_back_saving_error moved to Tepl
+7bb880114 io-error-info-bar: tepl function renamed to have a shorter name
+d1a14a063 io-error-info-bar: externally_modified: use TeplInfoBar
+bf60cc1af io-error-info-bar: invalid_character: TeplInfoBar + other improvements
+44cff9798 io-error-info-bar: externally_modified: remove unneeded code
+873ed25f1 io-error-info-bar: externally_modified: further simplify the code
+a8a4724fc io-error-info-bar: externally_modified: moved to Tepl
+ec8d8c717 io-error-info-bar: invalid_character: moved to Tepl
+2aae17c31 flatpak: switch Tepl to Meson
+9caaddeda Window: fix RTL bug for Open buttons in the headerbar
+82d8c507d View: subclass TeplView
+e23569c59 View: deprecate lots of functions, use the TeplView ones
+291eb9c8e commands-edit: use TeplView functions
+00f8c5e63 Use tepl_view_scroll_to_cursor()
+5fdeaee22 Document: deprecate goto_line() and goto_line_offset()
+d87bf25ba commands-file: use tepl_view_goto_line*()
+fd5500d90 Tab: use tepl_view_goto_line_offset()
+3c8a1dcb8 ViewFrame: use tepl_view_goto_line*()
+079f9699e pkg-config file: add Tepl as public dep
+cf6281d04 docs: document that gedit is in the process of using more Tepl features
+9ac62a6fd build: require Tepl 5
+3f84484d8 App: port to new Tepl metadata API
+9b9fa6c77 Document: port to new Tepl metadata API
+491280c04 docs: roadmap: link to new Tepl roadmap
+49db2a666 PreferencesDialog: use TeplStyleSchemeChooserWidget to fix several bugs
+94c3b70cb PreferencesDialog: improvements to color scheme management
+53cfa1715 PreferencesDialog: fix some bugs when (un)installing color schemes
+da5b9af9f snap: the tepl build is meson only now
+012a07cb7 snap: use the correct option to specify parameters
+325aa857c Factory: class skeleton
+7b8579770 Factory: implement ::create_metadata_manager_file vfunc
+d5a43cece Factory: create it in main() and set it as the TeplAbstractFactory
+392545195 App: use tepl_application_handle_metadata()
+8b2fa9092 Keep default buttons orientation for TeplInfoBars
+efe48bbe8 flatpak: remove uchardet, Tepl no longer depends on it
+5e588d978 PreferencesDialog: improve code to install extra style scheme
+eada68d97 PreferencesDialog: use GtkFileChooserNative, not GeditFileChooserDialog
+55fc5973c FileChooserDialog: remove hide() (now dead code)
+4f5a5681b FileChooserDialog: remove add_pattern_filter() (now dead code)
+105ca1ded File choosers: remove GeditFileChooserFlags
+ff1e9c27c Update Romanian translation
+b4a52f479 Merge branch 'master' of gitlab.gnome.org:GNOME/gedit
+21d94f23b Remove all the deprecated API
+4b5838b1e docs: update path to Amtk docs for the gtk-doc fixxref_args
+a4cf3ac57 Use tepl_pango_font_description_to_css()
+205bfc855 Window: port to TeplLanguageChooserWidget
+ffedbc882 commands-view: port to TeplLanguageChooserDialog
+1dc325294 Remove GeditHighlightModeSelector and GeditHighlightModeDialog
+e487680b2 Use Tepl 6 (currently 5.99)
+ee465ef0c Tab: port to TeplProgressInfoBar
+bc992e11e Remove GeditProgressInfoBar, replaced by TeplProgressInfoBar
+fa9d6aeaa docs: document the GeditProgressInfoBar removal
+bb4ba5543 docs: document that all deprecated APIs have been removed
+325351805 GeditDocument: subclass TeplBuffer
+8b01acace GeditDocument: remove the ::cursor-moved signal
+b938c50f8 Use the TeplBuffer::tepl-cursor-moved signal
+6b6a6e595 GeditDocument: bind GtkSourceFile and TeplFile :location properties
+f73828fe1 GeditDocument: remove unused instance variable
+01d8a1577 flatpak: build amtk from git master, not from an archive
+6e78a57c9 GeditDocument: use tepl_file_get_short_name()
+49749c38a GeditDocument: remove untitled_number handling
+844f6185a Tab: use TeplFile:short-name property notification
+49c0c814a GeditDocument: remove the :shortname property
+a4670d7ce help: "Untitled Document" -> "Untitled File"
+4d4d5d48c Use tepl_buffer_is_untouched()
+b0f67d391 GeditDocument: remove is_untouched()
+85b007052 GeditDocument: use the TeplFile location in is_untitled()
+4df850fb6 View: use TeplSignalGroup
+ef0d0ca9b View: minor code changes
+284e6c05c View: make set_font() private
+6b1e782d9 View: code refactorings for set_font()
+ce790b510 View: use tepl_utils_override_font()
+79b3e3011 GeditSettings: remove no longer needed code
+da4b3e61a GeditSettings: minor code change: removed unused function param
+13033affa GeditSettings: rework fonts changes handling, add ::fonts-changed signal
+878ceb988 GeditSettings: minor code change, improve get_system_font()
+1e89921a3 GeditSettings: add get_selected_font()
+9ef4cf7ed View: simplify the code to update the font
+3a3de93bd debug: remove DEBUG_METADATA (dead code)
+43925dac7 recent: use the TeplFile
+2f7c4a691 recent: move some functions to gedit-recent-osx
+87b1f50d4 recent-osx: add TODO comment
+
+Brought to you by GitLens, which honesntly has been very useful
+unpicking all this and sticking it back together again
+---
+ NEWS | 12 +
+ build-aux/flatpak/org.gnome.gedit.yml | 15 +-
+ build-aux/snap/snapcraft.yaml | 27 +-
+ data/org.gnome.gedit.gschema.xml.in | 5 +
+ docs/gedit-development-getting-started.md | 8 +-
+ docs/reference/api-breaks.xml | 50 +
+ docs/reference/gedit-docs.xml | 1 +
+ docs/reference/gedit-sections.txt | 36 +
+ docs/reference/meson.build | 6 +-
+ docs/roadmap-done.md | 56 -
+ docs/roadmap.md | 19 +-
+ gedit/Gedit-3.0.metadata | 1 +
+ gedit/gedit-app-osx.m | 4 +-
+ gedit/gedit-app-private.h | 3 +
+ gedit/gedit-app.c | 54 +-
+ gedit/gedit-commands-edit.c | 28 +-
+ gedit/gedit-commands-file.c | 26 +-
+ gedit/gedit-commands-search.c | 7 +-
+ gedit/gedit-commands-view.c | 42 +-
+ gedit/gedit-debug.c | 4 +
+ gedit/gedit-debug.h | 2 +
+ gedit/gedit-document-private.h | 12 +-
+ gedit/gedit-document.c | 534 ++++++-
+ gedit/gedit-document.h | 18 +-
+ gedit/gedit-documents-panel.c | 3 +-
+ gedit/gedit-factory.c | 50 -
+ gedit/gedit-factory.h | 53 -
+ gedit/gedit-file-chooser-dialog-gtk.c | 72 +-
+ gedit/gedit-file-chooser-dialog-gtk.h | 9 +-
+ gedit/gedit-file-chooser-dialog.c | 40 +-
+ gedit/gedit-file-chooser-dialog.h | 17 +
+ gedit/gedit-highlight-mode-dialog.c | 102 ++
+ gedit/gedit-highlight-mode-dialog.h | 41 +
+ gedit/gedit-highlight-mode-selector.c | 375 +++++
+ gedit/gedit-highlight-mode-selector.h | 44 +
+ gedit/gedit-io-error-info-bar.c | 362 ++++-
+ gedit/gedit-io-error-info-bar.h | 10 +
+ gedit/gedit-metadata-manager.c | 650 ++++++++
+ gedit/gedit-metadata-manager.h | 49 +
+ gedit/gedit-open-document-selector-helper.c | 103 ++
+ gedit/gedit-open-document-selector-helper.h | 103 ++
+ gedit/gedit-open-document-selector-store.c | 820 +++++++++++
+ gedit/gedit-open-document-selector-store.h | 68 +
+ gedit/gedit-open-document-selector.c | 1304 +++++++++++++++++
+ gedit/gedit-open-document-selector.h | 44 +
+ gedit/gedit-pango.c | 230 +++
+ gedit/gedit-pango.h | 28 +
+ gedit/gedit-preferences-dialog.c | 447 +++---
+ gedit/gedit-print-job.c | 4 +-
+ gedit/gedit-progress-info-bar.c | 177 +++
+ gedit/gedit-progress-info-bar.h | 53 +
+ gedit/gedit-recent-osx.c | 249 ----
+ gedit/gedit-recent-osx.h | 54 -
+ gedit/gedit-recent.c | 231 ++-
+ gedit/gedit-recent.h | 23 +-
+ gedit/gedit-settings.c | 177 ++-
+ gedit/gedit-settings.h | 7 +-
+ gedit/gedit-tab.c | 115 +-
+ gedit/gedit-utils.c | 333 ++++-
+ gedit/gedit-utils.h | 21 +-
+ gedit/gedit-view-centering.c | 495 +++++++
+ gedit/gedit-view-centering.h | 67 +
+ gedit/gedit-view-frame.c | 37 +-
+ gedit/gedit-view-frame.h | 4 +
+ gedit/gedit-view.c | 322 +++-
+ gedit/gedit-view.h | 24 +-
+ gedit/gedit-window-private.h | 15 +-
+ gedit/gedit-window.c | 380 ++---
+ gedit/gedit.c | 8 +-
+ gedit/meson.build | 23 +-
+ gedit/resources/css/gedit-style.css | 12 +
+ gedit/resources/css/gedit.adwaita.css | 25 +
+ gedit/resources/gedit.gresource.xml.in | 4 +
+ .../ui/gedit-highlight-mode-dialog.ui | 87 ++
+ .../ui/gedit-highlight-mode-selector.ui | 83 ++
+ .../ui/gedit-open-document-selector.ui | 115 ++
+ .../resources/ui/gedit-preferences-dialog.ui | 30 +-
+ gedit/resources/ui/gedit-progress-info-bar.ui | 88 ++
+ gedit/resources/ui/gedit-view-frame.ui | 27 +-
+ gedit/resources/ui/gedit-window.ui | 87 +-
+ help/C/gedit-tab-groups.page | 4 +-
+ meson.build | 34 +-
+ meson_options.txt | 7 +
+ plugins/snippets/snippets/document.py | 10 +-
+ plugins/spell/gedit-spell-plugin.c | 9 +-
+ po/POTFILES.in | 8 +-
+ 86 files changed, 8160 insertions(+), 1283 deletions(-)
+ delete mode 100644 docs/roadmap-done.md
+ delete mode 100644 gedit/gedit-factory.c
+ delete mode 100644 gedit/gedit-factory.h
+ create mode 100644 gedit/gedit-highlight-mode-dialog.c
+ create mode 100644 gedit/gedit-highlight-mode-dialog.h
+ create mode 100644 gedit/gedit-highlight-mode-selector.c
+ create mode 100644 gedit/gedit-highlight-mode-selector.h
+ create mode 100644 gedit/gedit-metadata-manager.c
+ create mode 100644 gedit/gedit-metadata-manager.h
+ create mode 100644 gedit/gedit-open-document-selector-helper.c
+ create mode 100644 gedit/gedit-open-document-selector-helper.h
+ create mode 100644 gedit/gedit-open-document-selector-store.c
+ create mode 100644 gedit/gedit-open-document-selector-store.h
+ create mode 100644 gedit/gedit-open-document-selector.c
+ create mode 100644 gedit/gedit-open-document-selector.h
+ create mode 100644 gedit/gedit-pango.c
+ create mode 100644 gedit/gedit-pango.h
+ create mode 100644 gedit/gedit-progress-info-bar.c
+ create mode 100644 gedit/gedit-progress-info-bar.h
+ delete mode 100644 gedit/gedit-recent-osx.c
+ delete mode 100644 gedit/gedit-recent-osx.h
+ create mode 100644 gedit/gedit-view-centering.c
+ create mode 100644 gedit/gedit-view-centering.h
+ create mode 100644 gedit/resources/ui/gedit-highlight-mode-dialog.ui
+ create mode 100644 gedit/resources/ui/gedit-highlight-mode-selector.ui
+ create mode 100644 gedit/resources/ui/gedit-open-document-selector.ui
+ create mode 100644 gedit/resources/ui/gedit-progress-info-bar.ui
+
+diff --git a/NEWS b/NEWS
+index d1f17abd1..fabc374cd 100644
+--- a/NEWS
++++ b/NEWS
+@@ -1,30 +1,42 @@
++News in [unreleased]
++----------------------------
++* Deteplification:
++ - The tepl maintainer has "frozen" the project until further notice
++ - Moving things to tepl introduced some breakage, such as translation of the
++ default filename
++ - gedit didn't use much of the API anyway
++ - Used even less of amtk
++ - Revert all usage of amtk and tepl
++ - Unfortunatly a couple bug fixes may have been lost
++ - Plugin API is essentially reverted to 3.36
++
+ News in 40, 2021-03-19
+ ----------------------------
+ * Remove all the deprecated API.
+ * file-browser: drop use of confirm-trash
+ * Translation updates.
+
+ Tepl-ification:
+ * Use tepl_pango_font_description_to_css().
+ * Use TeplLanguageChooser's.
+ * Use TeplProgressInfoBar.
+ * Start to use TeplBuffer and TeplFile APIs.
+ As a result the new tabs are now named "Untitled File", not
+ "Untitled Document".
+
+ News in 3.38.1, 2020-11-20
+ --------------------------
+ * AppData: change donation URL to Liberapay.
+ * Improvements to the user manual.
+ * Translation updates.
+
+ News in 3.38.0, 2020-09-11
+ --------------------------
+ * Translation updates.
+
+ News in 3.37.92, 2020-09-04
+ ---------------------------
+ * A few code refactorings.
+ * CI: small update.
+ * Translation updates.
+
+diff --git a/build-aux/flatpak/org.gnome.gedit.yml b/build-aux/flatpak/org.gnome.gedit.yml
+index 1438abd07..d3b535176 100644
+--- a/build-aux/flatpak/org.gnome.gedit.yml
++++ b/build-aux/flatpak/org.gnome.gedit.yml
+@@ -32,56 +32,51 @@ cleanup:
+ - "/share/aclocal"
+ - "/man"
+ - "/share/man"
+ - "/share/gtk-doc"
+ - "/share/vala"
+ - "/share/gir-1.0"
+ - "*.la"
+ - "*.a"
+
+ modules:
+ - name: libpeas
+ buildsystem: meson
+ config-opts:
+ - "-Dlua51=false"
+ - "-Dvapi=true"
+ - "-Ddemos=false"
+ - "-Dglade_catalog=false"
+ sources:
+ - type: archive
+ url: https://download.gnome.org/sources/libpeas/1.28/libpeas-1.28.0.tar.xz
+ sha256: 42d91993b46ed50f16add6d9577ecc22beb8e2dffa7101e2232c2b63733b8b15
+
+ - name: gspell
+ cleanup:
+ - "/bin"
+ sources:
+ - type: archive
+ url: https://download.gnome.org/sources/gspell/1.9/gspell-1.9.1.tar.xz
+ sha256: dcbb769dfdde8e3c0a8ed3102ce7e661abbf7ddf85df08b29915e92cd723abdd
+
+- - name: amtk
+- buildsystem: meson
++ - name: uchardet
++ buildsystem: cmake-ninja
+ sources:
+- - type: git
+- url: https://gitlab.gnome.org/GNOME/amtk.git
+-
+- - name: tepl
+- buildsystem: meson
+- sources:
+- - type: git
+- url: https://gitlab.gnome.org/GNOME/tepl.git
++ - type: archive
++ url: https://www.freedesktop.org/software/uchardet/releases/uchardet-0.0.6.tar.xz
++ sha256: 8351328cdfbcb2432e63938721dd781eb8c11ebc56e3a89d0f84576b96002c61
+
+ - name: gedit
+ buildsystem: meson
+ sources:
+ - type: git
+ url: https://gitlab.gnome.org/GNOME/gedit.git
+ # To build a local branch, comment out 'url' and uncomment:
+ # path: ../../
+ # branch: wip/misc
+
+ - name: gedit-plugins
+ buildsystem: meson
+ sources:
+ - type: git
+ url: https://gitlab.gnome.org/GNOME/gedit-plugins.git
+diff --git a/build-aux/snap/snapcraft.yaml b/build-aux/snap/snapcraft.yaml
+index fc49c3949..43db5e027 100644
+--- a/build-aux/snap/snapcraft.yaml
++++ b/build-aux/snap/snapcraft.yaml
+@@ -14,121 +14,98 @@ layout:
+ symlink: $SNAP/usr/share/gedit
+
+ slots:
+ # for GtkApplication registration
+ gedit:
+ interface: dbus
+ bus: session
+ name: org.gnome.gedit
+
+ apps:
+ gedit:
+ command: usr/bin/gedit
+ extensions: [gnome-3-28]
+ plugs:
+ - avahi-observe
+ - cups-control
+ - gsettings
+ - home
+ - network
+ - mount-observe
+ - removable-media
+ common-id: org.gnome.gedit.desktop
+ environment:
+ GSETTINGS_SCHEMA_DIR: $SNAP/share/glib-2.0/schemas
+ LD_LIBRARY_PATH: $LD_LIBRARY_PATH:$SNAP/lib/$SNAPCRAFT_ARCH_TRIPLET/gedit:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET:$SNAP/gnome-platform/usr/lib/$SNAPCRAFT_ARCH_TRIPLET
+ GI_TYPELIB_PATH: $SNAP/usr/lib/girepository-1.0:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/gedit/girepository-1.0:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/girepository-1.0:$SNAP/gnome-platform/usr/lib/girepository-1.0:$SNAP/gnome-platform/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/girepository-1.0
+ PYTHONPATH: $SNAP/usr/lib/python3/dist-packages:$SNAP/gnome-platform/usr/lib/python3/dist-packages
+ GTK_USE_PORTAL: 1
+
+ parts:
+- amtk:
+- source: https://gitlab.gnome.org/GNOME/amtk.git
+- source-type: git
+- plugin: autotools
+- configflags:
+- - --prefix=/usr
+- - --enable-introspection=no
+- organize:
+- snap/gedit/current/usr: usr
+-
+- tepl:
+- after: [amtk, gtksourceview]
+- source: https://gitlab.gnome.org/GNOME/tepl.git
+- source-type: git
+- plugin: meson
+- meson-parameters:
+- - --prefix=/usr
+- organize:
+- snap/gedit/current/usr: usr
+- build-packages:
+- - libuchardet-dev
+- stage-packages:
+- - libuchardet0
+-
+ gtksourceview:
+ source: https://gitlab.gnome.org/GNOME/gtksourceview.git
+ source-type: git
+ plugin: meson
+ meson-parameters:
+ - --prefix=/usr
+ - -Dc_args="-Wno-error=undef"
+ organize:
+ snap/gedit/current/usr: usr
+ build-packages:
+ - autoconf-archive
+ - gettext
+ - gobject-introspection
+ - gtk-doc-tools
+ - libfribidi-dev
+ - libgirepository1.0-dev
+ - libglib2.0-dev
+ - libgtk-3-dev
+ - libpeas-dev
+ - libxml2-dev
+ - libxml2-utils
+ - valac
+ # meson gir overrides don't work well
+ override-build: |
+ snapcraftctl build
+ cp $SNAPCRAFT_PART_INSTALL/usr/share/gir-1.0/GtkSource* /usr/share/gir-1.0
+ cp $SNAPCRAFT_PART_INSTALL/usr/share/vala/vapi/gtksource* /usr/share/vala/vapi
+
+ gedit:
+- after: [gtksourceview, tepl]
++ after: [gtksourceview]
+ source: .
+ source-type: git
+ parse-info: [usr/share/metainfo/org.gnome.gedit.appdata.xml]
+ plugin: meson
+ meson-parameters:
+ - --prefix=/usr
+ - -Dvala_args="--vapidir=$SNAPCRAFT_STAGE/usr/share/vala/vapi"
++
+ build-environment:
+ - C_INCLUDE_PATH: $SNAPCRAFT_STAGE/usr/include/gtksourceview-4
+ override-build: |
+ sed -i.bak -e 's|Icon=org.gnome.gedit$|Icon=${SNAP}/meta/gui/org.gnome.gedit.svg|g' data/org.gnome.gedit.desktop.in
+ sed -i.bak -e "s|symlink_media: true|symlink_media: false|g" help/meson.build
+ snapcraftctl build
+ mkdir -p $SNAPCRAFT_PART_INSTALL/meta/gui/
+ cp data/icons/org.gnome.gedit.svg $SNAPCRAFT_PART_INSTALL/meta/gui/
+ cp ../install/usr/share/applications/org.gnome.gedit.desktop $SNAPCRAFT_PART_INSTALL/meta/gui/
+ build-packages:
+ - desktop-file-utils
+ - gettext
+ - gsettings-desktop-schemas-dev
+ - gtk-doc-tools
+ - itstool
+ - libsoup2.4-dev
+ - libgspell-1-dev
+ - libxml2-dev
+ - libglib2.0-dev
+ - libgtk-3-dev
+ - libpeas-dev
+ - libx11-dev
+ - python3
+ - python-gi-dev
+ - gobject-introspection
+ - libgirepository1.0-dev
+ - valac
+ stage-packages:
+ - libfribidi0
+
+diff --git a/data/org.gnome.gedit.gschema.xml.in b/data/org.gnome.gedit.gschema.xml.in
+index b797d843c..59325f4ef 100644
+--- a/data/org.gnome.gedit.gschema.xml.in
++++ b/data/org.gnome.gedit.gschema.xml.in
+@@ -99,60 +99,65 @@
+
+ true
+ Automatic indent
+ Whether gedit should enable automatic indentation.
+
+
+ true
+ Display Line Numbers
+ Whether gedit should display line numbers in the editing area.
+
+
+ true
+ Highlight Current Line
+ Whether gedit should highlight the current line.
+
+
+ true
+ Highlight Matching Brackets
+ Whether gedit should highlight matching brackets.
+
+
+ false
+ Display Right Margin
+ Whether gedit should display the right margin in the editing area.
+
+
+ 80
+ Right Margin Position
+ Specifies the position of the right margin.
+
++
++ false
++ Display Overview Map
++ Whether gedit should display the overview map for the document.
++
+
+ 'none'
+ Document background pattern type
+ Whether the document will get a background pattern painted.
+
+
+
+
+
+
+
+
+ 'after'
+ Smart Home End
+ Specifies how the cursor moves when the HOME and END keys are pressed. Use “disabled” to always move at the start/end of the line, “after” to move to the start/end of the line the first time the keys are pressed and to the start/end of the text ignoring whitespaces the second time the keys are pressed, “before” to move to the start/end of the text before moving to the start/end of the line and “always” to always move to the start/end of the text instead of the start/end of the line.
+
+
+ true
+ Restore Previous Cursor Position
+ Whether gedit should restore the previous cursor position when a file is loaded.
+
+
+ true
+ Enable Syntax Highlighting
+ Whether gedit should enable syntax highlighting.
+
+
+ true
+ Enable Search Highlighting
+ Whether gedit should highlight all the occurrences of the searched text.
+diff --git a/docs/gedit-development-getting-started.md b/docs/gedit-development-getting-started.md
+index 4f930afc7..774bc180f 100644
+--- a/docs/gedit-development-getting-started.md
++++ b/docs/gedit-development-getting-started.md
+@@ -4,65 +4,63 @@ gedit development - getting started
+ The following explanations can be improved over time, if you see something
+ missing, a feedback is welcome.
+
+ Programming languages and paradigms
+ -----------------------------------
+
+ gedit is mostly written in C, with some plugins in Python or
+ [Vala](https://wiki.gnome.org/Projects/Vala/). The build system is in
+ [Meson](https://mesonbuild.com/).
+
+ The code is object-oriented and event-driven. In C, it's thanks to the use of
+ the GObject library (see next section). If you open some `*.c` or `*.h` files,
+ you may think “what is this horror?!” but – don't panic – it's just some
+ C/GObject boilerplate code, and that boilerplate can be generated by a tool. So
+ once you've learned GObject, you will no longer be afraid ;-)
+
+ Libraries used
+ --------------
+
+ As every GNOME application, gedit uses the GLib, GObject and GTK libraries. To
+ modify the gedit source code, you should be familiar with those libraries. See
+ the [GTK website](https://www.gtk.org/) and the document
+ [The GLib/GTK Development Platform – A Getting Started Guide](https://people.gnome.org/~swilmet/glib-gtk-book/).
+
+ The main widget used by gedit is GtkTextView, a general-purpose multiline text
+ editor. To learn that widget API, read the excellent
+ [GtkTextView tutorial](http://www.bravegnu.org/gtktext/) (a bit old but still
+ mostly valid). But GtkTextView is not enough for source code edition. gedit
+ actually uses the
+ [GtkSourceView](https://wiki.gnome.org/Projects/GtkSourceView) library, which
+-contains a subclass of GtkTextView with many features useful for a text editor
+-or an IDE. But GtkSourceView is not enough to have a full-blown text editor,
+-gedit is actually in the process of using more features from the
+-[Tepl](https://wiki.gnome.org/Projects/Tepl) library, and to further develop
+-Tepl alongside gedit.
++contains a subclass of GtkTextView with syntax highlighting, a completion
++framework, the search and replace, and many other features useful for a text
++editor or an IDE.
+
+ For its plugin system, gedit uses the
+ [libpeas](https://wiki.gnome.org/Projects/Libpeas) library.
+
+ Plugins may have other dependencies, for example the spell-checking plugin uses
+ [gspell](https://wiki.gnome.org/Projects/gspell).
+
+ gedit architecture
+ ------------------
+
+ The [gedit Git repository](https://gitlab.gnome.org/GNOME/gedit) contains the
+ _gedit core_ plus the default plugins. There is also the
+ [gedit-plugins Git repository](https://gitlab.gnome.org/GNOME/gedit-plugins)
+ for additional official plugins. The gedit core source code is in the `gedit/`
+ directory. The plugins are in … `plugins/`!
+
+ gedit core provides:
+ - A basic text editor.
+ - The integration of libpeas, with an API for plugins.
+
+ There is a class diagram of gedit core in the file
+ [class-diagram.dia](class-diagram.dia) (but it may be outdated, see the Git log
+ for that file).
+
+ Build/Installation
+ ------------------
+
+ See the file [build.md](build.md).
+
+ First contribution
+diff --git a/docs/reference/api-breaks.xml b/docs/reference/api-breaks.xml
+index f631761a6..f03c35975 100644
+--- a/docs/reference/api-breaks.xml
++++ b/docs/reference/api-breaks.xml
+@@ -1,53 +1,103 @@
+
+
+ ]>
+
+
+ API Breaks
+
+
+ gedit is a quite old piece of software (created in 1998, at the beginnings
+ of the GNOME project), and as every software, the code evolves during its
+ lifetime. So there are sometimes API breaks for gedit plugins, there are no
+ API stability guarantees.
+
+
+
+ When it is possible, instead of directly removing an API, that API is first
+ marked as deprecated, and then removed for the next API break. See the
+ index of deprecated symbols.
+
+
++
++ 40 -> 41
++
++
++
++ The GeditProgressInfoBar class has been restored
++
++
++
++
++ GeditDocument is no longer a subclass
++ of TeplBuffer.
++
++
++
++
++ The GeditDocument::cursor-moved signal has been restored.
++
++
++
++
++ The GeditDocument:shortname property has been restored.
++
++
++
++
++ The gedit_document_is_untouched() function has been
++ restored.
++
++
++
++
++ The gedit_view_set_font() function has been restored.
++
++
++
++
++ DEBUG_METADATA has been restored.
++
++
++
++
++ The GBOOLEAN_TO_POINTER() and
++ GPOINTER_TO_BOOLEAN() macros have been restored to
++ gedit-utils.h.
++
++
++
++
++
+
+ 3.38 -> 40
+
+
+
+ All previously deprecated APIs have been removed.
+
+
+
+
+ The GeditProgressInfoBar class has been removed, you can
+ use TeplProgressInfoBar
+ instead.
+
+
+
+
+ GeditDocument is now a subclass
+ of TeplBuffer.
+
+
+
+
+ The GeditDocument::cursor-moved signal has been removed.
+ You can use the TeplBuffer API
+ instead.
+
+
+
+
+diff --git a/docs/reference/gedit-docs.xml b/docs/reference/gedit-docs.xml
+index a0dc624cf..9e32e5469 100644
+--- a/docs/reference/gedit-docs.xml
++++ b/docs/reference/gedit-docs.xml
+@@ -1,48 +1,49 @@
+
+
+
+
+ gedit Reference Manual
+
+
+
+ API Reference
+
+
+
+
+
+
+
+
++
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Annexes
+
+
+ Object Hierarchy
+
+
+
+
+
+
+ Index of all symbols
+
+
+
+ Index of deprecated symbols
+
+
+diff --git a/docs/reference/gedit-sections.txt b/docs/reference/gedit-sections.txt
+index cec055fce..a71e00faa 100644
+--- a/docs/reference/gedit-sections.txt
++++ b/docs/reference/gedit-sections.txt
+@@ -27,61 +27,64 @@ gedit_app_activatable_activate
+ gedit_app_activatable_deactivate
+ gedit_app_activatable_extend_menu
+
+ GEDIT_TYPE_APP_ACTIVATABLE
+ GEDIT_APP_ACTIVATABLE
+ GEDIT_APP_ACTIVATABLE_IFACE
+ GEDIT_IS_APP_ACTIVATABLE
+ GEDIT_APP_ACTIVATABLE_GET_IFACE
+ gedit_app_activatable_get_type
+
+
+
+ gedit-commands
+ GeditCommands
+ gedit_commands_load_location
+ gedit_commands_load_locations
+ gedit_commands_save_document
+ gedit_commands_save_document_async
+ gedit_commands_save_document_finish
+ gedit_commands_save_all_documents
+
+
+
+ gedit-document
+ GeditDocument
+ GeditDocument
+ gedit_document_new
+ gedit_document_get_file
+ gedit_document_get_short_name_for_display
+ gedit_document_get_mime_type
++gedit_document_is_untouched
+ gedit_document_is_untitled
++gedit_document_goto_line
++gedit_document_goto_line_offset
+ gedit_document_set_language
+ gedit_document_get_content_type
+ gedit_document_get_metadata
+ gedit_document_set_metadata
+ gedit_document_set_search_context
+ gedit_document_get_search_context
+
+ GEDIT_DOCUMENT
+ GEDIT_IS_DOCUMENT
+ GEDIT_TYPE_DOCUMENT
+ gedit_document_get_type
+ GEDIT_DOCUMENT_CLASS
+ GEDIT_IS_DOCUMENT_CLASS
+ GEDIT_DOCUMENT_GET_CLASS
+
+
+
+ gedit-encodings-combo-box
+ GeditEncodingsComboBox
+ GeditEncodingsComboBox
+ gedit_encodings_combo_box_new
+ gedit_encodings_combo_box_get_selected_encoding
+ gedit_encodings_combo_box_set_selected_encoding
+
+ GEDIT_ENCODINGS_COMBO_BOX
+ GEDIT_IS_ENCODINGS_COMBO_BOX
+ GEDIT_TYPE_ENCODINGS_COMBO_BOX
+ gedit_encodings_combo_box_get_type
+ GEDIT_ENCODINGS_COMBO_BOX_CLASS
+ GEDIT_IS_ENCODINGS_COMBO_BOX_CLASS
+@@ -121,111 +124,138 @@ GEDIT_TYPE_MESSAGE_BUS
+ gedit_message_bus_get_type
+ GEDIT_MESSAGE_BUS_CLASS
+ GEDIT_IS_MESSAGE_BUS_CLASS
+ GEDIT_MESSAGE_BUS_GET_CLASS
+ GeditMessageBusPrivate
+
+
+
+ gedit-message
+ GeditMessage
+ GeditMessage
+ gedit_message_get_object_path
+ gedit_message_get_method
+ gedit_message_type_has
+ gedit_message_type_check
+ gedit_message_has
+ gedit_message_is_valid_object_path
+ gedit_message_type_identifier
+
+ GEDIT_MESSAGE
+ GEDIT_MESSAGE_CONST
+ GEDIT_IS_MESSAGE
+ GEDIT_TYPE_MESSAGE
+ gedit_message_get_type
+ GEDIT_MESSAGE_CLASS
+ GEDIT_IS_MESSAGE_CLASS
+ GEDIT_MESSAGE_GET_CLASS
+ GeditMessagePrivate
+
+
++
++gedit-progress-info-bar
++GeditProgressInfoBar
++GeditProgressInfoBar
++gedit_progress_info_bar_new
++gedit_progress_info_bar_set_icon_name
++gedit_progress_info_bar_set_markup
++gedit_progress_info_bar_set_text
++gedit_progress_info_bar_set_fraction
++gedit_progress_info_bar_pulse
++
++GEDIT_PROGRESS_INFO_BAR
++GEDIT_IS_PROGRESS_INFO_BAR
++GEDIT_TYPE_PROGRESS_INFO_BAR
++gedit_progress_info_bar_get_type
++GEDIT_PROGRESS_INFO_BAR_CLASS
++GEDIT_IS_PROGRESS_INFO_BAR_CLASS
++GEDIT_PROGRESS_INFO_BAR_GET_CLASS
++
++
+
+ gedit-statusbar
+ GeditStatusbar
+ GeditStatusbar
+ gedit_statusbar_new
+ gedit_statusbar_set_window_state
+ gedit_statusbar_set_overwrite
+ gedit_statusbar_clear_overwrite
+ gedit_statusbar_flash_message
+
+ GEDIT_STATUSBAR
+ GEDIT_IS_STATUSBAR
+ GEDIT_TYPE_STATUSBAR
+ gedit_statusbar_get_type
+ GEDIT_STATUSBAR_CLASS
+ GEDIT_IS_STATUSBAR_CLASS
+ GEDIT_STATUSBAR_GET_CLASS
+
+
+
+ gedit-tab
+ GeditTab
+ GeditTab
+ GeditTabState
+ gedit_tab_get_view
+ gedit_tab_get_document
+ gedit_tab_get_from_document
+ gedit_tab_get_state
+ gedit_tab_get_auto_save_enabled
+ gedit_tab_set_auto_save_enabled
+ gedit_tab_get_auto_save_interval
+ gedit_tab_set_auto_save_interval
+ gedit_tab_set_info_bar
+
+ GEDIT_TAB
+ GEDIT_IS_TAB
+ GEDIT_TYPE_TAB
+ gedit_tab_get_type
+ GEDIT_TAB_CLASS
+ GEDIT_IS_TAB_CLASS
+ GEDIT_TAB_GET_CLASS
+ GEDIT_TYPE_TAB_STATE
+ gedit_tab_state_get_type
+
+
+
+ gedit-view
+ GeditViewPrivate
+ GeditView
+ GeditView
+ gedit_view_new
++gedit_view_cut_clipboard
++gedit_view_copy_clipboard
++gedit_view_paste_clipboard
++gedit_view_delete_selection
++gedit_view_select_all
++gedit_view_scroll_to_cursor
++gedit_view_set_font
+
+ GEDIT_VIEW
+ GEDIT_IS_VIEW
+ GEDIT_TYPE_VIEW
+ gedit_view_get_type
+ GEDIT_VIEW_CLASS
+ GEDIT_IS_VIEW_CLASS
+ GEDIT_VIEW_GET_CLASS
+
+
+
+ gedit-view-activatable
+ GeditViewActivatable
+ GeditViewActivatable
+ gedit_view_activatable_activate
+ gedit_view_activatable_deactivate
+
+ GEDIT_TYPE_VIEW_ACTIVATABLE
+ GEDIT_VIEW_ACTIVATABLE
+ GEDIT_VIEW_ACTIVATABLE_IFACE
+ GEDIT_IS_VIEW_ACTIVATABLE
+ GEDIT_VIEW_ACTIVATABLE_GET_IFACE
+ gedit_view_activatable_get_type
+
+
+
+ gedit-window
+ GeditWindow
+ GeditWindow
+ GeditWindowState
+@@ -264,70 +294,76 @@ gedit_window_state_get_type
+
+
+ gedit-window-activatable
+ GeditWindowActivatable
+ GeditWindowActivatable
+ gedit_window_activatable_activate
+ gedit_window_activatable_deactivate
+ gedit_window_activatable_update_state
+
+ GEDIT_TYPE_WINDOW_ACTIVATABLE
+ GEDIT_WINDOW_ACTIVATABLE
+ GEDIT_WINDOW_ACTIVATABLE_IFACE
+ GEDIT_IS_WINDOW_ACTIVATABLE
+ GEDIT_WINDOW_ACTIVATABLE_GET_IFACE
+ gedit_window_activatable_get_type
+
+
+
+ gedit-debug
+ GeditDebugSection
+ DEBUG_VIEW
+ DEBUG_PREFS
+ DEBUG_WINDOW
+ DEBUG_PANEL
+ DEBUG_PLUGINS
+ DEBUG_TAB
+ DEBUG_DOCUMENT
+ DEBUG_COMMANDS
+ DEBUG_APP
+ DEBUG_UTILS
++DEBUG_METADATA
+ gedit_debug_init
+ gedit_debug
+ gedit_debug_message
+ gedit_debug_plugin_message
+
+ GEDIT_TYPE_DEBUG_SECTION
+ gedit_debug_section_get_type
+
+
+
+ gedit-menu-extension
+ GeditMenuExtension
+ gedit_menu_extension_new
+ gedit_menu_extension_append_menu_item
+ gedit_menu_extension_prepend_menu_item
+ gedit_menu_extension_remove_items
+
+ GEDIT_IS_MENU_EXTENSION
+ GEDIT_IS_MENU_EXTENSION_CLASS
+ GEDIT_MENU_EXTENSION
+ GEDIT_MENU_EXTENSION_CLASS
+ GEDIT_MENU_EXTENSION_CONST
+ GEDIT_MENU_EXTENSION_GET_CLASS
+ GEDIT_TYPE_MENU_EXTENSION
+ GeditMenuExtensionClass
+ gedit_menu_extension_get_type
+
+
+
+ gedit-utils
++GBOOLEAN_TO_POINTER
++GPOINTER_TO_BOOLEAN
+ gedit_utils_menu_position_under_tree_view
+ gedit_utils_set_atk_name_description
++gedit_warning
++gedit_utils_replace_home_dir_with_tilde
+ gedit_utils_basename_for_display
++gedit_utils_decode_uri
+ gedit_utils_drop_get_uris
+ gedit_utils_get_compression_type_from_content_type
+ gedit_utils_is_valid_location
+ gedit_utils_location_get_dirname_for_display
+ gedit_utils_set_direct_save_filename
+ gedit_utils_newline_type_to_string
+
+diff --git a/docs/reference/meson.build b/docs/reference/meson.build
+index 9a9c414dc..ed85f9cec 100644
+--- a/docs/reference/meson.build
++++ b/docs/reference/meson.build
+@@ -1,42 +1,38 @@
+ html_dir = get_option('prefix') / gnome.gtkdoc_html_dir('gedit')
+
+ glib_docpath = dependency('glib-2.0').get_pkgconfig_variable('prefix') / 'share/gtk-doc/html/glib'
+ gobject_docpath = dependency('gobject-2.0').get_pkgconfig_variable('prefix') / 'share/gtk-doc/html/gobject'
+ gio_docpath = dependency('gio-2.0').get_pkgconfig_variable('prefix') / 'share/gtk-doc/html/gio'
+ gdk_docpath = dependency('gdk-3.0').get_pkgconfig_variable('prefix') / 'share/gtk-doc/html/gdk3'
+ gtk_docpath = dependency('gtk+-3.0').get_pkgconfig_variable('prefix') / 'share/gtk-doc/html/gtk3'
+ gsv_docpath = dependency('gtksourceview-4').get_pkgconfig_variable('prefix') / 'share/gtk-doc/html/gtksourceview-4.0'
+-amtk_docpath = dependency('amtk-5').get_pkgconfig_variable('prefix') / 'share/gtk-doc/html/amtk-5'
+-tepl_docpath = dependency('tepl-6').get_pkgconfig_variable('prefix') / 'share/gtk-doc/html/tepl-6'
+ libpeas_docpath = dependency('libpeas-1.0').get_pkgconfig_variable('prefix') / 'share/gtk-doc/html/libpeas'
+
+ gedit_doc_dep = declare_dependency(
+ link_with: libgedit_shared_lib,
+ include_directories: root_include_dir,
+- dependencies: deps_basic_list,
++ dependencies: deps_basic_list + [libxml_dep],
+ )
+
+ gnome.gtkdoc(
+ 'gedit',
+ main_xml: 'gedit-docs.xml',
+ src_dir: include_directories('../../gedit/'),
+ dependencies: gedit_doc_dep,
+ scan_args: ['--rebuild-types'],
+ fixxref_args: [
+ '--html-dir=@0@'.format(html_dir),
+ '--extra-dir=@0@'.format(glib_docpath),
+ '--extra-dir=@0@'.format(gobject_docpath),
+ '--extra-dir=@0@'.format(gio_docpath),
+ '--extra-dir=@0@'.format(gdk_docpath),
+ '--extra-dir=@0@'.format(gtk_docpath),
+ '--extra-dir=@0@'.format(gsv_docpath),
+- '--extra-dir=@0@'.format(amtk_docpath),
+- '--extra-dir=@0@'.format(tepl_docpath),
+ '--extra-dir=@0@'.format(libpeas_docpath),
+ ],
+ content_files: [
+ 'api-breaks.xml'
+ ],
+ ignore_headers: libgedit_private_headers,
+ install: true,
+ )
+diff --git a/docs/roadmap-done.md b/docs/roadmap-done.md
+deleted file mode 100644
+index 7f210e49b..000000000
+--- a/docs/roadmap-done.md
++++ /dev/null
+@@ -1,56 +0,0 @@
+-gedit roadmap - done tasks
+-==========================
+-
+-Tepl-ification of the gedit core
+---------------------------------
+-
+-- gedit 3.36:
+- - Start to use the Tepl library.
+- - Use some Tepl utility functions.
+- - Use TeplFileMetadata, remove GeditMetadataManager.
+-- gedit 3.38:
+- - Move some utility functions to the Tepl library.
+- - Refactor and move some I/O error infobars to Tepl.
+- - GeditView now inherits from TeplView.
+- - Port to the new Tepl metadata API.
+- - Use TeplStyleSchemeChooserWidget in the preferences dialog.
+- - Create GeditFactory class, subclass of TeplAbstractFactory.
+-- gedit 40:
+- - Use `tepl_pango_font_description_to_css()`.
+- - Use TeplLanguageChooser's, for choosing a language for the syntax
+- highlighting. Remove GeditHighlightModeSelector and
+- GeditHighlightModeDialog.
+- - Use TeplProgressInfoBar. Remove GeditProgressInfoBar.
+- - GeditDocument now inherits from TeplBuffer, start to use the
+- TeplBuffer and TeplFile APIs.
+-
+-Links:
+-- https://wiki.gnome.org/Projects/Tepl
+-
+-Tepl-ification of the gedit plugins
+------------------------------------
+-
+-- gedit 40:
+- - Draw Spaces plugin: new implementation based on TeplSpaceDrawerPrefs.
+-
+-Other done tasks in gedit plugins
+----------------------------------
+-
+-- gedit 40:
+- - Smart Spaces plugin: new implementation based on a GtkSourceView
+- feature.
+-
+-New version of gedit on Windows
+--------------------------------
+-
+-[gedit is now available on the Microsoft Store](https://www.microsoft.com/store/apps/9PL1J21XF0PT).
+-It was done during the GNOME 3.38 development cycle. The integration with
+-Windows is not perfect, but it works. It is planned to improve gedit for
+-Windows over time.
+-
+-Documentation for contributors
+-------------------------------
+-
+-Write a guide to get started with gedit development.
+-
+-Done during the GNOME 3.34 development cycle.
+diff --git a/docs/roadmap.md b/docs/roadmap.md
+index 44a2f00b7..ec9445712 100644
+--- a/docs/roadmap.md
++++ b/docs/roadmap.md
+@@ -1,57 +1,40 @@
+ gedit roadmap
+ =============
+
+ This page contains the plans for major code changes we hope to get done in the
+ future.
+
+-See the [roadmap-done.md](roadmap-done.md) file for done tasks.
++See also the [GtkSourceView](https://wiki.gnome.org/Projects/GtkSourceView/RoadMap).
+
+ See the [NEWS file](../NEWS) for a detailed history.
+
+-See also the
+-[Tepl roadmap](https://gitlab.gnome.org/GNOME/tepl/blob/master/docs/roadmap.md).
+-
+-Continue to make the gedit source code more re-usable
+------------------------------------------------------
+-
+-Status: **in progress** (this is an ongoing effort)
+-
+-Next steps:
+-- Use more features from the Tepl library, and develop Tepl alongside gedit.
+- The goal is to reduce the amount of code in gedit, by having re-usable code
+- in Tepl instead.
+-
+-Links:
+-- https://wiki.gnome.org/Apps/Gedit/ReusableCode
+-- https://wiki.gnome.org/Projects/Tepl
+-
+ Improve gedit on Windows
+ ------------------------
+
+ Status: **in progress**
+
+ [gedit is now available on the Microsoft Store](https://www.microsoft.com/store/apps/9PL1J21XF0PT).
+ The integration with Windows is not perfect, but it works. It is planned to
+ improve gedit for Windows over time.
+
+ Replace search and replace dialog window by an horizontal bar below the text
+ ----------------------------------------------------------------------------
+
+ Status: **todo**
+
+ To not hide the text.
+
+ Be able to quit the application with all documents saved, and restored on next start
+ ------------------------------------------------------------------------------------
+
+ Status: **todo**
+
+ Even for unsaved and untitled files, be able to quit gedit, restart it later and
+ come back to the state before with all tabs restored.
+
+ Improve the workflow for printing to paper
+ ------------------------------------------
+
+ Status: **todo**
+
+ Implement it like in Firefox, show first a preview of the file to print.
+diff --git a/gedit/Gedit-3.0.metadata b/gedit/Gedit-3.0.metadata
+index e36d7cb30..1a5b45a3a 100644
+--- a/gedit/Gedit-3.0.metadata
++++ b/gedit/Gedit-3.0.metadata
+@@ -1,23 +1,24 @@
+ App cheader_filename="gedit/gedit-app.h"
+ AppActivatable cheader_filename="gedit/gedit-app-activatable.h"
+ DebugSection cheader_filename="gedit/gedit-debug.h"
+ Document cheader_filename="gedit/gedit-document.h"
+ EncodingsComboBox cheader_filename="gedit/gedit-encodings-combo-box.h"
+ MenuExtension cheader_filename="gedit/gedit-menu-extension.h"
+ Message cheader_filename="gedit/gedit-message.h"
+ MessageBus cheader_filename="gedit/gedit-message-bus.h"
++ProgressInfoBar cheader_filename="gedit/gedit-progress-info-bar.h"
+ Statusbar cheader_filename="gedit/gedit-statusbar.h"
+ Tab cheader_filename="gedit/gedit-tab.h"
+ TabState cheader_filename="gedit/gedit-tab.h"
+ View cheader_filename="gedit/gedit-view.h"
+ ViewActivatable cheader_filename="gedit/gedit-view-activatable.h"
+ Window cheader_filename="gedit/gedit-window.h"
+ WindowActivatable cheader_filename="gedit/gedit-window-activatable.h"
+ WindowState cheader_filename="gedit/gedit-window.h"
+
+ commands_* cheader_filename="gedit/gedit-commands.h"
+ debug* cheader_filename="gedit/gedit-debug.h"
+ utils_* cheader_filename="gedit/gedit-utils.h"
+
+ MessageBusForeach cheader_filename="gedit/gedit-message-bus.h"
+ MessageCallback cheader_filename="gedit/gedit-message-bus.h"
+diff --git a/gedit/gedit-app-osx.m b/gedit/gedit-app-osx.m
+index b02e9a28b..5df1b94da 100644
+--- a/gedit/gedit-app-osx.m
++++ b/gedit/gedit-app-osx.m
+@@ -4,61 +4,61 @@
+ *
+ * Copyright (C) 2010 - Jesse van den Kieboom
+ *
+ * gedit 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.
+ *
+ * gedit 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
+ * along with gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+ #include "gedit-app-osx.h"
+
+ #include
+ #include
+ #include
+
+ #include "gedit-app-private.h"
+ #include "gedit-dirs.h"
+ #include "gedit-debug.h"
+ #include "gedit-commands.h"
+ #include "gedit-commands-private.h"
+-#include "gedit-recent-osx.h"
++#include "gedit-recent.h"
+ #import
+
+ NSWindow *gdk_quartz_window_get_nswindow(GdkWindow *window);
+ NSEvent *gdk_quartz_event_get_nsevent(GdkEvent *event);
+
+ static GeditWindow *
+ ensure_window (GeditAppOSX *app,
+ gboolean with_empty_document)
+ {
+ GList *windows;
+ GeditWindow *ret = NULL;
+
+ windows = gtk_application_get_windows (GTK_APPLICATION (app));
+
+ while (windows)
+ {
+ GtkWindow *window;
+ GdkWindow *win;
+ NSWindow *nswin;
+
+ window = windows->data;
+ windows = g_list_next (windows);
+
+ if (!gtk_widget_get_realized (GTK_WIDGET (window)))
+ {
+ continue;
+ }
+
+ if (!GEDIT_IS_WINDOW (window))
+ {
+@@ -259,61 +259,61 @@ gedit_app_osx_set_window_title_impl (GeditApp *app,
+ }
+
+ native = gdk_quartz_window_get_nswindow (wnd);
+ document = gedit_window_get_active_document (window);
+
+ if (document)
+ {
+ bool ismodified;
+
+ if (gedit_document_is_untitled (document))
+ {
+ [native setRepresentedURL:nil];
+ }
+ else
+ {
+ GtkSourceFile *file;
+ GFile *location;
+ gchar *uri;
+
+ file = gedit_document_get_file (document);
+ location = gtk_source_file_get_location (file);
+
+ uri = g_file_get_uri (location);
+
+ NSURL *nsurl = [NSURL URLWithString:[NSString stringWithUTF8String:uri]];
+
+ [native setRepresentedURL:nsurl];
+ g_free (uri);
+ }
+
+- ismodified = !tepl_buffer_is_untouched (TEPL_BUFFER (document));
++ ismodified = !gedit_document_is_untouched (document);
+ [native setDocumentEdited:ismodified];
+ }
+ else
+ {
+ [native setRepresentedURL:nil];
+ [native setDocumentEdited:false];
+ }
+
+ GEDIT_APP_CLASS (gedit_app_osx_parent_class)->set_window_title (app, window, title);
+ }
+
+ typedef struct
+ {
+ GeditAppOSX *app;
+ GtkRecentInfo *info;
+ } RecentFileInfo;
+
+ static void
+ recent_file_info_free (gpointer data,
+ GClosure *closure)
+ {
+ RecentFileInfo *info = data;
+
+ g_object_unref (info->app);
+ gtk_recent_info_unref (info->info);
+
+ g_slice_free (RecentFileInfo, data);
+ }
+
+ static void
+diff --git a/gedit/gedit-app-private.h b/gedit/gedit-app-private.h
+index 6e1278a3b..e9c58cc27 100644
+--- a/gedit/gedit-app-private.h
++++ b/gedit/gedit-app-private.h
+@@ -1,52 +1,55 @@
+ /*
+ * gedit-app-private.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2015 - Sébastien Wilmet
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #ifndef GEDIT_APP_PRIVATE_H
+ #define GEDIT_APP_PRIVATE_H
+
+ #include "gedit-app.h"
++#include "gedit-metadata-manager.h"
+ #include "gedit-menu-extension.h"
+
+ G_BEGIN_DECLS
+
+ /* global print config */
+ GtkPageSetup *_gedit_app_get_default_page_setup (GeditApp *app);
+ void _gedit_app_set_default_page_setup (GeditApp *app,
+ GtkPageSetup *page_setup);
+ GtkPrintSettings *_gedit_app_get_default_print_settings (GeditApp *app);
+ void _gedit_app_set_default_print_settings (GeditApp *app,
+ GtkPrintSettings *settings);
+
++GeditMetadataManager *_gedit_app_get_metadata_manager (GeditApp *app);
++
+ GMenuModel *_gedit_app_get_hamburger_menu (GeditApp *app);
+
+ GMenuModel *_gedit_app_get_notebook_menu (GeditApp *app);
+
+ GMenuModel *_gedit_app_get_tab_width_menu (GeditApp *app);
+
+ GMenuModel *_gedit_app_get_line_col_menu (GeditApp *app);
+
+ GeditMenuExtension *_gedit_app_extend_menu (GeditApp *app,
+ const gchar *extension_point);
+
+ G_END_DECLS
+
+ #endif /* GEDIT_APP_PRIVATE_H */
+
+ /* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-app.c b/gedit/gedit-app.c
+index 5532d5975..27d71a87a 100644
+--- a/gedit/gedit-app.c
++++ b/gedit/gedit-app.c
+@@ -1,83 +1,92 @@
+ /*
+ * gedit-app.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2005-2006 - Paolo Maggi
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #include "config.h"
+
+ #include "gedit-app.h"
+ #include "gedit-app-private.h"
+
+ #include
+ #include
+ #include
+
+ #include
++#include
+ #include
+-#include
++#include
+
+ #include "gedit-commands-private.h"
+ #include "gedit-notebook.h"
+ #include "gedit-debug.h"
+ #include "gedit-utils.h"
+ #include "gedit-enum-types.h"
+ #include "gedit-dirs.h"
+ #include "gedit-settings.h"
+ #include "gedit-app-activatable.h"
+ #include "gedit-plugins-engine.h"
+ #include "gedit-commands.h"
+ #include "gedit-preferences-dialog.h"
+ #include "gedit-tab.h"
+
++#ifndef ENABLE_GVFS_METADATA
++#include "gedit-metadata-manager.h"
++#endif
++
+ #define GEDIT_PAGE_SETUP_FILE "gedit-page-setup"
+ #define GEDIT_PRINT_SETTINGS_FILE "gedit-print-settings"
+
+ typedef struct
+ {
+ GeditPluginsEngine *engine;
+
++#ifndef ENABLE_GVFS_METADATA
++ GeditMetadataManager *metadata_manager;
++#endif
++
+ GtkCssProvider *theme_provider;
+
+ GtkPageSetup *page_setup;
+ GtkPrintSettings *print_settings;
+
+ GSettings *ui_settings;
+ GSettings *window_settings;
+
+ GMenuModel *hamburger_menu;
+ GMenuModel *notebook_menu;
+ GMenuModel *tab_width_menu;
+ GMenuModel *line_col_menu;
+
+ PeasExtensionSet *extensions;
+
+ /* command line parsing */
+ gboolean new_window;
+ gboolean new_document;
+ const GtkSourceEncoding *encoding;
+ GInputStream *stdin_stream;
+ GSList *file_list;
+ gint line_position;
+ gint column_position;
+ GApplicationCommandLine *command_line;
+ } GeditAppPrivate;
+
+ static const GOptionEntry options[] =
+ {
+ /* Version */
+ {
+@@ -118,60 +127,64 @@ static const GOptionEntry options[] =
+ "wait", 'w', 0, G_OPTION_ARG_NONE, NULL,
+ N_("Open files and block process until files are closed"),
+ NULL
+ },
+
+ /* New instance */
+ {
+ "standalone", 's', 0, G_OPTION_ARG_NONE, NULL,
+ N_("Run gedit in standalone mode"),
+ NULL
+ },
+
+ /* collects file arguments */
+ {
+ G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, NULL, NULL,
+ N_("[FILE…] [+LINE[:COLUMN]]")
+ },
+
+ {NULL}
+ };
+
+ G_DEFINE_TYPE_WITH_PRIVATE (GeditApp, gedit_app, GTK_TYPE_APPLICATION)
+
+ static void
+ gedit_app_dispose (GObject *object)
+ {
+ GeditAppPrivate *priv;
+
+ priv = gedit_app_get_instance_private (GEDIT_APP (object));
+
++#ifndef ENABLE_GVFS_METADATA
++ g_clear_object (&priv->metadata_manager);
++#endif
++
+ g_clear_object (&priv->ui_settings);
+ g_clear_object (&priv->window_settings);
+
+ g_clear_object (&priv->page_setup);
+ g_clear_object (&priv->print_settings);
+
+ /* Note that unreffing the extensions will automatically remove
+ * all extensions which in turn will deactivate the extension
+ */
+ g_clear_object (&priv->extensions);
+
+ g_clear_object (&priv->engine);
+
+ if (priv->theme_provider != NULL)
+ {
+ gtk_style_context_remove_provider_for_screen (gdk_screen_get_default (),
+ GTK_STYLE_PROVIDER (priv->theme_provider));
+ g_clear_object (&priv->theme_provider);
+ }
+
+ g_clear_object (&priv->hamburger_menu);
+ g_clear_object (&priv->notebook_menu);
+ g_clear_object (&priv->tab_width_menu);
+ g_clear_object (&priv->line_col_menu);
+
+ G_OBJECT_CLASS (gedit_app_parent_class)->dispose (object);
+ }
+
+ static gchar *
+ gedit_app_help_link_id_impl (GeditApp *app,
+@@ -616,71 +629,82 @@ add_accelerator (GtkApplication *app,
+ const gchar *action_name,
+ const gchar *accel)
+ {
+ const gchar *vaccels[] = {
+ accel,
+ NULL
+ };
+
+ gtk_application_set_accels_for_action (app, action_name, vaccels);
+ }
+
+ static gboolean
+ show_menubar (void)
+ {
+ GtkSettings *settings = gtk_settings_get_default ();
+ gboolean result;
+
+ g_object_get (settings,
+ "gtk-shell-shows-menubar", &result,
+ NULL);
+
+ return result;
+ }
+
+ static void
+ gedit_app_startup (GApplication *application)
+ {
+ GeditAppPrivate *priv;
+ GtkCssProvider *css_provider;
+ GtkSourceStyleSchemeManager *manager;
++#ifndef ENABLE_GVFS_METADATA
++ const gchar *cache_dir;
++ gchar *metadata_filename;
++#endif
+
+ priv = gedit_app_get_instance_private (GEDIT_APP (application));
+
+ G_APPLICATION_CLASS (gedit_app_parent_class)->startup (application);
+
+ /* Setup debugging */
+ gedit_debug_init ();
+ gedit_debug_message (DEBUG_APP, "Startup");
+
+ setup_theme_extensions (GEDIT_APP (application));
+
++#ifndef ENABLE_GVFS_METADATA
++ cache_dir = gedit_dirs_get_user_cache_dir ();
++ metadata_filename = g_build_filename (cache_dir, "gedit-metadata.xml", NULL);
++ priv->metadata_manager = gedit_metadata_manager_new (metadata_filename);
++ g_free (metadata_filename);
++#endif
++
+ /* Load/init settings */
+ _gedit_settings_get_singleton ();
+ priv->ui_settings = g_settings_new ("org.gnome.gedit.preferences.ui");
+ priv->window_settings = g_settings_new ("org.gnome.gedit.state.window");
+
+ g_action_map_add_action_entries (G_ACTION_MAP (application),
+ app_entries,
+ G_N_ELEMENTS (app_entries),
+ application);
+
+ /* menus */
+ if (!show_menubar ())
+ {
+ gtk_application_set_menubar (GTK_APPLICATION (application), NULL);
+ priv->hamburger_menu = get_menu_model (GEDIT_APP (application),
+ "hamburger-menu");
+ }
+
+ priv->notebook_menu = get_menu_model (GEDIT_APP (application), "notebook-menu");
+ priv->tab_width_menu = get_menu_model (GEDIT_APP (application), "tab-width-menu");
+ priv->line_col_menu = get_menu_model (GEDIT_APP (application), "line-col-menu");
+
+ /* Accelerators */
+ add_accelerator (GTK_APPLICATION (application), "app.new-window", "N");
+ add_accelerator (GTK_APPLICATION (application), "app.quit", "Q");
+ add_accelerator (GTK_APPLICATION (application), "app.help", "F1");
+ add_accelerator (GTK_APPLICATION (application), "app.shortcuts", "question");
+
+ add_accelerator (GTK_APPLICATION (application), "win.hamburger-menu", "F10");
+ add_accelerator (GTK_APPLICATION (application), "win.open", "O");
+@@ -1087,60 +1111,64 @@ save_print_settings (GeditApp *app)
+ gchar *filename;
+ GError *error = NULL;
+
+ filename = get_print_settings_file ();
+
+ gtk_print_settings_to_file (priv->print_settings,
+ filename,
+ &error);
+ if (error)
+ {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+
+ g_free (filename);
+ }
+ }
+
+ static void
+ gedit_app_shutdown (GApplication *app)
+ {
+ gedit_debug_message (DEBUG_APP, "Quitting\n");
+
+ /* Last window is gone... save some settings and exit */
+ ensure_user_config_dir ();
+
+ save_accels ();
+ save_page_setup (GEDIT_APP (app));
+ save_print_settings (GEDIT_APP (app));
+
++ /* GTK+ can still hold references to some gedit objects, for example
++ * GeditDocument for the clipboard. So the metadata-manager should be
++ * shutdown after.
++ */
+ G_APPLICATION_CLASS (gedit_app_parent_class)->shutdown (app);
+ }
+
+ static gboolean
+ window_delete_event (GeditWindow *window,
+ GdkEvent *event,
+ GeditApp *app)
+ {
+ GeditWindowState ws;
+
+ ws = gedit_window_get_state (window);
+
+ if (ws &
+ (GEDIT_WINDOW_STATE_SAVING | GEDIT_WINDOW_STATE_PRINTING))
+ {
+ return TRUE;
+ }
+
+ _gedit_cmd_file_quit (NULL, NULL, window);
+
+ /* Do not destroy the window */
+ return TRUE;
+ }
+
+ static GeditWindow *
+ gedit_app_create_window_impl (GeditApp *app)
+ {
+ GeditWindow *window;
+
+ window = g_object_new (GEDIT_TYPE_WINDOW, "application", app, NULL);
+@@ -1226,69 +1254,64 @@ load_print_settings (GeditApp *app)
+
+ priv->print_settings = gtk_print_settings_new_from_file (filename, &error);
+ if (error != NULL)
+ {
+ /* - Ignore file not found error.
+ * - Ignore empty file error, i.e. group not found. This happens
+ * when we click on cancel in the print dialog, when using the
+ * printing for the first time in gedit.
+ */
+ if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT) &&
+ !g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND))
+ {
+ g_warning ("Load print settings error: %s", error->message);
+ }
+
+ g_error_free (error);
+ }
+
+ g_free (filename);
+
+ /* fall back to default settings */
+ if (priv->print_settings == NULL)
+ {
+ priv->print_settings = gtk_print_settings_new ();
+ }
+ }
+
+ static void
+ gedit_app_init (GeditApp *app)
+ {
+- TeplApplication *tepl_app;
+-
+ g_set_application_name ("gedit");
+ gtk_window_set_default_icon_name ("org.gnome.gedit");
+
+ g_application_add_main_option_entries (G_APPLICATION (app), options);
+-
+- tepl_app = tepl_application_get_from_gtk_application (GTK_APPLICATION (app));
+- tepl_application_handle_metadata (tepl_app);
+ }
+
+ /**
+ * gedit_app_create_window:
+ * @app: the #GeditApp
+ * @screen: (allow-none):
+ *
+ * Create a new #GeditWindow part of @app.
+ *
+ * Return value: (transfer none): the new #GeditWindow
+ */
+ GeditWindow *
+ gedit_app_create_window (GeditApp *app,
+ GdkScreen *screen)
+ {
+ GeditAppPrivate *priv;
+ GeditWindow *window;
+ GdkWindowState state;
+ gint w, h;
+
+ gedit_debug (DEBUG_APP);
+
+ priv = gedit_app_get_instance_private (app);
+
+ window = GEDIT_APP_GET_CLASS (app)->create_window (app);
+
+ if (screen != NULL)
+ {
+ gtk_window_set_screen (GTK_WINDOW (window), screen);
+ }
+@@ -1544,60 +1567,79 @@ _gedit_app_get_default_print_settings (GeditApp *app)
+
+ priv = gedit_app_get_instance_private (app);
+
+ if (priv->print_settings == NULL)
+ {
+ load_print_settings (app);
+ }
+
+ return gtk_print_settings_copy (priv->print_settings);
+ }
+
+ void
+ _gedit_app_set_default_print_settings (GeditApp *app,
+ GtkPrintSettings *settings)
+ {
+ GeditAppPrivate *priv;
+
+ g_return_if_fail (GEDIT_IS_APP (app));
+ g_return_if_fail (GTK_IS_PRINT_SETTINGS (settings));
+
+ priv = gedit_app_get_instance_private (app);
+
+ if (priv->print_settings != NULL)
+ {
+ g_object_unref (priv->print_settings);
+ }
+
+ priv->print_settings = g_object_ref (settings);
+ }
+
++
++GeditMetadataManager *
++_gedit_app_get_metadata_manager (GeditApp *app)
++{
++#ifndef ENABLE_GVFS_METADATA
++ GeditAppPrivate *priv;
++
++ g_return_val_if_fail (GEDIT_IS_APP (app), NULL);
++
++ priv = gedit_app_get_instance_private (app);
++
++ return priv->metadata_manager;
++#else
++ g_assert_not_reached ();
++ return NULL;
++#endif
++}
++
++
+ GMenuModel *
+ _gedit_app_get_hamburger_menu (GeditApp *app)
+ {
+ GeditAppPrivate *priv;
+
+ g_return_val_if_fail (GEDIT_IS_APP (app), NULL);
+
+ priv = gedit_app_get_instance_private (app);
+
+ return priv->hamburger_menu;
+ }
+
+ GMenuModel *
+ _gedit_app_get_notebook_menu (GeditApp *app)
+ {
+ GeditAppPrivate *priv;
+
+ g_return_val_if_fail (GEDIT_IS_APP (app), NULL);
+
+ priv = gedit_app_get_instance_private (app);
+
+ return priv->notebook_menu;
+ }
+
+ GMenuModel *
+ _gedit_app_get_tab_width_menu (GeditApp *app)
+ {
+ GeditAppPrivate *priv;
+
+ g_return_val_if_fail (GEDIT_IS_APP (app), NULL);
+diff --git a/gedit/gedit-commands-edit.c b/gedit/gedit-commands-edit.c
+index 66ea0174b..978440150 100644
+--- a/gedit/gedit-commands-edit.c
++++ b/gedit/gedit-commands-edit.c
+@@ -17,180 +17,180 @@
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+ #include "config.h"
+
+ #include "gedit-commands.h"
+ #include "gedit-commands-private.h"
+
+ #include
+
+ #include "gedit-window.h"
+ #include "gedit-debug.h"
+ #include "gedit-view.h"
+ #include "gedit-preferences-dialog.h"
+
+ void
+ _gedit_cmd_edit_undo (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+ {
+ GeditWindow *window = GEDIT_WINDOW (user_data);
+ GeditView *active_view;
+ GtkSourceBuffer *active_document;
+
+ gedit_debug (DEBUG_COMMANDS);
+
+ active_view = gedit_window_get_active_view (window);
+- g_return_if_fail (active_view != NULL);
++ g_return_if_fail (active_view);
+
+ active_document = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (active_view)));
+
+ gtk_source_buffer_undo (active_document);
+
+- tepl_view_scroll_to_cursor (TEPL_VIEW (active_view));
++ gedit_view_scroll_to_cursor (active_view);
+
+ gtk_widget_grab_focus (GTK_WIDGET (active_view));
+ }
+
+ void
+ _gedit_cmd_edit_redo (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+ {
+ GeditWindow *window = GEDIT_WINDOW (user_data);
+ GeditView *active_view;
+ GtkSourceBuffer *active_document;
+
+ gedit_debug (DEBUG_COMMANDS);
+
+ active_view = gedit_window_get_active_view (window);
+- g_return_if_fail (active_view != NULL);
++ g_return_if_fail (active_view);
+
+ active_document = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (active_view)));
+
+ gtk_source_buffer_redo (active_document);
+
+- tepl_view_scroll_to_cursor (TEPL_VIEW (active_view));
++ gedit_view_scroll_to_cursor (active_view);
+
+ gtk_widget_grab_focus (GTK_WIDGET (active_view));
+ }
+
+ void
+ _gedit_cmd_edit_cut (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+ {
+ GeditWindow *window = GEDIT_WINDOW (user_data);
+ GeditView *active_view;
+
+ gedit_debug (DEBUG_COMMANDS);
+
+ active_view = gedit_window_get_active_view (window);
+- g_return_if_fail (active_view != NULL);
++ g_return_if_fail (active_view);
+
+- tepl_view_cut_clipboard (TEPL_VIEW (active_view));
++ gedit_view_cut_clipboard (active_view);
+
+ gtk_widget_grab_focus (GTK_WIDGET (active_view));
+ }
+
+ void
+ _gedit_cmd_edit_copy (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+ {
+ GeditWindow *window = GEDIT_WINDOW (user_data);
+ GeditView *active_view;
+
+ gedit_debug (DEBUG_COMMANDS);
+
+ active_view = gedit_window_get_active_view (window);
+- g_return_if_fail (active_view != NULL);
++ g_return_if_fail (active_view);
+
+- tepl_view_copy_clipboard (TEPL_VIEW (active_view));
++ gedit_view_copy_clipboard (active_view);
+
+ gtk_widget_grab_focus (GTK_WIDGET (active_view));
+ }
+
+ void
+ _gedit_cmd_edit_paste (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+ {
+ GeditWindow *window = GEDIT_WINDOW (user_data);
+ GeditView *active_view;
+
+ gedit_debug (DEBUG_COMMANDS);
+
+ active_view = gedit_window_get_active_view (window);
+- g_return_if_fail (active_view != NULL);
++ g_return_if_fail (active_view);
+
+- tepl_view_paste_clipboard (TEPL_VIEW (active_view));
++ gedit_view_paste_clipboard (active_view);
+
+ gtk_widget_grab_focus (GTK_WIDGET (active_view));
+ }
+
+ void
+ _gedit_cmd_edit_delete (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+ {
+ GeditWindow *window = GEDIT_WINDOW (user_data);
+ GeditView *active_view;
+
+ gedit_debug (DEBUG_COMMANDS);
+
+ active_view = gedit_window_get_active_view (window);
+- g_return_if_fail (active_view != NULL);
++ g_return_if_fail (active_view);
+
+- tepl_view_delete_selection (TEPL_VIEW (active_view));
++ gedit_view_delete_selection (active_view);
+
+ gtk_widget_grab_focus (GTK_WIDGET (active_view));
+ }
+
+ void
+ _gedit_cmd_edit_select_all (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+ {
+ GeditWindow *window = GEDIT_WINDOW (user_data);
+ GeditView *active_view;
+
+ gedit_debug (DEBUG_COMMANDS);
+
+ active_view = gedit_window_get_active_view (window);
+- g_return_if_fail (active_view != NULL);
++ g_return_if_fail (active_view);
+
+- tepl_view_select_all (TEPL_VIEW (active_view));
++ gedit_view_select_all (active_view);
+
+ gtk_widget_grab_focus (GTK_WIDGET (active_view));
+ }
+
+ void
+ _gedit_cmd_edit_preferences (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+ {
+ GeditWindow *window = GEDIT_WINDOW (user_data);
+
+ gedit_debug (DEBUG_COMMANDS);
+
+ gedit_show_preferences_dialog (window);
+ }
+
+ void
+ _gedit_cmd_edit_overwrite_mode (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+ {
+ GeditWindow *window = GEDIT_WINDOW (user_data);
+ GeditView *active_view;
+ gboolean overwrite;
+
+ gedit_debug (DEBUG_COMMANDS);
+
+ active_view = gedit_window_get_active_view (window);
+ g_return_if_fail (active_view);
+
+diff --git a/gedit/gedit-commands-file.c b/gedit/gedit-commands-file.c
+index fb64f880d..d1d440a3e 100644
+--- a/gedit/gedit-commands-file.c
++++ b/gedit/gedit-commands-file.c
+@@ -1,80 +1,75 @@
+ /*
+ * gedit-commands-file.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002-2005 Paolo Maggi
+ * Copyright (C) 2014 Sébastien Wilmet
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #include "config.h"
+
+ #include "gedit-commands.h"
+ #include "gedit-commands-private.h"
+
+ #include
+-#include
+
+ #include "gedit-app.h"
+ #include "gedit-debug.h"
+ #include "gedit-document.h"
+ #include "gedit-document-private.h"
+ #include "gedit-tab.h"
+ #include "gedit-tab-private.h"
+ #include "gedit-window.h"
+ #include "gedit-window-private.h"
+ #include "gedit-notebook.h"
+ #include "gedit-statusbar.h"
+ #include "gedit-utils.h"
+ #include "gedit-file-chooser-dialog.h"
+ #include "gedit-file-chooser-open.h"
+ #include "gedit-close-confirmation-dialog.h"
+
+-/* useful macro */
+-#define GBOOLEAN_TO_POINTER(i) (GINT_TO_POINTER ((i) ? 2 : 1))
+-#define GPOINTER_TO_BOOLEAN(i) ((gboolean) ((GPOINTER_TO_INT(i) == 2) ? TRUE : FALSE))
+-
+ #define GEDIT_IS_CLOSING_ALL "gedit-is-closing-all"
+ #define GEDIT_NOTEBOOK_TO_CLOSE "gedit-notebook-to-close"
+ #define GEDIT_IS_QUITTING "gedit-is-quitting"
+ #define GEDIT_IS_QUITTING_ALL "gedit-is-quitting-all"
+
+ void
+ _gedit_cmd_file_new (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+ {
+ GeditWindow *window = GEDIT_WINDOW (user_data);
+
+ gedit_debug (DEBUG_COMMANDS);
+
+ gedit_window_create_tab (window, TRUE);
+ }
+
+ static GeditTab *
+ get_tab_from_file (GList *docs,
+ GFile *file)
+ {
+ GList *l;
+
+ for (l = docs; l != NULL; l = l->next)
+ {
+ GeditDocument *doc;
+ GtkSourceFile *source_file;
+ GFile *location;
+
+ doc = l->data;
+@@ -123,105 +118,107 @@ load_file_list (GeditWindow *window,
+ gboolean jump_to = TRUE; /* Whether to jump to the new tab */
+ const GSList *l;
+ gint num_loaded_files = 0;
+
+ gedit_debug (DEBUG_COMMANDS);
+
+ win_docs = gedit_window_get_documents (window);
+
+ /* Remove the files corresponding to documents already opened in
+ * "window" and remove duplicates from the "files" list.
+ */
+ for (l = files; l != NULL; l = l->next)
+ {
+ GFile *file = l->data;
+
+ if (is_duplicated_file (files_to_load, file))
+ {
+ continue;
+ }
+
+ tab = get_tab_from_file (win_docs, file);
+
+ if (tab == NULL)
+ {
+ files_to_load = g_slist_prepend (files_to_load, file);
+ }
+ else
+ {
+ if (l == files)
+ {
+- TeplView *view;
++ GeditDocument *doc;
+
+ gedit_window_set_active_tab (window, tab);
+ jump_to = FALSE;
+- view = TEPL_VIEW (gedit_tab_get_view (tab));
++ doc = gedit_tab_get_document (tab);
+
+ if (line_pos > 0)
+ {
+ if (column_pos > 0)
+ {
+- tepl_view_goto_line_offset (view,
+- line_pos - 1,
+- column_pos - 1);
++ gedit_document_goto_line_offset (doc,
++ line_pos - 1,
++ column_pos - 1);
+ }
+ else
+ {
+- tepl_view_goto_line (view, line_pos - 1);
++ gedit_document_goto_line (doc, line_pos - 1);
+ }
++
++ gedit_view_scroll_to_cursor (gedit_tab_get_view (tab));
+ }
+ }
+
+ ++num_loaded_files;
+ loaded_files = g_slist_prepend (loaded_files,
+ gedit_tab_get_document (tab));
+ }
+ }
+
+ g_list_free (win_docs);
+
+ if (files_to_load == NULL)
+ {
+ return g_slist_reverse (loaded_files);
+ }
+
+ files_to_load = g_slist_reverse (files_to_load);
+ l = files_to_load;
+
+ tab = gedit_window_get_active_tab (window);
+ if (tab != NULL)
+ {
+ GeditDocument *doc;
+
+ doc = gedit_tab_get_document (tab);
+
+- if (tepl_buffer_is_untouched (TEPL_BUFFER (doc)) &&
++ if (gedit_document_is_untouched (doc) &&
+ gedit_tab_get_state (tab) == GEDIT_TAB_STATE_NORMAL)
+ {
+ _gedit_tab_load (tab,
+ l->data,
+ encoding,
+ line_pos,
+ column_pos,
+ create);
+
+ /* make sure the view has focus */
+ gtk_widget_grab_focus (GTK_WIDGET (gedit_tab_get_view (tab)));
+
+ l = g_slist_next (l);
+ jump_to = FALSE;
+
+ ++num_loaded_files;
+ loaded_files = g_slist_prepend (loaded_files,
+ gedit_tab_get_document (tab));
+ }
+ }
+
+ while (l != NULL)
+ {
+ g_return_val_if_fail (l->data != NULL, NULL);
+
+ tab = gedit_window_create_tab_from_location (window,
+ l->data,
+ encoding,
+ line_pos,
+ column_pos,
+@@ -446,113 +443,113 @@ _gedit_cmd_file_reopen_closed_tab (GSimpleAction *action,
+ GFile *file;
+
+ file = _gedit_window_pop_last_closed_doc (window);
+ if (file != NULL)
+ {
+ gedit_commands_load_location (window, file, NULL, 0, 0);
+ }
+ }
+
+ /* File saving */
+
+ /* FIXME: modify this dialog to be similar to the one provided by gtk+ for
+ * already existing files - Paolo (Oct. 11, 2005) */
+ static gboolean
+ replace_read_only_file (GtkWindow *parent,
+ GFile *file)
+ {
+ GtkWidget *dialog;
+ gint ret;
+ gchar *parse_name;
+ gchar *name_for_display;
+
+ gedit_debug (DEBUG_COMMANDS);
+
+ parse_name = g_file_get_parse_name (file);
+
+ /* Truncate the name so it doesn't get insanely wide. Note that even
+ * though the dialog uses wrapped text, if the name doesn't contain
+ * white space then the text-wrapping code is too stupid to wrap it.
+ */
+- name_for_display = tepl_utils_str_middle_truncate (parse_name, 50);
++ name_for_display = gedit_utils_str_middle_truncate (parse_name, 50);
+ g_free (parse_name);
+
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ _("The file “%s” is read-only."),
+ name_for_display);
+ g_free (name_for_display);
+
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("Do you want to try to replace it "
+ "with the one you are saving?"));
+
+ gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_Replace"), GTK_RESPONSE_YES,
+ NULL);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog),
+ GTK_RESPONSE_CANCEL);
+
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+
+ ret = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ gtk_widget_destroy (dialog);
+
+ return ret == GTK_RESPONSE_YES;
+ }
+
+ static gboolean
+ change_compression (GtkWindow *parent,
+ GFile *file,
+ gboolean compressed)
+ {
+ GtkWidget *dialog;
+ gint ret;
+ gchar *parse_name;
+ gchar *name_for_display;
+ const gchar *primary_message;
+ const gchar *button_label;
+
+ gedit_debug (DEBUG_COMMANDS);
+
+ parse_name = g_file_get_parse_name (file);
+
+ /* Truncate the name so it doesn't get insanely wide. Note that even
+ * though the dialog uses wrapped text, if the name doesn't contain
+ * white space then the text-wrapping code is too stupid to wrap it.
+ */
+- name_for_display = tepl_utils_str_middle_truncate (parse_name, 50);
++ name_for_display = gedit_utils_str_middle_truncate (parse_name, 50);
+ g_free (parse_name);
+
+ if (compressed)
+ {
+ primary_message = _("Save the file using compression?");
+ }
+ else
+ {
+ primary_message = _("Save the file as plain text?");
+ }
+
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ "%s",
+ primary_message);
+
+ if (compressed)
+ {
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("The file “%s” was previously saved as plain "
+ "text and will now be saved using compression."),
+ name_for_display);
+
+ button_label = _("_Save Using Compression");
+ }
+ else
+ {
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+@@ -760,60 +757,61 @@ confirm_overwrite_callback (GeditFileChooserDialog *dialog,
+
+ /* Call save_as_tab_finish() in @callback. */
+ static void
+ save_as_tab_async (GeditTab *tab,
+ GeditWindow *window,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+ {
+ GTask *task;
+ GeditFileChooserDialog *save_dialog;
+ GtkWindowGroup *window_group;
+ GtkWindow *dialog_window;
+ GeditDocument *doc;
+ GtkSourceFile *file;
+ GFile *location;
+ const GtkSourceEncoding *encoding;
+ GtkSourceNewlineType newline_type;
+
+ g_return_if_fail (GEDIT_IS_TAB (tab));
+ g_return_if_fail (GEDIT_IS_WINDOW (window));
+
+ gedit_debug (DEBUG_COMMANDS);
+
+ task = g_task_new (tab, cancellable, callback, user_data);
+ g_task_set_task_data (task, g_object_ref (window), g_object_unref);
+
+ /* Translators: "Save As" is the title of the file chooser window. */
+ save_dialog = gedit_file_chooser_dialog_create (C_("window title", "Save As"),
+ GTK_WINDOW (window),
++ GEDIT_FILE_CHOOSER_FLAG_SAVE,
+ _("_Save"),
+ _("_Cancel"));
+
+ gedit_file_chooser_dialog_set_do_overwrite_confirmation (save_dialog, TRUE);
+
+ g_signal_connect (save_dialog,
+ "confirm-overwrite",
+ G_CALLBACK (confirm_overwrite_callback),
+ NULL);
+
+ window_group = gedit_window_get_group (window);
+
+ dialog_window = gedit_file_chooser_dialog_get_window (save_dialog);
+
+ if (dialog_window != NULL)
+ {
+ gtk_window_group_add_window (window_group, dialog_window);
+ }
+
+ /* Save As dialog is modal to its main window */
+ gedit_file_chooser_dialog_set_modal (save_dialog, TRUE);
+
+ /* Set the suggested file name */
+ doc = gedit_tab_get_document (tab);
+ file = gedit_document_get_file (doc);
+ location = gtk_source_file_get_location (file);
+
+ if (location != NULL)
+ {
+ gedit_file_chooser_dialog_set_file (save_dialog, location);
+diff --git a/gedit/gedit-commands-search.c b/gedit/gedit-commands-search.c
+index 22703985e..f120b8bad 100644
+--- a/gedit/gedit-commands-search.c
++++ b/gedit/gedit-commands-search.c
+@@ -2,61 +2,60 @@
+ * gedit-commands-search.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002-2006 Paolo Maggi
+ * Copyright (C) 2013 Sébastien Wilmet
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #include "config.h"
+
+ #include "gedit-commands.h"
+ #include "gedit-commands-private.h"
+
+ #include
+ #include
+ #include
+-#include
+
+ #include "gedit-debug.h"
+ #include "gedit-statusbar.h"
+ #include "gedit-tab.h"
+ #include "gedit-tab-private.h"
+ #include "gedit-view-frame.h"
+ #include "gedit-window.h"
+ #include "gedit-window-private.h"
+ #include "gedit-utils.h"
+ #include "gedit-replace-dialog.h"
+
+ #define GEDIT_REPLACE_DIALOG_KEY "gedit-replace-dialog-key"
+ #define GEDIT_LAST_SEARCH_DATA_KEY "gedit-last-search-data-key"
+
+ typedef struct _LastSearchData LastSearchData;
+ struct _LastSearchData
+ {
+ gint x;
+ gint y;
+ };
+
+ static void
+ last_search_data_free (LastSearchData *data)
+ {
+ g_slice_free (LastSearchData, data);
+ }
+
+ static void
+ last_search_data_restore_position (GeditReplaceDialog *dlg)
+ {
+@@ -105,117 +104,117 @@ text_found (GeditWindow *window,
+ window->priv->generic_message_cid,
+ ngettext("Found and replaced %d occurrence",
+ "Found and replaced %d occurrences",
+ occurrences),
+ occurrences);
+ }
+ else if (occurrences == 1)
+ {
+ gedit_statusbar_flash_message (GEDIT_STATUSBAR (window->priv->statusbar),
+ window->priv->generic_message_cid,
+ _("Found and replaced one occurrence"));
+ }
+ else
+ {
+ gedit_statusbar_flash_message (GEDIT_STATUSBAR (window->priv->statusbar),
+ window->priv->generic_message_cid,
+ " ");
+ }
+ }
+
+ #define MAX_MSG_LENGTH 40
+
+ static void
+ text_not_found (GeditWindow *window,
+ GeditReplaceDialog *replace_dialog)
+ {
+ const gchar *search_text;
+ gchar *truncated_text;
+
+ search_text = gedit_replace_dialog_get_search_text (replace_dialog);
+- truncated_text = tepl_utils_str_end_truncate (search_text, MAX_MSG_LENGTH);
++ truncated_text = gedit_utils_str_end_truncate (search_text, MAX_MSG_LENGTH);
+
+ gedit_statusbar_flash_message (GEDIT_STATUSBAR (window->priv->statusbar),
+ window->priv->generic_message_cid,
+ /* Translators: %s is replaced by the text
+ entered by the user in the search box */
+ _("“%s” not found"), truncated_text);
+
+ g_free (truncated_text);
+ }
+
+ static void
+ finish_search_from_dialog (GeditWindow *window,
+ gboolean found)
+ {
+ GeditReplaceDialog *replace_dialog;
+
+ replace_dialog = g_object_get_data (G_OBJECT (window), GEDIT_REPLACE_DIALOG_KEY);
+
+ g_return_if_fail (replace_dialog != NULL);
+
+ if (found)
+ {
+ text_found (window, 0);
+ }
+ else
+ {
+ text_not_found (window, replace_dialog);
+ }
+ }
+
+ static gboolean
+ forward_search_finished (GtkSourceSearchContext *search_context,
+ GAsyncResult *result,
+ GeditView *view)
+ {
+ gboolean found;
+ GtkSourceBuffer *buffer;
+ GtkTextIter match_start;
+ GtkTextIter match_end;
+
+ found = gtk_source_search_context_forward_finish (search_context,
+ result,
+ &match_start,
+ &match_end,
+ NULL,
+ NULL);
+
+ buffer = gtk_source_search_context_get_buffer (search_context);
+
+ if (found)
+ {
+ gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer),
+ &match_start,
+ &match_end);
+
+- tepl_view_scroll_to_cursor (TEPL_VIEW (view));
++ gedit_view_scroll_to_cursor (view);
+ }
+ else
+ {
+ GtkTextIter end_selection;
+
+ gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (buffer),
+ NULL,
+ &end_selection);
+
+ gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer),
+ &end_selection,
+ &end_selection);
+ }
+
+ return found;
+ }
+
+ static void
+ forward_search_from_dialog_finished (GtkSourceSearchContext *search_context,
+ GAsyncResult *result,
+ GeditWindow *window)
+ {
+ GeditView *view = gedit_window_get_active_view (window);
+ gboolean found;
+
+ if (view == NULL)
+ {
+ return;
+ }
+
+@@ -267,61 +266,61 @@ run_forward_search (GeditWindow *window,
+ (GAsyncReadyCallback)forward_search_finished,
+ view);
+ }
+ }
+
+ static gboolean
+ backward_search_finished (GtkSourceSearchContext *search_context,
+ GAsyncResult *result,
+ GeditView *view)
+ {
+ gboolean found;
+ GtkTextIter match_start;
+ GtkTextIter match_end;
+ GtkSourceBuffer *buffer;
+
+ found = gtk_source_search_context_backward_finish (search_context,
+ result,
+ &match_start,
+ &match_end,
+ NULL,
+ NULL);
+
+ buffer = gtk_source_search_context_get_buffer (search_context);
+
+ if (found)
+ {
+ gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer),
+ &match_start,
+ &match_end);
+
+- tepl_view_scroll_to_cursor (TEPL_VIEW (view));
++ gedit_view_scroll_to_cursor (view);
+ }
+ else
+ {
+ GtkTextIter start_selection;
+
+ gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (buffer),
+ &start_selection,
+ NULL);
+
+ gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer),
+ &start_selection,
+ &start_selection);
+ }
+
+ return found;
+ }
+
+ static void
+ backward_search_from_dialog_finished (GtkSourceSearchContext *search_context,
+ GAsyncResult *result,
+ GeditWindow *window)
+ {
+ GeditView *view = gedit_window_get_active_view (window);
+ gboolean found;
+
+ if (view == NULL)
+ {
+ return;
+ }
+
+diff --git a/gedit/gedit-commands-view.c b/gedit/gedit-commands-view.c
+index 71785b78f..369bc93b0 100644
+--- a/gedit/gedit-commands-view.c
++++ b/gedit/gedit-commands-view.c
+@@ -1,58 +1,63 @@
+ /*
+ * gedit-view-commands.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002-2005 Paolo Maggi
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #include "config.h"
++
+ #include "gedit-commands.h"
+ #include "gedit-commands-private.h"
+-#include
++
++#include
++
+ #include "gedit-debug.h"
+ #include "gedit-window.h"
++#include "gedit-highlight-mode-dialog.h"
++#include "gedit-highlight-mode-selector.h"
+
+ void
+ _gedit_cmd_view_focus_active (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+ {
+ GeditView *active_view;
+ GeditWindow *window = GEDIT_WINDOW (user_data);
+
+ gedit_debug (DEBUG_COMMANDS);
+
+ active_view = gedit_window_get_active_view (window);
+
+ if (active_view)
+ {
+ gtk_widget_grab_focus (GTK_WIDGET (active_view));
+ }
+ }
+
+ void
+ _gedit_cmd_view_toggle_side_panel (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+ {
+ GeditWindow *window = GEDIT_WINDOW (user_data);
+ GtkWidget *panel;
+ gboolean visible;
+
+ gedit_debug (DEBUG_COMMANDS);
+
+@@ -94,88 +99,75 @@ _gedit_cmd_view_toggle_bottom_panel (GSimpleAction *action,
+ }
+
+ void
+ _gedit_cmd_view_toggle_fullscreen_mode (GSimpleAction *action,
+ GVariant *state,
+ gpointer user_data)
+ {
+ GeditWindow *window = GEDIT_WINDOW (user_data);
+
+ gedit_debug (DEBUG_COMMANDS);
+
+ if (g_variant_get_boolean (state))
+ {
+ _gedit_window_fullscreen (window);
+ }
+ else
+ {
+ _gedit_window_unfullscreen (window);
+ }
+ }
+
+ void
+ _gedit_cmd_view_leave_fullscreen_mode (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+ {
+ _gedit_window_unfullscreen (GEDIT_WINDOW (user_data));
+ }
+
+ static void
+-language_activated_cb (TeplLanguageChooserDialog *dialog,
+- GtkSourceLanguage *language,
+- GeditWindow *window)
++language_selected_cb (GeditHighlightModeSelector *selector,
++ GtkSourceLanguage *language,
++ GeditWindow *window)
+ {
+ GeditDocument *active_document;
+
+ active_document = gedit_window_get_active_document (window);
+ if (active_document != NULL)
+ {
+ gedit_document_set_language (active_document, language);
+ }
+-
+- gtk_widget_destroy (GTK_WIDGET (dialog));
+-}
+-
+-static void
+-language_chooser_dialog_response_after_cb (TeplLanguageChooserDialog *dialog,
+- gint response_id,
+- gpointer user_data)
+-{
+- gtk_widget_destroy (GTK_WIDGET (dialog));
+ }
+
+ void
+ _gedit_cmd_view_highlight_mode (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+ {
+ GeditWindow *window = GEDIT_WINDOW (user_data);
+- TeplLanguageChooserDialog *dialog;
++ GeditHighlightModeDialog *dialog;
++ GeditHighlightModeSelector *selector;
+ GeditDocument *active_document;
+
+- dialog = tepl_language_chooser_dialog_new (GTK_WINDOW (window));
++ dialog = GEDIT_HIGHLIGHT_MODE_DIALOG (gedit_highlight_mode_dialog_new (GTK_WINDOW (window)));
++ selector = gedit_highlight_mode_dialog_get_selector (dialog);
+
+ active_document = gedit_window_get_active_document (window);
+ if (active_document != NULL)
+ {
+ GtkSourceLanguage *language;
+
+ language = gedit_document_get_language (active_document);
+- tepl_language_chooser_select_language (TEPL_LANGUAGE_CHOOSER (dialog), language);
++ gedit_highlight_mode_selector_select_language (selector, language);
+ }
+
+- g_signal_connect_object (dialog,
+- "language-activated",
+- G_CALLBACK (language_activated_cb),
++ g_signal_connect_object (selector,
++ "language-selected",
++ G_CALLBACK (language_selected_cb),
+ window,
+ 0);
+
+- g_signal_connect_after (dialog,
+- "response",
+- G_CALLBACK (language_chooser_dialog_response_after_cb),
+- NULL);
+-
+ gtk_widget_show (GTK_WIDGET (dialog));
+ }
+
+ /* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-debug.c b/gedit/gedit-debug.c
+index 5aa82fa51..396dc140f 100644
+--- a/gedit/gedit-debug.c
++++ b/gedit/gedit-debug.c
+@@ -73,60 +73,64 @@ gedit_debug_init (void)
+ enabled_sections |= GEDIT_DEBUG_WINDOW;
+ }
+ if (g_getenv ("GEDIT_DEBUG_PANEL") != NULL)
+ {
+ enabled_sections |= GEDIT_DEBUG_PANEL;
+ }
+ if (g_getenv ("GEDIT_DEBUG_PLUGINS") != NULL)
+ {
+ enabled_sections |= GEDIT_DEBUG_PLUGINS;
+ }
+ if (g_getenv ("GEDIT_DEBUG_TAB") != NULL)
+ {
+ enabled_sections |= GEDIT_DEBUG_TAB;
+ }
+ if (g_getenv ("GEDIT_DEBUG_DOCUMENT") != NULL)
+ {
+ enabled_sections |= GEDIT_DEBUG_DOCUMENT;
+ }
+ if (g_getenv ("GEDIT_DEBUG_COMMANDS") != NULL)
+ {
+ enabled_sections |= GEDIT_DEBUG_COMMANDS;
+ }
+ if (g_getenv ("GEDIT_DEBUG_APP") != NULL)
+ {
+ enabled_sections |= GEDIT_DEBUG_APP;
+ }
+ if (g_getenv ("GEDIT_DEBUG_UTILS") != NULL)
+ {
+ enabled_sections |= GEDIT_DEBUG_UTILS;
+ }
++ if (g_getenv ("GEDIT_DEBUG_METADATA") != NULL)
++ {
++ enabled_sections |= GEDIT_DEBUG_METADATA;
++ }
+
+ out:
+
+ #ifdef ENABLE_PROFILING
+ if (enabled_sections != GEDIT_NO_DEBUG)
+ {
+ timer = g_timer_new ();
+ }
+ #endif
+ }
+
+ /**
+ * gedit_debug:
+ * @section: debug section.
+ * @file: file name.
+ * @line: line number.
+ * @function: name of the function that is calling gedit_debug().
+ *
+ * If @section is enabled, then logs the trace information @file, @line, and
+ * @function.
+ */
+ void
+ gedit_debug (GeditDebugSection section,
+ const gchar *file,
+ gint line,
+ const gchar *function)
+ {
+ gedit_debug_message (section, file, line, function, "%s", "");
+ }
+
+diff --git a/gedit/gedit-debug.h b/gedit/gedit-debug.h
+index a9d7caf37..49e5127e1 100644
+--- a/gedit/gedit-debug.h
++++ b/gedit/gedit-debug.h
+@@ -21,63 +21,65 @@
+ */
+
+ #ifndef GEDIT_DEBUG_H
+ #define GEDIT_DEBUG_H
+
+ #include
+
+ /**
+ * GeditDebugSection:
+ *
+ * Enumeration of debug sections.
+ *
+ * Debugging output for a section is enabled by setting an environment variable
+ * of the same name. For example, setting the GEDIT_DEBUG_PLUGINS
+ * environment variable enables all debugging output for the %GEDIT_DEBUG_PLUGINS
+ * section. Setting the special environment variable GEDIT_DEBUG
+ * enables output for all sections.
+ */
+ typedef enum {
+ GEDIT_NO_DEBUG = 0,
+ GEDIT_DEBUG_VIEW = 1 << 0,
+ GEDIT_DEBUG_PREFS = 1 << 1,
+ GEDIT_DEBUG_WINDOW = 1 << 2,
+ GEDIT_DEBUG_PANEL = 1 << 3,
+ GEDIT_DEBUG_PLUGINS = 1 << 4,
+ GEDIT_DEBUG_TAB = 1 << 5,
+ GEDIT_DEBUG_DOCUMENT = 1 << 6,
+ GEDIT_DEBUG_COMMANDS = 1 << 7,
+ GEDIT_DEBUG_APP = 1 << 8,
+ GEDIT_DEBUG_UTILS = 1 << 9,
++ GEDIT_DEBUG_METADATA = 1 << 10,
+ } GeditDebugSection;
+
+ #define DEBUG_VIEW GEDIT_DEBUG_VIEW, __FILE__, __LINE__, G_STRFUNC
+ #define DEBUG_PREFS GEDIT_DEBUG_PREFS, __FILE__, __LINE__, G_STRFUNC
+ #define DEBUG_WINDOW GEDIT_DEBUG_WINDOW, __FILE__, __LINE__, G_STRFUNC
+ #define DEBUG_PANEL GEDIT_DEBUG_PANEL, __FILE__, __LINE__, G_STRFUNC
+ #define DEBUG_PLUGINS GEDIT_DEBUG_PLUGINS, __FILE__, __LINE__, G_STRFUNC
+ #define DEBUG_TAB GEDIT_DEBUG_TAB, __FILE__, __LINE__, G_STRFUNC
+ #define DEBUG_DOCUMENT GEDIT_DEBUG_DOCUMENT,__FILE__, __LINE__, G_STRFUNC
+ #define DEBUG_COMMANDS GEDIT_DEBUG_COMMANDS,__FILE__, __LINE__, G_STRFUNC
+ #define DEBUG_APP GEDIT_DEBUG_APP, __FILE__, __LINE__, G_STRFUNC
+ #define DEBUG_UTILS GEDIT_DEBUG_UTILS, __FILE__, __LINE__, G_STRFUNC
++#define DEBUG_METADATA GEDIT_DEBUG_METADATA,__FILE__, __LINE__, G_STRFUNC
+
+ void gedit_debug_init (void);
+
+ void gedit_debug (GeditDebugSection section,
+ const gchar *file,
+ gint line,
+ const gchar *function);
+
+ void gedit_debug_message (GeditDebugSection section,
+ const gchar *file,
+ gint line,
+ const gchar *function,
+ const gchar *format, ...) G_GNUC_PRINTF(5, 6);
+
+ void gedit_debug_plugin_message (const gchar *file,
+ gint line,
+ const gchar *function,
+ const gchar *message);
+
+ #endif /* GEDIT_DEBUG_H */
+ /* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-document-private.h b/gedit/gedit-document-private.h
+index 62444cc76..574c0bb89 100644
+--- a/gedit/gedit-document-private.h
++++ b/gedit/gedit-document-private.h
+@@ -1,57 +1,63 @@
+ /*
+ * gedit-document.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002-2005 Paolo Maggi
+ * Copyright (C) 2014, 2020 Sébastien Wilmet
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #ifndef GEDIT_DOCUMENT_PRIVATE_H
+ #define GEDIT_DOCUMENT_PRIVATE_H
+
+ #include "gedit-document.h"
+
+ G_BEGIN_DECLS
+
+-#define GEDIT_METADATA_ATTRIBUTE_POSITION "gedit-position"
+-#define GEDIT_METADATA_ATTRIBUTE_ENCODING "gedit-encoding"
+-#define GEDIT_METADATA_ATTRIBUTE_LANGUAGE "gedit-language"
++#ifdef G_OS_WIN32
++#define GEDIT_METADATA_ATTRIBUTE_POSITION "position"
++#define GEDIT_METADATA_ATTRIBUTE_ENCODING "encoding"
++#define GEDIT_METADATA_ATTRIBUTE_LANGUAGE "language"
++#else
++#define GEDIT_METADATA_ATTRIBUTE_POSITION "metadata::gedit-position"
++#define GEDIT_METADATA_ATTRIBUTE_ENCODING "metadata::gedit-encoding"
++#define GEDIT_METADATA_ATTRIBUTE_LANGUAGE "metadata::gedit-language"
++#endif
+
+ G_GNUC_INTERNAL
+ glong _gedit_document_get_seconds_since_last_save_or_load (GeditDocument *doc);
+
+ G_GNUC_INTERNAL
+ gboolean _gedit_document_needs_saving (GeditDocument *doc);
+
+ G_GNUC_INTERNAL
+ gboolean _gedit_document_get_empty_search (GeditDocument *doc);
+
+ G_GNUC_INTERNAL
+ void _gedit_document_set_create (GeditDocument *doc,
+ gboolean create);
+
+ G_GNUC_INTERNAL
+ gboolean _gedit_document_get_create (GeditDocument *doc);
+
+ G_GNUC_INTERNAL
+ gchar * _gedit_document_get_uri_for_display (GeditDocument *doc);
+
+ G_END_DECLS
+
+ #endif /* GEDIT_DOCUMENT_PRIVATE_H */
+ /* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-document.c b/gedit/gedit-document.c
+index 54c11a96c..4cb08ee03 100644
+--- a/gedit/gedit-document.c
++++ b/gedit/gedit-document.c
+@@ -1,156 +1,177 @@
+ /*
+ * gedit-document.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002-2005 Paolo Maggi
+- * Copyright (C) 2014-2020 Sébastien Wilmet
++ * Copyright (C) 2014-2015 Sébastien Wilmet
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #include "config.h"
++
+ #include "gedit-document.h"
+ #include "gedit-document-private.h"
++
+ #include
+ #include
++
++#include "gedit-app.h"
++#include "gedit-app-private.h"
+ #include "gedit-settings.h"
+ #include "gedit-debug.h"
+ #include "gedit-utils.h"
++#include "gedit-metadata-manager.h"
++
++#define METADATA_QUERY "metadata::*"
+
+ #define NO_LANGUAGE_NAME "_NORMAL_"
+
+ static void gedit_document_loaded_real (GeditDocument *doc);
+
+ static void gedit_document_saved_real (GeditDocument *doc);
+
+ static void set_content_type (GeditDocument *doc,
+ const gchar *content_type);
+
+ typedef struct
+ {
+ GtkSourceFile *file;
+
+- TeplMetadata *metadata;
++ GSettings *editor_settings;
++
++ gint untitled_number;
++
++ GFileInfo *metadata_info;
+
+ gchar *content_type;
+
+ GDateTime *time_of_last_save_or_load;
+
+ /* The search context for the incremental search, or the search and
+ * replace. They are mutually exclusive.
+ */
+ GtkSourceSearchContext *search_context;
+
++ GeditMetadataManager *metadata_manager;
++
++ guint user_action;
++
+ guint language_set_by_user : 1;
++ guint use_gvfs_metadata : 1;
+
+ /* The search is empty if there is no search context, or if the
+ * search text is empty. It is used for the sensitivity of some menu
+ * actions.
+ */
+ guint empty_search : 1;
+
+ /* Create file if location points to a non existing file (for example
+ * when opened from the command line).
+ */
+ guint create : 1;
+ } GeditDocumentPrivate;
+
+ enum
+ {
+ PROP_0,
++ PROP_SHORTNAME,
+ PROP_CONTENT_TYPE,
+ PROP_MIME_TYPE,
+ PROP_EMPTY_SEARCH,
++ PROP_USE_GVFS_METADATA,
+ LAST_PROP
+ };
+
+ static GParamSpec *properties[LAST_PROP];
+
+ enum
+ {
++ CURSOR_MOVED,
+ LOAD,
+ LOADED,
+ SAVE,
+ SAVED,
+ LAST_SIGNAL
+ };
+
+ static guint document_signals[LAST_SIGNAL];
+
+-G_DEFINE_TYPE_WITH_PRIVATE (GeditDocument, gedit_document, TEPL_TYPE_BUFFER)
++static GHashTable *allocated_untitled_numbers = NULL;
+
+-static void
+-load_metadata_from_metadata_manager (GeditDocument *doc)
++G_DEFINE_TYPE_WITH_PRIVATE (GeditDocument, gedit_document, GTK_SOURCE_TYPE_BUFFER)
++
++static gint
++get_untitled_number (void)
+ {
+- GeditDocumentPrivate *priv = gedit_document_get_instance_private (doc);
+- GFile *location;
++ gint i = 1;
+
+- location = gtk_source_file_get_location (priv->file);
++ if (allocated_untitled_numbers == NULL)
++ allocated_untitled_numbers = g_hash_table_new (NULL, NULL);
+
+- if (location != NULL)
++ g_return_val_if_fail (allocated_untitled_numbers != NULL, -1);
++
++ while (TRUE)
+ {
+- TeplMetadataManager *manager;
++ if (g_hash_table_lookup (allocated_untitled_numbers, GINT_TO_POINTER (i)) == NULL)
++ {
++ g_hash_table_insert (allocated_untitled_numbers,
++ GINT_TO_POINTER (i),
++ GINT_TO_POINTER (i));
+
+- manager = tepl_metadata_manager_get_singleton ();
+- tepl_metadata_manager_copy_from (manager, location, priv->metadata);
++ return i;
++ }
++
++ ++i;
+ }
+ }
+
+ static void
+-save_metadata_into_metadata_manager (GeditDocument *doc)
++release_untitled_number (gint n)
+ {
+- GeditDocumentPrivate *priv = gedit_document_get_instance_private (doc);
+- GFile *location;
+-
+- location = gtk_source_file_get_location (priv->file);
+-
+- if (location != NULL)
+- {
+- TeplMetadataManager *manager;
++ g_return_if_fail (allocated_untitled_numbers != NULL);
+
+- manager = tepl_metadata_manager_get_singleton ();
+- tepl_metadata_manager_merge_into (manager, location, priv->metadata);
+- }
++ g_hash_table_remove (allocated_untitled_numbers, GINT_TO_POINTER (n));
+ }
+
+ static void
+ update_time_of_last_save_or_load (GeditDocument *doc)
+ {
+ GeditDocumentPrivate *priv = gedit_document_get_instance_private (doc);
+
+ if (priv->time_of_last_save_or_load != NULL)
+ {
+ g_date_time_unref (priv->time_of_last_save_or_load);
+ }
+
+ priv->time_of_last_save_or_load = g_date_time_new_now_utc ();
+ }
+
+ static const gchar *
+ get_language_string (GeditDocument *doc)
+ {
+ GtkSourceLanguage *lang = gedit_document_get_language (doc);
+
+ return lang != NULL ? gtk_source_language_get_id (lang) : NO_LANGUAGE_NAME;
+ }
+
+ static void
+ save_metadata (GeditDocument *doc)
+ {
+ GeditDocumentPrivate *priv;
+ const gchar *language = NULL;
+ GtkTextIter iter;
+ gchar *position;
+@@ -168,215 +189,361 @@ save_metadata (GeditDocument *doc)
+ position = g_strdup_printf ("%d", gtk_text_iter_get_offset (&iter));
+
+ if (language == NULL)
+ {
+ gedit_document_set_metadata (doc,
+ GEDIT_METADATA_ATTRIBUTE_POSITION, position,
+ NULL);
+ }
+ else
+ {
+ gedit_document_set_metadata (doc,
+ GEDIT_METADATA_ATTRIBUTE_POSITION, position,
+ GEDIT_METADATA_ATTRIBUTE_LANGUAGE, language,
+ NULL);
+ }
+
+ g_free (position);
+ }
+
+ static void
+ gedit_document_dispose (GObject *object)
+ {
+ GeditDocument *doc = GEDIT_DOCUMENT (object);
+ GeditDocumentPrivate *priv = gedit_document_get_instance_private (doc);
+
+ gedit_debug (DEBUG_DOCUMENT);
+
+ /* Metadata must be saved here and not in finalize because the language
+ * is gone by the time finalize runs.
+ */
+- if (priv->metadata != NULL)
++ if (priv->file != NULL)
+ {
+ save_metadata (doc);
+
+- g_object_unref (priv->metadata);
+- priv->metadata = NULL;
++ g_object_unref (priv->file);
++ priv->file = NULL;
+ }
+
+- g_clear_object (&priv->file);
++ g_clear_object (&priv->metadata_info);
+ g_clear_object (&priv->search_context);
++ g_clear_object (&priv->metadata_manager);
+
+ G_OBJECT_CLASS (gedit_document_parent_class)->dispose (object);
+ }
+
+ static void
+ gedit_document_finalize (GObject *object)
+ {
+- GeditDocumentPrivate *priv = gedit_document_get_instance_private (GEDIT_DOCUMENT (object));
++ GeditDocumentPrivate *priv;
+
+ gedit_debug (DEBUG_DOCUMENT);
+
++ priv = gedit_document_get_instance_private (GEDIT_DOCUMENT (object));
++
++ if (priv->untitled_number > 0)
++ {
++ release_untitled_number (priv->untitled_number);
++ }
++
+ g_free (priv->content_type);
+
+ if (priv->time_of_last_save_or_load != NULL)
+ {
+ g_date_time_unref (priv->time_of_last_save_or_load);
+ }
+
+ G_OBJECT_CLASS (gedit_document_parent_class)->finalize (object);
+ }
+
+ static void
+ gedit_document_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+ {
+ GeditDocument *doc = GEDIT_DOCUMENT (object);
+ GeditDocumentPrivate *priv;
+
+ priv = gedit_document_get_instance_private (doc);
+
+ switch (prop_id)
+ {
++ case PROP_SHORTNAME:
++ g_value_take_string (value, gedit_document_get_short_name_for_display (doc));
++ break;
++
+ case PROP_CONTENT_TYPE:
+ g_value_take_string (value, gedit_document_get_content_type (doc));
+ break;
+
+ case PROP_MIME_TYPE:
+ g_value_take_string (value, gedit_document_get_mime_type (doc));
+ break;
+
+ case PROP_EMPTY_SEARCH:
+ g_value_set_boolean (value, priv->empty_search);
+ break;
+
++ case PROP_USE_GVFS_METADATA:
++ g_value_set_boolean (value, priv->use_gvfs_metadata);
++ break;
++
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+ }
+
+ static void
+ gedit_document_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+ {
+ GeditDocument *doc = GEDIT_DOCUMENT (object);
++ GeditDocumentPrivate *priv = gedit_document_get_instance_private (doc);
+
+ switch (prop_id)
+ {
+ case PROP_CONTENT_TYPE:
+ set_content_type (doc, g_value_get_string (value));
+ break;
+
++ case PROP_USE_GVFS_METADATA:
++ priv->use_gvfs_metadata = g_value_get_boolean (value);
++ break;
++
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+ }
+
++static void
++gedit_document_begin_user_action (GtkTextBuffer *buffer)
++{
++ GeditDocumentPrivate *priv;
++
++ priv = gedit_document_get_instance_private (GEDIT_DOCUMENT (buffer));
++
++ ++priv->user_action;
++
++ if (GTK_TEXT_BUFFER_CLASS (gedit_document_parent_class)->begin_user_action != NULL)
++ {
++ GTK_TEXT_BUFFER_CLASS (gedit_document_parent_class)->begin_user_action (buffer);
++ }
++}
++
++static void
++gedit_document_end_user_action (GtkTextBuffer *buffer)
++{
++ GeditDocumentPrivate *priv;
++
++ priv = gedit_document_get_instance_private (GEDIT_DOCUMENT (buffer));
++
++ --priv->user_action;
++
++ if (GTK_TEXT_BUFFER_CLASS (gedit_document_parent_class)->end_user_action != NULL)
++ {
++ GTK_TEXT_BUFFER_CLASS (gedit_document_parent_class)->end_user_action (buffer);
++ }
++}
++
++static void
++gedit_document_mark_set (GtkTextBuffer *buffer,
++ const GtkTextIter *iter,
++ GtkTextMark *mark)
++{
++ GeditDocument *doc = GEDIT_DOCUMENT (buffer);
++ GeditDocumentPrivate *priv;
++
++ priv = gedit_document_get_instance_private (doc);
++
++ if (GTK_TEXT_BUFFER_CLASS (gedit_document_parent_class)->mark_set != NULL)
++ {
++ GTK_TEXT_BUFFER_CLASS (gedit_document_parent_class)->mark_set (buffer, iter, mark);
++ }
++
++ if (mark == gtk_text_buffer_get_insert (buffer) && (priv->user_action == 0))
++ {
++ g_signal_emit (doc, document_signals[CURSOR_MOVED], 0);
++ }
++}
++
++static void
++gedit_document_changed (GtkTextBuffer *buffer)
++{
++ g_signal_emit (GEDIT_DOCUMENT (buffer), document_signals[CURSOR_MOVED], 0);
++
++ GTK_TEXT_BUFFER_CLASS (gedit_document_parent_class)->changed (buffer);
++}
++
+ static void
+ gedit_document_constructed (GObject *object)
+ {
+ GeditDocument *doc = GEDIT_DOCUMENT (object);
++ GeditDocumentPrivate *priv;
+ GeditSettings *settings;
+ GSettings *editor_settings;
+
++ priv = gedit_document_get_instance_private (doc);
++
+ settings = _gedit_settings_get_singleton ();
+ editor_settings = _gedit_settings_peek_editor_settings (settings);
+
++ if (!priv->use_gvfs_metadata)
++ {
++ GeditMetadataManager *metadata_manager;
++
++ metadata_manager = _gedit_app_get_metadata_manager (GEDIT_APP (g_application_get_default ()));
++ g_assert (GEDIT_IS_METADATA_MANAGER (metadata_manager));
++ priv->metadata_manager = g_object_ref (metadata_manager);
++ }
++
+ /* Bind construct properties. */
+ g_settings_bind (editor_settings, GEDIT_SETTINGS_ENSURE_TRAILING_NEWLINE,
+ doc, "implicit-trailing-newline",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY);
+
+ G_OBJECT_CLASS (gedit_document_parent_class)->constructed (object);
+ }
+
+ static void
+ gedit_document_class_init (GeditDocumentClass *klass)
+ {
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
++ GtkTextBufferClass *buf_class = GTK_TEXT_BUFFER_CLASS (klass);
+
+ object_class->dispose = gedit_document_dispose;
+ object_class->finalize = gedit_document_finalize;
+ object_class->get_property = gedit_document_get_property;
+ object_class->set_property = gedit_document_set_property;
+ object_class->constructed = gedit_document_constructed;
+
++ buf_class->begin_user_action = gedit_document_begin_user_action;
++ buf_class->end_user_action = gedit_document_end_user_action;
++ buf_class->mark_set = gedit_document_mark_set;
++ buf_class->changed = gedit_document_changed;
++
+ klass->loaded = gedit_document_loaded_real;
+ klass->saved = gedit_document_saved_real;
+
++ /**
++ * GeditDocument:shortname:
++ *
++ * The document's short name.
++ */
++ properties[PROP_SHORTNAME] =
++ g_param_spec_string ("shortname",
++ "Short Name",
++ "The document's short name",
++ NULL,
++ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
++
+ /**
+ * GeditDocument:content-type:
+ *
+ * The document's content type.
+ */
+ properties[PROP_CONTENT_TYPE] =
+ g_param_spec_string ("content-type",
+ "Content Type",
+ "The document's Content Type",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GeditDocument:mime-type:
+ *
+ * The document's MIME type.
+ */
+ properties[PROP_MIME_TYPE] =
+ g_param_spec_string ("mime-type",
+ "MIME Type",
+ "The document's MIME Type",
+ "text/plain",
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GeditDocument:empty-search:
+ *
+ *
+ * The property is used internally by gedit. It must not be used in a
+ * gedit plugin. The property can be modified or removed at any time.
+ *
+ */
+ properties[PROP_EMPTY_SEARCH] =
+ g_param_spec_boolean ("empty-search",
+ "Empty search",
+ "Whether the search is empty",
+ TRUE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
++ /**
++ * GeditDocument:use-gvfs-metadata:
++ *
++ * Whether to use GVFS metadata. If %FALSE, use the gedit metadata
++ * manager that stores the metadata in an XML file in the user cache
++ * directory.
++ *
++ *
++ * The property is used internally by gedit. It must not be used in a
++ * gedit plugin. The property can be modified or removed at any time.
++ *
++ */
++ properties[PROP_USE_GVFS_METADATA] =
++ g_param_spec_boolean ("use-gvfs-metadata",
++ "Use GVFS metadata",
++ "",
++ TRUE,
++ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
++
+ g_object_class_install_properties (object_class, LAST_PROP, properties);
+
++ /* This signal is used to update the cursor position in the statusbar,
++ * it's emitted either when the insert mark is moved explicitely or
++ * when the buffer changes (insert/delete).
++ * FIXME When the replace_all was implemented in gedit, this signal was
++ * not emitted during the replace_all to improve performance. Now the
++ * replace_all is implemented in GtkSourceView, so the signal is
++ * emitted.
++ */
++ document_signals[CURSOR_MOVED] =
++ g_signal_new ("cursor-moved",
++ G_OBJECT_CLASS_TYPE (object_class),
++ G_SIGNAL_RUN_LAST,
++ G_STRUCT_OFFSET (GeditDocumentClass, cursor_moved),
++ NULL, NULL, NULL,
++ G_TYPE_NONE,
++ 0);
++
+ /**
+ * GeditDocument::load:
+ * @document: the #GeditDocument.
+ *
+ * The "load" signal is emitted at the beginning of a file loading.
+ *
+ * Before gedit 3.14 this signal contained parameters to configure the
+ * file loading (the location, encoding, etc). Plugins should not need
+ * those parameters.
+ */
+ document_signals[LOAD] =
+ g_signal_new ("load",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GeditDocumentClass, load),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+
+ /**
+ * GeditDocument::loaded:
+ * @document: the #GeditDocument.
+ *
+ * The "loaded" signal is emitted at the end of a successful file
+ * loading.
+ *
+ * Before gedit 3.14 this signal contained a #GError parameter, and the
+ * signal was also emitted if an error occurred. Plugins should not need
+ * the error parameter.
+ */
+ document_signals[LOADED] =
+@@ -605,128 +772,188 @@ static void
+ on_content_type_changed (GeditDocument *doc,
+ GParamSpec *pspec,
+ gpointer useless)
+ {
+ GeditDocumentPrivate *priv;
+
+ priv = gedit_document_get_instance_private (doc);
+
+ if (!priv->language_set_by_user)
+ {
+ GtkSourceLanguage *language = guess_language (doc);
+
+ gedit_debug_message (DEBUG_DOCUMENT, "Language: %s",
+ language != NULL ? gtk_source_language_get_name (language) : "None");
+
+ set_language (doc, language, FALSE);
+ }
+ }
+
+ static gchar *
+ get_default_content_type (void)
+ {
+ return g_content_type_from_mime_type ("text/plain");
+ }
+
+ static void
+ on_location_changed (GtkSourceFile *file,
+ GParamSpec *pspec,
+ GeditDocument *doc)
+ {
++ GeditDocumentPrivate *priv;
++ GFile *location;
++
+ gedit_debug (DEBUG_DOCUMENT);
+- load_metadata_from_metadata_manager (doc);
++
++ priv = gedit_document_get_instance_private (doc);
++
++ location = gtk_source_file_get_location (file);
++
++ if (location != NULL && priv->untitled_number > 0)
++ {
++ release_untitled_number (priv->untitled_number);
++ priv->untitled_number = 0;
++ }
++
++ g_object_notify_by_pspec (G_OBJECT (doc), properties[PROP_SHORTNAME]);
++
++ /* Load metadata for this location: we load sync since metadata is
++ * always local so it should be fast and we need the information
++ * right after the location was set.
++ * TODO: do async I/O for the metadata.
++ */
++ if (priv->use_gvfs_metadata && location != NULL)
++ {
++ GError *error = NULL;
++
++ if (priv->metadata_info != NULL)
++ {
++ g_object_unref (priv->metadata_info);
++ }
++
++ priv->metadata_info = g_file_query_info (location,
++ METADATA_QUERY,
++ G_FILE_QUERY_INFO_NONE,
++ NULL,
++ &error);
++
++ if (error != NULL)
++ {
++ /* Do not complain about metadata if we are opening a
++ * non existing file.
++ */
++ if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_ISDIR) &&
++ !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOTDIR) &&
++ !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT) &&
++ !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
++ {
++ g_warning ("%s", error->message);
++ }
++
++ g_error_free (error);
++ }
++
++ if (priv->metadata_info == NULL)
++ {
++ priv->metadata_info = g_file_info_new ();
++ }
++ }
+ }
+
+ static void
+ gedit_document_init (GeditDocument *doc)
+ {
+ GeditDocumentPrivate *priv = gedit_document_get_instance_private (doc);
+- TeplFile *tepl_file;
+ GeditSettings *settings;
+ GSettings *editor_settings;
+
+ gedit_debug (DEBUG_DOCUMENT);
+
++ settings = _gedit_settings_get_singleton ();
++ editor_settings = _gedit_settings_peek_editor_settings (settings);
++
++ priv->untitled_number = get_untitled_number ();
+ priv->content_type = get_default_content_type ();
+ priv->language_set_by_user = FALSE;
+ priv->empty_search = TRUE;
+
+ update_time_of_last_save_or_load (doc);
+
+ priv->file = gtk_source_file_new ();
+- tepl_file = tepl_buffer_get_file (TEPL_BUFFER (doc));
+-
+- g_object_bind_property (priv->file, "location",
+- tepl_file, "location",
+- G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
+-
+- priv->metadata = tepl_metadata_new ();
++ priv->metadata_info = g_file_info_new ();
+
+ g_signal_connect_object (priv->file,
+ "notify::location",
+ G_CALLBACK (on_location_changed),
+ doc,
+ 0);
+
+- settings = _gedit_settings_get_singleton ();
+- editor_settings = _gedit_settings_peek_editor_settings (settings);
+-
+ g_settings_bind (editor_settings, GEDIT_SETTINGS_MAX_UNDO_ACTIONS,
+ doc, "max-undo-levels",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY);
+
+ g_settings_bind (editor_settings, GEDIT_SETTINGS_SYNTAX_HIGHLIGHTING,
+ doc, "highlight-syntax",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY);
+
+ g_settings_bind (editor_settings, GEDIT_SETTINGS_BRACKET_MATCHING,
+ doc, "highlight-matching-brackets",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY);
+
+ g_signal_connect_object (editor_settings,
+ "changed::" GEDIT_SETTINGS_SCHEME,
+ G_CALLBACK (editor_settings_scheme_changed_cb),
+ doc,
+ 0);
+
+ update_style_scheme (doc);
+
+ g_signal_connect (doc,
+ "notify::content-type",
+ G_CALLBACK (on_content_type_changed),
+ NULL);
+ }
+
+ GeditDocument *
+ gedit_document_new (void)
+ {
+- return g_object_new (GEDIT_TYPE_DOCUMENT, NULL);
++ gboolean use_gvfs_metadata;
++
++#ifdef ENABLE_GVFS_METADATA
++ use_gvfs_metadata = TRUE;
++#else
++ use_gvfs_metadata = FALSE;
++#endif
++
++ return g_object_new (GEDIT_TYPE_DOCUMENT,
++ "use-gvfs-metadata", use_gvfs_metadata,
++ NULL);
+ }
+
+ static gchar *
+ get_content_type_from_content (GeditDocument *doc)
+ {
+ gchar *content_type;
+ gchar *data;
+ GtkTextBuffer *buffer;
+ GtkTextIter start;
+ GtkTextIter end;
+
+ buffer = GTK_TEXT_BUFFER (doc);
+
+ gtk_text_buffer_get_start_iter (buffer, &start);
+ end = start;
+ gtk_text_iter_forward_chars (&end, 255);
+
+ data = gtk_text_buffer_get_text (buffer, &start, &end, TRUE);
+
+ content_type = g_content_type_guess (NULL,
+ (const guchar *)data,
+ strlen (data),
+ NULL);
+
+ g_free (data);
+
+ return content_type;
+ }
+
+ static void
+@@ -787,93 +1014,107 @@ set_content_type (GeditDocument *doc,
+ if (content_type == NULL)
+ {
+ GFile *location;
+ gchar *guessed_type = NULL;
+
+ /* If content type is null, we guess from the filename */
+ location = gtk_source_file_get_location (priv->file);
+ if (location != NULL)
+ {
+ gchar *basename;
+
+ basename = g_file_get_basename (location);
+ guessed_type = g_content_type_guess (basename, NULL, 0, NULL);
+
+ g_free (basename);
+ }
+
+ set_content_type_no_guess (doc, guessed_type);
+ g_free (guessed_type);
+ }
+ else
+ {
+ set_content_type_no_guess (doc, content_type);
+ }
+ }
+
+ /* Note: this never returns %NULL. */
+ gchar *
+ _gedit_document_get_uri_for_display (GeditDocument *doc)
+ {
+- TeplFile *file;
++ GeditDocumentPrivate *priv;
+ GFile *location;
+
+ g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), g_strdup (""));
+
+- file = tepl_buffer_get_file (TEPL_BUFFER (doc));
+- location = tepl_file_get_location (file);
++ priv = gedit_document_get_instance_private (doc);
++
++ location = gtk_source_file_get_location (priv->file);
+
+ if (location == NULL)
+ {
+- return tepl_file_get_short_name (file);
++ return g_strdup_printf (_("Untitled Document %d"),
++ priv->untitled_number);
+ }
+ else
+ {
+ return g_file_get_parse_name (location);
+ }
+ }
+
+ /**
+ * gedit_document_get_short_name_for_display:
+ * @doc: a #GeditDocument.
+ *
+ * Note: this never returns %NULL.
+ **/
+ gchar *
+ gedit_document_get_short_name_for_display (GeditDocument *doc)
+ {
+- TeplFile *file;
++ GeditDocumentPrivate *priv;
++ GFile *location;
+
+ g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), g_strdup (""));
+
+- file = tepl_buffer_get_file (TEPL_BUFFER (doc));
+- return tepl_file_get_short_name (file);
++ priv = gedit_document_get_instance_private (doc);
++
++ location = gtk_source_file_get_location (priv->file);
++
++ if (location == NULL)
++ {
++ return g_strdup_printf (_("Untitled Document %d"),
++ priv->untitled_number);
++ }
++ else
++ {
++ return gedit_utils_basename_for_display (location);
++ }
+ }
+
+ gchar *
+ gedit_document_get_content_type (GeditDocument *doc)
+ {
+ GeditDocumentPrivate *priv;
+
+ g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), NULL);
+
+ priv = gedit_document_get_instance_private (doc);
+
+ return g_strdup (priv->content_type);
+ }
+
+ /**
+ * gedit_document_get_mime_type:
+ * @doc: a #GeditDocument.
+ *
+ * Note: this never returns %NULL.
+ **/
+ gchar *
+ gedit_document_get_mime_type (GeditDocument *doc)
+ {
+ GeditDocumentPrivate *priv;
+
+ g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), g_strdup ("text/plain"));
+
+ priv = gedit_document_get_instance_private (doc);
+
+ if (priv->content_type != NULL &&
+@@ -1005,225 +1246,398 @@ saved_query_info_cb (GFile *location,
+ priv->create = FALSE;
+
+ save_encoding_metadata (doc);
+
+ /* Async operation finished. */
+ g_object_unref (doc);
+ }
+
+ static void
+ gedit_document_saved_real (GeditDocument *doc)
+ {
+ GeditDocumentPrivate *priv;
+ GFile *location;
+
+ priv = gedit_document_get_instance_private (doc);
+
+ location = gtk_source_file_get_location (priv->file);
+
+ /* Keep the doc alive during the async operation. */
+ g_object_ref (doc);
+
+ g_file_query_info_async (location,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ (GAsyncReadyCallback) saved_query_info_cb,
+ doc);
+ }
+
++gboolean
++gedit_document_is_untouched (GeditDocument *doc)
++{
++ GeditDocumentPrivate *priv;
++ GFile *location;
++
++ g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), TRUE);
++
++ priv = gedit_document_get_instance_private (doc);
++
++ location = gtk_source_file_get_location (priv->file);
++
++ return location == NULL && !gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (doc));
++}
++
+ gboolean
+ gedit_document_is_untitled (GeditDocument *doc)
+ {
+- TeplFile *file;
++ GeditDocumentPrivate *priv;
+
+ g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), TRUE);
+
+- file = tepl_buffer_get_file (TEPL_BUFFER (doc));
+- return tepl_file_get_location (file) == NULL;
++ priv = gedit_document_get_instance_private (doc);
++
++ return gtk_source_file_get_location (priv->file) == NULL;
+ }
+
+ /*
+ * Deletion and external modification is only checked for local files.
+ */
+ gboolean
+ _gedit_document_needs_saving (GeditDocument *doc)
+ {
+ GeditDocumentPrivate *priv;
+ gboolean externally_modified = FALSE;
+ gboolean deleted = FALSE;
+
+ g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), FALSE);
+
+ priv = gedit_document_get_instance_private (doc);
+
+ if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (doc)))
+ {
+ return TRUE;
+ }
+
+ if (gtk_source_file_is_local (priv->file))
+ {
+ gtk_source_file_check_file_on_disk (priv->file);
+ externally_modified = gtk_source_file_is_externally_modified (priv->file);
+ deleted = gtk_source_file_is_deleted (priv->file);
+ }
+
+ return (externally_modified || deleted) && !priv->create;
+ }
+
++/* If @line is bigger than the lines of the document, the cursor is moved
++ * to the last line and FALSE is returned.
++ */
++gboolean
++gedit_document_goto_line (GeditDocument *doc,
++ gint line)
++{
++ GtkTextIter iter;
++
++ gedit_debug (DEBUG_DOCUMENT);
++
++ g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), FALSE);
++ g_return_val_if_fail (line >= -1, FALSE);
++
++ gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (doc),
++ &iter,
++ line);
++
++ gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc), &iter);
++
++ return gtk_text_iter_get_line (&iter) == line;
++}
++
++gboolean
++gedit_document_goto_line_offset (GeditDocument *doc,
++ gint line,
++ gint line_offset)
++{
++ GtkTextIter iter;
++
++ g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), FALSE);
++ g_return_val_if_fail (line >= -1, FALSE);
++ g_return_val_if_fail (line_offset >= -1, FALSE);
++
++ gtk_text_buffer_get_iter_at_line_offset (GTK_TEXT_BUFFER (doc),
++ &iter,
++ line,
++ line_offset);
++
++ gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc), &iter);
++
++ return (gtk_text_iter_get_line (&iter) == line &&
++ gtk_text_iter_get_line_offset (&iter) == line_offset);
++}
++
+ /**
+ * gedit_document_set_language:
+ * @doc:
+ * @lang: (allow-none):
+ **/
+ void
+ gedit_document_set_language (GeditDocument *doc,
+ GtkSourceLanguage *lang)
+ {
+ g_return_if_fail (GEDIT_IS_DOCUMENT (doc));
+
+ set_language (doc, lang, TRUE);
+ }
+
+ /**
+ * gedit_document_get_language:
+ * @doc:
+ *
+ * Return value: (transfer none):
+ */
+ GtkSourceLanguage *
+ gedit_document_get_language (GeditDocument *doc)
+ {
+ g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), NULL);
+
+ return gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (doc));
+ }
+
+ glong
+ _gedit_document_get_seconds_since_last_save_or_load (GeditDocument *doc)
+ {
+ GeditDocumentPrivate *priv;
+ GDateTime *now;
+ GTimeSpan n_microseconds;
+
+ gedit_debug (DEBUG_DOCUMENT);
+
+ g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), -1);
+
+ priv = gedit_document_get_instance_private (doc);
+
+ if (priv->time_of_last_save_or_load == NULL)
+ {
+ return -1;
+ }
+
+ now = g_date_time_new_now_utc ();
+ if (now == NULL)
+ {
+ return -1;
+ }
+
+ n_microseconds = g_date_time_difference (now, priv->time_of_last_save_or_load);
+ g_date_time_unref (now);
+
+ return n_microseconds / (1000 * 1000);
+ }
+
++static gchar *
++get_metadata_from_metadata_manager (GeditDocument *doc,
++ const gchar *key)
++{
++ GeditDocumentPrivate *priv;
++ GFile *location;
++
++ priv = gedit_document_get_instance_private (doc);
++
++ location = gtk_source_file_get_location (priv->file);
++
++ if (location != NULL)
++ {
++ return gedit_metadata_manager_get (priv->metadata_manager, location, key);
++ }
++
++ return NULL;
++}
++
++static gchar *
++get_metadata_from_gvfs (GeditDocument *doc,
++ const gchar *key)
++{
++ GeditDocumentPrivate *priv;
++
++ priv = gedit_document_get_instance_private (doc);
++
++ if (priv->metadata_info != NULL &&
++ g_file_info_has_attribute (priv->metadata_info, key) &&
++ g_file_info_get_attribute_type (priv->metadata_info, key) == G_FILE_ATTRIBUTE_TYPE_STRING)
++ {
++ return g_strdup (g_file_info_get_attribute_string (priv->metadata_info, key));
++ }
++
++ return NULL;
++}
++
++static void
++set_gvfs_metadata (GFileInfo *info,
++ const gchar *key,
++ const gchar *value)
++{
++ g_return_if_fail (G_IS_FILE_INFO (info));
++
++ if (value != NULL)
++ {
++ g_file_info_set_attribute_string (info, key, value);
++ }
++ else
++ {
++ /* Unset the key */
++ g_file_info_set_attribute (info,
++ key,
++ G_FILE_ATTRIBUTE_TYPE_INVALID,
++ NULL);
++ }
++}
++
+ /**
+ * gedit_document_get_metadata:
+ * @doc: a #GeditDocument
+ * @key: name of the key
+ *
+ * Gets the metadata assigned to @key.
+ *
+ * Returns: the value assigned to @key. Free with g_free().
+ */
+ gchar *
+ gedit_document_get_metadata (GeditDocument *doc,
+ const gchar *key)
+ {
+ GeditDocumentPrivate *priv;
+
+ g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), NULL);
+ g_return_val_if_fail (key != NULL, NULL);
+
+ priv = gedit_document_get_instance_private (doc);
+
+- if (priv->metadata == NULL)
++ if (priv->use_gvfs_metadata)
+ {
+- return NULL;
++ return get_metadata_from_gvfs (doc, key);
+ }
+
+- return tepl_metadata_get (priv->metadata, key);
++ return get_metadata_from_metadata_manager (doc, key);
+ }
+
+ /**
+ * gedit_document_set_metadata:
+ * @doc: a #GeditDocument
+ * @first_key: name of the first key to set
+ * @...: (allow-none): value for the first key, followed optionally by more key/value pairs,
+ * followed by %NULL.
+ *
+ * Sets metadata on a document.
+ */
+ void
+ gedit_document_set_metadata (GeditDocument *doc,
+ const gchar *first_key,
+ ...)
+ {
+ GeditDocumentPrivate *priv;
+- va_list var_args;
++ GFile *location;
+ const gchar *key;
++ va_list var_args;
++ GFileInfo *info = NULL;
+
+ g_return_if_fail (GEDIT_IS_DOCUMENT (doc));
+ g_return_if_fail (first_key != NULL);
+
+ priv = gedit_document_get_instance_private (doc);
+
+- if (priv->metadata == NULL)
++ location = gtk_source_file_get_location (priv->file);
++
++ /* With the metadata manager, can't set metadata for untitled documents.
++ * With GVFS metadata, if the location is NULL the metadata is stored in
++ * priv->metadata_info, so that it can be saved later if the document is
++ * saved.
++ */
++ if (!priv->use_gvfs_metadata && location == NULL)
+ {
+ return;
+ }
+
++ if (priv->use_gvfs_metadata)
++ {
++ info = g_file_info_new ();
++ }
++
+ va_start (var_args, first_key);
+
+- for (key = first_key; key != NULL; key = va_arg (var_args, const gchar *))
++ for (key = first_key; key; key = va_arg (var_args, const gchar *))
+ {
+ const gchar *value = va_arg (var_args, const gchar *);
+- tepl_metadata_set (priv->metadata, key, value);
++
++ if (priv->use_gvfs_metadata)
++ {
++ set_gvfs_metadata (info, key, value);
++ set_gvfs_metadata (priv->metadata_info, key, value);
++ }
++ else
++ {
++ gedit_metadata_manager_set (priv->metadata_manager, location, key, value);
++ }
+ }
+
+ va_end (var_args);
+
+- save_metadata_into_metadata_manager (doc);
++ if (priv->use_gvfs_metadata && location != NULL)
++ {
++ GError *error = NULL;
++
++ /* We save synchronously since metadata is always local so it
++ * should be fast. Moreover this function can be called on
++ * application shutdown, when the main loop has already exited,
++ * so an async operation would not terminate.
++ * https://bugzilla.gnome.org/show_bug.cgi?id=736591
++ */
++ g_file_set_attributes_from_info (location,
++ info,
++ G_FILE_QUERY_INFO_NONE,
++ NULL,
++ &error);
++
++ if (error != NULL)
++ {
++ /* Do not complain about metadata if we are closing a
++ * document for a non existing file.
++ */
++ if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT) &&
++ !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
++ {
++ g_warning ("Set document metadata failed: %s", error->message);
++ }
++
++ g_error_free (error);
++ }
++ }
++
++ g_clear_object (&info);
+ }
+
+ static void
+ update_empty_search (GeditDocument *doc)
+ {
+ GeditDocumentPrivate *priv;
+ gboolean new_value;
+
+ priv = gedit_document_get_instance_private (doc);
+
+ if (priv->search_context == NULL)
+ {
+ new_value = TRUE;
+ }
+ else
+ {
+ GtkSourceSearchSettings *search_settings;
+
+ search_settings = gtk_source_search_context_get_settings (priv->search_context);
+
+ new_value = gtk_source_search_settings_get_search_text (search_settings) == NULL;
+ }
+
+ if (priv->empty_search != new_value)
+ {
+ priv->empty_search = new_value;
+ g_object_notify_by_pspec (G_OBJECT (doc), properties[PROP_EMPTY_SEARCH]);
+ }
+ }
+
+diff --git a/gedit/gedit-document.h b/gedit/gedit-document.h
+index 901d02dc0..ed52a42fb 100644
+--- a/gedit/gedit-document.h
++++ b/gedit/gedit-document.h
+@@ -1,83 +1,93 @@
+ /*
+ * gedit-document.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002-2005 Paolo Maggi
+- * Copyright (C) 2014-2020 Sébastien Wilmet
++ * Copyright (C) 2014 Sébastien Wilmet
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #ifndef GEDIT_DOCUMENT_H
+ #define GEDIT_DOCUMENT_H
+
+-#include
++#include
+
+ G_BEGIN_DECLS
+
+ #define GEDIT_TYPE_DOCUMENT (gedit_document_get_type())
+
+-G_DECLARE_DERIVABLE_TYPE (GeditDocument, gedit_document, GEDIT, DOCUMENT, TeplBuffer)
++G_DECLARE_DERIVABLE_TYPE (GeditDocument, gedit_document, GEDIT, DOCUMENT, GtkSourceBuffer)
+
+ struct _GeditDocumentClass
+ {
+- TeplBufferClass parent_class;
++ GtkSourceBufferClass parent_class;
+
+ /* Signals */
++ void (* cursor_moved) (GeditDocument *document);
+
+ void (* load) (GeditDocument *document);
+
+ void (* loaded) (GeditDocument *document);
+
+ void (* save) (GeditDocument *document);
+
+ void (* saved) (GeditDocument *document);
+ };
+
+ GeditDocument *gedit_document_new (void);
+
+ GtkSourceFile *gedit_document_get_file (GeditDocument *doc);
+
+ gchar *gedit_document_get_short_name_for_display (GeditDocument *doc);
+
+ gchar *gedit_document_get_content_type (GeditDocument *doc);
+
+ gchar *gedit_document_get_mime_type (GeditDocument *doc);
+
++gboolean gedit_document_is_untouched (GeditDocument *doc);
++
+ gboolean gedit_document_is_untitled (GeditDocument *doc);
+
++gboolean gedit_document_goto_line (GeditDocument *doc,
++ gint line);
++
++gboolean gedit_document_goto_line_offset (GeditDocument *doc,
++ gint line,
++ gint line_offset);
++
+ void gedit_document_set_language (GeditDocument *doc,
+ GtkSourceLanguage *lang);
+ GtkSourceLanguage
+ *gedit_document_get_language (GeditDocument *doc);
+
+ gchar *gedit_document_get_metadata (GeditDocument *doc,
+ const gchar *key);
+
+ void gedit_document_set_metadata (GeditDocument *doc,
+ const gchar *first_key,
+ ...);
+
+ void gedit_document_set_search_context (GeditDocument *doc,
+ GtkSourceSearchContext *search_context);
+
+ GtkSourceSearchContext *
+ gedit_document_get_search_context (GeditDocument *doc);
+
+ G_END_DECLS
+
+ #endif /* GEDIT_DOCUMENT_H */
+ /* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-documents-panel.c b/gedit/gedit-documents-panel.c
+index 98d84a98f..8033f944e 100644
+--- a/gedit/gedit-documents-panel.c
++++ b/gedit/gedit-documents-panel.c
+@@ -1,56 +1,55 @@
+ /*
+ * gedit-documents-panel.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Sébastien Lafargue
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #include "config.h"
+
+ #include "gedit-documents-panel.h"
+
+ #include
+-#include
+
+ #include "gedit-debug.h"
+ #include "gedit-document.h"
+ #include "gedit-multi-notebook.h"
+ #include "gedit-notebook.h"
+ #include "gedit-notebook-popup-menu.h"
+ #include "gedit-tab.h"
+ #include "gedit-tab-private.h"
+ #include "gedit-utils.h"
+ #include "gedit-commands-private.h"
+
+ typedef struct _GeditDocumentsGenericRow GeditDocumentsGenericRow;
+ typedef struct _GeditDocumentsGenericRow GeditDocumentsGroupRow;
+ typedef struct _GeditDocumentsGenericRow GeditDocumentsDocumentRow;
+
+ struct _GeditDocumentsGenericRow
+ {
+ GtkListBoxRow parent_instance;
+
+ GeditDocumentsPanel *panel;
+ GtkWidget *ref;
+
+ GtkWidget *box;
+ GtkWidget *label;
+ GtkWidget *close_button;
+
+ /* Not used in GeditDocumentsGroupRow */
+ GtkWidget *image;
+ GtkWidget *status_label;
+ };
+@@ -420,61 +419,61 @@ group_row_update_names (GeditDocumentsPanel *panel,
+ {
+ group_row_set_notebook_name (row);
+ }
+ }
+
+ g_list_free (children);
+ }
+
+ static void
+ group_row_refresh_visibility (GeditDocumentsPanel *panel)
+ {
+ gboolean notebook_is_unique;
+ GtkWidget *first_group_row;
+
+ notebook_is_unique = gedit_multi_notebook_get_n_notebooks (panel->mnb) <= 1;
+ first_group_row = GTK_WIDGET (get_first_notebook_found (panel));
+
+ gtk_widget_set_no_show_all (first_group_row, notebook_is_unique);
+ gtk_widget_set_visible (first_group_row, !notebook_is_unique);
+ }
+
+ static gchar *
+ doc_get_name (GeditDocument *doc)
+ {
+ gchar *name;
+ gchar *docname;
+
+ name = gedit_document_get_short_name_for_display (doc);
+
+ /* Truncate the name so it doesn't get insanely wide. */
+- docname = tepl_utils_str_middle_truncate (name, MAX_DOC_NAME_LENGTH);
++ docname = gedit_utils_str_middle_truncate (name, MAX_DOC_NAME_LENGTH);
+
+ g_free (name);
+
+ return docname;
+ }
+
+ static void
+ document_row_sync_tab_name_and_icon (GeditTab *tab,
+ GParamSpec *pspec,
+ GtkWidget *row)
+ {
+ GeditDocumentsDocumentRow *document_row = GEDIT_DOCUMENTS_DOCUMENT_ROW (row);
+ GeditDocument *doc;
+ GtkSourceFile *file;
+ gchar *name;
+ GdkPixbuf *pixbuf;
+
+ doc = gedit_tab_get_document (tab);
+ name = doc_get_name (doc);
+
+ if (!gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (doc)))
+ {
+ gtk_label_set_text (GTK_LABEL (document_row->label), name);
+ }
+ else
+ {
+ gchar *markup;
+
+ markup = g_markup_printf_escaped ("%s", name);
+ gtk_label_set_markup (GTK_LABEL (document_row->label), markup);
+diff --git a/gedit/gedit-factory.c b/gedit/gedit-factory.c
+deleted file mode 100644
+index 409b3beb2..000000000
+--- a/gedit/gedit-factory.c
++++ /dev/null
+@@ -1,50 +0,0 @@
+-/*
+- * This file is part of gedit
+- *
+- * Copyright (C) 2020 Sébastien Wilmet
+- *
+- * 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
+- * along with this program; if not, see .
+- */
+-
+-#include "gedit-factory.h"
+-#include "gedit-dirs.h"
+-
+-G_DEFINE_TYPE (GeditFactory, gedit_factory, TEPL_TYPE_ABSTRACT_FACTORY)
+-
+-static GFile *
+-gedit_factory_create_metadata_manager_file (TeplAbstractFactory *factory)
+-{
+- return g_file_new_build_filename (gedit_dirs_get_user_data_dir (),
+- "gedit-metadata.xml",
+- NULL);
+-}
+-
+-static void
+-gedit_factory_class_init (GeditFactoryClass *klass)
+-{
+- TeplAbstractFactoryClass *factory_class = TEPL_ABSTRACT_FACTORY_CLASS (klass);
+-
+- factory_class->create_metadata_manager_file = gedit_factory_create_metadata_manager_file;
+-}
+-
+-static void
+-gedit_factory_init (GeditFactory *factory)
+-{
+-}
+-
+-GeditFactory *
+-gedit_factory_new (void)
+-{
+- return g_object_new (GEDIT_TYPE_FACTORY, NULL);
+-}
+diff --git a/gedit/gedit-factory.h b/gedit/gedit-factory.h
+deleted file mode 100644
+index 05e19f715..000000000
+--- a/gedit/gedit-factory.h
++++ /dev/null
+@@ -1,53 +0,0 @@
+-/*
+- * This file is part of gedit
+- *
+- * Copyright (C) 2020 Sébastien Wilmet
+- *
+- * 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
+- * along with this program; if not, see .
+- */
+-
+-#ifndef GEDIT_FACTORY_H
+-#define GEDIT_FACTORY_H
+-
+-#include
+-
+-G_BEGIN_DECLS
+-
+-#define GEDIT_TYPE_FACTORY (gedit_factory_get_type ())
+-#define GEDIT_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FACTORY, GeditFactory))
+-#define GEDIT_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_FACTORY, GeditFactoryClass))
+-#define GEDIT_IS_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_FACTORY))
+-#define GEDIT_IS_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_FACTORY))
+-#define GEDIT_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_FACTORY, GeditFactoryClass))
+-
+-typedef struct _GeditFactory GeditFactory;
+-typedef struct _GeditFactoryClass GeditFactoryClass;
+-
+-struct _GeditFactory
+-{
+- TeplAbstractFactory parent;
+-};
+-
+-struct _GeditFactoryClass
+-{
+- TeplAbstractFactoryClass parent_class;
+-};
+-
+-GType gedit_factory_get_type (void);
+-
+-GeditFactory * gedit_factory_new (void);
+-
+-G_END_DECLS
+-
+-#endif /* GEDIT_FACTORY_H */
+diff --git a/gedit/gedit-file-chooser-dialog-gtk.c b/gedit/gedit-file-chooser-dialog-gtk.c
+index 4b8b4dbb0..17671ff3e 100644
+--- a/gedit/gedit-file-chooser-dialog-gtk.c
++++ b/gedit/gedit-file-chooser-dialog-gtk.c
+@@ -165,131 +165,160 @@ chooser_set_current_name (GeditFileChooserDialog *dialog,
+ gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), name);
+ }
+
+ static void
+ chooser_set_file (GeditFileChooserDialog *dialog,
+ GFile *file)
+ {
+ gtk_file_chooser_set_file (GTK_FILE_CHOOSER (dialog), file, NULL);
+ }
+
+ static GFile *
+ chooser_get_file (GeditFileChooserDialog *dialog)
+ {
+ return gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
+ }
+
+ static void
+ chooser_set_do_overwrite_confirmation (GeditFileChooserDialog *dialog,
+ gboolean overwrite_confirmation)
+ {
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), overwrite_confirmation);
+ }
+
+ static void
+ chooser_show (GeditFileChooserDialog *dialog)
+ {
+ gtk_window_present (GTK_WINDOW (dialog));
+ gtk_widget_grab_focus (GTK_WIDGET (dialog));
+ }
+
++static void
++chooser_hide (GeditFileChooserDialog *dialog)
++{
++ gtk_widget_hide (GTK_WIDGET (dialog));
++}
++
+ static void
+ chooser_destroy (GeditFileChooserDialog *dialog)
+ {
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ }
+
+ static void
+ chooser_set_modal (GeditFileChooserDialog *dialog,
+ gboolean is_modal)
+ {
+ gtk_window_set_modal (GTK_WINDOW (dialog), is_modal);
+ }
+
+ static GtkWindow *
+ chooser_get_window (GeditFileChooserDialog *dialog)
+ {
+ return GTK_WINDOW (dialog);
+ }
+
++static void
++chooser_add_pattern_filter (GeditFileChooserDialog *dialog,
++ const gchar *name,
++ const gchar *pattern)
++{
++ GtkFileFilter *filter;
++
++ filter = gtk_file_filter_new ();
++
++ gtk_file_filter_set_name (filter, name);
++ gtk_file_filter_add_pattern (filter, pattern);
++
++ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
++
++ if (gtk_file_chooser_get_filter (GTK_FILE_CHOOSER (dialog)) == NULL)
++ {
++ gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
++ }
++}
++
+ static void
+ gedit_file_chooser_dialog_gtk_chooser_init (gpointer g_iface,
+ gpointer iface_data)
+ {
+ GeditFileChooserDialogInterface *iface = g_iface;
+
+ iface->set_encoding = chooser_set_encoding;
+ iface->get_encoding = chooser_get_encoding;
+
+ iface->set_newline_type = chooser_set_newline_type;
+ iface->get_newline_type = chooser_get_newline_type;
+
+ iface->set_current_folder = chooser_set_current_folder;
+ iface->set_current_name = chooser_set_current_name;
+ iface->set_file = chooser_set_file;
+ iface->get_file = chooser_get_file;
+ iface->set_do_overwrite_confirmation = chooser_set_do_overwrite_confirmation;
+ iface->show = chooser_show;
++ iface->hide = chooser_hide;
+ iface->destroy = chooser_destroy;
+ iface->set_modal = chooser_set_modal;
+ iface->get_window = chooser_get_window;
++ iface->add_pattern_filter = chooser_add_pattern_filter;
+ }
+
+ static void
+ gedit_file_chooser_dialog_gtk_dispose (GObject *object)
+ {
+ GeditFileChooserDialogGtk *dialog = GEDIT_FILE_CHOOSER_DIALOG_GTK (object);
+
+ g_clear_object (&dialog->gedit_file_chooser);
+
+ G_OBJECT_CLASS (gedit_file_chooser_dialog_gtk_parent_class)->dispose (object);
+ }
+
+ static void
+ gedit_file_chooser_dialog_gtk_class_init (GeditFileChooserDialogGtkClass *klass)
+ {
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gedit_file_chooser_dialog_gtk_dispose;
+ }
+
+ static void
+-create_option_menu (GeditFileChooserDialogGtk *dialog)
++create_option_menu (GeditFileChooserDialogGtk *dialog,
++ GeditFileChooserFlags flags)
+ {
+ GtkWidget *label;
+ GtkWidget *menu;
+ gboolean save_mode;
+
+ label = gtk_label_new_with_mnemonic (_("C_haracter Encoding:"));
+ gtk_widget_set_halign (label, GTK_ALIGN_START);
+
+- save_mode = TRUE;
++ save_mode = (flags & GEDIT_FILE_CHOOSER_FLAG_SAVE) != 0;
+ menu = gedit_encodings_combo_box_new (save_mode);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), menu);
+
+ gtk_box_pack_start (GTK_BOX (dialog->extra_widget),
+ label,
+ FALSE,
+ TRUE,
+ 0);
+
+ gtk_box_pack_start (GTK_BOX (dialog->extra_widget),
+ menu,
+ TRUE,
+ TRUE,
+ 0);
+
+ gtk_widget_show (label);
+ gtk_widget_show (menu);
+
+ dialog->option_menu = menu;
+ }
+
+ static void
+ update_newline_visibility (GeditFileChooserDialogGtk *dialog)
+ {
+ gboolean visible = gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog)) == GTK_FILE_CHOOSER_ACTION_SAVE;
+
+ gtk_widget_set_visible (dialog->newline_label, visible);
+ gtk_widget_set_visible (dialog->newline_combo, visible);
+ }
+@@ -347,119 +376,138 @@ create_newline_combo (GeditFileChooserDialogGtk *dialog)
+ GTK_SOURCE_NEWLINE_TYPE_CR);
+
+ newline_combo_append (GTK_COMBO_BOX (combo),
+ store,
+ &iter,
+ gedit_utils_newline_type_to_string (GTK_SOURCE_NEWLINE_TYPE_CR_LF),
+ GTK_SOURCE_NEWLINE_TYPE_CR_LF);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
+
+ gtk_box_pack_start (GTK_BOX (dialog->extra_widget),
+ label,
+ FALSE,
+ TRUE,
+ 0);
+
+ gtk_box_pack_start (GTK_BOX (dialog->extra_widget),
+ combo,
+ TRUE,
+ TRUE,
+ 0);
+
+ dialog->newline_combo = combo;
+ dialog->newline_label = label;
+ dialog->newline_store = store;
+
+ update_newline_visibility (dialog);
+ }
+
+ static void
+-create_extra_widget (GeditFileChooserDialogGtk *dialog)
++create_extra_widget (GeditFileChooserDialogGtk *dialog,
++ GeditFileChooserFlags flags)
+ {
+ dialog->extra_widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_widget_show (dialog->extra_widget);
+
+- create_option_menu (dialog);
+- create_newline_combo (dialog);
++ create_option_menu (dialog, flags);
++
++ if ((flags & GEDIT_FILE_CHOOSER_FLAG_SAVE) != 0)
++ {
++ create_newline_combo (dialog);
++ }
+
+ gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), dialog->extra_widget);
+ }
+
+ static void
+ action_changed (GeditFileChooserDialogGtk *dialog,
+ GParamSpec *pspec,
+ gpointer data)
+ {
+ GtkFileChooserAction action;
+
+ action = gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog));
+
+ switch (action)
+ {
+ case GTK_FILE_CHOOSER_ACTION_OPEN:
+ g_object_set (dialog->option_menu,
+ "save_mode", FALSE,
+ NULL);
+ gtk_widget_show (dialog->option_menu);
+ break;
+ case GTK_FILE_CHOOSER_ACTION_SAVE:
+ g_object_set (dialog->option_menu,
+ "save_mode", TRUE,
+ NULL);
+ gtk_widget_show (dialog->option_menu);
+ break;
+ default:
+ gtk_widget_hide (dialog->option_menu);
+ }
+
+ update_newline_visibility (dialog);
+ }
+
+ static void
+ gedit_file_chooser_dialog_gtk_init (GeditFileChooserDialogGtk *dialog)
+ {
+ }
+
+ GeditFileChooserDialog *
+-gedit_file_chooser_dialog_gtk_create (const gchar *title,
+- GtkWindow *parent,
+- const gchar *accept_label,
+- const gchar *cancel_label)
++gedit_file_chooser_dialog_gtk_create (const gchar *title,
++ GtkWindow *parent,
++ GeditFileChooserFlags flags,
++ const gchar *accept_label,
++ const gchar *cancel_label)
+ {
+ GeditFileChooserDialogGtk *result;
++ GtkFileChooserAction action;
++ gboolean select_multiple;
++
++ if ((flags & GEDIT_FILE_CHOOSER_FLAG_SAVE) != 0)
++ {
++ action = GTK_FILE_CHOOSER_ACTION_SAVE;
++ select_multiple = FALSE;
++ }
++ else
++ {
++ action = GTK_FILE_CHOOSER_ACTION_OPEN;
++ select_multiple = TRUE;
++ }
+
+ result = g_object_new (GEDIT_TYPE_FILE_CHOOSER_DIALOG_GTK,
+ "title", title,
+ "local-only", FALSE,
+- "action", GTK_FILE_CHOOSER_ACTION_SAVE,
+- "select-multiple", FALSE,
++ "action", action,
++ "select-multiple", select_multiple,
+ NULL);
+
+- create_extra_widget (result);
++ create_extra_widget (result, flags);
+
+ g_signal_connect (result,
+ "notify::action",
+ G_CALLBACK (action_changed),
+ NULL);
+
+ /* FIXME: attention, there is a ref cycle here. This will be fixed when
+ * GeditFileChooserSave will be created (and this class removed).
+ */
+ result->gedit_file_chooser = _gedit_file_chooser_new ();
+ _gedit_file_chooser_set_gtk_file_chooser (result->gedit_file_chooser,
+ GTK_FILE_CHOOSER (result));
+
+ if (parent != NULL)
+ {
+ gtk_window_set_transient_for (GTK_WINDOW (result), parent);
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (result), TRUE);
+ }
+
+ gtk_dialog_add_button (GTK_DIALOG (result), cancel_label, GTK_RESPONSE_CANCEL);
+ gtk_dialog_add_button (GTK_DIALOG (result), accept_label, GTK_RESPONSE_ACCEPT);
+ gtk_dialog_set_default_response (GTK_DIALOG (result), GTK_RESPONSE_ACCEPT);
+
+ return GEDIT_FILE_CHOOSER_DIALOG (result);
+ }
+
+ /* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-file-chooser-dialog-gtk.h b/gedit/gedit-file-chooser-dialog-gtk.h
+index 0bf6a0d41..40726af54 100644
+--- a/gedit/gedit-file-chooser-dialog-gtk.h
++++ b/gedit/gedit-file-chooser-dialog-gtk.h
+@@ -6,40 +6,41 @@
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #ifndef GEDIT_FILE_CHOOSER_DIALOG_GTK_H
+ #define GEDIT_FILE_CHOOSER_DIALOG_GTK_H
+
+ #include
+ #include "gedit-file-chooser-dialog.h"
+
+ G_BEGIN_DECLS
+
+ #define GEDIT_TYPE_FILE_CHOOSER_DIALOG_GTK (gedit_file_chooser_dialog_gtk_get_type ())
+
+ G_DECLARE_FINAL_TYPE (GeditFileChooserDialogGtk, gedit_file_chooser_dialog_gtk,
+ GEDIT, FILE_CHOOSER_DIALOG_GTK,
+ GtkFileChooserDialog)
+
+-GeditFileChooserDialog * gedit_file_chooser_dialog_gtk_create (const gchar *title,
+- GtkWindow *parent,
+- const gchar *accept_label,
+- const gchar *cancel_label);
++GeditFileChooserDialog * gedit_file_chooser_dialog_gtk_create (const gchar *title,
++ GtkWindow *parent,
++ GeditFileChooserFlags flags,
++ const gchar *accept_label,
++ const gchar *cancel_label);
+
+ G_END_DECLS
+
+ #endif /* GEDIT_FILE_CHOOSER_DIALOG_GTK_H */
+
+ /* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-file-chooser-dialog.c b/gedit/gedit-file-chooser-dialog.c
+index 56edbae3b..b4ce2fd9e 100644
+--- a/gedit/gedit-file-chooser-dialog.c
++++ b/gedit/gedit-file-chooser-dialog.c
+@@ -35,67 +35,69 @@ confirm_overwrite_accumulator (GSignalInvocationHint *ihint,
+
+ conf = g_value_get_enum (handler_return);
+ g_value_set_enum (return_accu, conf);
+ continue_emission = (conf == GTK_FILE_CHOOSER_CONFIRMATION_CONFIRM);
+
+ return continue_emission;
+ }
+
+ static void
+ gedit_file_chooser_dialog_default_init (GeditFileChooserDialogInterface *iface)
+ {
+ g_signal_new ("response",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL, NULL,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_INT);
+
+ g_signal_new ("confirm-overwrite",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ confirm_overwrite_accumulator, NULL, NULL,
+ GTK_TYPE_FILE_CHOOSER_CONFIRMATION,
+ 0);
+ }
+
+ GeditFileChooserDialog *
+-gedit_file_chooser_dialog_create (const gchar *title,
+- GtkWindow *parent,
+- const gchar *accept_label,
+- const gchar *cancel_label)
++gedit_file_chooser_dialog_create (const gchar *title,
++ GtkWindow *parent,
++ GeditFileChooserFlags flags,
++ const gchar *accept_label,
++ const gchar *cancel_label)
+ {
+ return gedit_file_chooser_dialog_gtk_create (title,
+ parent,
++ flags,
+ accept_label,
+ cancel_label);
+ }
+
+ void
+ gedit_file_chooser_dialog_set_encoding (GeditFileChooserDialog *dialog,
+ const GtkSourceEncoding *encoding)
+ {
+ GeditFileChooserDialogInterface *iface;
+
+ g_return_if_fail (GEDIT_IS_FILE_CHOOSER_DIALOG (dialog));
+
+ iface = GEDIT_FILE_CHOOSER_DIALOG_GET_IFACE (dialog);
+ g_return_if_fail (iface->set_encoding != NULL);
+
+ iface->set_encoding (dialog, encoding);
+ }
+
+ const GtkSourceEncoding *
+ gedit_file_chooser_dialog_get_encoding (GeditFileChooserDialog *dialog)
+ {
+ GeditFileChooserDialogInterface *iface;
+
+ g_return_val_if_fail (GEDIT_IS_FILE_CHOOSER_DIALOG (dialog), NULL);
+
+ iface = GEDIT_FILE_CHOOSER_DIALOG_GET_IFACE (dialog);
+ g_return_val_if_fail (iface->get_encoding != NULL, NULL);
+
+ return iface->get_encoding (dialog);
+ }
+@@ -184,75 +186,105 @@ gedit_file_chooser_dialog_get_file (GeditFileChooserDialog *dialog)
+ return iface->get_file (dialog);
+ }
+
+ void
+ gedit_file_chooser_dialog_set_do_overwrite_confirmation (GeditFileChooserDialog *dialog,
+ gboolean overwrite_confirmation)
+ {
+ GeditFileChooserDialogInterface *iface;
+
+ g_return_if_fail (GEDIT_IS_FILE_CHOOSER_DIALOG (dialog));
+
+ iface = GEDIT_FILE_CHOOSER_DIALOG_GET_IFACE (dialog);
+ g_return_if_fail (iface->set_do_overwrite_confirmation != NULL);
+
+ iface->set_do_overwrite_confirmation (dialog, overwrite_confirmation);
+ }
+
+ void
+ gedit_file_chooser_dialog_show (GeditFileChooserDialog *dialog)
+ {
+ GeditFileChooserDialogInterface *iface;
+
+ g_return_if_fail (GEDIT_IS_FILE_CHOOSER_DIALOG (dialog));
+
+ iface = GEDIT_FILE_CHOOSER_DIALOG_GET_IFACE (dialog);
+ g_return_if_fail (iface->show != NULL);
+
+ iface->show (dialog);
+ }
+
++void
++gedit_file_chooser_dialog_hide (GeditFileChooserDialog *dialog)
++{
++ GeditFileChooserDialogInterface *iface;
++
++ g_return_if_fail (GEDIT_IS_FILE_CHOOSER_DIALOG (dialog));
++
++ iface = GEDIT_FILE_CHOOSER_DIALOG_GET_IFACE (dialog);
++ g_return_if_fail (iface->hide != NULL);
++
++ iface->hide (dialog);
++}
++
+ void
+ gedit_file_chooser_dialog_destroy (GeditFileChooserDialog *dialog)
+ {
+ GeditFileChooserDialogInterface *iface;
+
+ g_return_if_fail (GEDIT_IS_FILE_CHOOSER_DIALOG (dialog));
+
+ iface = GEDIT_FILE_CHOOSER_DIALOG_GET_IFACE (dialog);
+ g_return_if_fail (iface->destroy != NULL);
+
+ iface->destroy (dialog);
+ }
+
+ void
+ gedit_file_chooser_dialog_set_modal (GeditFileChooserDialog *dialog,
+ gboolean is_modal)
+ {
+ GeditFileChooserDialogInterface *iface;
+
+ g_return_if_fail (GEDIT_IS_FILE_CHOOSER_DIALOG (dialog));
+
+ iface = GEDIT_FILE_CHOOSER_DIALOG_GET_IFACE (dialog);
+ g_return_if_fail (iface->set_modal != NULL);
+
+ iface->set_modal (dialog, is_modal);
+ }
+
+ GtkWindow *
+ gedit_file_chooser_dialog_get_window (GeditFileChooserDialog *dialog)
+ {
+ GeditFileChooserDialogInterface *iface;
+
+ g_return_val_if_fail (GEDIT_IS_FILE_CHOOSER_DIALOG (dialog), NULL);
+
+ iface = GEDIT_FILE_CHOOSER_DIALOG_GET_IFACE (dialog);
+
+ if (iface->get_window)
+ {
+ return iface->get_window (dialog);
+ }
+
+ return NULL;
+ }
+
++void
++gedit_file_chooser_dialog_add_pattern_filter (GeditFileChooserDialog *dialog,
++ const gchar *name,
++ const gchar *pattern)
++{
++ GeditFileChooserDialogInterface *iface;
++
++ g_return_if_fail (GEDIT_IS_FILE_CHOOSER_DIALOG (dialog));
++
++ iface = GEDIT_FILE_CHOOSER_DIALOG_GET_IFACE (dialog);
++
++ if (iface->add_pattern_filter)
++ {
++ iface->add_pattern_filter (dialog, name, pattern);
++ }
++}
++
+ /* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-file-chooser-dialog.h b/gedit/gedit-file-chooser-dialog.h
+index b759c6566..633950e05 100644
+--- a/gedit/gedit-file-chooser-dialog.h
++++ b/gedit/gedit-file-chooser-dialog.h
+@@ -37,87 +37,104 @@ struct _GeditFileChooserDialogInterface
+
+ /* Virtual public methods */
+ void (*set_encoding) (GeditFileChooserDialog *dialog,
+ const GtkSourceEncoding *encoding);
+
+ const GtkSourceEncoding *
+ (*get_encoding) (GeditFileChooserDialog *dialog);
+
+ void (*set_newline_type) (GeditFileChooserDialog *dialog,
+ GtkSourceNewlineType newline_type);
+
+ GtkSourceNewlineType
+ (*get_newline_type) (GeditFileChooserDialog *dialog);
+
+ void (*set_current_folder) (GeditFileChooserDialog *dialog,
+ GFile *folder);
+
+ void (*set_current_name) (GeditFileChooserDialog *dialog,
+ const gchar *name);
+
+ void (*set_file) (GeditFileChooserDialog *dialog,
+ GFile *file);
+
+ GFile * (*get_file) (GeditFileChooserDialog *dialog);
+
+ void (*set_do_overwrite_confirmation)
+ (GeditFileChooserDialog *dialog,
+ gboolean overwrite_confirmation);
+
+ void (*show) (GeditFileChooserDialog *dialog);
++ void (*hide) (GeditFileChooserDialog *dialog);
+
+ void (*destroy) (GeditFileChooserDialog *dialog);
+
+ void (*set_modal) (GeditFileChooserDialog *dialog,
+ gboolean is_modal);
+
+ GtkWindow *
+ (*get_window) (GeditFileChooserDialog *dialog);
++
++ void (*add_pattern_filter) (GeditFileChooserDialog *dilaog,
++ const gchar *name,
++ const gchar *pattern);
+ };
+
++typedef enum
++{
++ GEDIT_FILE_CHOOSER_FLAG_SAVE = 1 << 0,
++ GEDIT_FILE_CHOOSER_FLAG_OPEN = 1 << 1
++} GeditFileChooserFlags;
++
+ GeditFileChooserDialog *
+ gedit_file_chooser_dialog_create (const gchar *title,
+ GtkWindow *parent,
++ GeditFileChooserFlags flags,
+ const gchar *accept_label,
+ const gchar *cancel_label);
+
+ void gedit_file_chooser_dialog_destroy (GeditFileChooserDialog *dialog);
+
+ void gedit_file_chooser_dialog_set_encoding (GeditFileChooserDialog *dialog,
+ const GtkSourceEncoding *encoding);
+
+ const GtkSourceEncoding *
+ gedit_file_chooser_dialog_get_encoding (GeditFileChooserDialog *dialog);
+
+ void gedit_file_chooser_dialog_set_newline_type (GeditFileChooserDialog *dialog,
+ GtkSourceNewlineType newline_type);
+
+ GtkSourceNewlineType
+ gedit_file_chooser_dialog_get_newline_type (GeditFileChooserDialog *dialog);
+
+ void gedit_file_chooser_dialog_set_current_folder (GeditFileChooserDialog *dialog,
+ GFile *folder);
+
+ void gedit_file_chooser_dialog_set_current_name (GeditFileChooserDialog *dialog,
+ const gchar *name);
+
+ void gedit_file_chooser_dialog_set_file (GeditFileChooserDialog *dialog,
+ GFile *file);
+
+ GFile *gedit_file_chooser_dialog_get_file (GeditFileChooserDialog *dialog);
+
+ void gedit_file_chooser_dialog_set_do_overwrite_confirmation (
+ GeditFileChooserDialog *dialog,
+ gboolean overwrite_confirmation);
+
+ void gedit_file_chooser_dialog_show (GeditFileChooserDialog *dialog);
++void gedit_file_chooser_dialog_hide (GeditFileChooserDialog *dialog);
+
+ void gedit_file_chooser_dialog_set_modal (GeditFileChooserDialog *dialog,
+ gboolean is_modal);
+
+ GtkWindow *gedit_file_chooser_dialog_get_window (GeditFileChooserDialog *dialog);
+
++void gedit_file_chooser_dialog_add_pattern_filter (GeditFileChooserDialog *dialog,
++ const gchar *name,
++ const gchar *pattern);
++
+ G_END_DECLS
+
+ #endif /* GEDIT_FILE_CHOOSER_DIALOG_H */
+
+ /* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-highlight-mode-dialog.c b/gedit/gedit-highlight-mode-dialog.c
+new file mode 100644
+index 000000000..a0661bfc3
+--- /dev/null
++++ b/gedit/gedit-highlight-mode-dialog.c
+@@ -0,0 +1,102 @@
++/*
++ * gedit-highlight-mode-dialog.c
++ * This file is part of gedit
++ *
++ * Copyright (C) 2013 - Ignacio Casal Quinteiro
++ *
++ * gedit 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.
++ *
++ * gedit 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
++ * along with gedit. If not, see .
++ */
++
++#include "gedit-highlight-mode-dialog.h"
++
++struct _GeditHighlightModeDialog
++{
++ GtkDialog parent_instance;
++
++ GeditHighlightModeSelector *selector;
++ gulong on_language_selected_id;
++};
++
++G_DEFINE_TYPE (GeditHighlightModeDialog, gedit_highlight_mode_dialog, GTK_TYPE_DIALOG)
++
++static void
++gedit_highlight_mode_dialog_response (GtkDialog *dialog,
++ gint response_id)
++{
++ GeditHighlightModeDialog *dlg = GEDIT_HIGHLIGHT_MODE_DIALOG (dialog);
++
++ if (response_id == GTK_RESPONSE_OK)
++ {
++ g_signal_handler_block (dlg->selector, dlg->on_language_selected_id);
++ gedit_highlight_mode_selector_activate_selected_language (dlg->selector);
++ g_signal_handler_unblock (dlg->selector, dlg->on_language_selected_id);
++ }
++
++ gtk_widget_destroy (GTK_WIDGET (dialog));
++}
++
++static void
++on_language_selected (GeditHighlightModeSelector *sel,
++ GtkSourceLanguage *language,
++ GeditHighlightModeDialog *dlg)
++{
++ g_signal_handler_block (dlg->selector, dlg->on_language_selected_id);
++ gedit_highlight_mode_selector_activate_selected_language (dlg->selector);
++ g_signal_handler_unblock (dlg->selector, dlg->on_language_selected_id);
++
++ gtk_widget_destroy (GTK_WIDGET (dlg));
++}
++
++static void
++gedit_highlight_mode_dialog_class_init (GeditHighlightModeDialogClass *klass)
++{
++ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
++ GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass);
++
++ dialog_class->response = gedit_highlight_mode_dialog_response;
++
++ /* Bind class to template */
++ gtk_widget_class_set_template_from_resource (widget_class,
++ "/org/gnome/gedit/ui/gedit-highlight-mode-dialog.ui");
++ gtk_widget_class_bind_template_child (widget_class, GeditHighlightModeDialog, selector);
++}
++
++static void
++gedit_highlight_mode_dialog_init (GeditHighlightModeDialog *dlg)
++{
++ gtk_widget_init_template (GTK_WIDGET (dlg));
++ gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK);
++
++ dlg->on_language_selected_id = g_signal_connect (dlg->selector, "language-selected",
++ G_CALLBACK (on_language_selected), dlg);
++}
++
++GtkWidget *
++gedit_highlight_mode_dialog_new (GtkWindow *parent)
++{
++ return GTK_WIDGET (g_object_new (GEDIT_TYPE_HIGHLIGHT_MODE_DIALOG,
++ "transient-for", parent,
++ "use-header-bar", TRUE,
++ NULL));
++}
++
++GeditHighlightModeSelector *
++gedit_highlight_mode_dialog_get_selector (GeditHighlightModeDialog *dlg)
++{
++ g_return_val_if_fail (GEDIT_IS_HIGHLIGHT_MODE_DIALOG (dlg), NULL);
++
++ return dlg->selector;
++}
++
++/* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-highlight-mode-dialog.h b/gedit/gedit-highlight-mode-dialog.h
+new file mode 100644
+index 000000000..57d406bb3
+--- /dev/null
++++ b/gedit/gedit-highlight-mode-dialog.h
+@@ -0,0 +1,41 @@
++/*
++ * gedit-highlight-mode-dialog.h
++ * This file is part of gedit
++ *
++ * Copyright (C) 2013 - Ignacio Casal Quinteiro
++ *
++ * gedit 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.
++ *
++ * gedit 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
++ * along with gedit. If not, see .
++ */
++
++
++#ifndef GEDIT_HIGHLIGHT_MODE_DIALOG_H
++#define GEDIT_HIGHLIGHT_MODE_DIALOG_H
++
++#include "gedit-highlight-mode-selector.h"
++
++G_BEGIN_DECLS
++
++#define GEDIT_TYPE_HIGHLIGHT_MODE_DIALOG (gedit_highlight_mode_dialog_get_type ())
++
++G_DECLARE_FINAL_TYPE (GeditHighlightModeDialog, gedit_highlight_mode_dialog, GEDIT, HIGHLIGHT_MODE_DIALOG, GtkDialog)
++
++GtkWidget *gedit_highlight_mode_dialog_new (GtkWindow *parent);
++
++GeditHighlightModeSelector *gedit_highlight_mode_dialog_get_selector (GeditHighlightModeDialog *dlg);
++
++G_END_DECLS
++
++#endif /* GEDIT_HIGHLIGHT_MODE_DIALOG_H */
++
++/* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-highlight-mode-selector.c b/gedit/gedit-highlight-mode-selector.c
+new file mode 100644
+index 000000000..cb6bd466f
+--- /dev/null
++++ b/gedit/gedit-highlight-mode-selector.c
+@@ -0,0 +1,375 @@
++/*
++ * gedit-highlight-mode-selector.c
++ * This file is part of gedit
++ *
++ * Copyright (C) 2013 - Ignacio Casal Quinteiro
++ *
++ * gedit 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.
++ *
++ * gedit 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
++ * along with gedit. If not, see .
++ */
++
++#include "gedit-highlight-mode-selector.h"
++#include
++
++enum
++{
++ COLUMN_NAME,
++ COLUMN_LANG,
++ N_COLUMNS
++};
++
++struct _GeditHighlightModeSelector
++{
++ GtkGrid parent_instance;
++
++ GtkWidget *treeview;
++ GtkWidget *entry;
++ GtkListStore *liststore;
++ GtkTreeModelFilter *treemodelfilter;
++ GtkTreeSelection *treeview_selection;
++};
++
++/* Signals */
++enum
++{
++ LANGUAGE_SELECTED,
++ LAST_SIGNAL
++};
++
++static guint signals[LAST_SIGNAL] = { 0 };
++
++G_DEFINE_TYPE (GeditHighlightModeSelector, gedit_highlight_mode_selector, GTK_TYPE_GRID)
++
++static void
++gedit_highlight_mode_selector_language_selected (GeditHighlightModeSelector *widget,
++ GtkSourceLanguage *language)
++{
++}
++
++static void
++gedit_highlight_mode_selector_class_init (GeditHighlightModeSelectorClass *klass)
++{
++ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
++
++ signals[LANGUAGE_SELECTED] =
++ g_signal_new_class_handler ("language-selected",
++ G_TYPE_FROM_CLASS (klass),
++ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
++ G_CALLBACK (gedit_highlight_mode_selector_language_selected),
++ NULL, NULL, NULL,
++ G_TYPE_NONE,
++ 1,
++ GTK_SOURCE_TYPE_LANGUAGE);
++
++ /* Bind class to template */
++ gtk_widget_class_set_template_from_resource (widget_class,
++ "/org/gnome/gedit/ui/gedit-highlight-mode-selector.ui");
++ gtk_widget_class_bind_template_child (widget_class, GeditHighlightModeSelector, treeview);
++ gtk_widget_class_bind_template_child (widget_class, GeditHighlightModeSelector, entry);
++ gtk_widget_class_bind_template_child (widget_class, GeditHighlightModeSelector, liststore);
++ gtk_widget_class_bind_template_child (widget_class, GeditHighlightModeSelector, treemodelfilter);
++ gtk_widget_class_bind_template_child (widget_class, GeditHighlightModeSelector, treeview_selection);
++}
++
++static gboolean
++visible_func (GtkTreeModel *model,
++ GtkTreeIter *iter,
++ GeditHighlightModeSelector *selector)
++{
++ const gchar *entry_text;
++ gchar *name;
++ gchar *name_normalized;
++ gchar *name_casefolded;
++ gchar *text_normalized;
++ gchar *text_casefolded;
++ gboolean visible = FALSE;
++
++ entry_text = gtk_entry_get_text (GTK_ENTRY (selector->entry));
++
++ if (*entry_text == '\0')
++ {
++ return TRUE;
++ }
++
++ gtk_tree_model_get (model, iter, COLUMN_NAME, &name, -1);
++
++ name_normalized = g_utf8_normalize (name, -1, G_NORMALIZE_ALL);
++ g_free (name);
++
++ name_casefolded = g_utf8_casefold (name_normalized, -1);
++ g_free (name_normalized);
++
++ text_normalized = g_utf8_normalize (entry_text, -1, G_NORMALIZE_ALL);
++ text_casefolded = g_utf8_casefold (text_normalized, -1);
++ g_free (text_normalized);
++
++ if (strstr (name_casefolded, text_casefolded) != NULL)
++ {
++ visible = TRUE;
++ }
++
++ g_free (name_casefolded);
++ g_free (text_casefolded);
++
++ return visible;
++}
++
++static void
++on_entry_activate (GtkEntry *entry,
++ GeditHighlightModeSelector *selector)
++{
++ gedit_highlight_mode_selector_activate_selected_language (selector);
++}
++
++static void
++on_entry_changed (GtkEntry *entry,
++ GeditHighlightModeSelector *selector)
++{
++ GtkTreeIter iter;
++
++ gtk_tree_model_filter_refilter (selector->treemodelfilter);
++
++ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (selector->treemodelfilter), &iter))
++ {
++ gtk_tree_selection_select_iter (selector->treeview_selection, &iter);
++ }
++}
++
++static gboolean
++move_selection (GeditHighlightModeSelector *selector,
++ gint howmany)
++{
++ GtkTreeIter iter;
++ GtkTreePath *path;
++ gint *indices;
++ gint ret = FALSE;
++
++ if (!gtk_tree_selection_get_selected (selector->treeview_selection, NULL, &iter) &&
++ !gtk_tree_model_get_iter_first (GTK_TREE_MODEL (selector->treemodelfilter), &iter))
++ {
++ return FALSE;
++ }
++
++ path = gtk_tree_model_get_path (GTK_TREE_MODEL (selector->treemodelfilter), &iter);
++ indices = gtk_tree_path_get_indices (path);
++
++ if (indices)
++ {
++ gint num;
++ gint idx;
++ GtkTreePath *new_path;
++
++ idx = indices[0];
++ num = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (selector->treemodelfilter), NULL);
++
++ if ((idx + howmany) < 0)
++ {
++ idx = 0;
++ }
++ else if ((idx + howmany) >= num)
++ {
++ idx = num - 1;
++ }
++ else
++ {
++ idx = idx + howmany;
++ }
++
++ new_path = gtk_tree_path_new_from_indices (idx, -1);
++ gtk_tree_selection_select_path (selector->treeview_selection, new_path);
++ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (selector->treeview),
++ new_path, NULL, TRUE, 0.5, 0);
++ gtk_tree_path_free (new_path);
++
++ ret = TRUE;
++ }
++
++ gtk_tree_path_free (path);
++
++ return ret;
++}
++
++static gboolean
++on_entry_key_press_event (GtkWidget *entry,
++ GdkEventKey *event,
++ GeditHighlightModeSelector *selector)
++{
++ if (event->keyval == GDK_KEY_Down)
++ {
++ return move_selection (selector, 1);
++ }
++ else if (event->keyval == GDK_KEY_Up)
++ {
++ return move_selection (selector, -1);
++ }
++ else if (event->keyval == GDK_KEY_Page_Down)
++ {
++ return move_selection (selector, 5);
++ }
++ else if (event->keyval == GDK_KEY_Page_Up)
++ {
++ return move_selection (selector, -5);
++ }
++
++ return FALSE;
++}
++
++static void
++on_row_activated (GtkTreeView *tree_view,
++ GtkTreePath *path,
++ GtkTreeViewColumn *column,
++ GeditHighlightModeSelector *selector)
++{
++ gedit_highlight_mode_selector_activate_selected_language (selector);
++}
++
++static void
++gedit_highlight_mode_selector_init (GeditHighlightModeSelector *selector)
++{
++ GtkSourceLanguageManager *lm;
++ const gchar * const *ids;
++ gint i;
++ GtkTreeIter iter;
++
++ selector = gedit_highlight_mode_selector_get_instance_private (selector);
++
++ gtk_widget_init_template (GTK_WIDGET (selector));
++
++ gtk_tree_model_filter_set_visible_func (selector->treemodelfilter,
++ (GtkTreeModelFilterVisibleFunc)visible_func,
++ selector,
++ NULL);
++
++ g_signal_connect (selector->entry, "activate",
++ G_CALLBACK (on_entry_activate), selector);
++ g_signal_connect (selector->entry, "changed",
++ G_CALLBACK (on_entry_changed), selector);
++ g_signal_connect (selector->entry, "key-press-event",
++ G_CALLBACK (on_entry_key_press_event), selector);
++
++ g_signal_connect (selector->treeview, "row-activated",
++ G_CALLBACK (on_row_activated), selector);
++
++ /* Populate tree model */
++ gtk_list_store_append (selector->liststore, &iter);
++ gtk_list_store_set (selector->liststore, &iter,
++ COLUMN_NAME, _("Plain Text"),
++ COLUMN_LANG, NULL,
++ -1);
++
++ lm = gtk_source_language_manager_get_default ();
++ ids = gtk_source_language_manager_get_language_ids (lm);
++
++ for (i = 0; ids[i] != NULL; i++)
++ {
++ GtkSourceLanguage *lang;
++
++ lang = gtk_source_language_manager_get_language (lm, ids[i]);
++
++ if (!gtk_source_language_get_hidden (lang))
++ {
++ gtk_list_store_append (selector->liststore, &iter);
++ gtk_list_store_set (selector->liststore, &iter,
++ COLUMN_NAME, gtk_source_language_get_name (lang),
++ COLUMN_LANG, lang,
++ -1);
++ }
++ }
++
++ /* select first item */
++ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (selector->treemodelfilter), &iter))
++ {
++ gtk_tree_selection_select_iter (selector->treeview_selection, &iter);
++ }
++}
++
++GeditHighlightModeSelector *
++gedit_highlight_mode_selector_new ()
++{
++ return g_object_new (GEDIT_TYPE_HIGHLIGHT_MODE_SELECTOR, NULL);
++}
++
++void
++gedit_highlight_mode_selector_select_language (GeditHighlightModeSelector *selector,
++ GtkSourceLanguage *language)
++{
++ GtkTreeIter iter;
++
++ g_return_if_fail (GEDIT_IS_HIGHLIGHT_MODE_SELECTOR (selector));
++
++ if (language == NULL)
++ {
++ return;
++ }
++
++ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (selector->treemodelfilter), &iter))
++ {
++ do
++ {
++ GtkSourceLanguage *lang;
++
++ gtk_tree_model_get (GTK_TREE_MODEL (selector->treemodelfilter),
++ &iter,
++ COLUMN_LANG, &lang,
++ -1);
++
++ if (lang != NULL)
++ {
++ gboolean equal = (lang == language);
++
++ g_object_unref (lang);
++
++ if (equal)
++ {
++ GtkTreePath *path;
++
++ path = gtk_tree_model_get_path (GTK_TREE_MODEL (selector->treemodelfilter), &iter);
++
++ gtk_tree_selection_select_iter (selector->treeview_selection, &iter);
++ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (selector->treeview),
++ path, NULL, TRUE, 0.5, 0);
++ gtk_tree_path_free (path);
++ break;
++ }
++ }
++ }
++ while (gtk_tree_model_iter_next (GTK_TREE_MODEL (selector->treemodelfilter), &iter));
++ }
++}
++
++void
++gedit_highlight_mode_selector_activate_selected_language (GeditHighlightModeSelector *selector)
++{
++ GtkSourceLanguage *lang;
++ GtkTreeIter iter;
++
++ g_return_if_fail (GEDIT_IS_HIGHLIGHT_MODE_SELECTOR (selector));
++
++ if (!gtk_tree_selection_get_selected (selector->treeview_selection, NULL, &iter))
++ {
++ return;
++ }
++
++ gtk_tree_model_get (GTK_TREE_MODEL (selector->treemodelfilter), &iter,
++ COLUMN_LANG, &lang,
++ -1);
++
++ g_signal_emit (G_OBJECT (selector), signals[LANGUAGE_SELECTED], 0, lang);
++
++ if (lang != NULL)
++ {
++ g_object_unref (lang);
++ }
++}
++
++/* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-highlight-mode-selector.h b/gedit/gedit-highlight-mode-selector.h
+new file mode 100644
+index 000000000..dc19e3cc4
+--- /dev/null
++++ b/gedit/gedit-highlight-mode-selector.h
+@@ -0,0 +1,44 @@
++/*
++ * gedit-highlight-mode-selector.h
++ * This file is part of gedit
++ *
++ * Copyright (C) 2013 - Ignacio Casal Quinteiro
++ *
++ * gedit 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.
++ *
++ * gedit 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
++ * along with gedit. If not, see .
++ */
++
++#ifndef GEDIT_HIGHLIGHT_MODE_SELECTOR_H
++#define GEDIT_HIGHLIGHT_MODE_SELECTOR_H
++
++#include
++
++G_BEGIN_DECLS
++
++#define GEDIT_TYPE_HIGHLIGHT_MODE_SELECTOR (gedit_highlight_mode_selector_get_type ())
++
++G_DECLARE_FINAL_TYPE (GeditHighlightModeSelector, gedit_highlight_mode_selector, GEDIT, HIGHLIGHT_MODE_SELECTOR, GtkGrid)
++
++GeditHighlightModeSelector *gedit_highlight_mode_selector_new (void);
++
++void gedit_highlight_mode_selector_select_language (GeditHighlightModeSelector *selector,
++ GtkSourceLanguage *language);
++
++void gedit_highlight_mode_selector_activate_selected_language
++ (GeditHighlightModeSelector *selector);
++
++G_END_DECLS
++
++#endif /* GEDIT_HIGHLIGHT_MODE_SELECTOR_H */
++
++/* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-io-error-info-bar.c b/gedit/gedit-io-error-info-bar.c
+index 1edbe313a..1539e3b7b 100644
+--- a/gedit/gedit-io-error-info-bar.c
++++ b/gedit/gedit-io-error-info-bar.c
+@@ -1,58 +1,65 @@
+ /*
+ * gedit-io-error-info-bar.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2005 - Paolo Maggi
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ /*
+ * Verbose error reporting for file I/O operations (load, save, revert, create)
+ */
+
+ #include "gedit-io-error-info-bar.h"
++
++#include
++#include
+ #include
+-#include
++#include
++
+ #include "gedit-encodings-combo-box.h"
++#include "gedit-settings.h"
++#include "gedit-utils.h"
++#include "gedit-document.h"
+
+ #define MAX_URI_IN_DIALOG_LENGTH 50
+
+ static gboolean
+ is_recoverable_error (const GError *error)
+ {
+ gboolean is_recoverable = FALSE;
+
+ if (error->domain == G_IO_ERROR)
+ {
+ switch (error->code)
+ {
+ case G_IO_ERROR_PERMISSION_DENIED:
+ case G_IO_ERROR_NOT_FOUND:
+ case G_IO_ERROR_HOST_NOT_FOUND:
+ case G_IO_ERROR_TIMED_OUT:
+ case G_IO_ERROR_NOT_MOUNTABLE_FILE:
+ case G_IO_ERROR_NOT_MOUNTED:
+ case G_IO_ERROR_BUSY:
+ is_recoverable = TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return is_recoverable;
+ }
+
+ static gboolean
+@@ -193,61 +200,61 @@ parse_gio_error (gint code,
+
+ case G_IO_ERROR_IS_DIRECTORY:
+ *error_message = g_strdup_printf (_("“%s” is a directory."),
+ uri_for_display);
+ *message_details = g_strdup (_("Please check that you typed the "
+ "location correctly and try again."));
+ break;
+
+ case G_IO_ERROR_INVALID_FILENAME:
+ *error_message = g_strdup_printf (_("“%s” is not a valid location."),
+ uri_for_display);
+ *message_details = g_strdup (_("Please check that you typed the "
+ "location correctly and try again."));
+ break;
+
+ case G_IO_ERROR_HOST_NOT_FOUND:
+ /* This case can be hit for user-typed strings like "foo" due to
+ * the code that guesses web addresses when there's no initial "/".
+ * But this case is also hit for legitimate web addresses when
+ * the proxy is set up wrong.
+ */
+ {
+ gchar *hn = NULL;
+ gchar *uri = NULL;
+
+ if (location)
+ {
+ uri = g_file_get_uri (location);
+ }
+
+- if (uri && tepl_utils_decode_uri (uri, NULL, NULL, &hn, NULL, NULL))
++ if (uri && gedit_utils_decode_uri (uri, NULL, NULL, &hn, NULL, NULL))
+ {
+ if (hn != NULL)
+ {
+ gchar *host_markup;
+ gchar *host_name;
+
+ host_name = g_utf8_make_valid (hn, -1);
+ g_free (hn);
+
+ host_markup = g_markup_escape_text (host_name, -1);
+ g_free (host_name);
+
+ *message_details = g_strdup_printf (
+ /* Translators: %s is a host name */
+ _("Host “%s” could not be found. "
+ "Please check that your proxy settings "
+ "are correct and try again."),
+ host_markup);
+
+ g_free (host_markup);
+ }
+ }
+
+ g_free (uri);
+
+ if (!*message_details)
+ {
+ /* use the same string as INVALID_HOST */
+ *message_details = g_strdup_printf (
+ _("Hostname was invalid. "
+@@ -296,62 +303,62 @@ parse_error (const GError *error,
+ {
+ g_warning ("Hit unhandled case %d (%s) in %s.",
+ error->code, error->message, G_STRFUNC);
+ *message_details = g_strdup_printf (_("Unexpected error: %s"),
+ error->message);
+ }
+ }
+
+ GtkWidget *
+ gedit_unrecoverable_reverting_error_info_bar_new (GFile *location,
+ const GError *error)
+ {
+ gchar *error_message = NULL;
+ gchar *message_details = NULL;
+ gchar *full_formatted_uri;
+ gchar *uri_for_display;
+ gchar *temp_uri_for_display;
+ GtkWidget *info_bar;
+
+ g_return_val_if_fail (G_IS_FILE (location), NULL);
+ g_return_val_if_fail (error != NULL, NULL);
+ g_return_val_if_fail (error->domain == GTK_SOURCE_FILE_LOADER_ERROR ||
+ error->domain == G_IO_ERROR, NULL);
+
+ full_formatted_uri = g_file_get_parse_name (location);
+
+ /* Truncate the URI so it doesn't get insanely wide. Note that even
+ * though the dialog uses wrapped text, if the URI doesn't contain
+ * white space then the text-wrapping code is too stupid to wrap it.
+ */
+- temp_uri_for_display = tepl_utils_str_middle_truncate (full_formatted_uri,
+- MAX_URI_IN_DIALOG_LENGTH);
++ temp_uri_for_display = gedit_utils_str_middle_truncate (full_formatted_uri,
++ MAX_URI_IN_DIALOG_LENGTH);
+ g_free (full_formatted_uri);
+
+ uri_for_display = g_markup_escape_text (temp_uri_for_display, -1);
+ g_free (temp_uri_for_display);
+
+ if (is_gio_error (error, G_IO_ERROR_NOT_FOUND))
+ {
+ message_details = g_strdup (_("Cannot find the requested file. "
+ "Perhaps it has recently been deleted."));
+ }
+ else
+ {
+ parse_error (error, &error_message, &message_details, location, uri_for_display);
+ }
+
+ if (error_message == NULL)
+ {
+ error_message = g_strdup_printf (_("Could not revert the file “%s”."),
+ uri_for_display);
+ }
+
+ info_bar = create_io_loading_error_info_bar (error_message,
+ message_details,
+ FALSE);
+
+ g_free (uri_for_display);
+ g_free (error_message);
+ g_free (message_details);
+
+ return info_bar;
+@@ -472,62 +479,62 @@ gedit_io_loading_error_info_bar_new (GFile *location,
+ const GtkSourceEncoding *encoding,
+ const GError *error)
+ {
+ gchar *error_message = NULL;
+ gchar *message_details = NULL;
+ gchar *full_formatted_uri;
+ gchar *uri_for_display;
+ gchar *temp_uri_for_display;
+ GtkWidget *info_bar;
+ gboolean edit_anyway = FALSE;
+ gboolean convert_error = FALSE;
+
+ g_return_val_if_fail (error != NULL, NULL);
+ g_return_val_if_fail (error->domain == GTK_SOURCE_FILE_LOADER_ERROR ||
+ error->domain == G_IO_ERROR ||
+ error->domain == G_CONVERT_ERROR, NULL);
+
+ if (location != NULL)
+ {
+ full_formatted_uri = g_file_get_parse_name (location);
+ }
+ else
+ {
+ full_formatted_uri = g_strdup ("stdin");
+ }
+
+ /* Truncate the URI so it doesn't get insanely wide. Note that even
+ * though the dialog uses wrapped text, if the URI doesn't contain
+ * white space then the text-wrapping code is too stupid to wrap it.
+ */
+- temp_uri_for_display = tepl_utils_str_middle_truncate (full_formatted_uri,
+- MAX_URI_IN_DIALOG_LENGTH);
++ temp_uri_for_display = gedit_utils_str_middle_truncate (full_formatted_uri,
++ MAX_URI_IN_DIALOG_LENGTH);
+ g_free (full_formatted_uri);
+
+ uri_for_display = g_markup_escape_text (temp_uri_for_display, -1);
+ g_free (temp_uri_for_display);
+
+ if (is_gio_error (error, G_IO_ERROR_TOO_MANY_LINKS))
+ {
+ message_details = g_strdup (_("The number of followed links is limited and the actual file could not be found within this limit."));
+ }
+ else if (is_gio_error (error, G_IO_ERROR_PERMISSION_DENIED))
+ {
+ message_details = g_strdup (_("You do not have the permissions necessary to open the file."));
+ }
+ else if ((is_gio_error (error, G_IO_ERROR_INVALID_DATA) && encoding == NULL) ||
+ (error->domain == GTK_SOURCE_FILE_LOADER_ERROR &&
+ error->code == GTK_SOURCE_FILE_LOADER_ERROR_ENCODING_AUTO_DETECTION_FAILED))
+ {
+ message_details = g_strconcat (_("Unable to detect the character encoding."), "\n",
+ _("Please check that you are not trying to open a binary file."), "\n",
+ _("Select a character encoding from the menu and try again."), NULL);
+ convert_error = TRUE;
+ }
+ else if (error->domain == GTK_SOURCE_FILE_LOADER_ERROR &&
+ error->code == GTK_SOURCE_FILE_LOADER_ERROR_CONVERSION_FALLBACK)
+ {
+ error_message = g_strdup_printf (_("There was a problem opening the file “%s”."),
+ uri_for_display);
+ message_details = g_strconcat (_("The file you opened has some invalid characters. "
+ "If you continue editing this file you could corrupt this "
+ "document."), "\n",
+@@ -578,219 +585,405 @@ gedit_io_loading_error_info_bar_new (GFile *location,
+ g_free (message_details);
+
+ return info_bar;
+ }
+
+ GtkWidget *
+ gedit_conversion_error_while_saving_info_bar_new (GFile *location,
+ const GtkSourceEncoding *encoding,
+ const GError *error)
+ {
+ gchar *error_message = NULL;
+ gchar *message_details = NULL;
+ gchar *full_formatted_uri;
+ gchar *encoding_name;
+ gchar *uri_for_display;
+ gchar *temp_uri_for_display;
+ GtkWidget *info_bar;
+
+ g_return_val_if_fail (G_IS_FILE (location), NULL);
+ g_return_val_if_fail (error != NULL, NULL);
+ g_return_val_if_fail (error->domain == G_CONVERT_ERROR ||
+ error->domain == G_IO_ERROR, NULL);
+ g_return_val_if_fail (encoding != NULL, NULL);
+
+ full_formatted_uri = g_file_get_parse_name (location);
+
+ /* Truncate the URI so it doesn't get insanely wide. Note that even
+ * though the dialog uses wrapped text, if the URI doesn't contain
+ * white space then the text-wrapping code is too stupid to wrap it.
+ */
+- temp_uri_for_display = tepl_utils_str_middle_truncate (full_formatted_uri,
+- MAX_URI_IN_DIALOG_LENGTH);
++ temp_uri_for_display = gedit_utils_str_middle_truncate (full_formatted_uri,
++ MAX_URI_IN_DIALOG_LENGTH);
+ g_free (full_formatted_uri);
+
+ uri_for_display = g_markup_escape_text (temp_uri_for_display, -1);
+ g_free (temp_uri_for_display);
+
+ encoding_name = gtk_source_encoding_to_string (encoding);
+
+ error_message = g_strdup_printf (_("Could not save the file “%s” using the “%s” character encoding."),
+ uri_for_display,
+ encoding_name);
+ message_details = g_strconcat (_("The document contains one or more characters that cannot be encoded "
+ "using the specified character encoding."), "\n",
+ _("Select a different character encoding from the menu and try again."), NULL);
+
+ info_bar = create_conversion_error_info_bar (error_message,
+ message_details,
+ FALSE);
+
+ g_free (uri_for_display);
+ g_free (encoding_name);
+ g_free (error_message);
+ g_free (message_details);
+
+ return info_bar;
+ }
+
+ const GtkSourceEncoding *
+ gedit_conversion_error_info_bar_get_encoding (GtkWidget *info_bar)
+ {
+ gpointer menu;
+
+ g_return_val_if_fail (GTK_IS_INFO_BAR (info_bar), NULL);
+
+ menu = g_object_get_data (G_OBJECT (info_bar),
+ "gedit-info-bar-encoding-menu");
+ if (menu != NULL)
+ {
+ return gedit_encodings_combo_box_get_selected_encoding (GEDIT_ENCODINGS_COMBO_BOX (menu));
+ }
+
+ return NULL;
+ }
+
++GtkWidget *
++gedit_file_already_open_warning_info_bar_new (GFile *location)
++{
++ GtkWidget *info_bar;
++ GtkWidget *hbox_content;
++ GtkWidget *vbox;
++ gchar *primary_markup;
++ gchar *secondary_markup;
++ GtkWidget *primary_label;
++ GtkWidget *secondary_label;
++ gchar *primary_text;
++ const gchar *secondary_text;
++ gchar *full_formatted_uri;
++ gchar *uri_for_display;
++ gchar *temp_uri_for_display;
++
++ g_return_val_if_fail (G_IS_FILE (location), NULL);
++
++ full_formatted_uri = g_file_get_parse_name (location);
++
++ /* Truncate the URI so it doesn't get insanely wide. Note that even
++ * though the dialog uses wrapped text, if the URI doesn't contain
++ * white space then the text-wrapping code is too stupid to wrap it.
++ */
++ temp_uri_for_display = gedit_utils_str_middle_truncate (full_formatted_uri,
++ MAX_URI_IN_DIALOG_LENGTH);
++ g_free (full_formatted_uri);
++
++ uri_for_display = g_markup_escape_text (temp_uri_for_display, -1);
++ g_free (temp_uri_for_display);
++
++ info_bar = gtk_info_bar_new ();
++ gtk_info_bar_add_button (GTK_INFO_BAR (info_bar),
++ /* Translators: the access key chosen for this string should be
++ different from other main menu access keys (Open, Edit, View...) */
++ _("Edit Any_way"),
++ GTK_RESPONSE_YES);
++ gtk_info_bar_add_button (GTK_INFO_BAR (info_bar),
++ /* Translators: the access key chosen for this string should be
++ different from other main menu access keys (Open, Edit, View...) */
++ _("D_on’t Edit"),
++ GTK_RESPONSE_CANCEL);
++ gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar),
++ GTK_MESSAGE_WARNING);
++
++ hbox_content = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
++
++ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
++ gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0);
++
++ primary_text = g_strdup_printf (_("This file “%s” is already open in another window."), uri_for_display);
++ g_free (uri_for_display);
++
++ primary_markup = g_strdup_printf ("%s", primary_text);
++ g_free (primary_text);
++ primary_label = gtk_label_new (primary_markup);
++ g_free (primary_markup);
++ gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0);
++ gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
++ gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
++ gtk_widget_set_halign (primary_label, GTK_ALIGN_START);
++ gtk_widget_set_can_focus (primary_label, TRUE);
++ gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
++
++ secondary_text = _("Do you want to edit it anyway?");
++ secondary_markup = g_strdup_printf ("%s",
++ secondary_text);
++ secondary_label = gtk_label_new (secondary_markup);
++ g_free (secondary_markup);
++ gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0);
++ gtk_widget_set_can_focus (secondary_label, TRUE);
++ gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE);
++ gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
++ gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
++ gtk_widget_set_halign (secondary_label, GTK_ALIGN_START);
++
++ gtk_widget_show_all (hbox_content);
++ set_contents (info_bar, hbox_content);
++
++ return info_bar;
++}
++
+ GtkWidget *
+ gedit_externally_modified_saving_error_info_bar_new (GFile *location,
+ const GError *error)
+ {
+ GtkWidget *info_bar;
+ GtkWidget *hbox_content;
+ GtkWidget *vbox;
+ gchar *primary_markup;
+ gchar *secondary_markup;
+ GtkWidget *primary_label;
+ GtkWidget *secondary_label;
+ gchar *primary_text;
+ const gchar *secondary_text;
+ gchar *full_formatted_uri;
+ gchar *uri_for_display;
+ gchar *temp_uri_for_display;
+
+ g_return_val_if_fail (G_IS_FILE (location), NULL);
+ g_return_val_if_fail (error != NULL, NULL);
+ g_return_val_if_fail (error->domain == GTK_SOURCE_FILE_SAVER_ERROR, NULL);
+ g_return_val_if_fail (error->code == GTK_SOURCE_FILE_SAVER_ERROR_EXTERNALLY_MODIFIED, NULL);
+
+ full_formatted_uri = g_file_get_parse_name (location);
+
+ /* Truncate the URI so it doesn't get insanely wide. Note that even
+ * though the dialog uses wrapped text, if the URI doesn't contain
+ * white space then the text-wrapping code is too stupid to wrap it.
+ */
+- temp_uri_for_display = tepl_utils_str_middle_truncate (full_formatted_uri,
+- MAX_URI_IN_DIALOG_LENGTH);
++ temp_uri_for_display = gedit_utils_str_middle_truncate (full_formatted_uri,
++ MAX_URI_IN_DIALOG_LENGTH);
+ g_free (full_formatted_uri);
+
+ uri_for_display = g_markup_escape_text (temp_uri_for_display, -1);
+ g_free (temp_uri_for_display);
+
+ info_bar = gtk_info_bar_new ();
+
+ gtk_info_bar_add_button (GTK_INFO_BAR (info_bar),
+ _("S_ave Anyway"),
+ GTK_RESPONSE_YES);
+ gtk_info_bar_add_button (GTK_INFO_BAR (info_bar),
+ _("D_on’t Save"),
+ GTK_RESPONSE_CANCEL);
+ gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar),
+ GTK_MESSAGE_WARNING);
+
+ hbox_content = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0);
+
+ /* FIXME: review this message, it's not clear since for the user the "modification"
+ * could be interpreted as the changes he made in the document. beside "reading" is
+ * not accurate (since last load/save)
+ */
+ primary_text = g_strdup_printf (_("The file “%s” has been modified since reading it."),
+ uri_for_display);
+ g_free (uri_for_display);
+
+ primary_markup = g_strdup_printf ("%s", primary_text);
+ g_free (primary_text);
+ primary_label = gtk_label_new (primary_markup);
+ g_free (primary_markup);
+ gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0);
+ gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
+ gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
+ gtk_widget_set_halign (primary_label, GTK_ALIGN_START);
+ gtk_widget_set_can_focus (primary_label, TRUE);
+ gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
+
+ secondary_text = _("If you save it, all the external changes could be lost. Save it anyway?");
+ secondary_markup = g_strdup_printf ("%s",
+ secondary_text);
+ secondary_label = gtk_label_new (secondary_markup);
+ g_free (secondary_markup);
+ gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0);
+ gtk_widget_set_can_focus (secondary_label, TRUE);
+ gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE);
+ gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
+ gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
+ gtk_widget_set_halign (secondary_label, GTK_ALIGN_START);
+
+ gtk_widget_show_all (hbox_content);
+ set_contents (info_bar, hbox_content);
+
+ return info_bar;
+ }
+
++GtkWidget *
++gedit_no_backup_saving_error_info_bar_new (GFile *location,
++ const GError *error)
++{
++ GtkWidget *info_bar;
++ GtkWidget *hbox_content;
++ GtkWidget *vbox;
++ gchar *primary_markup;
++ gchar *secondary_markup;
++ GtkWidget *primary_label;
++ GtkWidget *secondary_label;
++ gchar *primary_text;
++ const gchar *secondary_text;
++ gchar *full_formatted_uri;
++ gchar *uri_for_display;
++ gchar *temp_uri_for_display;
++ gboolean create_backup_copy;
++ GSettings *editor_settings;
++
++ g_return_val_if_fail (G_IS_FILE (location), NULL);
++ g_return_val_if_fail (error != NULL, NULL);
++ g_return_val_if_fail (error->domain == G_IO_ERROR &&
++ error->code == G_IO_ERROR_CANT_CREATE_BACKUP, NULL);
++
++ full_formatted_uri = g_file_get_parse_name (location);
++
++ /* Truncate the URI so it doesn't get insanely wide. Note that even
++ * though the dialog uses wrapped text, if the URI doesn't contain
++ * white space then the text-wrapping code is too stupid to wrap it.
++ */
++ temp_uri_for_display = gedit_utils_str_middle_truncate (full_formatted_uri,
++ MAX_URI_IN_DIALOG_LENGTH);
++ g_free (full_formatted_uri);
++
++ uri_for_display = g_markup_escape_text (temp_uri_for_display, -1);
++ g_free (temp_uri_for_display);
++
++ info_bar = gtk_info_bar_new ();
++
++ gtk_info_bar_add_button (GTK_INFO_BAR (info_bar),
++ _("S_ave Anyway"),
++ GTK_RESPONSE_YES);
++ gtk_info_bar_add_button (GTK_INFO_BAR (info_bar),
++ _("D_on’t Save"),
++ GTK_RESPONSE_CANCEL);
++ gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar),
++ GTK_MESSAGE_WARNING);
++
++ hbox_content = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
++
++ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
++ gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0);
++
++ editor_settings = g_settings_new ("org.gnome.gedit.preferences.editor");
++
++ create_backup_copy = g_settings_get_boolean (editor_settings,
++ GEDIT_SETTINGS_CREATE_BACKUP_COPY);
++ g_object_unref (editor_settings);
++
++ /* FIXME: review this messages */
++ if (create_backup_copy)
++ {
++ primary_text = g_strdup_printf (_("Could not create a backup file while saving “%s”"),
++ uri_for_display);
++ }
++ else
++ {
++ primary_text = g_strdup_printf (_("Could not create a temporary backup file while saving “%s”"),
++ uri_for_display);
++ }
++
++ g_free (uri_for_display);
++
++ primary_markup = g_strdup_printf ("%s", primary_text);
++ g_free (primary_text);
++ primary_label = gtk_label_new (primary_markup);
++ g_free (primary_markup);
++ gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0);
++ gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
++ gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
++ gtk_widget_set_halign (primary_label, GTK_ALIGN_START);
++ gtk_widget_set_can_focus (primary_label, TRUE);
++ gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
++
++ secondary_text = _("Could not back up the old copy of the file before saving the new one. "
++ "You can ignore this warning and save the file anyway, but if an error "
++ "occurs while saving, you could lose the old copy of the file. Save anyway?");
++ secondary_markup = g_strdup_printf ("%s",
++ secondary_text);
++ secondary_label = gtk_label_new (secondary_markup);
++ g_free (secondary_markup);
++ gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0);
++ gtk_widget_set_can_focus (secondary_label, TRUE);
++ gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE);
++ gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
++ gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
++ gtk_widget_set_halign (secondary_label, GTK_ALIGN_START);
++
++ gtk_widget_show_all (hbox_content);
++ set_contents (info_bar, hbox_content);
++
++ return info_bar;
++}
++
+ GtkWidget *
+ gedit_unrecoverable_saving_error_info_bar_new (GFile *location,
+ const GError *error)
+ {
+ gchar *error_message = NULL;
+ gchar *message_details = NULL;
+ gchar *full_formatted_uri;
+ gchar *scheme_string;
+ gchar *scheme_markup;
+ gchar *uri_for_display;
+ gchar *temp_uri_for_display;
+ GtkWidget *info_bar;
+
+ g_return_val_if_fail (G_IS_FILE (location), NULL);
+ g_return_val_if_fail (error != NULL, NULL);
+ g_return_val_if_fail (error->domain == GTK_SOURCE_FILE_SAVER_ERROR ||
+ error->domain == G_IO_ERROR, NULL);
+
+ full_formatted_uri = g_file_get_parse_name (location);
+
+ /* Truncate the URI so it doesn't get insanely wide. Note that even
+ * though the dialog uses wrapped text, if the URI doesn't contain
+ * white space then the text-wrapping code is too stupid to wrap it.
+ */
+- temp_uri_for_display = tepl_utils_str_middle_truncate (full_formatted_uri,
+- MAX_URI_IN_DIALOG_LENGTH);
++ temp_uri_for_display = gedit_utils_str_middle_truncate (full_formatted_uri,
++ MAX_URI_IN_DIALOG_LENGTH);
+ g_free (full_formatted_uri);
+
+ uri_for_display = g_markup_escape_text (temp_uri_for_display, -1);
+ g_free (temp_uri_for_display);
+
+ if (is_gio_error (error, G_IO_ERROR_NOT_SUPPORTED))
+ {
+ scheme_string = g_file_get_uri_scheme (location);
+
+ if ((scheme_string != NULL) && g_utf8_validate (scheme_string, -1, NULL))
+ {
+ scheme_markup = g_markup_escape_text (scheme_string, -1);
+
+ /* Translators: %s is a URI scheme (like for example http:, ftp:, etc.) */
+ message_details = g_strdup_printf (_("Cannot handle “%s:” locations in write mode. "
+ "Please check that you typed the "
+ "location correctly and try again."),
+ scheme_markup);
+ g_free (scheme_markup);
+ }
+ else
+ {
+ message_details = g_strdup (_("Cannot handle this location in write mode. "
+ "Please check that you typed the "
+ "location correctly and try again."));
+ }
+
+ g_free (scheme_string);
+ }
+ else if (is_gio_error (error, G_IO_ERROR_INVALID_FILENAME))
+@@ -840,31 +1033,176 @@ gedit_unrecoverable_saving_error_info_bar_new (GFile *location,
+ "a smaller file or saving it to a disk that does not "
+ "have this limitation."));
+ }
+ #endif
+ else
+ {
+ parse_error (error,
+ &error_message,
+ &message_details,
+ location,
+ uri_for_display);
+ }
+
+ if (error_message == NULL)
+ {
+ error_message = g_strdup_printf (_("Could not save the file “%s”."),
+ uri_for_display);
+ }
+
+ info_bar = create_io_loading_error_info_bar (error_message,
+ message_details,
+ FALSE);
+
+ g_free (uri_for_display);
+ g_free (error_message);
+ g_free (message_details);
+
+ return info_bar;
+ }
+
++GtkWidget *
++gedit_externally_modified_info_bar_new (GFile *location,
++ gboolean document_modified)
++{
++ gchar *full_formatted_uri;
++ gchar *uri_for_display;
++ gchar *temp_uri_for_display;
++ gchar *primary_text;
++ GtkWidget *info_bar;
++
++ g_return_val_if_fail (G_IS_FILE (location), NULL);
++
++ full_formatted_uri = g_file_get_parse_name (location);
++
++ /* Truncate the URI so it doesn't get insanely wide. Note that even
++ * though the dialog uses wrapped text, if the URI doesn't contain
++ * white space then the text-wrapping code is too stupid to wrap it.
++ */
++ temp_uri_for_display = gedit_utils_str_middle_truncate (full_formatted_uri,
++ MAX_URI_IN_DIALOG_LENGTH);
++ g_free (full_formatted_uri);
++
++ uri_for_display = g_markup_escape_text (temp_uri_for_display, -1);
++ g_free (temp_uri_for_display);
++
++ primary_text = g_strdup_printf (_("The file “%s” changed on disk."),
++ uri_for_display);
++ g_free (uri_for_display);
++
++ info_bar = gtk_info_bar_new ();
++
++ if (document_modified)
++ {
++ GtkWidget *box;
++ GtkWidget *button;
++ button = gtk_info_bar_add_button (GTK_INFO_BAR (info_bar),
++ _("Drop Changes and _Reload"),
++ GTK_RESPONSE_OK);
++ box = gtk_info_bar_get_action_area (GTK_INFO_BAR (info_bar));
++ gtk_button_box_set_child_non_homogeneous (GTK_BUTTON_BOX (box),
++ button,
++ TRUE);
++ }
++ else
++ {
++ gtk_info_bar_add_button (GTK_INFO_BAR (info_bar),
++ _("_Reload"),
++ GTK_RESPONSE_OK);
++ }
++
++ gtk_info_bar_set_show_close_button (GTK_INFO_BAR (info_bar), TRUE);
++ gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar),
++ GTK_MESSAGE_WARNING);
++
++ set_info_bar_text (info_bar,
++ primary_text,
++ NULL);
++
++ g_free (primary_text);
++
++ return info_bar;
++}
++
++GtkWidget *
++gedit_invalid_character_info_bar_new (GFile *location)
++{
++ GtkWidget *info_bar;
++ GtkWidget *hbox_content;
++ GtkWidget *vbox;
++ GtkWidget *primary_label;
++ GtkWidget *secondary_label;
++ gchar *primary_markup;
++ gchar *secondary_markup;
++ gchar *primary_text;
++ gchar *full_formatted_uri;
++ gchar *uri_for_display;
++ gchar *temp_uri_for_display;
++ const gchar *secondary_text;
++
++ g_return_val_if_fail (G_IS_FILE (location), NULL);
++
++ full_formatted_uri = g_file_get_parse_name (location);
++
++ /* Truncate the URI so it doesn't get insanely wide. Note that even
++ * though the dialog uses wrapped text, if the URI doesn't contain
++ * white space then the text-wrapping code is too stupid to wrap it.
++ */
++ temp_uri_for_display = gedit_utils_str_middle_truncate (full_formatted_uri,
++ MAX_URI_IN_DIALOG_LENGTH);
++ g_free (full_formatted_uri);
++
++ uri_for_display = g_markup_escape_text (temp_uri_for_display, -1);
++ g_free (temp_uri_for_display);
++
++ info_bar = gtk_info_bar_new ();
++
++ gtk_info_bar_add_button (GTK_INFO_BAR (info_bar),
++ _("S_ave Anyway"),
++ GTK_RESPONSE_YES);
++ gtk_info_bar_add_button (GTK_INFO_BAR (info_bar),
++ _("D_on’t Save"),
++ GTK_RESPONSE_CANCEL);
++ gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar),
++ GTK_MESSAGE_WARNING);
++
++ hbox_content = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
++
++ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
++ gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0);
++
++ primary_text = g_strdup_printf (_("Some invalid chars have been detected while saving “%s”"),
++ uri_for_display);
++
++ g_free (uri_for_display);
++
++ primary_markup = g_strdup_printf ("%s", primary_text);
++ g_free (primary_text);
++ primary_label = gtk_label_new (primary_markup);
++ g_free (primary_markup);
++ gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0);
++ gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
++ gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
++ gtk_widget_set_halign (primary_label, GTK_ALIGN_START);
++ gtk_widget_set_can_focus (primary_label, TRUE);
++ gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
++
++ secondary_text = _("If you continue saving this file you can corrupt the document. "
++ " Save anyway?");
++ secondary_markup = g_strdup_printf ("%s",
++ secondary_text);
++ secondary_label = gtk_label_new (secondary_markup);
++ g_free (secondary_markup);
++ gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0);
++ gtk_widget_set_can_focus (secondary_label, TRUE);
++ gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE);
++ gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
++ gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
++ gtk_widget_set_halign (secondary_label, GTK_ALIGN_START);
++
++ gtk_widget_show_all (hbox_content);
++ set_contents (info_bar, hbox_content);
++
++ return info_bar;
++}
++
+ /* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-io-error-info-bar.h b/gedit/gedit-io-error-info-bar.h
+index 12780f7ae..9784652c7 100644
+--- a/gedit/gedit-io-error-info-bar.h
++++ b/gedit/gedit-io-error-info-bar.h
+@@ -12,41 +12,51 @@
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #ifndef GEDIT_IO_ERROR_INFO_BAR_H
+ #define GEDIT_IO_ERROR_INFO_BAR_H
+
+ #include
+
+ G_BEGIN_DECLS
+
+ GtkWidget *gedit_io_loading_error_info_bar_new (GFile *location,
+ const GtkSourceEncoding *encoding,
+ const GError *error);
+
+ GtkWidget *gedit_unrecoverable_reverting_error_info_bar_new (GFile *location,
+ const GError *error);
+
+ GtkWidget *gedit_conversion_error_while_saving_info_bar_new (GFile *location,
+ const GtkSourceEncoding *encoding,
+ const GError *error);
+
+ const GtkSourceEncoding
+ *gedit_conversion_error_info_bar_get_encoding (GtkWidget *info_bar);
+
++GtkWidget *gedit_file_already_open_warning_info_bar_new (GFile *location);
++
+ GtkWidget *gedit_externally_modified_saving_error_info_bar_new (GFile *location,
+ const GError *error);
+
++GtkWidget *gedit_no_backup_saving_error_info_bar_new (GFile *location,
++ const GError *error);
++
+ GtkWidget *gedit_unrecoverable_saving_error_info_bar_new (GFile *location,
+ const GError *error);
+
++GtkWidget *gedit_externally_modified_info_bar_new (GFile *location,
++ gboolean document_modified);
++
++GtkWidget *gedit_invalid_character_info_bar_new (GFile *location);
++
+ G_END_DECLS
+
+ #endif /* GEDIT_IO_ERROR_INFO_BAR_H */
+
+ /* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-metadata-manager.c b/gedit/gedit-metadata-manager.c
+new file mode 100644
+index 000000000..8f858b286
+--- /dev/null
++++ b/gedit/gedit-metadata-manager.c
+@@ -0,0 +1,650 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++/*
++ * gedit-metadata-manager.c
++ * This file is part of gedit
++ *
++ * Copyright (C) 2003-2007 Paolo Maggi
++ * Copyright (C) 2019 Canonical LTD
++ *
++ * 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
++ * along with this program; if not, see .
++ */
++
++#include "gedit-metadata-manager.h"
++#include
++#include "gedit-debug.h"
++
++/*
++#define GEDIT_METADATA_VERBOSE_DEBUG 1
++*/
++
++#define MAX_ITEMS 50
++
++typedef struct _Item Item;
++
++struct _Item
++{
++ /* Time of last access in seconds since January 1, 1970 UTC. */
++ gint64 atime;
++
++ GHashTable *values;
++};
++
++struct _GeditMetadataManager
++{
++ GObject parent_instance;
++
++ /* It is true if the file has been read. */
++ gboolean values_loaded;
++
++ guint timeout_id;
++
++ GHashTable *items;
++
++ gchar *metadata_filename;
++};
++
++enum
++{
++ PROP_0,
++ PROP_METADATA_FILENAME,
++ LAST_PROP
++};
++
++static GParamSpec *properties[LAST_PROP];
++
++G_DEFINE_TYPE (GeditMetadataManager, gedit_metadata_manager, G_TYPE_OBJECT);
++
++static gboolean gedit_metadata_manager_save (GeditMetadataManager *self);
++
++static void
++item_free (gpointer data)
++{
++ Item *item;
++
++ g_return_if_fail (data != NULL);
++
++#ifdef GEDIT_METADATA_VERBOSE_DEBUG
++ gedit_debug (DEBUG_METADATA);
++#endif
++
++ item = (Item *)data;
++
++ if (item->values != NULL)
++ g_hash_table_destroy (item->values);
++
++ g_free (item);
++}
++
++static void
++gedit_metadata_manager_arm_timeout (GeditMetadataManager *self)
++{
++ if (self->timeout_id == 0)
++ {
++ self->timeout_id =
++ g_timeout_add_seconds_full (G_PRIORITY_DEFAULT_IDLE,
++ 2,
++ (GSourceFunc)gedit_metadata_manager_save,
++ self,
++ NULL);
++ }
++}
++
++static void
++gedit_metadata_manager_parse_item (GeditMetadataManager *self,
++ xmlDocPtr doc,
++ xmlNodePtr cur)
++{
++ Item *item;
++
++ xmlChar *uri;
++ xmlChar *atime;
++
++#ifdef GEDIT_METADATA_VERBOSE_DEBUG
++ gedit_debug (DEBUG_METADATA);
++#endif
++
++ if (xmlStrcmp (cur->name, (const xmlChar *)"document") != 0)
++ return;
++
++ uri = xmlGetProp (cur, (const xmlChar *)"uri");
++ if (uri == NULL)
++ return;
++
++ atime = xmlGetProp (cur, (const xmlChar *)"atime");
++ if (atime == NULL)
++ {
++ xmlFree (uri);
++ return;
++ }
++
++ item = g_new0 (Item, 1);
++
++ item->atime = g_ascii_strtoll ((char *)atime, NULL, 0);
++
++ item->values = g_hash_table_new_full (g_str_hash,
++ g_str_equal,
++ g_free,
++ g_free);
++
++ cur = cur->xmlChildrenNode;
++
++ while (cur != NULL)
++ {
++ if (xmlStrcmp (cur->name, (const xmlChar *)"entry") == 0)
++ {
++ xmlChar *key;
++ xmlChar *value;
++
++ key = xmlGetProp (cur, (const xmlChar *)"key");
++ value = xmlGetProp (cur, (const xmlChar *)"value");
++
++ if ((key != NULL) && (value != NULL))
++ {
++ g_hash_table_insert (item->values,
++ g_strdup ((gchar *)key),
++ g_strdup ((gchar *)value));
++ }
++
++ if (key != NULL)
++ xmlFree (key);
++ if (value != NULL)
++ xmlFree (value);
++ }
++
++ cur = cur->next;
++ }
++
++ g_hash_table_insert (self->items,
++ g_strdup ((gchar *)uri),
++ item);
++
++ xmlFree (uri);
++ xmlFree (atime);
++}
++
++/* Returns FALSE in case of error. */
++static gboolean
++gedit_metadata_manager_load_values (GeditMetadataManager *self)
++{
++ xmlDocPtr doc;
++ xmlNodePtr cur;
++
++ gedit_debug (DEBUG_METADATA);
++
++ g_return_val_if_fail (self != NULL, FALSE);
++ g_return_val_if_fail (self->values_loaded == FALSE, FALSE);
++
++ self->values_loaded = TRUE;
++
++ xmlKeepBlanksDefault (0);
++
++ if (self->metadata_filename == NULL)
++ {
++ return FALSE;
++ }
++
++ /* TODO: avoid races */
++ if (!g_file_test (self->metadata_filename, G_FILE_TEST_EXISTS))
++ {
++ return TRUE;
++ }
++
++ doc = xmlParseFile (self->metadata_filename);
++
++ if (doc == NULL)
++ {
++ return FALSE;
++ }
++
++ cur = xmlDocGetRootElement (doc);
++ if (cur == NULL)
++ {
++ g_message ("The metadata file '%s' is empty",
++ g_path_get_basename (self->metadata_filename));
++ xmlFreeDoc (doc);
++
++ return TRUE;
++ }
++
++ if (xmlStrcmp (cur->name, (const xmlChar *) "metadata"))
++ {
++ g_message ("File '%s' is of the wrong type",
++ g_path_get_basename (self->metadata_filename));
++ xmlFreeDoc (doc);
++
++ return FALSE;
++ }
++
++ cur = xmlDocGetRootElement (doc);
++ cur = cur->xmlChildrenNode;
++
++ while (cur != NULL)
++ {
++ gedit_metadata_manager_parse_item (self, doc, cur);
++
++ cur = cur->next;
++ }
++
++ xmlFreeDoc (doc);
++
++ return TRUE;
++}
++
++/**
++ * gedit_metadata_manager_get:
++ * @self: a #GeditMetadataManager.
++ * @location: a #GFile.
++ * @key: a key.
++ *
++ * Gets the value associated with the specified @key for the file @location.
++ */
++gchar *
++gedit_metadata_manager_get (GeditMetadataManager *self,
++ GFile *location,
++ const gchar *key)
++{
++ Item *item;
++ gchar *value;
++ gchar *uri;
++
++ g_return_val_if_fail (GEDIT_IS_METADATA_MANAGER (self), NULL);
++ g_return_val_if_fail (G_IS_FILE (location), NULL);
++ g_return_val_if_fail (key != NULL, NULL);
++
++ uri = g_file_get_uri (location);
++
++ gedit_debug_message (DEBUG_METADATA, "URI: %s --- key: %s", uri, key );
++
++ if (!self->values_loaded)
++ {
++ gboolean res;
++
++ res = gedit_metadata_manager_load_values (self);
++
++ if (!res)
++ {
++ g_free (uri);
++ return NULL;
++ }
++ }
++
++ item = (Item *)g_hash_table_lookup (self->items, uri);
++
++ g_free (uri);
++
++ if (item == NULL)
++ return NULL;
++
++ item->atime = g_get_real_time () / 1000;
++
++ if (item->values == NULL)
++ return NULL;
++
++ value = g_hash_table_lookup (item->values, key);
++
++ if (value == NULL)
++ return NULL;
++ else
++ return g_strdup (value);
++}
++
++/**
++ * gedit_metadata_manager_set:
++ * @self: a #GeditMetadataManager.
++ * @location: a #GFile.
++ * @key: a key.
++ * @value: the value associated with the @key.
++ *
++ * Sets the @key to contain the given @value for the file @location.
++ */
++void
++gedit_metadata_manager_set (GeditMetadataManager *self,
++ GFile *location,
++ const gchar *key,
++ const gchar *value)
++{
++ Item *item;
++ gchar *uri;
++
++ g_return_if_fail (GEDIT_IS_METADATA_MANAGER (self));
++ g_return_if_fail (G_IS_FILE (location));
++ g_return_if_fail (key != NULL);
++
++ uri = g_file_get_uri (location);
++
++ gedit_debug_message (DEBUG_METADATA, "URI: %s --- key: %s --- value: %s", uri, key, value);
++
++ if (!self->values_loaded)
++ {
++ gboolean ok;
++
++ ok = gedit_metadata_manager_load_values (self);
++
++ if (!ok)
++ {
++ g_free (uri);
++ return;
++ }
++ }
++
++ item = (Item *)g_hash_table_lookup (self->items, uri);
++
++ if (item == NULL)
++ {
++ item = g_new0 (Item, 1);
++
++ g_hash_table_insert (self->items,
++ g_strdup (uri),
++ item);
++ }
++
++ if (item->values == NULL)
++ {
++ item->values = g_hash_table_new_full (g_str_hash,
++ g_str_equal,
++ g_free,
++ g_free);
++ }
++
++ if (value != NULL)
++ {
++ g_hash_table_insert (item->values,
++ g_strdup (key),
++ g_strdup (value));
++ }
++ else
++ {
++ g_hash_table_remove (item->values,
++ key);
++ }
++
++ item->atime = g_get_real_time () / 1000;
++
++ g_free (uri);
++
++ gedit_metadata_manager_arm_timeout (self);
++}
++
++static void
++save_values (const gchar *key, const gchar *value, xmlNodePtr parent)
++{
++ xmlNodePtr xml_node;
++
++#ifdef GEDIT_METADATA_VERBOSE_DEBUG
++ gedit_debug (DEBUG_METADATA);
++#endif
++
++ g_return_if_fail (key != NULL);
++
++ if (value == NULL)
++ return;
++
++ xml_node = xmlNewChild (parent,
++ NULL,
++ (const xmlChar *)"entry",
++ NULL);
++
++ xmlSetProp (xml_node,
++ (const xmlChar *)"key",
++ (const xmlChar *)key);
++ xmlSetProp (xml_node,
++ (const xmlChar *)"value",
++ (const xmlChar *)value);
++
++#ifdef GEDIT_METADATA_VERBOSE_DEBUG
++ gedit_debug_message (DEBUG_METADATA, "entry: %s = %s", key, value);
++#endif
++}
++
++static void
++save_item (const gchar *key, const gpointer *data, xmlNodePtr parent)
++{
++ xmlNodePtr xml_node;
++ const Item *item = (const Item *)data;
++ gchar *atime;
++
++#ifdef GEDIT_METADATA_VERBOSE_DEBUG
++ gedit_debug (DEBUG_METADATA);
++#endif
++
++ g_return_if_fail (key != NULL);
++
++ if (item == NULL)
++ return;
++
++ xml_node = xmlNewChild (parent, NULL, (const xmlChar *)"document", NULL);
++
++ xmlSetProp (xml_node, (const xmlChar *)"uri", (const xmlChar *)key);
++
++#ifdef GEDIT_METADATA_VERBOSE_DEBUG
++ gedit_debug_message (DEBUG_METADATA, "uri: %s", key);
++#endif
++
++ atime = g_strdup_printf ("%" G_GINT64_FORMAT, item->atime);
++ xmlSetProp (xml_node, (const xmlChar *)"atime", (const xmlChar *)atime);
++
++#ifdef GEDIT_METADATA_VERBOSE_DEBUG
++ gedit_debug_message (DEBUG_METADATA, "atime: %s", atime);
++#endif
++
++ g_free (atime);
++
++ g_hash_table_foreach (item->values,
++ (GHFunc)save_values,
++ xml_node);
++}
++
++static const gchar *
++gedit_metadata_manager_get_oldest (GeditMetadataManager *self)
++{
++ GHashTableIter iter;
++ gpointer key, value, key_to_remove = NULL;
++ const Item *item_to_remove = NULL;
++
++ g_hash_table_iter_init (&iter, self->items);
++ while (g_hash_table_iter_next (&iter, &key, &value))
++ {
++ const Item *item = (const Item *) value;
++
++ if (key_to_remove == NULL)
++ {
++ key_to_remove = key;
++ item_to_remove = item;
++ }
++ else
++ {
++ g_return_val_if_fail (item_to_remove != NULL, NULL);
++
++ if (item->atime < item_to_remove->atime)
++ key_to_remove = key;
++ }
++ }
++
++ return key_to_remove;
++}
++
++static void
++gedit_metadata_manager_resize_items (GeditMetadataManager *self)
++{
++ while (g_hash_table_size (self->items) > MAX_ITEMS)
++ {
++ const gchar *key_to_remove;
++
++ key_to_remove = gedit_metadata_manager_get_oldest (self);
++ g_return_if_fail (key_to_remove != NULL);
++ g_hash_table_remove (self->items,
++ key_to_remove);
++ }
++}
++
++static gboolean
++gedit_metadata_manager_save (GeditMetadataManager *self)
++{
++ xmlDocPtr doc;
++ xmlNodePtr root;
++
++ gedit_debug (DEBUG_METADATA);
++
++ self->timeout_id = 0;
++
++ gedit_metadata_manager_resize_items (self);
++
++ xmlIndentTreeOutput = TRUE;
++
++ doc = xmlNewDoc ((const xmlChar *)"1.0");
++ if (doc == NULL)
++ return TRUE;
++
++ /* Create metadata root */
++ root = xmlNewDocNode (doc, NULL, (const xmlChar *)"metadata", NULL);
++ xmlDocSetRootElement (doc, root);
++
++ g_hash_table_foreach (self->items,
++ (GHFunc)save_item,
++ root);
++
++ /* FIXME: lock file - Paolo */
++ if (self->metadata_filename != NULL)
++ {
++ gchar *cache_dir;
++ int res;
++
++ /* make sure the cache dir exists */
++ cache_dir = g_path_get_dirname (self->metadata_filename);
++ res = g_mkdir_with_parents (cache_dir, 0755);
++ if (res != -1)
++ {
++ xmlSaveFormatFile (self->metadata_filename,
++ doc,
++ 1);
++ }
++
++ g_free (cache_dir);
++ }
++
++ xmlFreeDoc (doc);
++
++ gedit_debug_message (DEBUG_METADATA, "DONE");
++
++ return FALSE;
++}
++
++static void
++gedit_metadata_manager_get_property (GObject *object,
++ guint prop_id,
++ GValue *value,
++ GParamSpec *pspec)
++{
++ GeditMetadataManager *self = GEDIT_METADATA_MANAGER (object);
++
++ switch (prop_id)
++ {
++ case PROP_METADATA_FILENAME:
++ g_value_set_string (value, self->metadata_filename);
++ break;
++ default:
++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++ break;
++ }
++}
++
++
++static void
++gedit_metadata_manager_set_property (GObject *object,
++ guint prop_id,
++ const GValue *value,
++ GParamSpec *pspec)
++{
++ GeditMetadataManager *self = GEDIT_METADATA_MANAGER (object);
++
++ switch (prop_id)
++ {
++ case PROP_METADATA_FILENAME:
++ self->metadata_filename = g_value_dup_string (value);
++ break;
++ default:
++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++ break;
++ }
++}
++
++static void
++gedit_metadata_manager_init (GeditMetadataManager *self)
++{
++ gedit_debug (DEBUG_METADATA);
++
++ self->values_loaded = FALSE;
++
++ self->items =
++ g_hash_table_new_full (g_str_hash,
++ g_str_equal,
++ g_free,
++ item_free);
++}
++
++static void
++gedit_metadata_manager_dispose (GObject *object)
++{
++ GeditMetadataManager *self = GEDIT_METADATA_MANAGER (object);
++
++ gedit_debug (DEBUG_METADATA);
++
++ if (self->timeout_id)
++ {
++ g_source_remove (self->timeout_id);
++ self->timeout_id = 0;
++ gedit_metadata_manager_save (self);
++ }
++
++ if (self->items != NULL)
++ g_hash_table_destroy (self->items);
++
++ g_free (self->metadata_filename);
++}
++
++static void
++gedit_metadata_manager_class_init (GeditMetadataManagerClass *klass)
++{
++ GObjectClass *object_class = G_OBJECT_CLASS (klass);
++
++ object_class->dispose = gedit_metadata_manager_dispose;
++ object_class->get_property = gedit_metadata_manager_get_property;
++ object_class->set_property = gedit_metadata_manager_set_property;
++
++ /**
++ * GeditMetadataManager:metadata-filename:
++ *
++ * The filename where the metadata is stored.
++ */
++ properties[PROP_METADATA_FILENAME] =
++ g_param_spec_string ("metadata-filename",
++ "Metadata filename",
++ "The filename where the metadata is stored",
++ NULL,
++ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
++
++ g_object_class_install_properties (object_class, LAST_PROP, properties);
++}
++
++GeditMetadataManager *
++gedit_metadata_manager_new (const gchar *metadata_filename)
++{
++ gedit_debug (DEBUG_METADATA);
++
++ return g_object_new (GEDIT_TYPE_METADATA_MANAGER,
++ "metadata-filename", metadata_filename,
++ NULL);
++}
++
++/* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-metadata-manager.h b/gedit/gedit-metadata-manager.h
+new file mode 100644
+index 000000000..49c2f05bf
+--- /dev/null
++++ b/gedit/gedit-metadata-manager.h
+@@ -0,0 +1,49 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++/*
++ * gedit-metadata-manager.h
++ * This file is part of gedit
++ *
++ * Copyright (C) 2003 Paolo Maggi
++ * Copyright (C) 2019 Canonical LTD
++ *
++ * 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
++ * along with this program; if not, see .
++ */
++
++#ifndef GEDIT_METADATA_MANAGER_H
++#define GEDIT_METADATA_MANAGER_H
++
++#include
++
++G_BEGIN_DECLS
++
++#define GEDIT_TYPE_METADATA_MANAGER (gedit_metadata_manager_get_type())
++
++G_DECLARE_FINAL_TYPE (GeditMetadataManager, gedit_metadata_manager, GEDIT, METADATA_MANAGER, GObject)
++
++GeditMetadataManager *gedit_metadata_manager_new (const gchar *metadata_filename);
++
++gchar *gedit_metadata_manager_get (GeditMetadataManager *self,
++ GFile *location,
++ const gchar *key);
++
++void gedit_metadata_manager_set (GeditMetadataManager *self,
++ GFile *location,
++ const gchar *key,
++ const gchar *value);
++
++G_END_DECLS
++
++#endif /* GEDIT_METADATA_MANAGER_H */
++
++/* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-open-document-selector-helper.c b/gedit/gedit-open-document-selector-helper.c
+new file mode 100644
+index 000000000..369d12ea2
+--- /dev/null
++++ b/gedit/gedit-open-document-selector-helper.c
+@@ -0,0 +1,103 @@
++/*
++ * gedit-open-document-selector-helper.c
++ * This file is part of gedit
++ *
++ * Copyright (C) 2015 - Sébastien Lafargue
++ *
++ * gedit 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.
++ *
++ * gedit 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
++ * along with gedit. If not, see .
++ */
++
++#include "gedit-open-document-selector-helper.h"
++
++void
++gedit_open_document_selector_debug_print_list (const gchar *title,
++ GList *fileitem_list)
++{
++ FileItem *item;
++ GList *l;
++ glong time_sec;
++ glong time_usec;
++
++ g_print ("%s\n", title);
++
++ for (l = fileitem_list; l != NULL; l = l->next)
++ {
++ item = (FileItem *)l->data;
++ time_sec = item->access_time.tv_sec;
++ time_usec = item->access_time.tv_usec;
++
++ g_print ("%ld:%ld uri:%s (%s %s)\n",
++ time_sec,
++ time_usec,
++ item->uri,
++ item->name,
++ item->path);
++ }
++}
++
++FileItem *
++gedit_open_document_selector_create_fileitem_item (void)
++{
++ FileItem *item;
++
++ item = g_slice_new0 (FileItem);
++
++ return item;
++}
++
++void
++gedit_open_document_selector_free_fileitem_item (FileItem *item)
++{
++ g_free (item->uri);
++ g_free (item->name);
++ g_free (item->path);
++
++ g_slice_free (FileItem, item);
++}
++
++FileItem *
++gedit_open_document_selector_copy_fileitem_item (FileItem *item)
++{
++ FileItem *new_item;
++
++ new_item = gedit_open_document_selector_create_fileitem_item ();
++
++ new_item->uri = g_strdup (item->uri);
++ new_item->name = g_strdup (item->name);
++ new_item->path = g_strdup (item->path);
++ new_item->access_time = item->access_time;
++
++ return new_item;
++}
++
++inline GList *
++gedit_open_document_selector_copy_file_items_list (const GList *file_items_list)
++{
++ GList *new_file_items_list;
++
++ new_file_items_list = g_list_copy_deep ((GList *)file_items_list,
++ (GCopyFunc)gedit_open_document_selector_copy_fileitem_item,
++ NULL);
++
++ return new_file_items_list;
++}
++
++inline void
++gedit_open_document_selector_free_file_items_list (GList *file_items_list)
++{
++ g_list_free_full (file_items_list,
++ (GDestroyNotify)gedit_open_document_selector_free_fileitem_item);
++}
++
++/* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-open-document-selector-helper.h b/gedit/gedit-open-document-selector-helper.h
+new file mode 100644
+index 000000000..6feb65408
+--- /dev/null
++++ b/gedit/gedit-open-document-selector-helper.h
+@@ -0,0 +1,103 @@
++/*
++ * gedit-open-document-selector-helper.h
++ * This file is part of gedit
++ *
++ * Copyright (C) 2015 - Sébastien Lafargue
++ *
++ * gedit 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.
++ *
++ * gedit 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
++ * along with gedit. If not, see .
++ */
++
++#ifndef GEDIT_OPEN_DOCUMENT_SELECTOR_HELPER_H
++#define GEDIT_OPEN_DOCUMENT_SELECTOR_HELPER_H
++
++#include "gedit-open-document-selector.h"
++
++#include
++
++G_BEGIN_DECLS
++
++typedef struct
++{
++ gchar *uri;
++ gchar *name;
++ gchar *path;
++ GTimeVal access_time;
++} FileItem;
++
++typedef enum
++{
++ GEDIT_OPEN_DOCUMENT_SELECTOR_RECENT_FILES_LIST = 0,
++ GEDIT_OPEN_DOCUMENT_SELECTOR_HOME_DIR_LIST,
++ GEDIT_OPEN_DOCUMENT_SELECTOR_DESKTOP_DIR_LIST,
++ GEDIT_OPEN_DOCUMENT_SELECTOR_LOCAL_BOOKMARKS_DIR_LIST,
++ GEDIT_OPEN_DOCUMENT_SELECTOR_FILE_BROWSER_ROOT_DIR_LIST,
++ GEDIT_OPEN_DOCUMENT_SELECTOR_ACTIVE_DOC_DIR_LIST,
++ GEDIT_OPEN_DOCUMENT_SELECTOR_CURRENT_DOCS_LIST,
++ GEDIT_OPEN_DOCUMENT_SELECTOR_LIST_TYPE_NUM_OF_LISTS
++} ListType;
++
++/* Use #if 1 and rebuild to activate selector debugging and timing */
++#if 0
++#define DEBUG_OPEN_DOCUMENT_SELECTOR
++#endif
++
++#ifdef DEBUG_OPEN_DOCUMENT_SELECTOR
++G_GNUC_UNUSED static const gchar *list_type_string[] =
++{
++ "RECENT_FILES_LIST",
++ "HOME_DIR_LIST",
++ "DESKTOP_DIR_LIST",
++ "LOCAL_BOOKMARKS_DIR_LIST",
++ "FILE_BROWSER_ROOT_DIR_LIST",
++ "ACTIVE_DOC_DIR_LIST",
++ "CURRENT_DOCS_LIST"
++};
++
++#define DEBUG_SELECTOR(x) do { x; } while (0)
++#define DEBUG_SELECTOR_TIMER_DECL G_GNUC_UNUSED GTimer *debug_timer;
++#define DEBUG_SELECTOR_TIMER_NEW debug_timer = g_timer_new ();
++#define DEBUG_SELECTOR_TIMER_DESTROY g_timer_destroy (debug_timer);
++#define DEBUG_SELECTOR_TIMER_GET g_timer_elapsed (debug_timer, NULL)
++#else
++#define DEBUG_SELECTOR(x)
++#define DEBUG_SELECTOR_TIMER_DECL
++#define DEBUG_SELECTOR_TIMER_NEW
++#define DEBUG_SELECTOR_TIMER_DESTROY
++#define DEBUG_SELECTOR_TIMER_GET
++#endif
++
++typedef struct
++{
++ GeditOpenDocumentSelector *selector;
++ ListType type;
++} PushMessage;
++
++void gedit_open_document_selector_debug_print_list (const gchar *title,
++ GList *fileitem_list);
++
++GList *gedit_open_document_selector_copy_file_items_list (const GList *file_items_list);
++
++void gedit_open_document_selector_free_file_items_list (GList *file_items_list);
++
++FileItem *gedit_open_document_selector_create_fileitem_item (void);
++
++void gedit_open_document_selector_free_fileitem_item (FileItem *item);
++
++FileItem *gedit_open_document_selector_copy_fileitem_item (FileItem *item);
++
++G_END_DECLS
++
++#endif /* GEDIT_OPEN_DOCUMENT_SELECTOR_HELPER_H */
++
++/* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-open-document-selector-store.c b/gedit/gedit-open-document-selector-store.c
+new file mode 100644
+index 000000000..e3454f12c
+--- /dev/null
++++ b/gedit/gedit-open-document-selector-store.c
+@@ -0,0 +1,820 @@
++/*
++ * gedit-open-document-selector-store.c
++ * This file is part of gedit
++ *
++ * Copyright (C) 2015 - Sébastien Lafargue
++ *
++ * gedit 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.
++ *
++ * gedit 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
++ * along with gedit. If not, see .
++ */
++
++/* You need to call gedit_open_document_selector_store_get_default()
++ * to get a singleton #GeditOpenDocumentSelectorStore object.
++ * #GeditOpenDocumentSelectorStore is responsible of managing
++ * the recent files list and computing others lists.
++ *
++ * The lists returned are lists of FileItem structs.
++ *
++ * #GeditOpenDocumentSelectorStore is destroyed automaticly at
++ * the end of your application.
++ *
++ * Call gedit_open_document_selector_store_update_list_async() with
++ * the corresponding ListType, then in your callback, call
++ * gedit_open_document_selector_store_update_list_finish() to get
++ * in return the list of FileItem structs.
++ *
++ * The recent files list can be filtered by calling
++ * gedit_open_document_selector_store_set_filter()
++ * and you can get the actual filter by calling
++ * gedit_open_document_selector_store_get_filter()
++ * ( this is in addition to the text mime type filter)
++ *
++ * The recent files list is not capped by Gedit settings like
++ * in gedit_recent_get_items() but you still can get the limit
++ * by calling gedit_open_document_selector_store_get_recent_limit().
++ *
++ * The original setting is stored in gsettings at :
++ * org.gnome.gedit.preferences.ui
++ * with the key : max-recents
++ */
++
++#include "gedit-open-document-selector-store.h"
++
++#include
++
++#include
++#include
++
++#include
++#include
++
++#include "gedit-recent.h"
++#include "gedit-utils.h"
++#include "gedit-window.h"
++#include "gedit-debug.h"
++
++struct _GeditOpenDocumentSelectorStore
++{
++ GObject parent_instance;
++
++ GSource *recent_source;
++
++ GeditRecentConfiguration recent_config;
++ gchar *filter;
++ GList *recent_items;
++ gint recent_config_limit;
++ gboolean recent_items_need_update;
++};
++
++G_LOCK_DEFINE_STATIC (recent_files_filter_lock);
++
++G_DEFINE_TYPE (GeditOpenDocumentSelectorStore, gedit_open_document_selector_store, G_TYPE_OBJECT)
++
++G_DEFINE_QUARK (gedit-open-document-selector-store-error-quark,
++ gedit_open_document_selector_store_error)
++
++static GList *
++get_current_docs_list (GeditOpenDocumentSelectorStore *selector_store G_GNUC_UNUSED,
++ GeditOpenDocumentSelector *selector)
++{
++ GeditWindow *window;
++ GList *docs;
++ GList *l;
++ GFile *file;
++ GFileInfo *info;
++ FileItem *item;
++ GList *file_items_list = NULL;
++
++ window = gedit_open_document_selector_get_window (selector);
++
++ docs = gedit_window_get_documents (window);
++ for (l = docs; l != NULL; l = l->next)
++ {
++ file = gtk_source_file_get_location (gedit_document_get_file (l->data));
++ if (file == NULL)
++ {
++ /* In case of not saved docs */
++ continue;
++ }
++
++ info = g_file_query_info (file,
++ "time::access,time::access-usec",
++ G_FILE_QUERY_INFO_NONE,
++ NULL,
++ NULL);
++ if (info == NULL)
++ {
++ continue;
++ }
++
++ item = gedit_open_document_selector_create_fileitem_item ();
++
++ item->access_time.tv_sec = g_file_info_get_attribute_uint64 (info, "time::access");
++ item->access_time.tv_usec = g_file_info_get_attribute_uint32 (info, "time::access-usec");
++ item->uri = g_file_get_uri (file);
++
++ file_items_list = g_list_prepend (file_items_list, item);
++
++ g_object_unref (info);
++ }
++
++ g_list_free (docs);
++ return file_items_list;
++}
++
++/* Notice that a content-type attribute must have been query to work */
++static gboolean
++check_mime_type (GFileInfo *info)
++{
++ const gchar *content_type;
++ G_GNUC_UNUSED gchar *mime_type;
++
++ content_type = g_file_info_get_attribute_string (info, "standard::fast-content-type");
++ if (content_type == NULL)
++ {
++ return FALSE;
++ }
++
++#ifdef G_OS_WIN32
++ if (g_content_type_is_a (content_type, "text"))
++ {
++ return TRUE;
++ }
++
++ mime_type = g_content_type_get_mime_type (content_type);
++ if (mime_type == NULL)
++ {
++ return FALSE;
++ }
++
++ if (g_strcmp0 (mime_type, "text/plain") == 0)
++ {
++ g_free (mime_type);
++ return TRUE;
++ }
++
++ g_free (mime_type);
++#else
++ if (g_content_type_is_a (content_type, "text/plain"))
++ {
++ return TRUE;
++ }
++#endif
++ return FALSE;
++}
++
++static GList *
++get_children_from_dir (GeditOpenDocumentSelectorStore *selector_store G_GNUC_UNUSED,
++ GFile *dir)
++{
++ GList *file_items_list = NULL;
++ GFileEnumerator *file_enum;
++ GFileInfo *info;
++ GFileType filetype;
++ GFile *file;
++ FileItem *item;
++ gboolean is_text;
++ gboolean is_correct_type;
++
++ g_return_val_if_fail (G_IS_FILE (dir), NULL);
++
++ file_enum = g_file_enumerate_children (dir,
++ "standard::name,"
++ "standard::type,"
++ "standard::fast-content-type,"
++ "time::access,time::access-usec",
++ G_FILE_QUERY_INFO_NONE,
++ NULL,
++ NULL);
++ if (file_enum == NULL)
++ {
++ return NULL;
++ }
++
++ while ((info = g_file_enumerator_next_file (file_enum, NULL, NULL)))
++ {
++ filetype = g_file_info_get_file_type (info);
++ is_text = check_mime_type (info);
++ is_correct_type = (filetype == G_FILE_TYPE_REGULAR ||
++ filetype == G_FILE_TYPE_SYMBOLIC_LINK ||
++ filetype == G_FILE_TYPE_SHORTCUT);
++
++ if (is_text &&
++ is_correct_type &&
++ (file = g_file_enumerator_get_child (file_enum, info)) != NULL)
++ {
++ item = gedit_open_document_selector_create_fileitem_item ();
++ item->uri = g_file_get_uri (file);
++
++ item->access_time.tv_sec = g_file_info_get_attribute_uint64 (info, "time::access");
++ item->access_time.tv_usec = g_file_info_get_attribute_uint32 (info, "time::access-usec");
++
++ file_items_list = g_list_prepend (file_items_list, item);
++ g_object_unref (file);
++ }
++
++ g_object_unref (info);
++ }
++
++ g_file_enumerator_close (file_enum, NULL, NULL);
++ g_object_unref (file_enum);
++
++ return file_items_list;
++}
++
++static GList *
++get_active_doc_dir_list (GeditOpenDocumentSelectorStore *selector_store,
++ GeditOpenDocumentSelector *selector)
++{
++ GeditWindow *window;
++ GeditDocument *active_doc;
++ GtkSourceFile *source_file;
++ GList *file_items_list = NULL;
++
++ window = gedit_open_document_selector_get_window (selector);
++
++ active_doc = gedit_window_get_active_document (window);
++
++ if (active_doc == NULL)
++ {
++ return NULL;
++ }
++
++ source_file = gedit_document_get_file (active_doc);
++ if (gtk_source_file_is_local (source_file))
++ {
++ GFile *location;
++ GFile *parent_dir;
++
++ location = gtk_source_file_get_location (source_file);
++ parent_dir = g_file_get_parent (location);
++
++ if (parent_dir != NULL)
++ {
++ file_items_list = get_children_from_dir (selector_store, parent_dir);
++ g_object_unref (parent_dir);
++ }
++ }
++
++ return file_items_list;
++}
++
++static GFile *
++get_file_browser_root (GeditOpenDocumentSelectorStore *selector_store G_GNUC_UNUSED,
++ GeditOpenDocumentSelector *selector)
++{
++ GeditWindow *window;
++ GeditMessageBus *bus;
++ GeditMessage *msg;
++ GFile *root = NULL;
++
++ window = gedit_open_document_selector_get_window (selector);
++
++ bus = gedit_window_get_message_bus (window);
++ if (gedit_message_bus_is_registered (bus, "/plugins/filebrowser", "get_root"))
++ {
++ msg = gedit_message_bus_send_sync (bus, "/plugins/filebrowser", "get_root", NULL, NULL);
++ g_object_get (msg, "location", &root, NULL);
++ g_object_unref (msg);
++ }
++
++ return root;
++}
++
++static GList *
++get_file_browser_root_dir_list (GeditOpenDocumentSelectorStore *selector_store,
++ GeditOpenDocumentSelector *selector)
++{
++ GFile *root;
++ GList *file_items_list = NULL;
++
++ root = get_file_browser_root (selector_store, selector);
++ if (root != NULL && g_file_is_native (root))
++ {
++ file_items_list = get_children_from_dir (selector_store, root);
++ }
++
++ g_clear_object (&root);
++ return file_items_list;
++}
++
++/* Taken and adapted from gtk+ gtkbookmarksmanager.c */
++static GList *
++read_bookmarks_file (GFile *file)
++{
++ gchar *contents;
++ gchar **lines, *space;
++ GList *uri_list = NULL;
++ gint i;
++
++ if (!g_file_load_contents (file, NULL, &contents, NULL, NULL, NULL))
++ {
++ return NULL;
++ }
++
++ lines = g_strsplit (contents, "\n", -1);
++
++ for (i = 0; lines[i]; i++)
++ {
++ if (*lines[i] == '\0')
++ {
++ continue;
++ }
++
++ if (!g_utf8_validate (lines[i], -1, NULL))
++ {
++ continue;
++ }
++
++ if ((space = strchr (lines[i], ' ')) != NULL)
++ {
++ space[0] = '\0';
++ }
++
++ uri_list = g_list_prepend (uri_list, g_strdup (lines[i]));
++ }
++
++ g_strfreev (lines);
++ g_free (contents);
++
++ return uri_list;
++}
++
++static GList *
++get_local_bookmarks_list (GeditOpenDocumentSelectorStore *selector_store,
++ GeditOpenDocumentSelector *selector G_GNUC_UNUSED)
++{
++ GList *bookmarks_uri_list = NULL;
++ GList *file_items_list = NULL;
++ GList *new_file_items_list = NULL;
++ GFile *bookmarks_file;
++ GFile *file;
++ gchar *filename;
++ GList *l;
++
++ filename = g_build_filename (g_get_user_config_dir (), "gtk-3.0", "bookmarks", NULL);
++ bookmarks_file = g_file_new_for_path (filename);
++ g_free (filename);
++
++ bookmarks_uri_list = read_bookmarks_file (bookmarks_file);
++ g_object_unref (bookmarks_file);
++
++ for (l = bookmarks_uri_list; l != NULL; l = l->next)
++ {
++ file = g_file_new_for_uri (l->data);
++ if (g_file_is_native (file))
++ {
++ new_file_items_list = get_children_from_dir (selector_store, file);
++ file_items_list = g_list_concat (file_items_list, new_file_items_list);
++ }
++
++ g_object_unref (file);
++ }
++
++ g_list_free_full (bookmarks_uri_list, g_free);
++ return file_items_list;
++}
++
++/* Taken and adapted from gtk+ gtkplacessidebar.c */
++static gboolean
++path_is_home_dir (const gchar *path)
++{
++ GFile *home_dir;
++ GFile *location;
++ const gchar *home_path;
++ gboolean res;
++
++ home_path = g_get_home_dir ();
++ if (home_path == NULL)
++ {
++ return FALSE;
++ }
++
++ home_dir = g_file_new_for_path (home_path);
++ location = g_file_new_for_path (path);
++ res = g_file_equal (home_dir, location);
++
++ g_object_unref (home_dir);
++ g_object_unref (location);
++
++ return res;
++}
++
++static GList *
++get_desktop_dir_list (GeditOpenDocumentSelectorStore *selector_store,
++ GeditOpenDocumentSelector *selector G_GNUC_UNUSED)
++{
++ GList *file_items_list = NULL;
++ const gchar *desktop_dir_name;
++ gchar *desktop_uri;
++ GFile *desktop_file;
++
++ desktop_dir_name = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP);
++
++ /* "To disable a directory, point it to the homedir."
++ * See http://freedesktop.org/wiki/Software/xdg-user-dirs
++ */
++ if (path_is_home_dir (desktop_dir_name))
++ {
++ return NULL;
++ }
++
++ desktop_uri = g_strconcat ("file://", desktop_dir_name, NULL);
++ desktop_file = g_file_new_for_uri (desktop_uri);
++ file_items_list = get_children_from_dir (selector_store, desktop_file);
++
++ g_free (desktop_uri);
++ g_object_unref (desktop_file);
++
++ return file_items_list;
++}
++
++static GList *
++get_home_dir_list (GeditOpenDocumentSelectorStore *selector_store,
++ GeditOpenDocumentSelector *selector G_GNUC_UNUSED)
++{
++ GList *file_items_list = NULL;
++ const gchar *home_name;
++ gchar *home_uri;
++ GFile *home_file;
++
++ home_name = g_get_home_dir ();
++ if (home_name == NULL)
++ {
++ return NULL;
++ }
++
++ home_uri = g_strconcat ("file://", home_name, NULL);
++ home_file = g_file_new_for_uri (home_uri);
++ file_items_list = get_children_from_dir (selector_store, home_file);
++
++ g_free (home_uri);
++ g_object_unref (home_file);
++
++ return file_items_list;
++}
++
++static GList *
++convert_recent_item_list_to_fileitem_list (GList *uri_list)
++{
++ GList *l;
++ GList *fileitem_list = NULL;
++
++ for (l = uri_list; l != NULL; l = l->next)
++ {
++ gchar *uri;
++ FileItem *item;
++
++ uri = g_strdup (gtk_recent_info_get_uri (l->data));
++
++ item = gedit_open_document_selector_create_fileitem_item ();
++ item->uri = uri;
++
++ item->access_time.tv_sec = gtk_recent_info_get_visited (l->data);
++ item->access_time.tv_usec = 0;
++
++ fileitem_list = g_list_prepend (fileitem_list, item);
++ }
++
++ fileitem_list = g_list_reverse (fileitem_list);
++ return fileitem_list;
++}
++
++static GList *
++get_recent_files_list (GeditOpenDocumentSelectorStore *selector_store,
++ GeditOpenDocumentSelector *selector G_GNUC_UNUSED)
++{
++ GList *recent_items_list;
++ GList *file_items_list;
++
++ G_LOCK (recent_files_filter_lock);
++ recent_items_list = gedit_recent_get_items (&selector_store->recent_config);
++ G_UNLOCK (recent_files_filter_lock);
++
++ file_items_list = convert_recent_item_list_to_fileitem_list (recent_items_list);
++ g_list_free_full (recent_items_list, (GDestroyNotify)gtk_recent_info_unref);
++
++ return file_items_list;
++}
++
++static void
++update_list_cb (GeditOpenDocumentSelectorStore *selector_store,
++ GAsyncResult *res,
++ gpointer user_data G_GNUC_UNUSED)
++{
++ GList *list;
++ GError *error;
++ PushMessage *message;
++ ListType type;
++
++ list = gedit_open_document_selector_store_update_list_finish (selector_store, res, &error);
++
++ message = g_task_get_task_data (G_TASK (res));
++ type = message->type;
++
++ switch (type)
++ {
++ case GEDIT_OPEN_DOCUMENT_SELECTOR_RECENT_FILES_LIST:
++ gedit_open_document_selector_free_file_items_list (selector_store->recent_items);
++ selector_store->recent_items = list;
++
++ DEBUG_SELECTOR (g_print ("\tStore(%p): update_list_cb: type:%s, length:%i\n",
++ selector_store, list_type_string[type], g_list_length (list)););
++
++ break;
++ default:
++ break;
++ }
++}
++
++static void
++on_recent_manager_changed (GtkRecentManager *manager G_GNUC_UNUSED,
++ gpointer user_data)
++{
++ GeditOpenDocumentSelectorStore *selector_store = GEDIT_OPEN_DOCUMENT_SELECTOR_STORE (user_data);
++
++ selector_store->recent_items_need_update = TRUE;
++ gedit_open_document_selector_store_update_list_async (selector_store,
++ NULL,
++ NULL,
++ (GAsyncReadyCallback)update_list_cb,
++ GEDIT_OPEN_DOCUMENT_SELECTOR_RECENT_FILES_LIST,
++ NULL);
++}
++
++static void
++gedit_open_document_selector_store_dispose (GObject *object)
++{
++ GeditOpenDocumentSelectorStore *selector_store = GEDIT_OPEN_DOCUMENT_SELECTOR_STORE (object);
++
++ gedit_recent_configuration_destroy (&selector_store->recent_config);
++
++ g_clear_pointer (&selector_store->recent_source, g_source_destroy);
++ g_clear_pointer (&selector_store->filter, g_free);
++
++ if (selector_store->recent_items)
++ {
++ gedit_open_document_selector_free_file_items_list (selector_store->recent_items);
++ selector_store->recent_items = NULL;
++ }
++
++ G_OBJECT_CLASS (gedit_open_document_selector_store_parent_class)->dispose (object);
++}
++
++static void
++gedit_open_document_selector_store_class_init (GeditOpenDocumentSelectorStoreClass *klass)
++{
++ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
++
++ gobject_class->dispose = gedit_open_document_selector_store_dispose;
++}
++
++/* The order of functions pointers must be the same as in
++ * ListType enum define in ./gedit-open-document-selector-helper.h
++ */
++static GList * (*list_func [])(GeditOpenDocumentSelectorStore *selector_store,
++ GeditOpenDocumentSelector *selector) =
++{
++ get_recent_files_list,
++ get_home_dir_list,
++ get_desktop_dir_list,
++ get_local_bookmarks_list,
++ get_file_browser_root_dir_list,
++ get_active_doc_dir_list,
++ get_current_docs_list
++};
++
++static gboolean
++update_recent_list (gpointer user_data)
++{
++ GeditOpenDocumentSelectorStore *selector_store;
++ GeditOpenDocumentSelector *selector;
++ PushMessage *message;
++ /* The type variable is only used when debug code activated */
++ G_GNUC_UNUSED ListType type;
++ GList *file_items_list;
++ GTask *task = G_TASK(user_data);
++
++ selector_store = g_task_get_source_object (task);
++ message = g_task_get_task_data (task);
++ selector = message->selector;
++ type = message->type;
++
++ DEBUG_SELECTOR_TIMER_DECL
++ DEBUG_SELECTOR_TIMER_NEW
++ DEBUG_SELECTOR (g_print ("\tStore(%p): store dispatcher: type:%s\n",
++ selector, list_type_string[type]););
++
++ /* Update the recent list only when it changes, copy otherwise but keep it the first time */
++ if (selector_store->recent_items != NULL && selector_store->recent_items_need_update == FALSE)
++ {
++ file_items_list = gedit_open_document_selector_copy_file_items_list (selector_store->recent_items);
++
++ DEBUG_SELECTOR (g_print ("\tStore(%p): store dispatcher: recent list copy\n", selector););
++ }
++ else
++ {
++ selector_store->recent_items_need_update = FALSE;
++ file_items_list = get_recent_files_list (selector_store, selector);
++
++ DEBUG_SELECTOR (g_print ("\tStore(%p): store dispatcher: recent list compute\n", selector););
++
++ if (selector_store->recent_items == NULL)
++ {
++ selector_store->recent_items = gedit_open_document_selector_copy_file_items_list (file_items_list);
++ }
++ }
++
++ g_task_return_pointer (task,
++ file_items_list,
++ (GDestroyNotify)gedit_open_document_selector_free_file_items_list);
++
++ DEBUG_SELECTOR (g_print ("\tStore(%p): store dispatcher: type:%s, time:%lf\n",
++ selector, list_type_string[type], DEBUG_SELECTOR_TIMER_GET););
++ DEBUG_SELECTOR_TIMER_DESTROY
++
++ selector_store->recent_source = NULL;
++ return G_SOURCE_REMOVE;
++}
++
++static void
++update_list_dispatcher (GTask *task,
++ gpointer source_object,
++ gpointer task_data,
++ GCancellable *cancellable G_GNUC_UNUSED)
++{
++ GeditOpenDocumentSelectorStore *selector_store = source_object;
++ GeditOpenDocumentSelector *selector;
++ PushMessage *message;
++ ListType type;
++ GList *file_items_list;
++
++ message = task_data;
++ selector = message->selector;
++ type = message->type;
++
++ DEBUG_SELECTOR_TIMER_DECL
++ DEBUG_SELECTOR_TIMER_NEW
++ DEBUG_SELECTOR (g_print ("\tStore(%p): store dispatcher: Thread:%p, type:%s\n",
++ selector, g_thread_self (), list_type_string[type]););
++
++ if (type >= GEDIT_OPEN_DOCUMENT_SELECTOR_LIST_TYPE_NUM_OF_LISTS)
++ {
++ g_task_return_new_error (task,
++ GEDIT_OPEN_DOCUMENT_SELECTOR_STORE_ERROR, TYPE_OUT_OF_RANGE,
++ "List Type out of range");
++ g_object_unref (task);
++ return;
++ }
++
++ /* Here we call the corresponding list creator function */
++ file_items_list = (*list_func[type]) (selector_store, selector);
++
++ DEBUG_SELECTOR (g_print ("\tStore(%p): store dispatcher: Thread:%p, type:%s, time:%lf\n",
++ selector, g_thread_self (), list_type_string[type], DEBUG_SELECTOR_TIMER_GET););
++ DEBUG_SELECTOR_TIMER_DESTROY
++
++ g_task_return_pointer (task,
++ file_items_list,
++ (GDestroyNotify)gedit_open_document_selector_free_file_items_list);
++}
++
++GList *
++gedit_open_document_selector_store_update_list_finish (GeditOpenDocumentSelectorStore *open_document_selector_store,
++ GAsyncResult *result,
++ GError **error)
++{
++ g_return_val_if_fail (GEDIT_IS_OPEN_DOCUMENT_SELECTOR_STORE (open_document_selector_store), NULL);
++ g_return_val_if_fail (g_task_is_valid (result, open_document_selector_store), NULL);
++
++ return g_task_propagate_pointer (G_TASK (result), error);
++}
++
++void
++gedit_open_document_selector_store_update_list_async (GeditOpenDocumentSelectorStore *selector_store,
++ GeditOpenDocumentSelector *selector,
++ GCancellable *cancellable,
++ GAsyncReadyCallback callback,
++ ListType type,
++ gpointer user_data)
++{
++ GTask *task;
++ PushMessage *message;
++
++ g_return_if_fail (GEDIT_IS_OPEN_DOCUMENT_SELECTOR_STORE (selector_store));
++ g_return_if_fail (selector == NULL || GEDIT_IS_OPEN_DOCUMENT_SELECTOR (selector));
++
++ message = g_new (PushMessage, 1);
++ message->selector = selector;
++ message->type = type;
++
++ task = g_task_new (selector_store, cancellable, callback, user_data);
++ g_task_set_source_tag (task, gedit_open_document_selector_store_update_list_async);
++ g_task_set_priority (task, G_PRIORITY_DEFAULT);
++ g_task_set_task_data (task, message, (GDestroyNotify)g_free);
++
++ if (type == GEDIT_OPEN_DOCUMENT_SELECTOR_RECENT_FILES_LIST &&
++ selector_store->recent_source == NULL)
++ {
++ selector_store->recent_source = g_idle_source_new ();
++ g_task_attach_source (task, selector_store->recent_source, update_recent_list);
++ }
++ else
++ {
++ g_task_run_in_thread (task, update_list_dispatcher);
++ }
++
++ g_object_unref (task);
++}
++
++static void
++gedit_open_document_selector_store_init (GeditOpenDocumentSelectorStore *selector_store)
++{
++ gedit_recent_configuration_init_default (&selector_store->recent_config);
++
++ /* We remove the recent files limit since we need the whole list but
++ * we back it up as gedit_open_document_selector_store_get_recent_limit
++ * use it
++ */
++ selector_store->recent_config_limit = selector_store->recent_config.limit;
++ selector_store->recent_config.limit = -1;
++
++ g_signal_connect_object (selector_store->recent_config.manager,
++ "changed",
++ G_CALLBACK (on_recent_manager_changed),
++ selector_store,
++ 0);
++
++ selector_store->recent_items_need_update = TRUE;
++}
++
++gint
++gedit_open_document_selector_store_get_recent_limit (GeditOpenDocumentSelectorStore *selector_store)
++{
++ g_return_val_if_fail (GEDIT_IS_OPEN_DOCUMENT_SELECTOR_STORE (selector_store), -1);
++
++ return selector_store->recent_config_limit;
++}
++
++void
++gedit_open_document_selector_store_set_filter (GeditOpenDocumentSelectorStore *selector_store,
++ const gchar *filter)
++{
++ gchar *old_filter;
++
++ g_return_if_fail (GEDIT_IS_OPEN_DOCUMENT_SELECTOR_STORE (selector_store));
++ g_return_if_fail (filter != NULL);
++
++ G_LOCK (recent_files_filter_lock);
++
++ old_filter = selector_store->filter;
++ selector_store->filter = g_strdup (filter);
++
++ G_UNLOCK (recent_files_filter_lock);
++ g_free (old_filter);
++}
++
++gchar *
++gedit_open_document_selector_store_get_filter (GeditOpenDocumentSelectorStore *selector_store)
++{
++ gchar *recent_filter;
++
++ g_return_val_if_fail (GEDIT_IS_OPEN_DOCUMENT_SELECTOR_STORE (selector_store), NULL);
++
++ G_LOCK (recent_files_filter_lock);
++ recent_filter = g_strdup (selector_store->filter);
++ G_UNLOCK (recent_files_filter_lock);
++
++ return recent_filter;
++}
++
++/* Gets a unique instance of #GeditOpenDocumentSelectorStore
++ *
++ * Returns: (transfer none): A unique #GeditOpenDocumentSelectorStore.
++ * Do not ref or unref it, it will be destroyed at the end of the application.
++ */
++GeditOpenDocumentSelectorStore *
++gedit_open_document_selector_store_get_default (void)
++{
++ static GeditOpenDocumentSelectorStore *instance;
++
++ if (instance == NULL)
++ {
++ instance = g_object_new (GEDIT_TYPE_OPEN_DOCUMENT_SELECTOR_STORE, NULL);
++ g_object_add_weak_pointer (G_OBJECT (instance), (gpointer) &instance);
++ }
++
++ return instance;
++}
++
++/* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-open-document-selector-store.h b/gedit/gedit-open-document-selector-store.h
+new file mode 100644
+index 000000000..d1e17a908
+--- /dev/null
++++ b/gedit/gedit-open-document-selector-store.h
+@@ -0,0 +1,68 @@
++/*
++ * gedit-open-document-selector-store.h
++ * This file is part of gedit
++ *
++ * Copyright (C) 2015 - Sébastien Lafargue
++ *
++ * gedit 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.
++ *
++ * gedit 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
++ * along with gedit. If not, see .
++ */
++
++#ifndef GEDIT_OPEN_DOCUMENT_SELECTOR_STORE_H
++#define GEDIT_OPEN_DOCUMENT_SELECTOR_STORE_H
++
++#include "gedit-open-document-selector-helper.h"
++#include "gedit-open-document-selector.h"
++
++#include
++#include
++
++G_BEGIN_DECLS
++
++#define GEDIT_TYPE_OPEN_DOCUMENT_SELECTOR_STORE (gedit_open_document_selector_store_get_type ())
++
++G_DECLARE_FINAL_TYPE (GeditOpenDocumentSelectorStore, gedit_open_document_selector_store, GEDIT, OPEN_DOCUMENT_SELECTOR_STORE, GObject)
++
++#define GEDIT_OPEN_DOCUMENT_SELECTOR_STORE_ERROR gedit_open_document_selector_store_error_quark ()
++
++typedef enum
++{
++ TYPE_OUT_OF_RANGE
++} GeditOpenDocumentSelectorStoreError;
++
++GQuark gedit_open_document_selector_store_error_quark (void);
++
++gint gedit_open_document_selector_store_get_recent_limit (GeditOpenDocumentSelectorStore *store);
++
++void gedit_open_document_selector_store_set_filter (GeditOpenDocumentSelectorStore *store,
++ const gchar *filter);
++
++gchar *gedit_open_document_selector_store_get_filter (GeditOpenDocumentSelectorStore *store);
++
++GList *gedit_open_document_selector_store_update_list_finish (GeditOpenDocumentSelectorStore *open_document_selector_store,
++ GAsyncResult *res,
++ GError **error);
++
++void gedit_open_document_selector_store_update_list_async (GeditOpenDocumentSelectorStore *open_document_selector_store,
++ GeditOpenDocumentSelector *open_document_selector,
++ GCancellable *cancellable,
++ GAsyncReadyCallback callback,
++ ListType type,
++ gpointer user_data);
++
++GeditOpenDocumentSelectorStore *gedit_open_document_selector_store_get_default (void);
++
++G_END_DECLS
++
++#endif /* GEDIT_OPEN_DOCUMENT_SELECTOR_STORE_H */
++/* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-open-document-selector.c b/gedit/gedit-open-document-selector.c
+new file mode 100644
+index 000000000..f67a6ba6d
+--- /dev/null
++++ b/gedit/gedit-open-document-selector.c
+@@ -0,0 +1,1304 @@
++/*
++ * gedit-open-document-selector.c
++ * This file is part of gedit
++ *
++ * Copyright (C) 2014 - Sébastien Lafargue
++ *
++ * gedit 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.
++ *
++ * gedit 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
++ * along with gedit. If not, see .
++ */
++
++#include "gedit-open-document-selector.h"
++#include "gedit-open-document-selector-store.h"
++#include "gedit-open-document-selector-helper.h"
++
++#include
++
++#include
++#include
++#include
++
++#include
++#include
++
++#include "gedit-recent.h"
++#include "gedit-utils.h"
++#include "gedit-window.h"
++#include "gedit-debug.h"
++
++struct _GeditOpenDocumentSelector
++{
++ GtkBox parent_instance;
++
++ GeditWindow *window;
++ GtkWidget *search_entry;
++
++ GtkWidget *open_button;
++ GtkWidget *treeview;
++ GtkListStore *liststore;
++ GtkCellRenderer *name_renderer;
++ GtkCellRenderer *path_renderer;
++ GtkWidget *placeholder_box;
++ GtkWidget *scrolled_window;
++
++ guint populate_listbox_id;
++
++ GdkRGBA name_label_color;
++ PangoFontDescription *name_font;
++ GdkRGBA path_label_color;
++ PangoFontDescription *path_font;
++ gchar *match_markup_color;
++
++ GeditOpenDocumentSelectorStore *selector_store;
++ GList *recent_items;
++ GList *home_dir_items;
++ GList *desktop_dir_items;
++ GList *local_bookmarks_dir_items;
++ GList *file_browser_root_items;
++ GList *active_doc_dir_items;
++ GList *current_docs_items;
++ GList *all_items;
++};
++
++typedef enum
++{
++ SELECTOR_TAG_NONE,
++ SELECTOR_TAG_MATCH
++} SelectorTag;
++
++enum
++{
++ NAME_COLUMN,
++ PATH_COLUMN,
++ URI_COLUMN,
++ N_COLUMNS
++};
++
++enum
++{
++ PROP_0,
++ PROP_WINDOW,
++ LAST_PROP
++};
++
++static GParamSpec *properties[LAST_PROP];
++
++enum
++{
++ SELECTOR_FILE_ACTIVATED,
++ LAST_SIGNAL
++};
++
++static guint signals[LAST_SIGNAL];
++
++/* Value 0xFF is reserved to mark the end of the array */
++#define BYTE_ARRAY_END 0xFF
++
++#define OPEN_DOCUMENT_SELECTOR_WIDTH 400
++#define OPEN_DOCUMENT_SELECTOR_MAX_VISIBLE_ROWS 10
++
++G_DEFINE_TYPE (GeditOpenDocumentSelector, gedit_open_document_selector, GTK_TYPE_BOX)
++
++static inline const guint8 *
++get_byte_run (const guint8 *byte_array,
++ gsize *count,
++ SelectorTag *tag)
++{
++ guint8 tag_found;
++ gsize c = 1;
++
++ tag_found = *byte_array++;
++
++ while ( *byte_array != BYTE_ARRAY_END && *byte_array == tag_found)
++ {
++ c++;
++ byte_array++;
++ }
++
++ *count = c;
++ *tag = tag_found;
++
++ return ( *byte_array != BYTE_ARRAY_END) ? byte_array : NULL;
++}
++
++static gchar*
++get_markup_from_tagged_byte_array (GeditOpenDocumentSelector *selector,
++ const gchar *str,
++ const guint8 *byte_array)
++{
++ gchar *txt;
++ GString *string;
++ gchar *result_str;
++ SelectorTag tag;
++ gsize count;
++
++ string = g_string_sized_new (255);
++
++ while (TRUE)
++ {
++ byte_array = get_byte_run (byte_array, &count, &tag);
++ txt = g_markup_escape_text (str, count);
++ if (tag == SELECTOR_TAG_MATCH)
++ {
++ g_string_append (string, selector->match_markup_color);
++ g_string_append (string, txt);
++ g_string_append (string, "");
++ }
++ else
++ {
++ g_string_append (string, txt);
++ }
++
++ g_free (txt);
++
++ if (!byte_array)
++ {
++ break;
++ }
++
++ str = (const gchar *)((gsize)str + count);
++ }
++
++ result_str = g_string_free (string, FALSE);
++ return result_str;
++}
++
++static guint8 *
++get_tagged_byte_array (const gchar *uri,
++ GRegex *filter_regex)
++{
++ guint8 *byte_array;
++ gsize uri_len;
++ GMatchInfo *match_info;
++ gboolean no_match = TRUE;
++
++ g_return_val_if_fail (uri != NULL, NULL);
++
++ uri_len = strlen (uri);
++ byte_array = g_malloc0 (uri_len + 1);
++ byte_array[uri_len] = BYTE_ARRAY_END;
++
++ if (g_regex_match (filter_regex, uri, 0, &match_info) == TRUE)
++ {
++ while (g_match_info_matches (match_info) == TRUE)
++ {
++ guint8 *p;
++ gint match_len;
++ gint start_pos;
++ gint end_pos;
++
++ if (g_match_info_fetch_pos (match_info, 0, &start_pos, &end_pos) == TRUE)
++ {
++ match_len = end_pos - start_pos;
++ no_match = FALSE;
++
++ p = (guint8 *)((gsize)byte_array + start_pos);
++ memset (p, SELECTOR_TAG_MATCH, match_len);
++ }
++
++ g_match_info_next (match_info, NULL);
++ }
++ }
++
++ g_match_info_free (match_info);
++
++ if (no_match)
++ {
++ g_free (byte_array);
++ return NULL;
++ }
++
++ return byte_array;
++}
++
++static void
++get_markup_for_path_and_name (GeditOpenDocumentSelector *selector,
++ GRegex *filter_regex,
++ const gchar *src_path,
++ const gchar *src_name,
++ gchar **dst_path,
++ gchar **dst_name)
++{
++ gchar *filename;
++ gsize path_len;
++ gsize name_len;
++ gsize path_separator_len;
++ guint8 *byte_array;
++ guint8 *path_byte_array;
++ guint8 *name_byte_array;
++
++ filename = g_build_filename (src_path, src_name, NULL);
++
++ path_len = g_utf8_strlen (src_path, -1);
++ name_len = g_utf8_strlen (src_name, -1);
++ path_separator_len = g_utf8_strlen (filename, -1) - ( path_len + name_len);
++
++ byte_array = get_tagged_byte_array (filename, filter_regex);
++ if (byte_array)
++ {
++ path_byte_array = g_memdup (byte_array, path_len + 1);
++ path_byte_array[path_len] = BYTE_ARRAY_END;
++
++ /* name_byte_array is part of byte_array, so released with it */
++ name_byte_array = (guint8 *)((gsize)byte_array + path_len + path_separator_len);
++
++ *dst_path = get_markup_from_tagged_byte_array (selector, src_path, path_byte_array);
++ *dst_name = get_markup_from_tagged_byte_array (selector, src_name, name_byte_array);
++
++ g_free (byte_array);
++ g_free (path_byte_array);
++ }
++ else
++ {
++ *dst_path = g_strdup (src_path);
++ *dst_name = g_strdup (src_name);
++ }
++
++ g_free (filename);
++}
++
++static void
++create_row (GeditOpenDocumentSelector *selector,
++ const FileItem *item,
++ GRegex *filter_regex)
++{
++ GtkTreeIter iter;
++ gchar *uri;
++ gchar *dst_path;
++ gchar *dst_name;
++
++ uri =item->uri;
++
++ if (filter_regex)
++ {
++ get_markup_for_path_and_name (selector,
++ filter_regex,
++ (const gchar *)item->path,
++ (const gchar *)item->name,
++ &dst_path,
++ &dst_name);
++ }
++ else
++ {
++ dst_path = g_markup_escape_text (item->path, -1);
++ dst_name = g_markup_escape_text (item->name, -1);
++ }
++
++ gtk_list_store_append (selector->liststore, &iter);
++ gtk_list_store_set (selector->liststore, &iter,
++ URI_COLUMN, uri,
++ NAME_COLUMN, dst_name,
++ PATH_COLUMN, dst_path,
++ -1);
++
++ g_free (dst_path);
++ g_free (dst_name);
++}
++
++static gint
++sort_items_by_mru (FileItem *a,
++ FileItem *b,
++ gpointer unused G_GNUC_UNUSED)
++{
++ glong diff;
++
++ g_assert (a != NULL && b != NULL);
++ diff = b->access_time.tv_sec - a->access_time.tv_sec;
++
++ if (diff == 0)
++ {
++ return (b->access_time.tv_usec - a->access_time.tv_usec);
++ }
++ else
++ {
++ return diff;
++ }
++}
++
++static GList *
++compute_all_items_list (GeditOpenDocumentSelector *selector)
++{
++ GList *recent_items;
++ GList *home_dir_items;
++ GList *desktop_dir_items;
++ GList *local_bookmarks_dir_items;
++ GList *file_browser_root_items;
++ GList *active_doc_dir_items;
++ GList *current_docs_items;
++ GList *all_items = NULL;
++
++ /* Copy/concat the whole list */
++ recent_items = gedit_open_document_selector_copy_file_items_list ((const GList *)selector->recent_items);
++ home_dir_items = gedit_open_document_selector_copy_file_items_list ((const GList *)selector->home_dir_items);
++ desktop_dir_items = gedit_open_document_selector_copy_file_items_list ((const GList *)selector->desktop_dir_items);
++ local_bookmarks_dir_items = gedit_open_document_selector_copy_file_items_list ((const GList *)selector->local_bookmarks_dir_items);
++ file_browser_root_items = gedit_open_document_selector_copy_file_items_list ((const GList *)selector->file_browser_root_items);
++ active_doc_dir_items = gedit_open_document_selector_copy_file_items_list ((const GList *)selector->active_doc_dir_items);
++ current_docs_items = gedit_open_document_selector_copy_file_items_list ((const GList *)selector->current_docs_items);
++
++ if (selector->all_items)
++ {
++ gedit_open_document_selector_free_file_items_list (selector->all_items);
++ selector->all_items = NULL;
++ }
++
++ all_items = g_list_concat (all_items, recent_items);
++ all_items = g_list_concat (all_items, home_dir_items);
++ all_items = g_list_concat (all_items, desktop_dir_items);
++ all_items = g_list_concat (all_items, local_bookmarks_dir_items);
++ all_items = g_list_concat (all_items, file_browser_root_items);
++ all_items = g_list_concat (all_items, active_doc_dir_items);
++ all_items = g_list_concat (all_items, current_docs_items);
++
++ return all_items;
++}
++
++static GList *
++clamp_recent_items_list (GList *recent_items,
++ gint limit)
++{
++ GList *recent_items_capped = NULL;
++ GList *l;
++ FileItem *item;
++
++ l = recent_items;
++ while (limit > 0 && l != NULL)
++ {
++ item = gedit_open_document_selector_copy_fileitem_item (l->data);
++ recent_items_capped = g_list_prepend (recent_items_capped, item);
++ l = l->next;
++ limit -= 1;
++ }
++
++ recent_items_capped = g_list_reverse (recent_items_capped);
++ return recent_items_capped;
++}
++
++/* Setup the fileitem, depending uri's scheme
++ * Return a string to search in.
++ */
++static gchar *
++fileitem_setup (FileItem *item)
++{
++ gchar *scheme;
++ gchar *filename;
++ gchar *normalized_filename = NULL;
++ gchar *candidate = NULL;
++ gchar *path;
++ gchar *name;
++
++ scheme = g_uri_parse_scheme (item->uri);
++ if (g_strcmp0 (scheme, "file") == 0)
++ {
++ filename = g_filename_from_uri ((const gchar *)item->uri, NULL, NULL);
++ if (filename)
++ {
++ path = g_path_get_dirname (filename);
++ item->path = g_filename_to_utf8 (path, -1, NULL, NULL, NULL);
++ g_free (path);
++
++ name = g_path_get_basename (filename);
++ item->name = g_filename_to_utf8 (name, -1, NULL, NULL, NULL);
++ g_free (name);
++
++ normalized_filename = g_utf8_normalize (filename, -1, G_NORMALIZE_ALL);
++ g_free (filename);
++ }
++ }
++ else
++ {
++ GFile *file;
++ gchar *parse_name;
++
++ file = g_file_new_for_uri (item->uri);
++ item->path = gedit_utils_location_get_dirname_for_display (file);
++ item->name = gedit_utils_basename_for_display (file);
++ parse_name = g_file_get_parse_name (file);
++ g_object_unref (file);
++
++ normalized_filename = g_utf8_normalize (parse_name, -1, G_NORMALIZE_ALL);
++ g_free (parse_name);
++ }
++
++ if (normalized_filename)
++ {
++ candidate = g_utf8_casefold (normalized_filename, -1);
++ g_free (normalized_filename);
++ }
++
++ g_free (scheme);
++
++ return candidate;
++}
++
++static inline gboolean
++is_filter_in_candidate (const gchar *candidate,
++ const gchar *filter)
++{
++ gchar *candidate_fold;
++ gboolean ret;
++
++ g_assert (candidate != NULL);
++ g_assert (filter != NULL);
++
++ candidate_fold = g_utf8_casefold (candidate, -1);
++ ret = (strstr (candidate_fold, filter) != NULL);
++
++ g_free (candidate_fold);
++ return ret;
++}
++
++/* If filter == NULL then items are
++ * not checked against the filter.
++ */
++static GList *
++fileitem_list_filter (GList *items,
++ const gchar *filter)
++{
++ GList *new_items = NULL;
++ GList *l;
++ gchar *filter_fold = NULL;
++
++ if (filter != NULL)
++ filter_fold = g_utf8_casefold (filter, -1);
++
++ for (l = items; l != NULL; l = l->next)
++ {
++ FileItem *item;
++ gchar *candidate;
++
++ item = l->data;
++ candidate = fileitem_setup (item);
++ if (candidate != NULL)
++ {
++ if (filter == NULL || is_filter_in_candidate (candidate, filter_fold))
++ {
++ new_items = g_list_prepend (new_items,
++ gedit_open_document_selector_copy_fileitem_item (item));
++ }
++
++ g_free (candidate);
++ }
++ }
++
++ g_free (filter_fold);
++ new_items = g_list_reverse (new_items);
++ return new_items;
++}
++
++/* Remove duplicated, the HEAD of the list never change,
++ * the list passed in is modified.
++ */
++static void
++fileitem_list_remove_duplicates (GList *items)
++{
++ GList *l;
++ G_GNUC_UNUSED GList *dummy_ptr;
++
++ l = items;
++ while (l != NULL)
++ {
++ gchar *l_uri, *l1_uri;
++ GList *l1;
++
++ if ((l1 = l->next) == NULL)
++ {
++ break;
++ }
++
++ l_uri = ((FileItem *)l->data)->uri;
++ l1_uri = ((FileItem *)l1->data)->uri;
++ if (g_strcmp0 (l_uri, l1_uri) == 0)
++ {
++ gedit_open_document_selector_free_fileitem_item ((FileItem *)l1->data);
++ dummy_ptr = g_list_delete_link (items, l1);
++ }
++ else
++ {
++ l = l->next;
++ }
++ }
++}
++
++static gboolean
++real_populate_liststore (gpointer data)
++{
++ GeditOpenDocumentSelector *selector = GEDIT_OPEN_DOCUMENT_SELECTOR (data);
++ GeditOpenDocumentSelectorStore *selector_store;
++ GList *l;
++ GList *filter_items = NULL;
++ gchar *filter;
++ GRegex *filter_regex = NULL;
++
++ DEBUG_SELECTOR_TIMER_DECL
++ DEBUG_SELECTOR_TIMER_NEW
++
++ gtk_list_store_clear (selector->liststore);
++
++ selector_store = selector->selector_store;
++ filter = gedit_open_document_selector_store_get_filter (selector_store);
++ if (filter && *filter != '\0')
++ {
++ DEBUG_SELECTOR (g_print ("Selector(%p): populate liststore: all lists\n", selector););
++
++ filter_items = fileitem_list_filter (selector->all_items, (const gchar *)filter);
++ filter_items = g_list_sort_with_data (filter_items, (GCompareDataFunc)sort_items_by_mru, NULL);
++ fileitem_list_remove_duplicates (filter_items);
++
++ filter_regex = g_regex_new (filter, G_REGEX_CASELESS, 0, NULL);
++ }
++ else
++ {
++ gint recent_limit;
++ GList *recent_items;
++
++ DEBUG_SELECTOR (g_print ("Selector(%p): populate liststore: recent files list\n", selector););
++
++ recent_limit = gedit_open_document_selector_store_get_recent_limit (selector_store);
++
++ if (recent_limit > 0 )
++ {
++ recent_items = fileitem_list_filter (selector->recent_items, NULL);
++ filter_items = clamp_recent_items_list (recent_items, recent_limit);
++ gedit_open_document_selector_free_file_items_list (recent_items);
++ }
++ else
++ {
++ filter_items = fileitem_list_filter (selector->recent_items, NULL);
++ }
++ }
++
++ g_free (filter);
++
++ DEBUG_SELECTOR (g_print ("Selector(%p): populate liststore: length:%i\n",
++ selector, g_list_length (filter_items)););
++
++ /* Show the placeholder if no results, show the treeview otherwise */
++ gtk_widget_set_visible (selector->scrolled_window, (filter_items != NULL));
++ gtk_widget_set_visible (selector->placeholder_box, (filter_items == NULL));
++
++ for (l = filter_items; l != NULL; l = l->next)
++ {
++ FileItem *item;
++
++ item = l->data;
++ create_row (selector, (const FileItem *)item, filter_regex);
++ }
++
++ if (filter_regex)
++ {
++ g_regex_unref (filter_regex);
++ }
++
++ gedit_open_document_selector_free_file_items_list (filter_items);
++
++ DEBUG_SELECTOR (g_print ("Selector(%p): populate liststore: time:%lf\n\n",
++ selector, DEBUG_SELECTOR_TIMER_GET););
++ DEBUG_SELECTOR_TIMER_DESTROY
++
++ selector->populate_listbox_id = 0;
++ return G_SOURCE_REMOVE;
++}
++
++static void
++populate_liststore (GeditOpenDocumentSelector *selector)
++{
++ /* Populate requests are compressed */
++ if (selector->populate_listbox_id != 0)
++ {
++ DEBUG_SELECTOR (g_print ("Selector(%p): populate liststore: idle\n", selector););
++ return;
++ }
++
++ DEBUG_SELECTOR (g_print ("Selector(%p): populate liststore: scheduled\n", selector););
++ selector->populate_listbox_id = gdk_threads_add_idle_full (G_PRIORITY_HIGH_IDLE + 30,
++ real_populate_liststore,
++ selector,
++ NULL);
++}
++
++static gboolean
++on_treeview_key_press (GtkTreeView *treeview,
++ GdkEventKey *event,
++ GeditOpenDocumentSelector *selector)
++{
++ guint keyval;
++ gboolean is_control_pressed;
++ GtkTreeSelection *tree_selection;
++ GtkTreePath *root_path;
++ GdkModifierType modifiers;
++
++ if (gdk_event_get_keyval ((GdkEvent *)event, &keyval) == TRUE)
++ {
++ tree_selection = gtk_tree_view_get_selection (treeview);
++ root_path = gtk_tree_path_new_from_string ("0");
++
++ modifiers = gtk_accelerator_get_default_mod_mask ();
++ is_control_pressed = (event->state & modifiers) == GDK_CONTROL_MASK;
++
++ if ((keyval == GDK_KEY_Up || keyval == GDK_KEY_KP_Up) &&
++ !is_control_pressed)
++ {
++ if (gtk_tree_selection_path_is_selected (tree_selection, root_path))
++ {
++ gtk_tree_selection_unselect_all (tree_selection);
++ gtk_widget_grab_focus (selector->search_entry);
++
++ return GDK_EVENT_STOP;
++ }
++ }
++ }
++
++ return GDK_EVENT_PROPAGATE;
++}
++
++static void
++on_entry_changed (GtkEntry *entry,
++ GeditOpenDocumentSelector *selector)
++{
++ const gchar *entry_text;
++
++ entry_text = gtk_entry_get_text (entry);
++ gedit_open_document_selector_store_set_filter (selector->selector_store,
++ entry_text);
++
++ if (gtk_widget_get_mapped ( GTK_WIDGET (selector)))
++ {
++ populate_liststore (selector);
++ }
++}
++
++static void
++on_entry_activated (GtkEntry *entry,
++ GeditOpenDocumentSelector *selector)
++{
++ const gchar *entry_text;
++ GtkTreeSelection *selection;
++ gchar *uri;
++ GFile *file;
++ gchar *scheme;
++
++ entry_text = gtk_entry_get_text (entry);
++ scheme = g_uri_parse_scheme (entry_text);
++ if (!scheme)
++ {
++ const gchar *home_dir = g_get_home_dir ();
++
++ if ( home_dir != NULL && g_str_has_prefix (entry_text, "~/"))
++ {
++ uri = g_strconcat ("file://", home_dir, "/", entry_text + 2, NULL);
++ }
++ else
++ {
++ uri = g_strconcat ("file://", entry_text, NULL);
++ }
++ }
++ else
++ {
++ g_free (scheme);
++ uri = g_strdup (entry_text);
++ }
++
++ file = g_file_new_for_uri (uri);
++ if (g_file_query_exists (file, NULL))
++ {
++ DEBUG_SELECTOR (g_print ("Selector(%p): search entry activated : loading '%s'\n",
++ selector, uri););
++
++ gtk_entry_set_text (entry, "");
++ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->treeview));
++ gtk_tree_selection_unselect_all (selection);
++
++ g_signal_emit (G_OBJECT (selector), signals[SELECTOR_FILE_ACTIVATED], 0, uri);
++ }
++
++ g_object_unref (file);
++}
++
++static void
++gedit_open_document_selector_dispose (GObject *object)
++{
++ GeditOpenDocumentSelector *selector = GEDIT_OPEN_DOCUMENT_SELECTOR (object);
++
++ if (selector->populate_listbox_id != 0)
++ {
++ g_source_remove (selector->populate_listbox_id);
++ selector->populate_listbox_id = 0;
++ }
++
++ g_clear_pointer (&selector->name_font, pango_font_description_free);
++ g_clear_pointer (&selector->path_font, pango_font_description_free);
++ g_clear_pointer (&selector->match_markup_color, g_free);
++
++ if (selector->recent_items)
++ {
++ gedit_open_document_selector_free_file_items_list (selector->recent_items);
++ selector->recent_items = NULL;
++ }
++
++ if (selector->home_dir_items)
++ {
++ gedit_open_document_selector_free_file_items_list (selector->home_dir_items);
++ selector->home_dir_items = NULL;
++ }
++
++ if (selector->desktop_dir_items)
++ {
++ gedit_open_document_selector_free_file_items_list (selector->desktop_dir_items);
++ selector->desktop_dir_items = NULL;
++ }
++
++ if (selector->local_bookmarks_dir_items)
++ {
++ gedit_open_document_selector_free_file_items_list (selector->local_bookmarks_dir_items);
++ selector->local_bookmarks_dir_items = NULL;
++ }
++
++ if (selector->file_browser_root_items)
++ {
++ gedit_open_document_selector_free_file_items_list (selector->file_browser_root_items);
++ selector->file_browser_root_items = NULL;
++ }
++
++ if (selector->active_doc_dir_items)
++ {
++ gedit_open_document_selector_free_file_items_list (selector->active_doc_dir_items);
++ selector->active_doc_dir_items = NULL;
++ }
++
++ if (selector->current_docs_items)
++ {
++ gedit_open_document_selector_free_file_items_list (selector->current_docs_items);
++ selector->current_docs_items = NULL;
++ }
++
++ if (selector->all_items)
++ {
++ gedit_open_document_selector_free_file_items_list (selector->all_items);
++ selector->all_items = NULL;
++ }
++
++ G_OBJECT_CLASS (gedit_open_document_selector_parent_class)->dispose (object);
++}
++
++static void
++on_row_activated (GtkTreeView *treeview,
++ GtkTreePath *path,
++ GtkTreeViewColumn *column G_GNUC_UNUSED,
++ GeditOpenDocumentSelector *selector)
++{
++ GtkTreeModel *liststore = GTK_TREE_MODEL (selector->liststore);
++ GtkTreeSelection *selection;
++ GtkTreeIter iter;
++ gchar *uri;
++
++ g_return_if_fail (gtk_tree_model_get_iter (liststore, &iter, path));
++ gtk_tree_model_get (liststore, &iter,
++ URI_COLUMN, &uri,
++ -1);
++
++ selection = gtk_tree_view_get_selection (treeview);
++ gtk_tree_selection_unselect_all (selection);
++
++ /* Leak of uri */
++ g_signal_emit (G_OBJECT (selector), signals[SELECTOR_FILE_ACTIVATED], 0, uri);
++}
++
++static void
++update_list_cb (GeditOpenDocumentSelectorStore *selector_store,
++ GAsyncResult *res,
++ gpointer user_data G_GNUC_UNUSED)
++{
++ GList *list;
++ GError *error;
++ PushMessage *message;
++ ListType type;
++ GeditOpenDocumentSelector *selector;
++
++ list = gedit_open_document_selector_store_update_list_finish (selector_store, res, &error);
++ message = g_task_get_task_data (G_TASK (res));
++ selector = message->selector;
++ type = message->type;
++
++ DEBUG_SELECTOR (g_print ("Selector(%p): update_list_cb - type:%s, length:%i\n",
++ selector, list_type_string[type], g_list_length (list)););
++
++ switch (type)
++ {
++ case GEDIT_OPEN_DOCUMENT_SELECTOR_RECENT_FILES_LIST:
++ gedit_open_document_selector_free_file_items_list (selector->recent_items);
++ selector->recent_items = list;
++ break;
++
++ case GEDIT_OPEN_DOCUMENT_SELECTOR_HOME_DIR_LIST:
++ gedit_open_document_selector_free_file_items_list (selector->home_dir_items);
++ selector->home_dir_items = list;
++ break;
++
++ case GEDIT_OPEN_DOCUMENT_SELECTOR_DESKTOP_DIR_LIST:
++ gedit_open_document_selector_free_file_items_list (selector->desktop_dir_items);
++ selector->desktop_dir_items = list;
++ break;
++
++ case GEDIT_OPEN_DOCUMENT_SELECTOR_LOCAL_BOOKMARKS_DIR_LIST:
++ gedit_open_document_selector_free_file_items_list (selector->local_bookmarks_dir_items);
++ selector->local_bookmarks_dir_items = list;
++ break;
++
++ case GEDIT_OPEN_DOCUMENT_SELECTOR_FILE_BROWSER_ROOT_DIR_LIST:
++ gedit_open_document_selector_free_file_items_list (selector->file_browser_root_items);
++ selector->file_browser_root_items = list;
++ break;
++
++ case GEDIT_OPEN_DOCUMENT_SELECTOR_ACTIVE_DOC_DIR_LIST:
++ gedit_open_document_selector_free_file_items_list (selector->active_doc_dir_items);
++ selector->active_doc_dir_items = list;
++ break;
++
++ case GEDIT_OPEN_DOCUMENT_SELECTOR_CURRENT_DOCS_LIST:
++ gedit_open_document_selector_free_file_items_list (selector->current_docs_items);
++ selector->current_docs_items = list;
++ break;
++
++ default:
++ g_return_if_reached ();
++ }
++
++ selector->all_items = compute_all_items_list (selector);
++ populate_liststore (selector);
++}
++
++static void
++gedit_open_document_selector_constructed (GObject *object)
++{
++ GeditOpenDocumentSelector *selector = GEDIT_OPEN_DOCUMENT_SELECTOR (object);
++
++ G_OBJECT_CLASS (gedit_open_document_selector_parent_class)->constructed (object);
++
++ DEBUG_SELECTOR (g_print ("Selector(%p): constructed - ask recent file list\n", selector););
++
++ gedit_open_document_selector_store_update_list_async (selector->selector_store,
++ selector,
++ NULL,
++ (GAsyncReadyCallback)update_list_cb,
++ GEDIT_OPEN_DOCUMENT_SELECTOR_RECENT_FILES_LIST,
++ selector);
++}
++
++static void
++gedit_open_document_selector_mapped (GtkWidget *widget)
++{
++ GeditOpenDocumentSelector *selector = GEDIT_OPEN_DOCUMENT_SELECTOR (widget);
++ ListType list_number;
++
++ /* We update all the lists */
++ DEBUG_SELECTOR (g_print ("Selector(%p): mapped - ask all lists\n", selector););
++
++ for (list_number = 0; list_number < GEDIT_OPEN_DOCUMENT_SELECTOR_LIST_TYPE_NUM_OF_LISTS; list_number++)
++ {
++ gedit_open_document_selector_store_update_list_async (selector->selector_store,
++ selector,
++ NULL,
++ (GAsyncReadyCallback)update_list_cb,
++ list_number,
++ selector);
++ }
++
++ GTK_WIDGET_CLASS (gedit_open_document_selector_parent_class)->map (widget);
++}
++
++static GtkSizeRequestMode
++gedit_open_document_selector_get_request_mode (GtkWidget *widget G_GNUC_UNUSED)
++{
++ return GTK_SIZE_REQUEST_CONSTANT_SIZE;
++}
++
++static void
++gedit_open_document_selector_get_preferred_width (GtkWidget *widget G_GNUC_UNUSED,
++ gint *minimum_width,
++ gint *natural_width)
++{
++ *minimum_width = *natural_width = OPEN_DOCUMENT_SELECTOR_WIDTH;
++}
++
++static void
++gedit_open_document_selector_set_property (GObject *object,
++ guint prop_id,
++ const GValue *value,
++ GParamSpec *pspec)
++{
++ GeditOpenDocumentSelector *selector = GEDIT_OPEN_DOCUMENT_SELECTOR (object);
++
++ switch (prop_id)
++ {
++ case PROP_WINDOW:
++ selector->window = g_value_get_object (value);
++ break;
++
++ default:
++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++ break;
++ }
++}
++
++static void
++gedit_open_document_selector_get_property (GObject *object,
++ guint prop_id,
++ GValue *value,
++ GParamSpec *pspec)
++{
++ GeditOpenDocumentSelector *selector = GEDIT_OPEN_DOCUMENT_SELECTOR (object);
++
++ switch (prop_id)
++ {
++ case PROP_WINDOW:
++ g_value_set_object (value, selector->window);
++ break;
++
++ default:
++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++ break;
++ }
++}
++
++static void
++gedit_open_document_selector_file_activated (GeditOpenDocumentSelector *selector G_GNUC_UNUSED,
++ const gchar *uri G_GNUC_UNUSED)
++{
++ /* Do nothing in the default handler */
++}
++
++static void
++gedit_open_document_selector_class_init (GeditOpenDocumentSelectorClass *klass)
++{
++ GObjectClass *object_class = G_OBJECT_CLASS (klass);
++ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
++
++ object_class->constructed = gedit_open_document_selector_constructed;
++ object_class->dispose = gedit_open_document_selector_dispose;
++
++ object_class->get_property = gedit_open_document_selector_get_property;
++ object_class->set_property = gedit_open_document_selector_set_property;
++
++ widget_class->get_request_mode = gedit_open_document_selector_get_request_mode;
++ widget_class->get_preferred_width = gedit_open_document_selector_get_preferred_width;
++ widget_class->map = gedit_open_document_selector_mapped;
++
++ properties[PROP_WINDOW] =
++ g_param_spec_object ("window",
++ "Window",
++ "The GeditWindow this GeditOpenDocumentSelector is associated with",
++ GEDIT_TYPE_WINDOW,
++ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
++
++ g_object_class_install_properties (object_class, LAST_PROP, properties);
++
++ signals[SELECTOR_FILE_ACTIVATED] =
++ g_signal_new_class_handler ("file-activated",
++ G_TYPE_FROM_CLASS (klass),
++ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
++ G_CALLBACK (gedit_open_document_selector_file_activated),
++ NULL, NULL, NULL,
++ G_TYPE_NONE,
++ 1,
++ G_TYPE_STRING);
++
++ gtk_widget_class_set_template_from_resource (widget_class,
++ "/org/gnome/gedit/ui/gedit-open-document-selector.ui");
++
++ gtk_widget_class_bind_template_child (widget_class, GeditOpenDocumentSelector, open_button);
++ gtk_widget_class_bind_template_child (widget_class, GeditOpenDocumentSelector, treeview);
++ gtk_widget_class_bind_template_child (widget_class, GeditOpenDocumentSelector, placeholder_box);
++ gtk_widget_class_bind_template_child (widget_class, GeditOpenDocumentSelector, scrolled_window);
++ gtk_widget_class_bind_template_child (widget_class, GeditOpenDocumentSelector, search_entry);
++}
++
++static void
++on_treeview_allocate (GtkWidget *widget G_GNUC_UNUSED,
++ GdkRectangle *allocation G_GNUC_UNUSED,
++ GeditOpenDocumentSelector *selector)
++{
++ GeditOpenDocumentSelectorStore *selector_store;
++ GtkStyleContext *context;
++ gint name_renderer_natural_size;
++ gint path_renderer_natural_size;
++ GtkBorder padding;
++ gint ypad;
++ gint limit_capped;
++ gint treeview_height;
++ gint grid_line_width;
++ gint row_height;
++ gint recent_limit;
++
++ selector_store = selector->selector_store;
++
++ context = gtk_widget_get_style_context (selector->treeview);
++ gtk_style_context_get_padding (context,
++ gtk_style_context_get_state (context),
++ &padding);
++
++ /* Treeview height computation */
++ gtk_cell_renderer_get_preferred_height (selector->name_renderer,
++ selector->treeview,
++ NULL,
++ &name_renderer_natural_size);
++
++ gtk_cell_renderer_get_preferred_height (selector->path_renderer,
++ selector->treeview,
++ NULL,
++ &path_renderer_natural_size);
++
++ gtk_cell_renderer_get_padding (selector->name_renderer, NULL, &ypad);
++ gtk_widget_style_get (selector->treeview, "grid-line-width", &grid_line_width, NULL);
++
++ recent_limit = gedit_open_document_selector_store_get_recent_limit (selector_store);
++
++ limit_capped = (recent_limit > 0 ) ? MIN (recent_limit, OPEN_DOCUMENT_SELECTOR_MAX_VISIBLE_ROWS) :
++ OPEN_DOCUMENT_SELECTOR_MAX_VISIBLE_ROWS;
++
++ row_height = name_renderer_natural_size +
++ path_renderer_natural_size +
++ 2 * (padding.top + padding.bottom) +
++ ypad +
++ grid_line_width;
++
++ treeview_height = row_height * limit_capped;
++ gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (selector->scrolled_window),
++ treeview_height);
++ gtk_scrolled_window_set_max_content_height (GTK_SCROLLED_WINDOW (selector->scrolled_window),
++ treeview_height);
++
++ gtk_widget_set_size_request (selector->placeholder_box, -1, treeview_height);
++}
++
++static inline gchar *
++rgba_to_hex8 (GdkRGBA *rgba)
++{
++ guint red = (guint)(0.5 + CLAMP (rgba->red, 0.0, 1.0) * 255.0);
++ guint green = (guint)(0.5 + CLAMP (rgba->green, 0.0, 1.0) * 255.0);
++ guint blue = (guint)(0.5 + CLAMP (rgba->blue, 0.0, 1.0) * 255.0);
++ guint alpha = (guint)(0.5 + CLAMP (rgba->alpha, 0.0, 1.0) * 255.0);
++ gchar *str = g_strdup_printf ("#%02X%02X%02X%02X", red, green, blue, alpha);
++
++ return str;
++}
++
++static void
++on_treeview_style_updated (GtkWidget *widget,
++ GeditOpenDocumentSelector *selector)
++{
++ GtkStyleContext *context;
++ GdkRGBA match_foreground_rgba = {0.0, 0.0, 0.0, 0.0};
++ GdkRGBA match_background_rgba = {0.0, 0.0, 0.0, 0.0};
++ gchar *match_foreground_hex8;
++ gchar *match_background_hex8;
++
++ context = gtk_widget_get_style_context (widget);
++
++ /* Name label foreground and font size styling */
++ gtk_style_context_save (context);
++ gtk_style_context_add_class (context, "open-document-selector-name-label");
++
++ gtk_style_context_get_color (context,
++ gtk_style_context_get_state (context),
++ &selector->name_label_color);
++
++ g_clear_pointer (&selector->name_font, pango_font_description_free);
++ gtk_style_context_get (context,
++ gtk_style_context_get_state (context),
++ "font", &selector->name_font,
++ NULL);
++
++ gtk_style_context_restore (context);
++
++ /* Path label foreground and font size styling */
++ gtk_style_context_save (context);
++ gtk_style_context_add_class (context, "open-document-selector-path-label");
++
++ gtk_style_context_get_color (context,
++ gtk_style_context_get_state (context),
++ &selector->path_label_color);
++
++ g_clear_pointer (&selector->path_font, pango_font_description_free);
++ gtk_style_context_get (context,
++ gtk_style_context_get_state (context),
++ "font", &selector->path_font,
++ NULL);
++
++ gtk_style_context_restore (context);
++
++ /* Match styling */
++ gtk_style_context_save (context);
++ gtk_style_context_add_class (context, "open-document-selector-match");
++
++ gtk_style_context_get_color (context,
++ gtk_style_context_get_state (context),
++ &match_foreground_rgba);
++
++ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
++ gtk_style_context_get_background_color (context,
++ gtk_style_context_get_state (context),
++ &match_background_rgba);
++ G_GNUC_END_IGNORE_DEPRECATIONS;
++
++ gtk_style_context_restore (context);
++ g_free (selector->match_markup_color);
++
++ match_foreground_hex8 = rgba_to_hex8 (&match_foreground_rgba);
++ match_background_hex8 = rgba_to_hex8 (&match_background_rgba);
++
++ selector->match_markup_color = g_strdup_printf ("",
++ match_foreground_hex8,
++ match_background_hex8);
++
++ g_free (match_foreground_hex8);
++ g_free (match_background_hex8);
++}
++
++static void
++name_renderer_datafunc (GtkTreeViewColumn *column G_GNUC_UNUSED,
++ GtkCellRenderer *name_renderer G_GNUC_UNUSED,
++ GtkTreeModel *liststore G_GNUC_UNUSED,
++ GtkTreeIter *iter G_GNUC_UNUSED,
++ GeditOpenDocumentSelector *selector)
++{
++ g_object_set (selector->name_renderer, "foreground-rgba", &selector->name_label_color, NULL);
++ g_object_set (selector->name_renderer, "font-desc", selector->name_font, NULL);
++}
++
++static void
++path_renderer_datafunc (GtkTreeViewColumn *column G_GNUC_UNUSED,
++ GtkCellRenderer *path_renderer G_GNUC_UNUSED,
++ GtkTreeModel *liststore G_GNUC_UNUSED,
++ GtkTreeIter *iter G_GNUC_UNUSED,
++ GeditOpenDocumentSelector *selector)
++{
++ g_object_set (selector->path_renderer, "foreground-rgba", &selector->path_label_color, NULL);
++ g_object_set (selector->path_renderer, "font-desc", selector->path_font, NULL);
++}
++
++static void
++setup_treeview (GeditOpenDocumentSelector *selector)
++{
++ GtkTreeViewColumn *column;
++ GtkCellArea *cell_area;
++ GtkStyleContext *context;
++
++ gtk_tree_view_set_model (GTK_TREE_VIEW (selector->treeview), GTK_TREE_MODEL (selector->liststore));
++ g_object_unref(GTK_TREE_MODEL (selector->liststore));
++
++ selector->name_renderer = gtk_cell_renderer_text_new ();
++ selector->path_renderer = gtk_cell_renderer_text_new ();
++
++ g_object_set (selector->name_renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
++ g_object_set (selector->path_renderer, "ellipsize", PANGO_ELLIPSIZE_START, NULL);
++
++ column = gtk_tree_view_column_new ();
++ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
++
++ gtk_tree_view_column_pack_start (column, selector->name_renderer, TRUE);
++ gtk_tree_view_column_pack_start (column, selector->path_renderer, TRUE);
++
++ gtk_tree_view_column_set_attributes (column, selector->name_renderer, "markup", NAME_COLUMN, NULL);
++ gtk_tree_view_column_set_attributes (column, selector->path_renderer, "markup", PATH_COLUMN, NULL);
++
++ gtk_tree_view_append_column (GTK_TREE_VIEW (selector->treeview), column);
++ cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
++ gtk_orientable_set_orientation (GTK_ORIENTABLE (cell_area), GTK_ORIENTATION_VERTICAL);
++
++ context = gtk_widget_get_style_context (selector->treeview);
++ gtk_style_context_add_class (context, "open-document-selector-treeview");
++
++ gtk_tree_view_column_set_cell_data_func (column,
++ selector->name_renderer,
++ (GtkTreeCellDataFunc)name_renderer_datafunc,
++ selector,
++ NULL);
++
++ gtk_tree_view_column_set_cell_data_func (column,
++ selector->path_renderer,
++ (GtkTreeCellDataFunc)path_renderer_datafunc,
++ selector,
++ NULL);
++}
++
++static void
++gedit_open_document_selector_init (GeditOpenDocumentSelector *selector)
++{
++ gedit_debug (DEBUG_WINDOW);
++
++ gtk_widget_init_template (GTK_WIDGET (selector));
++
++ selector->selector_store = gedit_open_document_selector_store_get_default ();
++
++ selector->liststore = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
++ setup_treeview (selector);
++
++ g_signal_connect (selector->search_entry,
++ "changed",
++ G_CALLBACK (on_entry_changed),
++ selector);
++
++ g_signal_connect (selector->search_entry,
++ "activate",
++ G_CALLBACK (on_entry_activated),
++ selector);
++
++ g_signal_connect (selector->treeview,
++ "row-activated",
++ G_CALLBACK (on_row_activated),
++ selector);
++
++ g_signal_connect (selector->treeview,
++ "size-allocate",
++ G_CALLBACK (on_treeview_allocate),
++ selector);
++
++ g_signal_connect (selector->treeview,
++ "key-press-event",
++ G_CALLBACK (on_treeview_key_press),
++ selector);
++
++ g_signal_connect (selector->treeview,
++ "style-updated",
++ G_CALLBACK (on_treeview_style_updated),
++ selector);
++}
++
++GeditOpenDocumentSelector *
++gedit_open_document_selector_new (GeditWindow *window)
++{
++ g_return_val_if_fail (GEDIT_IS_WINDOW (window), NULL);
++
++ return g_object_new (GEDIT_TYPE_OPEN_DOCUMENT_SELECTOR,
++ "window", window,
++ NULL);
++}
++
++GeditWindow *
++gedit_open_document_selector_get_window (GeditOpenDocumentSelector *selector)
++{
++ g_return_val_if_fail (GEDIT_IS_OPEN_DOCUMENT_SELECTOR (selector), NULL);
++
++ return selector->window;
++}
++
++GtkWidget *
++gedit_open_document_selector_get_search_entry (GeditOpenDocumentSelector *selector)
++{
++ g_return_val_if_fail (GEDIT_IS_OPEN_DOCUMENT_SELECTOR (selector), NULL);
++
++ return selector->search_entry;
++}
++
++/* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-open-document-selector.h b/gedit/gedit-open-document-selector.h
+new file mode 100644
+index 000000000..b4d50cefd
+--- /dev/null
++++ b/gedit/gedit-open-document-selector.h
+@@ -0,0 +1,44 @@
++/*
++ * gedit-open-document-selector.h
++ * This file is part of gedit
++ *
++ * Copyright (C) 2014 - Sébastien Lafargue
++ *
++ * gedit 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.
++ *
++ * gedit 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
++ * along with gedit. If not, see .
++ */
++
++#ifndef GEDIT_OPEN_DOCUMENT_SELECTOR_H
++#define GEDIT_OPEN_DOCUMENT_SELECTOR_H
++
++#include
++#include "gedit-window.h"
++
++#include
++
++G_BEGIN_DECLS
++
++#define GEDIT_TYPE_OPEN_DOCUMENT_SELECTOR (gedit_open_document_selector_get_type ())
++
++G_DECLARE_FINAL_TYPE (GeditOpenDocumentSelector, gedit_open_document_selector, GEDIT, OPEN_DOCUMENT_SELECTOR, GtkBox)
++
++GeditOpenDocumentSelector *gedit_open_document_selector_new (GeditWindow *window);
++
++GeditWindow *gedit_open_document_selector_get_window (GeditOpenDocumentSelector *selector);
++
++GtkWidget *gedit_open_document_selector_get_search_entry (GeditOpenDocumentSelector *selector);
++
++G_END_DECLS
++
++#endif /* GEDIT_OPEN_DOCUMENT_SELECTOR_H */
++/* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-pango.c b/gedit/gedit-pango.c
+new file mode 100644
+index 000000000..0488bbcd2
+--- /dev/null
++++ b/gedit/gedit-pango.c
+@@ -0,0 +1,230 @@
++/* gedit-pango.c
++ *
++ * This file is a copy of pango_font_description_to_css from gtk gtkfontbutton.c
++ *
++ * Copyright (C) 2016 Matthias Clasen
++ *
++ * 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
++ * along with this program. If not, see .
++ */
++
++#define G_LOG_DOMAIN "gedit-pango"
++
++#include "config.h"
++
++#include "gedit-pango.h"
++
++#if PANGO_VERSION_CHECK (1, 44, 0)
++static void
++add_css_variations (GString *s,
++ const char *variations)
++{
++ const char *p;
++ const char *sep = "";
++
++ if (variations == NULL || variations[0] == '\0')
++ {
++ g_string_append (s, "normal");
++ return;
++ }
++
++ p = variations;
++ while (p && *p)
++ {
++ const char *start;
++ const char *end, *end2;
++ double value;
++ char name[5];
++
++ while (g_ascii_isspace (*p)) p++;
++
++ start = p;
++ end = strchr (p, ',');
++ if (end && (end - p < 6))
++ goto skip;
++
++ name[0] = p[0];
++ name[1] = p[1];
++ name[2] = p[2];
++ name[3] = p[3];
++ name[4] = '\0';
++
++ p += 4;
++ while (g_ascii_isspace (*p)) p++;
++ if (*p == '=') p++;
++
++ if (p - start < 5)
++ goto skip;
++
++ value = g_ascii_strtod (p, (char **) &end2);
++
++ while (end2 && g_ascii_isspace (*end2)) end2++;
++
++ if (end2 && (*end2 != ',' && *end2 != '\0'))
++ goto skip;
++
++ g_string_append_printf (s, "%s\"%s\" %g", sep, name, value);
++ sep = ", ";
++
++skip:
++ p = end ? end + 1 : NULL;
++ }
++}
++#endif
++
++/**
++ * gedit_pango_font_description_to_css:
++ *
++ * This function will generate CSS suitable for Gtk's CSS engine
++ * based on the properties of the #PangoFontDescription.
++ *
++ * Returns: (transfer full): A newly allocated string containing the
++ * CSS describing the font description.
++ */
++gchar *
++gedit_pango_font_description_to_css (const PangoFontDescription *desc)
++{
++ GString *s;
++ PangoFontMask set;
++
++ s = g_string_new ("");
++
++ set = pango_font_description_get_set_fields (desc);
++ if (set & PANGO_FONT_MASK_FAMILY)
++ {
++ g_string_append (s, "font-family: ");
++ g_string_append (s, pango_font_description_get_family (desc));
++ g_string_append (s, "; ");
++ }
++ if (set & PANGO_FONT_MASK_STYLE)
++ {
++ switch (pango_font_description_get_style (desc))
++ {
++ case PANGO_STYLE_NORMAL:
++ g_string_append (s, "font-style: normal; ");
++ break;
++ case PANGO_STYLE_OBLIQUE:
++ g_string_append (s, "font-style: oblique; ");
++ break;
++ case PANGO_STYLE_ITALIC:
++ g_string_append (s, "font-style: italic; ");
++ break;
++ default:
++ break;
++ }
++ }
++ if (set & PANGO_FONT_MASK_VARIANT)
++ {
++ switch (pango_font_description_get_variant (desc))
++ {
++ case PANGO_VARIANT_NORMAL:
++ g_string_append (s, "font-variant: normal; ");
++ break;
++ case PANGO_VARIANT_SMALL_CAPS:
++ g_string_append (s, "font-variant: small-caps; ");
++ break;
++ default:
++ break;
++ }
++ }
++ if (set & PANGO_FONT_MASK_WEIGHT)
++ {
++ switch (pango_font_description_get_weight (desc))
++ {
++ case PANGO_WEIGHT_THIN:
++ g_string_append (s, "font-weight: 100; ");
++ break;
++ case PANGO_WEIGHT_ULTRALIGHT:
++ g_string_append (s, "font-weight: 200; ");
++ break;
++ case PANGO_WEIGHT_LIGHT:
++ case PANGO_WEIGHT_SEMILIGHT:
++ g_string_append (s, "font-weight: 300; ");
++ break;
++ case PANGO_WEIGHT_BOOK:
++ case PANGO_WEIGHT_NORMAL:
++ g_string_append (s, "font-weight: 400; ");
++ break;
++ case PANGO_WEIGHT_MEDIUM:
++ g_string_append (s, "font-weight: 500; ");
++ break;
++ case PANGO_WEIGHT_SEMIBOLD:
++ g_string_append (s, "font-weight: 600; ");
++ break;
++ case PANGO_WEIGHT_BOLD:
++ g_string_append (s, "font-weight: 700; ");
++ break;
++ case PANGO_WEIGHT_ULTRABOLD:
++ g_string_append (s, "font-weight: 800; ");
++ break;
++ case PANGO_WEIGHT_HEAVY:
++ case PANGO_WEIGHT_ULTRAHEAVY:
++ g_string_append (s, "font-weight: 900; ");
++ break;
++ default:
++ break;
++ }
++ }
++ if (set & PANGO_FONT_MASK_STRETCH)
++ {
++ switch (pango_font_description_get_stretch (desc))
++ {
++ case PANGO_STRETCH_ULTRA_CONDENSED:
++ g_string_append (s, "font-stretch: ultra-condensed; ");
++ break;
++ case PANGO_STRETCH_EXTRA_CONDENSED:
++ g_string_append (s, "font-stretch: extra-condensed; ");
++ break;
++ case PANGO_STRETCH_CONDENSED:
++ g_string_append (s, "font-stretch: condensed; ");
++ break;
++ case PANGO_STRETCH_SEMI_CONDENSED:
++ g_string_append (s, "font-stretch: semi-condensed; ");
++ break;
++ case PANGO_STRETCH_NORMAL:
++ g_string_append (s, "font-stretch: normal; ");
++ break;
++ case PANGO_STRETCH_SEMI_EXPANDED:
++ g_string_append (s, "font-stretch: semi-expanded; ");
++ break;
++ case PANGO_STRETCH_EXPANDED:
++ g_string_append (s, "font-stretch: expanded; ");
++ break;
++ case PANGO_STRETCH_EXTRA_EXPANDED:
++ break;
++ case PANGO_STRETCH_ULTRA_EXPANDED:
++ g_string_append (s, "font-stretch: ultra-expanded; ");
++ break;
++ default:
++ break;
++ }
++ }
++ if (set & PANGO_FONT_MASK_SIZE)
++ {
++ g_string_append_printf (s, "font-size: %dpt; ", pango_font_description_get_size (desc) / PANGO_SCALE);
++ }
++
++#if PANGO_VERSION_CHECK (1, 44, 0)
++ if (set & PANGO_FONT_MASK_VARIATIONS)
++ {
++ const char *variations;
++
++ g_string_append (s, "font-variation-settings: ");
++ variations = pango_font_description_get_variations (desc);
++ add_css_variations (s, variations);
++ g_string_append (s, "; ");
++ }
++#endif
++
++ return g_string_free (s, FALSE);
++}
+diff --git a/gedit/gedit-pango.h b/gedit/gedit-pango.h
+new file mode 100644
+index 000000000..8c800d502
+--- /dev/null
++++ b/gedit/gedit-pango.h
+@@ -0,0 +1,28 @@
++/* gedit-pango.h
++ *
++ * 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
++ * along with this program. If not, see .
++ */
++
++#ifndef GEDIT_PANGO_H
++#define GEDIT_PANGO_H
++
++#include
++
++G_BEGIN_DECLS
++
++gchar *gedit_pango_font_description_to_css (const PangoFontDescription *font_desc);
++
++G_END_DECLS
++
++#endif /* GEDIT_PANGO_H */
+diff --git a/gedit/gedit-preferences-dialog.c b/gedit/gedit-preferences-dialog.c
+index 016baf189..ec3f53a3d 100644
+--- a/gedit/gedit-preferences-dialog.c
++++ b/gedit/gedit-preferences-dialog.c
+@@ -1,137 +1,148 @@
+ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+ /*
+ * gedit-preferences-dialog.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2001-2005 Paolo Maggi
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #include "config.h"
+
+ #include "gedit-preferences-dialog.h"
+
++#include
++#include
++#include
++
+ #include
+ #include
+-#include
++#include
+ #include
+
++#include "gedit-utils.h"
+ #include "gedit-debug.h"
++#include "gedit-document.h"
+ #include "gedit-dirs.h"
+ #include "gedit-settings.h"
++#include "gedit-utils.h"
++#include "gedit-file-chooser-dialog.h"
+
+ /*
+ * gedit-preferences dialog is a singleton since we don't
+ * want two dialogs showing an inconsistent state of the
+ * preferences.
+ * When gedit_show_preferences_dialog is called and there
+ * is already a prefs dialog dialog open, it is reparented
+ * and shown.
+ */
+
+ static GtkWidget *preferences_dialog = NULL;
+
+ #define GEDIT_SCHEME_ROW_ID_KEY "gedit-scheme-row-id"
+
+ #define GEDIT_TYPE_PREFERENCES_DIALOG (gedit_preferences_dialog_get_type())
+
+ G_DECLARE_FINAL_TYPE (GeditPreferencesDialog, gedit_preferences_dialog, GEDIT, PREFERENCES_DIALOG, GtkWindow)
+
+ enum
+ {
+ ID_COLUMN = 0,
+ NAME_COLUMN,
+ DESC_COLUMN,
+ NUM_COLUMNS
+ };
+
+ enum
+ {
+ CLOSE,
+ LAST_SIGNAL
+ };
+
+ static guint signals[LAST_SIGNAL];
+
+ struct _GeditPreferencesDialog
+ {
+ GtkWindow parent_instance;
+
+ GSettings *editor;
+ GSettings *uisettings; /* unfortunately our settings are split for historical reasons */
+
+ GtkWidget *notebook;
+
+ /* Font */
+ GtkWidget *default_font_checkbutton;
+ GtkWidget *font_button;
+ GtkWidget *font_grid;
+
+ /* Style Scheme */
+ GtkWidget *schemes_list;
+ GtkWidget *install_scheme_button;
+ GtkWidget *uninstall_scheme_button;
++ GtkWidget *schemes_scrolled_window;
+ GtkWidget *schemes_toolbar;
+- GtkFileChooserNative *
+- install_scheme_file_chooser;
++
++ GeditFileChooserDialog *
++ install_scheme_file_schooser;
+
+ /* Tabs */
+ GtkWidget *tabs_width_spinbutton;
+ GtkWidget *insert_spaces_checkbutton;
+
+ /* Auto indentation */
+ GtkWidget *auto_indent_checkbutton;
+
+ /* Text Wrapping */
+ GtkWidget *wrap_text_checkbutton;
+ GtkWidget *split_checkbutton;
+
+ /* File Saving */
+ GtkWidget *backup_copy_checkbutton;
+ GtkWidget *auto_save_checkbutton;
+ GtkWidget *auto_save_spinbutton;
+
+ GtkWidget *display_line_numbers_checkbutton;
+ GtkWidget *display_statusbar_checkbutton;
++ GtkWidget *display_overview_map_checkbutton;
+ GtkWidget *display_grid_checkbutton;
+
+ /* Right margin */
+ GtkWidget *right_margin_checkbutton;
+ GtkWidget *right_margin_position_grid;
+ GtkWidget *right_margin_position_spinbutton;
+
+ /* Highlighting */
+ GtkWidget *highlight_current_line_checkbutton;
+ GtkWidget *bracket_matching_checkbutton;
+
+ /* Plugin manager */
+ GtkWidget *plugin_manager;
+ };
+
+ G_DEFINE_TYPE (GeditPreferencesDialog, gedit_preferences_dialog, GTK_TYPE_WINDOW)
+
+ static void
+ gedit_preferences_dialog_dispose (GObject *object)
+ {
+ GeditPreferencesDialog *dlg = GEDIT_PREFERENCES_DIALOG (object);
+
+ g_clear_object (&dlg->editor);
+ g_clear_object (&dlg->uisettings);
+
+ G_OBJECT_CLASS (gedit_preferences_dialog_parent_class)->dispose (object);
+ }
+
+ static void
+ gedit_preferences_dialog_close (GeditPreferencesDialog *dialog)
+@@ -143,77 +154,79 @@ static void
+ gedit_preferences_dialog_class_init (GeditPreferencesDialogClass *klass)
+ {
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GtkBindingSet *binding_set;
+
+ /* Otherwise libpeas-gtk might not be linked */
+ g_type_ensure (PEAS_GTK_TYPE_PLUGIN_MANAGER);
+
+ object_class->dispose = gedit_preferences_dialog_dispose;
+
+ signals[CLOSE] =
+ g_signal_new_class_handler ("close",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_CALLBACK (gedit_preferences_dialog_close),
+ NULL, NULL, NULL,
+ G_TYPE_NONE,
+ 0);
+
+ binding_set = gtk_binding_set_by_class (klass);
+ gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "close", 0);
+
+ /* Bind class to template */
+ gtk_widget_class_set_template_from_resource (widget_class,
+ "/org/gnome/gedit/ui/gedit-preferences-dialog.ui");
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, notebook);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, display_line_numbers_checkbutton);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, display_statusbar_checkbutton);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, display_grid_checkbutton);
++ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, display_overview_map_checkbutton);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, right_margin_checkbutton);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, right_margin_position_grid);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, right_margin_position_spinbutton);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, highlight_current_line_checkbutton);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, bracket_matching_checkbutton);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, wrap_text_checkbutton);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, split_checkbutton);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, tabs_width_spinbutton);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, insert_spaces_checkbutton);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, auto_indent_checkbutton);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, backup_copy_checkbutton);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, auto_save_checkbutton);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, auto_save_spinbutton);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, default_font_checkbutton);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, font_button);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, font_grid);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, schemes_list);
++ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, schemes_scrolled_window);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, install_scheme_button);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, uninstall_scheme_button);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, schemes_toolbar);
+ gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, plugin_manager);
+ }
+
+ static void
+ setup_editor_page (GeditPreferencesDialog *dlg)
+ {
+ gedit_debug (DEBUG_PREFS);
+
+ /* Connect signal */
+ g_settings_bind (dlg->editor,
+ GEDIT_SETTINGS_TABS_SIZE,
+ dlg->tabs_width_spinbutton,
+ "value",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+ g_settings_bind (dlg->editor,
+ GEDIT_SETTINGS_INSERT_SPACES,
+ dlg->insert_spaces_checkbutton,
+ "active",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+ g_settings_bind (dlg->editor,
+ GEDIT_SETTINGS_AUTO_INDENT,
+ dlg->auto_indent_checkbutton,
+ "active",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+ g_settings_bind (dlg->editor,
+ GEDIT_SETTINGS_CREATE_BACKUP_COPY,
+ dlg->backup_copy_checkbutton,
+@@ -359,488 +372,554 @@ setup_view_page (GeditPreferencesDialog *dlg)
+ gtk_toggle_button_set_inconsistent (
+ GTK_TOGGLE_BUTTON (dlg->split_checkbutton), TRUE);
+ }
+
+ gtk_toggle_button_set_active (
+ GTK_TOGGLE_BUTTON (dlg->right_margin_checkbutton),
+ display_right_margin);
+ gtk_toggle_button_set_active (
+ GTK_TOGGLE_BUTTON (dlg->display_grid_checkbutton),
+ background_pattern == GTK_SOURCE_BACKGROUND_PATTERN_TYPE_GRID);
+
+ /* Set widgets sensitivity */
+ gtk_widget_set_sensitive (dlg->split_checkbutton,
+ (wrap_mode != GTK_WRAP_NONE));
+
+ g_settings_bind (dlg->editor,
+ GEDIT_SETTINGS_DISPLAY_LINE_NUMBERS,
+ dlg->display_line_numbers_checkbutton,
+ "active",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+ g_settings_bind (dlg->editor,
+ GEDIT_SETTINGS_HIGHLIGHT_CURRENT_LINE,
+ dlg->highlight_current_line_checkbutton,
+ "active",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+ g_settings_bind (dlg->uisettings,
+ GEDIT_SETTINGS_STATUSBAR_VISIBLE,
+ dlg->display_statusbar_checkbutton,
+ "active",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
++ g_settings_bind (dlg->editor,
++ GEDIT_SETTINGS_DISPLAY_OVERVIEW_MAP,
++ dlg->display_overview_map_checkbutton,
++ "active",
++ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+ g_settings_bind (dlg->editor,
+ GEDIT_SETTINGS_DISPLAY_RIGHT_MARGIN,
+ dlg->right_margin_checkbutton,
+ "active",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+ g_settings_bind (dlg->editor,
+ GEDIT_SETTINGS_DISPLAY_RIGHT_MARGIN,
+ dlg->right_margin_position_grid,
+ "sensitive",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+ g_settings_bind (dlg->editor,
+ GEDIT_SETTINGS_RIGHT_MARGIN_POSITION,
+ dlg->right_margin_position_spinbutton,
+ "value",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+ g_settings_bind (dlg->editor,
+ GEDIT_SETTINGS_AUTO_SAVE_INTERVAL,
+ dlg->auto_save_spinbutton,
+ "value",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+ g_signal_connect (dlg->wrap_text_checkbutton,
+ "toggled",
+ G_CALLBACK (wrap_mode_checkbutton_toggled),
+ dlg);
+ g_signal_connect (dlg->split_checkbutton,
+ "toggled",
+ G_CALLBACK (wrap_mode_checkbutton_toggled),
+ dlg);
+ g_signal_connect (dlg->display_grid_checkbutton,
+ "toggled",
+ G_CALLBACK (grid_checkbutton_toggled),
+ dlg);
+ }
+
+ static void
+ setup_font_colors_page_font_section (GeditPreferencesDialog *dlg)
+ {
+ GeditSettings *settings;
+ gchar *system_font = NULL;
+ gchar *label;
+
+ gedit_debug (DEBUG_PREFS);
+
+ gtk_widget_set_tooltip_text (dlg->font_button,
+ _("Click on this button to select the font to be used by the editor"));
+
+ /* Get values */
+ settings = _gedit_settings_get_singleton ();
+- system_font = _gedit_settings_get_system_font (settings);
++ system_font = gedit_settings_get_system_font (settings);
+
+ label = g_strdup_printf(_("_Use the system fixed width font (%s)"),
+ system_font);
+ gtk_button_set_label (GTK_BUTTON (dlg->default_font_checkbutton),
+ label);
+ g_free (system_font);
+ g_free (label);
+
+ /* Bind settings */
+ g_settings_bind (dlg->editor,
+ GEDIT_SETTINGS_USE_DEFAULT_FONT,
+ dlg->default_font_checkbutton,
+ "active",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+ g_settings_bind (dlg->editor,
+ GEDIT_SETTINGS_USE_DEFAULT_FONT,
+ dlg->font_grid,
+ "sensitive",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET | G_SETTINGS_BIND_INVERT_BOOLEAN);
+ g_settings_bind (dlg->editor,
+ GEDIT_SETTINGS_EDITOR_FONT,
+ dlg->font_button,
+ "font-name",
+ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+ }
+
+ static void
+-update_style_scheme_buttons_sensisitivity (GeditPreferencesDialog *dlg)
++set_buttons_sensisitivity_according_to_scheme (GeditPreferencesDialog *dlg,
++ GtkSourceStyleScheme *scheme)
+ {
+- GtkSourceStyleScheme *selected_style_scheme;
+ gboolean editable = FALSE;
+
+- selected_style_scheme = gtk_source_style_scheme_chooser_get_style_scheme (GTK_SOURCE_STYLE_SCHEME_CHOOSER (dlg->schemes_list));
+-
+- if (selected_style_scheme != NULL)
++ if (scheme != NULL)
+ {
+ const gchar *filename;
+
+- filename = gtk_source_style_scheme_get_filename (selected_style_scheme);
++ filename = gtk_source_style_scheme_get_filename (scheme);
+ if (filename != NULL)
+ {
+ editable = g_str_has_prefix (filename, gedit_dirs_get_user_styles_dir ());
+ }
+ }
+
+- gtk_widget_set_sensitive (dlg->uninstall_scheme_button, editable);
++ gtk_widget_set_sensitive (dlg->uninstall_scheme_button,
++ editable);
+ }
+
+ static void
+-style_scheme_notify_cb (GtkSourceStyleSchemeChooser *chooser,
+- GParamSpec *pspec,
+- GeditPreferencesDialog *dlg)
++style_scheme_changed (GtkSourceStyleSchemeChooser *chooser,
++ GParamSpec *pspec,
++ GeditPreferencesDialog *dlg)
+ {
+- update_style_scheme_buttons_sensisitivity (dlg);
++ GtkSourceStyleScheme *scheme;
++ const gchar *id;
++
++ scheme = gtk_source_style_scheme_chooser_get_style_scheme (chooser);
++ id = gtk_source_style_scheme_get_id (scheme);
++
++ g_settings_set_string (dlg->editor, GEDIT_SETTINGS_SCHEME, id);
++ set_buttons_sensisitivity_according_to_scheme (dlg, scheme);
+ }
+
+-static GFile *
+-get_user_style_scheme_destination_file (GFile *src_file)
++static GtkSourceStyleScheme *
++get_default_color_scheme (GeditPreferencesDialog *dlg)
+ {
+- gchar *basename;
+- const gchar *styles_dir;
+- GFile *dest_file;
++ GtkSourceStyleSchemeManager *manager;
++ GtkSourceStyleScheme *scheme = NULL;
++ gchar *pref_id;
+
+- basename = g_file_get_basename (src_file);
+- g_return_val_if_fail (basename != NULL, NULL);
++ manager = gtk_source_style_scheme_manager_get_default ();
+
+- styles_dir = gedit_dirs_get_user_styles_dir ();
+- dest_file = g_file_new_build_filename (styles_dir, basename, NULL);
++ pref_id = g_settings_get_string (dlg->editor,
++ GEDIT_SETTINGS_SCHEME);
+
+- g_free (basename);
+- return dest_file;
++ scheme = gtk_source_style_scheme_manager_get_scheme (manager,
++ pref_id);
++ g_free (pref_id);
++
++ if (scheme == NULL)
++ {
++ /* Fall-back to classic style scheme */
++ scheme = gtk_source_style_scheme_manager_get_scheme (manager,
++ "classic");
++ }
++
++ return scheme;
+ }
+
+-/* Returns: whether @src_file has been correctly copied to @dest_file. */
++/*
++ * file_copy:
++ * @name: a pointer to a %NULL-terminated string, that names
++ * the file to be copied, in the GLib file name encoding
++ * @dest_name: a pointer to a %NULL-terminated string, that is the
++ * name for the destination file, in the GLib file name encoding
++ * @error: return location for a #GError, or %NULL
++ *
++ * Copies file @name to @dest_name.
++ *
++ * If the call was successful, it returns %TRUE. If the call was not
++ * successful, it returns %FALSE and sets @error. The error domain
++ * is #G_FILE_ERROR. Possible error
++ * codes are those in the #GFileError enumeration.
++ *
++ * Return value: %TRUE on success, %FALSE otherwise.
++ */
+ static gboolean
+-copy_file (GFile *src_file,
+- GFile *dest_file,
+- GError **error)
++file_copy (const gchar *name,
++ const gchar *dest_name,
++ GError **error)
+ {
+- if (g_file_equal (src_file, dest_file))
++ gchar *contents;
++ gsize length;
++ gchar *dest_dir;
++
++ /* FIXME - Paolo (Aug. 13, 2007):
++ * Since the style scheme files are relatively small, we can implement
++ * file copy getting all the content of the source file in a buffer and
++ * then write the content to the destination file. In this way we
++ * can use the g_file_get_contents and g_file_set_contents and avoid to
++ * write custom code to copy the file (with sane error management).
++ * If needed we can improve this code later. */
++
++ g_return_val_if_fail (name != NULL, FALSE);
++ g_return_val_if_fail (dest_name != NULL, FALSE);
++ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
++
++ /* Note: we allow to copy a file to itself since this is not a problem
++ * in our use case */
++
++ /* Ensure the destination directory exists */
++ dest_dir = g_path_get_dirname (dest_name);
++
++ errno = 0;
++ if (g_mkdir_with_parents (dest_dir, 0755) != 0)
+ {
++ gint save_errno = errno;
++ gchar *display_filename = g_filename_display_name (dest_dir);
++
++ g_set_error (error,
++ G_FILE_ERROR,
++ g_file_error_from_errno (save_errno),
++ _("Directory “%s” could not be created: g_mkdir_with_parents() failed: %s"),
++ display_filename,
++ g_strerror (save_errno));
++
++ g_free (dest_dir);
++ g_free (display_filename);
++
+ return FALSE;
+ }
+
+- if (!tepl_utils_create_parent_directories (dest_file, NULL, error))
++ g_free (dest_dir);
++
++ if (!g_file_get_contents (name, &contents, &length, error))
++ return FALSE;
++
++ if (!g_file_set_contents (dest_name, contents, length, error))
+ {
++ g_free (contents);
+ return FALSE;
+ }
+
+- return g_file_copy (src_file,
+- dest_file,
+- G_FILE_COPY_OVERWRITE | G_FILE_COPY_TARGET_DEFAULT_PERMS,
+- NULL, /* cancellable */
+- NULL, NULL, /* progress callback */
+- error);
++ g_free (contents);
++
++ return TRUE;
+ }
+
+-/* Get the style scheme ID of @user_style_scheme_file if it has been correctly
+- * installed and @user_style_scheme_file is a valid style scheme file.
++/*
++ * install_style_scheme:
++ * @manager: a #GtkSourceStyleSchemeManager
++ * @fname: the file name of the style scheme to be installed
++ *
++ * Install a new user scheme.
++ * This function copies @fname in #GEDIT_STYLES_DIR and ask the style manager to
++ * recompute the list of available style schemes. It then checks if a style
++ * scheme with the right file name exists.
++ *
++ * If the call was succesful, it returns the id of the installed scheme
++ * otherwise %NULL.
++ *
++ * Return value: the id of the installed scheme, %NULL otherwise.
+ */
+-static const gchar *
+-get_style_scheme_id_after_installing_user_style_scheme (GFile *user_style_scheme_file)
++static GtkSourceStyleScheme *
++install_style_scheme (const gchar *fname)
+ {
+ GtkSourceStyleSchemeManager *manager;
+- const gchar * const *scheme_ids;
+- gint i;
++ gchar *new_file_name = NULL;
++ gchar *dirname;
++ const gchar *styles_dir;
++ GError *error = NULL;
++ gboolean copied = FALSE;
++ const gchar * const *ids;
++
++ g_return_val_if_fail (fname != NULL, NULL);
+
+ manager = gtk_source_style_scheme_manager_get_default ();
+- gtk_source_style_scheme_manager_force_rescan (manager);
+
+- scheme_ids = gtk_source_style_scheme_manager_get_scheme_ids (manager);
++ dirname = g_path_get_dirname (fname);
++ styles_dir = gedit_dirs_get_user_styles_dir ();
+
+- for (i = 0; scheme_ids != NULL && scheme_ids[i] != NULL; i++)
++ if (strcmp (dirname, styles_dir) != 0)
+ {
+- const gchar *cur_scheme_id = scheme_ids[i];
+- GtkSourceStyleScheme *scheme;
+- const gchar *filename;
+- GFile *scheme_file;
++ gchar *basename;
+
+- scheme = gtk_source_style_scheme_manager_get_scheme (manager, cur_scheme_id);
+- filename = gtk_source_style_scheme_get_filename (scheme);
+- if (filename == NULL)
+- {
+- continue;
+- }
++ basename = g_path_get_basename (fname);
++ new_file_name = g_build_filename (styles_dir, basename, NULL);
++ g_free (basename);
+
+- scheme_file = g_file_new_for_path (filename);
+- if (g_file_equal (scheme_file, user_style_scheme_file))
++ /* Copy the style scheme file into GEDIT_STYLES_DIR */
++ if (!file_copy (fname, new_file_name, &error))
+ {
+- g_object_unref (scheme_file);
+- return cur_scheme_id;
++ g_free (new_file_name);
++ g_free (dirname);
++
++ g_message ("Cannot install style scheme:\n%s",
++ error->message);
++
++ g_error_free (error);
++
++ return NULL;
+ }
+
+- g_object_unref (scheme_file);
++ copied = TRUE;
++ }
++ else
++ {
++ new_file_name = g_strdup (fname);
+ }
+
+- return NULL;
+-}
+-
+-/* Returns: (nullable): the installed style scheme ID, or %NULL on failure. */
+-static const gchar *
+-install_style_scheme (GFile *src_file,
+- GError **error)
+-{
+- GFile *dest_file;
+- gboolean copied;
+- const gchar *installed_style_scheme_id = NULL;
+- GError *my_error = NULL;
++ g_free (dirname);
+
+- g_return_val_if_fail (G_IS_FILE (src_file), NULL);
+- g_return_val_if_fail (error == NULL || *error == NULL, NULL);
++ /* Reload the available style schemes */
++ gtk_source_style_scheme_manager_force_rescan (manager);
+
+- dest_file = get_user_style_scheme_destination_file (src_file);
+- g_return_val_if_fail (dest_file != NULL, NULL);
++ /* Check the new style scheme has been actually installed */
++ ids = gtk_source_style_scheme_manager_get_scheme_ids (manager);
+
+- copied = copy_file (src_file, dest_file, &my_error);
+- if (my_error != NULL)
++ while (*ids != NULL)
+ {
+- g_propagate_error (error, my_error);
+- g_object_unref (dest_file);
+- return NULL;
+- }
++ GtkSourceStyleScheme *scheme;
++ const gchar *filename;
+
+- installed_style_scheme_id = get_style_scheme_id_after_installing_user_style_scheme (dest_file);
++ scheme = gtk_source_style_scheme_manager_get_scheme (manager, *ids);
+
+- if (installed_style_scheme_id == NULL && copied)
+- {
+- /* The style scheme has not been correctly installed. */
+- g_file_delete (dest_file, NULL, &my_error);
+- if (my_error != NULL)
+- {
+- gchar *dest_file_parse_name = g_file_get_parse_name (dest_file);
++ filename = gtk_source_style_scheme_get_filename (scheme);
+
+- g_warning ("Failed to delete the file “%s”: %s",
+- dest_file_parse_name,
+- my_error->message);
++ if (filename && (strcmp (filename, new_file_name) == 0))
++ {
++ /* The style scheme has been correctly installed */
++ g_free (new_file_name);
+
+- g_free (dest_file_parse_name);
+- g_clear_error (&my_error);
++ return scheme;
+ }
++ ++ids;
+ }
+
+- g_object_unref (dest_file);
+- return installed_style_scheme_id;
++ /* The style scheme has not been correctly installed */
++ if (copied)
++ g_unlink (new_file_name);
++
++ g_free (new_file_name);
++
++ return NULL;
+ }
+
+-/*
++/**
+ * uninstall_style_scheme:
++ * @manager: a #GtkSourceStyleSchemeManager
+ * @scheme: a #GtkSourceStyleScheme
+ *
+ * Uninstall a user scheme.
+ *
+- * Returns: %TRUE on success, %FALSE otherwise.
++ * If the call was succesful, it returns %TRUE
++ * otherwise %FALSE.
++ *
++ * Return value: %TRUE on success, %FALSE otherwise.
+ */
+ static gboolean
+ uninstall_style_scheme (GtkSourceStyleScheme *scheme)
+ {
+ GtkSourceStyleSchemeManager *manager;
+ const gchar *filename;
+
+ g_return_val_if_fail (GTK_SOURCE_IS_STYLE_SCHEME (scheme), FALSE);
+
+ manager = gtk_source_style_scheme_manager_get_default ();
+
+ filename = gtk_source_style_scheme_get_filename (scheme);
+ if (filename == NULL)
+ return FALSE;
+
+ if (g_unlink (filename) == -1)
+ return FALSE;
+
+ /* Reload the available style schemes */
+ gtk_source_style_scheme_manager_force_rescan (manager);
+
+ return TRUE;
+ }
+
+ static void
+-add_scheme_chooser_response_cb (GtkFileChooserNative *chooser,
+- gint response_id,
+- GeditPreferencesDialog *dialog)
++add_scheme_chooser_response_cb (GeditFileChooserDialog *chooser,
++ gint res_id,
++ GeditPreferencesDialog *dlg)
+ {
+ GFile *file;
+- const gchar *scheme_id;
+- GeditSettings *settings;
+- GSettings *editor_settings;
+- GError *error = NULL;
++ gchar *filename;
++ GtkSourceStyleScheme *scheme;
+
+- if (response_id != GTK_RESPONSE_ACCEPT)
++ if (res_id != GTK_RESPONSE_ACCEPT)
+ {
++ gedit_file_chooser_dialog_hide (chooser);
+ return;
+ }
+
+- file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (chooser));
++ file = gedit_file_chooser_dialog_get_file (chooser);
++
+ if (file == NULL)
+ {
+ return;
+ }
+
+- scheme_id = install_style_scheme (file, &error);
++ filename = g_file_get_path (file);
+ g_object_unref (file);
+
+- if (scheme_id == NULL)
++ if (filename == NULL)
+ {
+- if (error != NULL)
+- {
+- tepl_utils_show_warning_dialog (GTK_WINDOW (dialog),
+- _("The selected color scheme cannot be installed: %s"),
+- error->message);
+- }
+- else
+- {
+- tepl_utils_show_warning_dialog (GTK_WINDOW (dialog),
+- _("The selected color scheme cannot be installed."));
+- }
++ return;
++ }
++
++ gedit_file_chooser_dialog_hide (chooser);
++
++ scheme = install_style_scheme (filename);
++ g_free (filename);
++
++ if (scheme == NULL)
++ {
++ gedit_warning (GTK_WINDOW (dlg),
++ _("The selected color scheme cannot be installed."));
+
+- g_clear_error (&error);
+ return;
+ }
+
+- settings = _gedit_settings_get_singleton ();
+- editor_settings = _gedit_settings_peek_editor_settings (settings);
+- g_settings_set_string (editor_settings, GEDIT_SETTINGS_SCHEME, scheme_id);
++ g_settings_set_string (dlg->editor, GEDIT_SETTINGS_SCHEME,
++ gtk_source_style_scheme_get_id (scheme));
++
++ set_buttons_sensisitivity_according_to_scheme (dlg, scheme);
+ }
+
+ static void
+ install_scheme_clicked (GtkButton *button,
+- GeditPreferencesDialog *dialog)
++ GeditPreferencesDialog *dlg)
+ {
+- GtkFileChooserNative *chooser;
+- GtkFileFilter *scheme_filter;
+- GtkFileFilter *all_filter;
++ GeditFileChooserDialog *chooser;
+
+- if (dialog->install_scheme_file_chooser != NULL)
++ if (dlg->install_scheme_file_schooser != NULL)
+ {
+- gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog->install_scheme_file_chooser));
++ gedit_file_chooser_dialog_show (dlg->install_scheme_file_schooser);
+ return;
+ }
+
+- chooser = gtk_file_chooser_native_new (_("Add Color Scheme"),
+- GTK_WINDOW (dialog),
+- GTK_FILE_CHOOSER_ACTION_OPEN,
+- _("_Add Scheme"),
+- _("_Cancel"));
++ chooser = gedit_file_chooser_dialog_create (_("Add Scheme"),
++ GTK_WINDOW (dlg),
++ GEDIT_FILE_CHOOSER_FLAG_OPEN,
++ _("_Cancel"),
++ _("A_dd Scheme"));
+
+ /* Filters */
+- scheme_filter = gtk_file_filter_new ();
+- gtk_file_filter_set_name (scheme_filter, _("Color Scheme Files"));
+- gtk_file_filter_add_pattern (scheme_filter, "*.xml");
+- gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), scheme_filter);
+-
+- all_filter = gtk_file_filter_new ();
+- gtk_file_filter_set_name (all_filter, _("All Files"));
+- gtk_file_filter_add_pattern (all_filter, "*");
+- gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), all_filter);
++ gedit_file_chooser_dialog_add_pattern_filter (chooser,
++ _("Color Scheme Files"),
++ "*.xml");
+
+- gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (chooser), scheme_filter);
++ gedit_file_chooser_dialog_add_pattern_filter (chooser,
++ _("All Files"),
++ "*");
+
+ g_signal_connect (chooser,
+ "response",
+ G_CALLBACK (add_scheme_chooser_response_cb),
+- dialog);
++ dlg);
+
+- g_set_weak_pointer (&dialog->install_scheme_file_chooser, chooser);
++ dlg->install_scheme_file_schooser = chooser;
+
+- gtk_native_dialog_show (GTK_NATIVE_DIALOG (chooser));
++ g_object_add_weak_pointer (G_OBJECT (chooser),
++ (gpointer) &dlg->install_scheme_file_schooser);
++
++ gedit_file_chooser_dialog_show (chooser);
+ }
+
+ static void
+ uninstall_scheme_clicked (GtkButton *button,
+ GeditPreferencesDialog *dlg)
+ {
+ GtkSourceStyleScheme *scheme;
+- GtkSourceStyleScheme *new_selected_scheme;
+
+ scheme = gtk_source_style_scheme_chooser_get_style_scheme (GTK_SOURCE_STYLE_SCHEME_CHOOSER (dlg->schemes_list));
+
+- if (scheme == NULL)
+- {
+- return;
+- }
+-
+ if (!uninstall_style_scheme (scheme))
+ {
+- tepl_utils_show_warning_dialog (GTK_WINDOW (dlg),
+- _("Could not remove color scheme “%s”."),
+- gtk_source_style_scheme_get_name (scheme));
+- return;
+- }
+-
+- new_selected_scheme = gtk_source_style_scheme_chooser_get_style_scheme (GTK_SOURCE_STYLE_SCHEME_CHOOSER (dlg->schemes_list));
+- if (new_selected_scheme == NULL)
+- {
+- GeditSettings *settings;
+- GSettings *editor_settings;
+-
+- settings = _gedit_settings_get_singleton ();
+- editor_settings = _gedit_settings_peek_editor_settings (settings);
+-
+- g_settings_reset (editor_settings, GEDIT_SETTINGS_SCHEME);
++ gedit_warning (GTK_WINDOW (dlg),
++ _("Could not remove color scheme “%s”."),
++ gtk_source_style_scheme_get_name (scheme));
+ }
+ }
+
+ static void
+ setup_font_colors_page_style_scheme_section (GeditPreferencesDialog *dlg)
+ {
+ GtkStyleContext *context;
+- GeditSettings *settings;
+- GSettings *editor_settings;
++ GtkSourceStyleScheme *scheme;
+
+ gedit_debug (DEBUG_PREFS);
+
+- /* junction between the schemes list and the toolbar */
+- context = gtk_widget_get_style_context (dlg->schemes_list);
++ scheme = get_default_color_scheme (dlg);
++
++ /* junction between the scrolled window and the toolbar */
++ context = gtk_widget_get_style_context (dlg->schemes_scrolled_window);
+ gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
+ context = gtk_widget_get_style_context (dlg->schemes_toolbar);
+ gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
+
+ /* Connect signals */
+ g_signal_connect (dlg->schemes_list,
+ "notify::style-scheme",
+- G_CALLBACK (style_scheme_notify_cb),
++ G_CALLBACK (style_scheme_changed),
+ dlg);
+ g_signal_connect (dlg->install_scheme_button,
+ "clicked",
+ G_CALLBACK (install_scheme_clicked),
+ dlg);
+ g_signal_connect (dlg->uninstall_scheme_button,
+ "clicked",
+ G_CALLBACK (uninstall_scheme_clicked),
+ dlg);
+
+- settings = _gedit_settings_get_singleton ();
+- editor_settings = _gedit_settings_peek_editor_settings (settings);
+- g_settings_bind (editor_settings, GEDIT_SETTINGS_SCHEME,
+- dlg->schemes_list, "tepl-style-scheme-id",
+- G_SETTINGS_BIND_DEFAULT);
++ gtk_source_style_scheme_chooser_set_style_scheme (GTK_SOURCE_STYLE_SCHEME_CHOOSER (dlg->schemes_list),
++ scheme);
+
+- update_style_scheme_buttons_sensisitivity (dlg);
++ /* Set initial widget sensitivity */
++ set_buttons_sensisitivity_according_to_scheme (dlg, scheme);
+ }
+
+ static void
+ setup_font_colors_page (GeditPreferencesDialog *dlg)
+ {
+ setup_font_colors_page_font_section (dlg);
+ setup_font_colors_page_style_scheme_section (dlg);
+ }
+
+ static void
+ setup_plugins_page (GeditPreferencesDialog *dlg)
+ {
+ gtk_widget_show_all (dlg->plugin_manager);
+ }
+
+ static void
+ gedit_preferences_dialog_init (GeditPreferencesDialog *dlg)
+ {
+ gedit_debug (DEBUG_PREFS);
+
+ dlg->editor = g_settings_new ("org.gnome.gedit.preferences.editor");
+ dlg->uisettings = g_settings_new ("org.gnome.gedit.preferences.ui");
+
+ gtk_widget_init_template (GTK_WIDGET (dlg));
+
+ setup_editor_page (dlg);
+ setup_view_page (dlg);
+ setup_font_colors_page (dlg);
+ setup_plugins_page (dlg);
+ }
+diff --git a/gedit/gedit-print-job.c b/gedit/gedit-print-job.c
+index 6083669f9..e6c1dcdcb 100644
+--- a/gedit/gedit-print-job.c
++++ b/gedit/gedit-print-job.c
+@@ -1,56 +1,56 @@
+ /*
+ * gedit-print-job.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2000-2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002-2008 Paolo Maggi
+ * Copyright (C) 2015 Sébastien Wilmet
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #include "gedit-print-job.h"
+
+ #include
+-#include
++#include
+
+ #include "gedit-debug.h"
+ #include "gedit-document-private.h"
+ #include "gedit-print-preview.h"
+ #include "gedit-utils.h"
+ #include "gedit-dirs.h"
+ #include "gedit-settings.h"
+
+ struct _GeditPrintJob
+ {
+ GObject parent_instance;
+
+ GSettings *gsettings;
+
+ GeditView *view;
+
+ GtkPrintOperation *operation;
+ GtkSourcePrintCompositor *compositor;
+
+ GtkWidget *preview;
+
+ gchar *status_string;
+ gdouble progress;
+
+ /* Widgets part of the custom print preferences widget.
+ * These pointers are valid just when the dialog is displayed.
+ */
+ GtkToggleButton *syntax_checkbutton;
+ GtkToggleButton *page_header_checkbutton;
+ GtkToggleButton *line_numbers_checkbutton;
+@@ -508,61 +508,61 @@ create_compositor (GeditPrintJob *job)
+ "tab-width", tab_width,
+ "highlight-syntax", syntax_hl,
+ "wrap-mode", wrap_mode,
+ "print-line-numbers", print_line_numbers,
+ "print-header", print_header,
+ "print-footer", FALSE,
+ "body-font-name", print_font_body,
+ "line-numbers-font-name", print_font_numbers,
+ "header-font-name", print_font_header,
+ NULL));
+
+ margin = g_settings_get_double (job->gsettings, GEDIT_SETTINGS_PRINT_MARGIN_LEFT);
+ gtk_source_print_compositor_set_left_margin (job->compositor, margin, GTK_UNIT_MM);
+
+ margin = g_settings_get_double (job->gsettings, GEDIT_SETTINGS_PRINT_MARGIN_TOP);
+ gtk_source_print_compositor_set_top_margin (job->compositor, margin, GTK_UNIT_MM);
+
+ margin = g_settings_get_double (job->gsettings, GEDIT_SETTINGS_PRINT_MARGIN_RIGHT);
+ gtk_source_print_compositor_set_right_margin (job->compositor, margin, GTK_UNIT_MM);
+
+ margin = g_settings_get_double (job->gsettings, GEDIT_SETTINGS_PRINT_MARGIN_BOTTOM);
+ gtk_source_print_compositor_set_bottom_margin (job->compositor, margin, GTK_UNIT_MM);
+
+ if (print_header)
+ {
+ gchar *doc_name;
+ gchar *name_to_display;
+ gchar *left;
+
+ doc_name = _gedit_document_get_uri_for_display (GEDIT_DOCUMENT (buf));
+- name_to_display = tepl_utils_str_middle_truncate (doc_name, 60);
++ name_to_display = gedit_utils_str_middle_truncate (doc_name, 60);
+
+ left = g_strdup_printf (_("File: %s"), name_to_display);
+
+ gtk_source_print_compositor_set_header_format (job->compositor,
+ TRUE,
+ left,
+ NULL,
+ /* Translators: %N is the current page number, %Q is the total
+ * number of pages (ex. Page 2 of 10)
+ */
+ _("Page %N of %Q"));
+
+ g_free (doc_name);
+ g_free (name_to_display);
+ g_free (left);
+ }
+
+ g_free (print_font_body);
+ g_free (print_font_header);
+ g_free (print_font_numbers);
+ }
+
+ static void
+ begin_print_cb (GtkPrintOperation *operation,
+ GtkPrintContext *context,
+ GeditPrintJob *job)
+ {
+ create_compositor (job);
+
+ job->progress = 0.0;
+diff --git a/gedit/gedit-progress-info-bar.c b/gedit/gedit-progress-info-bar.c
+new file mode 100644
+index 000000000..d547189fb
+--- /dev/null
++++ b/gedit/gedit-progress-info-bar.c
+@@ -0,0 +1,177 @@
++/*
++ * gedit-progress-info-bar.c
++ * This file is part of gedit
++ *
++ * Copyright (C) 2005 - Paolo Maggi
++ *
++ * 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
++ * along with this program; if not, see .
++ */
++
++#include "gedit-progress-info-bar.h"
++#include
++
++enum {
++ PROP_0,
++ PROP_HAS_CANCEL_BUTTON,
++ LAST_PROP
++};
++
++static GParamSpec *properties[LAST_PROP];
++
++struct _GeditProgressInfoBar
++{
++ GtkInfoBar parent_instance;
++
++ GtkWidget *image;
++ GtkWidget *label;
++ GtkWidget *progress;
++};
++
++G_DEFINE_TYPE (GeditProgressInfoBar, gedit_progress_info_bar, GTK_TYPE_INFO_BAR)
++
++static void
++gedit_progress_info_bar_set_has_cancel_button (GeditProgressInfoBar *bar,
++ gboolean has_button)
++{
++ if (has_button)
++ {
++ gtk_info_bar_add_button (GTK_INFO_BAR (bar), _("_Cancel"), GTK_RESPONSE_CANCEL);
++ }
++}
++
++static void
++gedit_progress_info_bar_set_property (GObject *object,
++ guint prop_id,
++ const GValue *value,
++ GParamSpec *pspec)
++{
++ GeditProgressInfoBar *bar;
++
++ bar = GEDIT_PROGRESS_INFO_BAR (object);
++
++ switch (prop_id)
++ {
++ case PROP_HAS_CANCEL_BUTTON:
++ gedit_progress_info_bar_set_has_cancel_button (bar,
++ g_value_get_boolean (value));
++ break;
++ default:
++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++ break;
++ }
++}
++
++static void
++gedit_progress_info_bar_class_init (GeditProgressInfoBarClass *klass)
++{
++ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
++ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
++
++ gobject_class->set_property = gedit_progress_info_bar_set_property;
++
++ properties[PROP_HAS_CANCEL_BUTTON] =
++ g_param_spec_boolean ("has-cancel-button",
++ "Has Cancel Button",
++ "If the message bar has a cancel button",
++ TRUE,
++ G_PARAM_WRITABLE |
++ G_PARAM_CONSTRUCT_ONLY |
++ G_PARAM_STATIC_STRINGS);
++
++ g_object_class_install_properties (gobject_class, LAST_PROP, properties);
++
++ /* Bind class to template */
++ gtk_widget_class_set_template_from_resource (widget_class,
++ "/org/gnome/gedit/ui/gedit-progress-info-bar.ui");
++ gtk_widget_class_bind_template_child (widget_class, GeditProgressInfoBar, image);
++ gtk_widget_class_bind_template_child (widget_class, GeditProgressInfoBar, label);
++ gtk_widget_class_bind_template_child (widget_class, GeditProgressInfoBar, progress);
++}
++
++static void
++gedit_progress_info_bar_init (GeditProgressInfoBar *bar)
++{
++ gtk_widget_init_template (GTK_WIDGET (bar));
++}
++
++GtkWidget *
++gedit_progress_info_bar_new (const gchar *icon_name,
++ const gchar *markup,
++ gboolean has_cancel)
++{
++ GeditProgressInfoBar *bar;
++
++ g_return_val_if_fail (icon_name != NULL, NULL);
++ g_return_val_if_fail (markup != NULL, NULL);
++
++ bar = GEDIT_PROGRESS_INFO_BAR (g_object_new (GEDIT_TYPE_PROGRESS_INFO_BAR,
++ "has-cancel-button", has_cancel,
++ NULL));
++
++ gedit_progress_info_bar_set_icon_name (bar, icon_name);
++ gedit_progress_info_bar_set_markup (bar, markup);
++
++ return GTK_WIDGET (bar);
++}
++
++void
++gedit_progress_info_bar_set_icon_name (GeditProgressInfoBar *bar,
++ const gchar *icon_name)
++{
++ g_return_if_fail (GEDIT_IS_PROGRESS_INFO_BAR (bar));
++ g_return_if_fail (icon_name != NULL);
++
++ gtk_image_set_from_icon_name (GTK_IMAGE (bar->image),
++ icon_name,
++ GTK_ICON_SIZE_SMALL_TOOLBAR);
++}
++
++void
++gedit_progress_info_bar_set_markup (GeditProgressInfoBar *bar,
++ const gchar *markup)
++{
++ g_return_if_fail (GEDIT_IS_PROGRESS_INFO_BAR (bar));
++ g_return_if_fail (markup != NULL);
++
++ gtk_label_set_markup (GTK_LABEL (bar->label), markup);
++}
++
++void
++gedit_progress_info_bar_set_text (GeditProgressInfoBar *bar,
++ const gchar *text)
++{
++ g_return_if_fail (GEDIT_IS_PROGRESS_INFO_BAR (bar));
++ g_return_if_fail (text != NULL);
++
++ gtk_label_set_text (GTK_LABEL (bar->label), text);
++}
++
++void
++gedit_progress_info_bar_set_fraction (GeditProgressInfoBar *bar,
++ gdouble fraction)
++{
++ g_return_if_fail (GEDIT_IS_PROGRESS_INFO_BAR (bar));
++
++ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (bar->progress), fraction);
++}
++
++void
++gedit_progress_info_bar_pulse (GeditProgressInfoBar *bar)
++{
++ g_return_if_fail (GEDIT_IS_PROGRESS_INFO_BAR (bar));
++
++ gtk_progress_bar_pulse (GTK_PROGRESS_BAR (bar->progress));
++}
++
++/* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-progress-info-bar.h b/gedit/gedit-progress-info-bar.h
+new file mode 100644
+index 000000000..0d820d8e4
+--- /dev/null
++++ b/gedit/gedit-progress-info-bar.h
+@@ -0,0 +1,53 @@
++/*
++ * gedit-progress-info-bar.h
++ * This file is part of gedit
++ *
++ * Copyright (C) 2005 - Paolo Maggi
++ *
++ * 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
++ * along with this program; if not, see .
++ */
++
++#ifndef GEDIT_PROGRESS_INFO_BAR_H
++#define GEDIT_PROGRESS_INFO_BAR_H
++
++#include
++
++G_BEGIN_DECLS
++
++#define GEDIT_TYPE_PROGRESS_INFO_BAR (gedit_progress_info_bar_get_type ())
++G_DECLARE_FINAL_TYPE (GeditProgressInfoBar, gedit_progress_info_bar, GEDIT, PROGRESS_INFO_BAR, GtkInfoBar)
++
++GtkWidget *gedit_progress_info_bar_new (const gchar *icon_name,
++ const gchar *markup,
++ gboolean has_cancel);
++
++void gedit_progress_info_bar_set_icon_name (GeditProgressInfoBar *bar,
++ const gchar *icon_name);
++
++void gedit_progress_info_bar_set_markup (GeditProgressInfoBar *bar,
++ const gchar *markup);
++
++void gedit_progress_info_bar_set_text (GeditProgressInfoBar *bar,
++ const gchar *text);
++
++void gedit_progress_info_bar_set_fraction (GeditProgressInfoBar *bar,
++ gdouble fraction);
++
++void gedit_progress_info_bar_pulse (GeditProgressInfoBar *bar);
++
++G_END_DECLS
++
++#endif /* GEDIT_PROGRESS_INFO_BAR_H */
++
++/* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-recent-osx.c b/gedit/gedit-recent-osx.c
+deleted file mode 100644
+index 6f8c8cd6e..000000000
+--- a/gedit/gedit-recent-osx.c
++++ /dev/null
+@@ -1,249 +0,0 @@
+-/*
+- * This file is part of gedit
+- *
+- * Copyright (C) 2005 - Paolo Maggi
+- * Copyright (C) 2014 - Paolo Borelli
+- * Copyright (C) 2014 - Jesse van den Kieboom
+- *
+- * 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
+- * along with this program; if not, see .
+- */
+-
+-#include "gedit-recent-osx.h"
+-
+-static gint
+-sort_recent_items_mru (GtkRecentInfo *a,
+- GtkRecentInfo *b,
+- gpointer unused)
+-{
+- g_assert (a != NULL && b != NULL);
+- return gtk_recent_info_get_modified (b) - gtk_recent_info_get_modified (a);
+-}
+-
+-static void
+-populate_filter_info (GtkRecentInfo *info,
+- GtkRecentFilterInfo *filter_info,
+- GtkRecentFilterFlags needed)
+-{
+- filter_info->uri = gtk_recent_info_get_uri (info);
+- filter_info->mime_type = gtk_recent_info_get_mime_type (info);
+-
+- filter_info->contains = GTK_RECENT_FILTER_URI | GTK_RECENT_FILTER_MIME_TYPE;
+-
+- if (needed & GTK_RECENT_FILTER_DISPLAY_NAME)
+- {
+- filter_info->display_name = gtk_recent_info_get_display_name (info);
+- filter_info->contains |= GTK_RECENT_FILTER_DISPLAY_NAME;
+- }
+- else
+- {
+- filter_info->uri = NULL;
+- }
+-
+- if (needed & GTK_RECENT_FILTER_APPLICATION)
+- {
+- filter_info->applications = (const gchar **) gtk_recent_info_get_applications (info, NULL);
+- filter_info->contains |= GTK_RECENT_FILTER_APPLICATION;
+- }
+- else
+- {
+- filter_info->applications = NULL;
+- }
+-
+- if (needed & GTK_RECENT_FILTER_GROUP)
+- {
+- filter_info->groups = (const gchar **) gtk_recent_info_get_groups (info, NULL);
+- filter_info->contains |= GTK_RECENT_FILTER_GROUP;
+- }
+- else
+- {
+- filter_info->groups = NULL;
+- }
+-
+- if (needed & GTK_RECENT_FILTER_AGE)
+- {
+- filter_info->age = gtk_recent_info_get_age (info);
+- filter_info->contains |= GTK_RECENT_FILTER_AGE;
+- }
+- else
+- {
+- filter_info->age = -1;
+- }
+-}
+-
+-/* The GeditRecentConfiguration struct is allocated and owned by the caller */
+-void
+-gedit_recent_configuration_init_default (GeditRecentConfiguration *config)
+-{
+- config->manager = gtk_recent_manager_get_default ();
+-
+- if (config->filter != NULL)
+- {
+- g_object_unref (config->filter);
+- }
+-
+- config->filter = gtk_recent_filter_new ();
+- gtk_recent_filter_add_application (config->filter, g_get_application_name ());
+- gtk_recent_filter_add_mime_type (config->filter, "text/plain");
+- g_object_ref_sink (config->filter);
+-
+- config->limit = 5;
+- config->show_not_found = TRUE;
+- config->show_private = FALSE;
+- config->local_only = FALSE;
+-
+- config->substring_filter = NULL;
+-}
+-
+-/* The GeditRecentConfiguration struct is owned and destroyed by the caller */
+-void
+-gedit_recent_configuration_destroy (GeditRecentConfiguration *config)
+-{
+- g_clear_object (&config->filter);
+- config->manager = NULL;
+-
+- g_clear_pointer (&config->substring_filter, (GDestroyNotify)g_free);
+-}
+-
+-GList *
+-gedit_recent_get_items (GeditRecentConfiguration *config)
+-{
+- GtkRecentFilterFlags needed;
+- GList *items;
+- GList *retitems = NULL;
+- gint length;
+- char *substring_filter = NULL;
+-
+- if (config->limit == 0)
+- {
+- return NULL;
+- }
+-
+- items = gtk_recent_manager_get_items (config->manager);
+-
+- if (!items)
+- {
+- return NULL;
+- }
+-
+- needed = gtk_recent_filter_get_needed (config->filter);
+- if (config->substring_filter && *config->substring_filter != '\0')
+- {
+- gchar *filter_normalized;
+-
+- filter_normalized = g_utf8_normalize (config->substring_filter, -1, G_NORMALIZE_ALL);
+- substring_filter = g_utf8_casefold (filter_normalized, -1);
+- g_free (filter_normalized);
+- }
+-
+- while (items)
+- {
+- GtkRecentInfo *info;
+- GtkRecentFilterInfo filter_info;
+- gboolean is_filtered;
+-
+- info = items->data;
+- is_filtered = FALSE;
+-
+- if (config->local_only && !gtk_recent_info_is_local (info))
+- {
+- is_filtered = TRUE;
+- }
+- else if (!config->show_private && gtk_recent_info_get_private_hint (info))
+- {
+- is_filtered = TRUE;
+- }
+- else if (!config->show_not_found && !gtk_recent_info_exists (info))
+- {
+- is_filtered = TRUE;
+- }
+- else
+- {
+- if (substring_filter)
+- {
+- gchar *uri_normalized;
+- gchar *uri_casefolded;
+-
+- uri_normalized = g_utf8_normalize (gtk_recent_info_get_uri_display (info), -1, G_NORMALIZE_ALL);
+- uri_casefolded = g_utf8_casefold (uri_normalized, -1);
+- g_free (uri_normalized);
+-
+- if (strstr (uri_casefolded, substring_filter) == NULL)
+- {
+- is_filtered = TRUE;
+- }
+-
+- g_free (uri_casefolded);
+- }
+-
+- if (!is_filtered)
+- {
+- populate_filter_info (info, &filter_info, needed);
+- is_filtered = !gtk_recent_filter_filter (config->filter, &filter_info);
+-
+- /* these we own */
+- if (filter_info.applications)
+- {
+- g_strfreev ((gchar **) filter_info.applications);
+- }
+-
+- if (filter_info.groups)
+- {
+- g_strfreev ((gchar **) filter_info.groups);
+- }
+- }
+- }
+-
+- if (!is_filtered)
+- {
+- retitems = g_list_prepend (retitems, info);
+- }
+- else
+- {
+- gtk_recent_info_unref (info);
+- }
+-
+- items = g_list_delete_link (items, items);
+- }
+-
+- g_free (substring_filter);
+-
+- if (!retitems)
+- {
+- return NULL;
+- }
+-
+- retitems = g_list_sort_with_data (retitems, (GCompareDataFunc) sort_recent_items_mru, NULL);
+- length = g_list_length (retitems);
+-
+- if ((config->limit != -1) && (length > config->limit))
+- {
+- GList *clamp, *l;
+-
+- clamp = g_list_nth (retitems, config->limit - 1);
+-
+- if (!clamp)
+- {
+- return retitems;
+- }
+-
+- l = clamp->next;
+- clamp->next = NULL;
+-
+- g_list_free_full (l, (GDestroyNotify) gtk_recent_info_unref);
+- }
+-
+- return retitems;
+-}
+-
+-/* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-recent-osx.h b/gedit/gedit-recent-osx.h
+deleted file mode 100644
+index df77ca724..000000000
+--- a/gedit/gedit-recent-osx.h
++++ /dev/null
+@@ -1,54 +0,0 @@
+-/*
+- * This file is part of gedit
+- *
+- * Copyright (C) 2005 - Paolo Maggi
+- * Copyright (C) 2014 - Paolo Borelli
+- * Copyright (C) 2014 - Jesse van den Kieboom
+- *
+- * 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
+- * MERCHANWINDOWILITY 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
+- * along with this program; if not, see .
+- */
+-
+-#ifndef GEDIT_RECENT_OSX_H
+-#define GEDIT_RECENT_OSX_H
+-
+-#include
+-
+-G_BEGIN_DECLS
+-
+-/* TODO: this code can be simplified, the struct can be made private, the dead
+- * code can be removed, etc.
+- */
+-
+-typedef struct
+-{
+- GtkRecentManager *manager;
+- GtkRecentFilter *filter;
+-
+- gint limit;
+- gchar *substring_filter;
+-
+- guint show_private : 1;
+- guint show_not_found : 1;
+- guint local_only : 1;
+-} GeditRecentConfiguration;
+-
+-void gedit_recent_configuration_init_default (GeditRecentConfiguration *config);
+-void gedit_recent_configuration_destroy (GeditRecentConfiguration *config);
+-GList *gedit_recent_get_items (GeditRecentConfiguration *config);
+-
+-G_END_DECLS
+-
+-#endif /* GEDIT_RECENT_OSX_H */
+-
+-/* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-recent.c b/gedit/gedit-recent.c
+index b1535d057..2a0063306 100644
+--- a/gedit/gedit-recent.c
++++ b/gedit/gedit-recent.c
+@@ -1,92 +1,317 @@
+ /*
+ * This file is part of gedit
+ *
+ * Copyright (C) 2005 - Paolo Maggi
+ * Copyright (C) 2014 - Paolo Borelli
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #include "gedit-recent.h"
+
+ void
+ gedit_recent_add_document (GeditDocument *document)
+ {
+- TeplFile *file;
++ GtkSourceFile *file;
+ GFile *location;
+ GtkRecentManager *recent_manager;
+ GtkRecentData recent_data;
+ gchar *uri;
+ static gchar *groups[2];
+
+ g_return_if_fail (GEDIT_IS_DOCUMENT (document));
+
+- file = tepl_buffer_get_file (TEPL_BUFFER (document));
+- location = tepl_file_get_location (file);
++ file = gedit_document_get_file (document);
++ location = gtk_source_file_get_location (file);
+
+ if (location == NULL)
+ {
+ return;
+ }
+
+ recent_manager = gtk_recent_manager_get_default ();
+
+ groups[0] = (gchar *) g_get_application_name ();
+ groups[1] = NULL;
+
+ recent_data.display_name = NULL;
+ recent_data.description = NULL;
+ recent_data.mime_type = gedit_document_get_mime_type (document);
+ recent_data.app_name = (gchar *) g_get_application_name ();
+ recent_data.app_exec = g_strjoin (" ", g_get_prgname (), "%u", NULL);
+ recent_data.groups = groups;
+ recent_data.is_private = FALSE;
+
+ uri = g_file_get_uri (location);
+
+ if (!gtk_recent_manager_add_full (recent_manager, uri, &recent_data))
+ {
+ g_warning ("Failed to add uri '%s' to the recent manager.", uri);
+ }
+
+ g_free (uri);
+ g_free (recent_data.app_exec);
+ g_free (recent_data.mime_type);
+ }
+
+ void
+ gedit_recent_remove_if_local (GFile *location)
+ {
+ g_return_if_fail (G_IS_FILE (location));
+
+ /* If a file is local chances are that if load/save fails the file has
+ * beed removed and the failure is permanent so we remove it from the
+ * list of recent files. For remote files the failure may be just
+ * transitory and we keep the file in the list.
+ */
+ if (g_file_has_uri_scheme (location, "file"))
+ {
+ GtkRecentManager *recent_manager;
+ gchar *uri;
+
+ recent_manager = gtk_recent_manager_get_default ();
+
+ uri = g_file_get_uri (location);
+ gtk_recent_manager_remove_item (recent_manager, uri, NULL);
+ g_free (uri);
+ }
+ }
+
++static gint
++sort_recent_items_mru (GtkRecentInfo *a,
++ GtkRecentInfo *b,
++ gpointer unused)
++{
++ g_assert (a != NULL && b != NULL);
++ return gtk_recent_info_get_modified (b) - gtk_recent_info_get_modified (a);
++}
++
++static void
++populate_filter_info (GtkRecentInfo *info,
++ GtkRecentFilterInfo *filter_info,
++ GtkRecentFilterFlags needed)
++{
++ filter_info->uri = gtk_recent_info_get_uri (info);
++ filter_info->mime_type = gtk_recent_info_get_mime_type (info);
++
++ filter_info->contains = GTK_RECENT_FILTER_URI | GTK_RECENT_FILTER_MIME_TYPE;
++
++ if (needed & GTK_RECENT_FILTER_DISPLAY_NAME)
++ {
++ filter_info->display_name = gtk_recent_info_get_display_name (info);
++ filter_info->contains |= GTK_RECENT_FILTER_DISPLAY_NAME;
++ }
++ else
++ {
++ filter_info->uri = NULL;
++ }
++
++ if (needed & GTK_RECENT_FILTER_APPLICATION)
++ {
++ filter_info->applications = (const gchar **) gtk_recent_info_get_applications (info, NULL);
++ filter_info->contains |= GTK_RECENT_FILTER_APPLICATION;
++ }
++ else
++ {
++ filter_info->applications = NULL;
++ }
++
++ if (needed & GTK_RECENT_FILTER_GROUP)
++ {
++ filter_info->groups = (const gchar **) gtk_recent_info_get_groups (info, NULL);
++ filter_info->contains |= GTK_RECENT_FILTER_GROUP;
++ }
++ else
++ {
++ filter_info->groups = NULL;
++ }
++
++ if (needed & GTK_RECENT_FILTER_AGE)
++ {
++ filter_info->age = gtk_recent_info_get_age (info);
++ filter_info->contains |= GTK_RECENT_FILTER_AGE;
++ }
++ else
++ {
++ filter_info->age = -1;
++ }
++}
++
++/* The GeditRecentConfiguration struct is allocated and owned by the caller */
++void
++gedit_recent_configuration_init_default (GeditRecentConfiguration *config)
++{
++ config->manager = gtk_recent_manager_get_default ();
++
++ if (config->filter != NULL)
++ {
++ g_object_unref (config->filter);
++ }
++
++ config->filter = gtk_recent_filter_new ();
++ gtk_recent_filter_add_application (config->filter, g_get_application_name ());
++ gtk_recent_filter_add_mime_type (config->filter, "text/plain");
++ g_object_ref_sink (config->filter);
++
++ config->limit = 5;
++ config->show_not_found = TRUE;
++ config->show_private = FALSE;
++ config->local_only = FALSE;
++
++ config->substring_filter = NULL;
++}
++
++/* The GeditRecentConfiguration struct is owned and destroyed by the caller */
++void
++gedit_recent_configuration_destroy (GeditRecentConfiguration *config)
++{
++ g_clear_object (&config->filter);
++ config->manager = NULL;
++
++ g_clear_pointer (&config->substring_filter, (GDestroyNotify)g_free);
++}
++
++GList *
++gedit_recent_get_items (GeditRecentConfiguration *config)
++{
++ GtkRecentFilterFlags needed;
++ GList *items;
++ GList *retitems = NULL;
++ gint length;
++ char *substring_filter = NULL;
++
++ if (config->limit == 0)
++ {
++ return NULL;
++ }
++
++ items = gtk_recent_manager_get_items (config->manager);
++
++ if (!items)
++ {
++ return NULL;
++ }
++
++ needed = gtk_recent_filter_get_needed (config->filter);
++ if (config->substring_filter && *config->substring_filter != '\0')
++ {
++ gchar *filter_normalized;
++
++ filter_normalized = g_utf8_normalize (config->substring_filter, -1, G_NORMALIZE_ALL);
++ substring_filter = g_utf8_casefold (filter_normalized, -1);
++ g_free (filter_normalized);
++ }
++
++ while (items)
++ {
++ GtkRecentInfo *info;
++ GtkRecentFilterInfo filter_info;
++ gboolean is_filtered;
++
++ info = items->data;
++ is_filtered = FALSE;
++
++ if (config->local_only && !gtk_recent_info_is_local (info))
++ {
++ is_filtered = TRUE;
++ }
++ else if (!config->show_private && gtk_recent_info_get_private_hint (info))
++ {
++ is_filtered = TRUE;
++ }
++ else if (!config->show_not_found && !gtk_recent_info_exists (info))
++ {
++ is_filtered = TRUE;
++ }
++ else
++ {
++ if (substring_filter)
++ {
++ gchar *uri_normalized;
++ gchar *uri_casefolded;
++
++ uri_normalized = g_utf8_normalize (gtk_recent_info_get_uri_display (info), -1, G_NORMALIZE_ALL);
++ uri_casefolded = g_utf8_casefold (uri_normalized, -1);
++ g_free (uri_normalized);
++
++ if (strstr (uri_casefolded, substring_filter) == NULL)
++ {
++ is_filtered = TRUE;
++ }
++
++ g_free (uri_casefolded);
++ }
++
++ if (!is_filtered)
++ {
++ populate_filter_info (info, &filter_info, needed);
++ is_filtered = !gtk_recent_filter_filter (config->filter, &filter_info);
++
++ /* these we own */
++ if (filter_info.applications)
++ {
++ g_strfreev ((gchar **) filter_info.applications);
++ }
++
++ if (filter_info.groups)
++ {
++ g_strfreev ((gchar **) filter_info.groups);
++ }
++ }
++ }
++
++ if (!is_filtered)
++ {
++ retitems = g_list_prepend (retitems, info);
++ }
++ else
++ {
++ gtk_recent_info_unref (info);
++ }
++
++ items = g_list_delete_link (items, items);
++ }
++
++ g_free (substring_filter);
++
++ if (!retitems)
++ {
++ return NULL;
++ }
++
++ retitems = g_list_sort_with_data (retitems, (GCompareDataFunc) sort_recent_items_mru, NULL);
++ length = g_list_length (retitems);
++
++ if ((config->limit != -1) && (length > config->limit))
++ {
++ GList *clamp, *l;
++
++ clamp = g_list_nth (retitems, config->limit - 1);
++
++ if (!clamp)
++ {
++ return retitems;
++ }
++
++ l = clamp->next;
++ clamp->next = NULL;
++
++ g_list_free_full (l, (GDestroyNotify) gtk_recent_info_unref);
++ }
++
++ return retitems;
++}
++
+ /* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-recent.h b/gedit/gedit-recent.h
+index 068d89c72..5c72837ed 100644
+--- a/gedit/gedit-recent.h
++++ b/gedit/gedit-recent.h
+@@ -1,38 +1,55 @@
+ /*
+ * This file is part of gedit
+ *
+ * Copyright (C) 2005 - Paolo Maggi
+ * Copyright (C) 2014 - Paolo Borelli
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * 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
+ * MERCHANWINDOWILITY 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
+ * along with this program; if not, see .
+ */
+
+ #ifndef GEDIT_RECENT_H
+ #define GEDIT_RECENT_H
+
+ #include
+ #include
+
+ G_BEGIN_DECLS
+
+-void gedit_recent_add_document (GeditDocument *document);
++typedef struct
++{
++ GtkRecentManager *manager;
++ GtkRecentFilter *filter;
+
+-void gedit_recent_remove_if_local (GFile *location);
++ gint limit;
++ gchar *substring_filter;
++
++ guint show_private : 1;
++ guint show_not_found : 1;
++ guint local_only : 1;
++} GeditRecentConfiguration;
++
++void gedit_recent_add_document (GeditDocument *document);
++
++void gedit_recent_remove_if_local (GFile *location);
++
++void gedit_recent_configuration_init_default (GeditRecentConfiguration *config);
++void gedit_recent_configuration_destroy (GeditRecentConfiguration *config);
++GList *gedit_recent_get_items (GeditRecentConfiguration *config);
+
+ G_END_DECLS
+
+-#endif /* GEDIT_RECENT_H */
++#endif /* GEDIT_RECENT_H */
+
+ /* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-settings.c b/gedit/gedit-settings.c
+index a762a1dc2..6fa300f29 100644
+--- a/gedit/gedit-settings.c
++++ b/gedit/gedit-settings.c
+@@ -10,144 +10,184 @@
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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
+ * along with gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+ #include "gedit-settings.h"
+ #include
+ #include "gedit-app.h"
+
+ #define GEDIT_SETTINGS_SYSTEM_FONT "monospace-font-name"
+
+ struct _GeditSettings
+ {
+ GObject parent_instance;
+
+ GSettings *settings_interface;
+ GSettings *settings_editor;
+ GSettings *settings_ui;
+ GSettings *settings_file_chooser_state;
+ };
+
+-enum
+-{
+- SIGNAL_FONTS_CHANGED,
+- N_SIGNALS
+-};
+-
+-static guint signals[N_SIGNALS];
++/* GeditSettings is a singleton. */
+ static GeditSettings *singleton = NULL;
+
+ G_DEFINE_TYPE (GeditSettings, gedit_settings, G_TYPE_OBJECT)
+
+ static void
+ gedit_settings_dispose (GObject *object)
+ {
+ GeditSettings *self = GEDIT_SETTINGS (object);
+
+ g_clear_object (&self->settings_interface);
+ g_clear_object (&self->settings_editor);
+ g_clear_object (&self->settings_ui);
+ g_clear_object (&self->settings_file_chooser_state);
+
+ G_OBJECT_CLASS (gedit_settings_parent_class)->dispose (object);
+ }
+
+ static void
+ gedit_settings_finalize (GObject *object)
+ {
+ GeditSettings *self = GEDIT_SETTINGS (object);
+
+ if (singleton == self)
+ {
+ singleton = NULL;
+ }
+
+ G_OBJECT_CLASS (gedit_settings_parent_class)->finalize (object);
+ }
+
+ static void
+ gedit_settings_class_init (GeditSettingsClass *klass)
+ {
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gedit_settings_dispose;
+ object_class->finalize = gedit_settings_finalize;
++}
+
+- /* This signal is emitted when the return value of
+- * _gedit_settings_get_selected_font() has potentially changed.
+- */
+- signals[SIGNAL_FONTS_CHANGED] =
+- g_signal_new ("fonts-changed",
+- G_TYPE_FROM_CLASS (klass),
+- G_SIGNAL_RUN_FIRST,
+- 0,
+- NULL, NULL, NULL,
+- G_TYPE_NONE, 0);
++static void
++set_font (GeditSettings *self,
++ const gchar *font)
++{
++ guint tabs_size;
++ GList *views;
++ GList *l;
++
++ tabs_size = g_settings_get_uint (self->settings_editor, GEDIT_SETTINGS_TABS_SIZE);
++
++ views = gedit_app_get_views (GEDIT_APP (g_application_get_default ()));
++
++ for (l = views; l != NULL; l = l->next)
++ {
++ /* Note: we use def=FALSE to avoid GeditView to query dconf. */
++ gedit_view_set_font (GEDIT_VIEW (l->data), FALSE, font);
++
++ /* FIXME: setting the tab width seems unrelated to set_font(). */
++ gtk_source_view_set_tab_width (GTK_SOURCE_VIEW (l->data), tabs_size);
++ }
++
++ g_list_free (views);
+ }
+
+ static void
+-system_font_changed_cb (GSettings *settings,
++on_system_font_changed (GSettings *settings,
+ const gchar *key,
+ GeditSettings *self)
+ {
+- if (g_settings_get_boolean (self->settings_editor, GEDIT_SETTINGS_USE_DEFAULT_FONT))
++
++ gboolean use_default_font;
++
++ use_default_font = g_settings_get_boolean (self->settings_editor, GEDIT_SETTINGS_USE_DEFAULT_FONT);
++
++ if (use_default_font)
+ {
+- g_signal_emit (self, signals[SIGNAL_FONTS_CHANGED], 0);
++ gchar *font;
++
++ font = g_settings_get_string (settings, key);
++ set_font (self, font);
++ g_free (font);
+ }
+ }
+
+ static void
+-use_default_font_changed_cb (GSettings *settings,
++on_use_default_font_changed (GSettings *settings,
+ const gchar *key,
+ GeditSettings *self)
+ {
+- g_signal_emit (self, signals[SIGNAL_FONTS_CHANGED], 0);
++ gboolean use_default_font;
++ gchar *font;
++
++ use_default_font = g_settings_get_boolean (settings, key);
++
++ if (use_default_font)
++ {
++ font = g_settings_get_string (self->settings_interface, GEDIT_SETTINGS_SYSTEM_FONT);
++ }
++ else
++ {
++ font = g_settings_get_string (self->settings_editor, GEDIT_SETTINGS_EDITOR_FONT);
++ }
++
++ set_font (self, font);
++
++ g_free (font);
+ }
+
+ static void
+-editor_font_changed_cb (GSettings *settings,
++on_editor_font_changed (GSettings *settings,
+ const gchar *key,
+ GeditSettings *self)
+ {
+- if (!g_settings_get_boolean (self->settings_editor, GEDIT_SETTINGS_USE_DEFAULT_FONT))
++ gboolean use_default_font;
++
++ use_default_font = g_settings_get_boolean (self->settings_editor, GEDIT_SETTINGS_USE_DEFAULT_FONT);
++
++ if (!use_default_font)
+ {
+- g_signal_emit (self, signals[SIGNAL_FONTS_CHANGED], 0);
++ gchar *font;
++
++ font = g_settings_get_string (settings, key);
++ set_font (self, font);
++ g_free (font);
+ }
+ }
+
+ static void
+ on_auto_save_changed (GSettings *settings,
+ const gchar *key,
+ GeditSettings *self)
+ {
+ gboolean auto_save;
+ GList *docs;
+ GList *l;
+
+ auto_save = g_settings_get_boolean (settings, key);
+
+ docs = gedit_app_get_documents (GEDIT_APP (g_application_get_default ()));
+
+ for (l = docs; l != NULL; l = l->next)
+ {
+ GeditTab *tab = gedit_tab_get_from_document (GEDIT_DOCUMENT (l->data));
+ gedit_tab_set_auto_save_enabled (tab, auto_save);
+ }
+
+ g_list_free (docs);
+ }
+
+ static void
+ on_auto_save_interval_changed (GSettings *settings,
+ const gchar *key,
+ GeditSettings *self)
+ {
+@@ -180,163 +220,146 @@ on_syntax_highlighting_changed (GSettings *settings,
+
+ enable = g_settings_get_boolean (settings, key);
+
+ docs = gedit_app_get_documents (GEDIT_APP (g_application_get_default ()));
+
+ for (l = docs; l != NULL; l = l->next)
+ {
+ GtkSourceBuffer *buffer = GTK_SOURCE_BUFFER (l->data);
+ gtk_source_buffer_set_highlight_syntax (buffer, enable);
+ }
+
+ g_list_free (docs);
+
+ /* update the sensitivity of the Higlight Mode menu item */
+ windows = gedit_app_get_main_windows (GEDIT_APP (g_application_get_default ()));
+
+ for (l = windows; l != NULL; l = l->next)
+ {
+ GAction *action;
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (l->data), "highlight-mode");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), enable);
+ }
+
+ g_list_free (windows);
+ }
+
+ static void
+ gedit_settings_init (GeditSettings *self)
+ {
+- self->settings_interface = g_settings_new ("org.gnome.desktop.interface");
+-
+ self->settings_editor = g_settings_new ("org.gnome.gedit.preferences.editor");
+ self->settings_ui = g_settings_new ("org.gnome.gedit.preferences.ui");
+ self->settings_file_chooser_state = g_settings_new ("org.gnome.gedit.state.file-chooser");
+
+- g_signal_connect_object (self->settings_interface,
+- "changed::" GEDIT_SETTINGS_SYSTEM_FONT,
+- G_CALLBACK (system_font_changed_cb),
+- self,
+- 0);
+-
+- g_signal_connect_object (self->settings_editor,
+- "changed::" GEDIT_SETTINGS_USE_DEFAULT_FONT,
+- G_CALLBACK (use_default_font_changed_cb),
+- self,
+- 0);
+-
+- g_signal_connect_object (self->settings_editor,
+- "changed::" GEDIT_SETTINGS_EDITOR_FONT,
+- G_CALLBACK (editor_font_changed_cb),
+- self,
+- 0);
+-
+- g_signal_connect_object (self->settings_editor,
+- "changed::auto-save",
+- G_CALLBACK (on_auto_save_changed),
+- self,
+- 0);
+-
+- g_signal_connect_object (self->settings_editor,
+- "changed::auto-save-interval",
+- G_CALLBACK (on_auto_save_interval_changed),
+- self,
+- 0);
+-
+- g_signal_connect_object (self->settings_editor,
+- "changed::syntax-highlighting",
+- G_CALLBACK (on_syntax_highlighting_changed),
+- self,
+- 0);
++ self->settings_interface = g_settings_new ("org.gnome.desktop.interface");
++
++ g_signal_connect (self->settings_interface,
++ "changed::monospace-font-name",
++ G_CALLBACK (on_system_font_changed),
++ self);
++
++ /* editor changes */
++
++ g_signal_connect (self->settings_editor,
++ "changed::use-default-font",
++ G_CALLBACK (on_use_default_font_changed),
++ self);
++
++ g_signal_connect (self->settings_editor,
++ "changed::editor-font",
++ G_CALLBACK (on_editor_font_changed),
++ self);
++
++ g_signal_connect (self->settings_editor,
++ "changed::auto-save",
++ G_CALLBACK (on_auto_save_changed),
++ self);
++
++ g_signal_connect (self->settings_editor,
++ "changed::auto-save-interval",
++ G_CALLBACK (on_auto_save_interval_changed),
++ self);
++
++ g_signal_connect (self->settings_editor,
++ "changed::syntax-highlighting",
++ G_CALLBACK (on_syntax_highlighting_changed),
++ self);
+ }
+
+ GeditSettings *
+ _gedit_settings_get_singleton (void)
+ {
+ if (singleton == NULL)
+ {
+ singleton = g_object_new (GEDIT_TYPE_SETTINGS, NULL);
+ }
+
+ return singleton;
+ }
+
+ void
+ gedit_settings_unref_singleton (void)
+ {
+ if (singleton != NULL)
+ {
+ g_object_unref (singleton);
+ }
+
+ /* singleton is not set to NULL here, it is set to NULL in
+ * gedit_settings_finalize() (i.e. when we are sure that the ref count
+ * reaches 0).
+ */
+ }
+
+ GSettings *
+ _gedit_settings_peek_editor_settings (GeditSettings *self)
+ {
+ g_return_val_if_fail (GEDIT_IS_SETTINGS (self), NULL);
+
+ return self->settings_editor;
+ }
+
+ GSettings *
+ _gedit_settings_peek_file_chooser_state_settings (GeditSettings *self)
+ {
+ g_return_val_if_fail (GEDIT_IS_SETTINGS (self), NULL);
+
+ return self->settings_file_chooser_state;
+ }
+
+ gchar *
+-_gedit_settings_get_system_font (GeditSettings *self)
++gedit_settings_get_system_font (GeditSettings *self)
+ {
+ g_return_val_if_fail (GEDIT_IS_SETTINGS (self), NULL);
+
+- return g_settings_get_string (self->settings_interface, GEDIT_SETTINGS_SYSTEM_FONT);
+-}
+-
+-gchar *
+-_gedit_settings_get_selected_font (GeditSettings *self)
+-{
+- g_return_val_if_fail (GEDIT_IS_SETTINGS (self), NULL);
+-
+- if (g_settings_get_boolean (self->settings_editor, GEDIT_SETTINGS_USE_DEFAULT_FONT))
+- {
+- return _gedit_settings_get_system_font (self);
+- }
+-
+- return g_settings_get_string (self->settings_editor, GEDIT_SETTINGS_EDITOR_FONT);
++ return g_settings_get_string (self->settings_interface, "monospace-font-name");
+ }
+
+ static gboolean
+ strv_is_empty (gchar **strv)
+ {
+ if (strv == NULL || strv[0] == NULL)
+ {
+ return TRUE;
+ }
+
+ /* Contains one empty string. */
+ if (strv[1] == NULL && strv[0][0] == '\0')
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ static GSList *
+ encoding_strv_to_list (const gchar * const *encoding_strv)
+ {
+ GSList *list = NULL;
+ gchar **p;
+
+ for (p = (gchar **)encoding_strv; p != NULL && *p != NULL; p++)
+ {
+ const gchar *charset = *p;
+ const GtkSourceEncoding *encoding;
+
+diff --git a/gedit/gedit-settings.h b/gedit/gedit-settings.h
+index a7993d5d1..a2fe9e47b 100644
+--- a/gedit/gedit-settings.h
++++ b/gedit/gedit-settings.h
+@@ -16,90 +16,87 @@
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+ #ifndef GEDIT_SETTINGS_H
+ #define GEDIT_SETTINGS_H
+
+ #include
+
+ G_BEGIN_DECLS
+
+ #define GEDIT_TYPE_SETTINGS (gedit_settings_get_type ())
+
+ G_DECLARE_FINAL_TYPE (GeditSettings, gedit_settings, GEDIT, SETTINGS, GObject)
+
+ G_GNUC_INTERNAL
+ GeditSettings * _gedit_settings_get_singleton (void);
+
+ void gedit_settings_unref_singleton (void);
+
+ G_GNUC_INTERNAL
+ GSettings * _gedit_settings_peek_editor_settings (GeditSettings *self);
+
+ G_GNUC_INTERNAL
+ GSettings * _gedit_settings_peek_file_chooser_state_settings (GeditSettings *self);
+
+-G_GNUC_INTERNAL
+-gchar * _gedit_settings_get_system_font (GeditSettings *self);
+-
+-G_GNUC_INTERNAL
+-gchar * _gedit_settings_get_selected_font (GeditSettings *self);
++gchar * gedit_settings_get_system_font (GeditSettings *self);
+
+ GSList * gedit_settings_get_candidate_encodings (gboolean *default_candidates);
+
+ /* key constants */
+ #define GEDIT_SETTINGS_USE_DEFAULT_FONT "use-default-font"
+ #define GEDIT_SETTINGS_EDITOR_FONT "editor-font"
+ #define GEDIT_SETTINGS_SCHEME "scheme"
+ #define GEDIT_SETTINGS_CREATE_BACKUP_COPY "create-backup-copy"
+ #define GEDIT_SETTINGS_AUTO_SAVE "auto-save"
+ #define GEDIT_SETTINGS_AUTO_SAVE_INTERVAL "auto-save-interval"
+ #define GEDIT_SETTINGS_MAX_UNDO_ACTIONS "max-undo-actions"
+ #define GEDIT_SETTINGS_WRAP_MODE "wrap-mode"
+ #define GEDIT_SETTINGS_WRAP_LAST_SPLIT_MODE "wrap-last-split-mode"
+ #define GEDIT_SETTINGS_TABS_SIZE "tabs-size"
+ #define GEDIT_SETTINGS_INSERT_SPACES "insert-spaces"
+ #define GEDIT_SETTINGS_AUTO_INDENT "auto-indent"
+ #define GEDIT_SETTINGS_DISPLAY_LINE_NUMBERS "display-line-numbers"
+ #define GEDIT_SETTINGS_HIGHLIGHT_CURRENT_LINE "highlight-current-line"
+ #define GEDIT_SETTINGS_BRACKET_MATCHING "bracket-matching"
+ #define GEDIT_SETTINGS_DISPLAY_RIGHT_MARGIN "display-right-margin"
+ #define GEDIT_SETTINGS_RIGHT_MARGIN_POSITION "right-margin-position"
+ #define GEDIT_SETTINGS_SMART_HOME_END "smart-home-end"
+ #define GEDIT_SETTINGS_RESTORE_CURSOR_POSITION "restore-cursor-position"
+ #define GEDIT_SETTINGS_SYNTAX_HIGHLIGHTING "syntax-highlighting"
+ #define GEDIT_SETTINGS_SEARCH_HIGHLIGHTING "search-highlighting"
++#define GEDIT_SETTINGS_DISPLAY_OVERVIEW_MAP "display-overview-map"
+ #define GEDIT_SETTINGS_BACKGROUND_PATTERN "background-pattern"
+ #define GEDIT_SETTINGS_STATUSBAR_VISIBLE "statusbar-visible"
+ #define GEDIT_SETTINGS_SIDE_PANEL_VISIBLE "side-panel-visible"
+ #define GEDIT_SETTINGS_BOTTOM_PANEL_VISIBLE "bottom-panel-visible"
+ #define GEDIT_SETTINGS_PRINT_SYNTAX_HIGHLIGHTING "print-syntax-highlighting"
+ #define GEDIT_SETTINGS_PRINT_HEADER "print-header"
+ #define GEDIT_SETTINGS_PRINT_WRAP_MODE "print-wrap-mode"
+ #define GEDIT_SETTINGS_PRINT_LINE_NUMBERS "print-line-numbers"
+ #define GEDIT_SETTINGS_PRINT_FONT_BODY_PANGO "print-font-body-pango"
+ #define GEDIT_SETTINGS_PRINT_FONT_HEADER_PANGO "print-font-header-pango"
+ #define GEDIT_SETTINGS_PRINT_FONT_NUMBERS_PANGO "print-font-numbers-pango"
+ #define GEDIT_SETTINGS_PRINT_MARGIN_LEFT "margin-left"
+ #define GEDIT_SETTINGS_PRINT_MARGIN_TOP "margin-top"
+ #define GEDIT_SETTINGS_PRINT_MARGIN_RIGHT "margin-right"
+ #define GEDIT_SETTINGS_PRINT_MARGIN_BOTTOM "margin-bottom"
+ #define GEDIT_SETTINGS_CANDIDATE_ENCODINGS "candidate-encodings"
+ #define GEDIT_SETTINGS_ACTIVE_PLUGINS "active-plugins"
+ #define GEDIT_SETTINGS_ENSURE_TRAILING_NEWLINE "ensure-trailing-newline"
+
+ /* window state keys */
+ #define GEDIT_SETTINGS_WINDOW_STATE "state"
+ #define GEDIT_SETTINGS_WINDOW_SIZE "size"
+ #define GEDIT_SETTINGS_SHOW_TABS_MODE "show-tabs-mode"
+ #define GEDIT_SETTINGS_SIDE_PANEL_SIZE "side-panel-size"
+ #define GEDIT_SETTINGS_SIDE_PANEL_ACTIVE_PAGE "side-panel-active-page"
+ #define GEDIT_SETTINGS_BOTTOM_PANEL_SIZE "bottom-panel-size"
+ #define GEDIT_SETTINGS_BOTTOM_PANEL_ACTIVE_PAGE "bottom-panel-active-page"
+
+ /* file chooser state keys */
+ #define GEDIT_SETTINGS_ACTIVE_FILE_FILTER "filter-id"
+diff --git a/gedit/gedit-tab.c b/gedit/gedit-tab.c
+index af72864e2..6bb38b160 100644
+--- a/gedit/gedit-tab.c
++++ b/gedit/gedit-tab.c
+@@ -1,65 +1,65 @@
+ /*
+ * gedit-tab.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2005 - Paolo Maggi
+ * Copyright (C) 2014, 2015 - Sébastien Wilmet
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #include "gedit-tab.h"
+ #include "gedit-tab-private.h"
+
+ #include
+ #include
+-#include
+
+ #include "gedit-app.h"
+ #include "gedit-app-private.h"
+ #include "gedit-recent.h"
+ #include "gedit-utils.h"
+ #include "gedit-io-error-info-bar.h"
+ #include "gedit-print-job.h"
+ #include "gedit-print-preview.h"
++#include "gedit-progress-info-bar.h"
+ #include "gedit-debug.h"
+ #include "gedit-document.h"
+ #include "gedit-document-private.h"
+ #include "gedit-enum-types.h"
+ #include "gedit-settings.h"
+ #include "gedit-view-frame.h"
+
+ #define GEDIT_TAB_KEY "GEDIT_TAB_KEY"
+
+ struct _GeditTab
+ {
+ GtkBox parent_instance;
+
+ GeditTabState state;
+
+ GSettings *editor_settings;
+
+ GeditViewFrame *frame;
+
+ GtkWidget *info_bar;
+ GtkWidget *info_bar_hidden;
+
+ GeditPrintJob *print_job;
+ GtkWidget *print_preview;
+
+ GtkSourceFileSaverFlags save_flags;
+
+ guint idle_scroll;
+
+ gint auto_save_interval;
+@@ -547,63 +547,63 @@ gedit_tab_set_state (GeditTab *tab,
+ if (state == GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW)
+ {
+ gtk_widget_hide (GTK_WIDGET (tab->frame));
+ }
+ else if (state != GEDIT_TAB_STATE_LOADING_ERROR)
+ {
+ gtk_widget_show (GTK_WIDGET (tab->frame));
+ }
+
+ set_cursor_according_to_state (GTK_TEXT_VIEW (gedit_tab_get_view (tab)),
+ state);
+
+ update_auto_save_timeout (tab);
+
+ g_object_notify_by_pspec (G_OBJECT (tab), properties[PROP_STATE]);
+ g_object_notify_by_pspec (G_OBJECT (tab), properties[PROP_CAN_CLOSE]);
+ }
+
+ static void
+ document_location_notify_handler (GtkSourceFile *file,
+ GParamSpec *pspec,
+ GeditTab *tab)
+ {
+ gedit_debug (DEBUG_TAB);
+
+ /* Notify the change in the location */
+ g_object_notify_by_pspec (G_OBJECT (tab), properties[PROP_NAME]);
+ }
+
+ static void
+-document_shortname_notify_handler (TeplFile *file,
+- GParamSpec *pspec,
+- GeditTab *tab)
++document_shortname_notify_handler (GeditDocument *document,
++ GParamSpec *pspec,
++ GeditTab *tab)
+ {
+ gedit_debug (DEBUG_TAB);
+
+ /* Notify the change in the shortname */
+ g_object_notify_by_pspec (G_OBJECT (tab), properties[PROP_NAME]);
+ }
+
+ static void
+ document_modified_changed (GtkTextBuffer *document,
+ GeditTab *tab)
+ {
+ g_object_notify_by_pspec (G_OBJECT (tab), properties[PROP_NAME]);
+ g_object_notify_by_pspec (G_OBJECT (tab), properties[PROP_CAN_CLOSE]);
+ }
+
+ static void
+ set_info_bar (GeditTab *tab,
+ GtkWidget *info_bar,
+ GtkResponseType default_response)
+ {
+ gedit_debug (DEBUG_TAB);
+
+ if (tab->info_bar == info_bar)
+ {
+ return;
+ }
+
+ if (info_bar == NULL)
+ {
+ /* Don't destroy the old info_bar right away,
+@@ -699,369 +699,369 @@ io_loading_error_info_bar_response (GtkWidget *info_bar,
+ g_task_return_boolean (loading_task, FALSE);
+ g_object_unref (loading_task);
+ break;
+ }
+ }
+
+ static void
+ file_already_open_warning_info_bar_response (GtkWidget *info_bar,
+ gint response_id,
+ GeditTab *tab)
+ {
+ GeditView *view = gedit_tab_get_view (tab);
+
+ if (response_id == GTK_RESPONSE_YES)
+ {
+ set_editable (tab, TRUE);
+ }
+
+ set_info_bar (tab, NULL, GTK_RESPONSE_NONE);
+
+ gtk_widget_grab_focus (GTK_WIDGET (view));
+ }
+
+ static void
+ load_cancelled (GtkWidget *bar,
+ gint response_id,
+ GTask *loading_task)
+ {
+ LoaderData *data = g_task_get_task_data (loading_task);
+
+- g_return_if_fail (TEPL_IS_PROGRESS_INFO_BAR (data->tab->info_bar));
++ g_return_if_fail (GEDIT_IS_PROGRESS_INFO_BAR (data->tab->info_bar));
+
+ g_cancellable_cancel (g_task_get_cancellable (loading_task));
+ remove_tab (data->tab);
+ }
+
+ static void
+ unrecoverable_reverting_error_info_bar_response (GtkWidget *info_bar,
+ gint response_id,
+ GTask *loading_task)
+ {
+ LoaderData *data = g_task_get_task_data (loading_task);
+ GeditView *view;
+
+ gedit_tab_set_state (data->tab, GEDIT_TAB_STATE_NORMAL);
+
+ set_info_bar (data->tab, NULL, GTK_RESPONSE_NONE);
+
+ view = gedit_tab_get_view (data->tab);
+ gtk_widget_grab_focus (GTK_WIDGET (view));
+
+ g_task_return_boolean (loading_task, FALSE);
+ g_object_unref (loading_task);
+ }
+
+ #define MAX_MSG_LENGTH 100
+
+ static void
+ show_loading_info_bar (GTask *loading_task)
+ {
+ LoaderData *data = g_task_get_task_data (loading_task);
+- TeplProgressInfoBar *bar;
++ GtkWidget *bar;
+ GeditDocument *doc;
+ gchar *name;
+ gchar *dirname = NULL;
+ gchar *msg = NULL;
+ gchar *name_markup;
+ gchar *dirname_markup;
+ gint len;
+
+ if (data->tab->info_bar != NULL)
+ {
+ return;
+ }
+
+ gedit_debug (DEBUG_TAB);
+
+ doc = gedit_tab_get_document (data->tab);
+
+ name = gedit_document_get_short_name_for_display (doc);
+ len = g_utf8_strlen (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)
+ {
+ gchar *str;
+
+- str = tepl_utils_str_middle_truncate (name, MAX_MSG_LENGTH);
++ str = gedit_utils_str_middle_truncate (name, MAX_MSG_LENGTH);
+ g_free (name);
+ name = str;
+ }
+ else
+ {
+ GtkSourceFile *file = gedit_document_get_file (doc);
+ GFile *location = gtk_source_file_get_location (file);
+
+ if (location != NULL)
+ {
+ gchar *str = gedit_utils_location_get_dirname_for_display (location);
+
+ /* 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 :)
+ */
+- dirname = tepl_utils_str_middle_truncate (str,
+- MAX (20, MAX_MSG_LENGTH - len));
++ dirname = gedit_utils_str_middle_truncate (str,
++ MAX (20, MAX_MSG_LENGTH - len));
+ g_free (str);
+ }
+ }
+
+ name_markup = g_markup_printf_escaped ("%s", name);
+
+ if (data->tab->state == GEDIT_TAB_STATE_REVERTING)
+ {
+ if (dirname != NULL)
+ {
+ dirname_markup = g_markup_printf_escaped ("%s", dirname);
+
+ /* 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) */
+ msg = g_strdup_printf (_("Reverting %s from %s"),
+ name_markup,
+ dirname_markup);
+ g_free (dirname_markup);
+ }
+ else
+ {
+ msg = g_strdup_printf (_("Reverting %s"), name_markup);
+ }
+
+- bar = tepl_progress_info_bar_new ("document-revert", msg, TRUE);
++ bar = gedit_progress_info_bar_new ("document-revert", msg, TRUE);
+ }
+ else
+ {
+ if (dirname != NULL)
+ {
+ dirname_markup = g_markup_printf_escaped ("%s", dirname);
+
+ /* 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) */
+ msg = g_strdup_printf (_("Loading %s from %s"),
+ name_markup,
+ dirname_markup);
+ g_free (dirname_markup);
+ }
+ else
+ {
+ msg = g_strdup_printf (_("Loading %s"), name_markup);
+ }
+
+- bar = tepl_progress_info_bar_new ("document-open", msg, TRUE);
++ bar = gedit_progress_info_bar_new ("document-open", msg, TRUE);
+ }
+
+ g_signal_connect_object (bar,
+ "response",
+ G_CALLBACK (load_cancelled),
+ loading_task,
+ 0);
+
+- set_info_bar (data->tab, GTK_WIDGET (bar), GTK_RESPONSE_NONE);
++ set_info_bar (data->tab, bar, GTK_RESPONSE_NONE);
+
+ g_free (msg);
+ g_free (name);
+ g_free (name_markup);
+ g_free (dirname);
+ }
+
+ static void
+ show_saving_info_bar (GTask *saving_task)
+ {
+ GeditTab *tab = g_task_get_source_object (saving_task);
+- TeplProgressInfoBar *bar;
++ GtkWidget *bar;
+ GeditDocument *doc;
+ gchar *short_name;
+ gchar *from;
+ gchar *to = NULL;
+ gchar *from_markup;
+ gchar *to_markup;
+ gchar *msg = NULL;
+ gint len;
+
+ if (tab->info_bar != NULL)
+ {
+ return;
+ }
+
+ gedit_debug (DEBUG_TAB);
+
+ doc = gedit_tab_get_document (tab);
+
+ 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)
+ {
+- from = tepl_utils_str_middle_truncate (short_name, MAX_MSG_LENGTH);
++ from = gedit_utils_str_middle_truncate (short_name, MAX_MSG_LENGTH);
+ g_free (short_name);
+ }
+ else
+ {
+ gchar *str;
+ SaverData *data;
+ GFile *location;
+
+ data = g_task_get_task_data (saving_task);
+ location = gtk_source_file_saver_get_location (data->saver);
+
+ from = short_name;
+ to = g_file_get_parse_name (location);
+- str = tepl_utils_str_middle_truncate (to, MAX (20, MAX_MSG_LENGTH - len));
++ str = gedit_utils_str_middle_truncate (to, MAX (20, MAX_MSG_LENGTH - len));
+ g_free (to);
+
+ to = str;
+ }
+
+ from_markup = g_markup_printf_escaped ("%s", from);
+
+ if (to != NULL)
+ {
+ to_markup = g_markup_printf_escaped ("%s", to);
+
+ /* 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) */
+ msg = g_strdup_printf (_("Saving %s to %s"), from_markup, to_markup);
+ g_free (to_markup);
+ }
+ else
+ {
+ msg = g_strdup_printf (_("Saving %s"), from_markup);
+ }
+
+- bar = tepl_progress_info_bar_new ("document-save", msg, FALSE);
++ bar = gedit_progress_info_bar_new ("document-save", msg, FALSE);
+
+- set_info_bar (tab, GTK_WIDGET (bar), GTK_RESPONSE_NONE);
++ set_info_bar (tab, bar, GTK_RESPONSE_NONE);
+
+ g_free (msg);
+ g_free (to);
+ g_free (from);
+ g_free (from_markup);
+ }
+
+ static void
+ info_bar_set_progress (GeditTab *tab,
+ goffset size,
+ goffset total_size)
+ {
+- TeplProgressInfoBar *progress_info_bar;
++ GeditProgressInfoBar *progress_info_bar;
+
+ if (tab->info_bar == NULL)
+ {
+ return;
+ }
+
+ gedit_debug_message (DEBUG_TAB, "%" G_GOFFSET_FORMAT "/%" G_GOFFSET_FORMAT, size, total_size);
+
+- g_return_if_fail (TEPL_IS_PROGRESS_INFO_BAR (tab->info_bar));
++ g_return_if_fail (GEDIT_IS_PROGRESS_INFO_BAR (tab->info_bar));
+
+- progress_info_bar = TEPL_PROGRESS_INFO_BAR (tab->info_bar);
++ progress_info_bar = GEDIT_PROGRESS_INFO_BAR (tab->info_bar);
+
+ if (total_size != 0)
+ {
+ gdouble frac = (gdouble)size / (gdouble)total_size;
+
+- tepl_progress_info_bar_set_fraction (progress_info_bar, frac);
++ gedit_progress_info_bar_set_fraction (progress_info_bar, frac);
+ }
+ else if (size != 0)
+ {
+- tepl_progress_info_bar_pulse (progress_info_bar);
++ gedit_progress_info_bar_pulse (progress_info_bar);
+ }
+ else
+ {
+- tepl_progress_info_bar_set_fraction (progress_info_bar, 0);
++ gedit_progress_info_bar_set_fraction (progress_info_bar, 0);
+ }
+ }
+
+ /* Returns whether progress info should be shown. */
+ static gboolean
+ should_show_progress_info (GTimer **timer,
+ goffset size,
+ goffset total_size)
+ {
+ gdouble elapsed_time;
+ gdouble total_time;
+ gdouble remaining_time;
+
+ g_assert (timer != NULL);
+
+ if (*timer == NULL)
+ {
+ return TRUE;
+ }
+
+ elapsed_time = g_timer_elapsed (*timer, NULL);
+
+ /* 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.
+ */
+ g_timer_destroy (*timer);
+ *timer = NULL;
+
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ static gboolean
+ scroll_to_cursor (GeditTab *tab)
+ {
+ GeditView *view;
+
+ view = gedit_tab_get_view (tab);
+- tepl_view_scroll_to_cursor (TEPL_VIEW (view));
++ gedit_view_scroll_to_cursor (view);
+
+ tab->idle_scroll = 0;
+ return G_SOURCE_REMOVE;
+ }
+
+ static void
+ unrecoverable_saving_error_info_bar_response (GtkWidget *info_bar,
+ gint response_id,
+ GTask *saving_task)
+ {
+ GeditTab *tab = g_task_get_source_object (saving_task);
+ GeditView *view;
+
+ gedit_tab_set_state (tab, GEDIT_TAB_STATE_NORMAL);
+
+ set_info_bar (tab, NULL, GTK_RESPONSE_NONE);
+
+ view = gedit_tab_get_view (tab);
+ gtk_widget_grab_focus (GTK_WIDGET (view));
+
+ g_task_return_boolean (saving_task, FALSE);
+ g_object_unref (saving_task);
+ }
+
+ /* Sets the save flags after an info bar response. */
+ static void
+ response_set_save_flags (GTask *saving_task,
+ GtkSourceFileSaverFlags save_flags)
+ {
+ GeditTab *tab = g_task_get_source_object (saving_task);
+@@ -1091,63 +1091,63 @@ response_set_save_flags (GTask *saving_task,
+ static void
+ invalid_character_info_bar_response (GtkWidget *info_bar,
+ gint response_id,
+ GTask *saving_task)
+ {
+ if (response_id == GTK_RESPONSE_YES)
+ {
+ GeditTab *tab = g_task_get_source_object (saving_task);
+ SaverData *data = g_task_get_task_data (saving_task);
+ GtkSourceFileSaverFlags save_flags;
+
+ set_info_bar (tab, NULL, GTK_RESPONSE_NONE);
+
+ /* Don't bug the user again with this... */
+ tab->save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_INVALID_CHARS;
+
+ save_flags = gtk_source_file_saver_get_flags (data->saver);
+ save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_INVALID_CHARS;
+ response_set_save_flags (saving_task, save_flags);
+
+ /* Force saving */
+ launch_saver (saving_task);
+ }
+ else
+ {
+ unrecoverable_saving_error_info_bar_response (info_bar, response_id, saving_task);
+ }
+ }
+
+ static void
+-cant_create_backup_error_info_bar_response (GtkWidget *info_bar,
+- gint response_id,
+- GTask *saving_task)
++no_backup_error_info_bar_response (GtkWidget *info_bar,
++ gint response_id,
++ GTask *saving_task)
+ {
+ if (response_id == GTK_RESPONSE_YES)
+ {
+ GeditTab *tab = g_task_get_source_object (saving_task);
+ SaverData *data = g_task_get_task_data (saving_task);
+ GtkSourceFileSaverFlags save_flags;
+
+ set_info_bar (tab, NULL, GTK_RESPONSE_NONE);
+
+ data->force_no_backup = TRUE;
+ save_flags = gtk_source_file_saver_get_flags (data->saver);
+ response_set_save_flags (saving_task, save_flags);
+
+ /* Force saving */
+ launch_saver (saving_task);
+ }
+ else
+ {
+ unrecoverable_saving_error_info_bar_response (info_bar, response_id, saving_task);
+ }
+ }
+
+ static void
+ externally_modified_error_info_bar_response (GtkWidget *info_bar,
+ gint response_id,
+ GTask *saving_task)
+ {
+ if (response_id == GTK_RESPONSE_YES)
+ {
+ GeditTab *tab = g_task_get_source_object (saving_task);
+@@ -1199,77 +1199,77 @@ recoverable_saving_error_info_bar_response (GtkWidget *info_bar,
+
+ static void
+ externally_modified_notification_info_bar_response (GtkWidget *info_bar,
+ gint response_id,
+ GeditTab *tab)
+ {
+ GeditView *view;
+
+ set_info_bar (tab, NULL, GTK_RESPONSE_NONE);
+
+ view = gedit_tab_get_view (tab);
+
+ if (response_id == GTK_RESPONSE_OK)
+ {
+ _gedit_tab_revert (tab);
+ }
+ else
+ {
+ tab->ask_if_externally_modified = FALSE;
+
+ /* go back to normal state */
+ gedit_tab_set_state (tab, GEDIT_TAB_STATE_NORMAL);
+ }
+
+ gtk_widget_grab_focus (GTK_WIDGET (view));
+ }
+
+ static void
+ display_externally_modified_notification (GeditTab *tab)
+ {
+- TeplInfoBar *info_bar;
++ GtkWidget *info_bar;
+ GeditDocument *doc;
+ GtkSourceFile *file;
+ GFile *location;
+ gboolean document_modified;
+
+ doc = gedit_tab_get_document (tab);
+ file = gedit_document_get_file (doc);
+
+ /* we're here because the file we're editing changed on disk */
+ location = gtk_source_file_get_location (file);
+ g_return_if_fail (location != NULL);
+
+ document_modified = gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (doc));
+- info_bar = tepl_io_error_info_bar_externally_modified (location, document_modified);
++ info_bar = gedit_externally_modified_info_bar_new (location, document_modified);
+
+- set_info_bar (tab, GTK_WIDGET (info_bar), GTK_RESPONSE_OK);
++ set_info_bar (tab, info_bar, GTK_RESPONSE_OK);
+
+ g_signal_connect (info_bar,
+ "response",
+ G_CALLBACK (externally_modified_notification_info_bar_response),
+ tab);
+ }
+
+ static gboolean
+ view_focused_in (GtkWidget *widget,
+ GdkEventFocus *event,
+ GeditTab *tab)
+ {
+ GeditDocument *doc;
+ GtkSourceFile *file;
+
+ g_return_val_if_fail (GEDIT_IS_TAB (tab), GDK_EVENT_PROPAGATE);
+
+ /* we try to detect file changes only in the normal state */
+ if (tab->state != GEDIT_TAB_STATE_NORMAL)
+ {
+ return GDK_EVENT_PROPAGATE;
+ }
+
+ /* we already asked, don't bug the user again */
+ if (!tab->ask_if_externally_modified)
+ {
+ return GDK_EVENT_PROPAGATE;
+ }
+
+ doc = gedit_tab_get_document (tab);
+@@ -1280,104 +1280,101 @@ view_focused_in (GtkWidget *widget,
+ {
+ gtk_source_file_check_file_on_disk (file);
+
+ if (gtk_source_file_is_externally_modified (file))
+ {
+ gedit_tab_set_state (tab, GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION);
+
+ display_externally_modified_notification (tab);
+ }
+ }
+
+ return GDK_EVENT_PROPAGATE;
+ }
+
+ static void
+ on_drop_uris (GeditView *view,
+ gchar **uri_list,
+ GeditTab *tab)
+ {
+ g_signal_emit (G_OBJECT (tab), signals[DROP_URIS], 0, uri_list);
+ }
+
+ static void
+ gedit_tab_init (GeditTab *tab)
+ {
+ gboolean auto_save;
+ gint auto_save_interval;
+ GeditDocument *doc;
+ GeditView *view;
+ GtkSourceFile *file;
+- TeplFile *tepl_file;
+
+ tab->state = GEDIT_TAB_STATE_NORMAL;
+
+ tab->editor_settings = g_settings_new ("org.gnome.gedit.preferences.editor");
+
+ tab->editable = TRUE;
+
+ tab->ask_if_externally_modified = TRUE;
+
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (tab),
+ GTK_ORIENTATION_VERTICAL);
+
+ /* Manage auto save data */
+ auto_save = g_settings_get_boolean (tab->editor_settings,
+ GEDIT_SETTINGS_AUTO_SAVE);
+ g_settings_get (tab->editor_settings, GEDIT_SETTINGS_AUTO_SAVE_INTERVAL,
+ "u", &auto_save_interval);
+ tab->auto_save = auto_save != FALSE;
+ tab->auto_save_interval = auto_save_interval;
+
+ /* Create the frame */
+ tab->frame = gedit_view_frame_new ();
+ gtk_widget_show (GTK_WIDGET (tab->frame));
+
+ gtk_box_pack_end (GTK_BOX (tab), GTK_WIDGET (tab->frame), TRUE, TRUE, 0);
+
+ doc = gedit_tab_get_document (tab);
+ g_object_set_data (G_OBJECT (doc), GEDIT_TAB_KEY, tab);
+
+ file = gedit_document_get_file (doc);
+- tepl_file = tepl_buffer_get_file (TEPL_BUFFER (doc));
+
+ g_signal_connect_object (file,
+ "notify::location",
+ G_CALLBACK (document_location_notify_handler),
+ tab,
+ 0);
+
+- g_signal_connect_object (tepl_file,
+- "notify::short-name",
+- G_CALLBACK (document_shortname_notify_handler),
+- tab,
+- 0);
++ g_signal_connect (doc,
++ "notify::shortname",
++ G_CALLBACK (document_shortname_notify_handler),
++ tab);
+
+ g_signal_connect (doc,
+ "modified_changed",
+ G_CALLBACK (document_modified_changed),
+ tab);
+
+ view = gedit_tab_get_view (tab);
+
+ g_signal_connect_after (view,
+ "focus-in-event",
+ G_CALLBACK (view_focused_in),
+ tab);
+
+ g_signal_connect_after (view,
+ "realize",
+ G_CALLBACK (view_realized),
+ tab);
+
+ g_signal_connect (view,
+ "drop-uris",
+ G_CALLBACK (on_drop_uris),
+ tab);
+ }
+
+ GeditTab *
+ _gedit_tab_new (void)
+ {
+ return g_object_new (GEDIT_TYPE_TAB, NULL);
+ }
+
+@@ -1407,94 +1404,94 @@ gedit_tab_get_view (GeditTab *tab)
+ */
+ GeditDocument *
+ gedit_tab_get_document (GeditTab *tab)
+ {
+ GeditView *view;
+
+ g_return_val_if_fail (GEDIT_IS_TAB (tab), NULL);
+
+ view = gedit_view_frame_get_view (tab->frame);
+
+ return GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
+ }
+
+ #define MAX_DOC_NAME_LENGTH 40
+
+ gchar *
+ _gedit_tab_get_name (GeditTab *tab)
+ {
+ GeditDocument *doc;
+ gchar *name;
+ gchar *docname;
+ gchar *tab_name;
+
+ g_return_val_if_fail (GEDIT_IS_TAB (tab), NULL);
+
+ doc = gedit_tab_get_document (tab);
+
+ name = gedit_document_get_short_name_for_display (doc);
+
+ /* Truncate the name so it doesn't get insanely wide. */
+- docname = tepl_utils_str_middle_truncate (name, MAX_DOC_NAME_LENGTH);
++ docname = gedit_utils_str_middle_truncate (name, MAX_DOC_NAME_LENGTH);
+
+ if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (doc)))
+ {
+ tab_name = g_strdup_printf ("*%s", docname);
+ }
+ else
+ {
+ tab_name = g_strdup (docname);
+ }
+
+ g_free (docname);
+ g_free (name);
+
+ return tab_name;
+ }
+
+ gchar *
+ _gedit_tab_get_tooltip (GeditTab *tab)
+ {
+ GeditDocument *doc;
+ gchar *tip;
+ gchar *uri;
+ gchar *ruri;
+ gchar *ruri_markup;
+
+ g_return_val_if_fail (GEDIT_IS_TAB (tab), NULL);
+
+ doc = gedit_tab_get_document (tab);
+
+ uri = _gedit_document_get_uri_for_display (doc);
+ g_return_val_if_fail (uri != NULL, NULL);
+
+- ruri = tepl_utils_replace_home_dir_with_tilde (uri);
++ ruri = gedit_utils_replace_home_dir_with_tilde (uri);
+ g_free (uri);
+
+ ruri_markup = g_markup_printf_escaped ("%s", ruri);
+
+ switch (tab->state)
+ {
+ gchar *content_type;
+ gchar *mime_type;
+ gchar *content_description;
+ gchar *content_full_description;
+ gchar *encoding;
+ GtkSourceFile *file;
+ const GtkSourceEncoding *enc;
+
+ case GEDIT_TAB_STATE_LOADING_ERROR:
+ tip = g_strdup_printf (_("Error opening file %s"),
+ ruri_markup);
+ break;
+
+ case GEDIT_TAB_STATE_REVERTING_ERROR:
+ tip = g_strdup_printf (_("Error reverting file %s"),
+ ruri_markup);
+ break;
+
+ case GEDIT_TAB_STATE_SAVING_ERROR:
+ tip = g_strdup_printf (_("Error saving file %s"),
+ ruri_markup);
+ break;
+ default:
+ content_type = gedit_document_get_content_type (doc);
+@@ -1606,65 +1603,63 @@ gedit_tab_get_from_document (GeditDocument *doc)
+ return g_object_get_data (G_OBJECT (doc), GEDIT_TAB_KEY);
+ }
+
+ static void
+ loader_progress_cb (goffset size,
+ goffset total_size,
+ GTask *loading_task)
+ {
+ LoaderData *data = g_task_get_task_data (loading_task);
+
+ g_return_if_fail (data->tab->state == GEDIT_TAB_STATE_LOADING ||
+ data->tab->state == GEDIT_TAB_STATE_REVERTING);
+
+ if (should_show_progress_info (&data->timer, size, total_size))
+ {
+ show_loading_info_bar (loading_task);
+ info_bar_set_progress (data->tab, size, total_size);
+ }
+ }
+
+ static void
+ goto_line (GTask *loading_task)
+ {
+ LoaderData *data = g_task_get_task_data (loading_task);
+ GeditDocument *doc = gedit_tab_get_document (data->tab);
+ GtkTextIter iter;
+
+ /* Move the cursor at the requested line if any. */
+ if (data->line_pos > 0)
+ {
+- TeplView *view = TEPL_VIEW (gedit_tab_get_view (data->tab));
+-
+- tepl_view_goto_line_offset (view,
+- data->line_pos - 1,
+- MAX (0, data->column_pos - 1));
++ gedit_document_goto_line_offset (doc,
++ data->line_pos - 1,
++ MAX (0, data->column_pos - 1));
+ return;
+ }
+
+ /* If enabled, move to the position stored in the metadata. */
+ if (g_settings_get_boolean (data->tab->editor_settings, GEDIT_SETTINGS_RESTORE_CURSOR_POSITION))
+ {
+ gchar *pos;
+ gint offset;
+
+ pos = gedit_document_get_metadata (doc, GEDIT_METADATA_ATTRIBUTE_POSITION);
+
+ offset = pos != NULL ? atoi (pos) : 0;
+ g_free (pos);
+
+ gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc),
+ &iter,
+ MAX (0, offset));
+
+ /* make sure it's a valid position, if the file
+ * changed we may have ended up in the middle of
+ * a utf8 character cluster */
+ if (!gtk_text_iter_is_cursor_position (&iter))
+ {
+ gtk_text_iter_set_line_offset (&iter, 0);
+ }
+ }
+
+ /* Otherwise to the top. */
+ else
+ {
+@@ -1726,72 +1721,72 @@ successful_load (GTask *loading_task)
+
+ if (data->user_requested_encoding)
+ {
+ const GtkSourceEncoding *encoding = gtk_source_file_loader_get_encoding (data->loader);
+ const gchar *charset = gtk_source_encoding_get_charset (encoding);
+
+ gedit_document_set_metadata (doc,
+ GEDIT_METADATA_ATTRIBUTE_ENCODING, charset,
+ NULL);
+ }
+
+ goto_line (loading_task);
+
+ /* Scroll to the cursor when the document is loaded, we need to do it in
+ * an idle as after the document is loaded the textview is still
+ * redrawing and relocating its internals.
+ */
+ if (data->tab->idle_scroll == 0)
+ {
+ data->tab->idle_scroll = g_idle_add ((GSourceFunc)scroll_to_cursor, data->tab);
+ }
+
+ location = gtk_source_file_loader_get_location (data->loader);
+
+ /* If the document is readonly we don't care how many times the file
+ * is opened.
+ */
+ if (!gtk_source_file_is_readonly (file) &&
+ file_already_opened (doc, location))
+ {
+- TeplInfoBar *info_bar;
++ GtkWidget *info_bar;
+
+ set_editable (data->tab, FALSE);
+
+- info_bar = tepl_io_error_info_bar_file_already_open (location);
++ info_bar = gedit_file_already_open_warning_info_bar_new (location);
+
+ g_signal_connect (info_bar,
+ "response",
+ G_CALLBACK (file_already_open_warning_info_bar_response),
+ data->tab);
+
+- set_info_bar (data->tab, GTK_WIDGET (info_bar), GTK_RESPONSE_CANCEL);
++ set_info_bar (data->tab, info_bar, GTK_RESPONSE_CANCEL);
+ }
+
+ /* When loading from stdin, the contents may not be saved, so set the
+ * buffer as modified.
+ */
+ if (location == NULL)
+ {
+ gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (doc), TRUE);
+ }
+
+ data->tab->ask_if_externally_modified = TRUE;
+
+ g_signal_emit_by_name (doc, "loaded");
+ }
+
+ static void
+ load_cb (GtkSourceFileLoader *loader,
+ GAsyncResult *result,
+ GTask *loading_task)
+ {
+ LoaderData *data = g_task_get_task_data (loading_task);
+ GeditDocument *doc;
+ GFile *location = gtk_source_file_loader_get_location (loader);
+ gboolean create_named_new_doc;
+ GError *error = NULL;
+
+ g_clear_pointer (&data->timer, g_timer_destroy);
+
+ gtk_source_file_loader_load_finish (loader, result, &error);
+
+@@ -2283,75 +2278,75 @@ save_cb (GtkSourceFileSaver *saver,
+ if (data->timer != NULL)
+ {
+ g_timer_destroy (data->timer);
+ data->timer = NULL;
+ }
+
+ set_info_bar (tab, NULL, GTK_RESPONSE_NONE);
+
+ if (error != NULL)
+ {
+ GtkWidget *info_bar;
+
+ gedit_tab_set_state (tab, GEDIT_TAB_STATE_SAVING_ERROR);
+
+ if (error->domain == GTK_SOURCE_FILE_SAVER_ERROR &&
+ error->code == GTK_SOURCE_FILE_SAVER_ERROR_EXTERNALLY_MODIFIED)
+ {
+ /* This error is recoverable */
+ info_bar = gedit_externally_modified_saving_error_info_bar_new (location, error);
+ g_return_if_fail (info_bar != NULL);
+
+ g_signal_connect (info_bar,
+ "response",
+ G_CALLBACK (externally_modified_error_info_bar_response),
+ saving_task);
+ }
+ else if (error->domain == G_IO_ERROR &&
+ error->code == G_IO_ERROR_CANT_CREATE_BACKUP)
+ {
+ /* This error is recoverable */
+- info_bar = GTK_WIDGET (tepl_io_error_info_bar_cant_create_backup (location, error));
++ info_bar = gedit_no_backup_saving_error_info_bar_new (location, error);
+ g_return_if_fail (info_bar != NULL);
+
+ g_signal_connect (info_bar,
+ "response",
+- G_CALLBACK (cant_create_backup_error_info_bar_response),
++ G_CALLBACK (no_backup_error_info_bar_response),
+ saving_task);
+ }
+ else if (error->domain == GTK_SOURCE_FILE_SAVER_ERROR &&
+ error->code == GTK_SOURCE_FILE_SAVER_ERROR_INVALID_CHARS)
+ {
+ /* If we have any invalid char in the document we must warn the user
+ * as it can make the document useless if it is saved.
+ */
+- info_bar = GTK_WIDGET (tepl_io_error_info_bar_invalid_characters (location));
++ info_bar = gedit_invalid_character_info_bar_new (location);
+ g_return_if_fail (info_bar != NULL);
+
+ g_signal_connect (info_bar,
+ "response",
+ G_CALLBACK (invalid_character_info_bar_response),
+ saving_task);
+ }
+ else if (error->domain == GTK_SOURCE_FILE_SAVER_ERROR ||
+ (error->domain == G_IO_ERROR &&
+ error->code != G_IO_ERROR_INVALID_DATA &&
+ error->code != G_IO_ERROR_PARTIAL_INPUT))
+ {
+ /* These errors are _NOT_ recoverable */
+ gedit_recent_remove_if_local (location);
+
+ info_bar = gedit_unrecoverable_saving_error_info_bar_new (location, error);
+ g_return_if_fail (info_bar != NULL);
+
+ g_signal_connect (info_bar,
+ "response",
+ G_CALLBACK (unrecoverable_saving_error_info_bar_response),
+ saving_task);
+ }
+ else
+ {
+ const GtkSourceEncoding *encoding;
+
+ /* This error is recoverable */
+ g_return_if_fail (error->domain == G_CONVERT_ERROR ||
+ error->domain == G_IO_ERROR);
+@@ -2679,69 +2674,69 @@ get_print_settings (GeditTab *tab)
+ GEDIT_PRINT_SETTINGS_KEY);
+
+ if (data == NULL)
+ {
+ settings = _gedit_app_get_default_print_settings (GEDIT_APP (g_application_get_default ()));
+ }
+ else
+ {
+ settings = gtk_print_settings_copy (GTK_PRINT_SETTINGS (data));
+ }
+
+ /* Be sure the OUTPUT_URI is unset, because otherwise the
+ * OUTPUT_BASENAME is not taken into account.
+ */
+ gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_OUTPUT_URI, NULL);
+
+ name = gedit_document_get_short_name_for_display (doc);
+ gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_OUTPUT_BASENAME, name);
+
+ g_free (name);
+
+ return settings;
+ }
+
+ /* FIXME: show the info bar only if the operation will be "long" */
+ static void
+ printing_cb (GeditPrintJob *job,
+ GeditPrintJobStatus status,
+ GeditTab *tab)
+ {
+- g_return_if_fail (TEPL_IS_PROGRESS_INFO_BAR (tab->info_bar));
++ g_return_if_fail (GEDIT_IS_PROGRESS_INFO_BAR (tab->info_bar));
+
+ gtk_widget_show (tab->info_bar);
+
+- tepl_progress_info_bar_set_text (TEPL_PROGRESS_INFO_BAR (tab->info_bar),
+- gedit_print_job_get_status_string (job));
++ gedit_progress_info_bar_set_text (GEDIT_PROGRESS_INFO_BAR (tab->info_bar),
++ gedit_print_job_get_status_string (job));
+
+- tepl_progress_info_bar_set_fraction (TEPL_PROGRESS_INFO_BAR (tab->info_bar),
+- gedit_print_job_get_progress (job));
++ gedit_progress_info_bar_set_fraction (GEDIT_PROGRESS_INFO_BAR (tab->info_bar),
++ gedit_print_job_get_progress (job));
+ }
+
+ static void
+ store_print_settings (GeditTab *tab,
+ GeditPrintJob *job)
+ {
+ GeditDocument *doc;
+ GtkPrintSettings *settings;
+ GtkPageSetup *page_setup;
+
+ doc = gedit_tab_get_document (tab);
+
+ settings = gedit_print_job_get_print_settings (job);
+
+ /* clear n-copies settings since we do not want to
+ * persist that one */
+ gtk_print_settings_unset (settings,
+ GTK_PRINT_SETTINGS_N_COPIES);
+
+ /* remember settings for this document */
+ g_object_set_data_full (G_OBJECT (doc),
+ GEDIT_PRINT_SETTINGS_KEY,
+ g_object_ref (settings),
+ (GDestroyNotify)g_object_unref);
+
+ /* make them the default */
+ _gedit_app_set_default_print_settings (GEDIT_APP (g_application_get_default ()),
+ settings);
+
+ page_setup = gedit_print_job_get_page_setup (job);
+@@ -2797,73 +2792,75 @@ show_preview_cb (GeditPrintJob *job,
+ /* destroy the info bar */
+ set_info_bar (tab, NULL, GTK_RESPONSE_NONE);
+
+ tab->print_preview = GTK_WIDGET (preview);
+ g_object_ref_sink (tab->print_preview);
+
+ gtk_box_pack_end (GTK_BOX (tab), tab->print_preview, TRUE, TRUE, 0);
+
+ gtk_widget_show (tab->print_preview);
+ gtk_widget_grab_focus (tab->print_preview);
+
+ gedit_tab_set_state (tab, GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW);
+ }
+
+ static void
+ print_cancelled (GtkWidget *bar,
+ gint response_id,
+ GeditTab *tab)
+ {
+ gedit_debug (DEBUG_TAB);
+
+ if (tab->print_job != NULL)
+ {
+ gedit_print_job_cancel (tab->print_job);
+ }
+ }
+
+ static void
+ add_printing_info_bar (GeditTab *tab)
+ {
+- TeplProgressInfoBar *bar;
++ GtkWidget *bar;
+
+- bar = tepl_progress_info_bar_new ("document-print", NULL, TRUE);
++ bar = gedit_progress_info_bar_new ("document-print",
++ "",
++ TRUE);
+
+ g_signal_connect (bar,
+ "response",
+ G_CALLBACK (print_cancelled),
+ tab);
+
+- set_info_bar (tab, GTK_WIDGET (bar), GTK_RESPONSE_NONE);
++ set_info_bar (tab, bar, GTK_RESPONSE_NONE);
+
+ /* hide until we start printing */
+- gtk_widget_hide (GTK_WIDGET (bar));
++ gtk_widget_hide (bar);
+ }
+
+ void
+ _gedit_tab_print (GeditTab *tab)
+ {
+ GeditView *view;
+ GtkPageSetup *setup;
+ GtkPrintSettings *settings;
+ GtkPrintOperationResult res;
+ GError *error = NULL;
+
+ g_return_if_fail (GEDIT_IS_TAB (tab));
+
+ /* FIXME: currently we can have just one printoperation going on at a
+ * given time, so before starting the print we close the preview.
+ * Would be nice to handle it properly though.
+ */
+ if (tab->state == GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW)
+ {
+ close_printing (tab);
+ }
+
+ g_return_if_fail (tab->print_job == NULL);
+ g_return_if_fail (tab->state == GEDIT_TAB_STATE_NORMAL);
+
+ view = gedit_tab_get_view (tab);
+
+ tab->print_job = gedit_print_job_new (view);
+
+ add_printing_info_bar (tab);
+diff --git a/gedit/gedit-utils.c b/gedit/gedit-utils.c
+index 9fc9e4fb0..ae7e92156 100644
+--- a/gedit/gedit-utils.c
++++ b/gedit/gedit-utils.c
+@@ -1,56 +1,55 @@
+ /*
+ * gedit-utils.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
+ * Copyright (C) 2000, 2002 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2003-2005 Paolo Maggi
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #include "gedit-utils.h"
+ #include
+ #include
+-#include
+ #include "gedit-debug.h"
+
+ gboolean
+ gedit_utils_menu_position_under_tree_view (GtkTreeView *tree_view,
+ GdkRectangle *rect)
+ {
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ gint count_rows;
+ GList *rows;
+ gint widget_x, widget_y;
+
+ model = gtk_tree_view_get_model (tree_view);
+ g_return_val_if_fail (model != NULL, FALSE);
+
+ selection = gtk_tree_view_get_selection (tree_view);
+ g_return_val_if_fail (selection != NULL, FALSE);
+
+ count_rows = gtk_tree_selection_count_selected_rows (selection);
+ if (count_rows != 1)
+ return FALSE;
+
+ rows = gtk_tree_selection_get_selected_rows (selection, &model);
+ gtk_tree_view_get_cell_area (tree_view, (GtkTreePath *)(rows->data),
+ gtk_tree_view_get_column (tree_view, 0),
+ rect);
+
+ gtk_tree_view_convert_bin_window_to_widget_coords (tree_view, rect->x, rect->y, &widget_x, &widget_y);
+ rect->x = widget_x;
+ rect->y = widget_y;
+@@ -60,160 +59,321 @@ gedit_utils_menu_position_under_tree_view (GtkTreeView *tree_view,
+ }
+
+ /**
+ * gedit_utils_set_atk_name_description:
+ * @widget: The Gtk widget for which name/description to be set
+ * @name: Atk name string
+ * @description: Atk description string
+ *
+ * This function sets up name and description
+ * for a specified gtk widget.
+ */
+ void
+ gedit_utils_set_atk_name_description (GtkWidget *widget,
+ const gchar *name,
+ const gchar *description)
+ {
+ AtkObject *aobj;
+
+ aobj = gtk_widget_get_accessible (widget);
+
+ if (!(GTK_IS_ACCESSIBLE (aobj)))
+ return;
+
+ if (name)
+ atk_object_set_name (aobj, name);
+
+ if (description)
+ atk_object_set_description (aobj, description);
+ }
+
++void
++gedit_warning (GtkWindow *parent, const gchar *format, ...)
++{
++ va_list args;
++ gchar *str;
++ GtkWidget *dialog;
++ GtkWindowGroup *wg = NULL;
++
++ g_return_if_fail (format != NULL);
++
++ if (parent != NULL)
++ wg = gtk_window_get_group (parent);
++
++ va_start (args, format);
++ str = g_strdup_vprintf (format, args);
++ va_end (args);
++
++ dialog = gtk_message_dialog_new_with_markup (
++ parent,
++ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
++ GTK_MESSAGE_ERROR,
++ GTK_BUTTONS_OK,
++ "%s", str);
++
++ g_free (str);
++
++ if (wg != NULL)
++ gtk_window_group_add_window (wg, GTK_WINDOW (dialog));
++
++ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
++
++ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
++
++ g_signal_connect (G_OBJECT (dialog),
++ "response",
++ G_CALLBACK (gtk_widget_destroy),
++ NULL);
++
++ gtk_widget_show (dialog);
++}
++
++/* the following functions are taken from eel */
++
++static gchar *
++gedit_utils_str_truncate (const gchar *string,
++ guint truncate_length,
++ gboolean middle)
++{
++ GString *truncated;
++ guint length;
++ guint n_chars;
++ guint num_left_chars;
++ guint right_offset;
++ guint delimiter_length;
++ const gchar *delimiter = "\342\200\246";
++
++ g_return_val_if_fail (string != NULL, NULL);
++
++ length = strlen (string);
++
++ g_return_val_if_fail (g_utf8_validate (string, length, NULL), NULL);
++
++ /* It doesnt make sense to truncate strings to less than
++ * the size of the delimiter plus 2 characters (one on each
++ * side)
++ */
++ delimiter_length = g_utf8_strlen (delimiter, -1);
++ if (truncate_length < (delimiter_length + 2))
++ {
++ return g_strdup (string);
++ }
++
++ n_chars = g_utf8_strlen (string, length);
++
++ /* Make sure the string is not already small enough. */
++ if (n_chars <= truncate_length)
++ {
++ return g_strdup (string);
++ }
++
++ /* Find the 'middle' where the truncation will occur. */
++ if (middle)
++ {
++ num_left_chars = (truncate_length - delimiter_length) / 2;
++ right_offset = n_chars - truncate_length + num_left_chars + delimiter_length;
++
++ truncated = g_string_new_len (string,
++ g_utf8_offset_to_pointer (string, num_left_chars) - string);
++ g_string_append (truncated, delimiter);
++ g_string_append (truncated, g_utf8_offset_to_pointer (string, right_offset));
++ }
++ else
++ {
++ num_left_chars = truncate_length - delimiter_length;
++ truncated = g_string_new_len (string,
++ g_utf8_offset_to_pointer (string, num_left_chars) - string);
++ g_string_append (truncated, delimiter);
++ }
++
++ return g_string_free (truncated, FALSE);
++}
++
++gchar *
++gedit_utils_str_middle_truncate (const gchar *string,
++ guint truncate_length)
++{
++ return gedit_utils_str_truncate (string, truncate_length, TRUE);
++}
++
++gchar *
++gedit_utils_str_end_truncate (const gchar *string,
++ guint truncate_length)
++{
++ return gedit_utils_str_truncate (string, truncate_length, FALSE);
++}
++
+ static gchar *
+ uri_get_dirname (const gchar *uri)
+ {
+ gchar *res;
+ gchar *str;
+
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ /* CHECK: does it work with uri chaining? - Paolo */
+ str = g_path_get_dirname (uri);
+ g_return_val_if_fail (str != NULL, g_strdup ("."));
+
+ if ((strlen (str) == 1) && (*str == '.'))
+ {
+ g_free (str);
+
+ return NULL;
+ }
+
+- res = tepl_utils_replace_home_dir_with_tilde (str);
++ res = gedit_utils_replace_home_dir_with_tilde (str);
+
+ g_free (str);
+
+ return res;
+ }
+
+ /**
+ * gedit_utils_location_get_dirname_for_display:
+ * @location: the location
+ *
+ * Returns a string suitable to be displayed in the UI indicating
+ * the name of the directory where the file is located.
+ * For remote files it may also contain the hostname etc.
+ * For local files it tries to replace the home dir with ~.
+ *
+ * Returns: (transfer full): a string to display the dirname
+ */
+ gchar *
+ gedit_utils_location_get_dirname_for_display (GFile *location)
+ {
+ gchar *uri;
+ gchar *res;
+ GMount *mount;
+
+ g_return_val_if_fail (location != NULL, NULL);
+
+ /* we use the parse name, that is either the local path
+ * or an uri but which is utf8 safe */
+ uri = g_file_get_parse_name (location);
+
+ /* FIXME: this is sync... is it a problem? */
+ mount = g_file_find_enclosing_mount (location, NULL, NULL);
+ if (mount != NULL)
+ {
+ gchar *mount_name;
+ gchar *path = NULL;
+ gchar *dirname;
+
+ mount_name = g_mount_get_name (mount);
+ g_object_unref (mount);
+
+ /* obtain the "path" part of the uri */
+- tepl_utils_decode_uri (uri,
+- NULL, NULL,
+- NULL, NULL,
+- &path);
++ gedit_utils_decode_uri (uri,
++ NULL, NULL,
++ NULL, NULL,
++ &path);
+
+ if (path == NULL)
+ {
+ dirname = uri_get_dirname (uri);
+ }
+ else
+ {
+ dirname = uri_get_dirname (path);
+ }
+
+ if (dirname == NULL || strcmp (dirname, ".") == 0)
+ {
+ res = mount_name;
+ }
+ else
+ {
+ res = g_strdup_printf ("%s %s", mount_name, dirname);
+ g_free (mount_name);
+ }
+
+ g_free (path);
+ g_free (dirname);
+ }
+ else
+ {
+ /* fallback for local files or uris without mounts */
+ res = uri_get_dirname (uri);
+ }
+
+ g_free (uri);
+
+ return res;
+ }
+
++gchar *
++gedit_utils_replace_home_dir_with_tilde (const gchar *uri)
++{
++ gchar *tmp;
++ gchar *home;
++
++ g_return_val_if_fail (uri != NULL, NULL);
++
++ /* Note that g_get_home_dir returns a const string */
++ tmp = (gchar *)g_get_home_dir ();
++
++ if (tmp == NULL)
++ return g_strdup (uri);
++
++ home = g_filename_to_utf8 (tmp, -1, NULL, NULL, NULL);
++ if (home == NULL)
++ return g_strdup (uri);
++
++ if (strcmp (uri, home) == 0)
++ {
++ g_free (home);
++
++ return g_strdup ("~/");
++ }
++
++ tmp = home;
++ home = g_strdup_printf ("%s/", tmp);
++ g_free (tmp);
++
++ if (g_str_has_prefix (uri, home))
++ {
++ gchar *res;
++
++ res = g_strdup_printf ("~/%s", uri + strlen (home));
++
++ g_free (home);
++
++ return res;
++ }
++
++ g_free (home);
++
++ return g_strdup (uri);
++}
++
+ static gboolean
+ is_valid_scheme_character (gchar c)
+ {
+ return g_ascii_isalnum (c) || c == '+' || c == '-' || c == '.';
+ }
+
+ static gboolean
+ has_valid_scheme (const gchar *uri)
+ {
+ const gchar *p;
+
+ p = uri;
+
+ if (!is_valid_scheme_character (*p))
+ {
+ return FALSE;
+ }
+
+ do
+ {
+ p++;
+ } while (is_valid_scheme_character (*p));
+
+ return *p == ':';
+ }
+
+ gboolean
+ gedit_utils_is_valid_location (GFile *location)
+ {
+ const guchar *p;
+@@ -326,61 +486,61 @@ gedit_utils_basename_for_display (GFile *location)
+
+ /* First, try to query the display name, but only on local files */
+ if (g_file_has_uri_scheme (location, "file"))
+ {
+ GFileInfo *info;
+
+ info = g_file_query_info (location,
+ G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ NULL);
+
+ if (info)
+ {
+ /* Simply get the display name to use as the basename */
+ name = g_strdup (g_file_info_get_display_name (info));
+ g_object_unref (info);
+ }
+ else
+ {
+ /* This is a local file, and therefore we will use
+ * g_filename_display_basename on the local path */
+ gchar *local_path;
+
+ local_path = g_file_get_path (location);
+ name = g_filename_display_basename (local_path);
+ g_free (local_path);
+ }
+ }
+ else if (g_file_has_parent (location, NULL) ||
+- !tepl_utils_decode_uri (uri, NULL, NULL, &hn, NULL, NULL))
++ !gedit_utils_decode_uri (uri, NULL, NULL, &hn, NULL, NULL))
+ {
+ /* For remote files with a parent (so not just http://foo.com)
+ or remote file for which the decoding of the host name fails,
+ use the _parse_name and take basename of that */
+ gchar *parse_name;
+ gchar *base;
+
+ parse_name = g_file_get_parse_name (location);
+ base = g_filename_display_basename (parse_name);
+ name = g_uri_unescape_string (base, NULL);
+
+ g_free (base);
+ g_free (parse_name);
+ }
+ else
+ {
+ /* display '/ on ' using the decoded host */
+ gchar *hn_utf8;
+
+ if (hn != NULL)
+ {
+ hn_utf8 = g_utf8_make_valid (hn, -1);
+ }
+ else
+ {
+ /* we should never get here */
+ hn_utf8 = g_strdup ("?");
+ }
+
+ /* Translators: '/ on ' */
+@@ -411,60 +571,219 @@ gedit_utils_drop_get_uris (GtkSelectionData *selection_data)
+ gchar **uris;
+ gint i;
+ gint p = 0;
+ gchar **uri_list;
+
+ uris = g_uri_list_extract_uris ((gchar *) gtk_selection_data_get_data (selection_data));
+ uri_list = g_new0(gchar *, g_strv_length (uris) + 1);
+
+ for (i = 0; uris[i] != NULL; i++)
+ {
+ gchar *uri;
+
+ uri = make_canonical_uri_from_shell_arg (uris[i]);
+
+ /* Silently ignore malformed URI/filename */
+ if (uri != NULL)
+ uri_list[p++] = uri;
+ }
+
+ if (*uri_list == NULL)
+ {
+ g_free(uri_list);
+ g_strfreev (uris);
+ return NULL;
+ }
+
+ g_strfreev (uris);
+ return uri_list;
+ }
+
++static void
++null_ptr (gchar **ptr)
++{
++ if (ptr)
++ *ptr = NULL;
++}
++
++/**
++ * gedit_utils_decode_uri:
++ * @uri: the uri to decode
++ * @scheme: (out) (allow-none): return value pointer for the uri's
++ * scheme (e.g. http, sftp, ...), or %NULL
++ * @user: (out) (allow-none): return value pointer for the uri user info, or %NULL
++ * @port: (out) (allow-none): return value pointer for the uri port, or %NULL
++ * @host: (out) (allow-none): return value pointer for the uri host, or %NULL
++ * @path: (out) (allow-none): return value pointer for the uri path, or %NULL
++ *
++ * Parse and break an uri apart in its individual components like the uri
++ * scheme, user info, port, host and path. The return value pointer can be
++ * %NULL to ignore certain parts of the uri. If the function returns %TRUE, then
++ * all return value pointers should be freed using g_free
++ *
++ * Return value: %TRUE if the uri could be properly decoded, %FALSE otherwise.
++ */
++gboolean
++gedit_utils_decode_uri (const gchar *uri,
++ gchar **scheme,
++ gchar **user,
++ gchar **host,
++ gchar **port,
++ gchar **path)
++{
++ /* Largely copied from glib/gio/gdummyfile.c:_g_decode_uri. This
++ * functionality should be in glib/gio, but for now we implement it
++ * ourselves (see bug #546182) */
++
++ const char *p, *in, *hier_part_start, *hier_part_end;
++ char *out;
++ char c;
++
++ /* From RFC 3986 Decodes:
++ * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
++ */
++
++ p = uri;
++
++ null_ptr (scheme);
++ null_ptr (user);
++ null_ptr (port);
++ null_ptr (host);
++ null_ptr (path);
++
++ /* Decode scheme:
++ * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
++ */
++
++ if (!g_ascii_isalpha (*p))
++ return FALSE;
++
++ while (1)
++ {
++ c = *p++;
++
++ if (c == ':')
++ break;
++
++ if (!(g_ascii_isalnum(c) ||
++ c == '+' ||
++ c == '-' ||
++ c == '.'))
++ {
++ return FALSE;
++ }
++ }
++
++ if (scheme)
++ {
++ *scheme = g_malloc (p - uri);
++ out = *scheme;
++
++ for (in = uri; in < p - 1; in++)
++ {
++ *out++ = g_ascii_tolower (*in);
++ }
++
++ *out = '\0';
++ }
++
++ hier_part_start = p;
++ hier_part_end = p + strlen (p);
++
++ if (hier_part_start[0] == '/' && hier_part_start[1] == '/')
++ {
++ const char *authority_start, *authority_end;
++ const char *userinfo_start, *userinfo_end;
++ const char *host_start, *host_end;
++ const char *port_start;
++
++ authority_start = hier_part_start + 2;
++ /* authority is always followed by / or nothing */
++ authority_end = memchr (authority_start, '/', hier_part_end - authority_start);
++
++ if (authority_end == NULL)
++ authority_end = hier_part_end;
++
++ /* 3.2:
++ * authority = [ userinfo "@" ] host [ ":" port ]
++ */
++
++ userinfo_end = memchr (authority_start, '@', authority_end - authority_start);
++
++ if (userinfo_end)
++ {
++ userinfo_start = authority_start;
++
++ if (user)
++ *user = g_uri_unescape_segment (userinfo_start, userinfo_end, NULL);
++
++ if (user && *user == NULL)
++ {
++ if (scheme)
++ g_free (*scheme);
++
++ return FALSE;
++ }
++
++ host_start = userinfo_end + 1;
++ }
++ else
++ {
++ host_start = authority_start;
++ }
++
++ port_start = memchr (host_start, ':', authority_end - host_start);
++
++ if (port_start)
++ {
++ host_end = port_start++;
++
++ if (port)
++ *port = g_strndup (port_start, authority_end - port_start);
++ }
++ else
++ {
++ host_end = authority_end;
++ }
++
++ if (host)
++ *host = g_strndup (host_start, host_end - host_start);
++
++ hier_part_start = authority_end;
++ }
++
++ if (path)
++ *path = g_uri_unescape_segment (hier_part_start, hier_part_end, "/");
++
++ return TRUE;
++}
++
+ GtkSourceCompressionType
+ gedit_utils_get_compression_type_from_content_type (const gchar *content_type)
+ {
+ if (content_type == NULL)
+ {
+ return GTK_SOURCE_COMPRESSION_TYPE_NONE;
+ }
+
+ if (g_content_type_is_a (content_type, "application/x-gzip"))
+ {
+ return GTK_SOURCE_COMPRESSION_TYPE_GZIP;
+ }
+
+ return GTK_SOURCE_COMPRESSION_TYPE_NONE;
+ }
+
+ /* Copied from nautilus */
+ static gchar *
+ get_direct_save_filename (GdkDragContext *context)
+ {
+ guchar *prop_text;
+ gint prop_len;
+
+ if (!gdk_property_get (gdk_drag_context_get_source_window (context), gdk_atom_intern ("XdndDirectSave0", FALSE),
+ gdk_atom_intern ("text/plain", FALSE), 0, 1024, FALSE, NULL, NULL,
+ &prop_len, &prop_text) && prop_text != NULL) {
+ return NULL;
+ }
+
+ /* Zero-terminate the string */
+diff --git a/gedit/gedit-utils.h b/gedit/gedit-utils.h
+index a6b423db0..64af070d2 100644
+--- a/gedit/gedit-utils.h
++++ b/gedit/gedit-utils.h
+@@ -1,56 +1,75 @@
+ /*
+ * gedit-utils.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002 - 2005 Paolo Maggi
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #ifndef GEDIT_UTILS_H
+ #define GEDIT_UTILS_H
+
+ #include
+
+ G_BEGIN_DECLS
+
++/* useful macro */
++#define GBOOLEAN_TO_POINTER(i) (GINT_TO_POINTER ((i) ? 2 : 1))
++#define GPOINTER_TO_BOOLEAN(i) ((gboolean) ((GPOINTER_TO_INT(i) == 2) ? TRUE : FALSE))
++
+ gboolean gedit_utils_menu_position_under_tree_view (GtkTreeView *tree_view,
+ GdkRectangle *rect);
+
++gchar *gedit_utils_str_middle_truncate (const gchar *string,
++ guint truncate_length);
++gchar *gedit_utils_str_end_truncate (const gchar *string,
++ guint truncate_length);
+ void gedit_utils_set_atk_name_description (GtkWidget *widget,
+ const gchar *name,
+ const gchar *description);
++void gedit_warning (GtkWindow *parent,
++ const gchar *format,
++ ...) G_GNUC_PRINTF(2, 3);
+
+-gchar *gedit_utils_location_get_dirname_for_display (GFile *location);
++gchar *gedit_utils_location_get_dirname_for_display (GFile *location);
++gchar *gedit_utils_replace_home_dir_with_tilde (const gchar *uri);
+
+ gboolean gedit_utils_is_valid_location (GFile *location);
+
+ gchar *gedit_utils_basename_for_display (GFile *location);
+
++gboolean gedit_utils_decode_uri (const gchar *uri,
++ gchar **scheme,
++ gchar **user,
++ gchar **host,
++ gchar **port,
++ gchar **path);
++
+ /* Turns data from a drop into a list of well formatted uris */
+ gchar **gedit_utils_drop_get_uris (GtkSelectionData *selection_data);
+
+ gchar *gedit_utils_set_direct_save_filename (GdkDragContext *context);
+
+ GtkSourceCompressionType gedit_utils_get_compression_type_from_content_type (const gchar *content_type);
+
+ const gchar *gedit_utils_newline_type_to_string (GtkSourceNewlineType newline_type);
+
+ G_END_DECLS
+
+ #endif /* GEDIT_UTILS_H */
+
+ /* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-view-centering.c b/gedit/gedit-view-centering.c
+new file mode 100644
+index 000000000..f9c742076
+--- /dev/null
++++ b/gedit/gedit-view-centering.c
+@@ -0,0 +1,495 @@
++/*
++ * gedit-view-centering.c
++ * This file is part of gedit
++ *
++ * Copyright (C) 2014 - Sébastien Lafargue
++ *
++ * Gedit is free software; you can redistribute this file and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * Gedit 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ * Based on Christian Hergert's prototype.
++ */
++
++#include "gedit-view-centering.h"
++
++#include
++
++#include "gedit-view.h"
++#include "gedit-debug.h"
++
++struct _GeditViewCenteringPrivate
++{
++ GtkWidget *box;
++ GtkWidget *scrolled_window;
++ GtkWidget *sourceview;
++ GtkWidget *spacer;
++
++ GtkStyleContext *view_context;
++ GdkRGBA view_background;
++ GdkRGBA view_line_margin_fg;
++ GdkRGBA view_margin_background;
++ guint view_text_width;
++
++ guint centered : 1;
++ guint view_background_set : 1;
++ guint view_line_margin_fg_set : 1;
++ guint view_margin_background_set : 1;
++};
++
++G_DEFINE_TYPE_WITH_PRIVATE (GeditViewCentering, gedit_view_centering, GTK_TYPE_BIN)
++
++#define STYLE_TEXT "text"
++#define STYLE_RIGHT_MARGIN "right-margin"
++
++#define RIGHT_MARGIN_LINE_ALPHA 40
++#define RIGHT_MARGIN_OVERLAY_ALPHA 15
++
++static gboolean
++get_style (GtkSourceStyleScheme *scheme,
++ const gchar *style_id,
++ const gchar *attribute,
++ GdkRGBA *color)
++{
++ GtkSourceStyle *style;
++ gchar *style_string;
++
++ style = gtk_source_style_scheme_get_style (scheme, style_id);
++ if (!style)
++ {
++ return FALSE;
++ }
++
++ g_object_get (style, attribute, &style_string, NULL);
++ if (style_string)
++ {
++ gdk_rgba_parse (color, style_string);
++ g_free (style_string);
++
++ return TRUE;
++ }
++
++ return FALSE;
++}
++
++static void
++get_spacer_colors (GeditViewCentering *container,
++ GtkSourceStyleScheme *scheme)
++{
++ GeditViewCenteringPrivate *priv = container->priv;
++
++ if (scheme)
++ {
++ priv->view_background_set = get_style (scheme,
++ STYLE_TEXT, "background",
++ &priv->view_background);
++
++ priv->view_line_margin_fg_set = get_style (scheme,
++ STYLE_RIGHT_MARGIN, "foreground",
++ &priv->view_line_margin_fg);
++ priv->view_line_margin_fg.alpha = RIGHT_MARGIN_LINE_ALPHA / 255.0;
++
++ priv->view_margin_background_set = get_style (scheme,
++ STYLE_RIGHT_MARGIN, "background",
++ &priv->view_margin_background);
++ priv->view_margin_background.alpha = RIGHT_MARGIN_OVERLAY_ALPHA / 255.0;
++ }
++}
++
++/* FIXME: when GeditViewCentering will be transfered to GtkSourceView,
++ * this method will be replaced by a call to a new method called
++ * gtk_source_view_get_right_margin_pixel_position ()
++ */
++static guint
++_gedit_view_centering_get_right_margin_pixel_position (GeditViewCentering *container)
++{
++ GeditViewCenteringPrivate *priv;
++ gchar *str;
++ PangoFontDescription *font_desc;
++ PangoLayout *layout;
++ guint right_margin_position;
++ gint width = 0;
++
++ g_return_val_if_fail (GEDIT_IS_VIEW_CENTERING (container), 0);
++
++ priv = container->priv;
++
++ right_margin_position = gtk_source_view_get_right_margin_position (GTK_SOURCE_VIEW (priv->sourceview));
++
++ gtk_style_context_save (priv->view_context);
++ gtk_style_context_set_state (priv->view_context, GTK_STATE_FLAG_NORMAL);
++ gtk_style_context_get (priv->view_context,
++ gtk_style_context_get_state (priv->view_context),
++ GTK_STYLE_PROPERTY_FONT, &font_desc,
++ NULL);
++ gtk_style_context_restore (priv->view_context);
++
++ str = g_strnfill (right_margin_position, '_');
++ layout = gtk_widget_create_pango_layout (GTK_WIDGET (priv->sourceview), str);
++ g_free (str);
++
++ pango_layout_set_font_description (layout, font_desc);
++ pango_font_description_free (font_desc);
++ pango_layout_get_pixel_size (layout, &width, NULL);
++
++ g_object_unref (G_OBJECT (layout));
++
++ return width;
++}
++
++static void
++on_view_right_margin_visibility_changed (GeditView *view,
++ GParamSpec *pspec,
++ GeditViewCentering *container)
++{
++ GeditViewCenteringPrivate *priv = container->priv;
++ gboolean visibility;
++
++ visibility = gtk_source_view_get_show_right_margin (GTK_SOURCE_VIEW (priv->sourceview));
++
++ gtk_widget_set_visible (GTK_WIDGET (container->priv->spacer), visibility && priv->centered);
++}
++
++static void
++on_view_right_margin_position_changed (GeditView *view,
++ GParamSpec *pspec,
++ GeditViewCentering *container)
++{
++ GeditViewCenteringPrivate *priv = container->priv;
++ gboolean visibility;
++
++ priv->view_text_width = _gedit_view_centering_get_right_margin_pixel_position (container);
++
++ visibility = gtk_source_view_get_show_right_margin (GTK_SOURCE_VIEW (priv->sourceview));
++
++ if (visibility)
++ {
++ gtk_widget_queue_resize (priv->spacer);
++ }
++}
++
++static void
++on_view_context_changed (GtkStyleContext *stylecontext,
++ GeditViewCentering *container)
++{
++ GeditViewCenteringPrivate *priv = container->priv;
++ GtkTextBuffer *buffer;
++ GtkSourceStyleScheme *scheme;
++ gboolean visibility;
++
++ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->sourceview));
++ scheme = gtk_source_buffer_get_style_scheme (GTK_SOURCE_BUFFER (buffer));
++ get_spacer_colors (container, scheme);
++
++ priv->view_text_width = _gedit_view_centering_get_right_margin_pixel_position (container);
++
++ visibility = gtk_source_view_get_show_right_margin (GTK_SOURCE_VIEW (priv->sourceview));
++
++ if (visibility)
++ {
++ gtk_widget_queue_resize (priv->spacer);
++ }
++}
++
++static gboolean
++on_spacer_draw (GeditViewCentering *container,
++ cairo_t *cr,
++ GtkDrawingArea *spacer)
++{
++ GeditViewCenteringPrivate *priv = container->priv;
++ GtkStyleContext *context;
++ guint width, height;
++
++ if (!container->priv->sourceview)
++ {
++ return FALSE;
++ }
++
++ width = gtk_widget_get_allocated_width (GTK_WIDGET (spacer));
++ height = gtk_widget_get_allocated_height (GTK_WIDGET (spacer));
++
++ context = gtk_widget_get_style_context (GTK_WIDGET (spacer));
++ gtk_style_context_save (context);
++ gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
++ gtk_render_background (context, cr, 0, 0, width, height);
++ gtk_style_context_restore (context);
++
++ cairo_set_line_width (cr, 1.0);
++
++ if (priv->view_background_set)
++ {
++ gdk_cairo_set_source_rgba (cr, &container->priv->view_background);
++ cairo_rectangle (cr, 0, 0, width, height);
++ cairo_fill (cr);
++ }
++
++ if (priv->view_margin_background_set)
++ {
++ gdk_cairo_set_source_rgba (cr, &container->priv->view_margin_background);
++ cairo_rectangle (cr, 0, 0, width, height);
++ cairo_fill (cr);
++ }
++
++ if (priv->view_line_margin_fg_set)
++ {
++ gdk_cairo_set_source_rgba (cr, &container->priv->view_line_margin_fg);
++ cairo_move_to (cr, width - 0.5, 0);
++ cairo_line_to (cr, width - 0.5, height);
++ cairo_stroke (cr);
++ }
++
++ return FALSE;
++}
++
++static void
++gedit_view_centering_remove (GtkContainer *container,
++ GtkWidget *child)
++{
++ GeditViewCenteringPrivate *priv;
++
++ g_assert (GEDIT_IS_VIEW_CENTERING (container));
++
++ priv = GEDIT_VIEW_CENTERING (container)->priv;
++
++ if (priv->sourceview == child)
++ {
++ gtk_container_remove (GTK_CONTAINER (priv->scrolled_window), priv->sourceview);
++ g_object_remove_weak_pointer (G_OBJECT (priv->sourceview), (gpointer *)&priv->sourceview);
++ priv->sourceview = NULL;
++ priv->view_context = NULL;
++ }
++ else
++ {
++ GTK_CONTAINER_CLASS (gedit_view_centering_parent_class)->remove (container, child);
++ }
++}
++
++static void
++gedit_view_centering_add (GtkContainer *container,
++ GtkWidget *child)
++{
++ GeditViewCenteringPrivate *priv;
++ GtkTextBuffer *buffer;
++ GtkSourceStyleScheme *scheme;
++
++ g_assert (GEDIT_IS_VIEW_CENTERING (container));
++
++ priv = GEDIT_VIEW_CENTERING (container)->priv;
++
++ if (GEDIT_IS_VIEW (child))
++ {
++ if (priv->sourceview)
++ {
++ gedit_view_centering_remove (container, priv->sourceview);
++ }
++
++ priv->sourceview = child;
++ g_object_add_weak_pointer (G_OBJECT (child), (gpointer *)&priv->sourceview);
++ gtk_container_add (GTK_CONTAINER (priv->scrolled_window), child);
++
++ priv->view_context = gtk_widget_get_style_context (child);
++
++ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->sourceview));
++ scheme = gtk_source_buffer_get_style_scheme (GTK_SOURCE_BUFFER (buffer));
++ get_spacer_colors (GEDIT_VIEW_CENTERING (container), scheme);
++
++ g_signal_connect (priv->sourceview,
++ "notify::right-margin-position",
++ G_CALLBACK (on_view_right_margin_position_changed),
++ container);
++
++ g_signal_connect (priv->sourceview,
++ "notify::show-right-margin",
++ G_CALLBACK (on_view_right_margin_visibility_changed),
++ container);
++
++ g_signal_connect (priv->view_context,
++ "changed",
++ G_CALLBACK (on_view_context_changed),
++ container);
++
++ gtk_widget_queue_resize (GTK_WIDGET (container));
++ }
++ else
++ {
++ GTK_CONTAINER_CLASS (gedit_view_centering_parent_class)->add (container, child);
++ }
++}
++
++static gboolean
++on_spacer_scroll_event (GtkWidget *widget,
++ GdkEvent *event,
++ GeditViewCentering *container)
++{
++ GdkEventScroll *new_scroll_event;
++
++ new_scroll_event = (GdkEventScroll *)gdk_event_copy (event);
++ g_object_unref (new_scroll_event->window);
++
++ new_scroll_event->window = g_object_ref (gtk_widget_get_window (container->priv->sourceview));
++ new_scroll_event->send_event = TRUE;
++
++ new_scroll_event->x = 0;
++ new_scroll_event->y = 0;
++ new_scroll_event->x_root = 0;
++ new_scroll_event->y_root = 0;
++
++ gtk_main_do_event ((GdkEvent *)new_scroll_event);
++ gdk_event_free ((GdkEvent *)new_scroll_event);
++
++ return TRUE;
++}
++
++static void
++gedit_view_centering_size_allocate (GtkWidget *widget,
++ GtkAllocation *alloc)
++{
++ GeditViewCenteringPrivate *priv;
++ GtkTextView *view;
++ gint container_width;
++ gint gutter_width;
++ gint text_width;
++ gint spacer_width;
++ gint current_spacer_width;
++ GdkWindow *gutter_window;
++
++ g_assert (GEDIT_IS_VIEW_CENTERING (widget));
++
++ priv = GEDIT_VIEW_CENTERING (widget)->priv;
++
++ view = GTK_TEXT_VIEW (priv->sourceview);
++
++ if (view)
++ {
++ container_width = alloc->width;
++
++ gutter_window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_LEFT);
++ gutter_width = (gutter_window) ? gdk_window_get_width (gutter_window) : 0;
++
++ text_width = priv->view_text_width;
++ spacer_width = MAX (0, container_width - text_width - gutter_width) / 2;
++
++ g_object_get(priv->spacer, "width-request", ¤t_spacer_width, NULL);
++
++ if (current_spacer_width != spacer_width)
++ {
++ g_object_set(priv->spacer, "width-request", spacer_width, NULL);
++ }
++ }
++
++ GTK_WIDGET_CLASS (gedit_view_centering_parent_class)->size_allocate (widget, alloc);
++}
++
++static void
++gedit_view_centering_finalize (GObject *object)
++{
++ GeditViewCentering *container = GEDIT_VIEW_CENTERING (object);
++ GeditViewCenteringPrivate *priv = container->priv;
++
++ if (priv->sourceview)
++ {
++ gedit_view_centering_remove (GTK_CONTAINER (container), priv->sourceview);
++ }
++
++ G_OBJECT_CLASS (gedit_view_centering_parent_class)->finalize (object);
++}
++
++static void
++gedit_view_centering_class_init (GeditViewCenteringClass *klass)
++{
++ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
++ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
++ GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
++
++ gobject_class->finalize = gedit_view_centering_finalize;
++
++ widget_class->size_allocate = gedit_view_centering_size_allocate;
++
++ container_class->add = gedit_view_centering_add;
++ container_class->remove = gedit_view_centering_remove;
++}
++
++static void
++gedit_view_centering_init (GeditViewCentering *container)
++{
++ GeditViewCenteringPrivate *priv;
++
++ container->priv = gedit_view_centering_get_instance_private (container);
++ priv = container->priv;
++ priv->view_text_width = 0;
++
++ priv->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
++ priv->spacer = gtk_drawing_area_new ();
++ priv->scrolled_window = gtk_scrolled_window_new (NULL, NULL);
++
++ gtk_container_add (GTK_CONTAINER (container), priv->box);
++ gtk_box_pack_start (GTK_BOX (priv->box), priv->spacer, FALSE, FALSE, 0);
++ gtk_box_pack_start (GTK_BOX (priv->box), priv->scrolled_window, TRUE, TRUE, 0);
++
++ gtk_widget_set_no_show_all (GTK_WIDGET (priv->spacer), TRUE);
++ gtk_widget_show_all (GTK_WIDGET (priv->box));
++
++ g_signal_connect_swapped (priv->spacer, "draw",
++ G_CALLBACK (on_spacer_draw),
++ container);
++
++ gtk_widget_add_events(GTK_WIDGET(priv->spacer), GDK_SCROLL_MASK);
++ g_signal_connect (priv->spacer, "scroll-event",
++ G_CALLBACK (on_spacer_scroll_event),
++ container);
++}
++
++/**
++ * gedit_view_centering_set_centered:
++ * @container: a #GeditViewCentering.
++ * @centered: whether to center the sourceview child or not.
++ *
++ * If @centered is %TRUE, the sourceview child is centered
++ * horizontally on the #GeditViewCentering container.
++ **/
++void
++gedit_view_centering_set_centered (GeditViewCentering *container,
++ gboolean centered)
++{
++ g_return_if_fail (GEDIT_IS_VIEW_CENTERING (container));
++
++ container->priv->centered = centered != FALSE;
++
++ on_view_right_margin_visibility_changed (GEDIT_VIEW (container->priv->sourceview), NULL, container);
++}
++
++/**
++ * gedit_view_centering_get_centered:
++ * @container: a #GeditViewCentering.
++ *
++ * Return whether the #GtkSourceView child is centered or not.
++ *
++ * Return value: %TRUE if the #GtkSourceView child is centered
++ * horizontally on the #GeditViewCentering container.
++ **/
++gboolean
++gedit_view_centering_get_centered (GeditViewCentering *container)
++{
++ g_return_val_if_fail (GEDIT_IS_VIEW_CENTERING (container), FALSE);
++
++ return container->priv->centered;
++}
++
++GeditViewCentering *
++gedit_view_centering_new (void)
++{
++ return g_object_new (GEDIT_TYPE_VIEW_CENTERING,
++ NULL);
++}
++
++/* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-view-centering.h b/gedit/gedit-view-centering.h
+new file mode 100644
+index 000000000..1d7218969
+--- /dev/null
++++ b/gedit/gedit-view-centering.h
+@@ -0,0 +1,67 @@
++/*
++ * gedit-view-centering.h
++ * This file is part of gedit
++ *
++ * Copyright (C) 2014 - Sébastien Lafargue
++ * Copyright (C) 2015 - Sébastien Wilmet
++ *
++ * Gedit is free software; you can redistribute this file and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * Gedit 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#ifndef GEDIT_VIEW_CENTERING_H
++#define GEDIT_VIEW_CENTERING_H
++
++#include
++
++G_BEGIN_DECLS
++
++#define GEDIT_TYPE_VIEW_CENTERING (gedit_view_centering_get_type())
++#define GEDIT_VIEW_CENTERING(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_VIEW_CENTERING, GeditViewCentering))
++#define GEDIT_VIEW_CENTERING_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_VIEW_CENTERING, GeditViewCentering const))
++#define GEDIT_VIEW_CENTERING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_VIEW_CENTERING, GeditViewCenteringClass))
++#define GEDIT_IS_VIEW_CENTERING(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_VIEW_CENTERING))
++#define GEDIT_IS_VIEW_CENTERING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_VIEW_CENTERING))
++#define GEDIT_VIEW_CENTERING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_VIEW_CENTERING, GeditViewCenteringClass))
++
++typedef struct _GeditViewCentering GeditViewCentering;
++typedef struct _GeditViewCenteringClass GeditViewCenteringClass;
++typedef struct _GeditViewCenteringPrivate GeditViewCenteringPrivate;
++
++struct _GeditViewCentering
++{
++ GtkBin parent;
++
++ GeditViewCenteringPrivate *priv;
++};
++
++struct _GeditViewCenteringClass
++{
++ GtkBinClass parent_class;
++};
++
++GType gedit_view_centering_get_type (void) G_GNUC_CONST;
++
++GeditViewCentering * gedit_view_centering_new (void);
++
++void gedit_view_centering_set_centered (GeditViewCentering *container,
++ gboolean centered);
++
++gboolean gedit_view_centering_get_centered (GeditViewCentering *container);
++
++G_END_DECLS
++
++#endif /* GEDIT_VIEW_CENTERING_H */
++
++/* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-view-frame.c b/gedit/gedit-view-frame.c
+index f41734c47..67c067a41 100644
+--- a/gedit/gedit-view-frame.c
++++ b/gedit/gedit-view-frame.c
+@@ -1,86 +1,91 @@
+ /*
+ * gedit-view-frame.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+- * Copyright (C) 2013, 2019 - Sébastien Wilmet
++ * Copyright (C) 2013 - Sébastien Wilmet
+ *
+ * gedit 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.
+ *
+ * gedit 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
+ * along with gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+ #include "gedit-view-frame.h"
+
+ #include
+ #include
+ #include
+ #include
+
++#include "gedit-view-centering.h"
+ #include "gedit-debug.h"
+ #include "gedit-utils.h"
+ #include "gedit-settings.h"
+ #include "libgd/gd.h"
+
+ #define FLUSH_TIMEOUT_DURATION 30 /* in seconds */
+
+ #define SEARCH_POPUP_MARGIN 12
+
+ typedef enum
+ {
+ GOTO_LINE,
+ SEARCH
+ } SearchMode;
+
+ typedef enum
+ {
+ SEARCH_STATE_NORMAL,
+ SEARCH_STATE_NOT_FOUND
+ } SearchState;
+
+ struct _GeditViewFrame
+ {
+ GtkOverlay parent_instance;
+
++ GSettings *editor_settings;
++
+ GeditView *view;
++ GeditViewCentering *view_centering;
++ GtkFrame *map_frame;
+
+ SearchMode search_mode;
+
+ /* Where the search has started. When the user presses escape in the
+ * search entry (to cancel the search), we return to the start_mark.
+ */
+ GtkTextMark *start_mark;
+
+ GtkRevealer *revealer;
+ GdTaggedEntry *search_entry;
+ GdTaggedEntryTag *entry_tag;
+ GtkWidget *go_up_button;
+ GtkWidget *go_down_button;
+
+ guint flush_timeout_id;
+ guint idle_update_entry_tag_id;
+ guint remove_entry_tag_timeout_id;
+ gulong view_scroll_event_id;
+ gulong search_entry_focus_out_id;
+ gulong search_entry_changed_id;
+
+ GtkSourceSearchSettings *search_settings;
+
+ /* Used to restore the search state if an incremental search is
+ * cancelled.
+ */
+ GtkSourceSearchSettings *old_search_settings;
+
+ /* The original search texts. In search_settings and
+ * old_search_settings, the search text is unescaped. Since the escape
+@@ -132,115 +137,116 @@ gedit_view_frame_dispose (GObject *object)
+ if (frame->start_mark != NULL && buffer != NULL)
+ {
+ gtk_text_buffer_delete_mark (buffer, frame->start_mark);
+ frame->start_mark = NULL;
+ }
+
+ if (frame->flush_timeout_id != 0)
+ {
+ g_source_remove (frame->flush_timeout_id);
+ frame->flush_timeout_id = 0;
+ }
+
+ if (frame->idle_update_entry_tag_id != 0)
+ {
+ g_source_remove (frame->idle_update_entry_tag_id);
+ frame->idle_update_entry_tag_id = 0;
+ }
+
+ if (frame->remove_entry_tag_timeout_id != 0)
+ {
+ g_source_remove (frame->remove_entry_tag_timeout_id);
+ frame->remove_entry_tag_timeout_id = 0;
+ }
+
+ if (buffer != NULL)
+ {
+ GtkSourceFile *file = gedit_document_get_file (GEDIT_DOCUMENT (buffer));
+ gtk_source_file_set_mount_operation_factory (file, NULL, NULL, NULL);
+ }
+
++ g_clear_object (&frame->editor_settings);
+ g_clear_object (&frame->entry_tag);
+ g_clear_object (&frame->search_settings);
+ g_clear_object (&frame->old_search_settings);
+
+ G_OBJECT_CLASS (gedit_view_frame_parent_class)->dispose (object);
+ }
+
+ static void
+ gedit_view_frame_finalize (GObject *object)
+ {
+ GeditViewFrame *frame = GEDIT_VIEW_FRAME (object);
+
+ g_free (frame->search_text);
+ g_free (frame->old_search_text);
+
+ G_OBJECT_CLASS (gedit_view_frame_parent_class)->finalize (object);
+ }
+
+ static void
+ hide_search_widget (GeditViewFrame *frame,
+ gboolean cancel)
+ {
+ GtkTextBuffer *buffer;
+
+ if (!gtk_revealer_get_reveal_child (frame->revealer))
+ {
+ return;
+ }
+
+ if (frame->view_scroll_event_id != 0)
+ {
+ g_signal_handler_disconnect (frame->view,
+ frame->view_scroll_event_id);
+ frame->view_scroll_event_id = 0;
+ }
+
+ if (frame->flush_timeout_id != 0)
+ {
+ g_source_remove (frame->flush_timeout_id);
+ frame->flush_timeout_id = 0;
+ }
+
+ gtk_revealer_set_reveal_child (frame->revealer, FALSE);
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (frame->view));
+
+ if (cancel && frame->start_mark != NULL)
+ {
+ GtkTextIter iter;
+
+ gtk_text_buffer_get_iter_at_mark (buffer, &iter,
+ frame->start_mark);
+ gtk_text_buffer_place_cursor (buffer, &iter);
+
+- tepl_view_scroll_to_cursor (TEPL_VIEW (frame->view));
++ gedit_view_scroll_to_cursor (frame->view);
+ }
+
+ if (frame->start_mark != NULL)
+ {
+ gtk_text_buffer_delete_mark (buffer, frame->start_mark);
+ frame->start_mark = NULL;
+ }
+ }
+
+ static gboolean
+ search_entry_flush_timeout (GeditViewFrame *frame)
+ {
+ frame->flush_timeout_id = 0;
+ hide_search_widget (frame, FALSE);
+
+ return G_SOURCE_REMOVE;
+ }
+
+ static void
+ renew_flush_timeout (GeditViewFrame *frame)
+ {
+ if (frame->flush_timeout_id != 0)
+ {
+ g_source_remove (frame->flush_timeout_id);
+ }
+
+ frame->flush_timeout_id =
+ g_timeout_add_seconds (FLUSH_TIMEOUT_DURATION,
+ (GSourceFunc)search_entry_flush_timeout,
+ frame);
+@@ -270,61 +276,61 @@ get_search_context (GeditViewFrame *frame)
+
+ return NULL;
+ }
+
+ static void
+ set_search_state (GeditViewFrame *frame,
+ SearchState state)
+ {
+ GtkStyleContext *context;
+
+ context = gtk_widget_get_style_context (GTK_WIDGET (frame->search_entry));
+
+ if (state == SEARCH_STATE_NOT_FOUND)
+ {
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_ERROR);
+ }
+ else
+ {
+ gtk_style_context_remove_class (context, GTK_STYLE_CLASS_ERROR);
+ }
+ }
+
+ static void
+ finish_search (GeditViewFrame *frame,
+ gboolean found)
+ {
+ const gchar *entry_text = gtk_entry_get_text (GTK_ENTRY (frame->search_entry));
+
+ if (found || (entry_text[0] == '\0'))
+ {
+- tepl_view_scroll_to_cursor (TEPL_VIEW (frame->view));
++ gedit_view_scroll_to_cursor (frame->view);
+
+ set_search_state (frame, SEARCH_STATE_NORMAL);
+ }
+ else
+ {
+ set_search_state (frame, SEARCH_STATE_NOT_FOUND);
+ }
+ }
+
+ static void
+ start_search_finished (GtkSourceSearchContext *search_context,
+ GAsyncResult *result,
+ GeditViewFrame *frame)
+ {
+ GtkTextIter match_start;
+ GtkTextIter match_end;
+ gboolean found;
+ GtkSourceBuffer *buffer;
+
+ found = gtk_source_search_context_forward_finish (search_context,
+ result,
+ &match_start,
+ &match_end,
+ NULL,
+ NULL);
+
+ buffer = gtk_source_search_context_get_buffer (search_context);
+
+ if (found)
+ {
+@@ -1034,117 +1040,121 @@ customize_for_search_mode (GeditViewFrame *frame)
+ gtk_widget_set_tooltip_text (GTK_WIDGET (frame->search_entry),
+ _("Line you want to move the cursor to"));
+
+ gtk_widget_hide (frame->go_up_button);
+ gtk_widget_hide (frame->go_down_button);
+ }
+
+ gtk_entry_set_icon_from_gicon (GTK_ENTRY (frame->search_entry),
+ GTK_ENTRY_ICON_PRIMARY,
+ icon);
+
+ gtk_widget_set_size_request (GTK_WIDGET (frame->search_entry),
+ width_request,
+ -1);
+
+ g_object_unref (icon);
+ }
+
+ static void
+ update_goto_line (GeditViewFrame *frame)
+ {
+ const gchar *entry_text;
+ gboolean moved;
+ gboolean moved_offset;
+ gint line;
+ gint offset_line = 0;
+ gint line_offset = 0;
+ gchar **split_text = NULL;
+ const gchar *text;
+ GtkTextIter iter;
++ GeditDocument *doc;
+
+ entry_text = gtk_entry_get_text (GTK_ENTRY (frame->search_entry));
+
+ if (entry_text[0] == '\0')
+ {
+ return;
+ }
+
+ get_iter_at_start_mark (frame, &iter);
+
+ split_text = g_strsplit (entry_text, ":", -1);
+
+ if (g_strv_length (split_text) > 1)
+ {
+ text = split_text[0];
+ }
+ else
+ {
+ text = entry_text;
+ }
+
+ if (text[0] == '-')
+ {
+ gint cur_line = gtk_text_iter_get_line (&iter);
+
+ if (text[1] != '\0')
+ {
+ offset_line = MAX (atoi (text + 1), 0);
+ }
+
+ line = MAX (cur_line - offset_line, 0);
+ }
+ else if (entry_text[0] == '+')
+ {
+ gint cur_line = gtk_text_iter_get_line (&iter);
+
+ if (text[1] != '\0')
+ {
+ offset_line = MAX (atoi (text + 1), 0);
+ }
+
+ line = cur_line + offset_line;
+ }
+ else
+ {
+ line = MAX (atoi (text) - 1, 0);
+ }
+
+ if (split_text[1] != NULL)
+ {
+ line_offset = atoi (split_text[1]);
+ }
+
+ g_strfreev (split_text);
+
+- moved = tepl_view_goto_line (TEPL_VIEW (frame->view), line);
+- moved_offset = tepl_view_goto_line_offset (TEPL_VIEW (frame->view), line, line_offset);
++ doc = get_document (frame);
++ moved = gedit_document_goto_line (doc, line);
++ moved_offset = gedit_document_goto_line_offset (doc, line, line_offset);
++
++ gedit_view_scroll_to_cursor (frame->view);
+
+ if (!moved || !moved_offset)
+ {
+ set_search_state (frame, SEARCH_STATE_NOT_FOUND);
+ }
+ else
+ {
+ set_search_state (frame, SEARCH_STATE_NORMAL);
+ }
+ }
+
+ static void
+ search_entry_changed_cb (GtkEntry *entry,
+ GeditViewFrame *frame)
+ {
+ renew_flush_timeout (frame);
+
+ if (frame->search_mode == SEARCH)
+ {
+ update_search_text (frame);
+ start_search (frame);
+ }
+ else
+ {
+ update_goto_line (frame);
+ }
+ }
+
+ static gboolean
+ search_entry_focus_out_event (GtkWidget *widget,
+@@ -1401,86 +1411,95 @@ start_interactive_search_real (GeditViewFrame *frame,
+
+ gtk_widget_grab_focus (GTK_WIDGET (frame->search_entry));
+
+ customize_for_search_mode (frame);
+ init_search_entry (frame);
+
+ /* Manage the scroll also for the view */
+ frame->view_scroll_event_id =
+ g_signal_connect (frame->view, "scroll-event",
+ G_CALLBACK (search_widget_scroll_event),
+ frame);
+
+ renew_flush_timeout (frame);
+
+ install_update_entry_tag_idle (frame);
+ }
+
+ static void
+ gedit_view_frame_class_init (GeditViewFrameClass *klass)
+ {
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->dispose = gedit_view_frame_dispose;
+ object_class->finalize = gedit_view_frame_finalize;
+
+ /* Bind class to template */
+ gtk_widget_class_set_template_from_resource (widget_class,
+ "/org/gnome/gedit/ui/gedit-view-frame.ui");
+ gtk_widget_class_bind_template_child (widget_class, GeditViewFrame, view);
++ gtk_widget_class_bind_template_child (widget_class, GeditViewFrame, view_centering);
++ gtk_widget_class_bind_template_child (widget_class, GeditViewFrame, map_frame);
+ gtk_widget_class_bind_template_child (widget_class, GeditViewFrame, revealer);
+ gtk_widget_class_bind_template_child (widget_class, GeditViewFrame, search_entry);
+ gtk_widget_class_bind_template_child (widget_class, GeditViewFrame, go_up_button);
+ gtk_widget_class_bind_template_child (widget_class, GeditViewFrame, go_down_button);
+ }
+
+ static GMountOperation *
+ view_frame_mount_operation_factory (GtkSourceFile *file,
+ gpointer user_data)
+ {
+ GtkWidget *view_frame = user_data;
+ GtkWidget *window = gtk_widget_get_toplevel (view_frame);
+
+ return gtk_mount_operation_new (GTK_WINDOW (window));
+ }
+
+ static void
+ gedit_view_frame_init (GeditViewFrame *frame)
+ {
+ GeditDocument *doc;
+ GtkSourceFile *file;
+
+ gedit_debug (DEBUG_WINDOW);
+
+ gtk_widget_init_template (GTK_WIDGET (frame));
+
++ frame->editor_settings = g_settings_new ("org.gnome.gedit.preferences.editor");
++ g_settings_bind (frame->editor_settings,
++ GEDIT_SETTINGS_DISPLAY_OVERVIEW_MAP,
++ frame->map_frame,
++ "visible",
++ G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY);
++
+ doc = get_document (frame);
+ file = gedit_document_get_file (doc);
+
+ gtk_source_file_set_mount_operation_factory (file,
+ view_frame_mount_operation_factory,
+ frame,
+ NULL);
+
+ frame->entry_tag = gd_tagged_entry_tag_new ("");
+
+ gd_tagged_entry_tag_set_style (frame->entry_tag,
+ "gedit-search-entry-occurrences-tag");
+
+ gd_tagged_entry_tag_set_has_close_button (frame->entry_tag, FALSE);
+
+ gtk_widget_set_margin_end (GTK_WIDGET (frame->revealer),
+ SEARCH_POPUP_MARGIN);
+
+ g_signal_connect (doc,
+ "mark-set",
+ G_CALLBACK (mark_set_cb),
+ frame);
+
+ g_signal_connect (frame->revealer,
+ "key-press-event",
+ G_CALLBACK (search_widget_key_press_event),
+ frame);
+
+ g_signal_connect (frame->revealer,
+ "scroll-event",
+@@ -1524,60 +1543,68 @@ gedit_view_frame_init (GeditViewFrame *frame)
+
+ frame->search_entry_changed_id =
+ g_signal_connect (frame->search_entry,
+ "changed",
+ G_CALLBACK (search_entry_changed_cb),
+ frame);
+
+ frame->search_entry_focus_out_id =
+ g_signal_connect (frame->search_entry,
+ "focus-out-event",
+ G_CALLBACK (search_entry_focus_out_event),
+ frame);
+
+ g_signal_connect_swapped (frame->go_up_button,
+ "clicked",
+ G_CALLBACK (backward_search),
+ frame);
+
+ g_signal_connect_swapped (frame->go_down_button,
+ "clicked",
+ G_CALLBACK (forward_search),
+ frame);
+ }
+
+ GeditViewFrame *
+ gedit_view_frame_new (void)
+ {
+ return g_object_new (GEDIT_TYPE_VIEW_FRAME, NULL);
+ }
+
++GeditViewCentering *
++gedit_view_frame_get_view_centering (GeditViewFrame *frame)
++{
++ g_return_val_if_fail (GEDIT_IS_VIEW_FRAME (frame), NULL);
++
++ return frame->view_centering;
++}
++
+ GeditView *
+ gedit_view_frame_get_view (GeditViewFrame *frame)
+ {
+ g_return_val_if_fail (GEDIT_IS_VIEW_FRAME (frame), NULL);
+
+ return frame->view;
+ }
+
+ void
+ gedit_view_frame_popup_search (GeditViewFrame *frame)
+ {
+ g_return_if_fail (GEDIT_IS_VIEW_FRAME (frame));
+
+ start_interactive_search_real (frame, SEARCH);
+ }
+
+ void
+ gedit_view_frame_popup_goto_line (GeditViewFrame *frame)
+ {
+ g_return_if_fail (GEDIT_IS_VIEW_FRAME (frame));
+
+ start_interactive_search_real (frame, GOTO_LINE);
+ }
+
+ void
+ gedit_view_frame_clear_search (GeditViewFrame *frame)
+ {
+ g_return_if_fail (GEDIT_IS_VIEW_FRAME (frame));
+
+ g_signal_handler_block (frame->search_entry,
+diff --git a/gedit/gedit-view-frame.h b/gedit/gedit-view-frame.h
+index 78ac469d1..d2e550840 100644
+--- a/gedit/gedit-view-frame.h
++++ b/gedit/gedit-view-frame.h
+@@ -1,45 +1,49 @@
+ /*
+ * gedit-view-frame.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * gedit 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.
+ *
+ * gedit 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
+ * along with gedit. If not, see .
+ */
+
+ #ifndef GEDIT_VIEW_FRAME_H
+ #define GEDIT_VIEW_FRAME_H
+
+ #include
+ #include "gedit-document.h"
+ #include "gedit-view.h"
++#include "gedit-view-centering.h"
+
+ G_BEGIN_DECLS
+
+ #define GEDIT_TYPE_VIEW_FRAME (gedit_view_frame_get_type ())
+ G_DECLARE_FINAL_TYPE (GeditViewFrame, gedit_view_frame, GEDIT, VIEW_FRAME, GtkOverlay)
+
+ GeditViewFrame *gedit_view_frame_new (void);
+
++GeditViewCentering
++ *gedit_view_frame_get_view_centering (GeditViewFrame *frame);
++
+ GeditView *gedit_view_frame_get_view (GeditViewFrame *frame);
+
+ void gedit_view_frame_popup_search (GeditViewFrame *frame);
+
+ void gedit_view_frame_popup_goto_line (GeditViewFrame *frame);
+
+ void gedit_view_frame_clear_search (GeditViewFrame *frame);
+
+ G_END_DECLS
+
+ #endif /* GEDIT_VIEW_FRAME_H */
+diff --git a/gedit/gedit-view.c b/gedit/gedit-view.c
+index 0c730c989..035e599ab 100644
+--- a/gedit/gedit-view.c
++++ b/gedit/gedit-view.c
+@@ -1,232 +1,259 @@
+ /*
+ * This file is part of gedit
+ *
+ * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
+ * Copyright (C) 2000, 2002 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2003-2005 Paolo Maggi
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #include "gedit-view.h"
+ #include
+ #include "gedit-view-activatable.h"
+ #include "gedit-plugins-engine.h"
+ #include "gedit-debug.h"
++#include "gedit-pango.h"
+ #include "gedit-utils.h"
+ #include "gedit-settings.h"
+
++#define GEDIT_VIEW_SCROLL_MARGIN 0.02
++
+ struct _GeditViewPrivate
+ {
++ GeditDocument *current_document;
+ PeasExtensionSet *extensions;
+
+ gchar *direct_save_uri;
+
+- TeplSignalGroup *file_signal_group;
++ GtkCssProvider *css_provider;
++ PangoFontDescription *font_desc;
+ };
+
+ enum
+ {
+ TARGET_URI_LIST = 100,
+ TARGET_XDNDDIRECTSAVE
+ };
+
+ enum
+ {
+ SIGNAL_DROP_URIS,
+ N_SIGNALS
+ };
+
+ static guint signals[N_SIGNALS];
+
+-G_DEFINE_TYPE_WITH_PRIVATE (GeditView, gedit_view, TEPL_TYPE_VIEW)
++G_DEFINE_TYPE_WITH_PRIVATE (GeditView, gedit_view, GTK_SOURCE_TYPE_VIEW)
+
+ static void
+ update_editable (GeditView *view)
+ {
+ GeditDocument *doc;
+ GtkSourceFile *file;
+
+ doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
+ file = gedit_document_get_file (doc);
+
+ gtk_text_view_set_editable (GTK_TEXT_VIEW (view),
+ !gtk_source_file_is_readonly (file));
+ }
+
+ static void
+ file_read_only_notify_cb (GtkSourceFile *file,
+ GParamSpec *pspec,
+ GeditView *view)
+ {
+ update_editable (view);
+ }
+
++static void
++current_document_removed (GeditView *view)
++{
++ if (view->priv->current_document != NULL)
++ {
++ GtkSourceFile *file;
++
++ file = gedit_document_get_file (view->priv->current_document);
++
++ g_signal_handlers_disconnect_by_func (file,
++ file_read_only_notify_cb,
++ view);
++
++ g_object_unref (view->priv->current_document);
++ view->priv->current_document = NULL;
++ }
++}
++
+ static void
+ buffer_changed (GeditView *view)
+ {
+- GeditDocument *doc;
+ GtkSourceFile *file;
++ GtkTextBuffer *buffer;
+
+- doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
+- file = gedit_document_get_file (doc);
++ current_document_removed (view);
++ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
++
++ if (!GEDIT_IS_DOCUMENT (buffer))
++ {
++ return;
++ }
+
+- tepl_signal_group_clear (&view->priv->file_signal_group);
+- view->priv->file_signal_group = tepl_signal_group_new (G_OBJECT (file));
++ view->priv->current_document = g_object_ref (GEDIT_DOCUMENT (buffer));
+
+- tepl_signal_group_add (view->priv->file_signal_group,
+- g_signal_connect (file,
+- "notify::read-only",
+- G_CALLBACK (file_read_only_notify_cb),
+- view));
++ file = gedit_document_get_file (view->priv->current_document);
++ g_signal_connect_object (file,
++ "notify::read-only",
++ G_CALLBACK (file_read_only_notify_cb),
++ view,
++ 0);
+
+ update_editable (view);
+ }
+
+ static void
+ buffer_notify_cb (GeditView *view,
+ GParamSpec *pspec,
+ gpointer user_data)
+ {
+ buffer_changed (view);
+ }
+
+ static void
+ gedit_view_init (GeditView *view)
+ {
+ GtkTargetList *target_list;
+- GtkStyleContext *style_context;
++ GtkStyleContext *context;
+
+ gedit_debug (DEBUG_VIEW);
+
+ view->priv = gedit_view_get_instance_private (view);
+
+ /* Drag and drop support */
+ view->priv->direct_save_uri = NULL;
+ target_list = gtk_drag_dest_get_target_list (GTK_WIDGET (view));
+
+ if (target_list != NULL)
+ {
+ gtk_target_list_add (target_list,
+ gdk_atom_intern ("XdndDirectSave0", FALSE),
+ 0,
+ TARGET_XDNDDIRECTSAVE);
+ gtk_target_list_add_uri_targets (target_list, TARGET_URI_LIST);
+ }
+
+ /* GeditViewActivatable */
+ view->priv->extensions =
+ peas_extension_set_new (PEAS_ENGINE (gedit_plugins_engine_get_default ()),
+ GEDIT_TYPE_VIEW_ACTIVATABLE,
+ "view", view,
+ NULL);
+
+ /* Act on buffer changes */
+ buffer_changed (view);
+ g_signal_connect (view,
+ "notify::buffer",
+ G_CALLBACK (buffer_notify_cb),
+ NULL);
+
+ /* CSS stuff */
+- style_context = gtk_widget_get_style_context (GTK_WIDGET (view));
+- gtk_style_context_add_class (style_context, "gedit-view");
++ context = gtk_widget_get_style_context (GTK_WIDGET (view));
++ gtk_style_context_add_class (context, "gedit-view");
++
++ view->priv->css_provider = gtk_css_provider_new ();
++ gtk_style_context_add_provider (context,
++ GTK_STYLE_PROVIDER (view->priv->css_provider),
++ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+ }
+
+ static void
+ gedit_view_dispose (GObject *object)
+ {
+ GeditView *view = GEDIT_VIEW (object);
+
+ g_clear_object (&view->priv->extensions);
+- tepl_signal_group_clear (&view->priv->file_signal_group);
++
++ current_document_removed (view);
+
+ /* Disconnect notify buffer because the destroy of the textview will set
+ * the buffer to NULL, and we call get_buffer in the notify which would
+ * reinstate a buffer which we don't want.
+ * There is no problem calling g_signal_handlers_disconnect_by_func()
+ * several times (if dispose() is called several times).
+ */
+ g_signal_handlers_disconnect_by_func (view, buffer_notify_cb, NULL);
+
+- G_OBJECT_CLASS (gedit_view_parent_class)->dispose (object);
+-}
+-
+-static void
+-update_font (GeditView *view)
+-{
+- GeditSettings *settings;
+- gchar *selected_font;
+-
+- settings = _gedit_settings_get_singleton ();
+- selected_font = _gedit_settings_get_selected_font (settings);
+- tepl_utils_override_font (GTK_WIDGET (view), selected_font);
+- g_free (selected_font);
+-}
++ g_clear_object (&view->priv->css_provider);
++ g_clear_pointer (&view->priv->font_desc, pango_font_description_free);
+
+-static void
+-fonts_changed_cb (GeditSettings *settings,
+- GeditView *view)
+-{
+- update_font (view);
++ G_OBJECT_CLASS (gedit_view_parent_class)->dispose (object);
+ }
+
+ static void
+ gedit_view_constructed (GObject *object)
+ {
+ GeditView *view = GEDIT_VIEW (object);
+ GeditSettings *settings;
+ GSettings *editor_settings;
++ gboolean use_default_font;
+
+ G_OBJECT_CLASS (gedit_view_parent_class)->constructed (object);
+
+ settings = _gedit_settings_get_singleton ();
+ editor_settings = _gedit_settings_peek_editor_settings (settings);
+
+- update_font (view);
+- g_signal_connect_object (settings,
+- "fonts-changed",
+- G_CALLBACK (fonts_changed_cb),
+- view,
+- 0);
++ use_default_font = g_settings_get_boolean (editor_settings, GEDIT_SETTINGS_USE_DEFAULT_FONT);
++
++ if (use_default_font)
++ {
++ gedit_view_set_font (view, TRUE, NULL);
++ }
++ else
++ {
++ gchar *editor_font;
++
++ editor_font = g_settings_get_string (editor_settings, GEDIT_SETTINGS_EDITOR_FONT);
++ gedit_view_set_font (view, FALSE, editor_font);
++ g_free (editor_font);
++ }
+
+ g_settings_bind (editor_settings, GEDIT_SETTINGS_DISPLAY_LINE_NUMBERS,
+ view, "show-line-numbers",
+ G_SETTINGS_BIND_GET);
+
+ g_settings_bind (editor_settings, GEDIT_SETTINGS_AUTO_INDENT,
+ view, "auto-indent",
+ G_SETTINGS_BIND_GET);
+
+ g_settings_bind (editor_settings, GEDIT_SETTINGS_TABS_SIZE,
+ view, "tab-width",
+ G_SETTINGS_BIND_GET);
+
+ g_settings_bind (editor_settings, GEDIT_SETTINGS_INSERT_SPACES,
+ view, "insert-spaces-instead-of-tabs",
+ G_SETTINGS_BIND_GET);
+
+ g_settings_bind (editor_settings, GEDIT_SETTINGS_DISPLAY_RIGHT_MARGIN,
+ view, "show-right-margin",
+ G_SETTINGS_BIND_GET);
+
+ g_settings_bind (editor_settings, GEDIT_SETTINGS_BACKGROUND_PATTERN,
+ view, "background-pattern",
+ G_SETTINGS_BIND_GET);
+
+ g_settings_bind (editor_settings, GEDIT_SETTINGS_RIGHT_MARGIN_POSITION,
+ view, "right-margin-position",
+ G_SETTINGS_BIND_GET);
+
+ g_settings_bind (editor_settings, GEDIT_SETTINGS_HIGHLIGHT_CURRENT_LINE,
+@@ -693,31 +720,244 @@ gedit_view_class_init (GeditViewClass *klass)
+ GDK_CONTROL_MASK,
+ "change-case", 1,
+ G_TYPE_ENUM, GTK_SOURCE_CHANGE_CASE_LOWER);
+
+ gtk_binding_entry_add_signal (binding_set,
+ GDK_KEY_asciitilde,
+ GDK_CONTROL_MASK,
+ "change-case", 1,
+ G_TYPE_ENUM, GTK_SOURCE_CHANGE_CASE_TOGGLE);
+ }
+
+ /**
+ * gedit_view_new:
+ * @doc: a #GeditDocument
+ *
+ * Creates a new #GeditView object displaying the @doc document.
+ * @doc cannot be %NULL.
+ *
+ * Returns: a new #GeditView.
+ */
+ GtkWidget *
+ gedit_view_new (GeditDocument *doc)
+ {
+ g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), NULL);
+
+ return g_object_new (GEDIT_TYPE_VIEW,
+ "buffer", doc,
+ NULL);
+ }
+
++void
++gedit_view_cut_clipboard (GeditView *view)
++{
++ GtkTextBuffer *buffer;
++ GtkClipboard *clipboard;
++
++ gedit_debug (DEBUG_VIEW);
++
++ g_return_if_fail (GEDIT_IS_VIEW (view));
++
++ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
++
++ clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view),
++ GDK_SELECTION_CLIPBOARD);
++
++ gtk_text_buffer_cut_clipboard (buffer,
++ clipboard,
++ gtk_text_view_get_editable (GTK_TEXT_VIEW (view)));
++
++ gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
++ gtk_text_buffer_get_insert (buffer),
++ GEDIT_VIEW_SCROLL_MARGIN,
++ FALSE,
++ 0.0,
++ 0.0);
++}
++
++void
++gedit_view_copy_clipboard (GeditView *view)
++{
++ GtkTextBuffer *buffer;
++ GtkClipboard *clipboard;
++
++ gedit_debug (DEBUG_VIEW);
++
++ g_return_if_fail (GEDIT_IS_VIEW (view));
++
++ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
++
++ clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view),
++ GDK_SELECTION_CLIPBOARD);
++
++ gtk_text_buffer_copy_clipboard (buffer, clipboard);
++
++ /* on copy do not scroll, we are already on screen */
++}
++
++void
++gedit_view_paste_clipboard (GeditView *view)
++{
++ GtkTextBuffer *buffer;
++ GtkClipboard *clipboard;
++
++ gedit_debug (DEBUG_VIEW);
++
++ g_return_if_fail (GEDIT_IS_VIEW (view));
++
++ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
++
++ clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view),
++ GDK_SELECTION_CLIPBOARD);
++
++ gtk_text_buffer_paste_clipboard (buffer,
++ clipboard,
++ NULL,
++ gtk_text_view_get_editable (GTK_TEXT_VIEW (view)));
++
++ gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
++ gtk_text_buffer_get_insert (buffer),
++ GEDIT_VIEW_SCROLL_MARGIN,
++ FALSE,
++ 0.0,
++ 0.0);
++}
++
++/**
++ * gedit_view_delete_selection:
++ * @view: a #GeditView
++ *
++ * Deletes the text currently selected in the #GtkTextBuffer associated
++ * to the view and scroll to the cursor position.
++ */
++void
++gedit_view_delete_selection (GeditView *view)
++{
++ GtkTextBuffer *buffer;
++
++ gedit_debug (DEBUG_VIEW);
++
++ g_return_if_fail (GEDIT_IS_VIEW (view));
++
++ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
++
++ gtk_text_buffer_delete_selection (buffer,
++ TRUE,
++ gtk_text_view_get_editable (GTK_TEXT_VIEW (view)));
++
++ gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
++ gtk_text_buffer_get_insert (buffer),
++ GEDIT_VIEW_SCROLL_MARGIN,
++ FALSE,
++ 0.0,
++ 0.0);
++}
++
++/**
++ * gedit_view_select_all:
++ * @view: a #GeditView
++ *
++ * Selects all the text.
++ */
++void
++gedit_view_select_all (GeditView *view)
++{
++ GtkTextBuffer *buffer;
++ GtkTextIter start;
++ GtkTextIter end;
++
++ gedit_debug (DEBUG_VIEW);
++
++ g_return_if_fail (GEDIT_IS_VIEW (view));
++
++ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
++
++ gtk_text_buffer_get_bounds (buffer, &start, &end);
++ gtk_text_buffer_select_range (buffer, &start, &end);
++}
++
++/**
++ * gedit_view_scroll_to_cursor:
++ * @view: a #GeditView
++ *
++ * Scrolls the @view to the cursor position.
++ */
++void
++gedit_view_scroll_to_cursor (GeditView *view)
++{
++ GtkTextBuffer *buffer;
++
++ gedit_debug (DEBUG_VIEW);
++
++ g_return_if_fail (GEDIT_IS_VIEW (view));
++
++ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
++
++ gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
++ gtk_text_buffer_get_insert (buffer),
++ 0.25,
++ FALSE,
++ 0.0,
++ 0.0);
++}
++
++static void
++update_css_provider (GeditView *view)
++{
++ gchar *str;
++ gchar *css;
++
++ g_assert (GEDIT_IS_VIEW (view));
++ g_assert (view->priv->font_desc != NULL);
++
++ str = gedit_pango_font_description_to_css (view->priv->font_desc);
++ css = g_strdup_printf ("textview { %s }", str ? str : "");
++ gtk_css_provider_load_from_data (view->priv->css_provider, css, -1, NULL);
++
++ g_free (css);
++ g_free (str);
++}
++
++/**
++ * gedit_view_set_font:
++ * @view: a #GeditView
++ * @default_font: whether to reset to the default font
++ * @font_name: the name of the font to use
++ *
++ * If @default_font is #TRUE, resets the font of the @view to the default font.
++ * Otherwise sets it to @font_name.
++ */
++void
++gedit_view_set_font (GeditView *view,
++ gboolean default_font,
++ const gchar *font_name)
++{
++ gedit_debug (DEBUG_VIEW);
++
++ g_return_if_fail (GEDIT_IS_VIEW (view));
++
++ g_clear_pointer (&view->priv->font_desc, pango_font_description_free);
++
++ if (default_font)
++ {
++ GeditSettings *settings;
++ gchar *font;
++
++ settings = _gedit_settings_get_singleton ();
++ font = gedit_settings_get_system_font (settings);
++
++ view->priv->font_desc = pango_font_description_from_string (font);
++ g_free (font);
++ }
++ else
++ {
++ g_return_if_fail (font_name != NULL);
++
++ view->priv->font_desc = pango_font_description_from_string (font_name);
++ }
++
++ g_return_if_fail (view->priv->font_desc != NULL);
++
++ update_css_provider (view);
++}
++
+ /* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-view.h b/gedit/gedit-view.h
+index c05d68553..7f2ae3ae2 100644
+--- a/gedit/gedit-view.h
++++ b/gedit/gedit-view.h
+@@ -1,67 +1,85 @@
+ /*
+ * This file is part of gedit
+ *
+ * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002-2005 Paolo Maggi
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #ifndef GEDIT_VIEW_H
+ #define GEDIT_VIEW_H
+
++#include
++
+ #include
+-#include
++#include
+
+ G_BEGIN_DECLS
+
+ #define GEDIT_TYPE_VIEW (gedit_view_get_type ())
+ #define GEDIT_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GEDIT_TYPE_VIEW, GeditView))
+ #define GEDIT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GEDIT_TYPE_VIEW, GeditViewClass))
+ #define GEDIT_IS_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GEDIT_TYPE_VIEW))
+ #define GEDIT_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_VIEW))
+ #define GEDIT_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GEDIT_TYPE_VIEW, GeditViewClass))
+
+ typedef struct _GeditView GeditView;
+ typedef struct _GeditViewClass GeditViewClass;
+ typedef struct _GeditViewPrivate GeditViewPrivate;
+
+ struct _GeditView
+ {
+- TeplView view;
++ GtkSourceView view;
+
+ /*< private >*/
+ GeditViewPrivate *priv;
+ };
+
+ struct _GeditViewClass
+ {
+- TeplViewClass parent_class;
++ GtkSourceViewClass parent_class;
+
+ void (*drop_uris) (GeditView *view,
+ gchar **uri_list);
+
+ gpointer padding;
+ };
+
+ GType gedit_view_get_type (void);
+
+ GtkWidget * gedit_view_new (GeditDocument *doc);
+
++void gedit_view_cut_clipboard (GeditView *view);
++
++void gedit_view_copy_clipboard (GeditView *view);
++
++void gedit_view_paste_clipboard (GeditView *view);
++
++void gedit_view_delete_selection (GeditView *view);
++
++void gedit_view_select_all (GeditView *view);
++
++void gedit_view_scroll_to_cursor (GeditView *view);
++
++void gedit_view_set_font (GeditView *view,
++ gboolean default_font,
++ const gchar *font_name);
++
+ G_END_DECLS
+
+ #endif /* GEDIT_VIEW_H */
+
+ /* ex:set ts=8 noet: */
+diff --git a/gedit/gedit-window-private.h b/gedit/gedit-window-private.h
+index 60f8ba706..380f6bdc5 100644
+--- a/gedit/gedit-window-private.h
++++ b/gedit/gedit-window-private.h
+@@ -1,112 +1,119 @@
+ /*
+ * gedit-window-private.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2005 - Paolo Maggi
+ *
+ * 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
+ * MERCHANWINDOWILITY 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
+ * along with this program; if not, see .
+ */
+
+ #ifndef GEDIT_WINDOW_PRIVATE_H
+ #define GEDIT_WINDOW_PRIVATE_H
+
+ #include
+
+ #include "gedit/gedit-window.h"
+ #include "gedit-message-bus.h"
+ #include "gedit-settings.h"
+ #include "gedit-multi-notebook.h"
++#include "gedit-open-document-selector.h"
+
+ G_BEGIN_DECLS
+
+ /* WindowPrivate is in a separate .h so that we can access it from gedit-commands */
+
+ struct _GeditWindowPrivate
+ {
+ GSettings *editor_settings;
+ GSettings *ui_settings;
+ GSettings *window_settings;
+
+ GeditMultiNotebook *multi_notebook;
+
+ GtkWidget *side_panel;
+ GtkWidget *side_stack_switcher;
+ GtkWidget *side_panel_inline_stack_switcher;
+ GtkWidget *bottom_panel_box;
+ GtkWidget *bottom_panel;
+
+ GtkWidget *hpaned;
+ GtkWidget *vpaned;
+
+ GeditMessageBus *message_bus;
+ PeasExtensionSet *extensions;
+
+ /* Widgets for fullscreen mode */
++ GtkWidget *fullscreen_controls;
+ GtkWidget *fullscreen_eventbox;
+- GtkRevealer *fullscreen_revealer;
+ GtkWidget *fullscreen_headerbar;
+- GtkWidget *fullscreen_new_button;
+ GtkMenuButton *fullscreen_gear_button;
+- GtkMenuButton *fullscreen_open_recent_button;
++
++ GtkWidget *fullscreen_new_button;
++ GtkWidget *fullscreen_open_button;
++ GtkWidget *fullscreen_open_document_popover;
++ GeditOpenDocumentSelector *fullscreen_open_document_selector;
+
+ /* statusbar and context ids for statusbar messages */
+ GtkWidget *statusbar;
+ GtkWidget *line_col_button;
+ GtkWidget *tab_width_button;
+ GtkWidget *language_button;
+ GtkWidget *language_button_label;
+ GtkWidget *language_popover;
+ guint generic_message_cid;
+ guint tip_message_cid;
+ guint bracket_match_message_cid;
+ guint tab_width_id;
+ guint language_changed_id;
+ guint wrap_mode_changed_id;
+
+ /* Headerbars */
+ GtkWidget *titlebar_paned;
+ GtkWidget *side_headerbar;
+ GtkWidget *headerbar;
+
+- GtkWidget *new_button;
++ GtkWidget *open_document_popover;
++ GtkWidget *new_button;
++ GtkWidget *open_button;
++ GeditOpenDocumentSelector *open_document_selector;
+
+ GtkMenuButton *gear_button;
+
+ gint num_tabs_with_error;
+
+ gint width;
+ gint height;
+ GdkWindowState window_state;
+
+ gint side_panel_size;
+ gint bottom_panel_size;
+
+ GeditWindowState state;
+
+ guint inhibition_cookie;
+
+ gint bottom_panel_item_removed_handler_id;
+
+ GtkWindowGroup *window_group;
+
+ gchar *file_chooser_folder_uri;
+
+ gchar *direct_save_uri;
+
+ GSList *closed_docs_stack;
+
+ guint removing_tabs : 1;
+ guint dispose_has_run : 1;
+
+ guint in_fullscreen_eventbox : 1;
+diff --git a/gedit/gedit-window.c b/gedit/gedit-window.c
+index 2f9a2076f..b08a1dbcc 100644
+--- a/gedit/gedit-window.c
++++ b/gedit/gedit-window.c
+@@ -1,86 +1,92 @@
+ /*
+ * gedit-window.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2005 - Paolo Maggi
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #include "config.h"
+
+ #include "gedit-window.h"
+
+ #include
+ #include
+ #include
+
+ #include
+ #include
+-#include
+
+ #include "gedit-window-private.h"
+ #include "gedit-app.h"
+ #include "gedit-app-private.h"
++#include "gedit-recent.h"
+ #include "gedit-notebook.h"
+ #include "gedit-notebook-popup-menu.h"
+ #include "gedit-multi-notebook.h"
+ #include "gedit-statusbar.h"
+ #include "gedit-tab.h"
+ #include "gedit-tab-private.h"
+ #include "gedit-view-frame.h"
++#include "gedit-view-centering.h"
+ #include "gedit-utils.h"
+ #include "gedit-commands.h"
+ #include "gedit-commands-private.h"
+ #include "gedit-debug.h"
+ #include "gedit-document.h"
+ #include "gedit-document-private.h"
+ #include "gedit-documents-panel.h"
+ #include "gedit-plugins-engine.h"
+ #include "gedit-window-activatable.h"
+ #include "gedit-enum-types.h"
+ #include "gedit-dirs.h"
+ #include "gedit-status-menu-button.h"
+ #include "gedit-settings.h"
+ #include "gedit-menu-stack-switcher.h"
++#include "gedit-highlight-mode-selector.h"
++#include "gedit-open-document-selector.h"
++
++#define TAB_WIDTH_DATA "GeditWindowTabWidthData"
++#define FULLSCREEN_ANIMATION_SPEED 500
+
+ enum
+ {
+ PROP_0,
+ PROP_STATE,
+ LAST_PROP
+ };
+
+ static GParamSpec *properties[LAST_PROP];
+
+ enum
+ {
+ TAB_ADDED,
+ TAB_REMOVED,
+ TABS_REORDERED,
+ ACTIVE_TAB_CHANGED,
+ ACTIVE_TAB_STATE_CHANGED,
+ LAST_SIGNAL
+ };
+
+ static guint signals[LAST_SIGNAL];
+
+ enum
+ {
+ TARGET_URI_LIST = 100,
+ TARGET_XDNDDIRECTSAVE
+ };
+
+ static const GtkTargetEntry drop_types [] = {
+ { "XdndDirectSave0", 0, TARGET_XDNDDIRECTSAVE }, /* XDS Protocol Type */
+@@ -131,63 +137,63 @@ save_panels_state (GeditWindow *window)
+ {
+ g_settings_set_string (window->priv->window_settings,
+ GEDIT_SETTINGS_SIDE_PANEL_ACTIVE_PAGE,
+ panel_page);
+ }
+
+ if (window->priv->bottom_panel_size > 0)
+ {
+ g_settings_set_int (window->priv->window_settings,
+ GEDIT_SETTINGS_BOTTOM_PANEL_SIZE,
+ window->priv->bottom_panel_size);
+ }
+
+ panel_page = gtk_stack_get_visible_child_name (GTK_STACK (window->priv->bottom_panel));
+ if (panel_page != NULL)
+ {
+ g_settings_set_string (window->priv->window_settings,
+ GEDIT_SETTINGS_BOTTOM_PANEL_ACTIVE_PAGE,
+ panel_page);
+ }
+
+ g_settings_apply (window->priv->window_settings);
+ }
+
+ static void
+ save_window_state (GtkWidget *widget)
+ {
+ GeditWindow *window = GEDIT_WINDOW (widget);
+
+ if ((window->priv->window_state &
+- (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN)) == 0)
++ (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN)) == 0)
+ {
+- gtk_window_get_size (GTK_WINDOW (widget), &window->priv->width, &window->priv->height);
++ gtk_window_get_size (GTK_WINDOW (widget), &window->priv->width, &window->priv->height);
+
+ g_settings_set (window->priv->window_settings, GEDIT_SETTINGS_WINDOW_SIZE,
+ "(ii)", window->priv->width, window->priv->height);
+ }
+ }
+
+ static void
+ gedit_window_dispose (GObject *object)
+ {
+ GeditWindow *window;
+
+ gedit_debug (DEBUG_WINDOW);
+
+ window = GEDIT_WINDOW (object);
+
+ /* Stop tracking removal of panels otherwise we always
+ * end up with thinking we had no panel active, since they
+ * should all be removed below */
+ if (window->priv->bottom_panel_item_removed_handler_id != 0)
+ {
+ g_signal_handler_disconnect (window->priv->bottom_panel,
+ window->priv->bottom_panel_item_removed_handler_id);
+ window->priv->bottom_panel_item_removed_handler_id = 0;
+ }
+
+ /* First of all, force collection so that plugins
+ * really drop some of the references.
+ */
+ peas_engine_garbage_collect (PEAS_ENGINE (gedit_plugins_engine_get_default ()));
+
+@@ -204,142 +210,160 @@ gedit_window_dispose (GObject *object)
+
+ peas_engine_garbage_collect (PEAS_ENGINE (gedit_plugins_engine_get_default ()));
+
+ window->priv->dispose_has_run = TRUE;
+ }
+
+ g_clear_object (&window->priv->message_bus);
+ g_clear_object (&window->priv->window_group);
+
+ /* We must free the settings after saving the panels */
+ g_clear_object (&window->priv->editor_settings);
+ g_clear_object (&window->priv->ui_settings);
+ g_clear_object (&window->priv->window_settings);
+
+ /* Now that there have broken some reference loops,
+ * force collection again.
+ */
+ peas_engine_garbage_collect (PEAS_ENGINE (gedit_plugins_engine_get_default ()));
+
+ g_clear_object (&window->priv->side_stack_switcher);
+
+ /* GTK+/GIO unref the action map in an idle. For the last GeditWindow,
+ * the application quits before the idle, so the action map is not
+ * unreffed, and some objects are not finalized on application shutdown
+ * (GeditView for example).
+ * So this is just for making the debugging of object references a bit
+ * nicer.
+ */
+ remove_actions (window);
+
+- window->priv->fullscreen_open_recent_button = NULL;
+-
+ G_OBJECT_CLASS (gedit_window_parent_class)->dispose (object);
+ }
+
+ static void
+ gedit_window_finalize (GObject *object)
+ {
+ GeditWindow *window = GEDIT_WINDOW (object);
+
+ g_free (window->priv->file_chooser_folder_uri);
+ g_slist_free_full (window->priv->closed_docs_stack, (GDestroyNotify)g_object_unref);
+
+ G_OBJECT_CLASS (gedit_window_parent_class)->finalize (object);
+ }
+
++/* Center the view when the window is in fullscreen mode. */
++static void
++update_view_centering (GeditTab *tab,
++ gpointer user_data)
++{
++ GeditViewFrame *view_frame;
++ GeditViewCentering *view_centering;
++ gboolean is_fullscreen;
++
++ view_frame = _gedit_tab_get_view_frame (tab);
++ view_centering = gedit_view_frame_get_view_centering (view_frame);
++
++ is_fullscreen = GPOINTER_TO_BOOLEAN (user_data);
++ gedit_view_centering_set_centered (view_centering, is_fullscreen);
++}
++
+ static void
+ update_fullscreen (GeditWindow *window,
+ gboolean is_fullscreen)
+ {
+ GAction *fullscreen_action;
+
+ _gedit_multi_notebook_set_show_tabs (window->priv->multi_notebook, !is_fullscreen);
+
+ if (is_fullscreen)
+ {
+ gtk_widget_hide (window->priv->statusbar);
+ }
+ else
+ {
+ if (g_settings_get_boolean (window->priv->ui_settings, "statusbar-visible"))
+ {
+ gtk_widget_show (window->priv->statusbar);
+ }
+ }
+
++ gedit_multi_notebook_foreach_tab (window->priv->multi_notebook,
++ (GtkCallback)update_view_centering,
++ GBOOLEAN_TO_POINTER (is_fullscreen));
++
+ #ifndef OS_OSX
+ if (is_fullscreen)
+ {
+ gtk_widget_show_all (window->priv->fullscreen_eventbox);
+ }
+ else
+ {
+ gtk_widget_hide (window->priv->fullscreen_eventbox);
+ }
+ #endif
+
+ fullscreen_action = g_action_map_lookup_action (G_ACTION_MAP (window),
+ "fullscreen");
+
+ g_simple_action_set_state (G_SIMPLE_ACTION (fullscreen_action),
+ g_variant_new_boolean (is_fullscreen));
+ }
+
+ static gboolean
+ gedit_window_window_state_event (GtkWidget *widget,
+ GdkEventWindowState *event)
+ {
+ GeditWindow *window = GEDIT_WINDOW (widget);
+
+ window->priv->window_state = event->new_window_state;
+
+ g_settings_set_int (window->priv->window_settings, GEDIT_SETTINGS_WINDOW_STATE,
+ window->priv->window_state);
+
+ if ((event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) != 0)
+ {
+ update_fullscreen (window, (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) != 0);
+ }
+
+ return GTK_WIDGET_CLASS (gedit_window_parent_class)->window_state_event (widget, event);
+ }
+
+ static gboolean
+ gedit_window_configure_event (GtkWidget *widget,
+ GdkEventConfigure *event)
+ {
+ GeditWindow *window = GEDIT_WINDOW (widget);
+
+ if (gtk_widget_get_realized (widget) &&
+ (window->priv->window_state &
+- (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN)) == 0)
++ (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN)) == 0)
+ {
+ save_window_state (widget);
+ }
+
+ return GTK_WIDGET_CLASS (gedit_window_parent_class)->configure_event (widget, event);
+ }
+
+ /*
+ * GtkWindow catches keybindings for the menu items _before_ passing them to
+ * the focused widget. This is unfortunate and means that pressing ctrl+V
+ * in an entry on a panel ends up pasting text in the TextView.
+ * Here we override GtkWindow's handler to do the same things that it
+ * does, but in the opposite order and then we chain up to the grand
+ * parent handler, skipping gtk_window_key_press_event.
+ */
+ static gboolean
+ gedit_window_key_press_event (GtkWidget *widget,
+ GdkEventKey *event)
+ {
+ static gpointer grand_parent_class = NULL;
+
+ GtkWindow *window = GTK_WINDOW (widget);
+ gboolean handled = FALSE;
+
+ if (grand_parent_class == NULL)
+ {
+ grand_parent_class = g_type_class_peek_parent (gedit_window_parent_class);
+ }
+
+ /* handle focus widget key events */
+@@ -427,76 +451,78 @@ gedit_window_class_init (GeditWindowClass *klass)
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GeditWindowClass, tabs_reordered),
+ NULL, NULL, NULL,
+ G_TYPE_NONE,
+ 0);
+ signals[ACTIVE_TAB_CHANGED] =
+ g_signal_new ("active-tab-changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GeditWindowClass, active_tab_changed),
+ NULL, NULL, NULL,
+ G_TYPE_NONE,
+ 1,
+ GEDIT_TYPE_TAB);
+ signals[ACTIVE_TAB_STATE_CHANGED] =
+ g_signal_new ("active-tab-state-changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GeditWindowClass, active_tab_state_changed),
+ NULL, NULL, NULL,
+ G_TYPE_NONE,
+ 0);
+
+ /* Bind class to template */
+ gtk_widget_class_set_template_from_resource (widget_class,
+ "/org/gnome/gedit/ui/gedit-window.ui");
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, titlebar_paned);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, side_headerbar);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, headerbar);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, new_button);
++ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, open_button);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, gear_button);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, hpaned);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, side_panel);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, side_panel_inline_stack_switcher);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, vpaned);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, multi_notebook);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, bottom_panel_box);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, bottom_panel);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, statusbar);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, language_button);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, tab_width_button);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, line_col_button);
++ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, fullscreen_controls);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, fullscreen_eventbox);
+- gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, fullscreen_revealer);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, fullscreen_headerbar);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, fullscreen_new_button);
++ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, fullscreen_open_button);
+ gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, fullscreen_gear_button);
+ }
+
+ static void
+ received_clipboard_contents (GtkClipboard *clipboard,
+ GtkSelectionData *selection_data,
+ GeditWindow *window)
+ {
+ GeditTab *tab;
+ gboolean enabled;
+ GAction *action;
+
+ /* getting clipboard contents is async, so we need to
+ * get the current tab and its state */
+
+ tab = gedit_window_get_active_tab (window);
+
+ if (tab != NULL)
+ {
+ GeditTabState state;
+ gboolean state_normal;
+
+ state = gedit_tab_get_state (tab);
+ state_normal = (state == GEDIT_TAB_STATE_NORMAL);
+
+ enabled = state_normal &&
+ gtk_selection_data_targets_include_text (selection_data);
+ }
+ else
+ {
+@@ -738,138 +764,178 @@ update_actions_sensitivity (GeditWindow *window)
+
+ /* We disable File->Quit/SaveAll/CloseAll while printing to avoid to have two
+ operations (save and print/print preview) that uses the message area at
+ the same time (may be we can remove this limitation in the future) */
+ /* We disable File->Quit/CloseAll if state is saving since saving cannot be
+ cancelled (may be we can remove this limitation in the future) */
+ action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
+ "quit");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
+ !(window->priv->state & GEDIT_WINDOW_STATE_SAVING) &&
+ !(window->priv->state & GEDIT_WINDOW_STATE_PRINTING));
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (window), "save-all");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
+ !(window->priv->state & GEDIT_WINDOW_STATE_PRINTING) &&
+ num_tabs > 0);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (window), "close-all");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
+ num_tabs > 0 &&
+ !(window->priv->state & GEDIT_WINDOW_STATE_SAVING) &&
+ !(window->priv->state & GEDIT_WINDOW_STATE_PRINTING) &&
+ num_tabs > 0);
+
+ peas_extension_set_foreach (window->priv->extensions,
+ (PeasExtensionSetForeachFunc) extension_update_state,
+ window);
+ }
+
+ static void
+-language_chooser_show_cb (TeplLanguageChooser *language_chooser,
+- GeditWindow *window)
++on_recent_chooser_item_activated (GeditOpenDocumentSelector *open_document_selector,
++ gchar *uri,
++ GeditWindow *window)
++{
++ GFile *location;
++ GeditView *active_view;
++
++ g_return_if_fail (GEDIT_WINDOW (window));
++ g_return_if_fail (GEDIT_OPEN_DOCUMENT_SELECTOR (open_document_selector));
++
++ /* TODO: get_current_file when exists */
++ location = g_file_new_for_uri (uri);
++
++ if (location)
++ {
++ GSList *locations = NULL;
++ GSList *loaded = NULL;
++
++ locations = g_slist_prepend (locations, (gpointer) location);
++ loaded = gedit_commands_load_locations (window, locations, NULL, 0, 0);
++
++ /* if it doesn't contain just 1 element */
++ if (!loaded || loaded->next)
++ {
++ gedit_recent_remove_if_local (location);
++ }
++
++ g_slist_free (locations);
++ g_slist_free (loaded);
++
++ g_object_unref (location);
++ }
++
++ /* Needed to close the popover when activating the same
++ * document as the current one */
++ active_view = gedit_window_get_active_view (window);
++ gtk_widget_grab_focus (GTK_WIDGET (active_view));
++}
++
++static void
++language_selector_show_cb (GeditHighlightModeSelector *selector,
++ GeditWindow *window)
+ {
+ GeditDocument *active_document;
+
+ active_document = gedit_window_get_active_document (window);
+ if (active_document != NULL)
+ {
+ GtkSourceLanguage *language;
+
+ language = gedit_document_get_language (active_document);
+- tepl_language_chooser_select_language (language_chooser, language);
++ gedit_highlight_mode_selector_select_language (selector, language);
+ }
+ }
+
+ static void
+-language_activated_cb (TeplLanguageChooser *language_chooser,
+- GtkSourceLanguage *language,
+- GeditWindow *window)
++language_selected_cb (GeditHighlightModeSelector *selector,
++ GtkSourceLanguage *language,
++ GeditWindow *window)
+ {
+ GeditDocument *active_document;
+
+ active_document = gedit_window_get_active_document (window);
+ if (active_document != NULL)
+ {
+ gedit_document_set_language (active_document, language);
+ }
+
+- gtk_widget_hide (window->priv->language_popover);
++ gtk_widget_hide (GTK_WIDGET (window->priv->language_popover));
+ }
+
+ static void
+ setup_statusbar (GeditWindow *window)
+ {
+- TeplLanguageChooserWidget *language_chooser;
++ GeditHighlightModeSelector *selector;
+
+ gedit_debug (DEBUG_WINDOW);
+
+ window->priv->generic_message_cid = gtk_statusbar_get_context_id
+ (GTK_STATUSBAR (window->priv->statusbar), "generic_message");
+ window->priv->tip_message_cid = gtk_statusbar_get_context_id
+ (GTK_STATUSBAR (window->priv->statusbar), "tip_message");
+ window->priv->bracket_match_message_cid = gtk_statusbar_get_context_id
+ (GTK_STATUSBAR (window->priv->statusbar), "bracket_match_message");
+
+ g_settings_bind (window->priv->ui_settings,
+ "statusbar-visible",
+ window->priv->statusbar,
+ "visible",
+ G_SETTINGS_BIND_GET);
+
+ /* Line Col button */
+ gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (window->priv->line_col_button),
+ _gedit_app_get_line_col_menu (GEDIT_APP (g_application_get_default ())));
+
+ /* Tab Width button */
+ gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (window->priv->tab_width_button),
+ _gedit_app_get_tab_width_menu (GEDIT_APP (g_application_get_default ())));
+
+ /* Language button */
+ window->priv->language_popover = gtk_popover_new (window->priv->language_button);
+ gtk_menu_button_set_popover (GTK_MENU_BUTTON (window->priv->language_button),
+ window->priv->language_popover);
+
+- language_chooser = tepl_language_chooser_widget_new ();
++ selector = gedit_highlight_mode_selector_new ();
+
+- g_signal_connect (language_chooser,
++ g_signal_connect (selector,
+ "show",
+- G_CALLBACK (language_chooser_show_cb),
++ G_CALLBACK (language_selector_show_cb),
+ window);
+
+- g_signal_connect (language_chooser,
+- "language-activated",
+- G_CALLBACK (language_activated_cb),
++ g_signal_connect (selector,
++ "language-selected",
++ G_CALLBACK (language_selected_cb),
+ window);
+
+- gtk_container_add (GTK_CONTAINER (window->priv->language_popover), GTK_WIDGET (language_chooser));
+- gtk_widget_show (GTK_WIDGET (language_chooser));
++ gtk_container_add (GTK_CONTAINER (window->priv->language_popover), GTK_WIDGET (selector));
++ gtk_widget_show (GTK_WIDGET (selector));
+ }
+
+ static GeditWindow *
+ clone_window (GeditWindow *origin)
+ {
+ GeditWindow *window;
+ GdkScreen *screen;
+ GeditApp *app;
+ const gchar *panel_page;
+
+ gedit_debug (DEBUG_WINDOW);
+
+ app = GEDIT_APP (g_application_get_default ());
+
+ screen = gtk_window_get_screen (GTK_WINDOW (origin));
+ window = gedit_app_create_window (app, screen);
+
+ gtk_window_set_default_size (GTK_WINDOW (window),
+ origin->priv->width,
+ origin->priv->height);
+
+ if ((origin->priv->window_state & GDK_WINDOW_STATE_MAXIMIZED) != 0)
+ gtk_window_maximize (GTK_WINDOW (window));
+ else
+ gtk_window_unmaximize (GTK_WINDOW (window));
+
+ if ((origin->priv->window_state & GDK_WINDOW_STATE_STICKY) != 0)
+ gtk_window_stick (GTK_WINDOW (window));
+ else
+ gtk_window_unstick (GTK_WINDOW (window));
+@@ -1017,81 +1083,81 @@ set_title (GeditWindow *window)
+ gedit_app_set_window_title (GEDIT_APP (g_application_get_default ()),
+ window,
+ "gedit");
+ gtk_header_bar_set_title (GTK_HEADER_BAR (window->priv->headerbar),
+ "gedit");
+ gtk_header_bar_set_subtitle (GTK_HEADER_BAR (window->priv->headerbar),
+ NULL);
+ gtk_header_bar_set_title (GTK_HEADER_BAR (window->priv->fullscreen_headerbar),
+ "gedit");
+ gtk_header_bar_set_subtitle (GTK_HEADER_BAR (window->priv->fullscreen_headerbar),
+ NULL);
+ return;
+ }
+
+ doc = gedit_tab_get_document (tab);
+ g_return_if_fail (doc != NULL);
+
+ file = gedit_document_get_file (doc);
+
+ name = gedit_document_get_short_name_for_display (doc);
+
+ len = g_utf8_strlen (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_TITLE_LENGTH)
+ {
+ gchar *tmp;
+
+- tmp = tepl_utils_str_middle_truncate (name,
+- MAX_TITLE_LENGTH);
++ tmp = gedit_utils_str_middle_truncate (name,
++ MAX_TITLE_LENGTH);
+ g_free (name);
+ name = tmp;
+ }
+ else
+ {
+ GFile *location = gtk_source_file_get_location (file);
+
+ if (location != NULL)
+ {
+ gchar *str = gedit_utils_location_get_dirname_for_display (location);
+
+ /* 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 :)
+ */
+- dirname = tepl_utils_str_middle_truncate (str,
+- MAX (20, MAX_TITLE_LENGTH - len));
++ dirname = gedit_utils_str_middle_truncate (str,
++ MAX (20, MAX_TITLE_LENGTH - len));
+ g_free (str);
+ }
+ }
+
+ if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (doc)))
+ {
+ gchar *tmp_name;
+
+ tmp_name = g_strdup_printf ("*%s", name);
+ g_free (name);
+
+ name = tmp_name;
+ }
+
+ if (gtk_source_file_is_readonly (file))
+ {
+ title = g_strdup_printf ("%s [%s]",
+ name, _("Read-Only"));
+
+ if (dirname != NULL)
+ {
+ main_title = g_strdup_printf ("%s [%s] (%s) - gedit",
+ name,
+ _("Read-Only"),
+ dirname);
+ subtitle = dirname;
+ }
+ else
+ {
+ main_title = g_strdup_printf ("%s [%s] - gedit",
+@@ -1663,142 +1729,138 @@ drag_drop_cb (GtkWidget *widget,
+
+ found = gtk_target_list_find (target_list, target, &info);
+ g_assert (found);
+
+ if (info == TARGET_XDNDDIRECTSAVE)
+ {
+ gchar *uri;
+ uri = gedit_utils_set_direct_save_filename (context);
+
+ if (uri != NULL)
+ {
+ g_free (window->priv->direct_save_uri);
+ window->priv->direct_save_uri = uri;
+ }
+ }
+
+ gtk_drag_get_data (GTK_WIDGET (widget), context,
+ target, time);
+ }
+ }
+
+ /* Handle drops on the GeditView */
+ static void
+ drop_uris_cb (GtkWidget *widget,
+ gchar **uri_list,
+ GeditWindow *window)
+ {
+ load_uris_from_drop (window, uri_list);
+ }
+
+-static void
+-update_fullscreen_revealer_state (GeditWindow *window)
++static gboolean
++on_fullscreen_controls_enter_notify_event (GtkWidget *widget,
++ GdkEventCrossing *event,
++ GeditWindow *window)
+ {
+- gboolean open_recent_menu_is_active;
+- gboolean hamburger_menu_is_active;
++ window->priv->in_fullscreen_eventbox = TRUE;
+
+- open_recent_menu_is_active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (window->priv->fullscreen_open_recent_button));
+- hamburger_menu_is_active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (window->priv->fullscreen_gear_button));
++ gtk_revealer_set_reveal_child (GTK_REVEALER (window->priv->fullscreen_controls), TRUE);
+
+- gtk_revealer_set_reveal_child (window->priv->fullscreen_revealer,
+- (window->priv->in_fullscreen_eventbox ||
+- open_recent_menu_is_active ||
+- hamburger_menu_is_active));
++ return FALSE;
+ }
+
+ static gboolean
+-on_fullscreen_eventbox_enter_notify_event (GtkWidget *fullscreen_eventbox,
+- GdkEventCrossing *event,
+- GeditWindow *window)
++real_fullscreen_controls_leave_notify_event (gpointer data)
+ {
+- window->priv->in_fullscreen_eventbox = TRUE;
+- update_fullscreen_revealer_state (window);
++ GeditWindow *window = GEDIT_WINDOW (data);
++ gboolean hamburger_menu_state;
++ gboolean fullscreen_open_button_state;
+
+- return GDK_EVENT_PROPAGATE;
+-}
++ hamburger_menu_state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (window->priv->fullscreen_gear_button));
++ fullscreen_open_button_state =
++ gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (window->priv->fullscreen_open_button));
+
+-static gboolean
+-on_fullscreen_eventbox_leave_notify_event (GtkWidget *fullscreen_eventbox,
+- GdkEventCrossing *event,
+- GeditWindow *window)
+-{
+- if (-1.0 <= event->y && event->y <= 0.0)
+- {
+- /* Ignore the event.
+- *
+- * Leave notify events are received with -1 <= y <= 0
+- * coordinates, although the GeditWindow is in fullscreen mode
+- * and when there are no screens above (it's maybe a bug in an
+- * underlying library).
+- * If we hide the headerbar when those events happen, then it
+- * makes the headerbar to be shown/hidden a lot of time in a
+- * short period of time, i.e. a "stuttering". In other words
+- * lots of leave/enter events are received when moving the mouse
+- * upwards on the screen when the mouse is already at the top.
+- * The expected leave event has a positive event->y value being
+- * >= to the height of the headerbar (approximately
+- * 40 <= y <= 50). So clearly when we receive a leave event with
+- * event->y <= 0, it means that the mouse has left the eventbox
+- * on the wrong side.
+- * The -1.0 <= event->y is there (instead of just <= 0.0) in the
+- * case that there is another screen *above*, even if this
+- * heuristic/workaround is not perfect in that case. But that
+- * case is quite rare, so it's probably a good enough solution.
+- *
+- * Note that apparently the "stuttering" occurs only on an Xorg
+- * session, not on Wayland (tested with GNOME).
+- *
+- * If you see a better solution...
+- */
+- return GDK_EVENT_PROPAGATE;
++ window->priv->in_fullscreen_eventbox = FALSE;
++
++ if (!hamburger_menu_state && !fullscreen_open_button_state)
++ {
++ gtk_revealer_set_reveal_child (GTK_REVEALER (window->priv->fullscreen_controls), FALSE);
+ }
+
+- window->priv->in_fullscreen_eventbox = FALSE;
+- update_fullscreen_revealer_state (window);
++ return G_SOURCE_REMOVE;
++}
++
++/* this idle is needed because the toggled signal from gear button is received
++ * after the leave event from the event box ( which is automatically triggered when user
++ * bring up the gear menu */
++static gboolean
++on_fullscreen_controls_leave_notify_event (GtkWidget *widget,
++ GdkEventCrossing *event,
++ GeditWindow *window)
++{
++ g_idle_add (real_fullscreen_controls_leave_notify_event, window);
+
+ return GDK_EVENT_PROPAGATE;
+ }
+
+ static void
+-setup_fullscreen_eventbox (GeditWindow *window)
++fullscreen_controls_setup (GeditWindow *window)
+ {
+- gtk_widget_set_size_request (window->priv->fullscreen_eventbox, -1, 1);
+- gtk_widget_hide (window->priv->fullscreen_eventbox);
++ GeditWindowPrivate *priv = window->priv;
+
+- g_signal_connect (window->priv->fullscreen_eventbox,
++ g_signal_connect (priv->fullscreen_eventbox,
+ "enter-notify-event",
+- G_CALLBACK (on_fullscreen_eventbox_enter_notify_event),
++ G_CALLBACK (on_fullscreen_controls_enter_notify_event),
+ window);
+
+- g_signal_connect (window->priv->fullscreen_eventbox,
++ g_signal_connect (priv->fullscreen_eventbox,
+ "leave-notify-event",
+- G_CALLBACK (on_fullscreen_eventbox_leave_notify_event),
++ G_CALLBACK (on_fullscreen_controls_leave_notify_event),
++ window);
++
++ gtk_widget_set_size_request (GTK_WIDGET (window->priv->fullscreen_eventbox), -1, 1);
++ gtk_widget_hide (window->priv->fullscreen_eventbox);
++
++ priv->fullscreen_open_document_popover = gtk_popover_new (priv->fullscreen_open_button);
++ gtk_menu_button_set_popover (GTK_MENU_BUTTON (priv->fullscreen_open_button),
++ priv->fullscreen_open_document_popover);
++
++ window->priv->fullscreen_open_document_selector = gedit_open_document_selector_new (window);
++
++ gtk_container_add (GTK_CONTAINER (priv->fullscreen_open_document_popover),
++ GTK_WIDGET (priv->fullscreen_open_document_selector));
++
++ gtk_widget_show_all (GTK_WIDGET (priv->fullscreen_open_document_selector));
++
++ g_signal_connect (window->priv->fullscreen_open_document_selector,
++ "file-activated",
++ G_CALLBACK (on_recent_chooser_item_activated),
+ window);
+ }
+
+ static void
+ empty_search_notify_cb (GeditDocument *doc,
+ GParamSpec *pspec,
+ GeditWindow *window)
+ {
+ if (doc == gedit_window_get_active_document (window))
+ {
+ update_actions_sensitivity (window);
+ }
+ }
+
+ static void
+ can_undo (GeditDocument *doc,
+ GParamSpec *pspec,
+ GeditWindow *window)
+ {
+ if (doc == gedit_window_get_active_document (window))
+ {
+ update_actions_sensitivity (window);
+ }
+ }
+
+ static void
+ can_redo (GeditDocument *doc,
+ GParamSpec *pspec,
+ GeditWindow *window)
+ {
+@@ -1858,61 +1920,61 @@ on_tab_added (GeditMultiNotebook *multi,
+ update_actions_sensitivity (window);
+
+ view = gedit_tab_get_view (tab);
+ doc = gedit_tab_get_document (tab);
+ file = gedit_document_get_file (doc);
+
+ /* IMPORTANT: remember to disconnect the signal in notebook_tab_removed
+ * if a new signal is connected here */
+
+ g_signal_connect (tab,
+ "notify::name",
+ G_CALLBACK (sync_name),
+ window);
+ g_signal_connect (tab,
+ "notify::state",
+ G_CALLBACK (sync_state),
+ window);
+ g_signal_connect (tab,
+ "notify::can-close",
+ G_CALLBACK (sync_can_close),
+ window);
+ g_signal_connect (tab,
+ "drop_uris",
+ G_CALLBACK (drop_uris_cb),
+ window);
+ g_signal_connect (doc,
+ "bracket-matched",
+ G_CALLBACK (bracket_matched_cb),
+ window);
+ g_signal_connect (doc,
+- "tepl-cursor-moved",
++ "cursor-moved",
+ G_CALLBACK (update_cursor_position_statusbar),
+ window);
+ g_signal_connect (doc,
+ "notify::empty-search",
+ G_CALLBACK (empty_search_notify_cb),
+ window);
+ g_signal_connect (doc,
+ "notify::can-undo",
+ G_CALLBACK (can_undo),
+ window);
+ g_signal_connect (doc,
+ "notify::can-redo",
+ G_CALLBACK (can_redo),
+ window);
+ g_signal_connect (doc,
+ "notify::has-selection",
+ G_CALLBACK (selection_changed),
+ window);
+ g_signal_connect (view,
+ "notify::overwrite",
+ G_CALLBACK (overwrite_mode_changed),
+ window);
+ g_signal_connect (view,
+ "notify::editable",
+ G_CALLBACK (editable_changed),
+ window);
+ g_signal_connect (file,
+ "notify::read-only",
+ G_CALLBACK (readonly_changed),
+ window);
+@@ -2117,64 +2179,77 @@ on_show_popup_menu (GeditMultiNotebook *multi,
+ }
+
+ menu = gedit_notebook_popup_menu_new (window, tab);
+
+ g_signal_connect (menu,
+ "selection-done",
+ G_CALLBACK (gtk_widget_destroy),
+ NULL);
+
+ gtk_widget_show (menu);
+ gtk_menu_popup_at_pointer (GTK_MENU (menu), (GdkEvent *)event);
+ }
+
+ static void
+ on_notebook_changed (GeditMultiNotebook *mnb,
+ GParamSpec *pspec,
+ GeditWindow *window)
+ {
+ update_actions_sensitivity (window);
+ }
+
+ static void
+ on_notebook_removed (GeditMultiNotebook *mnb,
+ GeditNotebook *notebook,
+ GeditWindow *window)
+ {
+ update_actions_sensitivity (window);
+ }
+
+ static void
+-on_fullscreen_toggle_button_toggled (GtkToggleButton *fullscreen_toggle_button,
+- GeditWindow *window)
++on_fullscreen_gear_button_toggled (GtkToggleButton *fullscreen_gear_button,
++ GeditWindow *window)
+ {
+- update_fullscreen_revealer_state (window);
++ gboolean button_active = gtk_toggle_button_get_active (fullscreen_gear_button);
++
++ gtk_revealer_set_reveal_child (GTK_REVEALER (window->priv->fullscreen_controls),
++ button_active || window->priv->in_fullscreen_eventbox);
++}
++
++static void
++on_fullscreen_file_menu_button_toggled (GtkMenuButton *fullscreen_open_button,
++ GeditWindow *window)
++{
++ gboolean button_active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fullscreen_open_button));
++
++ gtk_revealer_set_reveal_child (GTK_REVEALER (window->priv->fullscreen_controls),
++ button_active || window->priv->in_fullscreen_eventbox);
+ }
+
+ static void
+ side_panel_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation,
+ GeditWindow *window)
+ {
+ window->priv->side_panel_size = allocation->width;
+ }
+
+ static void
+ bottom_panel_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation,
+ GeditWindow *window)
+ {
+ window->priv->bottom_panel_size = allocation->height;
+ }
+
+ static void
+ hpaned_restore_position (GtkWidget *widget,
+ GeditWindow *window)
+ {
+ gint pos;
+
+ gedit_debug_message (DEBUG_WINDOW,
+ "Restoring hpaned position: side panel size %d",
+ window->priv->side_panel_size);
+
+ pos = MAX (100, window->priv->side_panel_size);
+ gtk_paned_set_position (GTK_PANED (window->priv->hpaned), pos);
+@@ -2510,60 +2585,72 @@ clipboard_owner_change (GtkClipboard *clipboard,
+
+ static void
+ window_realized (GtkWidget *window,
+ gpointer *data)
+ {
+ GtkClipboard *clipboard;
+
+ clipboard = gtk_widget_get_clipboard (window,
+ GDK_SELECTION_CLIPBOARD);
+
+ g_signal_connect (clipboard,
+ "owner_change",
+ G_CALLBACK (clipboard_owner_change),
+ window);
+ }
+
+ static void
+ window_unrealized (GtkWidget *window,
+ gpointer *data)
+ {
+ GtkClipboard *clipboard;
+
+ clipboard = gtk_widget_get_clipboard (window,
+ GDK_SELECTION_CLIPBOARD);
+
+ g_signal_handlers_disconnect_by_func (clipboard,
+ G_CALLBACK (clipboard_owner_change),
+ window);
+ }
+
++static void
++check_window_is_active (GeditWindow *window,
++ GParamSpec *property,
++ gpointer useless)
++{
++ if (window->priv->window_state & GDK_WINDOW_STATE_FULLSCREEN)
++ {
++ gtk_widget_set_visible (window->priv->fullscreen_eventbox,
++ gtk_window_is_active (GTK_WINDOW (window)));
++ }
++}
++
+ static void
+ extension_added (PeasExtensionSet *extensions,
+ PeasPluginInfo *info,
+ PeasExtension *exten,
+ GeditWindow *window)
+ {
+ gedit_window_activatable_activate (GEDIT_WINDOW_ACTIVATABLE (exten));
+ }
+
+ static void
+ extension_removed (PeasExtensionSet *extensions,
+ PeasPluginInfo *info,
+ PeasExtension *exten,
+ GeditWindow *window)
+ {
+ gedit_window_activatable_deactivate (GEDIT_WINDOW_ACTIVATABLE (exten));
+ }
+
+ static GActionEntry win_entries[] = {
+ { "new-tab", _gedit_cmd_file_new },
+ { "open", _gedit_cmd_file_open },
+ { "revert", _gedit_cmd_file_revert },
+ { "reopen-closed-tab", _gedit_cmd_file_reopen_closed_tab },
+ { "save", _gedit_cmd_file_save },
+ { "save-as", _gedit_cmd_file_save_as },
+ { "save-all", _gedit_cmd_file_save_all },
+ { "close", _gedit_cmd_file_close },
+ { "close-all", _gedit_cmd_file_close_all },
+ { "print", _gedit_cmd_file_print },
+ { "focus-active-view", NULL, NULL, "false", _gedit_cmd_view_focus_active },
+@@ -2581,188 +2668,145 @@ static GActionEntry win_entries[] = {
+ { "previous-tab-group", _gedit_cmd_documents_previous_tab_group },
+ { "next-tab-group", _gedit_cmd_documents_next_tab_group },
+ { "previous-document", _gedit_cmd_documents_previous_document },
+ { "next-document", _gedit_cmd_documents_next_document },
+ { "move-to-new-window", _gedit_cmd_documents_move_to_new_window },
+ { "undo", _gedit_cmd_edit_undo },
+ { "redo", _gedit_cmd_edit_redo },
+ { "cut", _gedit_cmd_edit_cut },
+ { "copy", _gedit_cmd_edit_copy },
+ { "paste", _gedit_cmd_edit_paste },
+ { "delete", _gedit_cmd_edit_delete },
+ { "select-all", _gedit_cmd_edit_select_all },
+ { "highlight-mode", _gedit_cmd_view_highlight_mode },
+ { "overwrite-mode", NULL, NULL, "false", _gedit_cmd_edit_overwrite_mode }
+ };
+
+ static void
+ sync_fullscreen_actions (GeditWindow *window,
+ gboolean fullscreen)
+ {
+ GtkMenuButton *button;
+ GPropertyAction *action;
+
+ button = fullscreen ? window->priv->fullscreen_gear_button : window->priv->gear_button;
+ g_action_map_remove_action (G_ACTION_MAP (window), "hamburger-menu");
+ action = g_property_action_new ("hamburger-menu", button, "active");
+ g_action_map_add_action (G_ACTION_MAP (window), G_ACTION (action));
+ g_object_unref (action);
+ }
+
+-static void
+-init_amtk_application_window (GeditWindow *gedit_window)
+-{
+- AmtkApplicationWindow *amtk_window;
+-
+- amtk_window = amtk_application_window_get_from_gtk_application_window (GTK_APPLICATION_WINDOW (gedit_window));
+- amtk_application_window_set_statusbar (amtk_window, GTK_STATUSBAR (gedit_window->priv->statusbar));
+-}
+-
+-static GtkWidget *
+-create_open_buttons (GeditWindow *window,
+- GtkMenuButton **open_recent_button)
+-{
+- GtkWidget *hbox;
+- GtkStyleContext *style_context;
+- GtkWidget *open_dialog_button;
+- GtkWidget *my_open_recent_button;
+- AmtkApplicationWindow *amtk_window;
+- GtkWidget *recent_menu;
+-
+- /* It currently needs to be a GtkBox, not a GtkGrid, because GtkGrid and
+- * GTK_STYLE_CLASS_LINKED doesn't work as expected in a RTL locale.
+- * Probably a GtkGrid bug.
+- */
+- hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+- style_context = gtk_widget_get_style_context (hbox);
+- gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_LINKED);
+-
+- open_dialog_button = gtk_button_new_with_mnemonic (_("_Open"));
+- gtk_widget_set_tooltip_text (open_dialog_button, _("Open a file"));
+- gtk_actionable_set_action_name (GTK_ACTIONABLE (open_dialog_button), "win.open");
+-
+- my_open_recent_button = gtk_menu_button_new ();
+- gtk_widget_set_tooltip_text (my_open_recent_button, _("Open a recently used file"));
+-
+- amtk_window = amtk_application_window_get_from_gtk_application_window (GTK_APPLICATION_WINDOW (window));
+- recent_menu = amtk_application_window_create_open_recent_menu (amtk_window);
+- gtk_menu_button_set_popup (GTK_MENU_BUTTON (my_open_recent_button), recent_menu);
+-
+- gtk_container_add (GTK_CONTAINER (hbox), open_dialog_button);
+- gtk_container_add (GTK_CONTAINER (hbox), my_open_recent_button);
+- gtk_widget_show_all (hbox);
+-
+- if (open_recent_button != NULL)
+- {
+- *open_recent_button = GTK_MENU_BUTTON (my_open_recent_button);
+- }
+-
+- return hbox;
+-}
+-
+-static void
+-init_open_buttons (GeditWindow *window)
+-{
+- gtk_container_add_with_properties (GTK_CONTAINER (window->priv->headerbar),
+- create_open_buttons (window, NULL),
+- "position", 0, /* The first on the left. */
+- NULL);
+-
+- gtk_container_add_with_properties (GTK_CONTAINER (window->priv->fullscreen_headerbar),
+- create_open_buttons (window, &(window->priv->fullscreen_open_recent_button)),
+- "position", 0, /* The first on the left. */
+- NULL);
+-
+- g_signal_connect (GTK_TOGGLE_BUTTON (window->priv->fullscreen_open_recent_button),
+- "toggled",
+- G_CALLBACK (on_fullscreen_toggle_button_toggled),
+- window);
+-}
+-
+ static void
+ gedit_window_init (GeditWindow *window)
+ {
+ GtkTargetList *tl;
+ GMenuModel *hamburger_menu;
+
+ gedit_debug (DEBUG_WINDOW);
+
+ window->priv = gedit_window_get_instance_private (window);
+
+ window->priv->removing_tabs = FALSE;
+ window->priv->state = GEDIT_WINDOW_STATE_NORMAL;
+ window->priv->inhibition_cookie = 0;
+ window->priv->dispose_has_run = FALSE;
++ window->priv->fullscreen_controls = NULL;
+ window->priv->direct_save_uri = NULL;
+ window->priv->closed_docs_stack = NULL;
+ window->priv->editor_settings = g_settings_new ("org.gnome.gedit.preferences.editor");
+ window->priv->ui_settings = g_settings_new ("org.gnome.gedit.preferences.ui");
+
+ /* window settings are applied only once the window is closed. We do not
+ want to keep writing to disk when the window is dragged around */
+ window->priv->window_settings = g_settings_new ("org.gnome.gedit.state.window");
+ g_settings_delay (window->priv->window_settings);
+
+ window->priv->message_bus = gedit_message_bus_new ();
+
+ gtk_widget_init_template (GTK_WIDGET (window));
+- init_amtk_application_window (window);
+- init_open_buttons (window);
+
+ g_action_map_add_action_entries (G_ACTION_MAP (window),
+ win_entries,
+ G_N_ELEMENTS (win_entries),
+ window);
+
+ window->priv->window_group = gtk_window_group_new ();
+ gtk_window_group_add_window (window->priv->window_group, GTK_WINDOW (window));
+
+- setup_fullscreen_eventbox (window);
++ /* Setup file popover and file dialog */
++ window->priv->open_document_popover = gtk_popover_new (window->priv->open_button);
++ gtk_menu_button_set_popover (GTK_MENU_BUTTON (window->priv->open_button),
++ window->priv->open_document_popover);
++
++ window->priv->open_document_selector = gedit_open_document_selector_new (window);
++
++ gtk_container_add (GTK_CONTAINER (window->priv->open_document_popover),
++ GTK_WIDGET (window->priv->open_document_selector));
++
++ gtk_widget_show_all (GTK_WIDGET (window->priv->open_document_selector));
++
++ g_signal_connect (window->priv->open_document_selector,
++ "file-activated",
++ G_CALLBACK (on_recent_chooser_item_activated),
++ window);
++
++ fullscreen_controls_setup (window);
+ sync_fullscreen_actions (window, FALSE);
+
++ g_object_bind_property (gedit_open_document_selector_get_search_entry (window->priv->open_document_selector),
++ "text",
++ gedit_open_document_selector_get_search_entry (window->priv->fullscreen_open_document_selector),
++ "text",
++ G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
++
+ hamburger_menu = _gedit_app_get_hamburger_menu (GEDIT_APP (g_application_get_default ()));
+ if (hamburger_menu)
+ {
+ gtk_menu_button_set_menu_model (window->priv->gear_button, hamburger_menu);
+ gtk_menu_button_set_menu_model (window->priv->fullscreen_gear_button, hamburger_menu);
+ }
+ else
+ {
+ gtk_widget_hide (GTK_WIDGET (window->priv->gear_button));
+ gtk_widget_hide (GTK_WIDGET (window->priv->fullscreen_gear_button));
+ gtk_widget_set_no_show_all (GTK_WIDGET (window->priv->gear_button), TRUE);
+ gtk_widget_set_no_show_all (GTK_WIDGET (window->priv->fullscreen_gear_button), TRUE);
+ }
+
++ g_signal_connect (GTK_TOGGLE_BUTTON (window->priv->fullscreen_open_button),
++ "toggled",
++ G_CALLBACK (on_fullscreen_file_menu_button_toggled),
++ window);
++
+ g_signal_connect (GTK_TOGGLE_BUTTON (window->priv->fullscreen_gear_button),
+ "toggled",
+- G_CALLBACK (on_fullscreen_toggle_button_toggled),
++ G_CALLBACK (on_fullscreen_gear_button_toggled),
+ window);
+
+ /* Setup status bar */
+ setup_statusbar (window);
+
+ /* Setup main area */
+ g_signal_connect (window->priv->multi_notebook,
+ "notebook-removed",
+ G_CALLBACK (on_notebook_removed),
+ window);
+ g_signal_connect (window->priv->multi_notebook,
+ "notify::active-notebook",
+ G_CALLBACK (on_notebook_changed),
+ window);
+
+ g_signal_connect (window->priv->multi_notebook,
+ "tab-added",
+ G_CALLBACK (on_tab_added),
+ window);
+
+ g_signal_connect (window->priv->multi_notebook,
+ "tab-removed",
+ G_CALLBACK (on_tab_removed),
+ window);
+
+ g_signal_connect (window->priv->multi_notebook,
+ "switch-tab",
+ G_CALLBACK (tab_switched),
+ window);
+
+@@ -2822,60 +2866,66 @@ gedit_window_init (GeditWindow *window)
+ {
+ tl = gtk_target_list_new (drop_types, G_N_ELEMENTS (drop_types));
+ gtk_drag_dest_set_target_list (GTK_WIDGET (window), tl);
+ gtk_target_list_unref (tl);
+ }
+
+ gtk_target_list_add_uri_targets (tl, TARGET_URI_LIST);
+
+ /* connect instead of override, so that we can
+ * share the cb code with the view */
+ g_signal_connect (window,
+ "drag_data_received",
+ G_CALLBACK (drag_data_received_cb),
+ NULL);
+ g_signal_connect (window,
+ "drag_drop",
+ G_CALLBACK (drag_drop_cb),
+ NULL);
+
+ /* we can get the clipboard only after the widget
+ * is realized */
+ g_signal_connect (window,
+ "realize",
+ G_CALLBACK (window_realized),
+ NULL);
+ g_signal_connect (window,
+ "unrealize",
+ G_CALLBACK (window_unrealized),
+ NULL);
+
++ /* Check if the window is active for fullscreen */
++ g_signal_connect (window,
++ "notify::is-active",
++ G_CALLBACK (check_window_is_active),
++ NULL);
++
+ gedit_debug_message (DEBUG_WINDOW, "Update plugins ui");
+
+ window->priv->extensions = peas_extension_set_new (PEAS_ENGINE (gedit_plugins_engine_get_default ()),
+ GEDIT_TYPE_WINDOW_ACTIVATABLE,
+ "window", window,
+ NULL);
+ g_signal_connect (window->priv->extensions,
+ "extension-added",
+ G_CALLBACK (extension_added),
+ window);
+ g_signal_connect (window->priv->extensions,
+ "extension-removed",
+ G_CALLBACK (extension_removed),
+ window);
+ peas_extension_set_foreach (window->priv->extensions,
+ (PeasExtensionSetForeachFunc) extension_added,
+ window);
+
+ /* set visibility of panels.
+ * This needs to be done after plugins activatation */
+ init_panels_visibility (window);
+
+ update_actions_sensitivity (window);
+
+ gedit_debug_message (DEBUG_WINDOW, "END");
+ }
+
+ /**
+ * gedit_window_get_active_view:
+ * @window: a #GeditWindow
+diff --git a/gedit/gedit.c b/gedit/gedit.c
+index fcffdaca6..ee3769537 100644
+--- a/gedit/gedit.c
++++ b/gedit/gedit.c
+@@ -1,67 +1,66 @@
+ /*
+ * gedit.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2005 - Paolo Maggi
+ *
+ * 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
+ * along with this program; if not, see .
+ */
+
+ #include "config.h"
+
+ #include "gedit-app.h"
+
+ #if defined OS_OSX
+ # include "gedit-app-osx.h"
+ #elif defined G_OS_WIN32
+ # include "gedit-app-win32.h"
+ #endif
+
++#include
+ #include
+ #include
+-#include
+
+ #include "gedit-dirs.h"
+ #include "gedit-debug.h"
+-#include "gedit-factory.h"
+ #include "gedit-settings.h"
+
+ #ifdef G_OS_WIN32
+ #include
+ static GModule *libgedit_dll = NULL;
+
+ /* This code must live in gedit.exe, not in libgedit.dll, since the whole
+ * point is to find and load libgedit.dll.
+ */
+ static gboolean
+ gedit_w32_load_private_dll (void)
+ {
+ gchar *dllpath;
+ gchar *prefix;
+
+ prefix = g_win32_get_package_installation_directory_of_module (NULL);
+
+ if (prefix != NULL)
+ {
+ /* Instead of g_module_open () it may be possible to do any of the
+ * following:
+ * A) Change PATH to "${dllpath}/lib/gedit;$PATH"
+ * B) Call SetDllDirectory ("${dllpath}/lib/gedit")
+ * C) Call AddDllDirectory ("${dllpath}/lib/gedit")
+ * But since we only have one library, and its name is known, may as well
+ * use gmodule.
+ */
+ dllpath = g_build_filename (prefix, "lib", "gedit", "lib" PACKAGE_STRING ".dll", NULL);
+ g_free (prefix);
+
+@@ -90,91 +89,86 @@ gedit_w32_load_private_dll (void)
+
+ static void
+ gedit_w32_unload_private_dll (void)
+ {
+ if (libgedit_dll)
+ {
+ g_module_close (libgedit_dll);
+ libgedit_dll = NULL;
+ }
+ }
+ #endif /* G_OS_WIN32 */
+
+ static void
+ setup_i18n (void)
+ {
+ const gchar *dir;
+
+ setlocale (LC_ALL, "");
+
+ dir = gedit_dirs_get_gedit_locale_dir ();
+ bindtextdomain (GETTEXT_PACKAGE, dir);
+
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+ }
+
+ int
+ main (int argc, char *argv[])
+ {
+ GType type;
+- GeditFactory *factory;
+ GeditApp *app;
+ gint status;
+
+ #if defined OS_OSX
+ type = GEDIT_TYPE_APP_OSX;
+ #elif defined G_OS_WIN32
+ if (!gedit_w32_load_private_dll ())
+ {
+ return 1;
+ }
+
+ type = GEDIT_TYPE_APP_WIN32;
+ #else
+ type = GEDIT_TYPE_APP;
+ #endif
+
+ /* NOTE: we should not make any calls to the gedit API before the
+ * private library is loaded.
+ */
+ gedit_dirs_init ();
+
+ setup_i18n ();
+- tepl_init ();
+- factory = gedit_factory_new ();
+- tepl_abstract_factory_set_singleton (TEPL_ABSTRACT_FACTORY (factory));
+
+ app = g_object_new (type,
+ "application-id", "org.gnome.gedit",
+ "flags", G_APPLICATION_HANDLES_COMMAND_LINE | G_APPLICATION_HANDLES_OPEN,
+ NULL);
+
+ status = g_application_run (G_APPLICATION (app), argc, argv);
+
+ gedit_settings_unref_singleton ();
+
+ /* Break reference cycles caused by the PeasExtensionSet
+ * for GeditAppActivatable which holds a ref on the GeditApp
+ */
+ g_object_run_dispose (G_OBJECT (app));
+
+ g_object_add_weak_pointer (G_OBJECT (app), (gpointer *) &app);
+ g_object_unref (app);
+
+ if (app != NULL)
+ {
+ gedit_debug_message (DEBUG_APP, "Leaking with %i refs",
+ G_OBJECT (app)->ref_count);
+ }
+
+- tepl_finalize ();
+ gedit_dirs_shutdown ();
+
+ #ifdef G_OS_WIN32
+ gedit_w32_unload_private_dll ();
+ #endif
+
+ return status;
+ }
+
+ /* ex:set ts=8 noet: */
+diff --git a/gedit/meson.build b/gedit/meson.build
+index 214c2b9a5..51472f12d 100644
+--- a/gedit/meson.build
++++ b/gedit/meson.build
+@@ -1,149 +1,166 @@
+ libgedit_public_headers = [
+ 'gedit-app-activatable.h',
+ 'gedit-app.h',
+ 'gedit-commands.h',
+ 'gedit-debug.h',
+ 'gedit-document.h',
+ 'gedit-encodings-combo-box.h',
+ 'gedit-menu-extension.h',
+ 'gedit-message-bus.h',
+ 'gedit-message.h',
++ 'gedit-progress-info-bar.h',
+ 'gedit-statusbar.h',
+ 'gedit-tab.h',
+ 'gedit-utils.h',
+ 'gedit-view-activatable.h',
+ 'gedit-view.h',
+ 'gedit-window-activatable.h',
+ 'gedit-window.h',
+ ]
+
+ libgedit_public_sources = [
+ 'gedit-app-activatable.c',
+ 'gedit-app.c',
+ 'gedit-commands-file.c',
+ 'gedit-debug.c',
+ 'gedit-document.c',
+ 'gedit-encodings-combo-box.c',
+ 'gedit-menu-extension.c',
+ 'gedit-message-bus.c',
+ 'gedit-message.c',
++ 'gedit-progress-info-bar.c',
+ 'gedit-statusbar.c',
+ 'gedit-tab.c',
+ 'gedit-utils.c',
+ 'gedit-view-activatable.c',
+ 'gedit-view.c',
++ 'gedit-view-centering.c',
+ 'gedit-window-activatable.c',
+ 'gedit-window.c',
+ ]
+
+ libgedit_private_headers = [
+ 'gedit-app-osx.h',
+ 'gedit-app-win32.h',
+ 'gedit-close-confirmation-dialog.h',
+ 'gedit-dirs.h',
+ 'gedit-document-private.h',
+ 'gedit-documents-panel.h',
+ 'gedit-encoding-items.h',
+ 'gedit-encodings-dialog.h',
+- 'gedit-factory.h',
+ 'gedit-file-chooser-dialog-gtk.h',
+ 'gedit-file-chooser-dialog.h',
+ 'gedit-file-chooser.h',
+ 'gedit-file-chooser-open-dialog.h',
+ 'gedit-file-chooser-open.h',
+ 'gedit-file-chooser-open-native.h',
++ 'gedit-highlight-mode-dialog.h',
++ 'gedit-highlight-mode-selector.h',
+ 'gedit-history-entry.h',
+ 'gedit-io-error-info-bar.h',
+ 'gedit-menu-stack-switcher.h',
++ 'gedit-metadata-manager.h',
+ 'gedit-multi-notebook.h',
+ 'gedit-notebook.h',
+ 'gedit-notebook-popup-menu.h',
+ 'gedit-notebook-stack-switcher.h',
++ 'gedit-open-document-selector.h',
++ 'gedit-open-document-selector-helper.h',
++ 'gedit-open-document-selector-store.h',
++ 'gedit-pango.h',
+ 'gedit-plugins-engine.h',
+ 'gedit-preferences-dialog.h',
+ 'gedit-print-job.h',
+ 'gedit-print-preview.h',
+ 'gedit-recent.h',
+- 'gedit-recent-osx.h',
+ 'gedit-replace-dialog.h',
+ 'gedit-settings.h',
+ 'gedit-status-menu-button.h',
+ 'gedit-tab-label.h',
++ 'gedit-tab-private.h',
++ 'gedit-view-centering.h',
+ 'gedit-view-frame.h',
+ 'gedit-window-private.h',
+ ]
+
+ libgedit_private_sources = [
+ 'gedit-close-confirmation-dialog.c',
+ 'gedit-commands-documents.c',
+ 'gedit-commands-edit.c',
+ 'gedit-commands-file-print.c',
+ 'gedit-commands-help.c',
+ 'gedit-commands-search.c',
+ 'gedit-commands-view.c',
+ 'gedit-dirs.c',
+ 'gedit-documents-panel.c',
+ 'gedit-encoding-items.c',
+ 'gedit-encodings-dialog.c',
+- 'gedit-factory.c',
+ 'gedit-file-chooser.c',
+ 'gedit-file-chooser-dialog.c',
+ 'gedit-file-chooser-dialog-gtk.c',
+ 'gedit-file-chooser-open.c',
+ 'gedit-file-chooser-open-dialog.c',
+ 'gedit-file-chooser-open-native.c',
++ 'gedit-highlight-mode-dialog.c',
++ 'gedit-highlight-mode-selector.c',
+ 'gedit-history-entry.c',
+ 'gedit-io-error-info-bar.c',
+ 'gedit-menu-stack-switcher.c',
++ 'gedit-metadata-manager.c',
+ 'gedit-multi-notebook.c',
+ 'gedit-notebook.c',
+ 'gedit-notebook-popup-menu.c',
+ 'gedit-notebook-stack-switcher.c',
++ 'gedit-open-document-selector.c',
++ 'gedit-open-document-selector-helper.c',
++ 'gedit-open-document-selector-store.c',
++ 'gedit-pango.c',
+ 'gedit-plugins-engine.c',
+ 'gedit-preferences-dialog.c',
+ 'gedit-print-job.c',
+ 'gedit-print-preview.c',
+ 'gedit-recent.c',
+ 'gedit-replace-dialog.c',
+ 'gedit-settings.c',
+ 'gedit-status-menu-button.c',
+ 'gedit-tab-label.c',
+ 'gedit-view-frame.c',
+ ]
+
+ libgedit_c_args = []
+ libgedit_link_args = []
+
+ libgedit_deps = [
+ deps_basic_list,
+ libgd_dep,
++ libxml_dep,
+ ]
+
+ if host_machine.system() == 'darwin'
+ libgedit_private_sources += [
+ 'gedit-app-osx.m',
+ 'gedit-recent-osx.c',
+ ]
+ libgedit_c_args += [
+ '-DOS_OSX=1',
+ ]
+ libgedit_link_args += [
+ '-Wl,-framework', '-Wl,Foundation',
+ '-Wl,-framework', '-Wl,AppKit',
+ ]
+ libgedit_deps += [
+ dependency('gtk-mac-integration-gtk3'),
+ ]
+ elif host_machine.system() == 'windows'
+ libgedit_private_sources += [
+ 'gedit-app-win32.c',
+ ]
+ endif
+
+ headers_install_dir = get_option('includedir') / 'gedit-@0@/gedit/'.format(api_version)
+ install_headers(
+ libgedit_public_headers,
+ install_dir: headers_install_dir,
+ )
+
+ libgedit_public_enum_types = gnome.mkenums_simple(
+diff --git a/gedit/resources/css/gedit-style.css b/gedit/resources/css/gedit-style.css
+index eb43a8233..7036567c4 100644
+--- a/gedit/resources/css/gedit-style.css
++++ b/gedit/resources/css/gedit-style.css
+@@ -1,31 +1,43 @@
+ .gedit-side-panel-paned.pane-separator:dir(ltr),
+ .gedit-side-panel-paned.pane-separator:hover:dir(ltr) {
+ border-radius: 0;
+ border-width: 0 1px 0 0;
+ }
+
+ .gedit-side-panel-paned.pane-separator:dir(rtl),
+ .gedit-side-panel-paned.pane-separator:hover:dir(rtl) {
+ border-radius: 0;
+ border-width: 0 0 0 1px;
+ }
+
+ .gedit-menu-stack-switcher {
+ padding: 12px;
+ }
+
++.gedit-map-frame:dir(ltr) border {
++ border-width: 0 0 0 1px;
++}
++
++.gedit-map-frame:dir(rtl) border {
++ border-width: 0 1px 0 0;
++}
++
++.open-document-selector-treeview {
++ padding: 3px 6px 3px 6px;
++}
++
+ statusbar frame {
+ border: none;
+ padding-left: 6px;
+ padding-right: 6px;
+ }
+
+ statusbar button.flat {
+ border-radius: 0;
+ border-bottom: none;
+ }
+
+ GeditFileBrowserWidget .small-button {
+ padding: 2px 4px;
+ }
+
+diff --git a/gedit/resources/css/gedit.adwaita.css b/gedit/resources/css/gedit.adwaita.css
+index 784e72aa2..8377c62a9 100644
+--- a/gedit/resources/css/gedit.adwaita.css
++++ b/gedit/resources/css/gedit.adwaita.css
+@@ -1,30 +1,55 @@
++.open-document-selector-treeview:hover {
++ background-color: alpha(@theme_fg_color, 0.05);
++}
++
++.open-document-selector-treeview:selected:hover {
++ background-color: @theme_selected_bg_color;
++}
++
++/* Only normal state is handle */
++.open-document-selector-name-label {
++ color: @theme_fg_color;
++}
++
++/* Only normal state is handle */
++.open-document-selector-path-label {
++ color: @theme_unfocused_fg_color;
++ font-size: smaller;
++}
++
++/* Only normal state is handle */
++.open-document-selector-match {
++ color: shade (@theme_fg_color, 0.6);
++ background-color: alpha(@warning_color, 0.4);
++}
++
+ .gedit-document-panel {
+ background-color: @sidebar_bg;
+ }
+
+ .gedit-document-panel:backdrop {
+ color: #b0b2b2;
+ }
+
+ .gedit-document-panel row:selected:backdrop {
+ background-color: #8b8e8f;
+ }
+
+ .gedit-document-panel-group-row,
+ .gedit-document-panel-group-row:hover {
+ border-top: 1px solid alpha(currentColor, 0.3);
+ }
+
+ .gedit-document-panel-group-row:first-child,
+ .gedit-document-panel-group-row:first-child:hover {
+ border-top: 0px;
+ }
+
+ /* Try to look as the notebook tab close button */
+ .gedit-document-panel row button.flat {
+ padding: 0;
+ margin-top: 8px;
+ margin-bottom: 8px;
+ min-width: 18px;
+ min-height: 18px;
+ color: alpha(currentColor,0.3);
+diff --git a/gedit/resources/gedit.gresource.xml.in b/gedit/resources/gedit.gresource.xml.in
+index a5905110e..b0a70c185 100644
+--- a/gedit/resources/gedit.gresource.xml.in
++++ b/gedit/resources/gedit.gresource.xml.in
+@@ -1,23 +1,27 @@
+
+
+
+ gtk/menus.ui
+ gtk/menus-common.ui
+ ui/gedit-encodings-dialog.ui
+ ui/gedit-preferences-dialog.ui
+ ui/gedit-replace-dialog.ui
+ ui/gedit-print-preview.ui
+ ui/gedit-print-preferences.ui
++ ui/gedit-progress-info-bar.ui
+ ui/gedit-status-menu-button.ui
+ ui/gedit-tab-label.ui
+ ui/gedit-view-frame.ui
++ ui/gedit-highlight-mode-dialog.ui
++ ui/gedit-highlight-mode-selector.ui
+ ui/gedit-window.ui
++ ui/gedit-open-document-selector.ui
+ ui/gedit-shortcuts.ui
+ ui/gedit-statusbar.ui
+ css/gedit-style.css
+ css/gedit.adwaita.css
+ css/gedit.highcontrast.css
+
+ @OS_DEPENDENT_RESOURCE_FILES@
+
+
+diff --git a/gedit/resources/ui/gedit-highlight-mode-dialog.ui b/gedit/resources/ui/gedit-highlight-mode-dialog.ui
+new file mode 100644
+index 000000000..31b8690bd
+--- /dev/null
++++ b/gedit/resources/ui/gedit-highlight-mode-dialog.ui
+@@ -0,0 +1,87 @@
++
++
++
++
++ 300
++ 400
++ False
++ False
++ False
++ 5
++ Highlight Mode
++ dialog
++ True
++
++
++
++
++ cancel_button
++ ok_button
++
++
++
+diff --git a/gedit/resources/ui/gedit-highlight-mode-selector.ui b/gedit/resources/ui/gedit-highlight-mode-selector.ui
+new file mode 100644
+index 000000000..1aa5c950e
+--- /dev/null
++++ b/gedit/resources/ui/gedit-highlight-mode-selector.ui
+@@ -0,0 +1,83 @@
++
++
++
++
++
++
++
++
++
++
++
++
++ liststore
++
++
++ 300
++ 400
++ True
++ False
++ False
++ False
++ 3
++ 6
++
++
++ True
++ True
++ True
++ False
++ True
++ Search highlight mode…
++
++
++ 0
++ 0
++ 1
++ 1
++
++
++
++
++ True
++ True
++ False
++ False
++ True
++ True
++ in
++
++
++ True
++ True
++ False
++ False
++ treemodelfilter
++ False
++ False
++ False
++
++
++
++
++
++
++
++
++ 0
++
++
++
++
++
++
++
++
++ 0
++ 1
++ 1
++ 1
++
++
++
++
+diff --git a/gedit/resources/ui/gedit-open-document-selector.ui b/gedit/resources/ui/gedit-open-document-selector.ui
+new file mode 100644
+index 000000000..9393ac46c
+--- /dev/null
++++ b/gedit/resources/ui/gedit-open-document-selector.ui
+@@ -0,0 +1,115 @@
++
++
++
++
++ True
++ False
++ 9
++ vertical
++ 6
++
++
++ True
++ True
++ edit-find-symbolic
++ False
++ False
++
++
++ False
++ False
++ 0
++
++
++
++
++ False
++ False
++ True
++ True
++ in
++
++
++ True
++ vertical
++ center
++ center
++
++
++ True
++ edit-find-symbolic
++ 64
++ False
++
++
++
++
++
++ True
++ False
++ False
++ No results
++
++
++
++
++
++
++
++ True
++ True
++ 1
++
++
++
++
++ True
++ True
++ True
++ never
++ in
++
++
++ True
++ True
++ True
++ True
++ False
++ True
++ horizontal
++ False
++ True
++
++
++
++
++ True
++ True
++ 2
++
++
++
++
++ Other _Documents…
++ True
++ True
++ True
++ Open another file
++ 6
++ win.open
++
++
++
++ False
++ True
++ 3
++
++
++
++
+diff --git a/gedit/resources/ui/gedit-preferences-dialog.ui b/gedit/resources/ui/gedit-preferences-dialog.ui
+index f1eeed45c..1ce0755da 100644
+--- a/gedit/resources/ui/gedit-preferences-dialog.ui
++++ b/gedit/resources/ui/gedit-preferences-dialog.ui
+@@ -78,72 +78,87 @@
+ 1
+ True
+ True
+
+
+ 0
+ 0
+
+
+
+
+ 1
+ 1
+
+
+
+
+ Display _statusbar
+ True
+ True
+ False
+ True
+ True
+
+
+ 0
+ 2
+ 2
+
+
++
++
++ Display _overview map
++ True
++ True
++ False
++ True
++ True
++
++
++ 0
++ 3
++ 2
++
++
+
+
+ Display _grid pattern
+ True
+ True
+ False
+ True
+ True
+
+
+ 0
+- 3
++ 4
+ 2
+
+
+
+
+ 0
+ 0
+
+
+
+
+ True
+ False
+ 6
+
+
+ True
+ False
+ 0
+ Text Wrapping
+
+
+
+
+
+ 0
+ 0
+
+
+
+@@ -603,62 +618,73 @@
+
+
+
+ True
+ False
+ True
+ True
+ 6
+
+
+ True
+ False
+ 0
+ Color Scheme
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ True
+ False
+ True
+ True
+
+-
++
+ True
++ True
++ True
++ True
++ etched-in
++ 200
++
++
++ True
++ True
++
++
+
+
+ 0
+ 0
+
+
+
+
+ True
+ False
+ icons
+ 1
+
+
+ True
+ False
+ True
+ Install scheme
+ Install scheme
+ Install Scheme
+ True
+ list-add-symbolic
+
+
+ False
+ True
+
+
+
+
+diff --git a/gedit/resources/ui/gedit-progress-info-bar.ui b/gedit/resources/ui/gedit-progress-info-bar.ui
+new file mode 100644
+index 000000000..3f733e4b6
+--- /dev/null
++++ b/gedit/resources/ui/gedit-progress-info-bar.ui
+@@ -0,0 +1,88 @@
++
++
++
++
++ True
++ False
++ other
++
++
++ False
++ vertical
++ 6
++
++
++ True
++ False
++ 4
++
++
++ True
++ False
++ 2
++ image-missing
++
++
++ False
++ True
++ 4
++ 0
++
++
++
++
++ True
++ False
++ start
++ label
++ True
++ end
++
++
++ False
++ True
++ 1
++
++
++
++
++ False
++ True
++ 0
++
++
++
++
++ 15
++ True
++ False
++ True
++
++
++ False
++ True
++ 1
++
++
++
++
++ True
++ True
++ 0
++
++
++
++
++ False
++
++
++
++
++
++ False
++ True
++ 1
++
++
++
++
+diff --git a/gedit/resources/ui/gedit-view-frame.ui b/gedit/resources/ui/gedit-view-frame.ui
+index 4c783c711..779802db3 100644
+--- a/gedit/resources/ui/gedit-view-frame.ui
++++ b/gedit/resources/ui/gedit-view-frame.ui
+@@ -1,47 +1,68 @@
+
+
+
+
+ True
+ False
+ False
+ False
+
+-
++
+ True
+ True
+ True
+
+-
++
+ True
+- True
++ True
++ True
++
++
++ True
++ True
++
++
++
++
++
++
++ True
++
++
++
++ True
++ view
++
++
+
+
+
+
+
+
+ True
+ False
+ end
+ start
+
+
+ True
+ False
+ none
+
+
+
+ True
+ False
+ horizontal
+
+
+
+ True
+ True
+diff --git a/gedit/resources/ui/gedit-window.ui b/gedit/resources/ui/gedit-window.ui
+index 0d131ad69..b6283dcf4 100644
+--- a/gedit/resources/ui/gedit-window.ui
++++ b/gedit/resources/ui/gedit-window.ui
+@@ -1,59 +1,103 @@
+
+
+
+
+ False
+ False
+ False
+
+
+
+ True
+
+
+
+
+ True
+ Documents
+
+
+ False
+ False
+
+
+
+
+ True
+ True
++
++
++ True
++ Open a file
++ center
++ True
++
++
++
++ True
++ False
++ False
++ False
++
++
++ _Open
++ True
++ True
++ baseline
++
++
++
++
++ True
++ baseline
++ pan-down-symbolic
++
++
++
++
++
++
++ Open
++ Open a file
++
++
++
++
++ start
++
++
+
+
+ True
+ True
+ True
+ False
+ Create a new document
+ win.new-tab
+ new_tab_image
+
+
+ New
+ Create a new document
+
+
+
+
+
+
+ True
+ True
+ menu_image
+
+
+ end
+
+
+
+
+ _Save
+@@ -283,68 +327,109 @@
+
+
+
+
+ False
+ True
+ 1
+
+
+
+
+ True
+ True
+
+
+
+
+ True
+ True
+ 1
+
+
+
+
+
+
+ True
+ False
+ start
+
+-
++
+ True
+ False
+ False
+ start
+
+
+ True
++
++
++ True
++ Open a file dialog
++ center
++ True
++
++
++
++ True
++ False
++ False
++ False
++
++
++ Open
++ True
++
++
++
++
++ True
++ pan-down-symbolic
++
++
++
++
++
++
++ Open
++ Open a file
++
++
++
++
++ start
++
++
+
+
+ True
+ True
+ True
+ False
+ Create a new document
+ win.new-tab
+ fullscreen_new_tab_image
+
+
+ New
+ Create a new document
+
+
+
+
+
+
+ True
+ Leave Fullscreen
+ win.leave-fullscreen
+ leave_fullscreen_image
+
+
+ Leave Fullscreen
+ Leave Fullscreen
+
+
+
+diff --git a/help/C/gedit-tab-groups.page b/help/C/gedit-tab-groups.page
+index a25fcb6e0..d7ed84e8b 100644
+--- a/help/C/gedit-tab-groups.page
++++ b/help/C/gedit-tab-groups.page
+@@ -1,58 +1,58 @@
+
+
+
+
+
+
+ Group similar tabs together.
+
+
+
+ Radina Matic
+ radina.matic@gmail.com
+ 2013
+
+
+
+
+
+ Organize files in grouped tabs
+
+
If you are working with multiple tabs in gedit you can group
+ them, making it easier to keep your opened files organized. Adding a new tab
+ group will divide the gedit window in two panes, open a new
+- “Untitled File” in the new pane, and make it active. You can open files into
+- that tab group and move tabs from one tab group to another.
++ “Untitled Document” in the new pane, and make it active. You can open files
++ into that tab group and move tabs from one tab group to another.
+
+
+ Open a new tab group in the gedit window
+
+
To open a new tab group you can:
+
+
+
+
Right click on a tab and select Move to New Tab Group.
+
+
+
Use the CtrlAltN
+ shortcut.
+
+
+
+
This action will divide the gedit window in two panes, and the
+ pane with the new tab group will be placed on the right of the active tab.
+ You can move the handle right or left assigning more or less space of the
+ gedit window between panes according to your needs.
+
+
You can open as much tab groups in a gedit window as your screen
+ allows, but you will have to move the handle in order to see them
+ correctly.
+
+
To close a tab group pane just close all the tabs that are opened inside
+ it.