diff -Nru gedit-40.1/build-aux/flatpak/org.gnome.gedit.yml gedit-41.0/build-aux/flatpak/org.gnome.gedit.yml --- gedit-40.1/build-aux/flatpak/org.gnome.gedit.yml 2021-04-17 05:45:33.348500000 +0000 +++ gedit-41.0/build-aux/flatpak/org.gnome.gedit.yml 2022-02-14 13:58:26.000000000 +0000 @@ -59,17 +59,12 @@ url: https://download.gnome.org/sources/gspell/1.9/gspell-1.9.1.tar.xz sha256: dcbb769dfdde8e3c0a8ed3102ce7e661abbf7ddf85df08b29915e92cd723abdd - - name: amtk - buildsystem: meson - sources: - - type: git - url: https://gitlab.gnome.org/GNOME/amtk.git - - - name: tepl - buildsystem: meson + - name: uchardet + buildsystem: cmake-ninja 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 diff -Nru gedit-40.1/build-aux/snap/snapcraft.yaml gedit-41.0/build-aux/snap/snapcraft.yaml --- gedit-40.1/build-aux/snap/snapcraft.yaml 2021-04-17 05:45:35.024535200 +0000 +++ gedit-41.0/build-aux/snap/snapcraft.yaml 2022-02-14 13:58:26.000000000 +0000 @@ -41,33 +41,10 @@ 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 + source-branch: gtksourceview-4-8 plugin: meson meson-parameters: - --prefix=/usr @@ -94,7 +71,7 @@ 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] @@ -102,6 +79,7 @@ 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: | diff -Nru gedit-40.1/data/gedit.1 gedit-41.0/data/gedit.1 --- gedit-40.1/data/gedit.1 2021-04-17 05:45:35.024535200 +0000 +++ gedit-41.0/data/gedit.1 2022-02-14 13:58:26.000000000 +0000 @@ -76,11 +76,11 @@ .B gedit will read from stdin .TP \fB+LINE\fR -For the first file, go to the line specified by LINE (do not insert a space between the "+" sign and the number). +For all the files specified on command line, go to the line specified by LINE (do not insert a space between the "+" sign and the number). If LINE is missing, go to the last line. .TP \fBCOLUMN\fR -For the first file, go to the column specified by COLUMN. +For all the files specified on command line, go to the column specified by COLUMN. If COLUMN is missing, go to the first column. .SH BUGS diff -Nru gedit-40.1/data/meson.build gedit-41.0/data/meson.build --- gedit-40.1/data/meson.build 2021-04-17 05:45:35.136537600 +0000 +++ gedit-41.0/data/meson.build 2022-02-14 13:58:26.000000000 +0000 @@ -4,7 +4,6 @@ appdata = 'org.gnome.gedit.appdata.xml' appdata_file = i18n.merge_file( - appdata, input: appdata + '.in', output: appdata, po_dir: '../po/', @@ -23,7 +22,6 @@ desktop_file = 'org.gnome.gedit.desktop' desktop_output_file = i18n.merge_file( - desktop_file, type: 'desktop', input: desktop_file + '.in', output: desktop_file, @@ -45,6 +43,7 @@ 'docinfo', 'filebrowser', 'modelines', + 'openlinks', 'sort', 'spell', ] diff -Nru gedit-40.1/data/org.gnome.gedit.appdata.xml.in gedit-41.0/data/org.gnome.gedit.appdata.xml.in --- gedit-40.1/data/org.gnome.gedit.appdata.xml.in 2021-04-17 05:45:35.400543200 +0000 +++ gedit-41.0/data/org.gnome.gedit.appdata.xml.in 2022-02-14 13:58:26.000000000 +0000 @@ -28,7 +28,7 @@ https://wiki.gnome.org/Apps/Gedit https://gitlab.gnome.org/GNOME/gedit/issues - https://liberapay.com/gedit/ + https://www.gnome.org/donate/ https://help.gnome.org/users/gedit/stable/ https://wiki.gnome.org/TranslationProject jmas@softcatala.org @@ -36,6 +36,7 @@ gedit + diff -Nru gedit-40.1/data/org.gnome.gedit.gschema.xml.in gedit-41.0/data/org.gnome.gedit.gschema.xml.in --- gedit-40.1/data/org.gnome.gedit.gschema.xml.in 2021-04-17 05:45:35.400543200 +0000 +++ gedit-41.0/data/org.gnome.gedit.gschema.xml.in 2022-02-14 13:58:26.000000000 +0000 @@ -126,6 +126,11 @@ 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 diff -Nru gedit-40.1/debian/changelog gedit-41.0/debian/changelog --- gedit-40.1/debian/changelog 2021-11-22 10:19:49.000000000 +0000 +++ gedit-41.0/debian/changelog 2022-03-02 12:34:07.000000000 +0000 @@ -1,3 +1,24 @@ +gedit (41.0-3) unstable; urgency=medium + + * debian/patches/gitlab_openlinks_fix.patch: + - don't try to convert an array of gunicode to a gchar, fix the build + fixed on s390x + + -- Sebastien Bacher Wed, 02 Mar 2022 13:34:07 +0100 + +gedit (41.0-2) unstable; urgency=medium + + * Restore fix_ftbfs_nonlinux.patch: accidentally left out of 41.0 release + + -- Jeremy Bicha Mon, 14 Feb 2022 12:29:08 -0500 + +gedit (41.0-1) unstable; urgency=medium + + * New upstream release + * Drop all patches except our Debian multiarch patch: applied in new release + + -- Jeremy Bicha Mon, 14 Feb 2022 09:28:53 -0500 + gedit (40.1-3) unstable; urgency=medium * d/control.in: Add libglib2.0-dev and libgtk-3-dev dependencies to gedit-dev diff -Nru gedit-40.1/debian/patches/08_multiarch_fallback.patch gedit-41.0/debian/patches/08_multiarch_fallback.patch --- gedit-40.1/debian/patches/08_multiarch_fallback.patch 2021-11-22 10:19:49.000000000 +0000 +++ gedit-41.0/debian/patches/08_multiarch_fallback.patch 2022-03-02 12:34:07.000000000 +0000 @@ -9,9 +9,11 @@ gedit/gedit-plugins-engine.c | 5 +++++ 3 files changed, 18 insertions(+) +diff --git a/gedit/gedit-dirs.c b/gedit/gedit-dirs.c +index 81f32c2..964e0a8 100644 --- a/gedit/gedit-dirs.c +++ b/gedit/gedit-dirs.c -@@ -33,6 +33,7 @@ static gchar *user_plugins_dir = N +@@ -33,6 +33,7 @@ static gchar *user_plugins_dir = NULL; static gchar *gedit_locale_dir = NULL; static gchar *gedit_lib_dir = NULL; static gchar *gedit_plugins_dir = NULL; @@ -37,22 +39,24 @@ g_clear_pointer (&gedit_plugins_data_dir, g_free); } -@@ -168,6 +173,12 @@ gedit_dirs_get_gedit_plugins_dir (void) +@@ -167,6 +172,12 @@ gedit_dirs_get_gedit_plugins_dir (void) + return gedit_plugins_dir; } - const gchar * ++const gchar * +gedit_dirs_get_gedit_fallback_plugins_dir (void) +{ + return gedit_fallback_plugins_dir; +} + -+const gchar * + const gchar * gedit_dirs_get_gedit_plugins_data_dir (void) { - return gedit_plugins_data_dir; +diff --git a/gedit/gedit-dirs.h b/gedit/gedit-dirs.h +index 3fc7ab5..7f0126c 100644 --- a/gedit/gedit-dirs.h +++ b/gedit/gedit-dirs.h -@@ -46,6 +46,8 @@ const gchar *gedit_dirs_get_gedit_lib_di +@@ -46,6 +46,8 @@ const gchar *gedit_dirs_get_gedit_lib_dir (void); const gchar *gedit_dirs_get_gedit_plugins_dir (void); @@ -61,9 +65,11 @@ const gchar *gedit_dirs_get_gedit_plugins_data_dir (void); G_END_DECLS +diff --git a/gedit/gedit-plugins-engine.c b/gedit/gedit-plugins-engine.c +index 28e6096..f47f369 100644 --- a/gedit/gedit-plugins-engine.c +++ b/gedit/gedit-plugins-engine.c -@@ -93,6 +93,11 @@ gedit_plugins_engine_init (GeditPluginsE +@@ -93,6 +93,11 @@ gedit_plugins_engine_init (GeditPluginsEngine *engine) gedit_dirs_get_gedit_plugins_dir (), gedit_dirs_get_gedit_plugins_data_dir ()); diff -Nru gedit-40.1/debian/patches/fix_ftbfs_nonlinux.patch gedit-41.0/debian/patches/fix_ftbfs_nonlinux.patch --- gedit-40.1/debian/patches/fix_ftbfs_nonlinux.patch 2021-11-22 10:19:49.000000000 +0000 +++ gedit-41.0/debian/patches/fix_ftbfs_nonlinux.patch 2022-03-02 12:34:07.000000000 +0000 @@ -1,13 +1,74 @@ -Index: gedit-40.1/meson.build -=================================================================== ---- gedit-40.1.orig/meson.build -+++ gedit-40.1/meson.build -@@ -75,7 +75,7 @@ config_h.set_quoted('DATADIR', join_path - config_h.set_quoted('VERSION', meson.project_version()) - - enable_gvfs_metadata = get_option('enable-gvfs-metadata') --if enable_gvfs_metadata == 'yes' or (enable_gvfs_metadata == 'auto' and host_machine.system() == 'linux') -+if enable_gvfs_metadata == 'yes' or (enable_gvfs_metadata == 'auto' and ['linux', 'gnu', 'gnu/kfreebsd'].contains(host_machine.system())) - enable_gvfs_metadata = true - else - enable_gvfs_metadata = false +From: Laurent Bigonville +Date: Mon, 22 Nov 2021 13:03:48 +0100 +Subject: Revert "gedit-dirs: remove get_user_cache_dir() (no longer used)" + +This also revert the move of the metadata file ("gedit-metadata.xml") +from user_data_dir to user_cache_dir when not using GVFS to store the +metadata + +This reverts commit f641a246fbaff482e216197d21e2e51397b1cb26. + +Fixes: https://gitlab.gnome.org/GNOME/gedit/-/issues/467 +(cherry picked from commit ba2662ff9ee99ef0d85023b06053792fd3eb9272) +(cherry picked from commit 741be1b11b977abd529aa2f633e50c2e80864afc) +--- + gedit/gedit-dirs.c | 11 +++++++++++ + gedit/gedit-dirs.h | 2 ++ + 2 files changed, 13 insertions(+) + +diff --git a/gedit/gedit-dirs.c b/gedit/gedit-dirs.c +index 964e0a8..91a4ce4 100644 +--- a/gedit/gedit-dirs.c ++++ b/gedit/gedit-dirs.c +@@ -26,6 +26,7 @@ + #include + #endif + ++static gchar *user_cache_dir = NULL; + static gchar *user_config_dir = NULL; + static gchar *user_data_dir = NULL; + static gchar *user_styles_dir = NULL; +@@ -96,6 +97,9 @@ gedit_dirs_init () + NULL); + } + ++ user_cache_dir = g_build_filename (g_get_user_cache_dir (), ++ "gedit", ++ NULL); + user_config_dir = g_build_filename (g_get_user_config_dir (), + "gedit", + NULL); +@@ -119,6 +123,7 @@ gedit_dirs_init () + void + gedit_dirs_shutdown () + { ++ g_clear_pointer (&user_cache_dir, g_free); + g_clear_pointer (&user_config_dir, g_free); + g_clear_pointer (&user_data_dir, g_free); + g_clear_pointer (&user_styles_dir, g_free); +@@ -130,6 +135,12 @@ gedit_dirs_shutdown () + g_clear_pointer (&gedit_plugins_data_dir, g_free); + } + ++const gchar * ++gedit_dirs_get_user_cache_dir (void) ++{ ++ return user_cache_dir; ++} ++ + const gchar * + gedit_dirs_get_user_config_dir (void) + { +diff --git a/gedit/gedit-dirs.h b/gedit/gedit-dirs.h +index 7f0126c..acd2424 100644 +--- a/gedit/gedit-dirs.h ++++ b/gedit/gedit-dirs.h +@@ -32,6 +32,8 @@ void gedit_dirs_init (void); + void gedit_dirs_shutdown (void); + + ++const gchar *gedit_dirs_get_user_cache_dir (void); ++ + const gchar *gedit_dirs_get_user_config_dir (void); + + const gchar *gedit_dirs_get_user_data_dir (void); diff -Nru gedit-40.1/debian/patches/gitlab_openlinks_fix.patch gedit-41.0/debian/patches/gitlab_openlinks_fix.patch --- gedit-40.1/debian/patches/gitlab_openlinks_fix.patch 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/debian/patches/gitlab_openlinks_fix.patch 2022-03-02 12:34:07.000000000 +0000 @@ -0,0 +1,52 @@ +From a51cafc7de9187150e56299866ea4452a8f38c5e Mon Sep 17 00:00:00 2001 +From: Sebastien Bacher +Date: Wed, 2 Mar 2022 12:02:24 +0100 +Subject: [PATCH] Fix the openlinks test by properly converting gunicode to + gchar + +--- + plugins/openlinks/gedit-open-links-plugin.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/plugins/openlinks/gedit-open-links-plugin.c b/plugins/openlinks/gedit-open-links-plugin.c +index 9d7562881..5193511a4 100644 +--- a/plugins/openlinks/gedit-open-links-plugin.c ++++ b/plugins/openlinks/gedit-open-links-plugin.c +@@ -85,8 +85,8 @@ gedit_open_links_plugin_get_uri (GtkTextIter *start, + GString **uri) + { + GtkTextIter *end; +- gunichar uri_test[2]; +- uri_test[1] = '\0'; ++ gchar uri_test[6]; ++ gint len; + + end = g_malloc (sizeof (GtkTextIter)); + memcpy (end, start, sizeof (GtkTextIter)); +@@ -95,8 +95,9 @@ gedit_open_links_plugin_get_uri (GtkTextIter *start, + gtk_text_iter_backward_char (end); + while (gtk_text_iter_forward_char (end)) + { +- uri_test[0] = gtk_text_iter_get_char (end); +- if (!g_regex_match (uri_char_regex, (const gchar *) &uri_test, 0, NULL)) ++ len = g_unichar_to_utf8 (gtk_text_iter_get_char (end), uri_test); ++ uri_test[len] = '\0'; ++ if (!g_regex_match (uri_char_regex, uri_test, 0, NULL)) + { + break; + } +@@ -104,8 +105,9 @@ gedit_open_links_plugin_get_uri (GtkTextIter *start, + + while (gtk_text_iter_backward_char (start)) + { +- uri_test[0] = gtk_text_iter_get_char (start); +- if (!g_regex_match (uri_char_regex, (const gchar *) &uri_test, 0, NULL)) ++ len = g_unichar_to_utf8 (gtk_text_iter_get_char (start), uri_test); ++ uri_test[len] = '\0'; ++ if (!g_regex_match (uri_char_regex, uri_test, 0, NULL)) + { + gtk_text_iter_forward_char (start); + break; +-- +2.32.0 + diff -Nru gedit-40.1/debian/patches/series gedit-41.0/debian/patches/series --- gedit-40.1/debian/patches/series 2021-11-22 10:19:49.000000000 +0000 +++ gedit-41.0/debian/patches/series 2022-03-02 12:34:07.000000000 +0000 @@ -1,3 +1,3 @@ 08_multiarch_fallback.patch -upstream-fa587e0-deteplification.patch fix_ftbfs_nonlinux.patch +gitlab_openlinks_fix.patch diff -Nru gedit-40.1/debian/patches/upstream-fa587e0-deteplification.patch gedit-41.0/debian/patches/upstream-fa587e0-deteplification.patch --- gedit-40.1/debian/patches/upstream-fa587e0-deteplification.patch 2021-11-22 10:19:49.000000000 +0000 +++ gedit-41.0/debian/patches/upstream-fa587e0-deteplification.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,12537 +0,0 @@ -From fa587e033c97fac65dacdb3c9520635beca68fbc 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 | 30 +- - 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(+), 1286 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,3 +1,15 @@ -+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.1, 2021-04-17 - ------------------------ - * Use document folder when opening new files -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 -@@ -59,17 +59,12 @@ modules: - 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 -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 -@@ -41,30 +41,6 @@ apps: - 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 -@@ -94,7 +70,7 @@ parts: - 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] -@@ -102,6 +78,7 @@ parts: - 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: | -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 -@@ -126,6 +126,11 @@ - 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 -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 -@@ -31,11 +31,9 @@ editor. To learn that widget API, read the excellent - 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. -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 -@@ -21,6 +21,56 @@ - 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 - -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 -@@ -16,6 +16,7 @@ - - - -+ - - - -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 -@@ -54,7 +54,10 @@ 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 -@@ -148,6 +151,26 @@ 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 -@@ -199,6 +222,13 @@ 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 -@@ -291,6 +321,7 @@ DEBUG_DOCUMENT - DEBUG_COMMANDS - DEBUG_APP - DEBUG_UTILS -+DEBUG_METADATA - gedit_debug_init - gedit_debug - gedit_debug_message -@@ -321,9 +352,14 @@ 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 -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 -@@ -6,14 +6,12 @@ gio_docpath = dependency('gio-2.0').get_pkgconfig_variable('prefix') / 'share/gt - 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( -@@ -30,8 +28,6 @@ gnome.gtkdoc( - '--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: [ -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 -@@ -4,27 +4,10 @@ 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 - ------------------------ - -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 -@@ -6,6 +6,7 @@ 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" -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 -@@ -31,7 +31,7 @@ - #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); -@@ -286,7 +286,7 @@ gedit_app_osx_set_window_title_impl (GeditApp *app, - g_free (uri); - } - -- ismodified = !tepl_buffer_is_untouched (TEPL_BUFFER (document)); -+ ismodified = !gedit_document_is_untouched (document); - [native setDocumentEdited:ismodified]; - } - else -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 -@@ -22,6 +22,7 @@ - #define GEDIT_APP_PRIVATE_H - - #include "gedit-app.h" -+#include "gedit-metadata-manager.h" - #include "gedit-menu-extension.h" - - G_BEGIN_DECLS -@@ -34,6 +35,8 @@ 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); -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 -@@ -28,8 +28,9 @@ - #include - - #include -+#include - #include --#include -+#include - - #include "gedit-commands-private.h" - #include "gedit-notebook.h" -@@ -44,6 +45,10 @@ - #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" - -@@ -51,6 +56,10 @@ typedef struct - { - GeditPluginsEngine *engine; - -+#ifndef ENABLE_GVFS_METADATA -+ GeditMetadataManager *metadata_manager; -+#endif -+ - GtkCssProvider *theme_provider; - - GtkPageSetup *page_setup; -@@ -145,6 +154,10 @@ gedit_app_dispose (GObject *object) - - 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); - -@@ -643,6 +656,10 @@ 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)); - -@@ -654,6 +671,13 @@ gedit_app_startup (GApplication *application) - - 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"); -@@ -1114,6 +1138,10 @@ gedit_app_shutdown (GApplication *app) - 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); - } - -@@ -1253,15 +1281,10 @@ load_print_settings (GeditApp *app) - 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); - } - - /** -@@ -1571,6 +1594,25 @@ _gedit_app_set_default_print_settings (GeditApp *app, - 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) - { -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 -@@ -44,13 +44,13 @@ _gedit_cmd_edit_undo (GSimpleAction *action, - 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)); - } -@@ -67,13 +67,13 @@ _gedit_cmd_edit_redo (GSimpleAction *action, - 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)); - } -@@ -89,9 +89,9 @@ _gedit_cmd_edit_cut (GSimpleAction *action, - 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)); - } -@@ -107,9 +107,9 @@ _gedit_cmd_edit_copy (GSimpleAction *action, - 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)); - } -@@ -125,9 +125,9 @@ _gedit_cmd_edit_paste (GSimpleAction *action, - 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)); - } -@@ -143,9 +143,9 @@ _gedit_cmd_edit_delete (GSimpleAction *action, - 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)); - } -@@ -161,9 +161,9 @@ _gedit_cmd_edit_select_all (GSimpleAction *action, - 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)); - } -diff --git a/gedit/gedit-commands-file.c b/gedit/gedit-commands-file.c -index 91798b95f..001899b0c 100644 ---- a/gedit/gedit-commands-file.c -+++ b/gedit/gedit-commands-file.c -@@ -27,7 +27,6 @@ - #include "gedit-commands-private.h" - - #include --#include - - #include "gedit-app.h" - #include "gedit-debug.h" -@@ -44,10 +43,6 @@ - #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" -@@ -150,24 +145,26 @@ load_file_list (GeditWindow *window, - { - 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)); - } - } - -@@ -194,7 +191,7 @@ load_file_list (GeditWindow *window, - - 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, -@@ -513,7 +510,7 @@ replace_read_only_file (GtkWindow *parent, - * 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, -@@ -565,7 +562,7 @@ change_compression (GtkWindow *parent, - * 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) -@@ -827,6 +824,7 @@ save_as_tab_async (GeditTab *tab, - /* 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")); - -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 -@@ -29,7 +29,6 @@ - #include - #include - #include --#include - - #include "gedit-debug.h" - #include "gedit-statusbar.h" -@@ -132,7 +131,7 @@ text_not_found (GeditWindow *window, - 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, -@@ -188,7 +187,7 @@ forward_search_finished (GtkSourceSearchContext *search_context, - &match_start, - &match_end); - -- tepl_view_scroll_to_cursor (TEPL_VIEW (view)); -+ gedit_view_scroll_to_cursor (view); - } - else - { -@@ -294,7 +293,7 @@ backward_search_finished (GtkSourceSearchContext *search_context, - &match_start, - &match_end); - -- tepl_view_scroll_to_cursor (TEPL_VIEW (view)); -+ gedit_view_scroll_to_cursor (view); - } - else - { -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 -@@ -21,11 +21,16 @@ - */ - - #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, -@@ -121,9 +126,9 @@ _gedit_cmd_view_leave_fullscreen_mode (GSimpleAction *action, - } - - static void --language_activated_cb (TeplLanguageChooserDialog *dialog, -- GtkSourceLanguage *language, -- GeditWindow *window) -+language_selected_cb (GeditHighlightModeSelector *selector, -+ GtkSourceLanguage *language, -+ GeditWindow *window) - { - GeditDocument *active_document; - -@@ -132,16 +137,6 @@ language_activated_cb (TeplLanguageChooserDialog *dialog, - { - 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 -@@ -150,10 +145,12 @@ _gedit_cmd_view_highlight_mode (GSimpleAction *action, - 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) -@@ -161,20 +158,15 @@ _gedit_cmd_view_highlight_mode (GSimpleAction *action, - 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)); - } - -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 -@@ -100,6 +100,10 @@ gedit_debug_init (void) - { - enabled_sections |= GEDIT_DEBUG_UTILS; - } -+ if (g_getenv ("GEDIT_DEBUG_METADATA") != NULL) -+ { -+ enabled_sections |= GEDIT_DEBUG_METADATA; -+ } - - out: - -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 -@@ -48,6 +48,7 @@ typedef enum { - 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 -@@ -60,6 +61,7 @@ typedef enum { - #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); - -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 -@@ -28,9 +28,15 @@ - - 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); -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 -@@ -5,7 +5,7 @@ - * 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 -@@ -22,13 +22,21 @@ - */ - - #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_" - -@@ -43,7 +51,11 @@ typedef struct - { - GtkSourceFile *file; - -- TeplMetadata *metadata; -+ GSettings *editor_settings; -+ -+ gint untitled_number; -+ -+ GFileInfo *metadata_info; - - gchar *content_type; - -@@ -54,7 +66,12 @@ typedef struct - */ - 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 -@@ -71,9 +88,11 @@ typedef struct - enum - { - PROP_0, -+ PROP_SHORTNAME, - PROP_CONTENT_TYPE, - PROP_MIME_TYPE, - PROP_EMPTY_SEARCH, -+ PROP_USE_GVFS_METADATA, - LAST_PROP - }; - -@@ -81,6 +100,7 @@ static GParamSpec *properties[LAST_PROP]; - - enum - { -+ CURSOR_MOVED, - LOAD, - LOADED, - SAVE, -@@ -90,40 +110,41 @@ enum - - 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 -@@ -195,16 +216,17 @@ gedit_document_dispose (GObject *object) - /* 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); - } -@@ -212,10 +234,17 @@ gedit_document_dispose (GObject *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) -@@ -239,6 +268,10 @@ gedit_document_get_property (GObject *object, - - 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; -@@ -251,6 +284,10 @@ gedit_document_get_property (GObject *object, - 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; -@@ -264,6 +301,7 @@ gedit_document_set_property (GObject *object, - GParamSpec *pspec) - { - GeditDocument *doc = GEDIT_DOCUMENT (object); -+ GeditDocumentPrivate *priv = gedit_document_get_instance_private (doc); - - switch (prop_id) - { -@@ -271,22 +309,97 @@ gedit_document_set_property (GObject *object, - 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", -@@ -299,6 +412,7 @@ 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; -@@ -306,9 +420,26 @@ gedit_document_class_init (GeditDocumentClass *klass) - 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: - * -@@ -348,8 +479,44 @@ gedit_document_class_init (GeditDocumentClass *klass) - 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. -@@ -632,20 +799,79 @@ 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; -@@ -653,13 +879,7 @@ gedit_document_init (GeditDocument *doc) - 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", -@@ -667,9 +887,6 @@ gedit_document_init (GeditDocument *doc) - 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); -@@ -699,7 +916,17 @@ gedit_document_init (GeditDocument *doc) - 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 * -@@ -814,17 +1041,19 @@ set_content_type (GeditDocument *doc, - 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 - { -@@ -841,12 +1070,24 @@ _gedit_document_get_uri_for_display (GeditDocument *doc) - 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 * -@@ -1032,15 +1273,31 @@ gedit_document_saved_real (GeditDocument *doc) - 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; - } - - /* -@@ -1072,6 +1329,51 @@ _gedit_document_needs_saving (GeditDocument *doc) - 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: -@@ -1130,6 +1432,64 @@ _gedit_document_get_seconds_since_last_save_or_load (GeditDocument *doc) - 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 -@@ -1150,12 +1510,12 @@ gedit_document_get_metadata (GeditDocument *doc, - - 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); - } - - /** -@@ -1173,30 +1533,84 @@ gedit_document_set_metadata (GeditDocument *doc, - ...) - { - 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 -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 -@@ -5,7 +5,7 @@ - * 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 -@@ -24,19 +24,20 @@ - #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); - -@@ -57,8 +58,17 @@ 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 -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 -@@ -23,7 +23,6 @@ - #include "gedit-documents-panel.h" - - #include --#include - - #include "gedit-debug.h" - #include "gedit-document.h" -@@ -447,7 +446,7 @@ doc_get_name (GeditDocument *doc) - 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); - -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 -@@ -192,6 +192,12 @@ chooser_show (GeditFileChooserDialog *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) - { -@@ -211,6 +217,26 @@ 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) -@@ -229,9 +255,11 @@ gedit_file_chooser_dialog_gtk_chooser_init (gpointer g_iface, - 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 -@@ -253,7 +281,8 @@ gedit_file_chooser_dialog_gtk_class_init (GeditFileChooserDialogGtkClass *klass) - } - - static void --create_option_menu (GeditFileChooserDialogGtk *dialog) -+create_option_menu (GeditFileChooserDialogGtk *dialog, -+ GeditFileChooserFlags flags) - { - GtkWidget *label; - GtkWidget *menu; -@@ -262,7 +291,7 @@ create_option_menu (GeditFileChooserDialogGtk *dialog) - 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); -@@ -374,13 +403,18 @@ create_newline_combo (GeditFileChooserDialogGtk *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); - } -@@ -421,21 +455,35 @@ 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", -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 -@@ -33,10 +33,11 @@ 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 - -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 -@@ -62,13 +62,15 @@ gedit_file_chooser_dialog_default_init (GeditFileChooserDialogInterface *iface) - } - - 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); - } -@@ -211,6 +213,19 @@ gedit_file_chooser_dialog_show (GeditFileChooserDialog *dialog) - 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) - { -@@ -255,4 +270,21 @@ gedit_file_chooser_dialog_get_window (GeditFileChooserDialog *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 -@@ -64,6 +64,7 @@ struct _GeditFileChooserDialogInterface - gboolean overwrite_confirmation); - - void (*show) (GeditFileChooserDialog *dialog); -+ void (*hide) (GeditFileChooserDialog *dialog); - - void (*destroy) (GeditFileChooserDialog *dialog); - -@@ -72,11 +73,22 @@ struct _GeditFileChooserDialogInterface - - 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); - -@@ -110,12 +122,17 @@ void gedit_file_chooser_dialog_set_do_overwrite_confirmation ( - 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 */ -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 77ca04d7b..21e27e459 100644 ---- a/gedit/gedit-io-error-info-bar.c -+++ b/gedit/gedit-io-error-info-bar.c -@@ -23,9 +23,16 @@ - */ - - #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 - -@@ -220,7 +227,7 @@ parse_gio_error (gint code, - 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) - { -@@ -323,8 +330,8 @@ gedit_unrecoverable_reverting_error_info_bar_new (GFile *location, - * 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); -@@ -534,8 +541,8 @@ gedit_io_loading_error_info_bar_new (GFile *location, - * 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); -@@ -655,8 +662,8 @@ gedit_conversion_error_while_saving_info_bar_new (GFile *locat - * 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); -@@ -700,6 +707,88 @@ gedit_conversion_error_info_bar_get_encoding (GtkWidget *info_bar) - 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) -@@ -728,8 +817,8 @@ gedit_externally_modified_saving_error_info_bar_new (GFile *location, - * 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); -@@ -788,6 +877,110 @@ gedit_externally_modified_saving_error_info_bar_new (GFile *location, - 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) -@@ -812,8 +1005,8 @@ gedit_unrecoverable_saving_error_info_bar_new (GFile *location, - * 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); -@@ -917,4 +1110,149 @@ gedit_unrecoverable_saving_error_info_bar_new (GFile *location, - 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 -@@ -39,12 +39,22 @@ GtkWidget *gedit_conversion_error_while_saving_info_bar_new (GFile - 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 */ -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 -@@ -23,14 +23,22 @@ - - #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 -@@ -83,9 +91,11 @@ struct _GeditPreferencesDialog - 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; -@@ -105,6 +115,7 @@ struct _GeditPreferencesDialog - - GtkWidget *display_line_numbers_checkbutton; - GtkWidget *display_statusbar_checkbutton; -+ GtkWidget *display_overview_map_checkbutton; - GtkWidget *display_grid_checkbutton; - - /* Right margin */ -@@ -170,6 +181,7 @@ gedit_preferences_dialog_class_init (GeditPreferencesDialogClass *klass) - 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); -@@ -187,6 +199,7 @@ gedit_preferences_dialog_class_init (GeditPreferencesDialogClass *klass) - 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); -@@ -386,6 +399,11 @@ setup_view_page (GeditPreferencesDialog *dlg) - 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, -@@ -434,7 +452,7 @@ setup_font_colors_page_font_section (GeditPreferencesDialog *dlg) - - /* 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); -@@ -462,172 +480,255 @@ setup_font_colors_page_font_section (GeditPreferencesDialog *dlg) - } - - 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) -@@ -653,94 +754,92 @@ uninstall_style_scheme (GtkSourceStyleScheme *scheme) - } - - 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 -@@ -748,33 +847,14 @@ 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)); - } - } - -@@ -782,13 +862,14 @@ 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); -@@ -796,7 +877,7 @@ setup_font_colors_page_style_scheme_section (GeditPreferencesDialog *dlg) - /* 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", -@@ -807,13 +888,11 @@ setup_font_colors_page_style_scheme_section (GeditPreferencesDialog *dlg) - 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 -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 -@@ -23,7 +23,7 @@ - #include "gedit-print-job.h" - - #include --#include -+#include - - #include "gedit-debug.h" - #include "gedit-document-private.h" -@@ -535,7 +535,7 @@ create_compositor (GeditPrintJob *job) - 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); - -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 -@@ -24,7 +24,7 @@ - void - gedit_recent_add_document (GeditDocument *document) - { -- TeplFile *file; -+ GtkSourceFile *file; - GFile *location; - GtkRecentManager *recent_manager; - GtkRecentData recent_data; -@@ -33,8 +33,8 @@ gedit_recent_add_document (GeditDocument *document) - - 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) - { -@@ -89,4 +89,229 @@ gedit_recent_remove_if_local (GFile *location) - } - } - -+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 -@@ -27,12 +27,29 @@ - - 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 -@@ -37,13 +37,7 @@ struct _GeditSettings - 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) -@@ -81,46 +75,92 @@ gedit_settings_class_init (GeditSettingsClass *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); - } - } - -@@ -207,47 +247,43 @@ on_syntax_highlighting_changed (GSettings *settings, - 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 * -@@ -292,24 +328,11 @@ _gedit_settings_peek_file_chooser_state_settings (GeditSettings *self) - } - - 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 -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 -@@ -43,11 +43,7 @@ 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); - -@@ -73,6 +69,7 @@ GSList * gedit_settings_get_candidate_encodings (gboolean *default_candidates) - #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" -diff --git a/gedit/gedit-tab.c b/gedit/gedit-tab.c -index 8bff54690..45e80c828 100644 ---- a/gedit/gedit-tab.c -+++ b/gedit/gedit-tab.c -@@ -24,7 +24,6 @@ - - #include - #include --#include - - #include "gedit-app.h" - #include "gedit-app-private.h" -@@ -33,6 +32,7 @@ - #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" -@@ -577,9 +577,9 @@ document_location_notify_handler (GtkSourceFile *file, - } - - 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); - -@@ -737,7 +737,7 @@ load_cancelled (GtkWidget *bar, - { - 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); -@@ -768,7 +768,7 @@ 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; -@@ -796,7 +796,7 @@ show_loading_info_bar (GTask *loading_task) - { - 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; - } -@@ -815,8 +815,8 @@ show_loading_info_bar (GTask *loading_task) - * 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); - } - } -@@ -841,7 +841,7 @@ show_loading_info_bar (GTask *loading_task) - 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 - { -@@ -861,7 +861,7 @@ show_loading_info_bar (GTask *loading_task) - 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, -@@ -870,7 +870,7 @@ show_loading_info_bar (GTask *loading_task) - 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); -@@ -882,7 +882,7 @@ 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; -@@ -910,7 +910,7 @@ show_saving_info_bar (GTask *saving_task) - */ - 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 -@@ -924,7 +924,7 @@ show_saving_info_bar (GTask *saving_task) - - 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; -@@ -946,9 +946,9 @@ show_saving_info_bar (GTask *saving_task) - 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); -@@ -961,7 +961,7 @@ info_bar_set_progress (GeditTab *tab, - goffset size, - goffset total_size) - { -- TeplProgressInfoBar *progress_info_bar; -+ GeditProgressInfoBar *progress_info_bar; - - if (tab->info_bar == NULL) - { -@@ -970,23 +970,23 @@ info_bar_set_progress (GeditTab *tab, - - 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); - } - } - -@@ -1045,7 +1045,7 @@ 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; -@@ -1129,9 +1129,9 @@ invalid_character_info_bar_response (GtkWidget *info_bar, - } - - 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) - { -@@ -1237,7 +1237,7 @@ externally_modified_notification_info_bar_response (GtkWidget *info_bar, - static void - display_externally_modified_notification (GeditTab *tab) - { -- TeplInfoBar *info_bar; -+ GtkWidget *info_bar; - GeditDocument *doc; - GtkSourceFile *file; - GFile *location; -@@ -1251,9 +1251,9 @@ display_externally_modified_notification (GeditTab *tab) - 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", -@@ -1318,7 +1318,6 @@ gedit_tab_init (GeditTab *tab) - GeditDocument *doc; - GeditView *view; - GtkSourceFile *file; -- TeplFile *tepl_file; - - tab->state = GEDIT_TAB_STATE_NORMAL; - -@@ -1349,7 +1348,6 @@ gedit_tab_init (GeditTab *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", -@@ -1357,11 +1355,10 @@ gedit_tab_init (GeditTab *tab) - 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", -@@ -1445,7 +1442,7 @@ _gedit_tab_get_name (GeditTab *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))) - { -@@ -1478,7 +1475,7 @@ _gedit_tab_get_tooltip (GeditTab *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); -@@ -1644,11 +1641,9 @@ goto_line (GTask *loading_task) - /* 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; - } - -@@ -1764,18 +1759,18 @@ successful_load (GTask *loading_task) - 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 -@@ -2406,12 +2401,12 @@ save_cb (GtkSourceFileSaver *saver, - 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 && -@@ -2420,7 +2415,7 @@ save_cb (GtkSourceFileSaver *saver, - /* 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, -@@ -2802,15 +2797,15 @@ 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 -@@ -2920,19 +2915,21 @@ print_cancelled (GtkWidget *bar, - 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 -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 -@@ -23,7 +23,6 @@ - #include "gedit-utils.h" - #include - #include --#include - #include "gedit-debug.h" - - gboolean -@@ -87,6 +86,122 @@ gedit_utils_set_atk_name_description (GtkWidget *widget, - 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) - { -@@ -106,7 +221,7 @@ uri_get_dirname (const gchar *uri) - return NULL; - } - -- res = tepl_utils_replace_home_dir_with_tilde (str); -+ res = gedit_utils_replace_home_dir_with_tilde (str); - - g_free (str); - -@@ -149,10 +264,10 @@ gedit_utils_location_get_dirname_for_display (GFile *location) - 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) - { -@@ -187,6 +302,51 @@ gedit_utils_location_get_dirname_for_display (GFile *location) - 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) - { -@@ -353,7 +513,7 @@ gedit_utils_basename_for_display (GFile *location) - } - } - 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, -@@ -438,6 +598,165 @@ gedit_utils_drop_get_uris (GtkSelectionData *selection_data) - 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) - { -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 -@@ -27,19 +27,38 @@ - - 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); - -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 -@@ -3,7 +3,7 @@ - * 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 -@@ -28,6 +28,7 @@ - #include - #include - -+#include "gedit-view-centering.h" - #include "gedit-debug.h" - #include "gedit-utils.h" - #include "gedit-settings.h" -@@ -53,7 +54,11 @@ struct _GeditViewFrame - { - GtkOverlay parent_instance; - -+ GSettings *editor_settings; -+ - GeditView *view; -+ GeditViewCentering *view_centering; -+ GtkFrame *map_frame; - - SearchMode search_mode; - -@@ -159,6 +164,7 @@ gedit_view_frame_dispose (GObject *object) - 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); -@@ -213,7 +219,7 @@ hide_search_widget (GeditViewFrame *frame, - 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) -@@ -297,7 +303,7 @@ finish_search (GeditViewFrame *frame, - - 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); - } -@@ -1061,6 +1067,7 @@ update_goto_line (GeditViewFrame *frame) - gchar **split_text = NULL; - const gchar *text; - GtkTextIter iter; -+ GeditDocument *doc; - - entry_text = gtk_entry_get_text (GTK_ENTRY (frame->search_entry)); - -@@ -1116,8 +1123,11 @@ update_goto_line (GeditViewFrame *frame) - - 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) - { -@@ -1428,6 +1438,8 @@ gedit_view_frame_class_init (GeditViewFrameClass *klass) - 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); -@@ -1454,6 +1466,13 @@ gedit_view_frame_init (GeditViewFrame *frame) - - 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); - -@@ -1551,6 +1570,14 @@ 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) - { -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 -@@ -24,6 +24,7 @@ - #include - #include "gedit-document.h" - #include "gedit-view.h" -+#include "gedit-view-centering.h" - - G_BEGIN_DECLS - -@@ -32,6 +33,9 @@ G_DECLARE_FINAL_TYPE (GeditViewFrame, gedit_view_frame, GEDIT, VIEW_FRAME, GtkOv - - 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); -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 -@@ -24,16 +24,21 @@ - #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 -@@ -50,7 +55,7 @@ enum - - 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) -@@ -73,23 +78,46 @@ file_read_only_notify_cb (GtkSourceFile *file, - 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); - } -@@ -106,7 +134,7 @@ static void - gedit_view_init (GeditView *view) - { - GtkTargetList *target_list; -- GtkStyleContext *style_context; -+ GtkStyleContext *context; - - gedit_debug (DEBUG_VIEW); - -@@ -140,8 +168,13 @@ gedit_view_init (GeditView *view) - 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 -@@ -150,7 +183,8 @@ 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 -@@ -160,26 +194,10 @@ gedit_view_dispose (GObject *object) - */ - 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 -@@ -188,18 +206,27 @@ 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", -@@ -720,4 +747,217 @@ gedit_view_new (GeditDocument *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 -@@ -22,8 +22,10 @@ - #ifndef GEDIT_VIEW_H - #define GEDIT_VIEW_H - -+#include -+ - #include --#include -+#include - - G_BEGIN_DECLS - -@@ -40,7 +42,7 @@ typedef struct _GeditViewPrivate GeditViewPrivate; - - struct _GeditView - { -- TeplView view; -+ GtkSourceView view; - - /*< private >*/ - GeditViewPrivate *priv; -@@ -48,7 +50,7 @@ struct _GeditView - - struct _GeditViewClass - { -- TeplViewClass parent_class; -+ GtkSourceViewClass parent_class; - - void (*drop_uris) (GeditView *view, - gchar **uri_list); -@@ -60,6 +62,22 @@ 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 */ -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 -@@ -27,6 +27,7 @@ - #include "gedit-message-bus.h" - #include "gedit-settings.h" - #include "gedit-multi-notebook.h" -+#include "gedit-open-document-selector.h" - - G_BEGIN_DECLS - -@@ -53,12 +54,15 @@ struct _GeditWindowPrivate - 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; -@@ -79,7 +83,10 @@ struct _GeditWindowPrivate - 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; - -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 -@@ -28,11 +28,11 @@ - - #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" -@@ -40,6 +40,7 @@ - #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" -@@ -54,6 +55,11 @@ - #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 - { -@@ -158,9 +164,9 @@ 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); -@@ -231,8 +237,6 @@ gedit_window_dispose (GObject *object) - */ - remove_actions (window); - -- window->priv->fullscreen_open_recent_button = NULL; -- - G_OBJECT_CLASS (gedit_window_parent_class)->dispose (object); - } - -@@ -247,6 +251,22 @@ gedit_window_finalize (GObject *object) - 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) -@@ -267,6 +287,10 @@ update_fullscreen (GeditWindow *window, - } - } - -+ gedit_multi_notebook_foreach_tab (window->priv->multi_notebook, -+ (GtkCallback)update_view_centering, -+ GBOOLEAN_TO_POINTER (is_fullscreen)); -+ - #ifndef OS_OSX - if (is_fullscreen) - { -@@ -312,7 +336,7 @@ gedit_window_configure_event (GtkWidget *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); - } -@@ -454,6 +478,7 @@ gedit_window_class_init (GeditWindowClass *klass) - 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); -@@ -466,10 +491,11 @@ gedit_window_class_init (GeditWindowClass *klass) - 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); - } - -@@ -765,8 +791,48 @@ update_actions_sensitivity (GeditWindow *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; - -@@ -776,14 +842,14 @@ language_chooser_show_cb (TeplLanguageChooser *language_chooser, - 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; - -@@ -793,13 +859,13 @@ language_activated_cb (TeplLanguageChooser *language_chooser, - 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); - -@@ -829,20 +895,20 @@ setup_statusbar (GeditWindow *window) - 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 * -@@ -1044,8 +1110,8 @@ set_title (GeditWindow *window) - { - 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; - } -@@ -1063,8 +1129,8 @@ set_title (GeditWindow *window) - * 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); - } - } -@@ -1690,88 +1756,84 @@ drop_uris_cb (GtkWidget *widget, - 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); - } - -@@ -1885,7 +1947,7 @@ on_tab_added (GeditMultiNotebook *multi, - 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, -@@ -2144,10 +2206,23 @@ on_notebook_removed (GeditMultiNotebook *mnb, - } - - 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 -@@ -2537,6 +2612,18 @@ window_unrealized (GtkWidget *window, - 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, -@@ -2608,76 +2695,6 @@ sync_fullscreen_actions (GeditWindow *window, - 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) - { -@@ -2692,6 +2709,7 @@ gedit_window_init (GeditWindow *window) - 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"); -@@ -2705,8 +2723,6 @@ gedit_window_init (GeditWindow *window) - 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, -@@ -2716,9 +2732,32 @@ gedit_window_init (GeditWindow *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) - { -@@ -2733,9 +2772,14 @@ gedit_window_init (GeditWindow *window) - 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 */ -@@ -2849,6 +2893,12 @@ gedit_window_init (GeditWindow *window) - 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 ()), -diff --git a/gedit/gedit.c b/gedit/gedit.c -index fcffdaca6..ee3769537 100644 ---- a/gedit/gedit.c -+++ b/gedit/gedit.c -@@ -28,13 +28,12 @@ - # 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 -@@ -117,7 +116,6 @@ int - main (int argc, char *argv[]) - { - GType type; -- GeditFactory *factory; - GeditApp *app; - gint status; - -@@ -140,9 +138,6 @@ main (int argc, char *argv[]) - 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", -@@ -167,7 +162,6 @@ main (int argc, char *argv[]) - G_OBJECT (app)->ref_count); - } - -- tepl_finalize (); - gedit_dirs_shutdown (); - - #ifdef G_OS_WIN32 -diff --git a/gedit/meson.build b/gedit/meson.build -index 9fc81468e..844b6bac8 100644 ---- a/gedit/meson.build -+++ b/gedit/meson.build -@@ -8,6 +8,7 @@ libgedit_public_headers = [ - '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', -@@ -27,11 +28,13 @@ libgedit_public_sources = [ - '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', - ] -@@ -45,30 +48,37 @@ libgedit_private_headers = [ - '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', - ] -@@ -85,20 +95,26 @@ libgedit_private_sources = [ - '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', -@@ -117,6 +133,7 @@ libgedit_link_args = [] - libgedit_deps = [ - deps_basic_list, - libgd_dep, -+ libxml_dep, - ] - - if host_machine.system() == 'darwin' -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 -@@ -14,6 +14,18 @@ - 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; -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,3 +1,28 @@ -+.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; - } -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 -@@ -8,10 +8,14 @@ - 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 -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 @@ -+ -+ -+ -+ -+ -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 -+ -+ -+ -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 @@ -+ -+ -+ -+ -+ -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 -@@ -105,6 +105,21 @@ - 2 - - -+ -+ -+ Display _overview map -+ True -+ True -+ False -+ True -+ True -+ -+ -+ 0 -+ 3 -+ 2 -+ -+ - - - Display _grid pattern -@@ -116,7 +131,7 @@ - - - 0 -- 3 -+ 4 - 2 - - -@@ -630,8 +645,19 @@ - True - True - -- -+ - True -+ True -+ True -+ True -+ etched-in -+ 200 -+ -+ -+ True -+ True -+ -+ - - - 0 -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 @@ -+ -+ -+ -+ -+ -diff --git a/gedit/resources/ui/gedit-view-frame.ui b/gedit/resources/ui/gedit-view-frame.ui -index ebf70b013..b61d82c3a 100644 ---- a/gedit/resources/ui/gedit-view-frame.ui -+++ b/gedit/resources/ui/gedit-view-frame.ui -@@ -7,15 +7,33 @@ - False - False - -- -+ - True -- True -- True -- False - -- -+ - True -- True -+ True -+ True -+ -+ -+ True -+ True -+ -+ -+ -+ -+ -+ -+ True -+ -+ -+ -+ True -+ view -+ -+ - - - -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 -@@ -27,6 +27,50 @@ - - 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 -@@ -310,7 +354,7 @@ - False - start - -- -+ - True - False - False -@@ -318,6 +362,47 @@ - - - True -+ -+ -+ True -+ Open a file dialog -+ center -+ True -+ -+ -+ -+ True -+ False -+ False -+ False -+ -+ -+ Open -+ True -+ -+ -+ -+ -+ True -+ pan-down-symbolic -+ -+ -+ -+ -+ -+ -+ Open -+ Open a file -+ -+ -+ -+ -+ start -+ -+ - - - True -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 -@@ -24,8 +24,8 @@ -

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 -diff --git a/meson.build b/meson.build -index be77a885f..ef77bc8a8 100644 ---- a/meson.build -+++ b/meson.build -@@ -40,13 +40,25 @@ libgd_subproject = subproject( - libgd_dep = libgd_subproject.get_variable('libgd_dep') - - # Dependencies --gio_dep = dependency('gio-2.0', version: '>= 2.64') -+glib_req = '>= 2.64' -+gtk_req = '>= 2.22' -+gtksourceview_req = '>= 4.0' -+libpeas_req = '>= 1.14.1' -+libxml_req = '>= 2.5.0' -+gspell_req = '>= 1.0' -+pygobject_req = '>= 3.0.0' -+ -+gio_dep = dependency('gio-2.0', version: glib_req) -+libxml_dep = dependency('libxml-2.0', version: libxml_req) -+gspell_dep = dependency('gspell-1', version: gspell_req) -+ -+python3 = python.find_installation('python3') - - libgedit_public_deps = [ - gio_dep, -- dependency('gtk+-3.0', version: '>= 3.22'), -- dependency('tepl-6', version: '>= 5.99.0'), -- dependency('libpeas-gtk-1.0'), -+ dependency('gtk+-3.0', version: gtk_req), -+ dependency('gtksourceview-4', version: gtksourceview_req), -+ dependency('libpeas-gtk-1.0', version: libpeas_req), - ] - - deps_basic_list = [ -@@ -54,9 +66,6 @@ deps_basic_list = [ - dependency('gobject-introspection-1.0'), - ] - --gspell_dep = dependency('gspell-1', version: '>= 1.0') --python3 = python.find_installation('python3') -- - # Configurations - config_h = configuration_data() - config_h.set_quoted('PACKAGE_STRING', 'gedit-@0@'.format(api_version)) -@@ -65,6 +74,17 @@ config_h.set_quoted('LIBDIR', join_paths(get_option('prefix'), get_option('libdi - config_h.set_quoted('DATADIR', join_paths(get_option('prefix'), get_option('datadir'))) - config_h.set_quoted('VERSION', meson.project_version()) - -+enable_gvfs_metadata = get_option('enable-gvfs-metadata') -+if enable_gvfs_metadata == 'yes' or (enable_gvfs_metadata == 'auto' and host_machine.system() == 'linux') -+ enable_gvfs_metadata = true -+else -+ enable_gvfs_metadata = false -+endif -+ -+if enable_gvfs_metadata -+ config_h.set('ENABLE_GVFS_METADATA', 1) -+endif -+ - configure_file( - output: 'config.h', - configuration: config_h -diff --git a/meson_options.txt b/meson_options.txt -index 4e842d1ea..33d03cb14 100644 ---- a/meson_options.txt -+++ b/meson_options.txt -@@ -21,4 +21,11 @@ option( - description: 'Build user documentation' - ) - -+option( -+ 'enable-gvfs-metadata', -+ type: 'combo', -+ choices: ['yes', 'no', 'auto'], value: 'auto', -+ description: 'Enable using gvfs to store metadata' -+) -+ - option('plugin_externaltools', type: 'boolean', value: true) -diff --git a/plugins/snippets/snippets/document.py b/plugins/snippets/snippets/document.py -index 003237d17..23df28091 100644 ---- a/plugins/snippets/snippets/document.py -+++ b/plugins/snippets/snippets/document.py -@@ -162,13 +162,13 @@ class Document(GObject.Object, Gedit.ViewActivatable, Signals): - buf = self.view.get_buffer() - - self.connect_signal(buf, 'changed', self.on_buffer_changed) -- self.connect_signal(buf, 'tepl-cursor-moved', self.on_buffer_cursor_moved) -+ self.connect_signal(buf, 'cursor-moved', self.on_buffer_cursor_moved) - self.connect_signal_after(buf, 'insert-text', self.on_buffer_insert_text) - - def last_snippet_removed(self): - buf = self.view.get_buffer() - self.disconnect_signal(buf, 'changed') -- self.disconnect_signal(buf, 'tepl-cursor-moved') -+ self.disconnect_signal(buf, 'cursor-moved') - self.disconnect_signal(buf, 'insert-text') - - def current_placeholder(self): -@@ -559,7 +559,7 @@ class Document(GObject.Object, Gedit.ViewActivatable, Signals): - self.goto_placeholder(current, None) - - if len(self.active_snippets) > 0: -- self.block_signal(buf, 'tepl-cursor-moved') -+ self.block_signal(buf, 'cursor-moved') - - buf.begin_user_action() - -@@ -569,7 +569,7 @@ class Document(GObject.Object, Gedit.ViewActivatable, Signals): - # Insert the snippet - if len(self.active_snippets) == 0: - self.first_snippet_inserted() -- self.block_signal(buf, 'tepl-cursor-moved') -+ self.block_signal(buf, 'cursor-moved') - - sn = s.insert_into(self, start) - self.active_snippets.append(sn) -@@ -585,7 +585,7 @@ class Document(GObject.Object, Gedit.ViewActivatable, Signals): - else: - self.goto_placeholder(self.active_placeholder, sn.placeholders[keys[0]]) - -- self.unblock_signal(buf, 'tepl-cursor-moved') -+ self.unblock_signal(buf, 'cursor-moved') - - if sn in self.active_snippets: - # Check if we can get end_iter in view without moving the -diff --git a/plugins/spell/gedit-spell-plugin.c b/plugins/spell/gedit-spell-plugin.c -index 611677826..47d449433 100644 ---- a/plugins/spell/gedit-spell-plugin.c -+++ b/plugins/spell/gedit-spell-plugin.c -@@ -30,8 +30,13 @@ - - #include "gedit-spell-app-activatable.h" - --#define GEDIT_METADATA_ATTRIBUTE_SPELL_LANGUAGE "gedit-spell-language" --#define GEDIT_METADATA_ATTRIBUTE_SPELL_ENABLED "gedit-spell-enabled" -+#ifdef G_OS_WIN32 -+#define GEDIT_METADATA_ATTRIBUTE_SPELL_LANGUAGE "spell-language" -+#define GEDIT_METADATA_ATTRIBUTE_SPELL_ENABLED "spell-enabled" -+#else -+#define GEDIT_METADATA_ATTRIBUTE_SPELL_LANGUAGE "metadata::gedit-spell-language" -+#define GEDIT_METADATA_ATTRIBUTE_SPELL_ENABLED "metadata::gedit-spell-enabled" -+#endif - - #define SPELL_ENABLED_STR "1" - #define SPELL_BASE_SETTINGS "org.gnome.gedit.plugins.spell" -diff --git a/po/POTFILES.in b/po/POTFILES.in -index be8af499a..25ff2db1a 100644 ---- a/po/POTFILES.in -+++ b/po/POTFILES.in -@@ -16,19 +16,22 @@ gedit/gedit-documents-panel.c - gedit/gedit-encodings-combo-box.c - gedit/gedit-encoding-items.c - gedit/gedit-encodings-dialog.c --gedit/gedit-factory.c - gedit/gedit-file-chooser.c - gedit/gedit-file-chooser-dialog-gtk.c - gedit/gedit-file-chooser-open.c - gedit/gedit-file-chooser-open-dialog.c - gedit/gedit-file-chooser-open-native.c -+gedit/gedit-highlight-mode-dialog.c -+gedit/gedit-highlight-mode-selector.c - gedit/gedit-io-error-info-bar.c - gedit/gedit-notebook.c - gedit/gedit-notebook-popup-menu.c -+gedit/gedit-open-document-selector.c - gedit/gedit-plugins-engine.c - gedit/gedit-preferences-dialog.c - gedit/gedit-print-job.c - gedit/gedit-print-preview.c -+gedit/gedit-progress-info-bar.c - gedit/gedit-replace-dialog.c - gedit/gedit-statusbar.c - gedit/gedit-tab.c -@@ -41,6 +44,9 @@ gedit/resources/gtk/menus-common.ui - gedit/resources/gtk/menus.ui - gedit/resources/gtk/menus-traditional.ui - gedit/resources/ui/gedit-encodings-dialog.ui -+gedit/resources/ui/gedit-highlight-mode-dialog.ui -+gedit/resources/ui/gedit-highlight-mode-selector.ui -+gedit/resources/ui/gedit-open-document-selector.ui - gedit/resources/ui/gedit-preferences-dialog.ui - gedit/resources/ui/gedit-print-preferences.ui - gedit/resources/ui/gedit-print-preview.ui --- -GitLab - diff -Nru gedit-40.1/docs/gedit-development-getting-started.md gedit-41.0/docs/gedit-development-getting-started.md --- gedit-40.1/docs/gedit-development-getting-started.md 2021-04-17 05:45:35.404543200 +0000 +++ gedit-41.0/docs/gedit-development-getting-started.md 2022-02-14 13:58:26.000000000 +0000 @@ -31,11 +31,9 @@ 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. diff -Nru gedit-40.1/docs/reference/api-breaks.xml gedit-41.0/docs/reference/api-breaks.xml --- gedit-40.1/docs/reference/api-breaks.xml 2021-04-17 05:45:35.404543200 +0000 +++ gedit-41.0/docs/reference/api-breaks.xml 2022-02-14 13:58:26.000000000 +0000 @@ -22,6 +22,56 @@ + 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 diff -Nru gedit-40.1/docs/reference/gedit-docs.xml gedit-41.0/docs/reference/gedit-docs.xml --- gedit-40.1/docs/reference/gedit-docs.xml 2021-04-17 05:45:35.404543200 +0000 +++ gedit-41.0/docs/reference/gedit-docs.xml 2022-02-14 13:58:26.000000000 +0000 @@ -16,6 +16,7 @@ + diff -Nru gedit-40.1/docs/reference/gedit-sections.txt gedit-41.0/docs/reference/gedit-sections.txt --- gedit-40.1/docs/reference/gedit-sections.txt 2021-04-17 05:45:35.404543200 +0000 +++ gedit-41.0/docs/reference/gedit-sections.txt 2022-02-14 13:58:26.000000000 +0000 @@ -54,7 +54,10 @@ 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 @@ -149,6 +152,26 @@
+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 @@ -199,6 +222,13 @@ 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 @@ -291,6 +321,7 @@ DEBUG_COMMANDS DEBUG_APP DEBUG_UTILS +DEBUG_METADATA gedit_debug_init gedit_debug gedit_debug_message @@ -321,9 +352,14 @@
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 diff -Nru gedit-40.1/docs/reference/meson.build gedit-41.0/docs/reference/meson.build --- gedit-40.1/docs/reference/meson.build 2021-04-17 05:45:35.404543200 +0000 +++ gedit-41.0/docs/reference/meson.build 2022-02-14 13:58:26.000000000 +0000 @@ -6,14 +6,12 @@ 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( @@ -30,8 +28,6 @@ '--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: [ diff -Nru gedit-40.1/docs/roadmap-done.md gedit-41.0/docs/roadmap-done.md --- gedit-40.1/docs/roadmap-done.md 2021-04-17 05:45:35.404543200 +0000 +++ gedit-41.0/docs/roadmap-done.md 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru gedit-40.1/docs/roadmap.md gedit-41.0/docs/roadmap.md --- gedit-40.1/docs/roadmap.md 2021-04-17 05:45:35.404543200 +0000 +++ gedit-41.0/docs/roadmap.md 2022-02-14 13:58:26.000000000 +0000 @@ -4,27 +4,10 @@ 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 ------------------------ diff -Nru gedit-40.1/gedit/Gedit-3.0.metadata gedit-41.0/gedit/Gedit-3.0.metadata --- gedit-40.1/gedit/Gedit-3.0.metadata 2021-04-17 05:45:35.404543200 +0000 +++ gedit-41.0/gedit/Gedit-3.0.metadata 2022-02-14 13:58:26.000000000 +0000 @@ -6,6 +6,7 @@ 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" diff -Nru gedit-40.1/gedit/gedit-app.c gedit-41.0/gedit/gedit-app.c --- gedit-40.1/gedit/gedit-app.c 2021-04-17 05:45:35.452544200 +0000 +++ gedit-41.0/gedit/gedit-app.c 2022-02-14 13:58:26.000000000 +0000 @@ -28,8 +28,9 @@ #include #include +#include #include -#include +#include #include "gedit-commands-private.h" #include "gedit-notebook.h" @@ -44,6 +45,10 @@ #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" @@ -51,6 +56,10 @@ { GeditPluginsEngine *engine; +#ifndef ENABLE_GVFS_METADATA + GeditMetadataManager *metadata_manager; +#endif + GtkCssProvider *theme_provider; GtkPageSetup *page_setup; @@ -145,6 +154,10 @@ 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); @@ -643,6 +656,10 @@ 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)); @@ -654,6 +671,13 @@ 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"); @@ -1114,6 +1138,10 @@ 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); } @@ -1253,15 +1281,10 @@ 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); } /** @@ -1571,6 +1594,25 @@ 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) { diff -Nru gedit-40.1/gedit/gedit-app-osx.m gedit-41.0/gedit/gedit-app-osx.m --- gedit-40.1/gedit/gedit-app-osx.m 2021-04-17 05:45:35.404543200 +0000 +++ gedit-41.0/gedit/gedit-app-osx.m 2022-02-14 13:58:26.000000000 +0000 @@ -31,7 +31,7 @@ #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); @@ -286,7 +286,7 @@ g_free (uri); } - ismodified = !tepl_buffer_is_untouched (TEPL_BUFFER (document)); + ismodified = !gedit_document_is_untouched (document); [native setDocumentEdited:ismodified]; } else diff -Nru gedit-40.1/gedit/gedit-app-private.h gedit-41.0/gedit/gedit-app-private.h --- gedit-40.1/gedit/gedit-app-private.h 2021-04-17 05:45:35.404543200 +0000 +++ gedit-41.0/gedit/gedit-app-private.h 2022-02-14 13:58:26.000000000 +0000 @@ -22,6 +22,7 @@ #define GEDIT_APP_PRIVATE_H #include "gedit-app.h" +#include "gedit-metadata-manager.h" #include "gedit-menu-extension.h" G_BEGIN_DECLS @@ -34,6 +35,8 @@ 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); diff -Nru gedit-40.1/gedit/gedit.c gedit-41.0/gedit/gedit.c --- gedit-40.1/gedit/gedit.c 2021-04-17 05:45:36.276561500 +0000 +++ gedit-41.0/gedit/gedit.c 2022-02-14 13:58:26.000000000 +0000 @@ -28,13 +28,12 @@ # 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 @@ -117,7 +116,6 @@ main (int argc, char *argv[]) { GType type; - GeditFactory *factory; GeditApp *app; gint status; @@ -140,9 +138,6 @@ 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", @@ -167,7 +162,6 @@ G_OBJECT (app)->ref_count); } - tepl_finalize (); gedit_dirs_shutdown (); #ifdef G_OS_WIN32 diff -Nru gedit-40.1/gedit/gedit-commands-edit.c gedit-41.0/gedit/gedit-commands-edit.c --- gedit-40.1/gedit/gedit-commands-edit.c 2021-04-17 05:45:35.664548600 +0000 +++ gedit-41.0/gedit/gedit-commands-edit.c 2022-02-14 13:58:26.000000000 +0000 @@ -44,13 +44,13 @@ 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)); } @@ -67,13 +67,13 @@ 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)); } @@ -89,9 +89,9 @@ 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)); } @@ -107,9 +107,9 @@ 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)); } @@ -125,9 +125,9 @@ 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)); } @@ -143,9 +143,9 @@ 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)); } @@ -161,9 +161,9 @@ 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)); } diff -Nru gedit-40.1/gedit/gedit-commands-file.c gedit-41.0/gedit/gedit-commands-file.c --- gedit-40.1/gedit/gedit-commands-file.c 2021-04-17 05:45:35.664548600 +0000 +++ gedit-41.0/gedit/gedit-commands-file.c 2022-02-14 13:58:26.000000000 +0000 @@ -27,7 +27,6 @@ #include "gedit-commands-private.h" #include -#include #include "gedit-app.h" #include "gedit-debug.h" @@ -44,10 +43,6 @@ #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" @@ -150,24 +145,26 @@ { 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)); } } @@ -194,7 +191,7 @@ 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, @@ -513,7 +510,7 @@ * 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, @@ -565,7 +562,7 @@ * 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) @@ -827,6 +824,7 @@ /* 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")); diff -Nru gedit-40.1/gedit/gedit-commands-search.c gedit-41.0/gedit/gedit-commands-search.c --- gedit-40.1/gedit/gedit-commands-search.c 2021-04-17 05:45:35.724550000 +0000 +++ gedit-41.0/gedit/gedit-commands-search.c 2022-02-14 13:58:26.000000000 +0000 @@ -29,7 +29,6 @@ #include #include #include -#include #include "gedit-debug.h" #include "gedit-statusbar.h" @@ -132,7 +131,7 @@ 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, @@ -188,7 +187,7 @@ &match_start, &match_end); - tepl_view_scroll_to_cursor (TEPL_VIEW (view)); + gedit_view_scroll_to_cursor (view); } else { @@ -294,7 +293,7 @@ &match_start, &match_end); - tepl_view_scroll_to_cursor (TEPL_VIEW (view)); + gedit_view_scroll_to_cursor (view); } else { diff -Nru gedit-40.1/gedit/gedit-commands-view.c gedit-41.0/gedit/gedit-commands-view.c --- gedit-40.1/gedit/gedit-commands-view.c 2021-04-17 05:45:35.728550000 +0000 +++ gedit-41.0/gedit/gedit-commands-view.c 2022-02-14 13:58:26.000000000 +0000 @@ -21,11 +21,16 @@ */ #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, @@ -121,9 +126,9 @@ } static void -language_activated_cb (TeplLanguageChooserDialog *dialog, - GtkSourceLanguage *language, - GeditWindow *window) +language_selected_cb (GeditHighlightModeSelector *selector, + GtkSourceLanguage *language, + GeditWindow *window) { GeditDocument *active_document; @@ -132,16 +137,6 @@ { 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 @@ -150,10 +145,12 @@ 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) @@ -161,20 +158,15 @@ 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)); } diff -Nru gedit-40.1/gedit/gedit-debug.c gedit-41.0/gedit/gedit-debug.c --- gedit-40.1/gedit/gedit-debug.c 2021-04-17 05:45:35.728550000 +0000 +++ gedit-41.0/gedit/gedit-debug.c 2022-02-14 13:58:26.000000000 +0000 @@ -100,6 +100,10 @@ { enabled_sections |= GEDIT_DEBUG_UTILS; } + if (g_getenv ("GEDIT_DEBUG_METADATA") != NULL) + { + enabled_sections |= GEDIT_DEBUG_METADATA; + } out: diff -Nru gedit-40.1/gedit/gedit-debug.h gedit-41.0/gedit/gedit-debug.h --- gedit-40.1/gedit/gedit-debug.h 2021-04-17 05:45:35.728550000 +0000 +++ gedit-41.0/gedit/gedit-debug.h 2022-02-14 13:58:26.000000000 +0000 @@ -48,6 +48,7 @@ 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 @@ -60,6 +61,7 @@ #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); diff -Nru gedit-40.1/gedit/gedit-document.c gedit-41.0/gedit/gedit-document.c --- gedit-40.1/gedit/gedit-document.c 2021-04-17 05:45:35.860552800 +0000 +++ gedit-41.0/gedit/gedit-document.c 2022-02-14 13:58:26.000000000 +0000 @@ -5,7 +5,7 @@ * 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 @@ -22,13 +22,21 @@ */ #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_" @@ -43,7 +51,11 @@ { GtkSourceFile *file; - TeplMetadata *metadata; + GSettings *editor_settings; + + gint untitled_number; + + GFileInfo *metadata_info; gchar *content_type; @@ -54,7 +66,12 @@ */ 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 @@ -71,9 +88,11 @@ enum { PROP_0, + PROP_SHORTNAME, PROP_CONTENT_TYPE, PROP_MIME_TYPE, PROP_EMPTY_SEARCH, + PROP_USE_GVFS_METADATA, LAST_PROP }; @@ -81,6 +100,7 @@ enum { + CURSOR_MOVED, LOAD, LOADED, SAVE, @@ -90,40 +110,41 @@ 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 @@ -195,16 +216,17 @@ /* 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); } @@ -212,10 +234,17 @@ 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) @@ -239,6 +268,10 @@ 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; @@ -251,6 +284,10 @@ 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; @@ -264,6 +301,7 @@ GParamSpec *pspec) { GeditDocument *doc = GEDIT_DOCUMENT (object); + GeditDocumentPrivate *priv = gedit_document_get_instance_private (doc); switch (prop_id) { @@ -271,6 +309,10 @@ 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; @@ -278,15 +320,86 @@ } 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", @@ -299,6 +412,7 @@ 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; @@ -306,10 +420,27 @@ 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. @@ -348,8 +479,44 @@ 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. @@ -632,20 +799,79 @@ 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; @@ -653,13 +879,7 @@ 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", @@ -667,9 +887,6 @@ 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); @@ -699,7 +916,17 @@ 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 * @@ -814,17 +1041,19 @@ 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 { @@ -841,12 +1070,24 @@ 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 * @@ -1033,14 +1274,30 @@ } 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; } /* @@ -1072,6 +1329,51 @@ 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: @@ -1130,6 +1432,64 @@ 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 @@ -1150,12 +1510,12 @@ 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); } /** @@ -1173,30 +1533,84 @@ ...) { 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 diff -Nru gedit-40.1/gedit/gedit-document.h gedit-41.0/gedit/gedit-document.h --- gedit-40.1/gedit/gedit-document.h 2021-04-17 05:45:35.860552800 +0000 +++ gedit-41.0/gedit/gedit-document.h 2022-02-14 13:58:26.000000000 +0000 @@ -5,7 +5,7 @@ * 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 @@ -24,19 +24,20 @@ #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); @@ -57,8 +58,17 @@ 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 diff -Nru gedit-40.1/gedit/gedit-document-private.h gedit-41.0/gedit/gedit-document-private.h --- gedit-40.1/gedit/gedit-document-private.h 2021-04-17 05:45:35.728550000 +0000 +++ gedit-41.0/gedit/gedit-document-private.h 2022-02-14 13:58:26.000000000 +0000 @@ -28,9 +28,15 @@ 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); diff -Nru gedit-40.1/gedit/gedit-documents-panel.c gedit-41.0/gedit/gedit-documents-panel.c --- gedit-40.1/gedit/gedit-documents-panel.c 2021-04-17 05:45:35.892553600 +0000 +++ gedit-41.0/gedit/gedit-documents-panel.c 2022-02-14 13:58:26.000000000 +0000 @@ -23,7 +23,6 @@ #include "gedit-documents-panel.h" #include -#include #include "gedit-debug.h" #include "gedit-document.h" @@ -447,7 +446,7 @@ 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); diff -Nru gedit-40.1/gedit/gedit-factory.c gedit-41.0/gedit/gedit-factory.c --- gedit-40.1/gedit/gedit-factory.c 2021-04-17 05:45:35.892553600 +0000 +++ gedit-41.0/gedit/gedit-factory.c 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru gedit-40.1/gedit/gedit-factory.h gedit-41.0/gedit/gedit-factory.h --- gedit-40.1/gedit/gedit-factory.h 2021-04-17 05:45:35.892553600 +0000 +++ gedit-41.0/gedit/gedit-factory.h 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru gedit-40.1/gedit/gedit-file-chooser-dialog.c gedit-41.0/gedit/gedit-file-chooser-dialog.c --- gedit-40.1/gedit/gedit-file-chooser-dialog.c 2021-04-17 05:45:36.012556000 +0000 +++ gedit-41.0/gedit/gedit-file-chooser-dialog.c 2022-02-14 13:58:26.000000000 +0000 @@ -62,13 +62,15 @@ } 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); } @@ -212,6 +214,19 @@ } 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; @@ -255,4 +270,21 @@ 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 -Nru gedit-40.1/gedit/gedit-file-chooser-dialog-gtk.c gedit-41.0/gedit/gedit-file-chooser-dialog-gtk.c --- gedit-40.1/gedit/gedit-file-chooser-dialog-gtk.c 2021-04-17 05:45:35.892553600 +0000 +++ gedit-41.0/gedit/gedit-file-chooser-dialog-gtk.c 2022-02-14 13:58:26.000000000 +0000 @@ -193,6 +193,12 @@ } static void +chooser_hide (GeditFileChooserDialog *dialog) +{ + gtk_widget_hide (GTK_WIDGET (dialog)); +} + +static void chooser_destroy (GeditFileChooserDialog *dialog) { gtk_widget_destroy (GTK_WIDGET (dialog)); @@ -212,6 +218,26 @@ } 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) { @@ -229,9 +255,11 @@ 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 @@ -253,7 +281,8 @@ } static void -create_option_menu (GeditFileChooserDialogGtk *dialog) +create_option_menu (GeditFileChooserDialogGtk *dialog, + GeditFileChooserFlags flags) { GtkWidget *label; GtkWidget *menu; @@ -262,7 +291,7 @@ 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); @@ -374,13 +403,18 @@ } 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); } @@ -421,21 +455,35 @@ } 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", diff -Nru gedit-40.1/gedit/gedit-file-chooser-dialog-gtk.h gedit-41.0/gedit/gedit-file-chooser-dialog-gtk.h --- gedit-40.1/gedit/gedit-file-chooser-dialog-gtk.h 2021-04-17 05:45:35.892553600 +0000 +++ gedit-41.0/gedit/gedit-file-chooser-dialog-gtk.h 2022-02-14 13:58:26.000000000 +0000 @@ -33,10 +33,11 @@ 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 diff -Nru gedit-40.1/gedit/gedit-file-chooser-dialog.h gedit-41.0/gedit/gedit-file-chooser-dialog.h --- gedit-40.1/gedit/gedit-file-chooser-dialog.h 2021-04-17 05:45:36.012556000 +0000 +++ gedit-41.0/gedit/gedit-file-chooser-dialog.h 2022-02-14 13:58:26.000000000 +0000 @@ -64,6 +64,7 @@ gboolean overwrite_confirmation); void (*show) (GeditFileChooserDialog *dialog); + void (*hide) (GeditFileChooserDialog *dialog); void (*destroy) (GeditFileChooserDialog *dialog); @@ -72,11 +73,22 @@ 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); @@ -110,12 +122,17 @@ 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 */ diff -Nru gedit-40.1/gedit/gedit-highlight-mode-dialog.c gedit-41.0/gedit/gedit-highlight-mode-dialog.c --- gedit-40.1/gedit/gedit-highlight-mode-dialog.c 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/gedit-highlight-mode-dialog.c 2022-02-14 13:58:26.000000000 +0000 @@ -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 -Nru gedit-40.1/gedit/gedit-highlight-mode-dialog.h gedit-41.0/gedit/gedit-highlight-mode-dialog.h --- gedit-40.1/gedit/gedit-highlight-mode-dialog.h 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/gedit-highlight-mode-dialog.h 2022-02-14 13:58:26.000000000 +0000 @@ -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 -Nru gedit-40.1/gedit/gedit-highlight-mode-selector.c gedit-41.0/gedit/gedit-highlight-mode-selector.c --- gedit-40.1/gedit/gedit-highlight-mode-selector.c 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/gedit-highlight-mode-selector.c 2022-02-14 13:58:26.000000000 +0000 @@ -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 -Nru gedit-40.1/gedit/gedit-highlight-mode-selector.h gedit-41.0/gedit/gedit-highlight-mode-selector.h --- gedit-40.1/gedit/gedit-highlight-mode-selector.h 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/gedit-highlight-mode-selector.h 2022-02-14 13:58:26.000000000 +0000 @@ -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 -Nru gedit-40.1/gedit/gedit-io-error-info-bar.c gedit-41.0/gedit/gedit-io-error-info-bar.c --- gedit-40.1/gedit/gedit-io-error-info-bar.c 2021-04-17 05:45:36.016556000 +0000 +++ gedit-41.0/gedit/gedit-io-error-info-bar.c 2022-02-14 13:58:26.000000000 +0000 @@ -23,9 +23,16 @@ */ #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 @@ -220,7 +227,7 @@ 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) { @@ -323,8 +330,8 @@ * 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); @@ -395,6 +402,67 @@ gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); } +static void +create_primary_and_secondary_widgets_info_bar(GtkWidget *vbox, const gchar *primary_text, + const gchar *secondary_text) +{ + gchar *primary_markup; + gchar *secondary_markup; + GtkWidget *primary_label; + GtkWidget *secondary_label; + + primary_markup = g_strdup_printf ("%s", 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); + + if (secondary_text != NULL) + { + 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); + } +} + +static GtkWidget * +create_file_too_big_error_info_bar (const gchar *primary_text, + const gchar *secondary_text) +{ + GtkWidget *info_bar; + GtkWidget *hbox_content; + GtkWidget *vbox; + + info_bar = gtk_info_bar_new (); + gtk_info_bar_set_show_close_button (GTK_INFO_BAR (info_bar), TRUE); + + gtk_info_bar_add_button (GTK_INFO_BAR (info_bar), + _("_Continue loading"), + GTK_RESPONSE_ACCEPT); + + 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); + + create_primary_and_secondary_widgets_info_bar (vbox, primary_text, secondary_text); + gtk_widget_show_all (hbox_content); + set_contents (info_bar, hbox_content); + + return info_bar; +} + static GtkWidget * create_conversion_error_info_bar (const gchar *primary_text, const gchar *secondary_text, @@ -403,10 +471,6 @@ GtkWidget *info_bar; GtkWidget *hbox_content; GtkWidget *vbox; - gchar *primary_markup; - gchar *secondary_markup; - GtkWidget *primary_label; - GtkWidget *secondary_label; info_bar = gtk_info_bar_new (); gtk_info_bar_set_show_close_button (GTK_INFO_BAR (info_bar), TRUE); @@ -436,30 +500,7 @@ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0); - primary_markup = g_strdup_printf ("%s", 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); - - if (secondary_text != NULL) - { - 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); - } - + create_primary_and_secondary_widgets_info_bar (vbox, primary_text, secondary_text); create_combo_box (info_bar, vbox); gtk_widget_show_all (hbox_content); set_contents (info_bar, hbox_content); @@ -480,6 +521,7 @@ GtkWidget *info_bar; gboolean edit_anyway = FALSE; gboolean convert_error = FALSE; + gboolean file_too_big = FALSE; g_return_val_if_fail (error != NULL, NULL); g_return_val_if_fail (error->domain == GTK_SOURCE_FILE_LOADER_ERROR || @@ -499,8 +541,8 @@ * 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); @@ -549,6 +591,16 @@ g_free (encoding_name); } + else if (error->domain == GTK_SOURCE_FILE_LOADER_ERROR && + error->code == GTK_SOURCE_FILE_LOADER_ERROR_TOO_BIG) + { + error_message = g_strdup_printf (_("The file “%s” is very big."), + uri_for_display); + message_details = g_strconcat (_("Large files can make gedit slow or unresponsive. " + "You can continue loading this file at your own risk"), + NULL); + file_too_big = TRUE; + } else { parse_error (error, &error_message, &message_details, location, uri_for_display); @@ -560,7 +612,12 @@ uri_for_display); } - if (convert_error) + if (file_too_big) + { + info_bar = create_file_too_big_error_info_bar (error_message, + message_details); + } + else if (convert_error) { info_bar = create_conversion_error_info_bar (error_message, message_details, @@ -605,8 +662,8 @@ * 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); @@ -651,6 +708,88 @@ } 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) { @@ -678,8 +817,8 @@ * 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); @@ -739,6 +878,110 @@ } 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) { @@ -762,8 +1005,8 @@ * 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); @@ -866,5 +1109,150 @@ 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 -Nru gedit-40.1/gedit/gedit-io-error-info-bar.h gedit-41.0/gedit/gedit-io-error-info-bar.h --- gedit-40.1/gedit/gedit-io-error-info-bar.h 2021-04-17 05:45:36.016556000 +0000 +++ gedit-41.0/gedit/gedit-io-error-info-bar.h 2022-02-14 13:58:26.000000000 +0000 @@ -39,12 +39,22 @@ 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 */ diff -Nru gedit-40.1/gedit/gedit-metadata-manager.c gedit-41.0/gedit/gedit-metadata-manager.c --- gedit-40.1/gedit/gedit-metadata-manager.c 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/gedit-metadata-manager.c 2022-02-14 13:58:26.000000000 +0000 @@ -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 -Nru gedit-40.1/gedit/gedit-metadata-manager.h gedit-41.0/gedit/gedit-metadata-manager.h --- gedit-40.1/gedit/gedit-metadata-manager.h 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/gedit-metadata-manager.h 2022-02-14 13:58:26.000000000 +0000 @@ -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 -Nru gedit-40.1/gedit/gedit-open-document-selector.c gedit-41.0/gedit/gedit-open-document-selector.c --- gedit-40.1/gedit/gedit-open-document-selector.c 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/gedit-open-document-selector.c 2022-02-14 13:58:26.000000000 +0000 @@ -0,0 +1,1294 @@ +/* + * 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) +{ + g_assert (a != NULL && b != NULL); + + return g_date_time_compare (b->accessed, a->accessed); +} + +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 -Nru gedit-40.1/gedit/gedit-open-document-selector.h gedit-41.0/gedit/gedit-open-document-selector.h --- gedit-40.1/gedit/gedit-open-document-selector.h 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/gedit-open-document-selector.h 2022-02-14 13:58:26.000000000 +0000 @@ -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 -Nru gedit-40.1/gedit/gedit-open-document-selector-helper.c gedit-41.0/gedit/gedit-open-document-selector-helper.c --- gedit-40.1/gedit/gedit-open-document-selector-helper.c 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/gedit-open-document-selector-helper.c 2022-02-14 13:58:26.000000000 +0000 @@ -0,0 +1,104 @@ +/* + * 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; + char *accessed = NULL; + + g_print ("%s\n", title); + + for (l = fileitem_list; l != NULL; l = l->next) + { + item = (FileItem *)l->data; + + accessed = g_date_time_format_iso8601 (item->accessed); + + g_print ("%s uri:%s (%s %s)\n", + accessed, + item->uri, + item->name, + item->path); + + g_clear_pointer (&accessed, g_free); + } +} + +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_clear_pointer (&item->accessed, g_date_time_unref); + + 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->accessed = g_date_time_ref (item->accessed); + + 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 -Nru gedit-40.1/gedit/gedit-open-document-selector-helper.h gedit-41.0/gedit/gedit-open-document-selector-helper.h --- gedit-40.1/gedit/gedit-open-document-selector-helper.h 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/gedit-open-document-selector-helper.h 2022-02-14 13:58:26.000000000 +0000 @@ -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; + GDateTime *accessed; +} 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 -Nru gedit-40.1/gedit/gedit-open-document-selector-store.c gedit-41.0/gedit/gedit-open-document-selector-store.c --- gedit-40.1/gedit/gedit-open-document-selector-store.c 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/gedit-open-document-selector-store.c 2022-02-14 13:58:26.000000000 +0000 @@ -0,0 +1,839 @@ +/* + * 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 GDateTime * +_get_date_time (GFileInfo *info) +{ + guint32 time; + guint32 usecs; + GDateTime *dt = NULL, *dt2 = NULL; + + g_return_val_if_fail (G_IS_FILE_INFO (info), NULL); + + time = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS); + dt = g_date_time_new_from_unix_utc (time); + + usecs = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC); + dt2 = g_date_time_add_seconds (dt, usecs / (gdouble) G_USEC_PER_SEC); + + g_date_time_unref (dt); + + return g_steal_pointer (&dt2); +} + + +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->accessed = _get_date_time (info); + 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->accessed = _get_date_time (info); + + 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->accessed = g_date_time_new_from_unix_local (gtk_recent_info_get_visited (l->data)); + + 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 -Nru gedit-40.1/gedit/gedit-open-document-selector-store.h gedit-41.0/gedit/gedit-open-document-selector-store.h --- gedit-40.1/gedit/gedit-open-document-selector-store.h 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/gedit-open-document-selector-store.h 2022-02-14 13:58:26.000000000 +0000 @@ -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 -Nru gedit-40.1/gedit/gedit-pango.c gedit-41.0/gedit/gedit-pango.c --- gedit-40.1/gedit/gedit-pango.c 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/gedit-pango.c 2022-02-14 13:58:26.000000000 +0000 @@ -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 -Nru gedit-40.1/gedit/gedit-pango.h gedit-41.0/gedit/gedit-pango.h --- gedit-40.1/gedit/gedit-pango.h 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/gedit-pango.h 2022-02-14 13:58:26.000000000 +0000 @@ -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 -Nru gedit-40.1/gedit/gedit-preferences-dialog.c gedit-41.0/gedit/gedit-preferences-dialog.c --- gedit-40.1/gedit/gedit-preferences-dialog.c 2021-04-17 05:45:36.120558300 +0000 +++ gedit-41.0/gedit/gedit-preferences-dialog.c 2022-02-14 13:58:26.000000000 +0000 @@ -23,14 +23,22 @@ #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 @@ -83,9 +91,11 @@ 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; @@ -105,6 +115,7 @@ GtkWidget *display_line_numbers_checkbutton; GtkWidget *display_statusbar_checkbutton; + GtkWidget *display_overview_map_checkbutton; GtkWidget *display_grid_checkbutton; /* Right margin */ @@ -170,6 +181,7 @@ 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); @@ -187,6 +199,7 @@ 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); @@ -387,6 +400,11 @@ "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", @@ -434,7 +452,7 @@ /* 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); @@ -462,172 +480,255 @@ } 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) -{ - if (g_file_equal (src_file, dest_file)) - { +file_copy (const gchar *name, + const gchar *dest_name, + GError **error) +{ + 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) @@ -653,94 +754,92 @@ } 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, + _("A_dd Scheme"), + _("_Cancel")); /* 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); - - gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (chooser), scheme_filter); + gedit_file_chooser_dialog_add_pattern_filter (chooser, + _("Color Scheme Files"), + "*.xml"); + + 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 @@ -748,33 +847,14 @@ 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)); } } @@ -782,13 +862,14 @@ 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); @@ -796,7 +877,7 @@ /* 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", @@ -807,13 +888,11 @@ 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 diff -Nru gedit-40.1/gedit/gedit-print-job.c gedit-41.0/gedit/gedit-print-job.c --- gedit-40.1/gedit/gedit-print-job.c 2021-04-17 05:45:36.120558300 +0000 +++ gedit-41.0/gedit/gedit-print-job.c 2022-02-14 13:58:26.000000000 +0000 @@ -23,7 +23,7 @@ #include "gedit-print-job.h" #include -#include +#include #include "gedit-debug.h" #include "gedit-document-private.h" @@ -535,7 +535,7 @@ 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); diff -Nru gedit-40.1/gedit/gedit-progress-info-bar.c gedit-41.0/gedit/gedit-progress-info-bar.c --- gedit-40.1/gedit/gedit-progress-info-bar.c 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/gedit-progress-info-bar.c 2022-02-14 13:58:26.000000000 +0000 @@ -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 -Nru gedit-40.1/gedit/gedit-progress-info-bar.h gedit-41.0/gedit/gedit-progress-info-bar.h --- gedit-40.1/gedit/gedit-progress-info-bar.h 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/gedit-progress-info-bar.h 2022-02-14 13:58:26.000000000 +0000 @@ -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 -Nru gedit-40.1/gedit/gedit-recent.c gedit-41.0/gedit/gedit-recent.c --- gedit-40.1/gedit/gedit-recent.c 2021-04-17 05:45:36.120558300 +0000 +++ gedit-41.0/gedit/gedit-recent.c 2022-02-14 13:58:26.000000000 +0000 @@ -24,7 +24,7 @@ void gedit_recent_add_document (GeditDocument *document) { - TeplFile *file; + GtkSourceFile *file; GFile *location; GtkRecentManager *recent_manager; GtkRecentData recent_data; @@ -33,8 +33,8 @@ 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) { @@ -89,4 +89,229 @@ } } +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 -Nru gedit-40.1/gedit/gedit-recent.h gedit-41.0/gedit/gedit-recent.h --- gedit-40.1/gedit/gedit-recent.h 2021-04-17 05:45:36.120558300 +0000 +++ gedit-41.0/gedit/gedit-recent.h 2022-02-14 13:58:26.000000000 +0000 @@ -27,12 +27,29 @@ G_BEGIN_DECLS -void gedit_recent_add_document (GeditDocument *document); - -void gedit_recent_remove_if_local (GFile *location); +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_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 -Nru gedit-40.1/gedit/gedit-recent-osx.c gedit-41.0/gedit/gedit-recent-osx.c --- gedit-40.1/gedit/gedit-recent-osx.c 2021-04-17 05:45:36.120558300 +0000 +++ gedit-41.0/gedit/gedit-recent-osx.c 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru gedit-40.1/gedit/gedit-recent-osx.h gedit-41.0/gedit/gedit-recent-osx.h --- gedit-40.1/gedit/gedit-recent-osx.h 2021-04-17 05:45:36.120558300 +0000 +++ gedit-41.0/gedit/gedit-recent-osx.h 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru gedit-40.1/gedit/gedit-settings.c gedit-41.0/gedit/gedit-settings.c --- gedit-40.1/gedit/gedit-settings.c 2021-04-17 05:45:36.120558300 +0000 +++ gedit-41.0/gedit/gedit-settings.c 2022-02-14 13:58:26.000000000 +0000 @@ -37,13 +37,7 @@ 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) @@ -81,46 +75,92 @@ 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); } } @@ -207,47 +247,43 @@ 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 * @@ -292,24 +328,11 @@ } gchar * -_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) +gedit_settings_get_system_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 diff -Nru gedit-40.1/gedit/gedit-settings.h gedit-41.0/gedit/gedit-settings.h --- gedit-40.1/gedit/gedit-settings.h 2021-04-17 05:45:36.120558300 +0000 +++ gedit-41.0/gedit/gedit-settings.h 2022-02-14 13:58:26.000000000 +0000 @@ -43,11 +43,7 @@ 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); @@ -73,6 +69,7 @@ #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" diff -Nru gedit-40.1/gedit/gedit-tab.c gedit-41.0/gedit/gedit-tab.c --- gedit-40.1/gedit/gedit-tab.c 2021-04-17 05:45:36.196560000 +0000 +++ gedit-41.0/gedit/gedit-tab.c 2022-02-14 13:58:26.000000000 +0000 @@ -24,7 +24,6 @@ #include #include -#include #include "gedit-app.h" #include "gedit-app-private.h" @@ -33,6 +32,7 @@ #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" @@ -143,6 +143,9 @@ static void launch_saver (GTask *saving_task); +static void continue_loading(GTask *loading_task); + + static SaverData * saver_data_new (void) { @@ -574,9 +577,9 @@ } 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); @@ -688,6 +691,14 @@ g_object_unref (loading_task); break; + + case GTK_RESPONSE_ACCEPT: + set_info_bar (data->tab, NULL, GTK_RESPONSE_NONE); + gedit_tab_set_state (data->tab, GEDIT_TAB_STATE_LOADING); + + continue_loading (loading_task); + break; + default: if (location != NULL) { @@ -726,7 +737,7 @@ { 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); @@ -757,7 +768,7 @@ 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; @@ -785,7 +796,7 @@ { 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; } @@ -804,8 +815,8 @@ * 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); } } @@ -830,7 +841,7 @@ 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 { @@ -850,7 +861,7 @@ 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, @@ -859,7 +870,7 @@ 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); @@ -871,7 +882,7 @@ 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; @@ -899,7 +910,7 @@ */ 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 @@ -913,7 +924,7 @@ 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; @@ -935,9 +946,9 @@ 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); @@ -950,7 +961,7 @@ goffset size, goffset total_size) { - TeplProgressInfoBar *progress_info_bar; + GeditProgressInfoBar *progress_info_bar; if (tab->info_bar == NULL) { @@ -959,23 +970,23 @@ 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); } } @@ -1034,7 +1045,7 @@ 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; @@ -1118,9 +1129,9 @@ } 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) { @@ -1226,7 +1237,7 @@ static void display_externally_modified_notification (GeditTab *tab) { - TeplInfoBar *info_bar; + GtkWidget *info_bar; GeditDocument *doc; GtkSourceFile *file; GFile *location; @@ -1240,9 +1251,9 @@ 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", @@ -1307,7 +1318,6 @@ GeditDocument *doc; GeditView *view; GtkSourceFile *file; - TeplFile *tepl_file; tab->state = GEDIT_TAB_STATE_NORMAL; @@ -1338,7 +1348,6 @@ 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", @@ -1346,11 +1355,10 @@ 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", @@ -1434,7 +1442,7 @@ 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))) { @@ -1467,7 +1475,7 @@ 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); @@ -1576,6 +1584,8 @@ { GdkScreen *screen; GtkIconTheme *theme; + GtkIconInfo *info; + GtkStyleContext *context; gint icon_size; screen = gtk_widget_get_screen (GTK_WIDGET (tab)); @@ -1584,7 +1594,10 @@ gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, NULL, &icon_size); - pixbuf = gtk_icon_theme_load_icon (theme, icon_name, icon_size, 0, NULL); + context = gtk_widget_get_style_context (GTK_WIDGET (tab)); + info = gtk_icon_theme_lookup_icon (theme, icon_name, icon_size, 0); + + pixbuf = gtk_icon_info_load_symbolic_for_context (info, context, NULL, NULL); } return pixbuf; @@ -1633,11 +1646,9 @@ /* 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; } @@ -1753,18 +1764,18 @@ 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 @@ -1979,12 +1990,56 @@ } static void +continue_loading(GTask *loading_task) +{ + LoaderData *data = g_task_get_task_data (loading_task); + // Pre loader + gtk_source_file_loader_load_async (data->loader, + G_PRIORITY_DEFAULT, + g_task_get_cancellable (loading_task), + (GFileProgressCallback) loader_progress_cb, + loading_task, + NULL, + (GAsyncReadyCallback) load_cb, + loading_task); +} + + + +static +guint64 get_file_size (GFile *file) +{ + GFileInfo *info; + GError *error = NULL; + guint64 res = 0; + + if (file == NULL) + { + return 0; + } + + info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, NULL, &error); + + if (error) + { + g_error_free (error); + return 0; + } + + res = g_file_info_get_size(info); + g_object_unref (info); + return res; +} + +static void launch_loader (GTask *loading_task, const GtkSourceEncoding *encoding) { LoaderData *data = g_task_get_task_data (loading_task); GSList *candidate_encodings = NULL; GeditDocument *doc; + const int MB = 1024*1024; + const int FILE_TOO_LARGE = 100*MB; if (encoding != NULL) { @@ -2010,6 +2065,47 @@ data->timer = g_timer_new (); + + GFile * file = gtk_source_file_loader_get_location (data->loader); + guint64 size = get_file_size (file); + + if (size > FILE_TOO_LARGE) + { + GtkWidget *info_bar; + GError *error = NULL; + GFile *location = gtk_source_file_loader_get_location (data->loader); + set_editable (data->tab, FALSE); + + error = g_error_new_literal (GTK_SOURCE_FILE_LOADER_ERROR, 0, ""); + error->code = GTK_SOURCE_FILE_LOADER_ERROR_TOO_BIG; + + info_bar = gedit_io_loading_error_info_bar_new (location, NULL, error); + + g_signal_connect (info_bar, + "response", + G_CALLBACK (io_loading_error_info_bar_response), + loading_task); + + set_info_bar (data->tab, info_bar, GTK_RESPONSE_CANCEL); + + if (data->tab->state == GEDIT_TAB_STATE_LOADING) + { + gtk_widget_show (GTK_WIDGET (data->tab->frame)); + gedit_tab_set_state (data->tab, GEDIT_TAB_STATE_LOADING_ERROR); + } + else + { + gedit_tab_set_state (data->tab, GEDIT_TAB_STATE_REVERTING_ERROR); + } + + successful_load (loading_task); + gedit_recent_add_document (doc); + + g_error_free (error); + return; + } + + // Pre loader gtk_source_file_loader_load_async (data->loader, G_PRIORITY_DEFAULT, g_task_get_cancellable (loading_task), @@ -2310,12 +2406,12 @@ 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 && @@ -2324,7 +2420,7 @@ /* 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, @@ -2596,6 +2692,7 @@ g_return_if_fail (GEDIT_IS_TAB (tab)); g_return_if_fail (tab->state == GEDIT_TAB_STATE_NORMAL || tab->state == GEDIT_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION || + tab->state == GEDIT_TAB_STATE_SAVING_ERROR || tab->state == GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW); g_return_if_fail (G_IS_FILE (location)); g_return_if_fail (encoding != NULL); @@ -2626,6 +2723,11 @@ set_info_bar (tab, NULL, GTK_RESPONSE_NONE); save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_MODIFICATION_TIME; } + else if (tab->state == GEDIT_TAB_STATE_SAVING_ERROR) + { + set_info_bar (tab, NULL, GTK_RESPONSE_NONE); + gedit_tab_set_state (tab, GEDIT_TAB_STATE_NORMAL); + } file = gedit_document_get_file (doc); @@ -2706,15 +2808,15 @@ 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 @@ -2824,19 +2926,21 @@ 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 diff -Nru gedit-40.1/gedit/gedit-utils.c gedit-41.0/gedit/gedit-utils.c --- gedit-40.1/gedit/gedit-utils.c 2021-04-17 05:45:36.196560000 +0000 +++ gedit-41.0/gedit/gedit-utils.c 2022-02-14 13:58:26.000000000 +0000 @@ -23,7 +23,6 @@ #include "gedit-utils.h" #include #include -#include #include "gedit-debug.h" gboolean @@ -87,6 +86,122 @@ 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) { @@ -106,7 +221,7 @@ return NULL; } - res = tepl_utils_replace_home_dir_with_tilde (str); + res = gedit_utils_replace_home_dir_with_tilde (str); g_free (str); @@ -149,10 +264,10 @@ 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) { @@ -187,6 +302,51 @@ 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) { @@ -353,7 +513,7 @@ } } 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, @@ -438,6 +598,165 @@ 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) { diff -Nru gedit-40.1/gedit/gedit-utils.h gedit-41.0/gedit/gedit-utils.h --- gedit-40.1/gedit/gedit-utils.h 2021-04-17 05:45:36.272561600 +0000 +++ gedit-41.0/gedit/gedit-utils.h 2022-02-14 13:58:26.000000000 +0000 @@ -27,19 +27,38 @@ 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); diff -Nru gedit-40.1/gedit/gedit-view.c gedit-41.0/gedit/gedit-view.c --- gedit-40.1/gedit/gedit-view.c 2021-04-17 05:45:36.276561500 +0000 +++ gedit-41.0/gedit/gedit-view.c 2022-02-14 13:58:26.000000000 +0000 @@ -24,16 +24,21 @@ #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 @@ -50,7 +55,7 @@ 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) @@ -74,22 +79,45 @@ } 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)); - tepl_signal_group_clear (&view->priv->file_signal_group); - view->priv->file_signal_group = tepl_signal_group_new (G_OBJECT (file)); + if (!GEDIT_IS_DOCUMENT (buffer)) + { + return; + } - tepl_signal_group_add (view->priv->file_signal_group, - g_signal_connect (file, - "notify::read-only", - G_CALLBACK (file_read_only_notify_cb), - view)); + view->priv->current_document = g_object_ref (GEDIT_DOCUMENT (buffer)); + + 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); } @@ -106,7 +134,7 @@ gedit_view_init (GeditView *view) { GtkTargetList *target_list; - GtkStyleContext *style_context; + GtkStyleContext *context; gedit_debug (DEBUG_VIEW); @@ -140,8 +168,13 @@ 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 @@ -150,7 +183,8 @@ 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 @@ -160,26 +194,10 @@ */ g_signal_handlers_disconnect_by_func (view, buffer_notify_cb, NULL); - G_OBJECT_CLASS (gedit_view_parent_class)->dispose (object); -} + g_clear_object (&view->priv->css_provider); + g_clear_pointer (&view->priv->font_desc, pango_font_description_free); -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); -} - -static void -fonts_changed_cb (GeditSettings *settings, - GeditView *view) -{ - update_font (view); + G_OBJECT_CLASS (gedit_view_parent_class)->dispose (object); } static void @@ -188,18 +206,27 @@ 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", @@ -720,4 +747,217 @@ 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 -Nru gedit-40.1/gedit/gedit-view-centering.c gedit-41.0/gedit/gedit-view-centering.c --- gedit-40.1/gedit/gedit-view-centering.c 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/gedit-view-centering.c 2022-02-14 13:58:26.000000000 +0000 @@ -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 -Nru gedit-40.1/gedit/gedit-view-centering.h gedit-41.0/gedit/gedit-view-centering.h --- gedit-40.1/gedit/gedit-view-centering.h 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/gedit-view-centering.h 2022-02-14 13:58:26.000000000 +0000 @@ -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 -Nru gedit-40.1/gedit/gedit-view-frame.c gedit-41.0/gedit/gedit-view-frame.c --- gedit-40.1/gedit/gedit-view-frame.c 2021-04-17 05:45:36.276561500 +0000 +++ gedit-41.0/gedit/gedit-view-frame.c 2022-02-14 13:58:26.000000000 +0000 @@ -3,7 +3,7 @@ * 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 @@ -28,6 +28,7 @@ #include #include +#include "gedit-view-centering.h" #include "gedit-debug.h" #include "gedit-utils.h" #include "gedit-settings.h" @@ -53,7 +54,11 @@ { GtkOverlay parent_instance; + GSettings *editor_settings; + GeditView *view; + GeditViewCentering *view_centering; + GtkFrame *map_frame; SearchMode search_mode; @@ -159,6 +164,7 @@ 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); @@ -213,7 +219,7 @@ 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) @@ -297,7 +303,7 @@ 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); } @@ -1061,6 +1067,7 @@ gchar **split_text = NULL; const gchar *text; GtkTextIter iter; + GeditDocument *doc; entry_text = gtk_entry_get_text (GTK_ENTRY (frame->search_entry)); @@ -1116,8 +1123,11 @@ 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) { @@ -1428,6 +1438,8 @@ 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); @@ -1454,6 +1466,13 @@ 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); @@ -1551,6 +1570,14 @@ 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) { diff -Nru gedit-40.1/gedit/gedit-view-frame.h gedit-41.0/gedit/gedit-view-frame.h --- gedit-40.1/gedit/gedit-view-frame.h 2021-04-17 05:45:36.276561500 +0000 +++ gedit-41.0/gedit/gedit-view-frame.h 2022-02-14 13:58:26.000000000 +0000 @@ -24,6 +24,7 @@ #include #include "gedit-document.h" #include "gedit-view.h" +#include "gedit-view-centering.h" G_BEGIN_DECLS @@ -32,6 +33,9 @@ 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); diff -Nru gedit-40.1/gedit/gedit-view.h gedit-41.0/gedit/gedit-view.h --- gedit-40.1/gedit/gedit-view.h 2021-04-17 05:45:36.276561500 +0000 +++ gedit-41.0/gedit/gedit-view.h 2022-02-14 13:58:26.000000000 +0000 @@ -22,8 +22,10 @@ #ifndef GEDIT_VIEW_H #define GEDIT_VIEW_H +#include + #include -#include +#include G_BEGIN_DECLS @@ -40,7 +42,7 @@ struct _GeditView { - TeplView view; + GtkSourceView view; /*< private >*/ GeditViewPrivate *priv; @@ -48,7 +50,7 @@ struct _GeditViewClass { - TeplViewClass parent_class; + GtkSourceViewClass parent_class; void (*drop_uris) (GeditView *view, gchar **uri_list); @@ -60,6 +62,22 @@ 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 */ diff -Nru gedit-40.1/gedit/gedit-window.c gedit-41.0/gedit/gedit-window.c --- gedit-40.1/gedit/gedit-window.c 2021-04-17 05:45:36.276561500 +0000 +++ gedit-41.0/gedit/gedit-window.c 2022-02-14 13:58:26.000000000 +0000 @@ -28,11 +28,11 @@ #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" @@ -40,6 +40,7 @@ #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" @@ -54,6 +55,11 @@ #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 { @@ -158,9 +164,9 @@ 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); @@ -231,8 +237,6 @@ */ remove_actions (window); - window->priv->fullscreen_open_recent_button = NULL; - G_OBJECT_CLASS (gedit_window_parent_class)->dispose (object); } @@ -247,6 +251,22 @@ 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) @@ -267,6 +287,10 @@ } } + gedit_multi_notebook_foreach_tab (window->priv->multi_notebook, + (GtkCallback)update_view_centering, + GBOOLEAN_TO_POINTER (is_fullscreen)); + #ifndef OS_OSX if (is_fullscreen) { @@ -312,7 +336,7 @@ 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); } @@ -454,6 +478,7 @@ 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); @@ -466,10 +491,11 @@ 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); } @@ -765,8 +791,48 @@ } 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; @@ -776,14 +842,14 @@ 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; @@ -793,13 +859,13 @@ 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); @@ -829,20 +895,20 @@ 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 * @@ -1044,8 +1110,8 @@ { 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; } @@ -1063,8 +1129,8 @@ * 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); } } @@ -1690,88 +1756,84 @@ 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; + + 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)); - return GDK_EVENT_PROPAGATE; -} + window->priv->in_fullscreen_eventbox = FALSE; -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; + 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); } @@ -1885,7 +1947,7 @@ 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, @@ -2144,10 +2206,23 @@ } 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 @@ -2538,6 +2613,18 @@ } 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, @@ -2609,76 +2696,6 @@ } 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; @@ -2692,6 +2709,7 @@ 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"); @@ -2705,8 +2723,6 @@ 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, @@ -2716,9 +2732,32 @@ 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) { @@ -2733,9 +2772,14 @@ 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 */ @@ -2849,6 +2893,12 @@ 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 ()), diff -Nru gedit-40.1/gedit/gedit-window-private.h gedit-41.0/gedit/gedit-window-private.h --- gedit-40.1/gedit/gedit-window-private.h 2021-04-17 05:45:36.276561500 +0000 +++ gedit-41.0/gedit/gedit-window-private.h 2022-02-14 13:58:26.000000000 +0000 @@ -27,6 +27,7 @@ #include "gedit-message-bus.h" #include "gedit-settings.h" #include "gedit-multi-notebook.h" +#include "gedit-open-document-selector.h" G_BEGIN_DECLS @@ -53,12 +54,15 @@ 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; @@ -79,7 +83,10 @@ 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; diff -Nru gedit-40.1/gedit/meson.build gedit-41.0/gedit/meson.build --- gedit-40.1/gedit/meson.build 2021-04-17 05:45:36.276561500 +0000 +++ gedit-41.0/gedit/meson.build 2022-02-14 13:58:26.000000000 +0000 @@ -8,6 +8,7 @@ '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', @@ -27,11 +28,13 @@ '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', ] @@ -45,30 +48,37 @@ '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', ] @@ -85,20 +95,26 @@ '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', @@ -117,6 +133,7 @@ libgedit_deps = [ deps_basic_list, libgd_dep, + libxml_dep, ] if host_machine.system() == 'darwin' @@ -197,10 +214,12 @@ install_dir_typelib: get_option('libdir') / 'gedit/girepository-1.0', ) -python3.install_sources( - 'Gedit.py', - subdir: 'gi/overrides', -) +if get_option('python') + python3.install_sources( + 'Gedit.py', + subdir: 'gi/overrides', + ) +endif # Vala API libgedit_vapi = gnome.generate_vapi( diff -Nru gedit-40.1/gedit/resources/css/gedit.adwaita.css gedit-41.0/gedit/resources/css/gedit.adwaita.css --- gedit-40.1/gedit/resources/css/gedit.adwaita.css 2021-04-17 05:45:36.276561500 +0000 +++ gedit-41.0/gedit/resources/css/gedit.adwaita.css 2022-02-14 13:58:26.000000000 +0000 @@ -1,3 +1,28 @@ +.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; } diff -Nru gedit-40.1/gedit/resources/css/gedit-style.css gedit-41.0/gedit/resources/css/gedit-style.css --- gedit-40.1/gedit/resources/css/gedit-style.css 2021-04-17 05:45:36.276561500 +0000 +++ gedit-41.0/gedit/resources/css/gedit-style.css 2022-02-14 13:58:26.000000000 +0000 @@ -14,6 +14,18 @@ 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; diff -Nru gedit-40.1/gedit/resources/gedit.gresource.xml.in gedit-41.0/gedit/resources/gedit.gresource.xml.in --- gedit-40.1/gedit/resources/gedit.gresource.xml.in 2021-04-17 05:45:36.276561500 +0000 +++ gedit-41.0/gedit/resources/gedit.gresource.xml.in 2022-02-14 13:58:26.000000000 +0000 @@ -8,10 +8,14 @@ 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 diff -Nru gedit-40.1/gedit/resources/ui/gedit-highlight-mode-dialog.ui gedit-41.0/gedit/resources/ui/gedit-highlight-mode-dialog.ui --- gedit-40.1/gedit/resources/ui/gedit-highlight-mode-dialog.ui 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/resources/ui/gedit-highlight-mode-dialog.ui 2022-02-14 13:58:26.000000000 +0000 @@ -0,0 +1,87 @@ + + + + + diff -Nru gedit-40.1/gedit/resources/ui/gedit-highlight-mode-selector.ui gedit-41.0/gedit/resources/ui/gedit-highlight-mode-selector.ui --- gedit-40.1/gedit/resources/ui/gedit-highlight-mode-selector.ui 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/resources/ui/gedit-highlight-mode-selector.ui 2022-02-14 13:58:26.000000000 +0000 @@ -0,0 +1,83 @@ + + + + + + + + + + + + + liststore + + + diff -Nru gedit-40.1/gedit/resources/ui/gedit-open-document-selector.ui gedit-41.0/gedit/resources/ui/gedit-open-document-selector.ui --- gedit-40.1/gedit/resources/ui/gedit-open-document-selector.ui 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/resources/ui/gedit-open-document-selector.ui 2022-02-14 13:58:26.000000000 +0000 @@ -0,0 +1,115 @@ + + + + + diff -Nru gedit-40.1/gedit/resources/ui/gedit-preferences-dialog.ui gedit-41.0/gedit/resources/ui/gedit-preferences-dialog.ui --- gedit-40.1/gedit/resources/ui/gedit-preferences-dialog.ui 2021-04-17 05:45:36.368563400 +0000 +++ gedit-41.0/gedit/resources/ui/gedit-preferences-dialog.ui 2022-02-14 13:58:26.000000000 +0000 @@ -106,6 +106,21 @@ + + Display _overview map + True + True + False + True + True + + + 0 + 3 + 2 + + + Display _grid pattern True @@ -116,7 +131,7 @@ 0 - 3 + 4 2 @@ -630,8 +645,19 @@ True True - + True + True + True + True + etched-in + 200 + + + True + True + + 0 diff -Nru gedit-40.1/gedit/resources/ui/gedit-progress-info-bar.ui gedit-41.0/gedit/resources/ui/gedit-progress-info-bar.ui --- gedit-40.1/gedit/resources/ui/gedit-progress-info-bar.ui 1970-01-01 00:00:00.000000000 +0000 +++ gedit-41.0/gedit/resources/ui/gedit-progress-info-bar.ui 2022-02-14 13:58:26.000000000 +0000 @@ -0,0 +1,88 @@ + + + + + diff -Nru gedit-40.1/gedit/resources/ui/gedit-view-frame.ui gedit-41.0/gedit/resources/ui/gedit-view-frame.ui --- gedit-40.1/gedit/resources/ui/gedit-view-frame.ui 2021-04-17 05:45:36.368563400 +0000 +++ gedit-41.0/gedit/resources/ui/gedit-view-frame.ui 2022-02-14 13:58:26.000000000 +0000 @@ -7,15 +7,33 @@ False False - + True - True - True - False - + True - True + True + True + + + True + True + + + + + + + True + + + + True + view + + diff -Nru gedit-40.1/gedit/resources/ui/gedit-window.ui gedit-41.0/gedit/resources/ui/gedit-window.ui --- gedit-40.1/gedit/resources/ui/gedit-window.ui 2021-04-17 05:45:36.368563400 +0000 +++ gedit-41.0/gedit/resources/ui/gedit-window.ui 2022-02-14 13:58:26.000000000 +0000 @@ -28,6 +28,50 @@ 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 @@ -310,7 +354,7 @@ False start - + True False False @@ -319,6 +363,47 @@ 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 diff -Nru gedit-40.1/gedit.doap gedit-41.0/gedit.doap --- gedit-40.1/gedit.doap 2021-04-17 05:45:35.404543200 +0000 +++ gedit-41.0/gedit.doap 2022-02-14 13:58:26.000000000 +0000 @@ -29,6 +29,7 @@ +