--- Begin Message ---
- To: Debian Bug Tracking System <submit@bugs.debian.org>
- Subject: buster-pu: package thunar/1.8.17-1
- From: Yves-Alexis Perez <corsac@debian.org>
- Date: Thu, 20 May 2021 15:25:02 +0200
- Message-id: <162151710265.646640.5790345330233042524.reportbug@scapa>
Package: release.debian.org
Severity: normal
Tags: buster
User: release.debian.org@packages.debian.org
Usertags: pu
X-Debbugs-Cc: xfce-devel@lists.debian.org
Hi release team
this is a pre-approval request for updating Thunar in stable, from 1.8.4
to 1.8.17.
The context is the recently found vulnerability CVE-2021-32563
(#988394), which has been fixed in 1.8.17.
With my security team hat on, I don't think it really desserves a DSA
with an isolated fix, but (with my Xfce maintainer hat on) I think it
would make sense to fix it in a point update, along with the various
bugfixes and translation updates that Thunar had since the freeze.
I've not yet done the packaging work (so I don't mess my local
repository) but the diff between the two upstream tags is attached.
Thanks in advance,
--
Yves-Alexis
diff --git a/.gitignore b/.gitignore
index 9fbb0a34..7c510800 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,6 +32,7 @@ core
*.service
*.policy
org.xfce.thunar.appdata.xml
+thunar.appdata.xml
gtk-doc.make
ThunarBulkRename
Thunar.spec
@@ -109,6 +110,7 @@ thunar/thunar-dbus-freedesktop-interfaces.[ch]
thunar/thunar-dbus-service-infos.[ch]
thunar/thunar-fallback-icon.c
thunar/thunar-thumbnail-cache-proxy.[ch]
+thunar/thunar-thumbnail-frame.c
thunar/thunar-thumbnailer-manager-proxy.h
thunar/thunar-thumbnailer-proxy.[ch]
thunar/thunar-marshal.[ch]
diff --git a/HACKING b/HACKING
index ca01ce77..4c0d0aac 100644
--- a/HACKING
+++ b/HACKING
@@ -1,7 +1,7 @@
Bug tracking system
===================
-Thunar uses the Xfce bug tracking system at http://bugzilla.xfce.org/,
+Thunar uses the Xfce bug tracking system at https://bugzilla.xfce.org/,
hosted and maintained by the Xfce project.
@@ -23,7 +23,7 @@ Feature requests
================
Please file feature requests to the Xfce bug tracking system
-(http://buzilla.xfce.org, product Thunar) with a Severity of
+(https://buzilla.xfce.org, product Thunar) with a Severity of
enhancement. Make sure that your feature request wasn't reported
already before; requesting a feature several times won't increase
the changed that it gets added!
diff --git a/Makefile.am b/Makefile.am
index cb2db7a0..f43aac8d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -61,9 +61,8 @@ ThunarBulkRename: ThunarBulkRename.in Makefile
desktopdir = $(datadir)/applications
desktop_in_in_files = \
- Thunar.desktop.in.in \
- Thunar-bulk-rename.desktop.in.in \
- Thunar-folder-handler.desktop.in.in
+ thunar.desktop.in.in \
+ thunar-bulk-rename.desktop.in.in
desktop_in_files = $(desktop_in_in_files:.desktop.in.in=.desktop.in)
%.desktop.in: %.desktop.in.in Makefile
$(AM_V_GEN) $(SED) -e "s,\@HELPERDIR\@,$(HELPER_PATH_PREFIX),g" < $< > $@
diff --git a/NEWS b/NEWS
index ae435d21..f0022ffd 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,231 @@
+1.8.17
+======
+- Dont execute files, passed via command line due to security risks
+ That Fixes CVE-2021-32563
+
+- Fix combo box entry order (Issue #435)
+- Translation Updates:
+ Albanian, Amharic, Arabic, Armenian, Armenian (Armenia), Asturian,
+ Basque, Belarusian, Bengali, Bulgarian, Catalan, Chinese (China),
+ Chinese (Hong Kong), Chinese (Taiwan), Croatian, Czech, Danish,
+ Dutch, Eastern Armenian, English (Australia), English (United
+ Kingdom), Esperanto, Estonian, Finnish, French, Galician, German,
+ Greek, Hebrew, Hungarian, Icelandic, Indonesian, Interlingue,
+ Italian, Japanese, Kazakh, Korean, Latvian, Lithuanian, Malay,
+ Norwegian Bokmål, Norwegian Nynorsk, Occitan (post 1500), Panjabi
+ (Punjabi), Persian (Iran), Polish, Portuguese, Portuguese (Brazil),
+ Romanian, Russian, Serbian, Slovak, Spanish, Swedish, Telugu, Thai,
+ Turkish, Ukrainian, Urdu, Urdu (Pakistan), Vietnamese
+
+1.8.16
+======
+- Add missing parameter to ThunarBrowserPokeDeviceFunc function
+- Fix error for custom date format in details view (issue #389)
+- Fix unavailable rubber banding in detailed view (Issue #326)
+- Ghost file ocasionally remains when dropping file into directory (Fixes #312)
+- Translation Updates:
+ Albanian, Armenian, Armenian (Armenia), Basque, Belarusian, Chinese
+ (China), Chinese (Hong Kong), Croatian, Eastern Armenian, Esperanto,
+ Estonian, Finnish, French, Hebrew, Hungarian, Indonesian, Interlingue,
+ Italian, Kazakh, Korean, Lithuanian, Portuguese, Slovak, Swedish,
+
+1.8.15
+======
+- Only open devices after successful mount attempt (Bug #16831)
+- Fix shortcut support for addressbar (Bug #4537 and Bug #13680)
+- Fix crash in bulk renamer on repeated rename (Bug #16824)
+- Add checks for thumbnailer 0 handles (Bug #14122)
+- Replace 'thunar_return_if_fail (THUNAR_IS_DEVICE (device))' with
+standard 'if (..)' to prevent possible crashes. (Bug #13404)
+- Fix check if folder is fully loaded when expanding path in tree view.
+Prevents 100% CPU load and loosing sync with main view in some cases.
+(Bug #15762)
+- Fixes 100%CPU on tree-view in some rare cases (Bug #16024)
+- Delete native files faster (Bug #16641)
+- Support libxfce4ui XfceTitledDialog new API (Bug #16616)
+- Translation Updates:
+ Albanian, Amharic, Arabic, Armenian, Armenian (Armenia), Basque,
+ Belarusian, Bengali, Bulgarian, Catalan, Chinese (China), Chinese (Hong
+ Kong), Chinese (Taiwan), Croatian, Czech, Danish, Dutch, English
+ (Australia), English (United Kingdom), Esperanto, Estonian, Finnish,
+ French, Galician, German, Greek, Hebrew, Hungarian, Icelandic,
+ Indonesian, Interlingue, Italian, Japanese, Kazakh, Korean, Latvian,
+ Lithuanian, Malay, Norwegian Bokmål, Norwegian Nynorsk, Occitan (post
+ 1500), Panjabi (Punjabi), Persian (Iran), Polish, Portuguese,
+ Portuguese (Brazil), Romanian, Russian, Serbian, Slovak, Spanish,
+ Swedish, Telugu, Thai, Turkish, Uighur, Ukrainian, Urdu, Urdu
+ (Pakistan), Vietnamese
+
+1.8.14
+======
+- Revert "Allow opening of multiple file selections (bug #2487)",
+because it introduced a regression (Not possible any more to DnD
+multiple files in icon/compact view)
+- Translation Updates: Portuguese
+
+1.8.13
+======
+- Use tre-view toplevel path of the cursor, if available, in order to
+prevent jumping (Bug #16024)
+- Increase vertical gap between icon and its label slightly (Bug #16041)
+- Fix crash when inserting USB device in tree-view mode. (Bug #15172)
+- Fix jump to Home when ejecting a currently viewed device (Bug #16504)
+- Allow context menu when editing location in pathbar (Bug #16483)
+- Sort device entries in tree view (Bug #16471)
+- Allow to open multiple files at once (Bug #2487)
+- Fix incorrect pathbar autocomplete (Bug #16267)
+- Avoid unreadable names in detailed view (Bug #16391)
+- Prevent crash when renaming files (Bug #10805)
+- Translation Updates:
+ Belarusian, Croatian, Finnish, French, Hebrew, Indonesian, Kazakh,
+ Malay, Portuguese, Portuguese (Brazil)
+
+1.8.12
+======
+- NULL is the proper sentinel for g_object_new() (Bug #16310)
+- Drop timer on finalize (Bug #15305)
+- Store column width setting asynchronously and only once (Bug #15305)
+- When move to trash fails, ask whether to delete files (Bug #15975)
+- Ctrl+Mousewheel does not enlarge/shrink entries (for detailed list
+view) (Bug #15936)
+- Extra padding for Eject button when scrollbar is visible (Bug #15312)
+- Use standard icon instead of custom
+- Translation Updates: Albanian, Chinese (China), Chinese (Taiwan), Croatian,
+ Czech, Dutch, French, Galician, Greek, Hungarian, Italian, Japanese,
+ Norwegian Bokmål, Portuguese, Portuguese (Brazil), Russian, Serbian, Slovak,
+ Spanish, Swedish, Ukrainian
+
+1.8.11
+======
+- Thunar 1.8.10 crashing on startup in FreeBSD and Fedora, caused by
+nonfunctional pango version check (Bug #16136, Bug #16138)
+- Translation Updates:
+Interlingue, Spanish
+
+1.8.10
+======
+- Allow compilation with panel 4.15
+- thunar-job: callee should keep track of the number of processed files
+(Bug #16117)
+- Thunar does not show a context menu on right-click when started via
+trash-panel-plugin (Bug #16000)
+- Make sure icon text is centered after unchecking "Text beside icons"
+- Remove the vertical gap between icon and its label (Bug #16041)
+- Fix icon view alignment (Bug #16107)
+- Not possible to grab scrollbar on the very right pixels when Thunar
+is maximized (Bug #16050)
+- Wrap text of error dialog
+- Not possible to empty the trash via the pathbar context menu
+- Crash on refresh if remote folder has been removed (Bug #15961)
+- Center action buttons in conflict dialog window (Bug #15973) -
+Prevent usage of deprecated gtk_dialog_get_action_area
+- Ensure user customizable action uses currently selected file path (Bug #15119)
+- make filename label selectable in conflict dialog window
+- Center action buttons in conflict dialog window (Bug #15973)
+- Clear user customizable action shortcut when the action is deleted
+- Prevent Gtk-CRITICAL when adding or modifying a user customizable action.
+- Thunar SendTo Email: Add missing archive formats for archive
+detection (Bug #15917)
+- sendto plugin: fix content type resolution. (Bug #15916)
+- sendto plugin: extract function tse_file_is_archive (Bug #15916)
+- sendto plugin: move g_file_info_get_content_type() call out of the
+cycle (Bug #15916)
+- All glory to lowercase (Bug #15394)
+- mismatched names between thunar.appdata.xml and thunar.desktop (Bug #15498)
+- Replace text "Enter the new name:" by "Enter the name:" for file
+creation dialog (Bug #15423)
+- Remove superfluous .desktop file "Thunar-folder-handler.desktop.in"
+(Bug #15467)
+- Prevent unnecessary fallback copy-delete in file move when overwriting
+- Fix possible memory leak
+- Fix popup menus size (Bug #15832)
+- Add Alt+D as alternative accelerator for Open Location (Bug #15828)
+- Do not insert hyphens at intra-word line breaks (Bug #15856)
+- Translation Updates:
+ Albanian, Arabic, Belarusian, Bulgarian, Catalan, Chinese (Taiwan),
+ Croatian, Danish, Dutch, English (United Kingdom), French, Galician,
+ German, Hungarian, Italian, Japanese, Korean, Lithuanian, Malay,
+ Norwegian Bokmål, Persian (Iran), Polish, Portuguese, Portuguese
+ (Brazil), Russian, Serbian, Slovak, Slovenian, Spanish, Thai, Turkish,
+ Ukrainian
+
+1.8.9
+======
+- Remove 'auto-expand folders' from tree-view since it causes bad
+usability with keyboard (Bug #15743)
+- preferences: Add button icons to Help/Close
+- Use designated initializer to avoid compile warnings (Bug #15734)
+- Prevent premature disposal of clipboard manager (Bug #15635)
+- Keep "Open with" menu items updated (Bug #15530)
+- Translation Updates: Norwegian Bokmål, Norwegian Nynorsk, Portuguese,
+Portuguese (Brazil), Turkish
+
+1.8.8
+=====
+- Do not register "send to" as last used app (Bug #14118)
+- Use https where possible
+- Dont restart the folder monitor on each refresh (Bug #13364)
+- Fix XML declaratation in uca.xml (Bug #13623)
+- Always show the executable checkbox (Bug #15605)
+- Replace Trash action with Delete as needed (Bug #15352)
+- Translation updates: Armenian, Finnish, Kazakh,
+Portuguese (Brazil), Swedish, Thai, Turkish
+
+1.8.7
+=====
+- Fix crash on unmounted volume in tree pane right click (Bug #15452)
+- Do not check G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE anymore (Bug #15367)
+- Deactivate "Move to Trash" menu entry on volumes without trash (Bug #15352)
+- thunar-sendto-email.desktop: use xdg mail-send icon
+- Restore "Empty File" menu icon (Bug #15540)
+- Rename Camelcase to Title Case (Bug #15579)
+- Update mimeapps.list only when necessary (Bug #15533)
+- Prevent new bookmarks on sidebar when dragging files (Bug #14921)
+- Translation updates: Albanian, Armenian (Armenia), Belarusian, Catalan,
+Chinese (China), Chinese (Taiwan), Croatian, Czech, Danish,
+English (Australia), Finnish, French, Galician, German, Hebrew, Hungarian,
+Interlingue, Italian, Japanese, Malay, Norwegian Nynorsk, Portuguese, Russian,
+Serbian, Spanish, Thai, Turkish
+
+1.8.6
+=====
+- Job is now optional for thunar_io_scan_directory
+- Expand scroll window of file operation progress dialog (Bug #14946)
+- Fix compiler error -Wcast-function-type (GCC 8)
+- Bump glib minimal required version
+- Fix g_type_class_add_private is deprecated
+- Small code cleanup
+- Fix pathbar to on middle click open folders in new tabs (Bug #15302)
+- Translation updates: Danish
+
+1.8.5
+=====
+- Do not exit when dbus name registration fails (Bug #15149)
+- tree view jumps (scrolls) when clicking on a directory (Bug #15174)
+- Correctly check if destination is writable (Bug #14718)
+- Make tree-view 'Move to Trash' icon the same as in main pane
+- Make toggle for the delete entry affect tree-view side pane too
+- Pathbar buttons are now resized on folder rename (#15024)
+- Load templates synchronously (Bug #15200)
+- delete key in tree-view can delete the user home folder (Bug #15095)
+- Hide unneeded context menu entries for folder "Trash" in tree view
+- crash after clicking when XDG_SESSION_TYPE isn't set (Bug #15366)
+- man page incorrectly suggests '-v' instead of '-V'
+- Fix how wallpaper is set on Gnome
+- SEGV (11) on USB-flash connection (Bug #13813)
+- Fix session startup priority
+- Fix queued context menu popup
+- Restore right-click drag and drop functionality (Bug #14583)
+- Translation updates: Albanian, Amharic, Arabic, Asturian, Basque, Belarusian,
+Bengali, Bulgarian, Catalan, Chinese (China), Chinese (Hong Kong SAR China),
+Chinese (Taiwan), Croatian, Czech, Danish, Dutch, English (Australia),
+English (United Kingdom), Esperanto, Estonian, Finnish, French, Galician,
+German, Greek, Hebrew, Hungarian, Icelandic, Indonesian, Interlingue, Italian,
+Japanese, Kazakh, Korean, Latvian, Lithuanian, Malay, Norwegian Bokmål,
+Norwegian Nynorsk, Occitan, Persian (Iran), Polish, Portuguese,
+Portuguese (Brazil), Punjabi, Romanian, Russian, Serbian, Slovak, Slovenian,
+Spanish, Swedish, Telugu, Thai, Turkish, Urdu, Urdu (Pakistan), Uyghur, Vietnamese
+
1.8.4
=====
- renamed org.freedesktop.FileManager1.service.in to
diff --git a/README b/README
index 4ab6c1b4..be4ca73d 100644
--- a/README
+++ b/README
@@ -60,32 +60,32 @@ Standards compliance
Thunar supports the following standards/specifications:
* XDG Base Directory Specification
- http://freedesktop.org/wiki/Standards_2fbasedir_2dspec
+ https://freedesktop.org/wiki/Specifications/basedir-spec
* Shared MIME Database Specification
- http://freedesktop.org/wiki/Standards_2fshared_2dmime_2dinfo_2dspec
+ https://freedesktop.org/wiki/Specifications/shared-mime-info-spec
* X Direct Save (XDS) Protocol for the X Window System
- http://freedesktop.org/wiki/Standards_2fdirect_2dsave
+ https://freedesktop.org/wiki/Specifications/direct-save
* Icon Theme Specification
- http://freedesktop.org/wiki/Standards_2ficon_2dtheme_2dspec
+ https://freedesktop.org/wiki/Specifications/icon-theme-spec
* Thumbnail Managing Standard
- http://jens.triq.net/thumbnail-spec/index.html
+ https://freedesktop.org/wiki/Specifications/thumbnails
* File URI Specification
- http://freedesktop.org/wiki/Standards_2ffile_2duri_2dspec
+ https://freedesktop.org/wiki/Specifications/file-uri-spec
* Desktop Trash Can Specification
- http://freedesktop.org/wiki/Standards_2ftrash_2dspec
+ https://freedesktop.org/wiki/Specifications/trash-spec
How to report bugs?
===================
Bugs should be reported to the Xfce bug tracking system
-(http://bugzilla.xfce.org, product Thunar). You will need to
+(https://bugzilla.xfce.org, product Thunar). You will need to
create an account for yourself.
Please read the HACKING file for information on where to send
diff --git a/Thunar-folder-handler.desktop.in.in b/Thunar-folder-handler.desktop.in.in
deleted file mode 100644
index c3865c47..00000000
--- a/Thunar-folder-handler.desktop.in.in
+++ /dev/null
@@ -1,15 +0,0 @@
-[Desktop Entry]
-_Name=Open Folder with Thunar
-_Comment=Open the specified folders in Thunar
-_GenericName=Open Folder
-TryExec=Thunar
-Exec=thunar %F
-Icon=Thunar
-NoDisplay=true
-Terminal=false
-StartupNotify=true
-Type=Application
-Categories=System;Utility;Core;GTK;FileTools;FileManager;
-MimeType=inode/directory;
-
-# vi:set encoding=UTF-8:
diff --git a/autogen.sh b/autogen.sh
index e5e6f6b8..2c6f7940 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -24,7 +24,7 @@
autogen.sh: You don't seem to have the Xfce development tools installed on
your system, which are required to build this software.
Please install the xfce4-dev-tools package first, it is available
- from http://www.xfce.org/.
+ from https://www.xfce.org/.
EOF
exit 1
}
diff --git a/configure.ac.in b/configure.ac.in
index 067af58e..31a5170f 100644
--- a/configure.ac.in
+++ b/configure.ac.in
@@ -26,7 +26,7 @@ m4_define([thunarx_verinfo], [0:0:0])
m4_define([thunarx_version_api], [3])
m4_define([thunar_version_major], [1])
m4_define([thunar_version_minor], [8])
-m4_define([thunar_version_micro], [4])
+m4_define([thunar_version_micro], [17])
m4_define([thunar_version_nano], [])
m4_define([thunar_version_build], [@REVISION@])
m4_define([thunar_version_tag], [])
@@ -40,8 +40,8 @@ m4_define([thunar_debug_default], [ifelse(thunar_version_tag(), [git], [yes], [m
dnl ***************************
dnl *** Initialize autoconf ***
dnl ***************************
-AC_COPYRIGHT([Copyright (c) 2004-2015 The Thunar development team. All rights reserved.])
-AC_INIT([Thunar], [thunar_version], [http://bugzilla.xfce.org/], [Thunar])
+AC_COPYRIGHT([Copyright (c) 2004-2019 The Thunar development team. All rights reserved.])
+AC_INIT([thunar], [thunar_version], [https://bugzilla.xfce.org/], [thunar])
AC_PREREQ([2.60])
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_TARGET()
@@ -146,16 +146,17 @@ dnl ***********************************
dnl *** Check for required packages ***
dnl ***********************************
XDT_CHECK_PACKAGE([EXO], [exo-2], [0.12.0])
-XDT_CHECK_PACKAGE([GLIB], [glib-2.0], [2.30.0])
-XDT_CHECK_PACKAGE([GIO], [gio-2.0], [2.30.0])
-XDT_CHECK_PACKAGE([GTHREAD], [gthread-2.0], [2.30.0])
-XDT_CHECK_PACKAGE([GMODULE], [gmodule-2.0], [2.30.0])
+XDT_CHECK_PACKAGE([GLIB], [glib-2.0], [2.42.0])
+XDT_CHECK_PACKAGE([GIO], [gio-2.0], [2.42.0])
+XDT_CHECK_PACKAGE([GTHREAD], [gthread-2.0], [2.42.0])
+XDT_CHECK_PACKAGE([GMODULE], [gmodule-2.0], [2.42.0])
XDT_CHECK_PACKAGE([GTK], [gtk+-3.0], [3.22.0])
XDT_CHECK_PACKAGE([GDK_PIXBUF], [gdk-pixbuf-2.0], [2.14.0])
XDT_CHECK_PACKAGE([LIBXFCE4UTIL], [libxfce4util-1.0], [4.12.0])
XDT_CHECK_PACKAGE([LIBXFCE4UI], [libxfce4ui-2], [4.12.0])
XDT_CHECK_PACKAGE([LIBXFCE4KBD_PRIVATE], [libxfce4kbd-private-3], [4.12.0])
XDT_CHECK_PACKAGE([XFCONF], [libxfconf-0], [4.12.0])
+XDT_CHECK_PACKAGE([PANGO], [pango], [1.38.0])
dnl ******************************
dnl *** GObject Instrospection ***
diff --git a/docs/Thunar.xml b/docs/Thunar.xml
index a2281744..531e1a5e 100644
--- a/docs/Thunar.xml
+++ b/docs/Thunar.xml
@@ -48,9 +48,9 @@
<refsect1>
<title>Invocation</title>
<para>
- <command>Thunar</command> takes a list of <replaceable>URI</replaceable>s for folders that should be
- opened in new file manager windows or files that should be run using the default application for their
- types. The <replaceable>URI</replaceable>s may be specified as either <emphasis role="bold">file:</emphasis>
+ <command>Thunar</command> takes a list of <replaceable>URI</replaceable>s for files/folders that should be
+ opened in new file manager windows.
+ The <replaceable>URI</replaceable>s may be specified as either <emphasis role="bold">file:</emphasis>
or <emphasis role="bold">trash:</emphasis> URIs, absolute paths or paths relative to the current directory
from which <command>Thunar</command> is being invoked. If no <replaceable>URI</replaceable>s are specified,
the current folder will be opened in a new file manager window.
@@ -72,7 +72,7 @@
</varlistentry>
<varlistentry>
- <term><option>-v</option>, <option>--version</option></term>
+ <term><option>-V</option>, <option>--version</option></term>
<listitem>
<para>Print version information and exit.</para>
</listitem>
diff --git a/docs/reference/thunarx/thunarx-docs.xml b/docs/reference/thunarx/thunarx-docs.xml
index d41bb2b5..4a1f2cbe 100644
--- a/docs/reference/thunarx/thunarx-docs.xml
+++ b/docs/reference/thunarx/thunarx-docs.xml
@@ -42,7 +42,7 @@
any later version published by the Free Software Foundation; with no
Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
Texts. The complete license text is available from the <ulink
- type="http" url="http://www.gnu.org/">Free Software Foundation</ulink>.
+ type="http" url="https://www.gnu.org/">Free Software Foundation</ulink>.
</para>
</legalnotice>
@@ -80,7 +80,7 @@
<para>
It is based on the <ulink type="http"
- url="http://library.gnome.org/devel/gobject/unstable/chapter-gtype.html">GLib Dynamic Type
+ url="https://developer.gnome.org/gobject/unstable/chapter-gtype.html">GLib Dynamic Type
System</ulink> and loads the extensions on demand to reduce the system resources
allocated for the file manager process.
</para>
@@ -106,7 +106,7 @@
<listitem>
Provide basic compatibility with the <ulink type="http"
- url="http://www.gnome.org/projects/nautilus/">Nautilus</ulink> Extension Framework,
+ url="https://www.gnome.org/projects/nautilus/">Nautilus</ulink> Extension Framework,
so vendors don't need to write several versions of their extensions for the various
file managers. With the current implementation it should be easy to write a small
wrapper library for generic extensions that can be loaded into both Thunar and
@@ -119,10 +119,10 @@
therefore people that already know how to write Nautilus extensions must be
careful when writing extensions for Thunar, because Thunar actually unloads the
extension when it's no longer needed. The <ulink type="http"
- url="http://library.gnome.org/devel/gobject/unstable/GTypePlugin.html">GTypePlugin</ulink>
+ url="https://developer.gnome.org/gobject/unstable/GTypePlugin.html">GTypePlugin</ulink>
and <ulink type="http"
- url="http://library.gnome.org/devel/gobject/unstable/GTypeModule.html">GTypeModule</ulink>
- sections in the <ulink type="http" url="http://library.gnome.org/devel/gobject/unstable/">GObject
+ url="https://developer.gnome.org/gobject/unstable/GTypeModule.html">GTypeModule</ulink>
+ sections in the <ulink type="http" url="https://developer.gnome.org/gobject/unstable/">GObject
Reference Manual</ulink> provide details about the handling of dynamic type plugins.
</listitem>
diff --git a/icons/16x16/Makefile.am b/icons/16x16/Makefile.am
index d121bf65..dfbd9507 100644
--- a/icons/16x16/Makefile.am
+++ b/icons/16x16/Makefile.am
@@ -4,9 +4,8 @@ apps_DATA = \
stockdir = $(datadir)/icons/hicolor/16x16/stock/navigation
stock_DATA = \
- stock_folder-copy.png \
- stock_folder-move.png \
- stock_thunar-shortcuts.png
+ stock_folder-copy.png \
+ stock_folder-move.png
EXTRA_DIST = \
$(apps_DATA) \
diff --git a/icons/16x16/stock_thunar-shortcuts.png b/icons/16x16/stock_thunar-shortcuts.png
deleted file mode 100644
index 59e04f27..00000000
Binary files a/icons/16x16/stock_thunar-shortcuts.png and /dev/null differ
diff --git a/org.xfce.thunar.appdata.xml.in b/org.xfce.thunar.appdata.xml.in
index 64a13577..272f6d72 100644
--- a/org.xfce.thunar.appdata.xml.in
+++ b/org.xfce.thunar.appdata.xml.in
@@ -14,12 +14,12 @@
clean two-pane design for browsing all your files.
</_p>
</description>
- <url type="homepage">http://xfce.org/projects</url>
+ <url type="homepage">https://xfce.org/projects</url>
<url type="bugtracker">https://bugzilla.xfce.org/describecomponents.cgi?product=Thunar</url>
- <url type="help">http://docs.xfce.org/xfce/thunar/start</url>
+ <url type="help">https://docs.xfce.org/xfce/thunar/start</url>
<screenshots>
- <screenshot type="default">http://docs.xfce.org/_media/xfce/thunar/file-manager-window.png</screenshot>
+ <screenshot type="default">https://docs.xfce.org/_media/xfce/thunar/file-manager-window.png</screenshot>
</screenshots>
<categories>
diff --git a/org.xfce.thunar.policy.in.in b/org.xfce.thunar.policy.in.in
index d64113e9..6caf6d06 100644
--- a/org.xfce.thunar.policy.in.in
+++ b/org.xfce.thunar.policy.in.in
@@ -13,7 +13,7 @@
-->
<vendor>Thunar</vendor>
- <vendor_url>http://xfce.org/</vendor_url>
+ <vendor_url>https://xfce.org/</vendor_url>
<icon_name>system-file-manager</icon_name>
diff --git a/plugins/thunar-apr/thunar-apr-image-page.c b/plugins/thunar-apr/thunar-apr-image-page.c
index 5a846192..20e14ce5 100644
--- a/plugins/thunar-apr/thunar-apr-image-page.c
+++ b/plugins/thunar-apr/thunar-apr-image-page.c
@@ -108,8 +108,8 @@ thunar_apr_image_page_init (ThunarAprImagePage *image_page)
AtkObject *object;
GtkWidget *label;
GtkWidget *grid;
- GtkWidget *spacer;
#ifdef HAVE_EXIF
+ GtkWidget *spacer;
guint n;
#endif
diff --git a/plugins/thunar-sbr/thunar-sbr-case-renamer.c b/plugins/thunar-sbr/thunar-sbr-case-renamer.c
index c5847b88..86f9c2a0 100644
--- a/plugins/thunar-sbr/thunar-sbr-case-renamer.c
+++ b/plugins/thunar-sbr/thunar-sbr-case-renamer.c
@@ -184,7 +184,7 @@ thunar_sbr_case_renamer_set_property (GObject *object,
static gchar*
tscr_utf8_strcase (const gchar *text,
- gboolean camelcase)
+ gboolean title_case)
{
const gchar *t;
gboolean upper = TRUE;
@@ -199,8 +199,7 @@ tscr_utf8_strcase (const gchar *text,
{
/* check the next char */
c = g_utf8_get_char (t);
- if (camelcase
- && g_unichar_isspace (c))
+ if (title_case && g_unichar_isspace (c))
{
upper = TRUE;
}
@@ -239,7 +238,7 @@ thunar_sbr_case_renamer_process (ThunarxRenamer *renamer,
case THUNAR_SBR_CASE_RENAMER_MODE_UPPER:
return g_utf8_strup (text, -1);
- case THUNAR_SBR_CASE_RENAMER_MODE_CAMEL:
+ case THUNAR_SBR_CASE_RENAMER_MODE_TITLE:
return tscr_utf8_strcase (text, TRUE);
case THUNAR_SBR_CASE_RENAMER_MODE_FIRST_UPPER:
diff --git a/plugins/thunar-sbr/thunar-sbr-enum-types.c b/plugins/thunar-sbr/thunar-sbr-enum-types.c
index 1368cee8..cad6b648 100644
--- a/plugins/thunar-sbr/thunar-sbr-enum-types.c
+++ b/plugins/thunar-sbr/thunar-sbr-enum-types.c
@@ -92,7 +92,7 @@ thunar_sbr_register_enum_types (ThunarxProviderPlugin *plugin)
{
{ THUNAR_SBR_CASE_RENAMER_MODE_LOWER, "THUNAR_SBR_CASE_RENAMER_MODE_LOWER", N_ ("lowercase"), },
{ THUNAR_SBR_CASE_RENAMER_MODE_UPPER, "THUNAR_SBR_CASE_RENAMER_MODE_UPPER", N_ ("UPPERCASE"), },
- { THUNAR_SBR_CASE_RENAMER_MODE_CAMEL, "THUNAR_SBR_CASE_RENAMER_MODE_CAMEL", N_ ("Camelcase"), },
+ { THUNAR_SBR_CASE_RENAMER_MODE_TITLE, "THUNAR_SBR_CASE_RENAMER_MODE_TITLE", N_ ("Title Case"), },
{ THUNAR_SBR_CASE_RENAMER_MODE_FIRST_UPPER, "THUNAR_SBR_CASE_RENAMER_MODE_FIRST_UPPER", N_ ("First character uppercase"), },
{ 0, NULL, NULL, },
};
diff --git a/plugins/thunar-sbr/thunar-sbr-enum-types.h b/plugins/thunar-sbr/thunar-sbr-enum-types.h
index db89e62c..6300b035 100644
--- a/plugins/thunar-sbr/thunar-sbr-enum-types.h
+++ b/plugins/thunar-sbr/thunar-sbr-enum-types.h
@@ -31,7 +31,7 @@ G_BEGIN_DECLS;
* ThunarSbrCaseRenamerMode:
* @THUNAR_SBR_CASE_RENAMER_MODE_LOWER : convert to lower case.
* @THUNAR_SBR_CASE_RENAMER_MODE_UPPER : convert to upper case.
- * @THUNAR_SBR_CASE_RENAMER_MODE_CAMEL : convert to camel case.
+ * @THUNAR_SBR_CASE_RENAMER_MODE_TITLE : convert to title case.
* @THUNAR_SBR_CASE_RENAMER_MODE_FIRST_UPPER : convert to First character uppercase.
*
* The operation mode for the #ThunarSbrCaseRenamer.
@@ -40,7 +40,7 @@ typedef enum
{
THUNAR_SBR_CASE_RENAMER_MODE_LOWER,
THUNAR_SBR_CASE_RENAMER_MODE_UPPER,
- THUNAR_SBR_CASE_RENAMER_MODE_CAMEL,
+ THUNAR_SBR_CASE_RENAMER_MODE_TITLE,
THUNAR_SBR_CASE_RENAMER_MODE_FIRST_UPPER,
} ThunarSbrCaseRenamerMode;
diff --git a/plugins/thunar-sendto-email/main.c b/plugins/thunar-sendto-email/main.c
index 587cdd88..4e1ee0c2 100644
--- a/plugins/thunar-sendto-email/main.c
+++ b/plugins/thunar-sendto-email/main.c
@@ -76,8 +76,12 @@ struct _TseData
/* well known archive types */
static const char *TSE_MIME_TYPES[] = {
+ "application/x-7z-compressed",
+ "application/x-7z-compressed-tar",
"application/x-ar",
"application/x-arj",
+ "application/x-brotli",
+ "application/x-brotli-compressed-tar",
"application/x-bzip",
"application/x-bzip-compressed-tar",
"application/x-compress",
@@ -87,9 +91,13 @@ static const char *TSE_MIME_TYPES[] = {
"application/x-gzip",
"application/x-lha",
"application/x-lhz",
+ "application/x-lzma",
+ "application/x-lzma-compressed-tar",
"application/x-rar",
"application/x-rar-compressed",
"application/x-tar",
+ "application/x-xz",
+ "application/x-xz-compressed-tar",
"application/x-zip",
"application/x-zip-compressed",
"application/zip",
@@ -100,6 +108,8 @@ static const char *TSE_MIME_TYPES[] = {
"application/x-lzop",
"application/x-zoo",
"application/x-cd-image",
+ "application/zstd",
+ "application/x-zstd-compressed-tar",
};
@@ -139,12 +149,36 @@ tse_error (GError *error,
g_free (primary_text);
}
+/**
+ * Check if the single file is already an archive
+ **/
+static gboolean
+tse_file_is_archive (GFileInfo *file_info)
+{
+ const gchar *content_type;
+ guint n;
+ /* determine the content type */
+ content_type = g_file_info_get_content_type (file_info);
+ if (content_type == NULL)
+ {
+ return FALSE;
+ }
+ for (n = 0; n < G_N_ELEMENTS (TSE_MIME_TYPES); ++n)
+ {
+ /* check if this mime type matches */
+ if (g_content_type_is_a (content_type, TSE_MIME_TYPES[n]))
+ {
+ /* yep, that's a match then */
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
static gint
tse_ask_compress (GList *infos)
{
- const gchar *content_type;
TseData *tse_data;
GtkWidget *message;
guint64 total_size = 0;
@@ -152,7 +186,6 @@ tse_ask_compress (GList *infos)
gint response = TSE_RESPONSE_PLAIN;
gint n_archives = 0;
gint n_infos = 0;
- guint n;
/* check the file infos */
for (lp = infos; lp != NULL; lp = lp->next, ++n_infos)
@@ -163,27 +196,15 @@ tse_ask_compress (GList *infos)
if (g_file_info_get_file_type (tse_data->info) == G_FILE_TYPE_DIRECTORY)
return TSE_RESPONSE_COMPRESS;
- /* check if the single file is already an archive */
- for (n = 0; n < G_N_ELEMENTS (TSE_MIME_TYPES); ++n)
- {
- /* determine the content type */
- content_type = g_file_info_get_content_type (tse_data->info);
-
- /* check if this mime type matches */
- if (content_type != NULL && g_content_type_is_a (content_type, TSE_MIME_TYPES[n]))
- {
- /* yep, that's a match then */
- ++n_archives;
- break;
- }
- }
+ if (tse_file_is_archive (tse_data->info))
+ ++n_archives;
/* add file size to total */
total_size += g_file_info_get_size (tse_data->info);
}
/* check if the total size is larger than 200KiB, or we have more than
- * one file, and atleast one of the files is not already an archive.
+ * one file, and at least one of the files is not already an archive.
*/
if ((n_infos > 1 || total_size > 200 * 1024) && n_infos != n_archives)
{
@@ -307,7 +328,7 @@ tse_progress (const gchar *working_directory,
watch_id = g_child_watch_add (pid, tse_child_watch, dialog);
/* start the pulse timer */
- pulse_timer_id = g_timeout_add (125, (GSourceFunc) gtk_progress_bar_pulse, progress);
+ pulse_timer_id = g_timeout_add (125, (GSourceFunc) (void (*)(void)) gtk_progress_bar_pulse, progress);
/* run the dialog */
response = gtk_dialog_run (GTK_DIALOG (dialog));
@@ -597,7 +618,8 @@ main (int argc, char **argv)
info = g_file_query_info (file,
G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME ","
G_FILE_ATTRIBUTE_STANDARD_SIZE ","
- G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE ","
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
G_FILE_QUERY_INFO_NONE, NULL, &error);
/* check if we failed */
diff --git a/plugins/thunar-sendto-email/thunar-sendto-email.desktop.in.in b/plugins/thunar-sendto-email/thunar-sendto-email.desktop.in.in
index 539c7850..90e860f8 100644
--- a/plugins/thunar-sendto-email/thunar-sendto-email.desktop.in.in
+++ b/plugins/thunar-sendto-email/thunar-sendto-email.desktop.in.in
@@ -2,5 +2,5 @@
Type=Application
Version=1.0
_Name=Mail Recipient
-Icon=internet-mail
+Icon=mail-send
Exec=@HELPERDIR@/Thunar/thunar-sendto-email %F
diff --git a/plugins/thunar-tpa/thunar-tpa.c b/plugins/thunar-tpa/thunar-tpa.c
index 73a53eb2..baff39ab 100644
--- a/plugins/thunar-tpa/thunar-tpa.c
+++ b/plugins/thunar-tpa/thunar-tpa.c
@@ -156,7 +156,7 @@ thunar_tpa_init (ThunarTpa *plugin)
GError *error = NULL;
/* setup the button for the trash plugin */
- plugin->button = xfce_create_panel_button ();
+ plugin->button = xfce_panel_create_button ();
xfce_panel_plugin_add_action_widget (XFCE_PANEL_PLUGIN (plugin), plugin->button);
gtk_drag_dest_set (plugin->button, GTK_DEST_DEFAULT_ALL, drop_targets, G_N_ELEMENTS (drop_targets), GDK_ACTION_MOVE);
g_signal_connect_swapped (G_OBJECT (plugin->button), "clicked", G_CALLBACK (thunar_tpa_display_trash), plugin);
diff --git a/plugins/thunar-uca/thunar-uca-editor.c b/plugins/thunar-uca/thunar-uca-editor.c
index 58ac524e..9bc80754 100644
--- a/plugins/thunar-uca/thunar-uca-editor.c
+++ b/plugins/thunar-uca/thunar-uca-editor.c
@@ -655,7 +655,7 @@ thunar_uca_editor_save (ThunarUcaEditor *uca_editor,
-1);
/* always clear the accelerator, it'll be updated in thunar_uca_model_update */
- if (gtk_accel_map_lookup_entry (uca_editor->accel_path, &key) && key.accel_key != 0)
+ if (uca_editor->accel_path != NULL && gtk_accel_map_lookup_entry (uca_editor->accel_path, &key) && key.accel_key != 0)
gtk_accel_map_change_entry (uca_editor->accel_path, 0, 0, TRUE);
thunar_uca_model_update (uca_model, iter,
diff --git a/plugins/thunar-uca/thunar-uca-model.c b/plugins/thunar-uca/thunar-uca-model.c
index edee3e40..54f0dd12 100644
--- a/plugins/thunar-uca/thunar-uca-model.c
+++ b/plugins/thunar-uca/thunar-uca-model.c
@@ -1263,10 +1263,24 @@ thunar_uca_model_remove (ThunarUcaModel *uca_model,
{
ThunarUcaModelItem *item;
GtkTreePath *path;
+ gchar *unique_id;
+ gchar *accel_path;
+ GtkAccelKey key;
g_return_if_fail (THUNAR_UCA_IS_MODEL (uca_model));
g_return_if_fail (iter->stamp == uca_model->stamp);
+ /* clear any accelerator associated to the item */
+ gtk_tree_model_get (GTK_TREE_MODEL (uca_model), iter,
+ THUNAR_UCA_MODEL_COLUMN_UNIQUE_ID, &unique_id,
+ -1);
+ accel_path = g_strdup_printf ("<Actions>/ThunarActions/uca-action-%s", unique_id);
+
+ if (gtk_accel_map_lookup_entry (accel_path, &key) && key.accel_key != 0)
+ gtk_accel_map_change_entry (accel_path, 0, 0, TRUE);
+
+ g_free (accel_path);
+
/* determine the path for the item to remove */
path = gtk_tree_model_get_path (GTK_TREE_MODEL (uca_model), iter);
@@ -1426,7 +1440,7 @@ thunar_uca_model_save (ThunarUcaModel *uca_model,
fp = fdopen (fd, "w");
/* write the header */
- fprintf (fp, "<?xml encoding=\"UTF-8\" version=\"1.0\"?>\n<actions>\n");
+ fprintf (fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<actions>\n");
/* write the model items */
for (lp = uca_model->items; lp != NULL; lp = lp->next)
diff --git a/plugins/thunar-uca/thunar-uca-provider.c b/plugins/thunar-uca/thunar-uca-provider.c
index 53dbc8d1..450616ce 100644
--- a/plugins/thunar-uca/thunar-uca-provider.c
+++ b/plugins/thunar-uca/thunar-uca-provider.c
@@ -246,7 +246,8 @@ thunar_uca_provider_get_file_menu_items (ThunarxMenuProvider *menu_provider,
/* connect the "activate" signal */
g_signal_connect_data (G_OBJECT (item), "activate", G_CALLBACK (thunar_uca_provider_activated),
- g_object_ref (G_OBJECT (uca_provider)), (GClosureNotify) g_object_unref,
+ g_object_ref (G_OBJECT (uca_provider)),
+ (GClosureNotify) (void (*)(void)) g_object_unref,
G_CONNECT_SWAPPED);
/* set the action path */
diff --git a/plugins/thunar-wallpaper/twp-provider.c b/plugins/thunar-wallpaper/twp-provider.c
index 92d09cd2..887ae646 100644
--- a/plugins/thunar-wallpaper/twp-provider.c
+++ b/plugins/thunar-wallpaper/twp-provider.c
@@ -50,22 +50,9 @@ static void twp_action_set_wallpaper (ThunarxMenuItem *item,
gpointer user_data);
static gint twp_get_active_workspace_number (GdkScreen *screen);
-
-typedef enum
-{
- DESKTOP_TYPE_NONE,
- DESKTOP_TYPE_XFCE,
- DESKTOP_TYPE_NAUTILUS
-} DesktopType;
-
-
-
-static DesktopType desktop_type = DESKTOP_TYPE_NONE;
-static gboolean _has_gconftool = FALSE;
+static gboolean _has_gsettings = FALSE;
static GtkWidget *main_window = NULL;
-
-
struct _TwpProviderClass
{
GObjectClass __parent__;
@@ -107,10 +94,10 @@ twp_provider_init (TwpProvider *twp_provider)
{
gchar *program;
- program = g_find_program_in_path ("gconftool-2");
+ program = g_find_program_in_path ("gsettings");
if (G_LIKELY (program != NULL))
{
- _has_gconftool = TRUE;
+ _has_gsettings = TRUE;
g_free (program);
}
}
@@ -134,19 +121,8 @@ twp_provider_get_file_menu_items (ThunarxMenuProvider *menu_provider,
GFile *location;
GList *items = NULL;
gchar *mime_type;
- gchar selection_name[100];
- Atom xfce_selection_atom;
- Atom nautilus_selection_atom;
- GdkScreen *gdk_screen = gdk_screen_get_default();
- gint xscreen = gdk_x11_screen_get_screen_number(gdk_screen);
-
- if(g_strcmp0 (g_getenv ("XDG_SESSION_TYPE"), "wayland") == 0)
- {
- return items; // wayland crashes on "gdk_x11_get_default_xdisplay"
- }
main_window = window;
- desktop_type = DESKTOP_TYPE_NONE;
/* we can only set a single wallpaper */
if (files->next == NULL)
@@ -184,25 +160,6 @@ twp_provider_get_file_menu_items (ThunarxMenuProvider *menu_provider,
}
}
- g_snprintf(selection_name, 100, XFDESKTOP_SELECTION_FMT, xscreen);
- xfce_selection_atom = XInternAtom (gdk_x11_get_default_xdisplay(), selection_name, False);
-
- if ((XGetSelectionOwner(gdk_x11_get_default_xdisplay(), xfce_selection_atom)))
- {
- desktop_type = DESKTOP_TYPE_XFCE;
- }
- else
- {
- /* FIXME: This is wrong, nautilus WINDOW_ID is not a selection */
- g_snprintf(selection_name, 100, NAUTILUS_SELECTION_FMT);
- nautilus_selection_atom = XInternAtom (gdk_x11_get_default_xdisplay(), selection_name, False);
- if((XGetSelectionOwner(gdk_x11_get_default_xdisplay(), nautilus_selection_atom)))
- {
- if (_has_gconftool)
- desktop_type = DESKTOP_TYPE_NAUTILUS;
- }
- }
-
return items;
}
@@ -230,23 +187,26 @@ twp_action_set_wallpaper (ThunarxMenuItem *item,
XfconfChannel *channel;
gboolean is_single_workspace;
gint current_image_style;
+ const gchar *desktop_type = NULL;
screen = gdk_display_get_default_screen (display);
- if (desktop_type != DESKTOP_TYPE_NONE)
+ desktop_type = g_getenv ("XDG_CURRENT_DESKTOP");
+ if (desktop_type == NULL)
{
- file_uri = thunarx_file_info_get_uri (file_info);
- file_name = g_filename_from_uri (file_uri, &hostname, NULL);
- if (hostname != NULL)
- {
- g_free (hostname);
- g_free (file_uri);
- g_free (file_name);
-
- return;
- }
+ g_warning ("Failed to set wallpaper: $XDG_CURRENT_DESKTOP is not defined");
+ return;
+ }
+ file_uri = thunarx_file_info_get_uri (file_info);
+ file_name = g_filename_from_uri (file_uri, &hostname, NULL);
+ if (hostname != NULL)
+ {
+ g_free (hostname);
g_free (file_uri);
+ g_free (file_name);
+
+ return;
}
workspace = twp_get_active_workspace_number (screen);
@@ -264,105 +224,103 @@ twp_action_set_wallpaper (ThunarxMenuItem *item,
monitor_name = gdk_monitor_get_model (monitor);
escaped_file_name = g_shell_quote (file_name);
- switch (desktop_type)
+ if (g_strcmp0 (desktop_type, "XFCE") == 0)
+ {
+ g_debug ("set on xfce");
+
+ channel = xfconf_channel_get ("xfce4-desktop");
+
+ /* This is the format for xfdesktop before 4.11 */
+ image_path_prop = g_strdup_printf("/backdrop/screen%d/monitor%d/image-path", screen_nr, monitor_nr);
+ image_show_prop = g_strdup_printf("/backdrop/screen%d/monitor%d/image-show", screen_nr, monitor_nr);
+ image_style_prop = g_strdup_printf("/backdrop/screen%d/monitor%d/image-style", screen_nr, monitor_nr);
+
+ /* Set the wallpaper and ensure that it's set to show */
+ xfconf_channel_set_string (channel, image_path_prop, file_name);
+ xfconf_channel_set_bool (channel, image_show_prop, TRUE);
+
+ /* If there isn't a wallpaper style set, then set one */
+ current_image_style = xfconf_channel_get_int (channel, image_style_prop, -1);
+ if (current_image_style == -1)
+ {
+ xfconf_channel_set_int (channel, image_style_prop, 0);
+ }
+
+ g_free(image_path_prop);
+ g_free(image_show_prop);
+ g_free(image_style_prop);
+
+
+ /* Xfdesktop 4.11+ has a concept of a single-workspace-mode where
+ * the same workspace is used for everything but additionally allows
+ * the user to use any current workspace as the single active
+ * workspace, we'll need to check if it is enabled (which by default
+ * it is) and use that. */
+ is_single_workspace = xfconf_channel_get_bool (channel, "/backdrop/single-workspace-mode", TRUE);
+ if (is_single_workspace)
+ {
+ workspace = xfconf_channel_get_int (channel, "/backdrop/single-workspace-number", 0);
+ }
+
+ /* This is the format for xfdesktop post 4.11. A workspace number is
+ * added and the monitor is referred to name. We set both formats so
+ * that it works as the user expects. */
+ if (monitor_name)
+ {
+ image_path_prop = g_strdup_printf("/backdrop/screen%d/monitor%s/workspace%d/last-image", screen_nr, monitor_name, workspace);
+ image_style_prop = g_strdup_printf("/backdrop/screen%d/monitor%s/workspace%d/image-style", screen_nr, monitor_name, workspace);
+ }
+ else
+ {
+ /* gdk_screen_get_monitor_plug_name can return NULL, in those
+ * instances we fallback to monitor number but still include the
+ * workspace number */
+ image_path_prop = g_strdup_printf("/backdrop/screen%d/monitor%d/workspace%d/last-image", screen_nr, monitor_nr, workspace);
+ image_style_prop = g_strdup_printf("/backdrop/screen%d/monitor%d/workspace%d/image-style", screen_nr, monitor_nr, workspace);
+ }
+
+ xfconf_channel_set_string (channel, image_path_prop, file_name);
+
+ /* If there isn't a wallpaper style set, then set one */
+ current_image_style = xfconf_channel_get_int (channel, image_style_prop, -1);
+ if (current_image_style == -1)
+ {
+ xfconf_channel_set_int (channel, image_style_prop, 5);
+ }
+
+ g_free(image_path_prop);
+ g_free(image_style_prop);
+ }
+ else if (g_strcmp0 (desktop_type, "GNOME") == 0)
+ {
+ if (_has_gsettings)
+ {
+ g_debug ("set on gnome");
+
+ command = g_strdup_printf ("gsettings set "
+ "org.gnome.desktop.background picture-uri "
+ "'%s'", file_uri);
+ g_spawn_command_line_async (command, NULL);
+ g_free (command);
+ }
+ else
+ {
+ g_warning ("Failed to set wallpaper: Missing executable 'gsettings'");
+ }
+ }
+ else
{
- case DESKTOP_TYPE_XFCE:
- g_debug ("set on xfce");
-
- channel = xfconf_channel_get ("xfce4-desktop");
-
- /* This is the format for xfdesktop before 4.11 */
- image_path_prop = g_strdup_printf("/backdrop/screen%d/monitor%d/image-path", screen_nr, monitor_nr);
- image_show_prop = g_strdup_printf("/backdrop/screen%d/monitor%d/image-show", screen_nr, monitor_nr);
- image_style_prop = g_strdup_printf("/backdrop/screen%d/monitor%d/image-style", screen_nr, monitor_nr);
-
- /* Set the wallpaper and ensure that it's set to show */
- xfconf_channel_set_string (channel, image_path_prop, file_name);
- xfconf_channel_set_bool (channel, image_show_prop, TRUE);
-
- /* If there isn't a wallpaper style set, then set one */
- current_image_style = xfconf_channel_get_int (channel, image_style_prop, -1);
- if (current_image_style == -1)
- {
- xfconf_channel_set_int (channel, image_style_prop, 0);
- }
-
- g_free(image_path_prop);
- g_free(image_show_prop);
- g_free(image_style_prop);
-
-
- /* Xfdesktop 4.11+ has a concept of a single-workspace-mode where
- * the same workspace is used for everything but additionally allows
- * the user to use any current workspace as the single active
- * workspace, we'll need to check if it is enabled (which by default
- * it is) and use that. */
- is_single_workspace = xfconf_channel_get_bool (channel, "/backdrop/single-workspace-mode", TRUE);
- if (is_single_workspace)
- {
- workspace = xfconf_channel_get_int (channel, "/backdrop/single-workspace-number", 0);
- }
-
- /* This is the format for xfdesktop post 4.11. A workspace number is
- * added and the monitor is referred to name. We set both formats so
- * that it works as the user expects. */
- if (monitor_name)
- {
- image_path_prop = g_strdup_printf("/backdrop/screen%d/monitor%s/workspace%d/last-image", screen_nr, monitor_name, workspace);
- image_style_prop = g_strdup_printf("/backdrop/screen%d/monitor%s/workspace%d/image-style", screen_nr, monitor_name, workspace);
- }
- else
- {
- /* gdk_screen_get_monitor_plug_name can return NULL, in those
- * instances we fallback to monitor number but still include the
- * workspace number */
- image_path_prop = g_strdup_printf("/backdrop/screen%d/monitor%d/workspace%d/last-image", screen_nr, monitor_nr, workspace);
- image_style_prop = g_strdup_printf("/backdrop/screen%d/monitor%d/workspace%d/image-style", screen_nr, monitor_nr, workspace);
- }
-
- xfconf_channel_set_string (channel, image_path_prop, file_name);
-
- /* If there isn't a wallpaper style set, then set one */
- current_image_style = xfconf_channel_get_int (channel, image_style_prop, -1);
- if (current_image_style == -1)
- {
- xfconf_channel_set_int (channel, image_style_prop, 5);
- }
-
- g_free(image_path_prop);
- g_free(image_style_prop);
- break;
-
- case DESKTOP_TYPE_NAUTILUS:
- g_debug ("set on gnome");
- image_path_prop = g_strdup_printf("/desktop/gnome/background/picture_filename");
- image_show_prop = g_strdup_printf("/desktop/gnome/background/draw_background");
-
- command = g_strdup_printf ("gconftool-2 %s --set %s--type string", image_path_prop, escaped_file_name);
- g_spawn_command_line_async (command, NULL);
- g_free (command);
-
-
- command = g_strdup_printf ("gconftool-2 %s --set true --type boolean", image_show_prop);
- g_spawn_command_line_async (command, NULL);
- g_free (command);
-
- g_free(image_path_prop);
- g_free(image_show_prop);
- break;
-
- default:
- return;
- break;
+ g_warning (("Failed to set wallpaper: $XDG_CURRENT_DESKTOP Desktop type '%s' not supported by thunar wallpaper plugin."), desktop_type);
}
g_free (escaped_file_name);
g_free (file_name);
+ g_free (file_uri);
}
/* Taken from xfce_spawn_get_active_workspace_number in xfce-spawn.c apart of
* the libxfce4ui library.
- * http://git.xfce.org/xfce/libxfce4ui/tree/libxfce4ui/xfce-spawn.c#n193
+ * https://git.xfce.org/xfce/libxfce4ui/tree/libxfce4ui/xfce-spawn.c#n193
*/
static gint
twp_get_active_workspace_number (GdkScreen *screen)
diff --git a/po/hy.po b/po/hy.po
new file mode 100644
index 00000000..86bb804d
diff --git a/po/hy_AM.po b/po/hy_AM.po
new file mode 100644
index 00000000..9d9d45d3
diff --git a/po/hye.po b/po/hye.po
new file mode 100644
index 00000000..1227a856
diff --git a/po/ie.po b/po/ie.po
new file mode 100644
index 00000000..381703d8
diff --git a/Thunar-bulk-rename.desktop.in.in b/thunar-bulk-rename.desktop.in.in
similarity index 100%
rename from Thunar-bulk-rename.desktop.in.in
rename to thunar-bulk-rename.desktop.in.in
diff --git a/Thunar.desktop.in.in b/thunar.desktop.in.in
diff --git a/Thunar.desktop.in.in b/thunar.desktop.in.in
similarity index 91%
rename from Thunar.desktop.in.in
rename to thunar.desktop.in.in
index 739ea437..734b1b89 100644
--- a/Thunar.desktop.in.in
+++ b/thunar.desktop.in.in
@@ -8,5 +8,6 @@ Terminal=false
StartupNotify=true
Type=Application
Categories=System;Utility;Core;GTK;FileTools;FileManager;
+MimeType=inode/directory;
# vi:set encoding=UTF-8:
diff --git a/thunar/Makefile.am b/thunar/Makefile.am
index a92ae747..cff7b495 100644
--- a/thunar/Makefile.am
+++ b/thunar/Makefile.am
@@ -144,8 +144,6 @@ thunar_SOURCES = \
thunar-location-entry.h \
thunar-menu-util.c \
thunar-menu-util.h \
- thunar-misc-jobs.c \
- thunar-misc-jobs.h \
thunar-notify.c \
thunar-notify.h \
thunar-navigator.c \
@@ -231,6 +229,7 @@ thunar_CFLAGS = \
$(LIBSM_CFLAGS) \
$(LIBXFCE4UI_CFLAGS) \
$(XFCONF_CFLAGS) \
+ $(PANGO_CFLAGS) \
$(PLATFORM_CFLAGS)
thunar_LDFLAGS = \
@@ -247,7 +246,8 @@ thunar_LDADD = \
$(LIBNOTIFY_LIBS) \
$(LIBSM_LIBS) \
$(LIBXFCE4UI_LIBS) \
- $(XFCONF_LIBS)
+ $(XFCONF_LIBS) \
+ $(PANGO_LIBS)
thunar_DEPENDENCIES = \
$(top_builddir)/thunarx/libthunarx-$(THUNARX_VERSION_API).la
diff --git a/thunar/thunar-abstract-icon-view.c b/thunar/thunar-abstract-icon-view.c
index f53f4530..91ee300a 100644
--- a/thunar/thunar-abstract-icon-view.c
+++ b/thunar/thunar-abstract-icon-view.c
@@ -32,10 +32,6 @@
-#define THUNAR_ABSTRACT_ICON_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), THUNAR_TYPE_ABSTRACT_ICON_VIEW, ThunarAbstractIconViewPrivate))
-
-
-
static void thunar_abstract_icon_view_style_set (GtkWidget *widget,
GtkStyle *previous_style);
static void thunar_abstract_icon_view_connect_ui_manager (ThunarStandardView *standard_view,
@@ -133,7 +129,7 @@ static const GtkRadioActionEntry order_action_entries[] =
-G_DEFINE_ABSTRACT_TYPE (ThunarAbstractIconView, thunar_abstract_icon_view, THUNAR_TYPE_STANDARD_VIEW)
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ThunarAbstractIconView, thunar_abstract_icon_view, THUNAR_TYPE_STANDARD_VIEW)
@@ -143,9 +139,6 @@ thunar_abstract_icon_view_class_init (ThunarAbstractIconViewClass *klass)
ThunarStandardViewClass *thunarstandard_view_class;
GtkWidgetClass *gtkwidget_class;
- /* add private data to the instance type */
- g_type_class_add_private (klass, sizeof (ThunarAbstractIconViewPrivate));
-
gtkwidget_class = GTK_WIDGET_CLASS (klass);
gtkwidget_class->style_set = thunar_abstract_icon_view_style_set;
@@ -198,7 +191,7 @@ thunar_abstract_icon_view_init (ThunarAbstractIconView *abstract_icon_view)
GtkWidget *view;
/* connect private instance data */
- abstract_icon_view->priv = THUNAR_ABSTRACT_ICON_VIEW_GET_PRIVATE (abstract_icon_view);
+ abstract_icon_view->priv = thunar_abstract_icon_view_get_instance_private (abstract_icon_view);
/* stay informed about zoom-level changes, so we can force a re-layout on the abstract_icon view */
g_signal_connect (G_OBJECT (abstract_icon_view), "notify::zoom-level", G_CALLBACK (thunar_abstract_icon_view_zoom_level_changed), NULL);
diff --git a/thunar/thunar-application.c b/thunar/thunar-application.c
index 694db532..c0ca694d 100644
--- a/thunar/thunar-application.c
+++ b/thunar/thunar-application.c
@@ -117,10 +117,7 @@ static void thunar_application_dbus_acquired_cb (GDBusConnection
static void thunar_application_name_acquired_cb (GDBusConnection *connection,
const gchar *name,
gpointer user_data);
-static void thunar_application_dbus_name_lost_crit_cb (GDBusConnection *connection,
- const gchar *name,
- gpointer user_data);
-static void thunar_application_dbus_name_lost_warn_cb (GDBusConnection *connection,
+static void thunar_application_dbus_name_lost_cb (GDBusConnection *connection,
const gchar *name,
gpointer user_data);
static void thunar_application_dbus_init (ThunarApplication *application);
@@ -182,37 +179,38 @@ struct _ThunarApplicationClass
struct _ThunarApplication
{
- GtkApplication __parent__;
+ GtkApplication __parent__;
- ThunarSessionClient *session_client;
+ ThunarSessionClient *session_client;
- ThunarPreferences *preferences;
- GtkWidget *progress_dialog;
+ ThunarPreferences *preferences;
+ GtkWidget *progress_dialog;
- ThunarThumbnailCache *thumbnail_cache;
- ThunarThumbnailer *thumbnailer;
+ ThunarThumbnailCache *thumbnail_cache;
+ ThunarThumbnailer *thumbnailer;
- ThunarDBusService *dbus_service;
+ ThunarDBusService *dbus_service;
- gboolean daemon;
+ gboolean daemon;
- guint accel_map_save_id;
- GtkAccelMap *accel_map;
+ guint accel_map_save_id;
+ GtkAccelMap *accel_map;
- guint show_dialogs_timer_id;
+ guint show_dialogs_timer_id;
#ifdef HAVE_GUDEV
- GUdevClient *udev_client;
+ GUdevClient *udev_client;
- GSList *volman_udis;
- guint volman_idle_id;
- guint volman_watch_id;
+ GSList *volman_udis;
+ guint volman_idle_id;
+ guint volman_watch_id;
#endif
- GList *files_to_launch;
+ GList *files_to_launch;
+ ThunarApplicationProcessAction process_file_action;
- guint dbus_owner_id_xfce;
- guint dbus_owner_id_fdo;
+ guint dbus_owner_id_xfce;
+ guint dbus_owner_id_fdo;
};
@@ -279,6 +277,7 @@ thunar_application_init (ThunarApplication *application)
* in the primary instance anyways */
application->files_to_launch = NULL;
+ application->process_file_action = THUNAR_APPLICATION_SELECT_FILES;
application->progress_dialog = NULL;
application->preferences = NULL;
@@ -308,19 +307,7 @@ thunar_application_name_acquired_cb (GDBusConnection *connection,
static void
-thunar_application_dbus_name_lost_crit_cb (GDBusConnection *connection,
- const gchar *name,
- gpointer user_data)
-{
- ThunarApplication *application = user_data;
- g_critical (_("Name '%s' lost on the message dbus, exiting."), name);
- g_application_quit (G_APPLICATION (application));
-}
-
-
-
-static void
-thunar_application_dbus_name_lost_warn_cb (GDBusConnection *connection,
+thunar_application_dbus_name_lost_cb (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
@@ -330,20 +317,16 @@ thunar_application_dbus_name_lost_warn_cb (GDBusConnection *connection,
/* TODO: [GTK3 Port] Check if there's a cleaner way to register */
-/* this extra dbus name (besides org.xfce.Thunar) */
+/* these extra dbus names (besides org.xfce.Thunar) */
static void
thunar_application_dbus_init (ThunarApplication *application)
{
- /* Do not atempt to register if running as root */
- if (geteuid() == 0)
- return;
-
application->dbus_owner_id_xfce = g_bus_own_name (G_BUS_TYPE_SESSION,
"org.xfce.FileManager",
G_BUS_NAME_OWNER_FLAGS_NONE,
thunar_application_dbus_acquired_cb,
thunar_application_name_acquired_cb,
- thunar_application_dbus_name_lost_crit_cb,
+ thunar_application_dbus_name_lost_cb,
application,
NULL);
@@ -352,7 +335,7 @@ thunar_application_dbus_init (ThunarApplication *application)
G_BUS_NAME_OWNER_FLAGS_NONE,
thunar_application_dbus_acquired_cb,
thunar_application_name_acquired_cb,
- thunar_application_dbus_name_lost_warn_cb,
+ thunar_application_dbus_name_lost_cb,
application,
NULL);
}
@@ -488,7 +471,7 @@ thunar_application_handle_local_options (GApplication *gapp,
if (G_UNLIKELY (opt_version))
{
g_print ("%s %s (Xfce %s)\n\n", PACKAGE_NAME, PACKAGE_VERSION, xfce_version_string ());
- g_print ("%s\n", "Copyright (c) 2004-2015");
+ g_print ("%s\n", "Copyright (c) 2004-2019");
g_print ("\t%s\n\n", _("The Thunar development team. All rights reserved."));
g_print ("%s\n\n", _("Written by Benedikt Meurer <benny@xfce.org>."));
g_print (_("Please report bugs to <%s>."), PACKAGE_BUGREPORT);
@@ -548,7 +531,7 @@ thunar_application_command_line (GApplication *gapp,
}
else if (filenames != NULL)
{
- if (!thunar_application_process_filenames (application, cwd, filenames, NULL, NULL, &error))
+ if (!thunar_application_process_filenames (application, cwd, filenames, NULL, NULL, &error, THUNAR_APPLICATION_SELECT_FILES))
{
/* we failed to process the filenames or the bulk rename failed */
g_application_command_line_printerr (command_line, "Thunar: %s\n", error->message);
@@ -556,7 +539,7 @@ thunar_application_command_line (GApplication *gapp,
}
else if (!daemon)
{
- if (!thunar_application_process_filenames (application, cwd, cwd_list, NULL, NULL, &error))
+ if (!thunar_application_process_filenames (application, cwd, cwd_list, NULL, NULL, &error, THUNAR_APPLICATION_SELECT_FILES))
{
/* we failed to process the filenames or the bulk rename failed */
g_application_command_line_printerr (command_line, "Thunar: %s\n", error->message);
@@ -612,7 +595,7 @@ thunar_application_load_css (void)
/* add missing top border to side pane */
".shortcuts-pane { border-top-style: solid; }"
/* make border thicker during DnD */
- ".standard-view { border-left-width: 0px; }"
+ ".standard-view { border-left-width: 0px; border-right-width: 0px; }"
".standard-view:drop(active) { border-width: 2px; }", -1, NULL);
screen = gdk_screen_get_default ();
gtk_style_context_add_provider_for_screen (screen, GTK_STYLE_PROVIDER (css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
@@ -927,7 +910,7 @@ thunar_application_uevent (GUdevClient *client,
{
/* only insert the path if we don't have it already */
if (g_slist_find_custom (application->volman_udis, sysfs_path,
- (GCompareFunc) g_utf8_collate) == NULL)
+ (GCompareFunc) (void (*)(void)) g_utf8_collate) == NULL)
{
application->volman_udis = g_slist_prepend (application->volman_udis,
g_strdup (sysfs_path));
@@ -947,7 +930,7 @@ thunar_application_uevent (GUdevClient *client,
{
/* look for the sysfs path in the list of pending paths */
lp = g_slist_find_custom (application->volman_udis, sysfs_path,
- (GCompareFunc) g_utf8_collate);
+ (GCompareFunc) (void (*)(void)) g_utf8_collate);
if (G_LIKELY (lp != NULL))
{
@@ -1276,7 +1259,7 @@ thunar_application_take_window (ThunarApplication *application,
{
group = gtk_window_group_new ();
gtk_window_group_add_window (group, window);
- g_object_weak_ref (G_OBJECT (window), (GWeakNotify) g_object_unref, group);
+ g_object_weak_ref (G_OBJECT (window), (GWeakNotify) (void (*)(void)) g_object_unref, group);
}
/* add the ourselves to the window */
@@ -1526,8 +1509,27 @@ thunar_application_process_files_finish (ThunarBrowser *browser,
}
else
{
- /* try to open the file or directory */
- thunar_file_launch (target_file, screen, startup_id, &error);
+ if (application->process_file_action == THUNAR_APPLICATION_LAUNCH_FILES)
+ {
+ /* try to launch the file / open the directory */
+ thunar_file_launch (target_file, screen, startup_id, &error);
+ }
+ else if (thunar_file_is_directory (file))
+ {
+ thunar_application_open_window (application, file, screen, startup_id, FALSE);
+ }
+ else
+ {
+ /* Note that for security reasons we do not execute files passed via command line */
+ /* Lets rather open the containing directory */
+ ThunarFile *parent = thunar_file_get_parent (file, NULL);
+
+ if (G_LIKELY (parent != NULL))
+ {
+ thunar_application_open_window (application, parent, screen, startup_id, FALSE);
+ g_object_unref (parent);
+ }
+ }
/* remove the file from the list */
application->files_to_launch = g_list_delete_link (application->files_to_launch,
@@ -1596,18 +1598,20 @@ thunar_application_process_files (ThunarApplication *application)
* @startup_id : startup id to finish startup notification and properly focus the
* window when focus stealing is enabled or %NULL.
* @error : return location for errors or %NULL.
+ * @action : action to invoke on the files
*
* Tells @application to process the given @filenames and launch them appropriately.
*
* Return value: %TRUE on success, %FALSE if @error is set.
**/
gboolean
-thunar_application_process_filenames (ThunarApplication *application,
- const gchar *working_directory,
- gchar **filenames,
- GdkScreen *screen,
- const gchar *startup_id,
- GError **error)
+thunar_application_process_filenames (ThunarApplication *application,
+ const gchar *working_directory,
+ gchar **filenames,
+ GdkScreen *screen,
+ const gchar *startup_id,
+ GError **error,
+ ThunarApplicationProcessAction action)
{
ThunarFile *file;
GError *derror = NULL;
@@ -1679,7 +1683,10 @@ thunar_application_process_filenames (ThunarApplication *application,
/* start processing files if we have any to launch */
if (application->files_to_launch != NULL)
- thunar_application_process_files (application);
+ {
+ application->process_file_action = action;
+ thunar_application_process_files (application);
+ }
/* free the file list */
g_list_free (file_list);
diff --git a/thunar/thunar-application.h b/thunar/thunar-application.h
index 547cb701..8c180e8c 100644
--- a/thunar/thunar-application.h
+++ b/thunar/thunar-application.h
@@ -31,6 +31,12 @@ G_BEGIN_DECLS;
typedef struct _ThunarApplicationClass ThunarApplicationClass;
typedef struct _ThunarApplication ThunarApplication;
+typedef enum
+{
+ THUNAR_APPLICATION_LAUNCH_FILES,
+ THUNAR_APPLICATION_SELECT_FILES
+} ThunarApplicationProcessAction;
+
#define THUNAR_TYPE_APPLICATION (thunar_application_get_type ())
#define THUNAR_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_APPLICATION, ThunarApplication))
#define THUNAR_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_APPLICATION, ThunarApplicationClass))
@@ -74,7 +80,8 @@ gboolean thunar_application_process_filenames (ThunarAppli
gchar **filenames,
GdkScreen *screen,
const gchar *startup_id,
- GError **error);
+ GError **error,
+ ThunarApplicationProcessAction action);
void thunar_application_rename_file (ThunarApplication *application,
ThunarFile *file,
diff --git a/thunar/thunar-column-model.c b/thunar/thunar-column-model.c
index 35ac6fc2..1ece1be7 100644
--- a/thunar/thunar-column-model.c
+++ b/thunar/thunar-column-model.c
@@ -86,6 +86,7 @@ static void thunar_column_model_save_visible_columns (ThunarCol
static void thunar_column_model_notify_visible_columns (ThunarPreferences *preferences,
GParamSpec *pspec,
ThunarColumnModel *column_model);
+static gboolean thunar_column_model_set_column_width_timer (gpointer user_data);
@@ -113,6 +114,7 @@ struct _ThunarColumnModel
ThunarColumn order[THUNAR_N_VISIBLE_COLUMNS];
gboolean visible[THUNAR_N_VISIBLE_COLUMNS];
gint width[THUNAR_N_VISIBLE_COLUMNS];
+ guint save_width_timer_id;
};
@@ -211,6 +213,10 @@ thunar_column_model_finalize (GObject *object)
g_signal_handlers_disconnect_matched (G_OBJECT (column_model->preferences), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, column_model);
g_object_unref (G_OBJECT (column_model->preferences));
+ /* drop any running "save width" timer */
+ if (G_UNLIKELY (column_model->save_width_timer_id != 0))
+ g_source_remove (column_model->save_width_timer_id);
+
(*G_OBJECT_CLASS (thunar_column_model_parent_class)->finalize) (object);
}
@@ -720,6 +726,19 @@ thunar_column_model_notify_visible_columns (ThunarPreferences *preferences,
+static gboolean
+thunar_column_model_set_column_width_timer (gpointer user_data)
+{
+ ThunarColumnModel *column_model = THUNAR_COLUMN_MODEL (user_data);
+
+ thunar_column_model_save_column_widths (column_model);
+ column_model->save_width_timer_id = 0;
+
+ return FALSE;
+}
+
+
+
/**
* thunar_column_model_get_default:
*
@@ -998,8 +1017,14 @@ thunar_column_model_set_column_width (ThunarColumnModel *column_model,
/* apply the new value */
column_model->width[column] = width;
- /* store the settings */
- thunar_column_model_save_column_widths (column_model);
+ /* store the settings... */
+ if (column_model->save_width_timer_id != 0)
+ g_source_remove (column_model->save_width_timer_id);
+
+ /* ... asynchronously and only once to not overload xfconf */
+ column_model->save_width_timer_id = g_timeout_add (1000,
+ thunar_column_model_set_column_width_timer,
+ column_model);
}
}
diff --git a/thunar/thunar-component.c b/thunar/thunar-component.c
index ddd42435..29cd6849 100644
--- a/thunar/thunar-component.c
+++ b/thunar/thunar-component.c
@@ -43,7 +43,7 @@ thunar_component_get_type (void)
type = g_type_register_static_simple (G_TYPE_INTERFACE,
I_("ThunarComponent"),
sizeof (ThunarComponentIface),
- (GClassInitFunc) thunar_component_class_init,
+ (GClassInitFunc) (void (*)(void)) thunar_component_class_init,
0,
NULL,
0);
diff --git a/thunar/thunar-create-dialog.c b/thunar/thunar-create-dialog.c
index 6fb204ba..b14d5bb0 100644
--- a/thunar/thunar-create-dialog.c
+++ b/thunar/thunar-create-dialog.c
@@ -156,7 +156,7 @@ thunar_create_dialog_init (ThunarCreateDialog *dialog)
gtk_grid_attach (GTK_GRID (grid), dialog->image, 0, 0, 1, 2);
gtk_widget_show (dialog->image);
- label = g_object_new (GTK_TYPE_LABEL, "label", _("Enter the new name:"), "xalign", 0.0f, "hexpand", TRUE, NULL);
+ label = g_object_new (GTK_TYPE_LABEL, "label", _("Enter the name:"), "xalign", 0.0f, "hexpand", TRUE, NULL);
gtk_grid_attach (GTK_GRID (grid), label, 1, 0, 1, 1);
gtk_widget_show (label);
diff --git a/thunar/thunar-dbus-service.c b/thunar/thunar-dbus-service.c
index 2d27642d..4205a2b2 100644
--- a/thunar/thunar-dbus-service.c
+++ b/thunar/thunar-dbus-service.c
@@ -991,7 +991,7 @@ thunar_dbus_service_launch_files (ThunarDBusFileManager *object,
{
/* let the application process the filenames */
application = thunar_application_get ();
- thunar_application_process_filenames (application, working_directory, filenames, screen, startup_id, &error);
+ thunar_application_process_filenames (application, working_directory, filenames, screen, startup_id, &error, THUNAR_APPLICATION_LAUNCH_FILES);
g_object_unref (G_OBJECT (application));
/* release the screen */
diff --git a/thunar/thunar-deep-count-job.c b/thunar/thunar-deep-count-job.c
index d36572eb..7efc400a 100644
--- a/thunar/thunar-deep-count-job.c
+++ b/thunar/thunar-deep-count-job.c
@@ -409,7 +409,7 @@ thunar_deep_count_job_new (GList *files,
job->files = g_list_copy (files);
job->query_flags = flags;
- g_list_foreach (job->files, (GFunc) g_object_ref, NULL);
+ g_list_foreach (job->files, (GFunc) (void (*)(void)) g_object_ref, NULL);
return job;
}
diff --git a/thunar/thunar-details-view.c b/thunar/thunar-details-view.c
index 5dabad6e..c0f585ee 100644
--- a/thunar/thunar-details-view.c
+++ b/thunar/thunar-details-view.c
@@ -269,7 +269,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
/* add the name renderer */
g_object_set (G_OBJECT (THUNAR_STANDARD_VIEW (details_view)->name_renderer),
- "xalign", 0.0, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+ "xalign", 0.0, "ellipsize", PANGO_ELLIPSIZE_END, "width-chars", 30, NULL);
gtk_tree_view_column_pack_start (details_view->columns[column], THUNAR_STANDARD_VIEW (details_view)->name_renderer, TRUE);
gtk_tree_view_column_set_attributes (details_view->columns[column], THUNAR_STANDARD_VIEW (details_view)->name_renderer,
"text", THUNAR_COLUMN_NAME,
@@ -690,6 +690,9 @@ thunar_details_view_button_press_event (GtkTreeView *tree_view,
&& !gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y, &path, &column, NULL, NULL))
gtk_tree_selection_unselect_all (selection);
+ /* make sure that rubber banding is enabled */
+ gtk_tree_view_set_rubber_banding (tree_view, TRUE);
+
/* if the user clicked on a row with the left button */
if (path != NULL && event->type == GDK_BUTTON_PRESS && event->button == 1)
{
diff --git a/thunar/thunar-dialogs.c b/thunar/thunar-dialogs.c
index 0083bdcf..78850ed4 100644
--- a/thunar/thunar-dialogs.c
+++ b/thunar/thunar-dialogs.c
@@ -173,6 +173,10 @@ thunar_dialogs_show_rename_file (gpointer parent,
/* resize the dialog to make long names fit as much as possible */
gtk_window_set_default_size (GTK_WINDOW (dialog), CLAMP (layout_width, 300, parent_width), -1);
+ /* automatically close the dialog when the file is destroyed */
+ g_signal_connect_swapped (G_OBJECT (file), "destroy",
+ G_CALLBACK (gtk_widget_destroy), dialog);
+
/* run the dialog */
response = gtk_dialog_run (GTK_DIALOG (dialog));
if (G_LIKELY (response == GTK_RESPONSE_OK))
@@ -192,7 +196,13 @@ thunar_dialogs_show_rename_file (gpointer parent,
}
/* cleanup */
- gtk_widget_destroy (dialog);
+ if (G_LIKELY (response != GTK_RESPONSE_NONE))
+ {
+ /* unregister handler */
+ g_signal_handlers_disconnect_by_func (G_OBJECT (file), gtk_widget_destroy, dialog);
+
+ gtk_widget_destroy (dialog);
+ }
return job;
}
@@ -258,8 +268,8 @@ thunar_dialogs_show_about (GtkWindow *parent,
"copyright", "Copyright \302\251 2004-2011 Benedikt Meurer\n"
"Copyright \302\251 2009-2011 Jannis Pohlmann\n"
"Copyright \302\251 2009-2012 Nick Schermer\n"
- "Copyright \302\251 2017-2018 Alexander Schwinn\n"
- "Copyright \302\251 2017-2018 Andre Miranda",
+ "Copyright \302\251 2017-2019 Alexander Schwinn\n"
+ "Copyright \302\251 2017-2019 Andre Miranda",
"destroy-with-parent", TRUE,
"documenters", documenters,
"license", XFCE_LICENSE_GPL,
@@ -304,6 +314,8 @@ thunar_dialogs_show_error (gpointer parent,
GdkScreen *screen;
va_list args;
gchar *primary_text;
+ GList *children;
+ GList *lp;
_thunar_return_if_fail (parent == NULL || GDK_IS_SCREEN (parent) || GTK_IS_WIDGET (parent));
@@ -335,12 +347,21 @@ thunar_dialogs_show_error (gpointer parent,
if (G_LIKELY (error != NULL))
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s.", error->message);
+ children = gtk_container_get_children (
+ GTK_CONTAINER (gtk_message_dialog_get_message_area (GTK_MESSAGE_DIALOG (dialog))));
+
+ /* enable wrap for labels */
+ for (lp = children; lp != NULL; lp = lp->next)
+ if (GTK_IS_LABEL (lp->data))
+ gtk_label_set_line_wrap_mode (GTK_LABEL (lp->data), PANGO_WRAP_WORD_CHAR);
+
/* display the dialog */
gtk_dialog_run (GTK_DIALOG (dialog));
/* cleanup */
gtk_widget_destroy (dialog);
g_free (primary_text);
+ g_list_free (children);
}
@@ -497,6 +518,19 @@ thunar_dialogs_show_job_ask (GtkWindow *parent,
+static void thunar_dialogs_show_job_ask_replace_callback (GtkWidget *button,
+ gpointer user_data)
+{
+ gint response;
+
+ _thunar_return_if_fail (GTK_IS_DIALOG (user_data));
+
+ response = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "response-id"));
+ gtk_dialog_response (GTK_DIALOG (user_data), response);
+}
+
+
+
/**
* thunar_dialogs_show_job_ask_replace:
* @parent : the parent #GtkWindow or %NULL.
@@ -522,6 +556,13 @@ thunar_dialogs_show_job_ask_replace (GtkWindow *parent,
GtkWidget *grid;
GtkWidget *image;
GtkWidget *label;
+ GtkWidget *content_area;
+ GtkWidget *cancel_button;
+ GtkWidget *button_box;
+ GtkWidget *skipall_button;
+ GtkWidget *skip_button;
+ GtkWidget *replaceall_button;
+ GtkWidget *replace_button;
GdkPixbuf *icon;
gchar *date_custom_style;
gchar *date_string;
@@ -542,17 +583,13 @@ thunar_dialogs_show_job_ask_replace (GtkWindow *parent,
g_object_unref (G_OBJECT (preferences));
/* setup the confirmation dialog */
- dialog = gtk_dialog_new_with_buttons (_("Confirm to replace files"),
- parent,
- GTK_DIALOG_MODAL
- | GTK_DIALOG_DESTROY_WITH_PARENT,
- _("_Cancel"), GTK_RESPONSE_CANCEL,
- _("S_kip All"), THUNAR_JOB_RESPONSE_NO_ALL,
- _("_Skip"), THUNAR_JOB_RESPONSE_NO,
- _("Replace _All"), THUNAR_JOB_RESPONSE_YES_ALL,
- _("_Replace"), THUNAR_JOB_RESPONSE_YES,
- NULL);
+ dialog = gtk_dialog_new();
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Confirm to replace files"));
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
+ gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), THUNAR_JOB_RESPONSE_YES);
+ content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
/* determine the icon factory to use */
icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (dialog));
@@ -562,9 +599,40 @@ thunar_dialogs_show_job_ask_replace (GtkWindow *parent,
gtk_grid_set_column_spacing (GTK_GRID (grid), 5);
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
gtk_container_set_border_width (GTK_CONTAINER (grid), 10);
- gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), grid, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (content_area), grid, TRUE, FALSE, 0);
gtk_widget_show (grid);
+ /* set up the action area buttons ourself */
+ button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
+
+ cancel_button = gtk_button_new_with_mnemonic (_("_Cancel"));
+ skipall_button = gtk_button_new_with_mnemonic (_("S_kip All"));
+ skip_button = gtk_button_new_with_mnemonic (_("_Skip"));
+ replaceall_button = gtk_button_new_with_mnemonic (_("Replace _All"));
+ replace_button = gtk_button_new_with_mnemonic (_("_Replace"));
+
+ g_signal_connect (cancel_button, "clicked", G_CALLBACK (thunar_dialogs_show_job_ask_replace_callback), dialog);
+ g_signal_connect (skipall_button, "clicked", G_CALLBACK (thunar_dialogs_show_job_ask_replace_callback), dialog);
+ g_signal_connect (skip_button, "clicked", G_CALLBACK (thunar_dialogs_show_job_ask_replace_callback), dialog);
+ g_signal_connect (replaceall_button, "clicked", G_CALLBACK (thunar_dialogs_show_job_ask_replace_callback), dialog);
+ g_signal_connect (replace_button, "clicked", G_CALLBACK (thunar_dialogs_show_job_ask_replace_callback), dialog);
+
+ g_object_set_data (G_OBJECT (cancel_button), "response-id", GINT_TO_POINTER (GTK_RESPONSE_CANCEL));
+ g_object_set_data (G_OBJECT (skipall_button), "response-id", GINT_TO_POINTER (THUNAR_JOB_RESPONSE_NO_ALL));
+ g_object_set_data (G_OBJECT (skip_button), "response-id", GINT_TO_POINTER (THUNAR_JOB_RESPONSE_NO));
+ g_object_set_data (G_OBJECT (replaceall_button), "response-id", GINT_TO_POINTER (THUNAR_JOB_RESPONSE_YES_ALL));
+ g_object_set_data (G_OBJECT (replace_button), "response-id", GINT_TO_POINTER (THUNAR_JOB_RESPONSE_YES));
+
+ gtk_container_add (GTK_CONTAINER (button_box), cancel_button);
+ gtk_container_add (GTK_CONTAINER (button_box), skipall_button);
+ gtk_container_add (GTK_CONTAINER (button_box), skip_button);
+ gtk_container_add (GTK_CONTAINER (button_box), replaceall_button);
+ gtk_container_add (GTK_CONTAINER (button_box), replace_button);
+ gtk_container_add (GTK_CONTAINER (content_area), button_box);
+ gtk_widget_set_halign (button_box, GTK_ALIGN_CENTER);
+ gtk_box_set_spacing (GTK_BOX (button_box), 5);
+ gtk_widget_show_all (button_box);
+
image = gtk_image_new_from_icon_name ("stock_folder-copy", GTK_ICON_SIZE_BUTTON);
gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
gtk_widget_set_valign (image, GTK_ALIGN_START);
@@ -596,6 +664,7 @@ thunar_dialogs_show_job_ask_replace (GtkWindow *parent,
gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
gtk_label_set_attributes (GTK_LABEL (label), thunar_pango_attr_list_big ());
gtk_widget_set_hexpand (label, TRUE);
+ gtk_label_set_selectable(GTK_LABEL (label), TRUE);
gtk_grid_attach (GTK_GRID (grid), label, 1, 0, 2, 1);
gtk_widget_show (label);
g_free (text);
diff --git a/thunar/thunar-emblem-chooser.c b/thunar/thunar-emblem-chooser.c
index 30953d63..1a7cdfee 100644
--- a/thunar/thunar-emblem-chooser.c
+++ b/thunar/thunar-emblem-chooser.c
@@ -230,7 +230,9 @@ thunar_emblem_chooser_unrealize (GtkWidget *widget)
ThunarEmblemChooser *chooser = THUNAR_EMBLEM_CHOOSER (widget);
/* drop all check buttons */
- gtk_container_foreach (GTK_CONTAINER (chooser->table), (GtkCallback) gtk_widget_destroy, NULL);
+ gtk_container_foreach (GTK_CONTAINER (chooser->table),
+ (GtkCallback) (void (*)(void)) gtk_widget_destroy,
+ NULL);
/* release our reference on the icon theme */
g_signal_handlers_disconnect_by_func (G_OBJECT (chooser->icon_theme), thunar_emblem_chooser_theme_changed, chooser);
@@ -276,7 +278,7 @@ thunar_emblem_chooser_button_toggled (GtkToggleButton *button,
if (gtk_toggle_button_get_active (button))
{
/* check if we need to add the new emblem */
- if (g_list_find_custom (emblem_names, emblem_name, (GCompareFunc) strcmp) == NULL)
+ if (g_list_find_custom (emblem_names, emblem_name, (GCompareFunc) (void (*)(void)) strcmp) == NULL)
{
emblem_names = g_list_append (emblem_names, (gchar *) emblem_name);
is_modified = TRUE;
@@ -284,7 +286,7 @@ thunar_emblem_chooser_button_toggled (GtkToggleButton *button,
}
else
{
- delete_link = g_list_find_custom (emblem_names, emblem_name, (GCompareFunc) strcmp);
+ delete_link = g_list_find_custom (emblem_names, emblem_name, (GCompareFunc) (void (*)(void)) strcmp);
if (delete_link != NULL)
{
emblem_names = g_list_delete_link (emblem_names, delete_link);
@@ -381,7 +383,9 @@ thunar_emblem_chooser_theme_changed (GtkIconTheme *icon_theme,
_thunar_return_if_fail (chooser->icon_theme == icon_theme);
/* drop the current buttons */
- gtk_container_foreach (GTK_CONTAINER (chooser->table), (GtkCallback) gtk_widget_destroy, NULL);
+ gtk_container_foreach (GTK_CONTAINER (chooser->table),
+ (GtkCallback) (void (*)(void)) gtk_widget_destroy,
+ NULL);
/* create buttons for the new theme */
thunar_emblem_chooser_create_buttons (chooser);
@@ -400,7 +404,7 @@ thunar_emblem_chooser_create_buttons (ThunarEmblemChooser *chooser)
emblems = gtk_icon_theme_list_icons (chooser->icon_theme, "Emblems");
/* sort the emblem list */
- emblems = g_list_sort (emblems, (GCompareFunc) g_ascii_strcasecmp);
+ emblems = g_list_sort (emblems, (GCompareFunc) (void (*)(void)) g_ascii_strcasecmp);
/* create buttons for the emblems */
for (lp = emblems; lp != NULL; lp = lp->next)
diff --git a/thunar/thunar-exec.c b/thunar/thunar-exec.c
index edbe270e..685783c0 100644
--- a/thunar/thunar-exec.c
+++ b/thunar/thunar-exec.c
@@ -104,7 +104,7 @@ te_string_append_quoted_uri (GString *string,
* @error : return location for errors or %NULL.
*
* Substitutes <literal>Exec</literal> parameter variables according
- * to the <ulink href="http://freedesktop.org/wiki/Standards_2fdesktop_2dentry_2dspec"
+ * to the <ulink href="https://freedesktop.org/wiki/Specifications/desktop-entry-spec"
* type="http">Desktop Entry Specification</ulink> and returns the
* parsed argument vector (in @argv) and the number of items placed
* into @argv (in @argc).
diff --git a/thunar/thunar-file.c b/thunar/thunar-file.c
index d9147aa7..1ac9a1e4 100644
--- a/thunar/thunar-file.c
+++ b/thunar/thunar-file.c
@@ -1822,7 +1822,7 @@ thunar_file_launch (ThunarFile *file,
/* HACK: check if we're not trying to launch another file manager again, possibly
* ourselfs which will end in a loop */
if (g_strcmp0 (g_app_info_get_id (app_info), "exo-file-manager.desktop") == 0
- || g_strcmp0 (g_app_info_get_id (app_info), "Thunar.desktop") == 0
+ || g_strcmp0 (g_app_info_get_id (app_info), "thunar.desktop") == 0
|| g_strcmp0 (g_app_info_get_name (app_info), "exo-file-manager") == 0)
{
g_object_unref (G_OBJECT (app_info));
@@ -2031,11 +2031,18 @@ thunar_file_accepts_drop (ThunarFile *file,
/* default to whatever GTK+ thinks for the suggested action */
suggested_action = gdk_drag_context_get_suggested_action (context);
+ /* get the possible actions */
+ actions = gdk_drag_context_get_actions (context);
+
+ /* when the option to ask the user is set, make it the preferred action */
+ if (G_UNLIKELY ((actions & GDK_ACTION_ASK) != 0))
+ suggested_action = GDK_ACTION_ASK;
+
/* check if we have a writable directory here or an executable file */
if (thunar_file_is_directory (file) && thunar_file_is_writable (file))
{
/* determine the possible actions */
- actions = gdk_drag_context_get_actions (context) & (GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK);
+ actions &= (GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK);
/* cannot create symbolic links in the trash or copy to the trash */
if (thunar_file_is_trashed (file))
@@ -2113,7 +2120,7 @@ thunar_file_accepts_drop (ThunarFile *file,
else if (thunar_file_is_executable (file))
{
/* determine the possible actions */
- actions = gdk_drag_context_get_actions (context) & (GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_PRIVATE);
+ actions &= (GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_PRIVATE);
}
else
return 0;
@@ -3384,7 +3391,7 @@ thunar_file_get_emblem_names (ThunarFile *file)
: 0;
/* we add "cant-read" if either (a) the file is not readable or (b) a directory, that lacks the
- * x-bit, see http://bugzilla.xfce.org/show_bug.cgi?id=1408 for the details about this change.
+ * x-bit, see https://bugzilla.xfce.org/show_bug.cgi?id=1408 for the details about this change.
*/
if (!thunar_file_is_readable (file)
|| (thunar_file_is_directory (file)
diff --git a/thunar/thunar-folder.c b/thunar/thunar-folder.c
index 7ca50b06..2d6134f4 100644
--- a/thunar/thunar-folder.c
+++ b/thunar/thunar-folder.c
@@ -132,6 +132,22 @@ G_DEFINE_TYPE (ThunarFolder, thunar_folder, G_TYPE_OBJECT)
+static void
+thunar_folder_constructed (GObject *object)
+{
+ ThunarFolder *folder = THUNAR_FOLDER (object);
+
+ /* add us to the folder alteration monitor */
+ folder->monitor = g_file_monitor_directory (thunar_file_get_file (folder->corresponding_file),
+ G_FILE_MONITOR_SEND_MOVED, NULL, NULL);
+ if (G_LIKELY (folder->monitor != NULL))
+ g_signal_connect (folder->monitor, "changed", G_CALLBACK (thunar_folder_monitor), folder);
+
+ G_OBJECT_CLASS (thunar_folder_parent_class)->constructed (object);
+}
+
+
+
static void
thunar_folder_class_init (ThunarFolderClass *klass)
{
@@ -142,6 +158,7 @@ thunar_folder_class_init (ThunarFolderClass *klass)
gobject_class->finalize = thunar_folder_finalize;
gobject_class->get_property = thunar_folder_get_property;
gobject_class->set_property = thunar_folder_set_property;
+ gobject_class->constructed = thunar_folder_constructed;
klass->destroy = thunar_folder_real_destroy;
@@ -359,8 +376,6 @@ thunar_folder_set_property (GObject *object,
switch (prop_id)
{
case PROP_CORRESPONDING_FILE:
- if (folder->corresponding_file)
- thunar_file_unwatch (folder->corresponding_file);
folder->corresponding_file = g_value_dup_object (value);
if (folder->corresponding_file)
thunar_file_watch (folder->corresponding_file);
@@ -407,7 +422,6 @@ thunar_folder_files_ready (ThunarJob *job,
{
_thunar_return_val_if_fail (THUNAR_IS_FOLDER (folder), FALSE);
_thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
- _thunar_return_val_if_fail (folder->monitor == NULL, FALSE);
/* merge the list with the existing list of new files */
folder->new_files = g_list_concat (folder->new_files, files);
@@ -485,7 +499,6 @@ thunar_folder_finished (ExoJob *job,
_thunar_return_if_fail (THUNAR_IS_FOLDER (folder));
_thunar_return_if_fail (THUNAR_IS_JOB (job));
_thunar_return_if_fail (THUNAR_IS_FILE (folder->corresponding_file));
- _thunar_return_if_fail (folder->monitor == NULL);
_thunar_return_if_fail (folder->content_type_idle_id == 0);
/* check if we need to merge new files with existing files */
@@ -573,19 +586,16 @@ thunar_folder_finished (ExoJob *job,
}
/* we did it, the folder is loaded */
- g_signal_handlers_disconnect_matched (folder->job, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, folder);
- g_object_unref (folder->job);
- folder->job = NULL;
+ if (G_LIKELY (folder->job != NULL))
+ {
+ g_signal_handlers_disconnect_matched (folder->job, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, folder);
+ g_object_unref (folder->job);
+ folder->job = NULL;
+ }
/* restart the content type idle loader */
thunar_folder_content_type_loader (folder);
- /* add us to the file alteration monitor */
- folder->monitor = g_file_monitor_directory (thunar_file_get_file (folder->corresponding_file),
- G_FILE_MONITOR_SEND_MOVED, NULL, NULL);
- if (G_LIKELY (folder->monitor != NULL))
- g_signal_connect (folder->monitor, "changed", G_CALLBACK (thunar_folder_monitor), folder);
-
/* tell the consumers that we have loaded the directory */
g_object_notify (G_OBJECT (folder), "loading");
}
@@ -733,7 +743,6 @@ thunar_folder_monitor (GFileMonitor *monitor,
_thunar_return_if_fail (G_IS_FILE_MONITOR (monitor));
_thunar_return_if_fail (THUNAR_IS_FOLDER (folder));
_thunar_return_if_fail (folder->monitor == monitor);
- _thunar_return_if_fail (folder->job == NULL);
_thunar_return_if_fail (THUNAR_IS_FILE (folder->corresponding_file));
_thunar_return_if_fail (G_IS_FILE (event_file));
@@ -762,6 +771,9 @@ thunar_folder_monitor (GFileMonitor *monitor,
/* tell others about the new file */
list.data = file; list.next = list.prev = NULL;
g_signal_emit (G_OBJECT (folder), folder_signals[FILES_ADDED], 0, &list);
+
+ /* load the new file */
+ thunar_file_reload (file);
}
}
else if (lp != NULL)
@@ -811,9 +823,6 @@ thunar_folder_monitor (GFileMonitor *monitor,
g_object_unref (file);
}
}
-
- /* reload the folder of the source file */
- thunar_file_reload (folder->corresponding_file);
}
else
{
@@ -990,15 +999,6 @@ thunar_folder_reload (ThunarFolder *folder,
folder->job = NULL;
}
- /* disconnect from the file alteration monitor */
- if (G_UNLIKELY (folder->monitor != NULL))
- {
- g_signal_handlers_disconnect_matched (folder->monitor, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, folder);
- g_file_monitor_cancel (folder->monitor);
- g_object_unref (folder->monitor);
- folder->monitor = NULL;
- }
-
/* reset the new_files list */
thunar_g_file_list_free (folder->new_files);
folder->new_files = NULL;
diff --git a/thunar/thunar-gdk-extensions.c b/thunar/thunar-gdk-extensions.c
index 18cfb3b6..279382cb 100644
--- a/thunar/thunar-gdk-extensions.c
+++ b/thunar/thunar-gdk-extensions.c
@@ -191,6 +191,12 @@ thunar_gdk_screen_open (const gchar *display_name,
display = dp->data;
break;
}
+ /* This second comparison will as well match the short notation, ":0" with the long notation ":0.0" */
+ if (strncmp (other_name, display_name, strlen (other_name)) == 0)
+ {
+ display = dp->data;
+ break;
+ }
}
g_slist_free (displays);
diff --git a/thunar/thunar-gio-extensions.c b/thunar/thunar-gio-extensions.c
index 629ec018..28988b62 100644
--- a/thunar/thunar-gio-extensions.c
+++ b/thunar/thunar-gio-extensions.c
@@ -552,11 +552,14 @@ thunar_g_app_info_launch (GAppInfo *info,
GError **error)
{
ThunarFile *file;
+ GAppInfo *default_app_info;
+ GList *recommended_app_infos;
GList *lp;
const gchar *content_type;
gboolean result = FALSE;
gchar *new_path = NULL;
gchar *old_path = NULL;
+ gboolean skip_app_info_update;
_thunar_return_val_if_fail (G_IS_APP_INFO (info), FALSE);
_thunar_return_val_if_fail (working_directory == NULL || G_IS_FILE (working_directory), FALSE);
@@ -564,6 +567,8 @@ thunar_g_app_info_launch (GAppInfo *info,
_thunar_return_val_if_fail (G_IS_APP_LAUNCH_CONTEXT (context), FALSE);
_thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ skip_app_info_update = (g_object_get_data (G_OBJECT (info), "skip-app-info-update") != NULL);
+
/* check if we want to set the working directory of the spawned app */
if (working_directory != NULL)
{
@@ -587,17 +592,44 @@ thunar_g_app_info_launch (GAppInfo *info,
{
for (lp = path_list; lp != NULL; lp = lp->next)
{
+ gboolean update_app_info = !skip_app_info_update;
+
file = thunar_file_get (lp->data, NULL);
- if (file != NULL)
+ if (file == NULL)
+ continue;
+
+ content_type = thunar_file_get_content_type (file);
+
+ /* determine default application */
+ default_app_info = thunar_file_get_default_handler (file);
+ if (default_app_info != NULL)
{
- content_type = thunar_file_get_content_type (file);
+ /* check if the application is the default one */
+ if (g_app_info_equal (info, default_app_info))
+ update_app_info = FALSE;
+ g_object_unref (default_app_info);
+ }
- /* emit "changed" on the file if we successfully changed the last used application */
- if (g_app_info_set_as_last_used_for_type (info, content_type, NULL))
- thunar_file_changed (file);
+ if (update_app_info)
+ {
+ /* obtain list of last used applications */
+ recommended_app_infos = g_app_info_get_recommended_for_type (content_type);
+ if (recommended_app_infos != NULL)
+ {
+ /* check if the application is already the last used one
+ * by comparing it with the first entry in the list */
+ if (g_app_info_equal (info, recommended_app_infos->data))
+ update_app_info = FALSE;
- g_object_unref (file);
+ g_list_free (recommended_app_infos);
+ }
}
+
+ /* emit "changed" on the file if we successfully changed the last used application */
+ if (update_app_info && g_app_info_set_as_last_used_for_type (info, content_type, NULL))
+ thunar_file_changed (file);
+
+ g_object_unref (file);
}
}
diff --git a/thunar/thunar-gtk-extensions.c b/thunar/thunar-gtk-extensions.c
index 4852c118..f2a0c226 100644
--- a/thunar/thunar-gtk-extensions.c
+++ b/thunar/thunar-gtk-extensions.c
@@ -131,27 +131,88 @@ thunar_gtk_label_set_a11y_relation (GtkLabel *label,
* thunar_gtk_menu_run:
* @menu : a #GtkMenu.
*
- * A simple wrapper around gtk_menu_popup_at_pointer(), which takes care on the
- * menu and returns only after the @menu was deactivated.
+ * Conveniance wrapper for thunar_gtk_menu_run_at_event_pointer, to run a menu for the current event
+ **/
+void
+thunar_gtk_menu_run (GtkMenu *menu)
+{
+ GdkEvent *event = gtk_get_current_event ();
+ thunar_gtk_menu_run_at_event (menu, event);
+ gdk_event_free (event);
+}
+
+
+
+#if GTK_CHECK_VERSION (3, 24, 8)
+static void
+moved_to_rect_cb (GdkWindow *window,
+ const GdkRectangle *flipped_rect,
+ const GdkRectangle *final_rect,
+ gboolean flipped_x,
+ gboolean flipped_y,
+ GtkMenu *menu)
+{
+ g_signal_emit_by_name (menu, "popped-up", 0, flipped_rect, final_rect, flipped_x, flipped_y);
+ g_signal_stop_emission_by_name (window, "moved-to-rect");
+}
+
+
+
+static void
+popup_menu_realized (GtkWidget *menu,
+ gpointer user_data)
+{
+ GdkWindow *toplevel = gtk_widget_get_window (gtk_widget_get_toplevel (menu));
+ g_signal_handlers_disconnect_by_func (toplevel, moved_to_rect_cb, menu);
+ g_signal_connect (toplevel, "moved-to-rect", G_CALLBACK (moved_to_rect_cb), menu);
+}
+#endif
+
+
+
+/**
+ * thunar_gtk_menu_run_at_event:
+ * @menu : a #GtkMenu.
+ * @event : a #GdkEvent which may be NULL if no previous event was stored.
+ *
+ * A simple wrapper around gtk_menu_popup_at_pointer(), which runs the @menu in a separate
+ * main loop and returns only after the @menu was deactivated.
*
* This method automatically takes over the floating reference of @menu if any and
* releases it on return. That means if you created the menu via gtk_menu_new() you'll
* not need to take care of destroying the menu later.
+ *
**/
void
-thunar_gtk_menu_run (GtkMenu *menu)
+thunar_gtk_menu_run_at_event (GtkMenu *menu,
+ GdkEvent *event)
{
- GdkEvent *event;
+ GMainLoop *loop;
+ gulong signal_id;
_thunar_return_if_fail (GTK_IS_MENU (menu));
/* take over the floating reference on the menu */
g_object_ref_sink (G_OBJECT (menu));
- event = gtk_get_current_event ();
+ /* run an internal main loop */
+ loop = g_main_loop_new (NULL, FALSE);
+ signal_id = g_signal_connect_swapped (G_OBJECT (menu), "deactivate", G_CALLBACK (g_main_loop_quit), loop);
+
+#if GTK_CHECK_VERSION (3, 24, 8)
+ /* Workaround for incorrect popup menus size */
+ g_signal_connect (G_OBJECT (menu), "realize", G_CALLBACK (popup_menu_realized), NULL);
+ gtk_widget_realize (GTK_WIDGET (menu));
+#endif
+
gtk_menu_popup_at_pointer (menu, event);
- gdk_event_free (event);
gtk_menu_reposition (menu);
+ gtk_grab_add (GTK_WIDGET (menu));
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
+ gtk_grab_remove (GTK_WIDGET (menu));
+
+ g_signal_handler_disconnect (G_OBJECT (menu), signal_id);
/* release the menu reference */
g_object_unref (G_OBJECT (menu));
diff --git a/thunar/thunar-gtk-extensions.h b/thunar/thunar-gtk-extensions.h
index a264595c..98e0c30f 100644
--- a/thunar/thunar-gtk-extensions.h
+++ b/thunar/thunar-gtk-extensions.h
@@ -37,6 +37,9 @@ void thunar_gtk_label_set_a11y_relation (GtkLabel
void thunar_gtk_menu_run (GtkMenu *menu);
+void thunar_gtk_menu_run_at_event (GtkMenu *menu,
+ GdkEvent *event);
+
GtkAction *thunar_gtk_ui_manager_get_action_by_name (GtkUIManager *ui_manager,
const gchar *action_name);
diff --git a/thunar/thunar-icon-factory.c b/thunar/thunar-icon-factory.c
index 9b899c4f..16a5556a 100644
--- a/thunar/thunar-icon-factory.c
+++ b/thunar/thunar-icon-factory.c
@@ -361,7 +361,9 @@ thunar_icon_factory_sweep_timer (gpointer user_data)
THUNAR_THREADS_ENTER
/* ditch all icons whose ref_count is 1 */
- g_hash_table_foreach_remove (factory->icon_cache, (GHRFunc) thunar_icon_check_sweep, factory);
+ g_hash_table_foreach_remove (factory->icon_cache,
+ (GHRFunc) (void (*)(void)) thunar_icon_check_sweep,
+ factory);
THUNAR_THREADS_LEAVE
diff --git a/thunar/thunar-icon-view.c b/thunar/thunar-icon-view.c
index 5dcc71ef..5a97f646 100644
--- a/thunar/thunar-icon-view.c
+++ b/thunar/thunar-icon-view.c
@@ -98,7 +98,7 @@ thunar_icon_view_init (ThunarIconView *icon_view)
{
/* setup the icon renderer */
g_object_set (G_OBJECT (THUNAR_STANDARD_VIEW (icon_view)->icon_renderer),
- "ypad", 3u,
+ "ypad", 1u,
NULL);
/* setup the name renderer */
@@ -126,7 +126,7 @@ thunar_icon_view_set_property (GObject *object,
if (G_UNLIKELY (g_value_get_boolean (value)))
{
exo_icon_view_set_orientation (EXO_ICON_VIEW (gtk_bin_get_child (GTK_BIN (standard_view))), GTK_ORIENTATION_HORIZONTAL);
- g_object_set (G_OBJECT (standard_view->name_renderer), "wrap-width", 128, "yalign", 0.5f, "alignment", PANGO_ALIGN_LEFT, NULL);
+ g_object_set (G_OBJECT (standard_view->name_renderer), "wrap-width", 128, "yalign", 0.5f, "xalign", 0.0f, "alignment", PANGO_ALIGN_LEFT, NULL);
/* disconnect the "zoom-level" signal handler, since we're using a fixed wrap-width here */
g_signal_handlers_disconnect_by_func (object, thunar_icon_view_zoom_level_changed, NULL);
@@ -134,7 +134,7 @@ thunar_icon_view_set_property (GObject *object,
else
{
exo_icon_view_set_orientation (EXO_ICON_VIEW (gtk_bin_get_child (GTK_BIN (standard_view))), GTK_ORIENTATION_VERTICAL);
- g_object_set (G_OBJECT (standard_view->name_renderer), "yalign", 0.0f, "alignment", PANGO_ALIGN_CENTER, NULL);
+ g_object_set (G_OBJECT (standard_view->name_renderer), "yalign", 0.0f, "xalign", 0.5f, "alignment", PANGO_ALIGN_CENTER, NULL);
/* connect the "zoom-level" signal handler as the wrap-width is now synced with the "zoom-level" */
g_signal_connect (object, "notify::zoom-level", G_CALLBACK (thunar_icon_view_zoom_level_changed), NULL);
diff --git a/thunar/thunar-image.c b/thunar/thunar-image.c
index cff52052..e3fe3aa6 100644
--- a/thunar/thunar-image.c
+++ b/thunar/thunar-image.c
@@ -33,10 +33,6 @@
-#define THUNAR_IMAGE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), THUNAR_TYPE_IMAGE, ThunarImagePrivate))
-
-
-
/* Property identifiers */
enum
{
@@ -81,7 +77,7 @@ struct _ThunarImagePrivate
-G_DEFINE_TYPE (ThunarImage, thunar_image, GTK_TYPE_IMAGE);
+G_DEFINE_TYPE_WITH_PRIVATE (ThunarImage, thunar_image, GTK_TYPE_IMAGE);
@@ -90,8 +86,6 @@ thunar_image_class_init (ThunarImageClass *klass)
{
GObjectClass *gobject_class;
- g_type_class_add_private (klass, sizeof (ThunarImagePrivate));
-
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = thunar_image_finalize;
gobject_class->get_property = thunar_image_get_property;
@@ -110,7 +104,7 @@ thunar_image_class_init (ThunarImageClass *klass)
static void
thunar_image_init (ThunarImage *image)
{
- image->priv = THUNAR_IMAGE_GET_PRIVATE (image);
+ image->priv = thunar_image_get_instance_private (image);
image->priv->file = NULL;
image->priv->monitor = thunar_file_monitor_get_default ();
diff --git a/thunar/thunar-io-jobs.c b/thunar/thunar-io-jobs.c
index eaaa7072..4f641840 100644
--- a/thunar/thunar-io-jobs.c
+++ b/thunar/thunar-io-jobs.c
@@ -22,7 +22,12 @@
#include <config.h>
#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
#include <gio/gio.h>
+#include <glib/gstdio.h>
#include <thunar/thunar-application.h>
#include <thunar/thunar-enum-types.h>
@@ -83,6 +88,34 @@ _tij_collect_nofollow (ThunarJob *job,
+static gboolean
+_tij_delete_file (GFile *file,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gchar *path;
+
+ if (!g_file_is_native (file))
+ return g_file_delete (file, cancellable, error);
+
+ /* adapted from g_local_file_delete of gio/glocalfile.c */
+ path = g_file_get_path (file);
+
+ if (g_remove (path) == 0)
+ {
+ g_free (path);
+ return TRUE;
+ }
+
+ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
+ _("Error removing file: %s"), g_strerror (errno));
+
+ g_free (path);
+ return FALSE;
+}
+
+
+
static gboolean
_thunar_io_jobs_create (ThunarJob *job,
GArray *param_values,
@@ -96,6 +129,7 @@ _thunar_io_jobs_create (ThunarJob *job,
GList *lp;
gchar *base_name;
gchar *display_name;
+ guint n_processed = 0;
GFile *template_file;
GFileInputStream *template_stream = NULL;
@@ -126,12 +160,12 @@ _thunar_io_jobs_create (ThunarJob *job,
/* iterate over all files in the list */
for (lp = file_list;
err == NULL && lp != NULL && !exo_job_is_cancelled (EXO_JOB (job));
- lp = lp->next)
+ lp = lp->next, n_processed++)
{
g_assert (G_IS_FILE (lp->data));
/* update progress information */
- thunar_job_processing_file (THUNAR_JOB (job), lp);
+ thunar_job_processing_file (THUNAR_JOB (job), lp, n_processed);
again:
/* try to create the file */
@@ -184,7 +218,7 @@ again:
if (response == THUNAR_JOB_RESPONSE_YES)
{
/* try to remove the file. fail if not possible */
- if (g_file_delete (lp->data, exo_job_get_cancellable (EXO_JOB (job)), &err))
+ if (_tij_delete_file (lp->data, exo_job_get_cancellable (EXO_JOB (job)), &err))
goto again;
}
@@ -272,6 +306,7 @@ _thunar_io_jobs_mkdir (ThunarJob *job,
GList *lp;
gchar *base_name;
gchar *display_name;
+ guint n_processed = 0;
_thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
_thunar_return_val_if_fail (param_values != NULL, FALSE);
@@ -285,12 +320,12 @@ _thunar_io_jobs_mkdir (ThunarJob *job,
for (lp = file_list;
err == NULL && lp != NULL && !exo_job_is_cancelled (EXO_JOB (job));
- lp = lp->next)
+ lp = lp->next, n_processed++)
{
g_assert (G_IS_FILE (lp->data));
/* update progress information */
- thunar_job_processing_file (THUNAR_JOB (job), lp);
+ thunar_job_processing_file (THUNAR_JOB (job), lp, n_processed);
again:
/* try to create the directory */
@@ -338,7 +373,7 @@ again:
if (response == THUNAR_JOB_RESPONSE_YES)
{
/* try to remove the file, fail if not possible */
- if (g_file_delete (lp->data, exo_job_get_cancellable (EXO_JOB (job)), &err))
+ if (_tij_delete_file (lp->data, exo_job_get_cancellable (EXO_JOB (job)), &err))
goto again;
}
@@ -410,6 +445,7 @@ _thunar_io_jobs_unlink (ThunarJob *job,
GList *lp;
gchar *base_name;
gchar *display_name;
+ guint n_processed = 0;
_thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
_thunar_return_val_if_fail (param_values != NULL, FALSE);
@@ -446,7 +482,9 @@ _thunar_io_jobs_unlink (ThunarJob *job,
g_object_unref (application);
/* remove all the files */
- for (lp = file_list; lp != NULL && !exo_job_is_cancelled (EXO_JOB (job)); lp = lp->next)
+ for (lp = file_list;
+ lp != NULL && !exo_job_is_cancelled (EXO_JOB (job));
+ lp = lp->next, n_processed++)
{
g_assert (G_IS_FILE (lp->data));
@@ -455,11 +493,11 @@ _thunar_io_jobs_unlink (ThunarJob *job,
continue;
/* update progress information */
- thunar_job_processing_file (THUNAR_JOB (job), lp);
+ thunar_job_processing_file (THUNAR_JOB (job), lp, n_processed);
again:
/* try to delete the file */
- if (g_file_delete (lp->data, exo_job_get_cancellable (EXO_JOB (job)), &err))
+ if (_tij_delete_file (lp->data, exo_job_get_cancellable (EXO_JOB (job)), &err))
{
/* notify the thumbnail cache that the corresponding thumbnail can also
* be deleted now */
@@ -673,7 +711,7 @@ _thunar_io_jobs_link_file (ThunarJob *job,
{
/* try to remove the target file. if not possible, err will be set and
* the while loop will be aborted */
- g_file_delete (target_file, exo_job_get_cancellable (EXO_JOB (job)), &err);
+ _tij_delete_file (target_file, exo_job_get_cancellable (EXO_JOB (job)), &err);
}
/* tell the caller that we skipped this file if the user doesn't want to
@@ -708,6 +746,7 @@ _thunar_io_jobs_link (ThunarJob *job,
GList *sp;
GList *target_file_list;
GList *tp;
+ guint n_processed = 0;
_thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
_thunar_return_val_if_fail (param_values != NULL, FALSE);
@@ -728,13 +767,13 @@ _thunar_io_jobs_link (ThunarJob *job,
/* process all files */
for (sp = source_file_list, tp = target_file_list;
err == NULL && sp != NULL && tp != NULL;
- sp = sp->next, tp = tp->next)
+ sp = sp->next, tp = tp->next, n_processed++)
{
_thunar_assert (G_IS_FILE (sp->data));
_thunar_assert (G_IS_FILE (tp->data));
/* update progress information */
- thunar_job_processing_file (THUNAR_JOB (job), sp);
+ thunar_job_processing_file (THUNAR_JOB (job), sp, n_processed);
/* try to create the symbolic link */
real_target_file = _thunar_io_jobs_link_file (job, sp->data, tp->data, &err);
@@ -799,6 +838,7 @@ _thunar_io_jobs_trash (ThunarJob *job,
{
ThunarThumbnailCache *thumbnail_cache;
ThunarApplication *application;
+ ThunarJobResponse response;
GError *err = NULL;
GList *file_list;
GList *lp;
@@ -825,6 +865,19 @@ _thunar_io_jobs_trash (ThunarJob *job,
/* trash the file or folder */
g_file_trash (lp->data, exo_job_get_cancellable (EXO_JOB (job)), &err);
+ if (err != NULL)
+ {
+ response = thunar_job_ask_delete (job, "%s", err->message);
+
+ g_clear_error (&err);
+
+ if (response == THUNAR_JOB_RESPONSE_CANCEL)
+ break;
+
+ if (response == THUNAR_JOB_RESPONSE_YES)
+ _tij_delete_file (lp->data, exo_job_get_cancellable (EXO_JOB (job)), &err);
+ }
+
/* update the thumbnail cache */
thunar_thumbnail_cache_cleanup_file (thumbnail_cache, lp->data);
}
@@ -888,6 +941,7 @@ _thunar_io_jobs_chown (ThunarJob *job,
GList *lp;
gint uid;
gint gid;
+ guint n_processed = 0;
_thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
_thunar_return_val_if_fail (param_values != NULL, FALSE);
@@ -917,10 +971,10 @@ _thunar_io_jobs_chown (ThunarJob *job,
thunar_job_set_total_files (THUNAR_JOB (job), file_list);
/* change the ownership of all files */
- for (lp = file_list; lp != NULL && err == NULL; lp = lp->next)
+ for (lp = file_list; lp != NULL && err == NULL; lp = lp->next, n_processed++)
{
/* update progress information */
- thunar_job_processing_file (THUNAR_JOB (job), lp);
+ thunar_job_processing_file (THUNAR_JOB (job), lp, n_processed);
/* try to query information about the file */
info = g_file_query_info (lp->data,
@@ -1000,7 +1054,7 @@ thunar_io_jobs_change_group (GList *files,
_thunar_return_val_if_fail (files != NULL, NULL);
/* files are released when the list if destroyed */
- g_list_foreach (files, (GFunc) g_object_ref, NULL);
+ g_list_foreach (files, (GFunc) (void (*)(void)) g_object_ref, NULL);
return thunar_simple_job_launch (_thunar_io_jobs_chown, 4,
THUNAR_TYPE_G_FILE_LIST, files,
@@ -1022,6 +1076,7 @@ _thunar_io_jobs_chmod (ThunarJob *job,
GError *err = NULL;
GList *file_list;
GList *lp;
+ guint n_processed = 0;
ThunarFileMode dir_mask;
ThunarFileMode dir_mode;
ThunarFileMode file_mask;
@@ -1059,10 +1114,10 @@ _thunar_io_jobs_chmod (ThunarJob *job,
thunar_job_set_total_files (THUNAR_JOB (job), file_list);
/* change the ownership of all files */
- for (lp = file_list; lp != NULL && err == NULL; lp = lp->next)
+ for (lp = file_list; lp != NULL && err == NULL; lp = lp->next, n_processed++)
{
/* update progress information */
- thunar_job_processing_file (THUNAR_JOB (job), lp);
+ thunar_job_processing_file (THUNAR_JOB (job), lp, n_processed);
/* try to query information about the file */
info = g_file_query_info (lp->data,
@@ -1155,7 +1210,7 @@ thunar_io_jobs_change_mode (GList *files,
_thunar_return_val_if_fail (files != NULL, NULL);
/* files are released when the list if destroyed */
- g_list_foreach (files, (GFunc) g_object_ref, NULL);
+ g_list_foreach (files, (GFunc) (void (*)(void)) g_object_ref, NULL);
return thunar_simple_job_launch (_thunar_io_jobs_chmod, 6,
THUNAR_TYPE_G_FILE_LIST, files,
diff --git a/thunar/thunar-io-scan-directory.c b/thunar/thunar-io-scan-directory.c
index 8f81724c..8072db1d 100644
--- a/thunar/thunar-io-scan-directory.c
+++ b/thunar/thunar-io-scan-directory.c
@@ -52,19 +52,19 @@ thunar_io_scan_directory (ThunarJob *job,
const gchar *namespace;
ThunarFile *thunar_file;
gboolean is_mounted;
+ GCancellable *cancellable = NULL;
- _thunar_return_val_if_fail (THUNAR_IS_JOB (job), NULL);
_thunar_return_val_if_fail (G_IS_FILE (file), NULL);
_thunar_return_val_if_fail (error == NULL || *error == NULL, NULL);
/* abort if the job was cancelled */
- if (exo_job_set_error_if_cancelled (EXO_JOB (job), error))
+ if (job != NULL && exo_job_set_error_if_cancelled (EXO_JOB (job), error))
return NULL;
/* don't recurse when we are scanning prior to unlinking and the current
* file/dir is in the trash. In GVfs, only the top-level directories in
* the trash can be modified and deleted directly. See
- * http://bugzilla.xfce.org/show_bug.cgi?id=7147
+ * https://bugzilla.xfce.org/show_bug.cgi?id=7147
* for more information */
if (unlinking
&& thunar_g_file_is_trashed (file)
@@ -73,11 +73,14 @@ thunar_io_scan_directory (ThunarJob *job,
return NULL;
}
+ if (job != NULL)
+ cancellable = exo_job_get_cancellable (EXO_JOB (job));
+
/* query the file type */
- type = g_file_query_file_type (file, flags, exo_job_get_cancellable (EXO_JOB (job)));
+ type = g_file_query_file_type (file, flags, cancellable);
/* abort if the job was cancelled */
- if (exo_job_set_error_if_cancelled (EXO_JOB (job), error))
+ if (job != NULL && exo_job_set_error_if_cancelled (EXO_JOB (job), error))
return NULL;
/* ignore non-directory nodes */
@@ -93,8 +96,7 @@ thunar_io_scan_directory (ThunarJob *job,
/* try to read from the direectory */
enumerator = g_file_enumerate_children (file, namespace,
- flags, exo_job_get_cancellable (EXO_JOB (job)),
- &err);
+ flags, cancellable, &err);
/* abort if there was an error or the job was cancelled */
if (err != NULL)
@@ -104,12 +106,10 @@ thunar_io_scan_directory (ThunarJob *job,
}
/* iterate over children one by one */
- while (!exo_job_is_cancelled (EXO_JOB (job)))
+ while (job == NULL || !exo_job_is_cancelled (EXO_JOB (job)))
{
/* query info of the child */
- info = g_file_enumerator_next_file (enumerator,
- exo_job_get_cancellable (EXO_JOB (job)),
- &err);
+ info = g_file_enumerator_next_file (enumerator, cancellable, &err);
if (G_UNLIKELY (info == NULL))
break;
@@ -171,7 +171,7 @@ thunar_io_scan_directory (ThunarJob *job,
thunar_g_file_list_free (files);
return NULL;
}
- else if (exo_job_set_error_if_cancelled (EXO_JOB (job), &err))
+ else if (job != NULL && exo_job_set_error_if_cancelled (EXO_JOB (job), &err))
{
g_propagate_error (error, err);
thunar_g_file_list_free (files);
diff --git a/thunar/thunar-job.c b/thunar/thunar-job.c
index 867278ef..88cc36d7 100644
--- a/thunar/thunar-job.c
+++ b/thunar/thunar-job.c
@@ -38,10 +38,6 @@
-#define THUNAR_JOB_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), THUNAR_TYPE_JOB, ThunarJobPrivate))
-
-
-
/* Signal identifiers */
enum
{
@@ -68,8 +64,10 @@ struct _ThunarJobPrivate
{
ThunarJobResponse earlier_ask_create_response;
ThunarJobResponse earlier_ask_overwrite_response;
+ ThunarJobResponse earlier_ask_delete_response;
ThunarJobResponse earlier_ask_skip_response;
GList *total_files;
+ guint n_total_files;
};
@@ -78,7 +76,7 @@ static guint job_signals[LAST_SIGNAL];
-G_DEFINE_ABSTRACT_TYPE (ThunarJob, thunar_job, EXO_TYPE_JOB)
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ThunarJob, thunar_job, EXO_TYPE_JOB)
@@ -99,9 +97,6 @@ thunar_job_class_init (ThunarJobClass *klass)
{
GObjectClass *gobject_class;
- /* add our private data for this class */
- g_type_class_add_private (klass, sizeof (ThunarJobPrivate));
-
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = thunar_job_finalize;
@@ -209,10 +204,12 @@ thunar_job_class_init (ThunarJobClass *klass)
static void
thunar_job_init (ThunarJob *job)
{
- job->priv = THUNAR_JOB_GET_PRIVATE (job);
+ job->priv = thunar_job_get_instance_private (job);
job->priv->earlier_ask_create_response = 0;
job->priv->earlier_ask_overwrite_response = 0;
+ job->priv->earlier_ask_delete_response = 0;
job->priv->earlier_ask_skip_response = 0;
+ job->priv->n_total_files = 0;
}
@@ -362,6 +359,63 @@ thunar_job_ask_overwrite (ThunarJob *job,
+ThunarJobResponse
+thunar_job_ask_delete (ThunarJob *job,
+ const gchar *format,
+ ...)
+{
+ ThunarJobResponse response;
+ va_list var_args;
+
+ _thunar_return_val_if_fail (THUNAR_IS_JOB (job), THUNAR_JOB_RESPONSE_CANCEL);
+ _thunar_return_val_if_fail (format != NULL, THUNAR_JOB_RESPONSE_CANCEL);
+
+ /* check if the user already cancelled the job */
+ if (G_UNLIKELY (exo_job_is_cancelled (EXO_JOB (job))))
+ return THUNAR_JOB_RESPONSE_CANCEL;
+
+ /* check if the user said "Delete All" earlier */
+ if (G_UNLIKELY (job->priv->earlier_ask_delete_response == THUNAR_JOB_RESPONSE_YES_ALL))
+ return THUNAR_JOB_RESPONSE_YES;
+
+ /* check if the user said "Delete None" earlier */
+ if (G_UNLIKELY (job->priv->earlier_ask_delete_response == THUNAR_JOB_RESPONSE_NO_ALL))
+ return THUNAR_JOB_RESPONSE_NO;
+
+ /* ask the user what he wants to do */
+ va_start (var_args, format);
+ response = _thunar_job_ask_valist (job, format, var_args,
+ _("Do you want to permanently delete it?"),
+ THUNAR_JOB_RESPONSE_YES
+ | THUNAR_JOB_RESPONSE_YES_ALL
+ | THUNAR_JOB_RESPONSE_NO
+ | THUNAR_JOB_RESPONSE_NO_ALL
+ | THUNAR_JOB_RESPONSE_CANCEL);
+ va_end (var_args);
+
+ /* remember response for later */
+ job->priv->earlier_ask_delete_response = response;
+
+ /* translate response */
+ switch (response)
+ {
+ case THUNAR_JOB_RESPONSE_YES_ALL:
+ response = THUNAR_JOB_RESPONSE_YES;
+ break;
+
+ case THUNAR_JOB_RESPONSE_NO_ALL:
+ response = THUNAR_JOB_RESPONSE_NO;
+ break;
+
+ default:
+ break;
+ }
+
+ return response;
+}
+
+
+
ThunarJobResponse
thunar_job_ask_create (ThunarJob *job,
const gchar *format,
@@ -598,23 +652,26 @@ thunar_job_set_total_files (ThunarJob *job,
_thunar_return_if_fail (total_files != NULL);
job->priv->total_files = total_files;
+ job->priv->n_total_files = g_list_length (total_files);
}
void
thunar_job_processing_file (ThunarJob *job,
- GList *current_file)
+ GList *current_file,
+ guint n_processed)
{
- GList *lp;
gchar *base_name;
gchar *display_name;
- guint n_processed;
- guint n_total;
_thunar_return_if_fail (THUNAR_IS_JOB (job));
_thunar_return_if_fail (current_file != NULL);
+ /* emit only if n_processed is a multiple of 8 */
+ if ((n_processed % 8) != 0)
+ return;
+
base_name = g_file_get_basename (current_file->data);
display_name = g_filename_display_name (base_name);
g_free (base_name);
@@ -623,20 +680,6 @@ thunar_job_processing_file (ThunarJob *job,
g_free (display_name);
/* verify that we have total files set */
- if (G_LIKELY (job->priv->total_files != NULL))
- {
- /* determine the number of files processed so far */
- for (lp = job->priv->total_files, n_processed = 0;
- lp != current_file;
- lp = lp->next, n_processed++);
-
- /* emit only if n_processed is a multiple of 8 */
- if ((n_processed % 8) == 0)
- {
- /* determine the total_number of files */
- n_total = g_list_length (job->priv->total_files);
-
- exo_job_percent (EXO_JOB (job), (n_processed * 100.0) / n_total);
- }
- }
+ if (G_LIKELY (job->priv->n_total_files > 0))
+ exo_job_percent (EXO_JOB (job), (n_processed * 100.0) / job->priv->n_total_files);
}
diff --git a/thunar/thunar-job.h b/thunar/thunar-job.h
index f1f636bd..9c0a7b41 100644
--- a/thunar/thunar-job.h
+++ b/thunar/thunar-job.h
@@ -69,7 +69,8 @@ GType thunar_job_get_type (void) G_GNUC_CONST;
void thunar_job_set_total_files (ThunarJob *job,
GList *total_files);
void thunar_job_processing_file (ThunarJob *job,
- GList *current_file);
+ GList *current_file,
+ guint n_processed);
ThunarJobResponse thunar_job_ask_create (ThunarJob *job,
const gchar *format,
@@ -77,6 +78,9 @@ ThunarJobResponse thunar_job_ask_create (ThunarJob *job,
ThunarJobResponse thunar_job_ask_overwrite (ThunarJob *job,
const gchar *format,
...);
+ThunarJobResponse thunar_job_ask_delete (ThunarJob *job,
+ const gchar *format,
+ ...);
ThunarJobResponse thunar_job_ask_replace (ThunarJob *job,
GFile *source_path,
GFile *target_path,
diff --git a/thunar/thunar-launcher.c b/thunar/thunar-launcher.c
index b34b491b..20789fe7 100644
--- a/thunar/thunar-launcher.c
+++ b/thunar/thunar-launcher.c
@@ -33,6 +33,7 @@
#include <thunar/thunar-browser.h>
#include <thunar/thunar-chooser-dialog.h>
#include <thunar/thunar-dialogs.h>
+#include <thunar/thunar-file-monitor.h>
#include <thunar/thunar-gio-extensions.h>
#include <thunar/thunar-gobject-extensions.h>
#include <thunar/thunar-gtk-extensions.h>
@@ -154,6 +155,8 @@ struct _ThunarLauncher
ThunarDeviceMonitor *device_monitor;
ThunarSendtoModel *sendto_model;
guint sendto_idle_id;
+
+ ThunarFileMonitor *file_monitor;
};
struct _ThunarLauncherMountData
@@ -290,6 +293,10 @@ G_GNUC_END_IGNORE_DEPRECATIONS
launcher->device_monitor = thunar_device_monitor_get ();
g_signal_connect_swapped (launcher->device_monitor, "device-added", G_CALLBACK (thunar_launcher_update), launcher);
g_signal_connect_swapped (launcher->device_monitor, "device-removed", G_CALLBACK (thunar_launcher_update), launcher);
+
+ /* update launcher actions when any monitored file changes */
+ launcher->file_monitor = thunar_file_monitor_get_default ();
+ g_signal_connect_swapped (launcher->file_monitor, "file-changed", G_CALLBACK (thunar_launcher_update), launcher);
}
@@ -336,6 +343,10 @@ thunar_launcher_finalize (GObject *object)
/* release the reference on the sendto model */
g_object_unref (launcher->sendto_model);
+ /* disconnect from the file monitor */
+ g_signal_handlers_disconnect_by_func (launcher->file_monitor, thunar_launcher_update, launcher);
+ g_object_unref (launcher->file_monitor);
+
(*G_OBJECT_CLASS (thunar_launcher_parent_class)->finalize) (object);
}
@@ -1761,6 +1772,7 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
/* allocate a new action for the device */
action = gtk_action_new (name, device_name, tooltip, NULL);
g_object_set_qdata_full (G_OBJECT (action), thunar_launcher_handler_quark, lp->data, g_object_unref);
+ g_object_set_data (G_OBJECT (lp->data), "skip-app-info-update", GUINT_TO_POINTER (1));
g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (thunar_launcher_action_sendto_device), launcher);
gtk_action_group_add_action (launcher->action_group, action);
gtk_ui_manager_add_ui (launcher->ui_manager, launcher->ui_addons_merge_id,
@@ -1818,6 +1830,7 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
action = gtk_action_new (name, label, tooltip, NULL);
gtk_action_set_gicon (action, g_app_info_get_icon (lp->data));
g_object_set_qdata_full (G_OBJECT (action), thunar_launcher_handler_quark, lp->data, g_object_unref);
+ g_object_set_data (G_OBJECT (lp->data), "skip-app-info-update", GUINT_TO_POINTER (1));
g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (thunar_launcher_action_open), launcher);
gtk_action_group_add_action (launcher->action_group, action);
gtk_ui_manager_add_ui (launcher->ui_manager, launcher->ui_addons_merge_id,
diff --git a/thunar/thunar-list-model.c b/thunar/thunar-list-model.c
index bc82f85c..201862c2 100644
--- a/thunar/thunar-list-model.c
+++ b/thunar/thunar-list-model.c
@@ -1741,7 +1741,7 @@ thunar_list_model_set_case_sensitive (ThunarListModel *store,
/* emit a "changed" signal for each row, so the display is
reloaded with the new case-sensitive setting */
gtk_tree_model_foreach (GTK_TREE_MODEL (store),
- (GtkTreeModelForeachFunc) gtk_tree_model_row_changed,
+ (GtkTreeModelForeachFunc) (void (*)(void)) gtk_tree_model_row_changed,
NULL);
}
}
@@ -1789,7 +1789,9 @@ thunar_list_model_set_date_style (ThunarListModel *store,
g_object_notify_by_pspec (G_OBJECT (store), list_model_props[PROP_DATE_STYLE]);
/* emit a "changed" signal for each row, so the display is reloaded with the new date style */
- gtk_tree_model_foreach (GTK_TREE_MODEL (store), (GtkTreeModelForeachFunc) gtk_tree_model_row_changed, NULL);
+ gtk_tree_model_foreach (GTK_TREE_MODEL (store),
+ (GtkTreeModelForeachFunc) (void (*)(void)) gtk_tree_model_row_changed,
+ NULL);
}
}
@@ -1834,7 +1836,9 @@ thunar_list_model_set_date_custom_style (ThunarListModel *store,
g_object_notify_by_pspec (G_OBJECT (store), list_model_props[PROP_DATE_CUSTOM_STYLE]);
/* emit a "changed" signal for each row, so the display is reloaded with the new date style */
- gtk_tree_model_foreach (GTK_TREE_MODEL (store), (GtkTreeModelForeachFunc) gtk_tree_model_row_changed, NULL);
+ gtk_tree_model_foreach (GTK_TREE_MODEL (store),
+ (GtkTreeModelForeachFunc) (void (*)(void)) gtk_tree_model_row_changed,
+ NULL);
}
}
@@ -1996,7 +2000,7 @@ thunar_list_model_set_folders_first (ThunarListModel *store,
/* emit a "changed" signal for each row, so the display is
reloaded with the new folders first setting */
gtk_tree_model_foreach (GTK_TREE_MODEL (store),
- (GtkTreeModelForeachFunc) gtk_tree_model_row_changed,
+ (GtkTreeModelForeachFunc) (void (*)(void)) gtk_tree_model_row_changed,
NULL);
}
@@ -2155,7 +2159,7 @@ thunar_list_model_set_file_size_binary (ThunarListModel *store,
/* emit a "changed" signal for each row, so the display is
reloaded with the new binary file size setting */
gtk_tree_model_foreach (GTK_TREE_MODEL (store),
- (GtkTreeModelForeachFunc) gtk_tree_model_row_changed,
+ (GtkTreeModelForeachFunc) (void (*)(void)) gtk_tree_model_row_changed,
NULL);
}
}
diff --git a/thunar/thunar-location-button.c b/thunar/thunar-location-button.c
index 30ea56e4..126ba936 100644
--- a/thunar/thunar-location-button.c
+++ b/thunar/thunar-location-button.c
@@ -444,6 +444,10 @@ thunar_location_button_file_changed (ThunarLocationButton *location_button,
dnd_icon_name = thunar_file_get_icon_name (file, location_button->file_icon_state, icon_theme);
gtk_drag_source_set_icon_name (GTK_WIDGET (location_button), dnd_icon_name);
}
+
+ /* recalculate the required size in case the filename changed */
+ gtk_widget_set_size_request (GTK_WIDGET (location_button->label), -1, -1);
+
}
@@ -559,7 +563,7 @@ thunar_location_button_button_release_event (GtkWidget *button,
if (open_in_tab)
{
/* open in tab */
- g_signal_emit_by_name (G_OBJECT (button), "location-button-clicked", 0, TRUE);
+ g_signal_emit_by_name (G_OBJECT (button), "location-button-clicked", TRUE);
}
else
{
diff --git a/thunar/thunar-location-buttons.c b/thunar/thunar-location-buttons.c
index 872e4568..eed9dffa 100644
--- a/thunar/thunar-location-buttons.c
+++ b/thunar/thunar-location-buttons.c
@@ -1280,7 +1280,7 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
/* setup the "Empty Trash" action */
action = gtk_action_group_get_action (buttons->action_group, "location-buttons-empty-trash");
gtk_action_set_visible (action, (thunar_file_is_root (file) && thunar_file_is_trashed (file)));
- gtk_action_set_sensitive (action, (thunar_file_get_size (file) > 0));
+ gtk_action_set_sensitive (action, (thunar_file_get_item_count (file) > 0));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), gtk_action_create_menu_item (action));
G_GNUC_END_IGNORE_DEPRECATIONS
diff --git a/thunar/thunar-location-entry.c b/thunar/thunar-location-entry.c
index fff18e1e..bd9406ea 100644
--- a/thunar/thunar-location-entry.c
+++ b/thunar/thunar-location-entry.c
@@ -62,6 +62,9 @@ static void thunar_location_entry_set_current_directory (ThunarNavigat
ThunarFile *current_directory);
static void thunar_location_entry_activate (GtkWidget *path_entry,
ThunarLocationEntry *location_entry);
+static gboolean thunar_location_entry_button_press_event (GtkWidget *path_entry,
+ GdkEventButton *event,
+ ThunarLocationEntry *location_entry);
static gboolean thunar_location_entry_reset (ThunarLocationEntry *location_entry);
static void thunar_location_entry_reload (GtkEntry *entry,
GtkEntryIconPosition icon_pos,
@@ -89,6 +92,8 @@ struct _ThunarLocationEntry
ThunarFile *current_directory;
GtkWidget *path_entry;
+
+ gboolean right_click_occurred;
};
@@ -198,6 +203,11 @@ thunar_location_entry_init (ThunarLocationEntry *location_entry)
/* make sure the edit-done signal is emitted upon moving the focus somewhere else */
g_signal_connect_swapped (location_entry->path_entry, "focus-out-event", G_CALLBACK (thunar_location_entry_emit_edit_done), location_entry);
+
+ /* ...except if it is grabbed by the context menu */
+ location_entry->right_click_occurred = FALSE;
+ g_signal_connect (G_OBJECT (location_entry->path_entry), "button-press-event",
+ G_CALLBACK (thunar_location_entry_button_press_event), location_entry);
}
@@ -410,6 +420,24 @@ thunar_location_entry_activate (GtkWidget *path_entry,
+static gboolean
+thunar_location_entry_button_press_event (GtkWidget *path_entry,
+ GdkEventButton *event,
+ ThunarLocationEntry *location_entry)
+{
+ _thunar_return_val_if_fail (THUNAR_IS_LOCATION_ENTRY (location_entry), FALSE);
+
+ /* check if the context menu was triggered */
+ if (event->type == GDK_BUTTON_PRESS && event->button == 3)
+ {
+ location_entry->right_click_occurred = TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
static gboolean
thunar_location_entry_reset (ThunarLocationEntry *location_entry)
{
@@ -445,7 +473,13 @@ thunar_location_entry_reload (GtkEntry *entry,
static void
thunar_location_entry_emit_edit_done (ThunarLocationEntry *entry)
{
- g_signal_emit_by_name (entry, "edit-done");
+ /* do not emit signal if the context menu was opened */
+ if (entry->right_click_occurred == FALSE)
+ {
+ g_signal_emit_by_name (entry, "edit-done");
+ }
+
+ entry->right_click_occurred = FALSE;
}
diff --git a/thunar/thunar-menu-util.c b/thunar/thunar-menu-util.c
index ca32ee4c..5caacc41 100644
--- a/thunar/thunar-menu-util.c
+++ b/thunar/thunar-menu-util.c
@@ -72,7 +72,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
g_signal_connect_data (action, "activate",
G_CALLBACK (extension_action_callback),
g_object_ref (item),
- (GClosureNotify) g_object_unref, 0);
+ (GClosureNotify) (void (*)(void)) g_object_unref, 0);
g_free (name);
g_free (label);
diff --git a/thunar/thunar-misc-jobs.c b/thunar/thunar-misc-jobs.c
deleted file mode 100644
index f131d8d1..00000000
--- a/thunar/thunar-misc-jobs.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/* vi:set et ai sw=2 sts=2 ts=2: */
-/*-
- * Copyright (c) 2009-2011 Jannis Pohlmann <jannis@xfce.org>
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <gio/gio.h>
-
-#include <thunar/thunar-io-scan-directory.h>
-#include <thunar/thunar-job.h>
-#include <thunar/thunar-misc-jobs.h>
-#include <thunar/thunar-private.h>
-#include <thunar/thunar-simple-job.h>
-
-
-
-static gboolean
-_thunar_misc_jobs_load_templates (ThunarJob *job,
- GArray *param_values,
- GError **error)
-{
- GtkWidget *menu;
- GFile *home_dir;
- GFile *templates_dir;
- GList *files = NULL;
- const gchar *path;
-
- _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
- _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- _thunar_return_val_if_fail (param_values != NULL && param_values->len == 1, FALSE);
-
- menu = g_value_get_object (&g_array_index (param_values, GValue, 0));
- g_object_set_data (G_OBJECT (job), "menu", menu);
-
- home_dir = thunar_g_file_new_for_home ();
- path = g_get_user_special_dir (G_USER_DIRECTORY_TEMPLATES);
- if (G_LIKELY (path != NULL))
- templates_dir = g_file_new_for_path (path);
- else
- templates_dir = g_file_resolve_relative_path (home_dir, "Templates");
-
- if (G_LIKELY (!g_file_equal (templates_dir, home_dir)))
- {
- /* load the ThunarFiles */
- files = thunar_io_scan_directory (job, templates_dir,
- G_FILE_QUERY_INFO_NONE, /* symlink ok */
- TRUE, FALSE, TRUE, NULL);
- }
-
- g_object_unref (templates_dir);
- g_object_unref (home_dir);
-
- if (files == NULL || exo_job_is_cancelled (EXO_JOB (job)))
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- _("No templates installed"));
-
- return FALSE;
- }
- else
- {
- if (!thunar_job_files_ready (job, files))
- thunar_g_file_list_free (files);
-
- return TRUE;
- }
-}
-
-
-
-ThunarJob *
-thunar_misc_jobs_load_template_files (GtkWidget *menu)
-{
- return thunar_simple_job_launch (_thunar_misc_jobs_load_templates, 1,
- GTK_TYPE_MENU, menu);
-}
diff --git a/thunar/thunar-misc-jobs.h b/thunar/thunar-misc-jobs.h
deleted file mode 100644
index 21483af0..00000000
--- a/thunar/thunar-misc-jobs.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* vi:set et ai sw=2 sts=2 ts=2: */
-/*-
- * Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef __THUNAR_MISC_JOBS_H__
-#define __THUNAR_MISC_JOBS_H__
-
-#include <thunar/thunar-job.h>
-
-G_BEGIN_DECLS
-
-ThunarJob *thunar_misc_jobs_load_template_files (GtkWidget *menu);
-
-G_END_DECLS
-
-#endif /* !__THUNAR_MISC_JOBS_H__ */
diff --git a/thunar/thunar-navigator.c b/thunar/thunar-navigator.c
index ff3e7617..ad5e8686 100644
--- a/thunar/thunar-navigator.c
+++ b/thunar/thunar-navigator.c
@@ -57,7 +57,7 @@ thunar_navigator_get_type (void)
sizeof (ThunarNavigatorIface),
(GBaseInitFunc) thunar_navigator_base_init,
NULL,
- (GClassInitFunc) thunar_navigator_class_init,
+ (GClassInitFunc) (void (*)(void)) thunar_navigator_class_init,
NULL,
NULL,
0,
diff --git a/thunar/thunar-pango-extensions.c b/thunar/thunar-pango-extensions.c
index 545b3a96..d42f83ba 100644
--- a/thunar/thunar-pango-extensions.c
+++ b/thunar/thunar-pango-extensions.c
@@ -118,6 +118,31 @@ thunar_pango_attr_list_bold (void)
+/**
+ * thunar_pango_attr_disable_hyphens:
+ *
+ * Returns a #PangoAttrList for not inserting hyphens at intra-word line breaks.
+ * The returned list is owned by the callee and must
+ * not be freed or modified by the caller.
+ *
+ * Return value: a #PangoAttrList for not inserting hyphens at intra-word line
+ * breaks.
+ **/
+#if PANGO_VERSION_CHECK (1, 44, 0)
+PangoAttrList*
+thunar_pango_attr_disable_hyphens (void)
+{
+ static PangoAttrList *attr_list = NULL;
+
+ if (G_UNLIKELY (attr_list == NULL))
+ attr_list = thunar_pango_attr_list_wrap (pango_attr_insert_hyphens_new (FALSE), NULL);
+
+ return attr_list;
+}
+#endif
+
+
+
/**
* thunar_pango_attr_list_italic:
*
diff --git a/thunar/thunar-pango-extensions.h b/thunar/thunar-pango-extensions.h
index a9d2c1cd..c86966e1 100644
--- a/thunar/thunar-pango-extensions.h
+++ b/thunar/thunar-pango-extensions.h
@@ -27,6 +27,9 @@ G_BEGIN_DECLS;
PangoAttrList *thunar_pango_attr_list_big (void) G_GNUC_CONST;
PangoAttrList *thunar_pango_attr_list_big_bold (void) G_GNUC_CONST;
PangoAttrList *thunar_pango_attr_list_bold (void) G_GNUC_CONST;
+#if PANGO_VERSION_CHECK (1, 44, 0)
+PangoAttrList *thunar_pango_attr_disable_hyphens (void) G_GNUC_CONST;
+#endif
PangoAttrList *thunar_pango_attr_list_italic (void) G_GNUC_CONST;
PangoAttrList *thunar_pango_attr_list_small_italic (void) G_GNUC_CONST;
PangoAttrList *thunar_pango_attr_list_small (void) G_GNUC_CONST;
diff --git a/thunar/thunar-path-entry.c b/thunar/thunar-path-entry.c
index 049e0ed2..76b5b64c 100644
--- a/thunar/thunar-path-entry.c
+++ b/thunar/thunar-path-entry.c
@@ -614,7 +614,7 @@ thunar_path_entry_changed (GtkEditable *editable)
/* set the new folder for the completion model, but disconnect the model from the
* completion first, because GtkEntryCompletion has become very slow recently when
- * updating the model being used (http://bugzilla.xfce.org/show_bug.cgi?id=1681).
+ * updating the model being used (https://bugzilla.xfce.org/show_bug.cgi?id=1681).
*/
model = gtk_entry_completion_get_model (completion);
g_object_ref (G_OBJECT (model));
@@ -893,22 +893,29 @@ thunar_path_entry_match_func (GtkEntryCompletion *completion,
GtkTreeIter *iter,
gpointer user_data)
{
- GtkTreeModel *model;
- const gchar *last_slash;
- ThunarFile *file;
- gboolean matched;
- gchar *text_normalized;
- gchar *name_normalized;
- gchar *name;
+ GtkTreeModel *model;
+ ThunarPathEntry *path_entry;
+ const gchar *last_slash;
+ ThunarFile *file;
+ gboolean matched;
+ gchar *text_normalized;
+ gchar *name_normalized;
+ gchar *name;
/* determine the model from the completion */
model = gtk_entry_completion_get_model (completion);
/* leave if the model is null, we do this in thunar_path_entry_changed() to speed
- * things up, but that causes http://bugzilla.xfce.org/show_bug.cgi?id=4847. */
+ * things up, but that causes https://bugzilla.xfce.org/show_bug.cgi?id=4847. */
if (G_UNLIKELY (model == NULL))
return FALSE;
+ /* leave if the auto completion highlight was not cleared yet, to prevent
+ * https://bugzilla.xfce.org/show_bug.cgi?id=16267. */
+ path_entry = THUNAR_PATH_ENTRY (user_data);
+ if (G_UNLIKELY (path_entry->has_completion))
+ return FALSE;
+
/* determine the current text (UTF-8 normalized) */
text_normalized = g_utf8_normalize (gtk_entry_get_text (GTK_ENTRY (user_data)), -1, G_NORMALIZE_ALL);
diff --git a/thunar/thunar-permissions-chooser.c b/thunar/thunar-permissions-chooser.c
index e02e2fca..b4534313 100644
--- a/thunar/thunar-permissions-chooser.c
+++ b/thunar/thunar-permissions-chooser.c
@@ -939,7 +939,7 @@ thunar_permissions_chooser_file_changed (ThunarPermissionsChooser *chooser)
if (G_LIKELY (user != NULL))
{
groups = g_list_copy (thunar_user_get_groups (user));
- g_list_foreach (groups, (GFunc) g_object_ref, NULL);
+ g_list_foreach (groups, (GFunc) (void (*)(void)) g_object_ref, NULL);
}
}
@@ -1009,14 +1009,9 @@ thunar_permissions_chooser_file_changed (ThunarPermissionsChooser *chooser)
g_object_unref (G_OBJECT (access_store));
}
- /* update the program setting based on the mode (only visible for regular files, allowed for execution) */
+ /* update the program setting based on the mode (only visible for regular files) */
g_signal_handlers_block_by_func (G_OBJECT (chooser->program_button), thunar_permissions_chooser_program_toggled, chooser);
- g_object_set (G_OBJECT (chooser->program_button), "visible", thunar_file_is_regular (file)
- && (thunarx_file_info_has_mime_type (THUNARX_FILE_INFO (file), "application/x-executable")
- || thunarx_file_info_has_mime_type (THUNARX_FILE_INFO (file), "application/x-shellscript")
- || thunarx_file_info_has_mime_type (THUNARX_FILE_INFO (file), "application/x-desktop")
- || thunarx_file_info_has_mime_type (THUNARX_FILE_INFO (file), "application/x-ms-dos-executable")
- || thunarx_file_info_has_mime_type (THUNARX_FILE_INFO (file), "application/x-msi")), NULL);
+ g_object_set (G_OBJECT (chooser->program_button), "visible", thunar_file_is_regular (file), NULL);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (chooser->program_button), (mode & 0111) != 0);
g_signal_handlers_unblock_by_func (G_OBJECT (chooser->program_button), thunar_permissions_chooser_program_toggled, chooser);
diff --git a/thunar/thunar-preferences-dialog.c b/thunar/thunar-preferences-dialog.c
index 101c5fa2..cfaf7cc6 100644
--- a/thunar/thunar-preferences-dialog.c
+++ b/thunar/thunar-preferences-dialog.c
@@ -229,6 +229,7 @@ thunar_preferences_dialog_init (ThunarPreferencesDialog *dialog)
GtkWidget *button;
GtkWidget *combo;
GtkWidget *entry;
+ GtkWidget *image;
GtkWidget *frame;
GtkWidget *label;
GtkWidget *range;
@@ -248,11 +249,31 @@ thunar_preferences_dialog_init (ThunarPreferencesDialog *dialog)
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
gtk_window_set_title (GTK_WINDOW (dialog), _("File Manager Preferences"));
- /* add "Help" and "Close" buttons */
- gtk_dialog_add_buttons (GTK_DIALOG (dialog),
- _("_Close"), GTK_RESPONSE_CLOSE,
- _("_Help"), GTK_RESPONSE_HELP,
- NULL);
+#if LIBXFCE4UI_CHECK_VERSION (4, 15, 1)
+ xfce_titled_dialog_create_action_area (XFCE_TITLED_DIALOG (dialog));
+#endif
+
+ /* add the "Close" button */
+ button = gtk_button_new_with_mnemonic (_("_Close"));
+ image = gtk_image_new_from_icon_name ("window-close", GTK_ICON_SIZE_BUTTON);
+ gtk_button_set_image (GTK_BUTTON (button), image);
+#if LIBXFCE4UI_CHECK_VERSION (4, 15, 1)
+ xfce_titled_dialog_add_action_widget (XFCE_TITLED_DIALOG (dialog), button, GTK_RESPONSE_CLOSE);
+#else
+ gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_CLOSE);
+#endif
+ gtk_widget_show (button);
+
+ /* add the "Help" button */
+ button = gtk_button_new_with_mnemonic (_("_Help"));
+ image = gtk_image_new_from_icon_name ("help-browser", GTK_ICON_SIZE_BUTTON);
+ gtk_button_set_image (GTK_BUTTON (button), image);
+#if LIBXFCE4UI_CHECK_VERSION (4, 15, 1)
+ xfce_titled_dialog_add_action_widget (XFCE_TITLED_DIALOG (dialog), button, GTK_RESPONSE_HELP);
+#else
+ gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_HELP);
+#endif
+ gtk_widget_show (button);
notebook = gtk_notebook_new ();
gtk_container_set_border_width (GTK_CONTAINER (notebook), 6);
@@ -711,8 +732,8 @@ thunar_preferences_dialog_init (ThunarPreferencesDialog *dialog)
combo = gtk_combo_box_text_new ();
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Ask every time"));
- gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Apply to Folder Only"));
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Apply to Folder and Contents"));
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Apply to Folder Only"));
exo_mutual_binding_new (G_OBJECT (dialog->preferences), "misc-recursive-permissions", G_OBJECT (combo), "active");
gtk_widget_set_hexpand (combo, TRUE);
gtk_grid_attach (GTK_GRID (grid), combo, 0, 1, 1, 1);
diff --git a/thunar/thunar-progress-dialog.c b/thunar/thunar-progress-dialog.c
index 7d227c21..f4de6097 100644
--- a/thunar/thunar-progress-dialog.c
+++ b/thunar/thunar-progress-dialog.c
@@ -368,6 +368,7 @@ thunar_progress_dialog_add_job (ThunarProgressDialog *dialog,
dialog->scrollwin = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (dialog->scrollwin),
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ gtk_widget_set_vexpand (dialog->scrollwin, TRUE);
gtk_container_add (GTK_CONTAINER (dialog->vbox), dialog->scrollwin);
gtk_widget_show (dialog->scrollwin);
diff --git a/thunar/thunar-properties-dialog.c b/thunar/thunar-properties-dialog.c
index e612a926..848eb564 100644
--- a/thunar/thunar-properties-dialog.c
+++ b/thunar/thunar-properties-dialog.c
@@ -704,7 +704,7 @@ static gboolean
thunar_properties_dialog_reload (ThunarPropertiesDialog *dialog)
{
/* reload the active files */
- g_list_foreach (dialog->files, (GFunc) thunar_file_reload, NULL);
+ g_list_foreach (dialog->files, (GFunc) (void (*)(void)) thunar_file_reload, NULL);
return dialog->files != NULL;
}
diff --git a/thunar/thunar-renamer-progress.c b/thunar/thunar-renamer-progress.c
index ef628b3e..57230000 100644
--- a/thunar/thunar-renamer-progress.c
+++ b/thunar/thunar-renamer-progress.c
@@ -361,6 +361,7 @@ thunar_renamer_progress_run (ThunarRenamerProgress *renamer_progress,
/* make sure to release the list of completed items first */
thunar_renamer_pair_list_free (renamer_progress->pairs_done);
renamer_progress->pairs_done = NULL;
+ renamer_progress->n_pairs_done = 0;
/* set the pairs on the todo list */
thunar_renamer_pair_list_free (renamer_progress->pairs_todo);
diff --git a/thunar/thunar-sendto-model.c b/thunar/thunar-sendto-model.c
index 42253864..35418582 100644
--- a/thunar/thunar-sendto-model.c
+++ b/thunar/thunar-sendto-model.c
@@ -154,7 +154,7 @@ thunar_sendto_model_load (ThunarSendtoModel *sendto_model)
/* add to our handler list, sorted by their desktop-ids (reverse order) */
sendto_model->handlers = g_list_insert_sorted (sendto_model->handlers,
G_APP_INFO (app_info),
- (GCompareFunc) g_app_info_compare);
+ (GCompareFunc) (void (*)(void)) g_app_info_compare);
/* attach the mime-types to the object */
mime_types = g_key_file_get_string_list (key_file,
diff --git a/thunar/thunar-session-client.c b/thunar/thunar-session-client.c
index 60728b54..40fd04c8 100644
--- a/thunar/thunar-session-client.c
+++ b/thunar/thunar-session-client.c
@@ -256,7 +256,7 @@ thunar_session_client_connect (ThunarSessionClient *session_client,
prop_priority.type = SmCARD8;
prop_priority.num_vals = G_N_ELEMENTS (value_priority);
prop_priority.vals = &value_priority[0];
- value_priority[0].value = "\30";
+ value_priority[0].value = "\36"; /* this is octal, 30 in decimal */
value_priority[0].length = 1;
/* setup the properties list */
diff --git a/thunar/thunar-settings.desktop.in b/thunar/thunar-settings.desktop.in
index 18e11d4d..9d7c2fae 100644
--- a/thunar/thunar-settings.desktop.in
+++ b/thunar/thunar-settings.desktop.in
@@ -1,6 +1,6 @@
[Desktop Entry]
Version=1.0
-_Name=File Manager
+_Name=File Manager Settings
_Comment=Configure the Thunar file manager
Exec=thunar-settings
Icon=system-file-manager
diff --git a/thunar/thunar-shortcuts-model.c b/thunar/thunar-shortcuts-model.c
index 0c9b5133..d5e92df2 100644
--- a/thunar/thunar-shortcuts-model.c
+++ b/thunar/thunar-shortcuts-model.c
@@ -318,7 +318,7 @@ thunar_shortcuts_model_finalize (GObject *object)
g_source_remove (model->bookmarks_idle_id);
/* free all shortcuts */
- g_list_foreach (model->shortcuts, (GFunc) thunar_shortcut_free, model);
+ g_list_foreach (model->shortcuts, (GFunc) (void (*)(void)) thunar_shortcut_free, model);
g_list_free (model->shortcuts);
/* disconnect from the preferences */
@@ -495,6 +495,9 @@ thunar_shortcuts_model_get_column_type (GtkTreeModel *tree_model,
case THUNAR_SHORTCUTS_MODEL_COLUMN_BUSY_PULSE:
return G_TYPE_UINT;
+
+ case THUNAR_SHORTCUTS_MODEL_COLUMN_HIDDEN:
+ return G_TYPE_BOOLEAN;
}
_thunar_assert_not_reached ();
@@ -711,6 +714,11 @@ thunar_shortcuts_model_get_value (GtkTreeModel *tree_model,
g_value_set_uint (value, shortcut->busy_pulse);
break;
+ case THUNAR_SHORTCUTS_MODEL_COLUMN_HIDDEN:
+ g_value_init (value, G_TYPE_BOOLEAN);
+ g_value_set_boolean (value, FALSE);
+ break;
+
default:
_thunar_assert_not_reached ();
}
diff --git a/thunar/thunar-shortcuts-model.h b/thunar/thunar-shortcuts-model.h
index cb87a1f7..677e9b43 100644
--- a/thunar/thunar-shortcuts-model.h
+++ b/thunar/thunar-shortcuts-model.h
@@ -52,6 +52,7 @@ typedef enum
THUNAR_SHORTCUTS_MODEL_COLUMN_GROUP,
THUNAR_SHORTCUTS_MODEL_COLUMN_BUSY,
THUNAR_SHORTCUTS_MODEL_COLUMN_BUSY_PULSE,
+ THUNAR_SHORTCUTS_MODEL_COLUMN_HIDDEN,
THUNAR_SHORTCUTS_MODEL_N_COLUMNS,
} ThunarShortcutsModelColumn;
diff --git a/thunar/thunar-shortcuts-pane.c b/thunar/thunar-shortcuts-pane.c
index 98b5d6eb..2cc26a20 100644
--- a/thunar/thunar-shortcuts-pane.c
+++ b/thunar/thunar-shortcuts-pane.c
@@ -66,6 +66,8 @@ static void thunar_shortcuts_pane_set_ui_manager (ThunarComponen
GtkUIManager *ui_manager);
static void thunar_shortcuts_pane_action_shortcuts_add (GtkAction *action,
ThunarShortcutsPane *shortcuts_pane);
+static void thunar_shortcuts_pane_show_shortcuts_view_padding (GtkWidget *widget);
+static void thunar_shortcuts_pane_hide_shortcuts_view_padding (GtkWidget *widget);
@@ -94,7 +96,7 @@ struct _ThunarShortcutsPane
static const GtkActionEntry action_entries[] =
{
- { "sendto-shortcuts", "stock_thunar-shortcuts", "", NULL, NULL, G_CALLBACK (thunar_shortcuts_pane_action_shortcuts_add), },
+ { "sendto-shortcuts", "bookmark-new", "", NULL, NULL, G_CALLBACK (thunar_shortcuts_pane_action_shortcuts_add), },
};
@@ -162,6 +164,8 @@ thunar_shortcuts_pane_side_pane_init (ThunarSidePaneIface *iface)
static void
thunar_shortcuts_pane_init (ThunarShortcutsPane *shortcuts_pane)
{
+ GtkWidget *vscrollbar;
+
/* setup the action group for the shortcuts actions */
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
shortcuts_pane->action_group = gtk_action_group_new ("ThunarShortcutsPane");
@@ -180,6 +184,14 @@ G_GNUC_END_IGNORE_DEPRECATIONS
gtk_container_add (GTK_CONTAINER (shortcuts_pane), shortcuts_pane->view);
gtk_widget_show (shortcuts_pane->view);
+ vscrollbar = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (shortcuts_pane));
+ g_signal_connect_swapped (G_OBJECT (vscrollbar), "map",
+ G_CALLBACK (thunar_shortcuts_pane_show_shortcuts_view_padding),
+ shortcuts_pane->view);
+ g_signal_connect_swapped (G_OBJECT (vscrollbar), "unmap",
+ G_CALLBACK (thunar_shortcuts_pane_hide_shortcuts_view_padding),
+ shortcuts_pane->view);
+
/* add widget to css class */
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (shortcuts_pane)), "shortcuts-pane");
@@ -508,3 +520,19 @@ G_GNUC_END_IGNORE_DEPRECATIONS
thunar_g_file_list_free (lp);
}
}
+
+
+
+static void
+thunar_shortcuts_pane_show_shortcuts_view_padding (GtkWidget *widget)
+{
+ thunar_shortcuts_view_toggle_padding (THUNAR_SHORTCUTS_VIEW (widget), TRUE);
+}
+
+
+
+static void
+thunar_shortcuts_pane_hide_shortcuts_view_padding (GtkWidget *widget)
+{
+ thunar_shortcuts_view_toggle_padding (THUNAR_SHORTCUTS_VIEW (widget), FALSE);
+}
diff --git a/thunar/thunar-shortcuts-view.c b/thunar/thunar-shortcuts-view.c
index 8e3b0e86..281e44e2 100644
--- a/thunar/thunar-shortcuts-view.c
+++ b/thunar/thunar-shortcuts-view.c
@@ -168,6 +168,9 @@ struct _ThunarShortcutsView
ThunarPreferences *preferences;
GtkCellRenderer *icon_renderer;
+ GtkCellRenderer *padding_renderer;
+ GtkTreeViewColumn *column;
+ gboolean padding_enabled;
ThunarxProviderFactory *provider_factory;
@@ -269,7 +272,7 @@ thunar_shortcuts_view_class_init (ThunarShortcutsViewClass *klass)
static void
thunar_shortcuts_view_init (ThunarShortcutsView *view)
{
- GtkTreeViewColumn *column, *column_eject;
+ GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
GtkTreeSelection *selection;
@@ -288,18 +291,14 @@ thunar_shortcuts_view_init (ThunarShortcutsView *view)
g_signal_connect_swapped (G_OBJECT (view->preferences), "notify::shortcuts-icon-emblems", G_CALLBACK (gtk_widget_queue_draw), view);
/* allocate a single column for our renderers */
- column = g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
+ column = view->column = g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
"reorderable", FALSE,
"resizable", FALSE,
"expand", TRUE,
- "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE,
"spacing", 2,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
- column_eject = gtk_tree_view_column_new ();
- gtk_tree_view_append_column (GTK_TREE_VIEW (view), column_eject);
-
/* queue a resize on the column whenever the icon size is changed */
view->queue_resize_signal_id = g_signal_connect_swapped (G_OBJECT (view->preferences), "notify::shortcuts-icon-size",
G_CALLBACK (gtk_tree_view_column_queue_resize), column);
@@ -311,7 +310,7 @@ thunar_shortcuts_view_init (ThunarShortcutsView *view)
"ypad", 4,
"ellipsize", PANGO_ELLIPSIZE_END,
NULL);
- gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ gtk_tree_view_column_pack_end (column, renderer, FALSE);
gtk_tree_view_column_set_attributes (column, renderer,
"text", THUNAR_SHORTCUTS_MODEL_COLUMN_NAME,
"visible", THUNAR_SHORTCUTS_MODEL_COLUMN_IS_HEADER,
@@ -354,8 +353,8 @@ thunar_shortcuts_view_init (ThunarShortcutsView *view)
/* spinner to indicate (un)mount/eject delay */
renderer = gtk_cell_renderer_spinner_new ();
- gtk_tree_view_column_pack_start (column_eject, renderer, FALSE);
- gtk_tree_view_column_set_attributes (column_eject, renderer,
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ gtk_tree_view_column_set_attributes (column, renderer,
"visible", THUNAR_SHORTCUTS_MODEL_COLUMN_BUSY,
"active", THUNAR_SHORTCUTS_MODEL_COLUMN_BUSY,
"pulse", THUNAR_SHORTCUTS_MODEL_COLUMN_BUSY_PULSE,
@@ -364,8 +363,17 @@ thunar_shortcuts_view_init (ThunarShortcutsView *view)
/* allocate icon renderer for the eject symbol */
renderer = gtk_cell_renderer_pixbuf_new ();
g_object_set (renderer, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, "icon-name", "media-eject", NULL);
- gtk_tree_view_column_pack_start (column_eject, renderer, FALSE);
- gtk_tree_view_column_set_attributes (column_eject, renderer,
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "visible", THUNAR_SHORTCUTS_MODEL_COLUMN_CAN_EJECT,
+ NULL);
+
+ /* padding for the eject symbol so it's not covered by scroll bar */
+ view->padding_enabled = FALSE;
+ view->padding_renderer = gtk_cell_renderer_text_new ();
+ g_object_set (G_OBJECT (view->padding_renderer), "xpad", 6, NULL);
+ gtk_tree_view_column_pack_start (column, view->padding_renderer, FALSE);
+ gtk_tree_view_column_set_attributes (column, view->padding_renderer,
"visible", THUNAR_SHORTCUTS_MODEL_COLUMN_CAN_EJECT,
NULL);
@@ -418,7 +426,7 @@ thunar_shortcuts_view_button_press_event (GtkWidget *widget,
GtkTreeIter iter;
gboolean result;
gboolean can_eject;
- gint icon_width, icon_height, column_width;
+ gint icon_width, column_width;
/* reset the pressed button state */
view->pressed_button = -1;
@@ -453,8 +461,8 @@ thunar_shortcuts_view_button_press_event (GtkWidget *widget,
{
/* check if we clicked the eject button area */
column_width = gtk_tree_view_column_get_width (gtk_tree_view_get_column (GTK_TREE_VIEW (view), 0));
- gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
- if (event->button == 1 && event->x > column_width)
+ gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, NULL);
+ if (event->button == 1 && event->x >= column_width - icon_width - (view->padding_enabled ? 16 : 3))
{
/* check if that shortcut actually has an eject button */
model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
@@ -837,6 +845,11 @@ thunar_shortcuts_view_drag_motion (GtkWidget *widget,
gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (view), path, position);
gtk_tree_path_free (path);
}
+ else
+ {
+ /* remove highlight */
+ gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (view), NULL, position);
+ }
/* tell Gdk whether we can drop here */
gdk_drag_status (context, action, timestamp);
@@ -865,7 +878,7 @@ thunar_shortcuts_view_drag_leave (GtkWidget *widget,
}
/* schedule a repaint to make sure the special drop icon for the target row
- * is reset to its default (http://bugzilla.xfce.org/show_bug.cgi?id=2498).
+ * is reset to its default (https://bugzilla.xfce.org/show_bug.cgi?id=2498).
*/
gtk_widget_queue_draw (widget);
@@ -1183,7 +1196,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_widget_show (item);
- image = gtk_image_new_from_icon_name ("stock_thunar-shortcuts", GTK_ICON_SIZE_MENU);
+ image = gtk_image_new_from_icon_name ("bookmark-new", GTK_ICON_SIZE_MENU);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
G_GNUC_END_IGNORE_DEPRECATIONS
@@ -1439,6 +1452,8 @@ thunar_shortcuts_view_compute_drop_actions (ThunarShortcutsView *view,
GtkTreeIter iter;
ThunarFile *file;
gint cell_y;
+ GList *lp;
+ guint n;
/* determine the shortcuts model */
model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
@@ -1481,6 +1496,30 @@ thunar_shortcuts_view_compute_drop_actions (ThunarShortcutsView *view,
/* check if we cannot drop into the shortcut */
if (G_UNLIKELY (actions == 0))
{
+ /* check if any of the paths is not directory but only up to 100, if
+ * someone drags too many directories it may slowdown or even freeze
+ * Thunar while moving the cursor.
+ */
+ for (lp = view->drop_file_list, n = 0; lp != NULL && n < 100; lp = lp->next, ++n)
+ {
+ GFileInfo *info;
+ gboolean is_directory;
+
+ info = g_file_query_info (lp->data,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+
+ if (G_UNLIKELY (info == NULL))
+ return 0;
+
+ is_directory = g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY;
+ g_object_unref (info);
+
+ if (!is_directory)
+ return 0;
+ }
+
/* check the action that should be performed */
if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_LINK || (gdk_drag_context_get_actions (context) & GDK_ACTION_LINK) != 0)
actions = GDK_ACTION_LINK;
@@ -1783,7 +1822,7 @@ thunar_shortcuts_view_open (ThunarShortcutsView *view,
THUNAR_SHORTCUTS_MODEL_COLUMN_LOCATION, &location,
-1);
- if (G_LIKELY (device != NULL))
+ if (G_LIKELY (THUNAR_IS_DEVICE (device)))
{
/* start the spinner */
child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
@@ -1870,18 +1909,20 @@ thunar_shortcuts_view_create_shortcut (ThunarShortcutsView *view)
{
/* determine the device/mount for the shortcut at the given tree iterator */
gtk_tree_model_get (model, &iter, THUNAR_SHORTCUTS_MODEL_COLUMN_DEVICE, &device, -1);
- _thunar_return_if_fail (THUNAR_IS_DEVICE (device));
- /* add the mount point to the model */
- mount_point = thunar_device_get_root (device);
- if (mount_point != NULL)
+ if (G_LIKELY (THUNAR_IS_DEVICE (device)))
{
- shortcuts_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
- thunar_shortcuts_model_add (THUNAR_SHORTCUTS_MODEL (shortcuts_model), NULL, mount_point);
- g_object_unref (mount_point);
- }
+ /* add the mount point to the model */
+ mount_point = thunar_device_get_root (device);
+ if (mount_point != NULL)
+ {
+ shortcuts_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
+ thunar_shortcuts_model_add (THUNAR_SHORTCUTS_MODEL (shortcuts_model), NULL, mount_point);
+ g_object_unref (mount_point);
+ }
- g_object_unref (G_OBJECT (device));
+ g_object_unref (G_OBJECT (device));
+ }
}
}
@@ -1937,24 +1978,26 @@ thunar_shortcuts_view_eject (ThunarShortcutsView *view)
{
/* determine the device/mount for the shortcut at the given tree iterator */
gtk_tree_model_get (model, &iter, THUNAR_SHORTCUTS_MODEL_COLUMN_DEVICE, &device, -1);
- _thunar_return_if_fail (THUNAR_IS_DEVICE (device));
- /* prepare a mount operation */
- mount_operation = thunar_gtk_mount_operation_new (GTK_WIDGET (view));
+ if (G_LIKELY (THUNAR_IS_DEVICE (device)))
+ {
+ /* prepare a mount operation */
+ mount_operation = thunar_gtk_mount_operation_new (GTK_WIDGET (view));
- /* start the spinner */
- child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
- thunar_shortcuts_model_set_busy (THUNAR_SHORTCUTS_MODEL (child_model), device, TRUE);
+ /* start the spinner */
+ child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
+ thunar_shortcuts_model_set_busy (THUNAR_SHORTCUTS_MODEL (child_model), device, TRUE);
- /* try to unmount */
- thunar_device_eject (device,
- mount_operation,
- NULL,
- thunar_shortcuts_view_eject_finish,
- g_object_ref (view));
+ /* try to unmount */
+ thunar_device_eject (device,
+ mount_operation,
+ NULL,
+ thunar_shortcuts_view_eject_finish,
+ g_object_ref (view));
- g_object_unref (G_OBJECT (device));
- g_object_unref (G_OBJECT (mount_operation));
+ g_object_unref (G_OBJECT (device));
+ g_object_unref (G_OBJECT (mount_operation));
+ }
}
}
@@ -1965,7 +2008,8 @@ thunar_shortcuts_view_poke_device_mount_finish (ThunarBrowser *browser,
ThunarDevice *device,
ThunarFile *mount_point,
GError *error,
- gpointer ignored)
+ gpointer ignored,
+ gboolean cancelled)
{
gchar *device_name;
GtkTreeModel *model;
@@ -2013,7 +2057,7 @@ thunar_shortcuts_view_mount (ThunarShortcutsView *view)
/* determine the file for the shortcut at the given tree iterator */
gtk_tree_model_get (model, &iter, THUNAR_SHORTCUTS_MODEL_COLUMN_DEVICE, &device, -1);
- if (G_LIKELY (device != NULL))
+ if (G_LIKELY (THUNAR_IS_DEVICE (device)))
{
/* start the spinner */
child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
@@ -2079,24 +2123,26 @@ thunar_shortcuts_view_unmount (ThunarShortcutsView *view)
{
/* determine the device/mount for the shortcut at the given tree iterator */
gtk_tree_model_get (model, &iter, THUNAR_SHORTCUTS_MODEL_COLUMN_DEVICE, &device, -1);
- _thunar_return_if_fail (THUNAR_IS_DEVICE (device));
- /* prepare a mount operation */
- mount_operation = thunar_gtk_mount_operation_new (GTK_WIDGET (view));
+ if (G_LIKELY (THUNAR_IS_DEVICE (device)))
+ {
+ /* prepare a mount operation */
+ mount_operation = thunar_gtk_mount_operation_new (GTK_WIDGET (view));
- /* start the spinner */
- child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
- thunar_shortcuts_model_set_busy (THUNAR_SHORTCUTS_MODEL (child_model), device, TRUE);
+ /* start the spinner */
+ child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
+ thunar_shortcuts_model_set_busy (THUNAR_SHORTCUTS_MODEL (child_model), device, TRUE);
- /* try to unmount */
- thunar_device_unmount (device,
- mount_operation,
- NULL,
- thunar_shortcuts_view_unmount_finish,
- g_object_ref (view));
+ /* try to unmount */
+ thunar_device_unmount (device,
+ mount_operation,
+ NULL,
+ thunar_shortcuts_view_unmount_finish,
+ g_object_ref (view));
- g_object_unref (G_OBJECT (device));
- g_object_unref (G_OBJECT (mount_operation));
+ g_object_unref (G_OBJECT (device));
+ g_object_unref (G_OBJECT (mount_operation));
+ }
}
}
@@ -2165,3 +2211,18 @@ thunar_shortcuts_view_select_by_file (ThunarShortcutsView *view,
else
gtk_tree_selection_unselect_all (selection);
}
+
+
+
+void
+thunar_shortcuts_view_toggle_padding (ThunarShortcutsView *view,
+ gboolean enable)
+{
+ gtk_tree_view_column_set_attributes (view->column, view->padding_renderer,
+ "visible", enable ?
+ THUNAR_SHORTCUTS_MODEL_COLUMN_CAN_EJECT :
+ THUNAR_SHORTCUTS_MODEL_COLUMN_HIDDEN,
+ NULL);
+
+ view->padding_enabled = enable;
+}
diff --git a/thunar/thunar-shortcuts-view.h b/thunar/thunar-shortcuts-view.h
index 5f81f0b2..3a0a3087 100644
--- a/thunar/thunar-shortcuts-view.h
+++ b/thunar/thunar-shortcuts-view.h
@@ -41,6 +41,9 @@ GtkWidget *thunar_shortcuts_view_new (void) G_GNUC_MALLOC;
void thunar_shortcuts_view_select_by_file (ThunarShortcutsView *view,
ThunarFile *file);
+void thunar_shortcuts_view_toggle_padding (ThunarShortcutsView *view,
+ gboolean enable);
+
G_END_DECLS;
#endif /* !__THUNAR_SHORTCUTS_VIEW_H__ */
diff --git a/thunar/thunar-side-pane.c b/thunar/thunar-side-pane.c
index 6084738a..e17c6305 100644
--- a/thunar/thunar-side-pane.c
+++ b/thunar/thunar-side-pane.c
@@ -41,7 +41,7 @@ thunar_side_pane_get_type (void)
type = g_type_register_static_simple (G_TYPE_INTERFACE,
I_("ThunarSidePane"),
sizeof (ThunarSidePaneIface),
- (GClassInitFunc) thunar_side_pane_class_init,
+ (GClassInitFunc) (void (*)(void)) thunar_side_pane_class_init,
0,
NULL,
0);
diff --git a/thunar/thunar-standard-view-ui.xml b/thunar/thunar-standard-view-ui.xml
index 2a1c609d..6972427f 100644
--- a/thunar/thunar-standard-view-ui.xml
+++ b/thunar/thunar-standard-view-ui.xml
@@ -9,6 +9,7 @@
-->
<accelerator action="zoom-in-alt"/>
+ <accelerator action="open-location-alt"/>
<menubar name="main-menu">
<menu action="file-menu">
diff --git a/thunar/thunar-standard-view.c b/thunar/thunar-standard-view.c
index f2ce4e4e..3115eec0 100644
--- a/thunar/thunar-standard-view.c
+++ b/thunar/thunar-standard-view.c
@@ -44,6 +44,7 @@
#include <thunar/thunar-icon-renderer.h>
#include <thunar/thunar-marshal.h>
#include <thunar/thunar-menu-util.h>
+#include <thunar/thunar-pango-extensions.h>
#include <thunar/thunar-private.h>
#include <thunar/thunar-properties-dialog.h>
#include <thunar/thunar-renamer-dialog.h>
@@ -60,10 +61,6 @@
-#define THUNAR_STANDARD_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), THUNAR_TYPE_STANDARD_VIEW, ThunarStandardViewPrivate))
-
-
-
/* Property identifiers */
enum
{
@@ -161,8 +158,7 @@ static ThunarFile *thunar_standard_view_get_drop_file (Thu
gint x,
gint y,
GtkTreePath **path_return);
-static void thunar_standard_view_merge_custom_actions (ThunarStandardView *standard_view,
- GList *selected_items);
+static void thunar_standard_view_merge_custom_actions (ThunarStandardView *standard_view);
static void thunar_standard_view_update_statusbar_text (ThunarStandardView *standard_view);
static void thunar_standard_view_current_directory_destroy (ThunarFile *current_directory,
ThunarStandardView *standard_view);
@@ -349,6 +345,7 @@ struct _ThunarStandardViewPrivate
GList *drag_g_file_list;
guint drag_scroll_timer_id;
guint drag_timer_id;
+ GdkEvent *drag_timer_event;
gint drag_x;
gint drag_y;
@@ -443,7 +440,8 @@ static GParamSpec *standard_view_props[N_PROPERTIES] = { NULL, };
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ThunarStandardView, thunar_standard_view, GTK_TYPE_SCROLLED_WINDOW,
G_IMPLEMENT_INTERFACE (THUNAR_TYPE_NAVIGATOR, thunar_standard_view_navigator_init)
G_IMPLEMENT_INTERFACE (THUNAR_TYPE_COMPONENT, thunar_standard_view_component_init)
- G_IMPLEMENT_INTERFACE (THUNAR_TYPE_VIEW, thunar_standard_view_view_init))
+ G_IMPLEMENT_INTERFACE (THUNAR_TYPE_VIEW, thunar_standard_view_view_init)
+ G_ADD_PRIVATE (ThunarStandardView))
@@ -455,8 +453,6 @@ thunar_standard_view_class_init (ThunarStandardViewClass *klass)
GObjectClass *gobject_class;
gpointer g_iface;
- g_type_class_add_private (klass, sizeof (ThunarStandardViewPrivate));
-
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->constructor = thunar_standard_view_constructor;
gobject_class->dispose = thunar_standard_view_dispose;
@@ -635,7 +631,7 @@ thunar_standard_view_view_init (ThunarViewIface *iface)
static void
thunar_standard_view_init (ThunarStandardView *standard_view)
{
- standard_view->priv = THUNAR_STANDARD_VIEW_GET_PRIVATE (standard_view);
+ standard_view->priv = thunar_standard_view_get_instance_private (standard_view);
/* allocate the scroll_to_files mapping (directory GFile -> first visible child GFile) */
standard_view->priv->scroll_to_files = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, g_object_unref);
@@ -718,9 +714,12 @@ G_GNUC_END_IGNORE_DEPRECATIONS
/* setup the name renderer */
standard_view->name_renderer = g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
+#if PANGO_VERSION_CHECK (1, 44, 0)
+ "attributes", thunar_pango_attr_disable_hyphens (),
+#endif
"alignment", PANGO_ALIGN_CENTER,
"xalign", 0.5,
- FALSE);
+ NULL);
g_object_ref_sink (G_OBJECT (standard_view->name_renderer));
/* TODO: prelit underline
@@ -849,6 +848,13 @@ thunar_standard_view_dispose (GObject *object)
if (G_UNLIKELY (standard_view->priv->drag_timer_id != 0))
g_source_remove (standard_view->priv->drag_timer_id);
+ /* be sure to free any pending drag timer event */
+ if (G_UNLIKELY (standard_view->priv->drag_timer_event != NULL))
+ {
+ gdk_event_free (standard_view->priv->drag_timer_event);
+ standard_view->priv->drag_timer_event = NULL;
+ }
+
/* reset the UI manager property */
thunar_component_set_ui_manager (THUNAR_COMPONENT (standard_view), NULL);
@@ -1742,11 +1748,19 @@ thunar_standard_view_reload (ThunarView *view,
{
ThunarStandardView *standard_view = THUNAR_STANDARD_VIEW (view);
ThunarFolder *folder;
+ ThunarFile *file;
/* determine the folder for the view model */
folder = thunar_list_model_get_folder (standard_view->model);
if (G_LIKELY (folder != NULL))
- thunar_folder_reload (folder, reload_info);
+ {
+ file = thunar_folder_get_corresponding_file (folder);
+
+ if (thunar_file_exists (file))
+ thunar_folder_reload (folder, reload_info);
+ else
+ thunar_standard_view_current_directory_destroy (file, standard_view);
+ }
/* schedule thumbnail reload update */
if (!standard_view->priv->thumbnailing_scheduled)
@@ -2015,8 +2029,7 @@ thunar_standard_view_get_drop_file (ThunarStandardView *standard_view,
static void
-thunar_standard_view_merge_custom_actions (ThunarStandardView *standard_view,
- GList *selected_items)
+thunar_standard_view_merge_custom_actions (ThunarStandardView *standard_view)
{
GtkTreeIter iter;
ThunarFile *file = NULL;
@@ -2026,6 +2039,7 @@ thunar_standard_view_merge_custom_actions (ThunarStandardView *standard_view,
GList *files = NULL;
GList *tmp;
GList *lp;
+ GList *selected_items;
gchar *path;
/* we cannot add anything if we aren't connected to any UI manager */
@@ -2035,6 +2049,9 @@ thunar_standard_view_merge_custom_actions (ThunarStandardView *standard_view,
/* determine the toplevel window we belong to */
window = gtk_widget_get_toplevel (GTK_WIDGET (standard_view));
+ /* get the selected items */
+ selected_items = (*THUNAR_STANDARD_VIEW_GET_CLASS (standard_view)->get_selected_items) (standard_view);
+
/* load the menu providers from the provider factory */
providers = thunarx_provider_factory_list_providers (standard_view->priv->provider_factory, THUNARX_TYPE_MENU_PROVIDER);
if (G_LIKELY (providers != NULL))
@@ -3073,6 +3090,8 @@ thunar_standard_view_motion_notify_event (GtkWidget *view,
GdkEventMotion *event,
ThunarStandardView *standard_view)
{
+ GtkTargetList *target_list;
+
_thunar_return_val_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view), FALSE);
_thunar_return_val_if_fail (standard_view->priv->drag_timer_id != 0, FALSE);
@@ -3081,11 +3100,19 @@ thunar_standard_view_motion_notify_event (GtkWidget *view,
{
/* cancel the drag timer, as we won't popup the menu anymore */
g_source_remove (standard_view->priv->drag_timer_id);
+ gdk_event_free (standard_view->priv->drag_timer_event);
+ standard_view->priv->drag_timer_event = NULL;
+
+ /* allocate the drag context */
+ target_list = gtk_target_list_new (drag_targets, G_N_ELEMENTS (drag_targets));
+ gtk_drag_begin_with_coordinates (view, target_list,
+ GDK_ACTION_COPY |
+ GDK_ACTION_MOVE |
+ GDK_ACTION_LINK |
+ GDK_ACTION_ASK,
+ 3, (GdkEvent *) event, -1, -1);
+ gtk_target_list_unref (target_list);
- /* FIXME
- * - according to doc, the GdkWindow associated to the widget needs to enable the GDK_POINTER_MOTION_MASK mask to use this event.
- * We dont do that. So possibly this is dead code, which can be removed ?
- */
return TRUE;
}
@@ -3099,12 +3126,29 @@ thunar_standard_view_scroll_event (GtkWidget *view,
GdkEventScroll *event,
ThunarStandardView *standard_view)
{
- GdkEventButton fake_event;
- gboolean misc_horizontal_wheel_navigates;
+ GdkEventButton fake_event;
+ GdkScrollDirection scrolling_direction;
+ gboolean misc_horizontal_wheel_navigates;
_thunar_return_val_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view), FALSE);
- if (G_UNLIKELY (event->direction == GDK_SCROLL_LEFT || event->direction == GDK_SCROLL_RIGHT))
+ if (event->direction != GDK_SCROLL_SMOOTH)
+ scrolling_direction = event->direction;
+ else if (event->delta_y < 0)
+ scrolling_direction = GDK_SCROLL_UP;
+ else if (event->delta_y > 0)
+ scrolling_direction = GDK_SCROLL_DOWN;
+ else if (event->delta_x < 0)
+ scrolling_direction = GDK_SCROLL_LEFT;
+ else if (event->delta_x > 0)
+ scrolling_direction = GDK_SCROLL_RIGHT;
+ else
+ {
+ g_debug ("GDK_SCROLL_SMOOTH scrolling event with no delta happened");
+ return TRUE;
+ }
+
+ if (G_UNLIKELY (scrolling_direction == GDK_SCROLL_LEFT || scrolling_direction == GDK_SCROLL_RIGHT))
{
/* check if we should use the horizontal mouse wheel for navigation */
g_object_get (G_OBJECT (standard_view->preferences), "misc-horizontal-wheel-navigates", &misc_horizontal_wheel_navigates, NULL);
@@ -3112,7 +3156,7 @@ thunar_standard_view_scroll_event (GtkWidget *view,
{
/* create a fake event (8 == back, 9 forward) */
fake_event.type = GDK_BUTTON_PRESS;
- fake_event.button = event->direction == GDK_SCROLL_LEFT ? 8 : 9;
+ fake_event.button = scrolling_direction == GDK_SCROLL_LEFT ? 8 : 9;
/* trigger a fake button press event */
return thunar_standard_view_button_press_event (view, &fake_event, standard_view);
@@ -3120,10 +3164,10 @@ thunar_standard_view_scroll_event (GtkWidget *view,
}
/* zoom-in/zoom-out on control+mouse wheel */
- if ((event->state & GDK_CONTROL_MASK) != 0 && (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_DOWN))
+ if ((event->state & GDK_CONTROL_MASK) != 0 && (scrolling_direction == GDK_SCROLL_UP || scrolling_direction == GDK_SCROLL_DOWN))
{
thunar_view_set_zoom_level (THUNAR_VIEW (standard_view),
- (event->direction == GDK_SCROLL_UP)
+ (scrolling_direction == GDK_SCROLL_UP)
? MIN (standard_view->priv->zoom_level + 1, THUNAR_ZOOM_N_LEVELS - 1)
: MAX (standard_view->priv->zoom_level, 1) - 1);
return TRUE;
@@ -4323,18 +4367,23 @@ thunar_standard_view_context_menu (ThunarStandardView *standard_view)
_thunar_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view));
- /* merge the custom menu actions for the selected items */
- selected_items = (*THUNAR_STANDARD_VIEW_GET_CLASS (standard_view)->get_selected_items) (standard_view);
- thunar_standard_view_merge_custom_actions (standard_view, selected_items);
-
/* grab an additional reference on the view */
g_object_ref (G_OBJECT (standard_view));
-G_GNUC_BEGIN_IGNORE_DEPRECATIONS
/* run the menu (figuring out whether to use the file or the folder context menu) */
+ selected_items = (*THUNAR_STANDARD_VIEW_GET_CLASS (standard_view)->get_selected_items) (standard_view);
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
menu = gtk_ui_manager_get_widget (standard_view->ui_manager, (selected_items != NULL) ? "/file-context-menu" : "/folder-context-menu");
G_GNUC_END_IGNORE_DEPRECATIONS
- thunar_gtk_menu_run (GTK_MENU (menu));
+ /* if there is a drag_timer_event (long press), we use it */
+ if (standard_view->priv->drag_timer_event != NULL)
+ {
+ thunar_gtk_menu_run_at_event (GTK_MENU (menu), standard_view->priv->drag_timer_event);
+ gdk_event_free (standard_view->priv->drag_timer_event);
+ standard_view->priv->drag_timer_event = NULL;
+ }
+ else
+ thunar_gtk_menu_run (GTK_MENU (menu));
g_list_free_full (selected_items, (GDestroyNotify) gtk_tree_path_free);
@@ -4389,6 +4438,8 @@ thunar_standard_view_queue_popup (ThunarStandardView *standard_view,
/* schedule the timer */
standard_view->priv->drag_timer_id = g_timeout_add_full (G_PRIORITY_LOW, MAX (225, delay), thunar_standard_view_drag_timer,
standard_view, thunar_standard_view_drag_timer_destroy);
+ /* store current event data */
+ standard_view->priv->drag_timer_event = gtk_get_current_event ();
/* register the motion notify and the button release events on the real view */
g_signal_connect (G_OBJECT (view), "button-release-event", G_CALLBACK (thunar_standard_view_button_release_event), standard_view);
@@ -4415,9 +4466,11 @@ thunar_standard_view_selection_changed (ThunarStandardView *standard_view)
ThunarFile *current_directory;
gboolean can_paste_into_folder;
gboolean restorable;
+ gboolean trashable;
gboolean pastable;
gboolean writable;
gboolean trashed;
+ gboolean hide_trash_action;
gboolean show_delete_action;
GList *lp, *selected_files;
gint n_selected_files = 0;
@@ -4438,6 +4491,7 @@ thunar_standard_view_selection_changed (ThunarStandardView *standard_view)
/* determine the new list of selected files (replacing GtkTreePath's with ThunarFile's) */
selected_files = (*THUNAR_STANDARD_VIEW_GET_CLASS (standard_view)->get_selected_items) (standard_view);
restorable = (selected_files != NULL);
+ trashable = (selected_files != NULL);
for (lp = selected_files; lp != NULL; lp = lp->next, ++n_selected_files)
{
/* determine the iterator for the path */
@@ -4452,6 +4506,10 @@ thunar_standard_view_selection_changed (ThunarStandardView *standard_view)
/* enable "Restore" if we have only trashed files (atleast one file) */
if (!thunar_file_is_trashed (lp->data))
restorable = FALSE;
+
+ /* enable "Move to Trash" if files can be trashed */
+ if (!thunar_file_can_be_trashed (lp->data))
+ trashable = FALSE;
}
/* and setup the new selected files list */
@@ -4462,6 +4520,10 @@ thunar_standard_view_selection_changed (ThunarStandardView *standard_view)
writable = (current_directory != NULL && thunar_file_is_writable (current_directory));
trashed = (current_directory != NULL && thunar_file_is_trashed (current_directory));
+ /* if moving to trash is not applicable, replace it with the delete action
+ * but only if the directory is writable -- keep "move to trash" otherwise */
+ hide_trash_action = writable && (trashed || !trashable || !thunar_g_vfs_is_uri_scheme_supported ("trash"));
+
g_object_get (G_OBJECT (standard_view->preferences), "misc-show-delete-action", &show_delete_action, NULL);
/* check whether the clipboard contains data that can be pasted here */
@@ -4507,7 +4569,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
/* update the "Move to Trash" action */
g_object_set (G_OBJECT (standard_view->priv->action_move_to_trash),
"sensitive", (n_selected_files > 0) && writable,
- "visible", !trashed && thunar_g_vfs_is_uri_scheme_supported ("trash"),
+ "visible", !hide_trash_action,
"tooltip", ngettext ("Move the selected file to the Trash",
"Move the selected files to the Trash",
n_selected_files),
@@ -4516,7 +4578,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
/* update the "Delete" action */
g_object_set (G_OBJECT (standard_view->priv->action_delete),
"sensitive", (n_selected_files > 0) && writable,
- "visible", trashed || !thunar_g_vfs_is_uri_scheme_supported ("trash") || show_delete_action,
+ "visible", hide_trash_action || show_delete_action,
"tooltip", ngettext ("Permanently delete the selected file",
"Permanently delete the selected files",
n_selected_files),
@@ -4564,6 +4626,9 @@ G_GNUC_END_IGNORE_DEPRECATIONS
/* update the statusbar text */
thunar_standard_view_update_statusbar_text (standard_view);
+ /* merge the custom actions */
+ thunar_standard_view_merge_custom_actions (standard_view);
+
/* emit notification for "selected-files" */
g_object_notify_by_pspec (G_OBJECT (standard_view), standard_view_props[PROP_SELECTED_FILES]);
}
diff --git a/thunar/thunar-templates-action.c b/thunar/thunar-templates-action.c
index 33a263d8..c60956c8 100644
--- a/thunar/thunar-templates-action.c
+++ b/thunar/thunar-templates-action.c
@@ -25,8 +25,7 @@
#include <gio/gio.h>
#include <thunar/thunar-icon-factory.h>
-#include <thunar/thunar-job.h>
-#include <thunar/thunar-misc-jobs.h>
+#include <thunar/thunar-io-scan-directory.h>
#include <thunar/thunar-private.h>
#include <thunar/thunar-templates-action.h>
#include <thunar/thunar-util.h>
@@ -44,7 +43,7 @@ enum
static void thunar_templates_action_finalize (GObject *object);
static GtkWidget *thunar_templates_action_create_menu_item (GtkAction *action);
-static void thunar_templates_action_menu_shown (GtkWidget *menu,
+static void thunar_templates_action_load (GtkWidget *menu,
ThunarTemplatesAction *templates_action);
@@ -167,9 +166,10 @@ G_GNUC_END_IGNORE_DEPRECATIONS
/* associate an empty submenu with the item (will be filled when shown) */
menu = gtk_menu_new ();
- g_signal_connect (G_OBJECT (menu), "show", G_CALLBACK (thunar_templates_action_menu_shown), action);
gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
+ thunar_templates_action_load (menu, THUNAR_TEMPLATES_ACTION (action));
+
return item;
}
@@ -310,14 +310,13 @@ compare_files (ThunarFile *a,
static gboolean
-thunar_templates_action_files_ready (ThunarJob *job,
- GList *files,
- ThunarTemplatesAction *templates_action)
+thunar_templates_action_set_files (GtkWidget *menu,
+ GList *files,
+ ThunarTemplatesAction *templates_action)
{
ThunarIconFactory *icon_factory;
ThunarFile *file;
GdkPixbuf *icon;
- GtkWidget *menu;
GtkWidget *parent_menu;
GtkWidget *submenu;
GtkWidget *image;
@@ -331,9 +330,6 @@ thunar_templates_action_files_ready (ThunarJob *job,
gchar *label;
gchar *dot;
- /* determine the menu to add the items and submenus to */
- menu = g_object_get_data (G_OBJECT (job), "menu");
-
/* do nothing if there is no menu */
if (menu == NULL)
return FALSE;
@@ -343,7 +339,7 @@ thunar_templates_action_files_ready (ThunarJob *job,
/* sort items so that directories come before files and ancestors come
* before descendants */
- files = g_list_sort (files, (GCompareFunc) compare_files);
+ files = g_list_sort (files, (GCompareFunc) (void (*)(void)) compare_files);
for (lp = g_list_first (files); lp != NULL; lp = lp->next)
{
@@ -447,26 +443,21 @@ G_GNUC_END_IGNORE_DEPRECATIONS
static void
-thunar_templates_action_load_error (ThunarJob *job,
- GError *error,
- ThunarTemplatesAction *templates_action)
+thunar_templates_action_set_error (GtkWidget *menu,
+ const gchar *error_message,
+ ThunarTemplatesAction *templates_action)
{
GtkWidget *item;
- GtkWidget *menu;
GList *menu_children = NULL;
- _thunar_return_if_fail (THUNAR_IS_JOB (job));
- _thunar_return_if_fail (error != NULL);
+ _thunar_return_if_fail (error_message != NULL);
_thunar_return_if_fail (THUNAR_IS_TEMPLATES_ACTION (templates_action));
- _thunar_return_if_fail (templates_action->job == job);
-
- menu = g_object_get_data (G_OBJECT (job), "menu");
/* check if any items were added to the menu */
if (G_LIKELY (menu != NULL && (menu_children = gtk_container_get_children( GTK_CONTAINER (menu))) == NULL))
{
/* tell the user that no templates were found */
- item = gtk_menu_item_new_with_label (error->message);
+ item = gtk_menu_item_new_with_label (error_message);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_widget_set_sensitive (item, FALSE);
gtk_widget_show (item);
@@ -478,17 +469,14 @@ thunar_templates_action_load_error (ThunarJob *job,
static void
-thunar_templates_action_load_finished (ThunarJob *job,
+thunar_templates_action_load_finished (GtkWidget *menu,
ThunarTemplatesAction *templates_action)
{
+ GtkWidget *image;
GtkWidget *item;
- GtkWidget *menu;
- _thunar_return_if_fail (THUNAR_IS_JOB (job));
_thunar_return_if_fail (THUNAR_IS_TEMPLATES_ACTION (templates_action));
- _thunar_return_if_fail (templates_action->job == job);
- menu = g_object_get_data (G_OBJECT (job), "menu");
if (G_LIKELY (menu != NULL))
{
/* append a menu separator */
@@ -497,49 +485,67 @@ thunar_templates_action_load_finished (ThunarJob *job,
gtk_widget_show (item);
/* add the "Empty File" item */
- item = gtk_menu_item_new_with_mnemonic (_("_Empty File"));
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+ item = gtk_image_menu_item_new_with_mnemonic (_("_Empty File"));
+G_GNUC_END_IGNORE_DEPRECATIONS
g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (item_activated),
templates_action);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_widget_show (item);
- }
- g_signal_handlers_disconnect_matched (job, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
- templates_action);
- g_object_unref (job);
+ /* add the icon for the emtpy file item */
+ image = gtk_image_new_from_icon_name ("text-x-generic", GTK_ICON_SIZE_MENU);
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+G_GNUC_END_IGNORE_DEPRECATIONS
+ }
}
static void
-thunar_templates_action_menu_shown (GtkWidget *menu,
- ThunarTemplatesAction *templates_action)
+thunar_templates_action_load (GtkWidget *menu,
+ ThunarTemplatesAction *templates_action)
{
- GList *children;
+ GList *files = NULL;
+ GFile *home_dir;
+ GFile *templates_dir;
+ const gchar *path;
_thunar_return_if_fail (THUNAR_IS_TEMPLATES_ACTION (templates_action));
_thunar_return_if_fail (GTK_IS_MENU_SHELL (menu));
- /* drop all existing children of the menu first */
- children = gtk_container_get_children (GTK_CONTAINER (menu));
- g_list_free_full (children, (GDestroyNotify) gtk_widget_destroy);
+ home_dir = thunar_g_file_new_for_home ();
+ path = g_get_user_special_dir (G_USER_DIRECTORY_TEMPLATES);
- if (G_LIKELY (templates_action->job == NULL))
+ if (G_LIKELY (path != NULL))
+ templates_dir = g_file_new_for_path (path);
+ else
+ templates_dir = g_file_resolve_relative_path (home_dir, "Templates");
+
+ if (G_LIKELY (!g_file_equal (templates_dir, home_dir)))
{
- templates_action->job = thunar_misc_jobs_load_template_files (menu);
- g_object_add_weak_pointer (G_OBJECT (templates_action->job),
- (gpointer) &templates_action->job);
+ /* load the ThunarFiles */
+ files = thunar_io_scan_directory (NULL, templates_dir,
+ G_FILE_QUERY_INFO_NONE,
+ TRUE, FALSE, TRUE, NULL);
+ }
- g_signal_connect (templates_action->job, "files-ready",
- G_CALLBACK (thunar_templates_action_files_ready),
- templates_action);
- g_signal_connect (templates_action->job, "error",
- G_CALLBACK (thunar_templates_action_load_error),
- templates_action);
- g_signal_connect (templates_action->job, "finished",
- G_CALLBACK (thunar_templates_action_load_finished),
- templates_action);
+ g_object_unref (templates_dir);
+ g_object_unref (home_dir);
+
+ if (files == NULL)
+ {
+ thunar_templates_action_set_error (menu, _("No templates installed"),
+ templates_action);
+ }
+ else
+ {
+ thunar_templates_action_set_files (menu, files, templates_action);
+ thunar_g_file_list_free (files);
}
+
+ thunar_templates_action_load_finished (menu, templates_action);
}
diff --git a/thunar/thunar-thumbnailer.c b/thunar/thunar-thumbnailer.c
index 0c45fd0b..4be88b4c 100644
--- a/thunar/thunar-thumbnailer.c
+++ b/thunar/thunar-thumbnailer.c
@@ -356,8 +356,15 @@ thunar_thumbnailer_queue_async_reply (GObject *proxy,
}
else if (error == NULL)
{
- /* store the handle returned by tumbler */
- job->handle = handle;
+ if (handle == 0)
+ {
+ g_printerr ("ThunarThumbnailer: got 0 handle (Queue)\n");
+ }
+ else
+ {
+ /* store the handle returned by tumbler */
+ job->handle = handle;
+ }
}
else
{
@@ -871,6 +878,12 @@ thunar_thumbnailer_thumbnailer_finished (GDBusProxy *proxy,
_thunar_return_if_fail (G_IS_DBUS_PROXY (proxy));
_thunar_return_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer));
+ if (handle == 0)
+ {
+ g_printerr ("ThunarThumbnailer: got 0 handle (Finished)\n");
+ return;
+ }
+
_thumbnailer_lock (thumbnailer);
for (lp = thumbnailer->jobs; lp != NULL; lp = lp->next)
@@ -912,6 +925,12 @@ thunar_thumbnailer_idle (ThunarThumbnailer *thumbnailer,
if (G_UNLIKELY (uris == NULL))
return;
+ if (handle == 0)
+ {
+ g_printerr ("ThunarThumbnailer: got 0 handle (Error or Ready)\n");
+ return;
+ }
+
_thumbnailer_lock (thumbnailer);
/* look for the job so we don't emit unknown handles, the reason
@@ -1089,7 +1108,7 @@ thunar_thumbnailer_queue_files (ThunarThumbnailer *thumbnailer,
/* allocate a job */
job = g_slice_new0 (ThunarThumbnailerJob);
job->thumbnailer = thumbnailer;
- job->files = g_list_copy_deep (files, (GCopyFunc)g_object_ref, NULL);
+ job->files = g_list_copy_deep (files, (GCopyFunc) (void (*)(void)) g_object_ref, NULL);
job->lazy_checks = lazy_checks ? 1 : 0;
success = thunar_thumbnailer_begin_job (thumbnailer, job);
diff --git a/thunar/thunar-transfer-job.c b/thunar/thunar-transfer-job.c
index 570f28a2..f7d75598 100644
--- a/thunar/thunar-transfer-job.c
+++ b/thunar/thunar-transfer-job.c
@@ -103,6 +103,7 @@ struct _ThunarTransferNode
ThunarTransferNode *next;
ThunarTransferNode *children;
GFile *source_file;
+ gboolean replace_confirmed;
};
@@ -318,6 +319,7 @@ thunar_transfer_job_collect_node (ThunarTransferJob *job,
/* allocate a new transfer node for the child */
child_node = g_slice_new0 (ThunarTransferNode);
child_node->source_file = g_object_ref (lp->data);
+ child_node->replace_confirmed = node->replace_confirmed;
/* hook the child node into the child list */
child_node->next = node->children;
@@ -471,12 +473,15 @@ ttj_copy_file (ThunarTransferJob *job,
* @job : a #ThunarTransferJob.
* @source_file : the source #GFile to copy.
* @target_file : the destination #GFile to copy to.
+ * @replace_confirmed : whether the user has already confirmed that this file should replace an existing one
* @error : return location for errors or %NULL.
*
* Tries to copy @source_file to @target_file. The real destination is the
* return value and may differ from @target_file (e.g. if you try to copy
* the file "/foo/bar" into the same directory you'll end up with something
- * like "/foo/copy of bar" instead of "/foo/bar".
+ * like "/foo/copy of bar" instead of "/foo/bar"). If an existing file would
+ * be replaced, the user is asked to confirm this unless @replace_confirmed
+ * is TRUE.
*
* The return value is guaranteed to be %NULL on errors and @error will
* always be set in those cases. If the file is skipped, the return value
@@ -492,6 +497,7 @@ static GFile *
thunar_transfer_job_copy_file (ThunarTransferJob *job,
GFile *source_file,
GFile *target_file,
+ gboolean replace_confirmed,
GError **error)
{
ThunarJobResponse response;
@@ -555,17 +561,16 @@ thunar_transfer_job_copy_file (ThunarTransferJob *job,
/* reset the error */
g_clear_error (&err);
- /* ask the user whether to replace the target file */
- response = thunar_job_ask_replace (THUNAR_JOB (job), source_file,
- target_file, &err);
+ /* if necessary, ask the user whether to replace the target file */
+ if(replace_confirmed)
+ response = THUNAR_JOB_RESPONSE_YES;
+ else
+ response = thunar_job_ask_replace (THUNAR_JOB (job), source_file,
+ target_file, &err);
if (err != NULL)
break;
- /* check if we should retry */
- if (response == THUNAR_JOB_RESPONSE_RETRY)
- continue;
-
/* add overwrite flag and retry if we should overwrite */
if (response == THUNAR_JOB_RESPONSE_YES)
{
@@ -652,7 +657,7 @@ thunar_transfer_job_copy_node (ThunarTransferJob *job,
retry_copy:
/* copy the item specified by this node (not recursively) */
real_target_file = thunar_transfer_job_copy_file (job, node->source_file,
- target_file, &err);
+ target_file, node->replace_confirmed, &err);
if (G_LIKELY (real_target_file != NULL))
{
/* node->source_file == real_target_file means to skip the file */
@@ -827,15 +832,11 @@ thunar_transfer_job_verify_destination (ThunarTransferJob *transfer_job,
}
}
- if (succeed && g_file_info_get_attribute_boolean (filesystem_info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY))
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_READ_ONLY,
- _("Error while copying to \"%s\": The destination is read-only"),
- dest_name);
-
- /* meh */
- succeed = FALSE;
- }
+ /* We used to check G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE here,
+ * but it's not completely reliable, especially on remote file systems.
+ * The downside is that operations on read-only files fail with a generic
+ * error message.
+ * More details: https://bugzilla.xfce.org/show_bug.cgi?id=15367#c16 */
g_object_unref (filesystem_info);
g_object_unref (G_OBJECT (dest));
@@ -858,6 +859,7 @@ thunar_transfer_job_execute (ExoJob *job,
GFileInfo *info;
GFileCopyFlags flags;
gboolean parent_exists;
+ gboolean move_successful;
GError *err = NULL;
GList *new_files_list = NULL;
GList *snext;
@@ -927,6 +929,7 @@ thunar_transfer_job_execute (ExoJob *job,
if (exo_job_set_error_if_cancelled (job, &err))
{
g_object_unref (target_parent);
+ g_object_unref (info);
break;
}
@@ -950,6 +953,7 @@ thunar_transfer_job_execute (ExoJob *job,
{
g_object_unref (target_parent);
g_free (parent_display_name);
+ g_object_unref (info);
break;
}
@@ -970,6 +974,7 @@ thunar_transfer_job_execute (ExoJob *job,
g_object_unref (target_parent);
g_free (parent_display_name);
+ g_object_unref (info);
break;
}
@@ -987,18 +992,58 @@ thunar_transfer_job_execute (ExoJob *job,
exo_job_info_message (job, _("Trying to move \"%s\""),
g_file_info_get_display_name (info));
- if (g_file_move (node->source_file, tp->data,
- flags,
- exo_job_get_cancellable (job),
- NULL, NULL, &err))
+ /* try moving without overwriting */
+ move_successful = g_file_move (node->source_file, tp->data,
+ flags,
+ exo_job_get_cancellable (job),
+ NULL, NULL, &err);
+
+ /* if the file already exists, ask the user if they want to overwrite it */
+ if (!move_successful && err->code == G_IO_ERROR_EXISTS)
{
- /* notify the thumbnail cache of the move operation */
- thunar_thumbnail_cache_move_file (thumbnail_cache,
- node->source_file,
- tp->data);
+ g_clear_error (&err);
+ response = thunar_job_ask_replace (THUNAR_JOB (job), node->source_file, tp->data, NULL);
- /* add the target file to the new files list */
- new_files_list = thunar_g_file_list_prepend (new_files_list, tp->data);
+ /* if the user chose to overwrite then try to do so */
+ if (response == THUNAR_JOB_RESPONSE_YES)
+ {
+ node->replace_confirmed = TRUE;
+ move_successful = g_file_move (node->source_file, tp->data,
+ flags | G_FILE_COPY_OVERWRITE,
+ exo_job_get_cancellable (job),
+ NULL, NULL, &err);
+ }
+
+ /* if the user chose to cancel then abort all remaining file moves */
+ if (response == THUNAR_JOB_RESPONSE_CANCEL)
+ {
+ /* release all the remaining source and target files, and free the lists */
+ g_list_free_full (transfer_job->source_node_list, thunar_transfer_node_free);
+ transfer_job->source_node_list = NULL;
+ g_list_free_full (transfer_job->target_file_list, g_object_unref);
+ transfer_job->target_file_list= NULL;
+ g_object_unref (info);
+ break;
+ }
+
+ /* if the user chose not to replace the file, so that response == THUNAR_JOB_RESPONSE_NO,
+ * then err will be NULL but move_successfull will be FALSE, so that the source and target
+ * files will be released and the matching list items will be dropped below
+ */
+ }
+
+ if (err == NULL)
+ {
+ if (move_successful)
+ {
+ /* notify the thumbnail cache of the move operation */
+ thunar_thumbnail_cache_move_file (thumbnail_cache,
+ node->source_file,
+ tp->data);
+
+ /* add the target file to the new files list */
+ new_files_list = thunar_g_file_list_prepend (new_files_list, tp->data);
+ }
/* release source and target files */
thunar_transfer_node_free (node);
@@ -1008,7 +1053,10 @@ thunar_transfer_job_execute (ExoJob *job,
transfer_job->source_node_list = g_list_delete_link (transfer_job->source_node_list, sp);
transfer_job->target_file_list = g_list_delete_link (transfer_job->target_file_list, tp);
}
- else if (!exo_job_is_cancelled (job))
+ /* prepare for the fallback copy and delete if appropriate */
+ else if (!exo_job_is_cancelled (job) &&
+ ((err->code == G_IO_ERROR_NOT_SUPPORTED) ||
+ (err->code == G_IO_ERROR_WOULD_MERGE) || (err->code == G_IO_ERROR_WOULD_RECURSE)) )
{
g_clear_error (&err);
@@ -1017,14 +1065,12 @@ thunar_transfer_job_execute (ExoJob *job,
"Collecting files for copying..."),
g_file_info_get_display_name (info));
- if (!thunar_transfer_job_collect_node (transfer_job, node, &err))
- {
- /* failed to collect, cannot continue */
- g_object_unref (info);
- break;
- }
+ /* if this call fails to collect the node, err will be non-NULL and the loop will exit */
+ thunar_transfer_job_collect_node (transfer_job, node, &err);
}
+
}
+
else if (transfer_job->type == THUNAR_TRANSFER_JOB_COPY)
{
if (!thunar_transfer_job_collect_node (THUNAR_TRANSFER_JOB (job), node, &err))
@@ -1144,6 +1190,7 @@ thunar_transfer_job_new (GList *source_node_list,
/* append transfer node for this source file */
node = g_slice_new0 (ThunarTransferNode);
node->source_file = g_object_ref (sp->data);
+ node->replace_confirmed = FALSE;
job->source_node_list = g_list_append (job->source_node_list, node);
/* append target file */
@@ -1222,4 +1269,3 @@ thunar_transfer_job_get_status (ThunarTransferJob *job)
return g_string_free (status, FALSE);
}
-
diff --git a/thunar/thunar-tree-model.c b/thunar/thunar-tree-model.c
index 3424f480..774a5e3d 100644
--- a/thunar/thunar-tree-model.c
+++ b/thunar/thunar-tree-model.c
@@ -295,7 +295,7 @@ thunar_tree_model_init (ThunarTreeModel *model)
/* initialize the model data */
model->sort_case_sensitive = TRUE;
- model->visible_func = (ThunarTreeModelVisibleFunc) exo_noop_true;
+ model->visible_func = (ThunarTreeModelVisibleFunc) (void (*)(void)) exo_noop_true;
model->visible_data = NULL;
model->cleanup_idle_id = 0;
@@ -1075,23 +1075,37 @@ thunar_tree_model_device_added (ThunarDeviceMonitor *device_monitor,
_thunar_return_if_fail (THUNAR_IS_DEVICE (device));
_thunar_return_if_fail (THUNAR_IS_TREE_MODEL (model));
+ /* lookup the last child of the root (the "File System" node) */
+ node = g_node_last_child (model->root);
+
+ /* determine the position for the new node in the item list */
+ for (node = node->prev; node != NULL; node = node->prev)
+ {
+ item = THUNAR_TREE_MODEL_ITEM (node->data);
+ if (item->device == NULL)
+ break;
+
+ /* sort devices by timestamp */
+ if (thunar_device_sort (item->device, device) < 0)
+ break;
+ }
+
/* allocate a new item for the volume */
item = thunar_tree_model_item_new_with_device (model, device);
- /* insert before the last child of the root (the "File System" node) */
- node = g_node_last_child (model->root);
- node = g_node_insert_data_before (model->root, node, item);
+ /* insert the new node */
+ node = g_node_insert_data_after (model->root, node, item);
/* determine the iterator for the new node */
GTK_TREE_ITER_INIT (iter, model->stamp, node);
- /* add the dummy node */
- thunar_tree_model_node_insert_dummy (node, model);
-
/* tell the view about the new node */
path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
gtk_tree_path_free (path);
+
+ /* add the dummy node */
+ thunar_tree_model_node_insert_dummy (node, model);
}
diff --git a/thunar/thunar-tree-view.c b/thunar/thunar-tree-view.c
index 3ac367e4..0db3b202 100644
--- a/thunar/thunar-tree-view.c
+++ b/thunar/thunar-tree-view.c
@@ -142,6 +142,8 @@ static GdkDragAction thunar_tree_view_get_dest_actions (T
ThunarFile **file_return);
static ThunarFile *thunar_tree_view_get_selected_file (ThunarTreeView *view);
static ThunarDevice *thunar_tree_view_get_selected_device (ThunarTreeView *view);
+static void thunar_tree_view_action_unlink_selected_folder(ThunarTreeView *view,
+ gboolean permanently);
static void thunar_tree_view_action_copy (ThunarTreeView *view);
static void thunar_tree_view_action_create_folder (ThunarTreeView *view);
static void thunar_tree_view_action_cut (ThunarTreeView *view);
@@ -1230,7 +1232,8 @@ thunar_tree_view_row_collapsed (GtkTreeView *tree_view,
static gboolean
thunar_tree_view_delete_selected_files (ThunarTreeView *view)
{
- GtkAccelKey key;
+ GtkAccelKey key;
+ GdkModifierType state;
_thunar_return_val_if_fail (THUNAR_IS_TREE_VIEW (view), FALSE);
@@ -1241,8 +1244,12 @@ thunar_tree_view_delete_selected_files (ThunarTreeView *view)
&& (key.accel_key != 0 || key.accel_mods != 0))
return FALSE;
- /* ask the user whether to delete the folder... */
- thunar_tree_view_action_move_to_trash (view);
+ /* check if we should permanently delete the files (user holds shift or no gvfs available) */
+ if ((gtk_get_current_event_state (&state) && (state & GDK_SHIFT_MASK) != 0) ||
+ (gtk_get_current_event_state (&state) && !thunar_g_vfs_is_uri_scheme_supported ("trash")))
+ thunar_tree_view_action_delete (view);
+ else
+ thunar_tree_view_action_move_to_trash (view);
/* ...and we're done */
return TRUE;
@@ -1265,6 +1272,7 @@ thunar_tree_view_context_menu (ThunarTreeView *view,
GIcon *icon;
GList *providers, *lp;
GList *items = NULL, *tmp;
+ gboolean show_delete_action;
/* verify that we're connected to the clipboard manager */
if (G_UNLIKELY (view->clipboard == NULL))
@@ -1351,7 +1359,12 @@ G_GNUC_END_IGNORE_DEPRECATIONS
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_widget_show (item);
}
- else if (G_UNLIKELY (file != NULL && thunar_file_is_trashed (file) && thunar_file_is_root (file)))
+
+ if (G_UNLIKELY (file == NULL))
+ {
+ /* do nothing */
+ }
+ else if (G_UNLIKELY (thunar_g_file_is_trash (thunar_file_get_file (file))))
{
/* append the "Empty Trash" menu action */
item = gtk_menu_item_new_with_mnemonic (_("_Empty Trash"));
@@ -1365,35 +1378,34 @@ G_GNUC_END_IGNORE_DEPRECATIONS
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_widget_show (item);
}
-
- /* check if we have a non-trashed resource */
- if (G_LIKELY (file != NULL && !thunar_file_is_trashed (file)))
+ else
{
- /* append the "Create Folder" menu action */
+ /* check if we have a non-trashed resource */
+ if (G_LIKELY (!thunar_file_is_trashed (file)))
+ {
+ /* append the "Create Folder" menu action */
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
- item = gtk_image_menu_item_new_with_mnemonic (_("Create _Folder..."));
+ item = gtk_image_menu_item_new_with_mnemonic (_("Create _Folder..."));
G_GNUC_END_IGNORE_DEPRECATIONS
- gtk_widget_set_sensitive (item, thunar_file_is_writable (file));
- g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_tree_view_action_create_folder), view);
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
- gtk_widget_show (item);
+ gtk_widget_set_sensitive (item, thunar_file_is_writable (file));
+ g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_tree_view_action_create_folder), view);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_show (item);
- /* set the icon */
- icon = g_themed_icon_new ("folder-new");
- image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_MENU);
+ /* set the icon */
+ icon = g_themed_icon_new ("folder-new");
+ image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_MENU);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
G_GNUC_END_IGNORE_DEPRECATIONS
- g_object_unref (icon);
+ g_object_unref (icon);
- /* append a separator item */
- item = gtk_separator_menu_item_new ();
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
- gtk_widget_show (item);
- }
+ /* append a separator item */
+ item = gtk_separator_menu_item_new ();
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_show (item);
+ }
- if (G_LIKELY (file != NULL))
- {
/* "Cut" and "Copy" don't make much sense for devices */
if (G_LIKELY (device == NULL))
{
@@ -1454,6 +1466,8 @@ G_GNUC_END_IGNORE_DEPRECATIONS
/* "Delete" and "Rename" don't make much sense for devices */
if (G_LIKELY (device == NULL))
{
+ g_object_get (G_OBJECT (view->preferences), "misc-show-delete-action", &show_delete_action, NULL);
+
/* determine the parent file (required to determine "Delete" sensitivity) */
parent_file = thunar_file_get_parent (file, NULL);
@@ -1462,8 +1476,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_widget_show (item);
- if (thunar_g_vfs_is_uri_scheme_supported ("trash")
- && thunar_file_can_be_trashed (file))
+ if (thunar_g_vfs_is_uri_scheme_supported ("trash"))
{
/* append the "Move to Tash" menu action */
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
@@ -1471,30 +1484,34 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
G_GNUC_END_IGNORE_DEPRECATIONS
g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_tree_view_action_move_to_trash), view);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
- gtk_widget_set_sensitive (item, (parent_file != NULL && thunar_file_is_writable (parent_file)));
+ gtk_widget_set_sensitive (item, (parent_file != NULL && thunar_file_is_writable (parent_file) && thunar_file_can_be_trashed (file)));
gtk_widget_show (item);
/* set the icon */
- image = gtk_image_new_from_icon_name ("user-trash-full", GTK_ICON_SIZE_MENU);
+ image = gtk_image_new_from_icon_name ("user-trash", GTK_ICON_SIZE_MENU);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
G_GNUC_END_IGNORE_DEPRECATIONS
}
- /* append the "Delete" menu action */
+ if (!thunar_g_vfs_is_uri_scheme_supported ("trash")
+ || show_delete_action || thunar_file_is_trashed (file))
+ {
+ /* append the "Delete" menu action */
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
- item = gtk_image_menu_item_new_with_mnemonic (_("_Delete"));
+ item = gtk_image_menu_item_new_with_mnemonic (_("_Delete"));
G_GNUC_END_IGNORE_DEPRECATIONS
- g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_tree_view_action_delete), view);
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
- gtk_widget_set_sensitive (item, (parent_file != NULL && thunar_file_is_writable (parent_file)));
- gtk_widget_show (item);
+ g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_tree_view_action_delete), view);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_set_sensitive (item, (parent_file != NULL && thunar_file_is_writable (parent_file)));
+ gtk_widget_show (item);
- /* set the icon */
- image = gtk_image_new_from_icon_name ("edit-delete", GTK_ICON_SIZE_MENU);
+ /* set the icon */
+ image = gtk_image_new_from_icon_name ("edit-delete", GTK_ICON_SIZE_MENU);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
G_GNUC_END_IGNORE_DEPRECATIONS
+ }
/* cleanup */
if (G_LIKELY (parent_file != NULL))
@@ -1814,13 +1831,12 @@ thunar_tree_view_action_cut (ThunarTreeView *view)
static void
-thunar_tree_view_action_move_to_trash (ThunarTreeView *view)
+thunar_tree_view_action_unlink_selected_folder (ThunarTreeView *view,
+ gboolean permanently)
{
ThunarApplication *application;
ThunarFile *file;
GList file_list;
- gboolean permanently;
- GdkModifierType state;
_thunar_return_if_fail (THUNAR_IS_TREE_VIEW (view));
@@ -1828,18 +1844,18 @@ thunar_tree_view_action_move_to_trash (ThunarTreeView *view)
file = thunar_tree_view_get_selected_file (view);
if (G_LIKELY (file != NULL))
{
- /* fake a file list */
- file_list.data = file;
- file_list.next = NULL;
- file_list.prev = NULL;
-
- /* check if we should permanently delete the files (user holds shift) */
- permanently = (gtk_get_current_event_state (&state) && (state & GDK_SHIFT_MASK) != 0);
-
- /* delete the file */
- application = thunar_application_get ();
- thunar_application_unlink_files (application, GTK_WIDGET (view), &file_list, permanently);
- g_object_unref (G_OBJECT (application));
+ if (thunar_file_can_be_trashed (file))
+ {
+ /* fake a file list */
+ file_list.data = file;
+ file_list.next = NULL;
+ file_list.prev = NULL;
+
+ /* delete the file */
+ application = thunar_application_get ();
+ thunar_application_unlink_files (application, GTK_WIDGET (view), &file_list, permanently);
+ g_object_unref (G_OBJECT (application));
+ }
/* release the file */
g_object_unref (G_OBJECT (file));
@@ -1849,31 +1865,17 @@ thunar_tree_view_action_move_to_trash (ThunarTreeView *view)
static void
-thunar_tree_view_action_delete (ThunarTreeView *view)
+thunar_tree_view_action_move_to_trash (ThunarTreeView *view)
{
- ThunarApplication *application;
- ThunarFile *file;
- GList file_list;
+ thunar_tree_view_action_unlink_selected_folder (view, FALSE);
+}
- _thunar_return_if_fail (THUNAR_IS_TREE_VIEW (view));
- /* determine the selected file */
- file = thunar_tree_view_get_selected_file (view);
- if (G_LIKELY (file != NULL))
- {
- /* fake a file list */
- file_list.data = file;
- file_list.next = NULL;
- file_list.prev = NULL;
- /* delete the file */
- application = thunar_application_get ();
- thunar_application_unlink_files (application, GTK_WIDGET (view), &file_list, TRUE);
- g_object_unref (G_OBJECT (application));
-
- /* release the file */
- g_object_unref (G_OBJECT (file));
- }
+static void
+thunar_tree_view_action_delete (ThunarTreeView *view)
+{
+ thunar_tree_view_action_unlink_selected_folder (view, TRUE);
}
@@ -2096,7 +2098,7 @@ thunar_tree_view_mount_finish (ThunarDevice *device,
thunar_dialogs_show_error (GTK_WIDGET (data->view), error, _("Failed to mount \"%s\""), device_name);
g_free (device_name);
}
- else
+ else if (thunar_device_is_mounted (device))
{
if (G_LIKELY (data->open_after_mounting))
{
@@ -2501,11 +2503,11 @@ thunar_tree_view_cursor_idle (gpointer user_data)
GtkTreePath *path;
GtkTreeIter iter;
ThunarFile *file;
- ThunarFile *parent;
- GFileInfo *parent_info;
+ ThunarFolder *folder;
+ GFileInfo *file_info;
GtkTreeIter child_iter;
ThunarFile *file_in_tree;
- gboolean done = TRUE;
+ gboolean done = FALSE;
GList *lp;
GList *path_as_list = NULL;
@@ -2517,12 +2519,12 @@ THUNAR_THREADS_ENTER
gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), view->select_path, NULL, FALSE);
gtk_tree_path_free (view->select_path);
view->select_path = NULL;
- return done;
+ return TRUE;
}
/* verify that we still have a current directory */
if (G_UNLIKELY (view->current_directory == NULL))
- return done;
+ return TRUE;
/* get the preferred toplevel path for the current directory */
path = thunar_tree_view_get_preferred_toplevel_path (view, view->current_directory);
@@ -2538,63 +2540,85 @@ THUNAR_THREADS_ENTER
for (file = view->current_directory; file != NULL; file = thunar_file_get_parent (file, NULL))
path_as_list = g_list_prepend (path_as_list, file);
- /* note that iter may start at e.g. $HOME where "path_as_list" usually starts at "/" */
- /* So the first few iterations most times will do nothing */
+ /* 1. skip files on path_as_list till we found the beginning of the tree (which e.g. may start at $HOME */
+ gtk_tree_model_get (GTK_TREE_MODEL (view->model), &iter, THUNAR_TREE_MODEL_COLUMN_FILE, &file_in_tree, -1);
for (lp = path_as_list; lp != NULL; lp = lp->next)
+ {
+ if (THUNAR_FILE (lp->data) == file_in_tree)
+ break;
+ }
+ if (file_in_tree)
+ g_object_unref (file_in_tree);
+
+ /* 2. loop on the remaining path_as_list */
+ for (; lp != NULL; lp = lp->next)
{
file = THUNAR_FILE (lp->data);
- /* check if iter has only a dummy node (tree not fully loaded yet) */
- if( thunar_tree_model_node_has_dummy (view->model, iter.user_data) )
+ /* 3. Check if the contents of the corresponding folder is still being loaded */
+ folder = thunar_folder_get_for_file (file);
+ if (folder != NULL && thunar_folder_get_loading (folder))
+ {
+ g_object_unref (folder);
+ break;
+ }
+ if (folder)
+ g_object_unref (folder);
+
+ /* 4. Loop on all items of current tree-level to see if any folder matches the path we search */
+ while (TRUE)
+ {
+ gtk_tree_model_get (GTK_TREE_MODEL (view->model), &iter, THUNAR_TREE_MODEL_COLUMN_FILE, &file_in_tree, -1);
+ if (file == file_in_tree)
+ {
+ g_object_unref (file_in_tree);
+ break;
+ }
+ if (file_in_tree)
+ g_object_unref (file_in_tree);
+
+ if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (view->model), &iter))
+ break;
+ }
+
+ /* 5. Did we already find the full path ?*/
+ if (lp->next == NULL)
{
- done = FALSE;
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (view->model), &iter);
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), path, NULL, FALSE);
+ gtk_tree_path_free (path);
+ done = TRUE;
break;
}
- /* Try to create missing children if there are none (this as well initializes child_iter if there are children) */
+ /* 6. Get all children of the current tree iter */
+ /* Try to create missing children on the tree if there are none */
if (!gtk_tree_model_iter_children (GTK_TREE_MODEL (view->model), &child_iter, &iter))
{
- done = FALSE;
- parent = thunar_file_get_parent (file, NULL);
- if (parent == NULL) /* e.g root has no parent .. skip it */
+ if (file == NULL) /* e.g root has no parent .. skip it */
continue;
- parent_info = thunar_file_get_info (parent);
- if (parent_info != NULL)
+ file_info = thunar_file_get_info (file);
+ if (file_info != NULL)
{
/* E.g. folders for which we do not have read permission dont have any child in the tree */
/* Make sure that missing read permissions are the problem */
- if (!g_file_info_get_attribute_boolean (parent_info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ))
+ if (!g_file_info_get_attribute_boolean (file_info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ))
{
/* We KNOW that there is a File. Lets just create the required tree-node */
- thunar_tree_model_add_child (view->model, iter.user_data, file);
+ thunar_tree_model_add_child (view->model, iter.user_data, THUNAR_FILE (lp->next->data));
}
}
- g_object_unref (parent);
break; /* we dont have a valid child_iter by now, so we cannot continue. */
/* Since done is FALSE, the next iteration on thunar_tree_view_cursor_idle will go deeper */
}
- /* loop on children to see if any folder matches */
- while (TRUE)
- {
- gtk_tree_model_get (GTK_TREE_MODEL (view->model), &child_iter, THUNAR_TREE_MODEL_COLUMN_FILE, &file_in_tree, -1);
- if (file == file_in_tree)
- {
- g_object_unref (file_in_tree);
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (view->model), &child_iter);
- gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view), path);
- gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), path, NULL, FALSE);
- gtk_tree_path_free (path);
- iter = child_iter; /* next tree level */
- break;
- }
- if (file_in_tree)
- g_object_unref (file_in_tree);
+ /* expand path up to the current tree level */
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (view->model), &iter);
+ gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view), path);
+ gtk_tree_path_free (path);
- if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (view->model), &child_iter))
- break;
- }
+ iter = child_iter; /* next tree level */
}
/* tidy up */
@@ -2849,8 +2873,8 @@ thunar_tree_view_set_show_hidden (ThunarTreeView *view,
*
* Searches for the best-matching toplevel path in the
* following order:
- * 1) any mounted device or network resource
- * 2) the user's desktop directory
+ * 1) the currently active one
+ * 2) any mounted device or network resource
* 3) the user's home directory
* 4) the root filesystem
*
@@ -2872,6 +2896,35 @@ thunar_tree_view_get_preferred_toplevel_path (ThunarTreeView *view,
_thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL);
+ /* get active toplevel path and check if we can use it */
+ gtk_tree_view_get_cursor (GTK_TREE_VIEW (view), &path, NULL);
+ if (path != NULL)
+ {
+ if (gtk_tree_path_get_depth (path) != 1)
+ while (gtk_tree_path_get_depth (path) > 1)
+ gtk_tree_path_up (path);
+
+ if (gtk_tree_model_get_iter (GTK_TREE_MODEL (view->model), &iter, path))
+ {
+ /* lookup file for the toplevel item */
+ gtk_tree_model_get (GTK_TREE_MODEL (view->model), &iter, THUNAR_TREE_MODEL_COLUMN_FILE, &toplevel_file, -1);
+ if (toplevel_file)
+ {
+ /* check if the toplevel file is an ancestor */
+ if (thunar_file_is_ancestor (file, toplevel_file))
+ {
+ g_object_unref (toplevel_file);
+ return path;
+ }
+
+ g_object_unref (toplevel_file);
+ }
+ }
+
+ gtk_tree_path_free (path);
+ path = NULL;
+ }
+
/* check whether the root node is available */
if (!gtk_tree_model_get_iter_first (model, &iter))
return NULL;
diff --git a/thunar/thunar-user.c b/thunar/thunar-user.c
index ceba7b0d..3fef90cf 100644
--- a/thunar/thunar-user.c
+++ b/thunar/thunar-user.c
@@ -562,10 +562,14 @@ thunar_user_manager_flush_timer (gpointer user_data)
THUNAR_THREADS_ENTER
/* drop all cached groups */
- size += g_hash_table_foreach_remove (manager->groups, (GHRFunc) gtk_true, NULL);
+ size += g_hash_table_foreach_remove (manager->groups,
+ (GHRFunc) (void (*)(void)) gtk_true,
+ NULL);
/* drop all cached users */
- size += g_hash_table_foreach_remove (manager->users, (GHRFunc) gtk_true, NULL);
+ size += g_hash_table_foreach_remove (manager->users,
+ (GHRFunc) (void (*)(void)) gtk_true,
+ NULL);
/* reload groups and passwd files if we had cached entities */
if (G_LIKELY (size > 0))
diff --git a/thunar/thunar-util.c b/thunar/thunar-util.c
index c3c864a7..99cd4786 100644
--- a/thunar/thunar-util.c
+++ b/thunar/thunar-util.c
@@ -374,7 +374,7 @@ thunar_util_humanize_file_time (guint64 file_time,
const gchar *date_custom_style)
{
const gchar *date_format;
- struct tm *tfile;
+ struct tm tfile;
time_t ftime;
GDate dfile;
GDate dnow;
@@ -385,8 +385,8 @@ thunar_util_humanize_file_time (guint64 file_time,
{
ftime = (time_t) file_time;
- /* determine the local file time */
- tfile = localtime (&ftime);
+ /* take a copy of the local file time */
+ tfile = *localtime (&ftime);
/* check which style to use to format the time */
if (date_style == THUNAR_DATE_STYLE_SIMPLE || date_style == THUNAR_DATE_STYLE_SHORT)
@@ -407,7 +407,7 @@ thunar_util_humanize_file_time (guint64 file_time,
else /* if (date_style == THUNAR_DATE_STYLE_SHORT) */
{
/* TRANSLATORS: file was modified less than one day ago */
- return exo_strdup_strftime (_("Today at %X"), tfile);
+ return exo_strdup_strftime (_("Today at %X"), &tfile);
}
}
else if (diff == 1)
@@ -420,7 +420,7 @@ thunar_util_humanize_file_time (guint64 file_time,
else /* if (date_style == THUNAR_DATE_STYLE_SHORT) */
{
/* TRANSLATORS: file was modified less than two days ago */
- return exo_strdup_strftime (_("Yesterday at %X"), tfile);
+ return exo_strdup_strftime (_("Yesterday at %X"), &tfile);
}
}
else
@@ -437,25 +437,25 @@ thunar_util_humanize_file_time (guint64 file_time,
}
/* format the date string accordingly */
- return exo_strdup_strftime (date_format, tfile);
+ return exo_strdup_strftime (date_format, &tfile);
}
}
else if (date_style == THUNAR_DATE_STYLE_LONG)
{
/* use long, date(1)-like format string */
- return exo_strdup_strftime ("%c", tfile);
+ return exo_strdup_strftime ("%c", &tfile);
}
else if (date_style == THUNAR_DATE_STYLE_YYYYMMDD)
{
- return exo_strdup_strftime ("%Y-%m-%d %H:%M:%S", tfile);
+ return exo_strdup_strftime ("%Y-%m-%d %H:%M:%S", &tfile);
}
else if (date_style == THUNAR_DATE_STYLE_MMDDYYYY)
{
- return exo_strdup_strftime ("%m-%d-%Y %H:%M:%S", tfile);
+ return exo_strdup_strftime ("%m-%d-%Y %H:%M:%S", &tfile);
}
else if (date_style == THUNAR_DATE_STYLE_DDMMYYYY)
{
- return exo_strdup_strftime ("%d-%m-%Y %H:%M:%S", tfile);
+ return exo_strdup_strftime ("%d-%m-%Y %H:%M:%S", &tfile);
}
else /* if (date_style == THUNAR_DATE_STYLE_CUSTOM) */
{
@@ -463,7 +463,7 @@ thunar_util_humanize_file_time (guint64 file_time,
return g_strdup ("");
/* use custom date formatting */
- return exo_strdup_strftime (date_custom_style, tfile);
+ return exo_strdup_strftime (date_custom_style, &tfile);
}
}
diff --git a/thunar/thunar-view.c b/thunar/thunar-view.c
index 698d6872..d2a15616 100644
--- a/thunar/thunar-view.c
+++ b/thunar/thunar-view.c
@@ -41,7 +41,7 @@ thunar_view_get_type (void)
type = g_type_register_static_simple (G_TYPE_INTERFACE,
I_("ThunarView"),
sizeof (ThunarViewIface),
- (GClassInitFunc) thunar_view_class_init,
+ (GClassInitFunc) (void (*)(void)) thunar_view_class_init,
0,
NULL,
0);
diff --git a/thunar/thunar-window.c b/thunar/thunar-window.c
index df24b900..9e9be0fd 100644
--- a/thunar/thunar-window.c
+++ b/thunar/thunar-window.c
@@ -216,6 +216,9 @@ static void thunar_window_action_about (GtkAction
ThunarWindow *window);
static void thunar_window_action_show_hidden (GtkToggleAction *action,
ThunarWindow *window);
+static gboolean thunar_window_propagate_key_event (GtkWindow *window,
+ GdkEvent *key_event,
+ gpointer user_data);
static void thunar_window_current_directory_changed (ThunarFile *current_directory,
ThunarWindow *window);
static void thunar_window_connect_proxy (GtkUIManager *manager,
@@ -377,6 +380,7 @@ static GtkActionEntry action_entries[] =
{ "open-network", "network-workgroup", N_("B_rowse Network"), NULL, N_ ("Browse local network connections"), G_CALLBACK (thunar_window_action_open_network), },
{ "open-templates", "text-x-generic-template", N_("T_emplates"), NULL, N_ ("Go to the templates folder"), G_CALLBACK (thunar_window_action_open_templates), },
{ "open-location", NULL, N_ ("_Open Location..."), "<control>L", N_ ("Specify a location to open"), G_CALLBACK (thunar_window_action_open_location), },
+ { "open-location-alt", NULL, "open-location-alt", "<alt>D", NULL, G_CALLBACK (thunar_window_action_open_location), },
{ "help-menu", NULL, N_ ("_Help"), NULL, },
{ "contents", "help-browser", N_ ("_Contents"), "F1", N_ ("Display Thunar user manual"), G_CALLBACK (thunar_window_action_contents), },
{ "about", "help-about", N_ ("_About"), NULL, N_ ("Display information about Thunar"), G_CALLBACK (thunar_window_action_about), },
@@ -651,7 +655,7 @@ static inline gint
view_type2index (GType type)
{
/* this necessary for platforms where sizeof(GType) != sizeof(gint),
- * see http://bugzilla.xfce.org/show_bug.cgi?id=2726 for details.
+ * see https://bugzilla.xfce.org/show_bug.cgi?id=2726 for details.
*/
if (sizeof (GType) == sizeof (gint))
{
@@ -676,7 +680,7 @@ static inline GType
view_index2type (gint idx)
{
/* this necessary for platforms where sizeof(GType) != sizeof(gint),
- * see http://bugzilla.xfce.org/show_bug.cgi?id=2726 for details.
+ * see https://bugzilla.xfce.org/show_bug.cgi?id=2726 for details.
*/
if (sizeof (GType) == sizeof (gint))
{
@@ -761,6 +765,10 @@ thunar_window_init (ThunarWindow *window)
g_closure_sink (window->menu_item_deselected_closure);
window->icon_factory = thunar_icon_factory_get_default ();
+ /* Catch key events before accelerators get processed */
+ g_signal_connect (window, "key-press-event", G_CALLBACK (thunar_window_propagate_key_event), NULL);
+ g_signal_connect (window, "key-release-event", G_CALLBACK (thunar_window_propagate_key_event), NULL);
+
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
/* setup the action group for this window */
window->action_group = gtk_action_group_new ("ThunarWindow");
@@ -1428,10 +1436,13 @@ thunar_window_unrealize (GtkWidget *widget)
/* disconnect from the clipboard manager */
g_signal_handlers_disconnect_by_func (G_OBJECT (window->clipboard), gtk_widget_queue_draw, widget);
- g_object_unref (G_OBJECT (window->clipboard));
/* let the GtkWidget class unrealize the window */
(*GTK_WIDGET_CLASS (thunar_window_parent_class)->unrealize) (widget);
+
+ /* drop the reference on the clipboard manager, we do this after letting the GtkWidget class
+ * unrealise the window to prevent the clipboard being disposed during the unrealize */
+ g_object_unref (G_OBJECT (window->clipboard));
}
@@ -3234,6 +3245,31 @@ G_GNUC_END_IGNORE_DEPRECATIONS
+static gboolean
+thunar_window_propagate_key_event (GtkWindow* window,
+ GdkEvent *key_event,
+ gpointer user_data)
+{
+ GtkWidget* focused_widget;
+
+ _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), GDK_EVENT_PROPAGATE);
+
+ focused_widget = gtk_window_get_focus (window);
+
+ /* Turn the accelerator priority around globally,
+ * so that the focused widget always gets the accels first.
+ * Implementing this cleanly while maintaining some wanted accels
+ * (like Ctrl+N and exo accels) is a lot of work. So we resort to
+ * only priorize GtkEditable, because that is the easiest way to
+ * fix the right-ahead problem. */
+ if (focused_widget != NULL && GTK_IS_EDITABLE (focused_widget))
+ return gtk_window_propagate_key_event (window, (GdkEventKey *) key_event);
+
+ return GDK_EVENT_PROPAGATE;
+}
+
+
+
static void
thunar_window_poke_location_finish (ThunarBrowser *browser,
GFile *location,
@@ -3619,7 +3655,8 @@ thunar_window_device_pre_unmount (ThunarDeviceMonitor *device_monitor,
return;
/* check if the file is the current directory or an ancestor of the current directory */
- if (thunar_file_is_gfile_ancestor (window->current_directory, root_file))
+ if (g_file_equal (thunar_file_get_file (window->current_directory), root_file)
+ || thunar_file_is_gfile_ancestor (window->current_directory, root_file))
{
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
/* change to the home folder */
diff --git a/thunarx/thunarx-file-info.c b/thunarx/thunarx-file-info.c
index ae9f184e..ad832062 100644
--- a/thunarx/thunarx-file-info.c
+++ b/thunarx/thunarx-file-info.c
@@ -427,12 +427,12 @@ GList*
thunarx_file_info_list_copy (GList *file_infos)
{
#if GLIB_CHECK_VERSION (2, 34, 0)
- return g_list_copy_deep (file_infos, (GCopyFunc) g_object_ref, NULL);
+ return g_list_copy_deep (file_infos, (GCopyFunc) (void (*)(void)) g_object_ref, NULL);
#else
GList *copy;
copy = g_list_copy (file_infos);
- g_list_foreach (copy, (GFunc) g_object_ref, NULL);
+ g_list_foreach (copy, (GFunc) (void (*)(void)) g_object_ref, NULL);
return copy;
#endif
diff --git a/thunarx/thunarx-menu-item.c b/thunarx/thunarx-menu-item.c
index d9a518c9..4969a6e7 100644
--- a/thunarx/thunarx-menu-item.c
+++ b/thunarx/thunarx-menu-item.c
@@ -27,8 +27,6 @@
-#define THUNARX_MENU_ITEM_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), THUNARX_TYPE_MENU_ITEM, ThunarxMenuItemPrivate))
-
/**
* SECTION: thunarx-menu-item
* @short_description: The base class for menu items added to the context menus
@@ -93,7 +91,7 @@ static guint signals[LAST_SIGNAL];
-G_DEFINE_TYPE (ThunarxMenuItem, thunarx_menu_item, G_TYPE_OBJECT)
+G_DEFINE_TYPE_WITH_PRIVATE (ThunarxMenuItem, thunarx_menu_item, G_TYPE_OBJECT)
@@ -102,9 +100,6 @@ thunarx_menu_item_class_init (ThunarxMenuItemClass *klass)
{
GObjectClass *gobject_class;
- /* add our private data to the class type */
- g_type_class_add_private (klass, sizeof (ThunarxMenuItemPrivate));
-
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = thunarx_menu_item_finalize;
gobject_class->get_property = thunarx_menu_item_get_property;
@@ -177,7 +172,7 @@ thunarx_menu_item_class_init (ThunarxMenuItemClass *klass)
static void
thunarx_menu_item_init (ThunarxMenuItem *item)
{
- item->priv = THUNARX_MENU_ITEM_GET_PRIVATE (item);
+ item->priv = thunarx_menu_item_get_instance_private (item);
item->priv->sensitive = TRUE;
item->priv->priority = FALSE;
item->priv->menu = NULL;
@@ -414,6 +409,6 @@ thunarx_menu_item_list_free (GList *items)
{
g_return_if_fail (items != NULL);
- g_list_foreach (items, (GFunc)g_object_unref, NULL);
+ g_list_foreach (items, (GFunc) (void (*)(void)) g_object_unref, NULL);
g_list_free (items);
}
diff --git a/thunarx/thunarx-menu.c b/thunarx/thunarx-menu.c
index 97961b59..87c431a4 100644
--- a/thunarx/thunarx-menu.c
+++ b/thunarx/thunarx-menu.c
@@ -27,8 +27,6 @@
-#define THUNARX_MENU_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), THUNARX_TYPE_MENU, ThunarxMenuPrivate))
-
/**
* SECTION: thunarx-menu
* @short_description: The base class for submenus added to the context menus
@@ -53,7 +51,7 @@ struct _ThunarxMenuPrivate
-G_DEFINE_TYPE (ThunarxMenu, thunarx_menu, G_TYPE_OBJECT)
+G_DEFINE_TYPE_WITH_PRIVATE (ThunarxMenu, thunarx_menu, G_TYPE_OBJECT)
@@ -62,9 +60,6 @@ thunarx_menu_class_init (ThunarxMenuClass *klass)
{
GObjectClass *gobject_class;
- /* add our private data to the class type */
- g_type_class_add_private (klass, sizeof (ThunarxMenuPrivate));
-
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = thunarx_menu_finalize;
}
@@ -74,7 +69,7 @@ thunarx_menu_class_init (ThunarxMenuClass *klass)
static void
thunarx_menu_init (ThunarxMenu *menu)
{
- menu->priv = THUNARX_MENU_GET_PRIVATE (menu);
+ menu->priv = thunarx_menu_get_instance_private (menu);
menu->priv->items = NULL;
}
@@ -138,7 +133,7 @@ thunarx_menu_get_items (ThunarxMenu *menu)
g_return_val_if_fail (menu != NULL, NULL);
items = g_list_copy (menu->priv->items);
- g_list_foreach (items, (GFunc) g_object_ref, NULL);
+ g_list_foreach (items, (GFunc) (void (*)(void)) g_object_ref, NULL);
return items;
}
diff --git a/thunarx/thunarx-property-page.c b/thunarx/thunarx-property-page.c
index 97bf5fc3..952c5903 100644
--- a/thunarx/thunarx-property-page.c
+++ b/thunarx/thunarx-property-page.c
@@ -29,8 +29,6 @@
-#define THUNARX_PROPERTY_PAGE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), THUNARX_TYPE_PROPERTY_PAGE, ThunarxPropertyPagePrivate))
-
/**
* SECTION: thunarx-property-page
* @short_description: The base class for pages added to the properties dialog
@@ -85,7 +83,7 @@ struct _ThunarxPropertyPagePrivate
-G_DEFINE_TYPE (ThunarxPropertyPage, thunarx_property_page, GTK_TYPE_BIN)
+G_DEFINE_TYPE_WITH_PRIVATE (ThunarxPropertyPage, thunarx_property_page, GTK_TYPE_BIN)
@@ -95,9 +93,6 @@ thunarx_property_page_class_init (ThunarxPropertyPageClass *klass)
GtkWidgetClass *gtkwidget_class;
GObjectClass *gobject_class;
- /* add our private data to the class type */
- g_type_class_add_private (klass, sizeof (ThunarxPropertyPagePrivate));
-
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = thunarx_property_page_get_property;
gobject_class->set_property = thunarx_property_page_set_property;
@@ -137,7 +132,7 @@ thunarx_property_page_class_init (ThunarxPropertyPageClass *klass)
static void
thunarx_property_page_init (ThunarxPropertyPage *property_page)
{
- property_page->priv = THUNARX_PROPERTY_PAGE_GET_PRIVATE (property_page);
+ property_page->priv = thunarx_property_page_get_instance_private (property_page);
}
diff --git a/thunarx/thunarx-provider-plugin.c b/thunarx/thunarx-provider-plugin.c
index a1d3abfb..ef2a197f 100644
--- a/thunarx/thunarx-provider-plugin.c
+++ b/thunarx/thunarx-provider-plugin.c
@@ -53,7 +53,7 @@ thunarx_provider_plugin_get_type (void)
type = g_type_register_static_simple (G_TYPE_INTERFACE,
I_("ThunarxProviderPlugin"),
sizeof (ThunarxProviderPluginIface),
- (GClassInitFunc) thunarx_provider_plugin_class_init,
+ (GClassInitFunc) (void (*)(void)) thunarx_provider_plugin_class_init,
0,
NULL,
0);
diff --git a/thunarx/thunarx-renamer.c b/thunarx/thunarx-renamer.c
index 715dbd39..34094e0e 100644
--- a/thunarx/thunarx-renamer.c
+++ b/thunarx/thunarx-renamer.c
@@ -29,10 +29,6 @@
-#define THUNARX_RENAMER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), THUNARX_TYPE_RENAMER, ThunarxRenamerPrivate))
-
-
-
/* Property identifiers */
enum
{
@@ -114,7 +110,7 @@ static guint renamer_signals[LAST_SIGNAL];
-G_DEFINE_ABSTRACT_TYPE (ThunarxRenamer, thunarx_renamer, GTK_TYPE_BOX)
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ThunarxRenamer, thunarx_renamer, GTK_TYPE_BOX)
@@ -123,9 +119,6 @@ thunarx_renamer_class_init (ThunarxRenamerClass *klass)
{
GObjectClass *gobject_class;
- /* add private data */
- g_type_class_add_private (klass, sizeof (ThunarxRenamerPrivate));
-
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = thunarx_renamer_finalize;
gobject_class->constructor = thunarx_renamer_constructor;
@@ -200,7 +193,7 @@ static void
thunarx_renamer_init (ThunarxRenamer *renamer)
{
/* grab a pointer on the private data */
- renamer->priv = THUNARX_RENAMER_GET_PRIVATE (renamer);
+ renamer->priv = thunarx_renamer_get_instance_private (renamer);
/* initialize the GtkBox to sane defaults */
gtk_orientable_set_orientation (GTK_ORIENTABLE (renamer), GTK_ORIENTATION_VERTICAL);
diff --git a/thunarx/thunarx.h b/thunarx/thunarx.h
index 192bf9a7..e0d6089a 100644
--- a/thunarx/thunarx.h
+++ b/thunarx/thunarx.h
@@ -69,12 +69,12 @@ type_name##_register_type (ThunarxProviderPlugin *thunarx_define_type_plugin) \
sizeof (TypeName##Class), \
NULL, \
NULL, \
- (GClassInitFunc) type_name##_class_intern_init, \
+ (GClassInitFunc) (void (*)(void)) type_name##_class_intern_init, \
NULL, \
NULL, \
sizeof (TypeName), \
0, \
- (GInstanceInitFunc) type_name##_init, \
+ (GInstanceInitFunc) (void (*)(void)) type_name##_init, \
NULL, \
}; \
thunarx_define_type_id = thunarx_provider_plugin_register_type (thunarx_define_type_plugin, TYPE_PARENT, \
@@ -87,7 +87,7 @@ type_name##_register_type (ThunarxProviderPlugin *thunarx_define_type_plugin) \
{ \
static const GInterfaceInfo thunarx_implement_interface_info = \
{ \
- (GInterfaceInitFunc) iface_init \
+ .interface_init = (GInterfaceInitFunc) (void (*)(void)) iface_init \
}; \
thunarx_provider_plugin_add_interface (thunarx_define_type_plugin, thunarx_define_type_id, TYPE_IFACE, &thunarx_implement_interface_info); \
}
--- End Message ---