Merge lp:~noskcaj/ubuntu/vivid/thunar/1.6.4 into lp:ubuntu/vivid/thunar
- Vivid (15.04)
- 1.6.4
- Merge into vivid
Proposed by
Jackson Doak
on 2015-01-04
| Status: | Needs review |
|---|---|
| Proposed branch: | lp:~noskcaj/ubuntu/vivid/thunar/1.6.4 |
| Merge into: | lp:ubuntu/vivid/thunar |
| Diff against target: |
212897 lines (+58226/-66350) 175 files modified
.pc/02_fix-default-application-selection.patch/thunar/thunar-file.c (+0/-4064) .pc/applied-patches (+0/-5) .pc/git-force-toolbr-icons.patch/thunar/thunar-window.c (+0/-3846) .pc/git-save-keyboard-shortcuts.patch/thunar/thunar-application.c (+0/-2067) .pc/git-xfdesktop-4.11.patch/plugins/thunar-wallpaper/twp-provider.c (+0/-307) .pc/gtk3-bookmarks.patch/thunar/thunar-gio-extensions.c (+0/-587) .pc/gtk3-bookmarks.patch/thunar/thunar-shortcuts-model.c (+0/-2214) .pc/gtk3-bookmarks.patch/thunar/thunar-util.c (+0/-485) .pc/menu-icon-tweaks.patch/thunar/thunar-standard-view.c (+9/-2) .pc/menu-icon-tweaks.patch/thunar/thunar-tree-view.c (+1/-0) .pc/menu-icon-tweaks.patch/thunar/thunar-window.c (+1/-0) ChangeLog (+2473/-0) INSTALL (+3/-3) Makefile.am (+26/-3) Makefile.in (+147/-41) NEWS (+29/-0) aclocal.m4 (+289/-154) config.guess (+99/-214) config.h.in (+0/-3) config.sub (+33/-24) configure (+431/-285) configure.ac (+4/-4) debian/changelog (+10/-0) debian/patches/0001-Don-t-copy-templates-but-create-them-bug-8312.patch (+0/-256) debian/patches/02_fix-default-application-selection.patch (+0/-39) debian/patches/git-force-toolbr-icons.patch (+0/-18) debian/patches/git-save-keyboard-shortcuts.patch (+0/-138) debian/patches/git-xfdesktop-4.11.patch (+0/-188) debian/patches/gtk3-bookmarks.patch (+0/-80) debian/patches/series (+0/-5) debian/thunar.install (+2/-0) depcomp (+2/-1) docs/Makefile.am (+1/-2) docs/Makefile.in (+53/-26) docs/README.thunarrc (+0/-253) docs/Thunar.1 (+2/-2) docs/design/Makefile.in (+46/-17) docs/papers/Makefile.in (+46/-17) docs/reference/Makefile.in (+52/-24) docs/reference/thunarx/Makefile.am (+2/-1) docs/reference/thunarx/Makefile.in (+134/-75) docs/reference/thunarx/html/ThunarxFileInfo.html (+798/-571) docs/reference/thunarx/html/ThunarxMenuProvider.html (+311/-243) docs/reference/thunarx/html/ThunarxPreferencesProvider.html (+131/-97) docs/reference/thunarx/html/ThunarxPropertyPage.html (+329/-227) docs/reference/thunarx/html/ThunarxPropertyPageProvider.html (+148/-115) docs/reference/thunarx/html/ThunarxProviderFactory.html (+125/-102) docs/reference/thunarx/html/ThunarxProviderPlugin.html (+654/-490) docs/reference/thunarx/html/ThunarxRenamer.html (+635/-475) docs/reference/thunarx/html/ThunarxRenamerProvider.html (+122/-95) docs/reference/thunarx/html/index.html (+4/-4) docs/reference/thunarx/html/index.sgml (+70/-40) docs/reference/thunarx/html/ix01.html (+109/-109) docs/reference/thunarx/html/style.css (+317/-107) docs/reference/thunarx/html/thunarx-Variables-and-functions-to-check-the-library-version.html (+208/-170) docs/reference/thunarx/html/thunarx-abstraction-layer.html (+9/-9) docs/reference/thunarx/html/thunarx-fundamentals.html (+9/-9) docs/reference/thunarx/html/thunarx-overview.html (+9/-9) docs/reference/thunarx/html/thunarx-providers.html (+9/-9) docs/reference/thunarx/html/thunarx-using-extensions.html (+9/-9) docs/reference/thunarx/html/thunarx-writing-extensions-advanced-topics.html (+11/-11) docs/reference/thunarx/html/thunarx-writing-extensions-getting-started.html (+10/-10) docs/reference/thunarx/html/thunarx-writing-extensions.html (+13/-13) docs/reference/thunarx/html/thunarx.devhelp2 (+58/-58) docs/reference/thunarx/version.xml (+1/-1) examples/Makefile.in (+52/-24) examples/tex-open-terminal/Makefile.in (+49/-19) gtk-doc.make (+77/-42) icons/128x128/Makefile.in (+46/-17) icons/16x16/Makefile.in (+46/-17) icons/24x24/Makefile.in (+46/-17) icons/48x48/Makefile.in (+46/-17) icons/64x64/Makefile.in (+46/-17) icons/Makefile.in (+52/-24) icons/scalable/Makefile.in (+46/-17) ltmain.sh (+19/-13) missing (+2/-2) org.xfce.thunar.policy.in.in (+37/-0) pixmaps/Makefile.in (+46/-17) plugins/Makefile.in (+52/-24) plugins/thunar-apr/Makefile.in (+49/-19) plugins/thunar-sbr/Makefile.in (+49/-19) plugins/thunar-sendto-email/Makefile.in (+49/-19) plugins/thunar-tpa/Makefile.in (+49/-19) plugins/thunar-tpa/thunar-tpa.c (+9/-11) plugins/thunar-uca/Makefile.in (+49/-19) plugins/thunar-wallpaper/Makefile.in (+49/-19) po/POTFILES.in (+2/-0) po/ar.po (+511/-807) po/ast.po (+938/-1327) po/be.po (+768/-1215) po/bg.po (+590/-885) po/bn.po (+602/-854) po/ca.po (+322/-741) po/cs.po (+632/-1066) po/da.po (+520/-901) po/de.po (+683/-1106) po/el.po (+717/-984) po/en_AU.po (+3597/-0) po/en_GB.po (+544/-927) po/eo.po (+666/-1129) po/es.po (+478/-670) po/et.po (+984/-1409) po/eu.po (+533/-918) po/fi.po (+618/-879) po/fr.po (+723/-1132) po/gl.po (+617/-1057) po/he.po (+394/-724) po/hr.po (+552/-658) po/hu.po (+417/-570) po/id.po (+299/-685) po/is.po (+939/-1426) po/it.po (+598/-1088) po/ja.po (+469/-585) po/kk.po (+436/-791) po/ko.po (+486/-523) po/lt.po (+613/-875) po/lv.po (+621/-1034) po/ms.po (+3563/-0) po/nb.po (+632/-1032) po/nl.po (+359/-784) po/nn.po (+364/-772) po/oc.po (+3591/-0) po/pa.po (+621/-898) po/pl.po (+557/-967) po/pt.po (+541/-758) po/pt_BR.po (+607/-1009) po/ro.po (+539/-771) po/ru.po (+328/-504) po/sk.po (+642/-1058) po/sq.po (+646/-1072) po/sr.po (+577/-765) po/sv.po (+717/-1142) po/te.po (+720/-834) po/th.po (+3564/-0) po/tr.po (+749/-1141) po/ug.po (+577/-816) po/uk.po (+542/-903) po/ur.po (+645/-1036) po/ur_PK.po (+645/-1036) po/vi.po (+1027/-1225) po/zh_CN.po (+543/-675) po/zh_HK.po (+3551/-0) po/zh_TW.po (+599/-896) test-driver (+16/-4) thunar.appdata.xml.in (+24/-0) thunar/Makefile.in (+49/-19) thunar/main.c (+4/-4) thunar/thunar-create-dialog.c (+1/-1) thunar/thunar-dialogs.c (+6/-4) thunar/thunar-dnd.c (+1/-1) thunar/thunar-file.c (+135/-50) thunar/thunar-file.h (+141/-139) thunar/thunar-folder.c (+7/-2) thunar/thunar-gio-extensions.c (+14/-7) thunar/thunar-history.c (+2/-0) thunar/thunar-icon-renderer.c (+43/-2) thunar/thunar-io-jobs-util.c (+39/-39) thunar/thunar-list-model.c (+85/-6) thunar/thunar-preferences-dialog.c (+7/-1) thunar/thunar-preferences.c (+13/-0) thunar/thunar-properties-dialog.c (+2/-4) thunar/thunar-renamer-model.c (+3/-4) thunar/thunar-session-client.c (+1/-0) thunar/thunar-size-label.c (+22/-9) thunar/thunar-standard-view.c (+9/-2) thunar/thunar-text-renderer.c (+2/-1) thunar/thunar-thumbnail-cache.c (+128/-128) thunar/thunar-thumbnailer.c (+2/-0) thunar/thunar-transfer-job.c (+30/-17) thunar/thunar-tree-view.c (+1/-0) thunar/thunar-util.c (+112/-0) thunar/thunar-util.h (+2/-0) thunarx/Makefile.in (+50/-20) thunarx/thunarx-config.h (+1/-1) |
| To merge this branch: | bzr merge lp:~noskcaj/ubuntu/vivid/thunar/1.6.4 |
| Related bugs: |
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| Daniel Holbach | 2015-01-04 | Needs Fixing on 2015-01-06 | |
|
Review via email:
|
|||
Commit Message
Description of the Change
New upstream release. Xubuntu 15.04
To post a comment you must log in.
lp:~noskcaj/ubuntu/vivid/thunar/1.6.4
updated
on 2015-01-04
- 100. By Jackson Doak on 2015-01-04
-
Install appdata and polkit files in thunar deb
lp:~noskcaj/ubuntu/vivid/thunar/1.6.4
updated
on 2015-01-06
- 101. By Jackson Doak on 2015-01-06
-
02_fix-
default- application- selection. patch, fixed upstream
Unmerged revisions
- 101. By Jackson Doak on 2015-01-06
-
02_fix-
default- application- selection. patch, fixed upstream - 100. By Jackson Doak on 2015-01-04
-
Install appdata and polkit files in thunar deb
- 99. By Jackson Doak on 2015-01-04
-
* New upstream release.
* Dropped patches: git-force-toolbr- icons.patch, gtk3-bookmarks. patch,
git-save-keyboard- shortcuts. patch, git-xfdesktop- 4.11.patch,
02_fix-default- application- selection. patch
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
| 1 | === removed directory '.pc/02_fix-default-application-selection.patch' |
| 2 | === removed directory '.pc/02_fix-default-application-selection.patch/thunar' |
| 3 | === removed file '.pc/02_fix-default-application-selection.patch/thunar/thunar-file.c' |
| 4 | --- .pc/02_fix-default-application-selection.patch/thunar/thunar-file.c 2014-10-30 11:00:02 +0000 |
| 5 | +++ .pc/02_fix-default-application-selection.patch/thunar/thunar-file.c 1970-01-01 00:00:00 +0000 |
| 6 | @@ -1,4064 +0,0 @@ |
| 7 | -/* vi:set et ai sw=2 sts=2 ts=2: */ |
| 8 | -/*- |
| 9 | - * Copyright (c) 2005-2007 Benedikt Meurer <benny@xfce.org> |
| 10 | - * Copyright (c) 2009-2011 Jannis Pohlmann <jannis@xfce.org> |
| 11 | - * |
| 12 | - * This program is free software; you can redistribute it and/or |
| 13 | - * modify it under the terms of the GNU General Public License as |
| 14 | - * published by the Free Software Foundation; either version 2 of |
| 15 | - * the License, or (at your option) any later version. |
| 16 | - * |
| 17 | - * This program is distributed in the hope that it will be useful, |
| 18 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 19 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 20 | - * GNU General Public License for more details. |
| 21 | - * |
| 22 | - * You should have received a copy of the GNU General Public |
| 23 | - * License along with this program; if not, write to the Free |
| 24 | - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 25 | - * Boston, MA 02110-1301, USA. |
| 26 | - */ |
| 27 | - |
| 28 | -#ifdef HAVE_CONFIG_H |
| 29 | -#include <config.h> |
| 30 | -#endif |
| 31 | - |
| 32 | -#ifdef HAVE_SYS_TYPES_H |
| 33 | -#include <sys/types.h> |
| 34 | -#endif |
| 35 | - |
| 36 | -#ifdef HAVE_SYS_STAT_H |
| 37 | -#include <sys/stat.h> |
| 38 | -#endif |
| 39 | - |
| 40 | -#ifdef HAVE_ERRNO_H |
| 41 | -#include <errno.h> |
| 42 | -#endif |
| 43 | -#ifdef HAVE_MEMORY_H |
| 44 | -#include <memory.h> |
| 45 | -#endif |
| 46 | -#ifdef HAVE_STDLIB_H |
| 47 | -#include <stdlib.h> |
| 48 | -#endif |
| 49 | -#ifdef HAVE_STRING_H |
| 50 | -#include <string.h> |
| 51 | -#endif |
| 52 | -#ifdef HAVE_TIME_H |
| 53 | -#include <time.h> |
| 54 | -#endif |
| 55 | -#ifdef HAVE_UNISTD_H |
| 56 | -#include <unistd.h> |
| 57 | -#endif |
| 58 | - |
| 59 | -#include <gio/gio.h> |
| 60 | -#include <libxfce4ui/libxfce4ui.h> |
| 61 | - |
| 62 | -#include <thunarx/thunarx.h> |
| 63 | - |
| 64 | -#include <thunar/thunar-application.h> |
| 65 | -#include <thunar/thunar-chooser-dialog.h> |
| 66 | -#include <thunar/thunar-exec.h> |
| 67 | -#include <thunar/thunar-file.h> |
| 68 | -#include <thunar/thunar-file-monitor.h> |
| 69 | -#include <thunar/thunar-gio-extensions.h> |
| 70 | -#include <thunar/thunar-gobject-extensions.h> |
| 71 | -#include <thunar/thunar-private.h> |
| 72 | -#include <thunar/thunar-user.h> |
| 73 | -#include <thunar/thunar-util.h> |
| 74 | -#include <thunar/thunar-dialogs.h> |
| 75 | -#include <thunar/thunar-icon-factory.h> |
| 76 | - |
| 77 | - |
| 78 | - |
| 79 | -/* Dump the file cache every X second, set to 0 to disable */ |
| 80 | -#define DUMP_FILE_CACHE 0 |
| 81 | - |
| 82 | - |
| 83 | - |
| 84 | -/* Signal identifiers */ |
| 85 | -enum |
| 86 | -{ |
| 87 | - DESTROY, |
| 88 | - LAST_SIGNAL, |
| 89 | -}; |
| 90 | - |
| 91 | - |
| 92 | - |
| 93 | -static void thunar_file_info_init (ThunarxFileInfoIface *iface); |
| 94 | -static void thunar_file_dispose (GObject *object); |
| 95 | -static void thunar_file_finalize (GObject *object); |
| 96 | -static gchar *thunar_file_info_get_name (ThunarxFileInfo *file_info); |
| 97 | -static gchar *thunar_file_info_get_uri (ThunarxFileInfo *file_info); |
| 98 | -static gchar *thunar_file_info_get_parent_uri (ThunarxFileInfo *file_info); |
| 99 | -static gchar *thunar_file_info_get_uri_scheme (ThunarxFileInfo *file_info); |
| 100 | -static gchar *thunar_file_info_get_mime_type (ThunarxFileInfo *file_info); |
| 101 | -static gboolean thunar_file_info_has_mime_type (ThunarxFileInfo *file_info, |
| 102 | - const gchar *mime_type); |
| 103 | -static gboolean thunar_file_info_is_directory (ThunarxFileInfo *file_info); |
| 104 | -static GFileInfo *thunar_file_info_get_file_info (ThunarxFileInfo *file_info); |
| 105 | -static GFileInfo *thunar_file_info_get_filesystem_info (ThunarxFileInfo *file_info); |
| 106 | -static GFile *thunar_file_info_get_location (ThunarxFileInfo *file_info); |
| 107 | -static void thunar_file_info_changed (ThunarxFileInfo *file_info); |
| 108 | -static gboolean thunar_file_denies_access_permission (const ThunarFile *file, |
| 109 | - ThunarFileMode usr_permissions, |
| 110 | - ThunarFileMode grp_permissions, |
| 111 | - ThunarFileMode oth_permissions); |
| 112 | -static void thunar_file_monitor (GFileMonitor *monitor, |
| 113 | - GFile *path, |
| 114 | - GFile *other_path, |
| 115 | - GFileMonitorEvent event_type, |
| 116 | - gpointer user_data); |
| 117 | -static gboolean thunar_file_load (ThunarFile *file, |
| 118 | - GCancellable *cancellable, |
| 119 | - GError **error); |
| 120 | -static gboolean thunar_file_is_readable (const ThunarFile *file); |
| 121 | -static gboolean thunar_file_same_filesystem (const ThunarFile *file_a, |
| 122 | - const ThunarFile *file_b); |
| 123 | - |
| 124 | - |
| 125 | - |
| 126 | -G_LOCK_DEFINE_STATIC (file_cache_mutex); |
| 127 | -G_LOCK_DEFINE_STATIC (file_content_type_mutex); |
| 128 | - |
| 129 | - |
| 130 | - |
| 131 | -static ThunarUserManager *user_manager; |
| 132 | -static GHashTable *file_cache; |
| 133 | -static guint32 effective_user_id; |
| 134 | -static GQuark thunar_file_watch_quark; |
| 135 | -static guint file_signals[LAST_SIGNAL]; |
| 136 | - |
| 137 | - |
| 138 | - |
| 139 | -#define FLAG_SET_THUMB_STATE(file,new_state) G_STMT_START{ (file)->flags = ((file)->flags & ~THUNAR_FILE_FLAG_THUMB_MASK) | (new_state); }G_STMT_END |
| 140 | -#define FLAG_GET_THUMB_STATE(file) ((file)->flags & THUNAR_FILE_FLAG_THUMB_MASK) |
| 141 | -#define FLAG_SET(file,flag) G_STMT_START{ ((file)->flags |= (flag)); }G_STMT_END |
| 142 | -#define FLAG_UNSET(file,flag) G_STMT_START{ ((file)->flags &= ~(flag)); }G_STMT_END |
| 143 | -#define FLAG_IS_SET(file,flag) (((file)->flags & (flag)) != 0) |
| 144 | - |
| 145 | -#define DEFAULT_CONTENT_TYPE "application/octet-stream" |
| 146 | - |
| 147 | - |
| 148 | - |
| 149 | -typedef enum |
| 150 | -{ |
| 151 | - THUNAR_FILE_FLAG_THUMB_MASK = 0x03, /* storage for ThunarFileThumbState */ |
| 152 | - THUNAR_FILE_FLAG_IN_DESTRUCTION = 1 << 2, /* for avoiding recursion during destroy */ |
| 153 | - THUNAR_FILE_FLAG_IS_MOUNTED = 1 << 3, /* whether this file is mounted */ |
| 154 | -} |
| 155 | -ThunarFileFlags; |
| 156 | - |
| 157 | -struct _ThunarFileClass |
| 158 | -{ |
| 159 | - GObjectClass __parent__; |
| 160 | - |
| 161 | - /* signals */ |
| 162 | - void (*destroy) (ThunarFile *file); |
| 163 | -}; |
| 164 | - |
| 165 | -struct _ThunarFile |
| 166 | -{ |
| 167 | - GObject __parent__; |
| 168 | - |
| 169 | - /* storage for the file information */ |
| 170 | - GFileInfo *info; |
| 171 | - GFileType kind; |
| 172 | - GFile *gfile; |
| 173 | - gchar *content_type; |
| 174 | - gchar *icon_name; |
| 175 | - |
| 176 | - gchar *custom_icon_name; |
| 177 | - gchar *display_name; |
| 178 | - gchar *basename; |
| 179 | - gchar *thumbnail_path; |
| 180 | - |
| 181 | - /* sorting */ |
| 182 | - gchar *collate_key; |
| 183 | - gchar *collate_key_nocase; |
| 184 | - |
| 185 | - /* flags for thumbnail state etc */ |
| 186 | - ThunarFileFlags flags; |
| 187 | -}; |
| 188 | - |
| 189 | -typedef struct |
| 190 | -{ |
| 191 | - GFileMonitor *monitor; |
| 192 | - guint watch_count; |
| 193 | -} |
| 194 | -ThunarFileWatch; |
| 195 | - |
| 196 | -typedef struct |
| 197 | -{ |
| 198 | - ThunarFileGetFunc func; |
| 199 | - gpointer user_data; |
| 200 | - GCancellable *cancellable; |
| 201 | -} |
| 202 | -ThunarFileGetData; |
| 203 | - |
| 204 | -static struct |
| 205 | -{ |
| 206 | - GUserDirectory type; |
| 207 | - const gchar *icon_name; |
| 208 | -} |
| 209 | -thunar_file_dirs[] = |
| 210 | -{ |
| 211 | - { G_USER_DIRECTORY_DESKTOP, "user-desktop" }, |
| 212 | - { G_USER_DIRECTORY_DOCUMENTS, "folder-documents" }, |
| 213 | - { G_USER_DIRECTORY_DOWNLOAD, "folder-download" }, |
| 214 | - { G_USER_DIRECTORY_MUSIC, "folder-music" }, |
| 215 | - { G_USER_DIRECTORY_PICTURES, "folder-pictures" }, |
| 216 | - { G_USER_DIRECTORY_PUBLIC_SHARE, "folder-publicshare" }, |
| 217 | - { G_USER_DIRECTORY_TEMPLATES, "folder-templates" }, |
| 218 | - { G_USER_DIRECTORY_VIDEOS, "folder-videos" } |
| 219 | -}; |
| 220 | - |
| 221 | - |
| 222 | - |
| 223 | -G_DEFINE_TYPE_WITH_CODE (ThunarFile, thunar_file, G_TYPE_OBJECT, |
| 224 | - G_IMPLEMENT_INTERFACE (THUNARX_TYPE_FILE_INFO, thunar_file_info_init)) |
| 225 | - |
| 226 | - |
| 227 | - |
| 228 | -#ifdef G_ENABLE_DEBUG |
| 229 | -#ifdef HAVE_ATEXIT |
| 230 | -static gboolean thunar_file_atexit_registered = FALSE; |
| 231 | - |
| 232 | - |
| 233 | - |
| 234 | -static void |
| 235 | -thunar_file_atexit_foreach (gpointer key, |
| 236 | - gpointer value, |
| 237 | - gpointer user_data) |
| 238 | -{ |
| 239 | - gchar *uri; |
| 240 | - |
| 241 | - uri = g_file_get_uri (key); |
| 242 | - g_print ("--> %s (%u)\n", uri, G_OBJECT (value)->ref_count); |
| 243 | - if (G_OBJECT (key)->ref_count > 2) |
| 244 | - g_print (" GFile (%u)\n", G_OBJECT (key)->ref_count - 2); |
| 245 | - g_free (uri); |
| 246 | -} |
| 247 | - |
| 248 | - |
| 249 | - |
| 250 | -static void |
| 251 | -thunar_file_atexit (void) |
| 252 | -{ |
| 253 | - G_LOCK (file_cache_mutex); |
| 254 | - |
| 255 | - if (file_cache == NULL || g_hash_table_size (file_cache) == 0) |
| 256 | - { |
| 257 | - G_UNLOCK (file_cache_mutex); |
| 258 | - return; |
| 259 | - } |
| 260 | - |
| 261 | - g_print ("--- Leaked a total of %u ThunarFile objects:\n", |
| 262 | - g_hash_table_size (file_cache)); |
| 263 | - |
| 264 | - g_hash_table_foreach (file_cache, thunar_file_atexit_foreach, NULL); |
| 265 | - |
| 266 | - g_print ("\n"); |
| 267 | - |
| 268 | - G_UNLOCK (file_cache_mutex); |
| 269 | -} |
| 270 | -#endif |
| 271 | -#endif |
| 272 | - |
| 273 | - |
| 274 | - |
| 275 | -#if DUMP_FILE_CACHE |
| 276 | -static void |
| 277 | -thunar_file_cache_dump_foreach (gpointer gfile, |
| 278 | - gpointer value, |
| 279 | - gpointer user_data) |
| 280 | -{ |
| 281 | - gchar *name; |
| 282 | - |
| 283 | - name = g_file_get_parse_name (G_FILE (gfile)); |
| 284 | - g_print (" %s (%u)\n", name, G_OBJECT (value)->ref_count); |
| 285 | - g_free (name); |
| 286 | -} |
| 287 | - |
| 288 | - |
| 289 | - |
| 290 | -static gboolean |
| 291 | -thunar_file_cache_dump (gpointer user_data) |
| 292 | -{ |
| 293 | - G_LOCK (file_cache_mutex); |
| 294 | - |
| 295 | - if (file_cache != NULL) |
| 296 | - { |
| 297 | - g_print ("--- %d ThunarFile objects in cache:\n", |
| 298 | - g_hash_table_size (file_cache)); |
| 299 | - |
| 300 | - g_hash_table_foreach (file_cache, thunar_file_cache_dump_foreach, NULL); |
| 301 | - |
| 302 | - g_print ("\n"); |
| 303 | - } |
| 304 | - |
| 305 | - G_UNLOCK (file_cache_mutex); |
| 306 | - |
| 307 | - return TRUE; |
| 308 | -} |
| 309 | -#endif |
| 310 | - |
| 311 | - |
| 312 | - |
| 313 | -static void |
| 314 | -thunar_file_class_init (ThunarFileClass *klass) |
| 315 | -{ |
| 316 | - GObjectClass *gobject_class; |
| 317 | - |
| 318 | -#ifdef G_ENABLE_DEBUG |
| 319 | -#ifdef HAVE_ATEXIT |
| 320 | - if (G_UNLIKELY (!thunar_file_atexit_registered)) |
| 321 | - { |
| 322 | - atexit ((void (*)(void)) thunar_file_atexit); |
| 323 | - thunar_file_atexit_registered = TRUE; |
| 324 | - } |
| 325 | -#endif |
| 326 | -#endif |
| 327 | - |
| 328 | -#if DUMP_FILE_CACHE |
| 329 | - g_timeout_add_seconds (DUMP_FILE_CACHE, thunar_file_cache_dump, NULL); |
| 330 | -#endif |
| 331 | - |
| 332 | - /* pre-allocate the required quarks */ |
| 333 | - thunar_file_watch_quark = g_quark_from_static_string ("thunar-file-watch"); |
| 334 | - |
| 335 | - /* grab a reference on the user manager */ |
| 336 | - user_manager = thunar_user_manager_get_default (); |
| 337 | - |
| 338 | - /* determine the effective user id of the process */ |
| 339 | - effective_user_id = geteuid (); |
| 340 | - |
| 341 | - gobject_class = G_OBJECT_CLASS (klass); |
| 342 | - gobject_class->dispose = thunar_file_dispose; |
| 343 | - gobject_class->finalize = thunar_file_finalize; |
| 344 | - |
| 345 | - /** |
| 346 | - * ThunarFile::destroy: |
| 347 | - * @file : the #ThunarFile instance. |
| 348 | - * |
| 349 | - * Emitted when the system notices that the @file |
| 350 | - * was destroyed. |
| 351 | - **/ |
| 352 | - file_signals[DESTROY] = |
| 353 | - g_signal_new (I_("destroy"), |
| 354 | - G_TYPE_FROM_CLASS (klass), |
| 355 | - G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, |
| 356 | - G_STRUCT_OFFSET (ThunarFileClass, destroy), |
| 357 | - NULL, NULL, |
| 358 | - g_cclosure_marshal_VOID__VOID, |
| 359 | - G_TYPE_NONE, 0); |
| 360 | -} |
| 361 | - |
| 362 | - |
| 363 | - |
| 364 | -static void |
| 365 | -thunar_file_init (ThunarFile *file) |
| 366 | -{ |
| 367 | -} |
| 368 | - |
| 369 | - |
| 370 | - |
| 371 | -static void |
| 372 | -thunar_file_info_init (ThunarxFileInfoIface *iface) |
| 373 | -{ |
| 374 | - iface->get_name = thunar_file_info_get_name; |
| 375 | - iface->get_uri = thunar_file_info_get_uri; |
| 376 | - iface->get_parent_uri = thunar_file_info_get_parent_uri; |
| 377 | - iface->get_uri_scheme = thunar_file_info_get_uri_scheme; |
| 378 | - iface->get_mime_type = thunar_file_info_get_mime_type; |
| 379 | - iface->has_mime_type = thunar_file_info_has_mime_type; |
| 380 | - iface->is_directory = thunar_file_info_is_directory; |
| 381 | - iface->get_file_info = thunar_file_info_get_file_info; |
| 382 | - iface->get_filesystem_info = thunar_file_info_get_filesystem_info; |
| 383 | - iface->get_location = thunar_file_info_get_location; |
| 384 | - iface->changed = thunar_file_info_changed; |
| 385 | -} |
| 386 | - |
| 387 | - |
| 388 | - |
| 389 | -static void |
| 390 | -thunar_file_dispose (GObject *object) |
| 391 | -{ |
| 392 | - ThunarFile *file = THUNAR_FILE (object); |
| 393 | - |
| 394 | - /* check that we don't recurse here */ |
| 395 | - if (!FLAG_IS_SET (file, THUNAR_FILE_FLAG_IN_DESTRUCTION)) |
| 396 | - { |
| 397 | - /* emit the "destroy" signal */ |
| 398 | - FLAG_SET (file, THUNAR_FILE_FLAG_IN_DESTRUCTION); |
| 399 | - g_signal_emit (object, file_signals[DESTROY], 0); |
| 400 | - FLAG_UNSET (file, THUNAR_FILE_FLAG_IN_DESTRUCTION); |
| 401 | - } |
| 402 | - |
| 403 | - (*G_OBJECT_CLASS (thunar_file_parent_class)->dispose) (object); |
| 404 | -} |
| 405 | - |
| 406 | - |
| 407 | - |
| 408 | -static void |
| 409 | -thunar_file_finalize (GObject *object) |
| 410 | -{ |
| 411 | - ThunarFile *file = THUNAR_FILE (object); |
| 412 | - |
| 413 | - /* verify that nobody's watching the file anymore */ |
| 414 | -#ifdef G_ENABLE_DEBUG |
| 415 | - ThunarFileWatch *file_watch = g_object_get_qdata (G_OBJECT (file), thunar_file_watch_quark); |
| 416 | - if (file_watch != NULL) |
| 417 | - { |
| 418 | - g_error ("Attempt to finalize a ThunarFile, which has an active " |
| 419 | - "watch count of %d", file_watch->watch_count); |
| 420 | - } |
| 421 | -#endif |
| 422 | - |
| 423 | - /* drop the entry from the cache */ |
| 424 | - G_LOCK (file_cache_mutex); |
| 425 | - g_hash_table_remove (file_cache, file->gfile); |
| 426 | - G_UNLOCK (file_cache_mutex); |
| 427 | - |
| 428 | - /* release file info */ |
| 429 | - if (file->info != NULL) |
| 430 | - g_object_unref (file->info); |
| 431 | - |
| 432 | - /* free the custom icon name */ |
| 433 | - g_free (file->custom_icon_name); |
| 434 | - |
| 435 | - /* content type info */ |
| 436 | - g_free (file->content_type); |
| 437 | - g_free (file->icon_name); |
| 438 | - |
| 439 | - /* free display name and basename */ |
| 440 | - g_free (file->display_name); |
| 441 | - g_free (file->basename); |
| 442 | - |
| 443 | - /* free collate keys */ |
| 444 | - if (file->collate_key_nocase != file->collate_key) |
| 445 | - g_free (file->collate_key_nocase); |
| 446 | - g_free (file->collate_key); |
| 447 | - |
| 448 | - /* free the thumbnail path */ |
| 449 | - g_free (file->thumbnail_path); |
| 450 | - |
| 451 | - /* release file */ |
| 452 | - g_object_unref (file->gfile); |
| 453 | - |
| 454 | - (*G_OBJECT_CLASS (thunar_file_parent_class)->finalize) (object); |
| 455 | -} |
| 456 | - |
| 457 | - |
| 458 | - |
| 459 | -static gchar * |
| 460 | -thunar_file_info_get_name (ThunarxFileInfo *file_info) |
| 461 | -{ |
| 462 | - return g_strdup (thunar_file_get_basename (THUNAR_FILE (file_info))); |
| 463 | -} |
| 464 | - |
| 465 | - |
| 466 | - |
| 467 | -static gchar* |
| 468 | -thunar_file_info_get_uri (ThunarxFileInfo *file_info) |
| 469 | -{ |
| 470 | - return thunar_file_dup_uri (THUNAR_FILE (file_info)); |
| 471 | -} |
| 472 | - |
| 473 | - |
| 474 | - |
| 475 | -static gchar* |
| 476 | -thunar_file_info_get_parent_uri (ThunarxFileInfo *file_info) |
| 477 | -{ |
| 478 | - GFile *parent; |
| 479 | - gchar *uri = NULL; |
| 480 | - |
| 481 | - parent = g_file_get_parent (THUNAR_FILE (file_info)->gfile); |
| 482 | - if (G_LIKELY (parent != NULL)) |
| 483 | - { |
| 484 | - uri = g_file_get_uri (parent); |
| 485 | - g_object_unref (parent); |
| 486 | - } |
| 487 | - |
| 488 | - return uri; |
| 489 | -} |
| 490 | - |
| 491 | - |
| 492 | - |
| 493 | -static gchar* |
| 494 | -thunar_file_info_get_uri_scheme (ThunarxFileInfo *file_info) |
| 495 | -{ |
| 496 | - return g_file_get_uri_scheme (THUNAR_FILE (file_info)->gfile); |
| 497 | -} |
| 498 | - |
| 499 | - |
| 500 | - |
| 501 | -static gchar* |
| 502 | -thunar_file_info_get_mime_type (ThunarxFileInfo *file_info) |
| 503 | -{ |
| 504 | - return g_strdup (thunar_file_get_content_type (THUNAR_FILE (file_info))); |
| 505 | -} |
| 506 | - |
| 507 | - |
| 508 | - |
| 509 | -static gboolean |
| 510 | -thunar_file_info_has_mime_type (ThunarxFileInfo *file_info, |
| 511 | - const gchar *mime_type) |
| 512 | -{ |
| 513 | - if (THUNAR_FILE (file_info)->info == NULL) |
| 514 | - return FALSE; |
| 515 | - |
| 516 | - return g_content_type_is_a (thunar_file_get_content_type (THUNAR_FILE (file_info)), mime_type); |
| 517 | -} |
| 518 | - |
| 519 | - |
| 520 | - |
| 521 | -static gboolean |
| 522 | -thunar_file_info_is_directory (ThunarxFileInfo *file_info) |
| 523 | -{ |
| 524 | - return thunar_file_is_directory (THUNAR_FILE (file_info)); |
| 525 | -} |
| 526 | - |
| 527 | - |
| 528 | - |
| 529 | -static GFileInfo * |
| 530 | -thunar_file_info_get_file_info (ThunarxFileInfo *file_info) |
| 531 | -{ |
| 532 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file_info), NULL); |
| 533 | - |
| 534 | - if (THUNAR_FILE (file_info)->info != NULL) |
| 535 | - return g_object_ref (THUNAR_FILE (file_info)->info); |
| 536 | - else |
| 537 | - return NULL; |
| 538 | -} |
| 539 | - |
| 540 | - |
| 541 | - |
| 542 | -static GFileInfo * |
| 543 | -thunar_file_info_get_filesystem_info (ThunarxFileInfo *file_info) |
| 544 | -{ |
| 545 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file_info), NULL); |
| 546 | - |
| 547 | - return g_file_query_filesystem_info (THUNAR_FILE (file_info)->gfile, |
| 548 | - THUNARX_FILESYSTEM_INFO_NAMESPACE, |
| 549 | - NULL, NULL); |
| 550 | -} |
| 551 | - |
| 552 | - |
| 553 | - |
| 554 | -static GFile * |
| 555 | -thunar_file_info_get_location (ThunarxFileInfo *file_info) |
| 556 | -{ |
| 557 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file_info), NULL); |
| 558 | - return g_object_ref (THUNAR_FILE (file_info)->gfile); |
| 559 | -} |
| 560 | - |
| 561 | - |
| 562 | - |
| 563 | -static void |
| 564 | -thunar_file_info_changed (ThunarxFileInfo *file_info) |
| 565 | -{ |
| 566 | - ThunarFile *file = THUNAR_FILE (file_info); |
| 567 | - |
| 568 | - _thunar_return_if_fail (THUNAR_IS_FILE (file_info)); |
| 569 | - |
| 570 | - /* set the new thumbnail state manually, so we only emit file |
| 571 | - * changed once */ |
| 572 | - FLAG_SET_THUMB_STATE (file, THUNAR_FILE_THUMB_STATE_UNKNOWN); |
| 573 | - |
| 574 | - /* tell the file monitor that this file changed */ |
| 575 | - thunar_file_monitor_file_changed (file); |
| 576 | -} |
| 577 | - |
| 578 | - |
| 579 | - |
| 580 | -static gboolean |
| 581 | -thunar_file_denies_access_permission (const ThunarFile *file, |
| 582 | - ThunarFileMode usr_permissions, |
| 583 | - ThunarFileMode grp_permissions, |
| 584 | - ThunarFileMode oth_permissions) |
| 585 | -{ |
| 586 | - ThunarFileMode mode; |
| 587 | - ThunarGroup *group; |
| 588 | - ThunarUser *user; |
| 589 | - gboolean result; |
| 590 | - GList *groups; |
| 591 | - GList *lp; |
| 592 | - |
| 593 | - /* query the file mode */ |
| 594 | - mode = thunar_file_get_mode (file); |
| 595 | - |
| 596 | - /* query the owner of the file, if we cannot determine |
| 597 | - * the owner, we can't tell if we're denied to access |
| 598 | - * the file, so we simply return FALSE then. |
| 599 | - */ |
| 600 | - user = thunar_file_get_user (file); |
| 601 | - if (G_UNLIKELY (user == NULL)) |
| 602 | - return FALSE; |
| 603 | - |
| 604 | - /* root is allowed to do everything */ |
| 605 | - if (G_UNLIKELY (effective_user_id == 0)) |
| 606 | - return FALSE; |
| 607 | - |
| 608 | - if (thunar_user_is_me (user)) |
| 609 | - { |
| 610 | - /* we're the owner, so the usr permissions must be granted */ |
| 611 | - result = ((mode & usr_permissions) == 0); |
| 612 | - |
| 613 | - /* release the user */ |
| 614 | - g_object_unref (G_OBJECT (user)); |
| 615 | - } |
| 616 | - else |
| 617 | - { |
| 618 | - group = thunar_file_get_group (file); |
| 619 | - if (G_LIKELY (group != NULL)) |
| 620 | - { |
| 621 | - /* release the file owner */ |
| 622 | - g_object_unref (G_OBJECT (user)); |
| 623 | - |
| 624 | - /* determine the effective user */ |
| 625 | - user = thunar_user_manager_get_user_by_id (user_manager, effective_user_id); |
| 626 | - if (G_LIKELY (user != NULL)) |
| 627 | - { |
| 628 | - /* check the group permissions */ |
| 629 | - groups = thunar_user_get_groups (user); |
| 630 | - for (lp = groups; lp != NULL; lp = lp->next) |
| 631 | - if (THUNAR_GROUP (lp->data) == group) |
| 632 | - { |
| 633 | - g_object_unref (G_OBJECT (user)); |
| 634 | - g_object_unref (G_OBJECT (group)); |
| 635 | - return ((mode & grp_permissions) == 0); |
| 636 | - } |
| 637 | - |
| 638 | - /* release the effective user */ |
| 639 | - g_object_unref (G_OBJECT (user)); |
| 640 | - } |
| 641 | - |
| 642 | - /* release the file group */ |
| 643 | - g_object_unref (G_OBJECT (group)); |
| 644 | - } |
| 645 | - |
| 646 | - /* check other permissions */ |
| 647 | - result = ((mode & oth_permissions) == 0); |
| 648 | - } |
| 649 | - |
| 650 | - return result; |
| 651 | -} |
| 652 | - |
| 653 | - |
| 654 | - |
| 655 | -static void |
| 656 | -thunar_file_monitor_update (GFile *path, |
| 657 | - GFileMonitorEvent event_type) |
| 658 | -{ |
| 659 | - ThunarFile *file; |
| 660 | - |
| 661 | - _thunar_return_if_fail (G_IS_FILE (path)); |
| 662 | - file = thunar_file_cache_lookup (path); |
| 663 | - if (G_LIKELY (file != NULL)) |
| 664 | - { |
| 665 | - switch (event_type) |
| 666 | - { |
| 667 | - case G_FILE_MONITOR_EVENT_CREATED: |
| 668 | - case G_FILE_MONITOR_EVENT_CHANGED: |
| 669 | - case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED: |
| 670 | - thunar_file_reload (file); |
| 671 | - break; |
| 672 | - |
| 673 | - case G_FILE_MONITOR_EVENT_PRE_UNMOUNT: |
| 674 | - case G_FILE_MONITOR_EVENT_DELETED: |
| 675 | - thunar_file_reload (file); |
| 676 | - break; |
| 677 | - |
| 678 | - default: |
| 679 | - break; |
| 680 | - } |
| 681 | - } |
| 682 | -} |
| 683 | - |
| 684 | - |
| 685 | - |
| 686 | -static void |
| 687 | -thunar_file_monitor (GFileMonitor *monitor, |
| 688 | - GFile *path, |
| 689 | - GFile *other_path, |
| 690 | - GFileMonitorEvent event_type, |
| 691 | - gpointer user_data) |
| 692 | -{ |
| 693 | - ThunarFile *file = THUNAR_FILE (user_data); |
| 694 | - |
| 695 | - _thunar_return_if_fail (G_IS_FILE_MONITOR (monitor)); |
| 696 | - _thunar_return_if_fail (THUNAR_IS_FILE (file)); |
| 697 | - |
| 698 | - if (G_UNLIKELY (!G_IS_FILE (path) || !g_file_equal (path, file->gfile))) |
| 699 | - return; |
| 700 | - |
| 701 | - if (G_LIKELY (G_IS_FILE (path))) |
| 702 | - thunar_file_monitor_update (path, event_type); |
| 703 | - |
| 704 | - if (G_UNLIKELY (G_IS_FILE (other_path))) |
| 705 | - thunar_file_monitor_update (other_path, event_type); |
| 706 | -} |
| 707 | - |
| 708 | - |
| 709 | - |
| 710 | -static void |
| 711 | -thunar_file_watch_destroyed (gpointer data) |
| 712 | -{ |
| 713 | - ThunarFileWatch *file_watch = data; |
| 714 | - |
| 715 | - if (G_LIKELY (file_watch->monitor != NULL)) |
| 716 | - { |
| 717 | - g_file_monitor_cancel (file_watch->monitor); |
| 718 | - g_object_unref (file_watch->monitor); |
| 719 | - } |
| 720 | - |
| 721 | - g_slice_free (ThunarFileWatch, file_watch); |
| 722 | -} |
| 723 | - |
| 724 | - |
| 725 | - |
| 726 | -static void |
| 727 | -thunar_file_watch_reconnect (ThunarFile *file) |
| 728 | -{ |
| 729 | - ThunarFileWatch *file_watch; |
| 730 | - |
| 731 | - /* recreate the monitor without changing the watch_count for file renames */ |
| 732 | - file_watch = g_object_get_qdata (G_OBJECT (file), thunar_file_watch_quark); |
| 733 | - if (file_watch != NULL) |
| 734 | - { |
| 735 | - /* reset the old monitor */ |
| 736 | - if (G_LIKELY (file_watch->monitor != NULL)) |
| 737 | - { |
| 738 | - g_file_monitor_cancel (file_watch->monitor); |
| 739 | - g_object_unref (file_watch->monitor); |
| 740 | - } |
| 741 | - |
| 742 | - /* create a file or directory monitor */ |
| 743 | - file_watch->monitor = g_file_monitor (file->gfile, G_FILE_MONITOR_WATCH_MOUNTS, NULL, NULL); |
| 744 | - if (G_LIKELY (file_watch->monitor != NULL)) |
| 745 | - { |
| 746 | - /* watch monitor for file changes */ |
| 747 | - g_signal_connect (file_watch->monitor, "changed", G_CALLBACK (thunar_file_monitor), file); |
| 748 | - } |
| 749 | - } |
| 750 | -} |
| 751 | - |
| 752 | - |
| 753 | - |
| 754 | -static void |
| 755 | -thunar_file_set_emblem_names_ready (GObject *source_object, |
| 756 | - GAsyncResult *result, |
| 757 | - gpointer user_data) |
| 758 | -{ |
| 759 | - ThunarFile *file = THUNAR_FILE (user_data); |
| 760 | - GError *error = NULL; |
| 761 | - |
| 762 | - if (!g_file_set_attributes_finish (G_FILE (source_object), result, NULL, &error)) |
| 763 | - { |
| 764 | - g_warning ("Failed to set metadata: %s", error->message); |
| 765 | - g_error_free (error); |
| 766 | - |
| 767 | - g_file_info_remove_attribute (file->info, "metadata::emblems"); |
| 768 | - } |
| 769 | - |
| 770 | - thunar_file_changed (file); |
| 771 | -} |
| 772 | - |
| 773 | - |
| 774 | - |
| 775 | -static void |
| 776 | -thunar_file_info_clear (ThunarFile *file) |
| 777 | -{ |
| 778 | - _thunar_return_if_fail (THUNAR_IS_FILE (file)); |
| 779 | - |
| 780 | - /* release the current file info */ |
| 781 | - if (file->info != NULL) |
| 782 | - { |
| 783 | - g_object_unref (file->info); |
| 784 | - file->info = NULL; |
| 785 | - } |
| 786 | - |
| 787 | - /* unset */ |
| 788 | - file->kind = G_FILE_TYPE_UNKNOWN; |
| 789 | - |
| 790 | - /* free the custom icon name */ |
| 791 | - g_free (file->custom_icon_name); |
| 792 | - file->custom_icon_name = NULL; |
| 793 | - |
| 794 | - /* free display name and basename */ |
| 795 | - g_free (file->display_name); |
| 796 | - file->display_name = NULL; |
| 797 | - |
| 798 | - g_free (file->basename); |
| 799 | - file->basename = NULL; |
| 800 | - |
| 801 | - /* content type */ |
| 802 | - g_free (file->content_type); |
| 803 | - file->content_type = NULL; |
| 804 | - g_free (file->icon_name); |
| 805 | - file->icon_name = NULL; |
| 806 | - |
| 807 | - /* free collate keys */ |
| 808 | - if (file->collate_key_nocase != file->collate_key) |
| 809 | - g_free (file->collate_key_nocase); |
| 810 | - file->collate_key_nocase = NULL; |
| 811 | - |
| 812 | - g_free (file->collate_key); |
| 813 | - file->collate_key = NULL; |
| 814 | - |
| 815 | - /* free thumbnail path */ |
| 816 | - g_free (file->thumbnail_path); |
| 817 | - file->thumbnail_path = NULL; |
| 818 | - |
| 819 | - /* assume the file is mounted by default */ |
| 820 | - FLAG_SET (file, THUNAR_FILE_FLAG_IS_MOUNTED); |
| 821 | - |
| 822 | - /* set thumb state to unknown */ |
| 823 | - FLAG_SET_THUMB_STATE (file, THUNAR_FILE_THUMB_STATE_UNKNOWN); |
| 824 | -} |
| 825 | - |
| 826 | - |
| 827 | - |
| 828 | -static void |
| 829 | -thunar_file_info_reload (ThunarFile *file, |
| 830 | - GCancellable *cancellable) |
| 831 | -{ |
| 832 | - const gchar *target_uri; |
| 833 | - GKeyFile *key_file; |
| 834 | - gchar *p; |
| 835 | - const gchar *display_name; |
| 836 | - gboolean is_secure = FALSE; |
| 837 | - gchar *casefold; |
| 838 | - gchar *path; |
| 839 | - |
| 840 | - _thunar_return_if_fail (THUNAR_IS_FILE (file)); |
| 841 | - _thunar_return_if_fail (file->info == NULL || G_IS_FILE_INFO (file->info)); |
| 842 | - |
| 843 | - if (G_LIKELY (file->info != NULL)) |
| 844 | - { |
| 845 | - /* this is requesed so often, cache it */ |
| 846 | - file->kind = g_file_info_get_file_type (file->info); |
| 847 | - |
| 848 | - if (file->kind == G_FILE_TYPE_MOUNTABLE) |
| 849 | - { |
| 850 | - target_uri = g_file_info_get_attribute_string (file->info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI); |
| 851 | - if (target_uri != NULL |
| 852 | - && !g_file_info_get_attribute_boolean (file->info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT)) |
| 853 | - FLAG_SET (file, THUNAR_FILE_FLAG_IS_MOUNTED); |
| 854 | - else |
| 855 | - FLAG_UNSET (file, THUNAR_FILE_FLAG_IS_MOUNTED); |
| 856 | - } |
| 857 | - } |
| 858 | - |
| 859 | - /* determine the basename */ |
| 860 | - file->basename = g_file_get_basename (file->gfile); |
| 861 | - _thunar_assert (file->basename != NULL); |
| 862 | - |
| 863 | - /* problematic files with content type reading */ |
| 864 | - if (strcmp (file->basename, "kmsg") == 0 |
| 865 | - && g_file_is_native (file->gfile)) |
| 866 | - { |
| 867 | - path = g_file_get_path (file->gfile); |
| 868 | - if (g_strcmp0 (path, "/proc/kmsg") == 0) |
| 869 | - file->content_type = g_strdup (DEFAULT_CONTENT_TYPE); |
| 870 | - g_free (path); |
| 871 | - } |
| 872 | - |
| 873 | - /* check if this file is a desktop entry */ |
| 874 | - if (thunar_file_is_desktop_file (file, &is_secure) && is_secure) |
| 875 | - { |
| 876 | - /* determine the custom icon and display name for .desktop files */ |
| 877 | - |
| 878 | - /* query a key file for the .desktop file */ |
| 879 | - key_file = thunar_g_file_query_key_file (file->gfile, cancellable, NULL); |
| 880 | - if (key_file != NULL) |
| 881 | - { |
| 882 | - /* read the icon name from the .desktop file */ |
| 883 | - file->custom_icon_name = g_key_file_get_string (key_file, |
| 884 | - G_KEY_FILE_DESKTOP_GROUP, |
| 885 | - G_KEY_FILE_DESKTOP_KEY_ICON, |
| 886 | - NULL); |
| 887 | - |
| 888 | - if (G_UNLIKELY (exo_str_is_empty (file->custom_icon_name))) |
| 889 | - { |
| 890 | - /* make sure we set null if the string is empty else the assertion in |
| 891 | - * thunar_icon_factory_lookup_icon() will fail */ |
| 892 | - g_free (file->custom_icon_name); |
| 893 | - file->custom_icon_name = NULL; |
| 894 | - } |
| 895 | - else |
| 896 | - { |
| 897 | - /* drop any suffix (e.g. '.png') from themed icons */ |
| 898 | - if (!g_path_is_absolute (file->custom_icon_name)) |
| 899 | - { |
| 900 | - p = strrchr (file->custom_icon_name, '.'); |
| 901 | - if (p != NULL) |
| 902 | - *p = '\0'; |
| 903 | - } |
| 904 | - } |
| 905 | - |
| 906 | - /* read the display name from the .desktop file (will be overwritten later |
| 907 | - * if it's undefined here) */ |
| 908 | - file->display_name = g_key_file_get_locale_string (key_file, |
| 909 | - G_KEY_FILE_DESKTOP_GROUP, |
| 910 | - G_KEY_FILE_DESKTOP_KEY_NAME, |
| 911 | - NULL, NULL); |
| 912 | - |
| 913 | - /* drop the name if it's empty or has invalid encoding */ |
| 914 | - if (exo_str_is_empty (file->display_name) |
| 915 | - || !g_utf8_validate (file->display_name, -1, NULL)) |
| 916 | - { |
| 917 | - g_free (file->display_name); |
| 918 | - file->display_name = NULL; |
| 919 | - } |
| 920 | - |
| 921 | - /* free the key file */ |
| 922 | - g_key_file_free (key_file); |
| 923 | - } |
| 924 | - } |
| 925 | - |
| 926 | - /* determine the display name */ |
| 927 | - if (file->display_name == NULL) |
| 928 | - { |
| 929 | - if (G_LIKELY (file->info != NULL)) |
| 930 | - { |
| 931 | - display_name = g_file_info_get_display_name (file->info); |
| 932 | - if (G_LIKELY (display_name != NULL)) |
| 933 | - { |
| 934 | - if (strcmp (display_name, "/") == 0) |
| 935 | - file->display_name = g_strdup (_("File System")); |
| 936 | - else |
| 937 | - file->display_name = g_strdup (display_name); |
| 938 | - } |
| 939 | - } |
| 940 | - |
| 941 | - /* faccl back to a name for the gfile */ |
| 942 | - if (file->display_name == NULL) |
| 943 | - file->display_name = thunar_g_file_get_display_name (file->gfile); |
| 944 | - } |
| 945 | - |
| 946 | - /* create case sensitive collation key */ |
| 947 | - file->collate_key = g_utf8_collate_key_for_filename (file->display_name, -1); |
| 948 | - |
| 949 | - /* lowercase the display name */ |
| 950 | - casefold = g_utf8_casefold (file->display_name, -1); |
| 951 | - |
| 952 | - /* if the lowercase name is equal, only peek the already hash key */ |
| 953 | - if (casefold != NULL && strcmp (casefold, file->display_name) != 0) |
| 954 | - file->collate_key_nocase = g_utf8_collate_key_for_filename (casefold, -1); |
| 955 | - else |
| 956 | - file->collate_key_nocase = file->collate_key; |
| 957 | - |
| 958 | - /* cleanup */ |
| 959 | - g_free (casefold); |
| 960 | -} |
| 961 | - |
| 962 | - |
| 963 | - |
| 964 | -static void |
| 965 | -thunar_file_get_async_finish (GObject *object, |
| 966 | - GAsyncResult *result, |
| 967 | - gpointer user_data) |
| 968 | -{ |
| 969 | - ThunarFileGetData *data = user_data; |
| 970 | - ThunarFile *file; |
| 971 | - GFileInfo *file_info; |
| 972 | - GError *error = NULL; |
| 973 | - GFile *location = G_FILE (object); |
| 974 | - |
| 975 | - _thunar_return_if_fail (G_IS_FILE (location)); |
| 976 | - _thunar_return_if_fail (G_IS_ASYNC_RESULT (result)); |
| 977 | - |
| 978 | - /* finish querying the file information */ |
| 979 | - file_info = g_file_query_info_finish (location, result, &error); |
| 980 | - |
| 981 | - /* allocate a new file object */ |
| 982 | - file = g_object_new (THUNAR_TYPE_FILE, NULL); |
| 983 | - file->gfile = g_object_ref (location); |
| 984 | - |
| 985 | - /* reset the file */ |
| 986 | - thunar_file_info_clear (file); |
| 987 | - |
| 988 | - /* set the file information */ |
| 989 | - file->info = file_info; |
| 990 | - |
| 991 | - /* update the file from the information */ |
| 992 | - thunar_file_info_reload (file, data->cancellable); |
| 993 | - |
| 994 | - /* update the mounted info */ |
| 995 | - if (error != NULL |
| 996 | - && error->domain == G_IO_ERROR |
| 997 | - && error->code == G_IO_ERROR_NOT_MOUNTED) |
| 998 | - { |
| 999 | - FLAG_UNSET (file, THUNAR_FILE_FLAG_IS_MOUNTED); |
| 1000 | - g_clear_error (&error); |
| 1001 | - } |
| 1002 | - |
| 1003 | - /* insert the file into the cache */ |
| 1004 | - G_LOCK (file_cache_mutex); |
| 1005 | -#ifdef G_ENABLE_DEBUG |
| 1006 | - /* check if there is no instance created in the meantime */ |
| 1007 | - _thunar_assert (g_hash_table_lookup (file_cache, file->gfile) == NULL); |
| 1008 | -#endif |
| 1009 | - g_hash_table_insert (file_cache, g_object_ref (file->gfile), file); |
| 1010 | - G_UNLOCK (file_cache_mutex); |
| 1011 | - |
| 1012 | - /* pass the loaded file and possible errors to the return function */ |
| 1013 | - (data->func) (location, file, error, data->user_data); |
| 1014 | - |
| 1015 | - /* release the file, see description in ThunarFileGetFunc */ |
| 1016 | - g_object_unref (file); |
| 1017 | - |
| 1018 | - /* free the error, if there is any */ |
| 1019 | - if (error != NULL) |
| 1020 | - g_error_free (error); |
| 1021 | - |
| 1022 | - /* release the get data */ |
| 1023 | - if (data->cancellable != NULL) |
| 1024 | - g_object_unref (data->cancellable); |
| 1025 | - g_slice_free (ThunarFileGetData, data); |
| 1026 | -} |
| 1027 | - |
| 1028 | - |
| 1029 | - |
| 1030 | -/** |
| 1031 | - * thunar_file_load: |
| 1032 | - * @file : a #ThunarFile. |
| 1033 | - * @cancellable : a #GCancellable. |
| 1034 | - * @error : return location for errors or %NULL. |
| 1035 | - * |
| 1036 | - * Loads all information about the file. As this is a possibly |
| 1037 | - * blocking call, it can be cancelled using @cancellable. |
| 1038 | - * |
| 1039 | - * If loading the file fails or the operation is cancelled, |
| 1040 | - * @error will be set. |
| 1041 | - * |
| 1042 | - * Return value: %TRUE on success, %FALSE on error or interruption. |
| 1043 | - **/ |
| 1044 | -static gboolean |
| 1045 | -thunar_file_load (ThunarFile *file, |
| 1046 | - GCancellable *cancellable, |
| 1047 | - GError **error) |
| 1048 | -{ |
| 1049 | - GError *err = NULL; |
| 1050 | - |
| 1051 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 1052 | - _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
| 1053 | - _thunar_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); |
| 1054 | - _thunar_return_val_if_fail (G_IS_FILE (file->gfile), FALSE); |
| 1055 | - |
| 1056 | - /* reset the file */ |
| 1057 | - thunar_file_info_clear (file); |
| 1058 | - |
| 1059 | - /* query a new file info */ |
| 1060 | - file->info = g_file_query_info (file->gfile, |
| 1061 | - THUNARX_FILE_INFO_NAMESPACE, |
| 1062 | - G_FILE_QUERY_INFO_NONE, |
| 1063 | - cancellable, &err); |
| 1064 | - |
| 1065 | - /* update the file from the information */ |
| 1066 | - thunar_file_info_reload (file, cancellable); |
| 1067 | - |
| 1068 | - /* update the mounted info */ |
| 1069 | - if (err != NULL |
| 1070 | - && err->domain == G_IO_ERROR |
| 1071 | - && err->code == G_IO_ERROR_NOT_MOUNTED) |
| 1072 | - { |
| 1073 | - FLAG_UNSET (file, THUNAR_FILE_FLAG_IS_MOUNTED); |
| 1074 | - g_clear_error (&err); |
| 1075 | - } |
| 1076 | - |
| 1077 | - if (err != NULL) |
| 1078 | - { |
| 1079 | - g_propagate_error (error, err); |
| 1080 | - return FALSE; |
| 1081 | - } |
| 1082 | - else |
| 1083 | - { |
| 1084 | - return TRUE; |
| 1085 | - } |
| 1086 | -} |
| 1087 | - |
| 1088 | - |
| 1089 | - |
| 1090 | -/** |
| 1091 | - * thunar_file_get: |
| 1092 | - * @file : a #GFile. |
| 1093 | - * @error : return location for errors. |
| 1094 | - * |
| 1095 | - * Looks up the #ThunarFile referred to by @file. This function may return a |
| 1096 | - * ThunarFile even though the file doesn't actually exist. This is the case |
| 1097 | - * with remote URIs (like SFTP) for instance, if they are not mounted. |
| 1098 | - * |
| 1099 | - * The caller is responsible to call g_object_unref() |
| 1100 | - * when done with the returned object. |
| 1101 | - * |
| 1102 | - * Return value: the #ThunarFile for @file or %NULL on errors. |
| 1103 | - **/ |
| 1104 | -ThunarFile* |
| 1105 | -thunar_file_get (GFile *gfile, |
| 1106 | - GError **error) |
| 1107 | -{ |
| 1108 | - ThunarFile *file; |
| 1109 | - |
| 1110 | - _thunar_return_val_if_fail (G_IS_FILE (gfile), NULL); |
| 1111 | - |
| 1112 | - /* check if we already have a cached version of that file */ |
| 1113 | - file = thunar_file_cache_lookup (gfile); |
| 1114 | - if (G_UNLIKELY (file != NULL)) |
| 1115 | - { |
| 1116 | - /* take a reference for the caller */ |
| 1117 | - g_object_ref (file); |
| 1118 | - } |
| 1119 | - else |
| 1120 | - { |
| 1121 | - /* allocate a new object */ |
| 1122 | - file = g_object_new (THUNAR_TYPE_FILE, NULL); |
| 1123 | - file->gfile = g_object_ref (gfile); |
| 1124 | - |
| 1125 | - if (thunar_file_load (file, NULL, error)) |
| 1126 | - { |
| 1127 | - /* setup lock until the file is inserted */ |
| 1128 | - G_LOCK (file_cache_mutex); |
| 1129 | - |
| 1130 | - /* insert the file into the cache */ |
| 1131 | - g_hash_table_insert (file_cache, g_object_ref (file->gfile), file); |
| 1132 | - |
| 1133 | - /* done inserting in the cache */ |
| 1134 | - G_UNLOCK (file_cache_mutex); |
| 1135 | - } |
| 1136 | - else |
| 1137 | - { |
| 1138 | - /* failed loading, destroy the file */ |
| 1139 | - g_object_unref (file); |
| 1140 | - |
| 1141 | - /* make sure we return NULL */ |
| 1142 | - file = NULL; |
| 1143 | - } |
| 1144 | - } |
| 1145 | - |
| 1146 | - return file; |
| 1147 | -} |
| 1148 | - |
| 1149 | - |
| 1150 | -/** |
| 1151 | - * thunar_file_get_with_info: |
| 1152 | - * @uri : an URI or an absolute filename. |
| 1153 | - * @info : #GFileInfo to use when loading the info. |
| 1154 | - * @not_mounted : if the file is mounted. |
| 1155 | - * |
| 1156 | - * Looks up the #ThunarFile referred to by @file. This function may return a |
| 1157 | - * ThunarFile even though the file doesn't actually exist. This is the case |
| 1158 | - * with remote URIs (like SFTP) for instance, if they are not mounted. |
| 1159 | - * |
| 1160 | - * This function does not use g_file_query_info() to get the info, |
| 1161 | - * but takes a reference on the @info, |
| 1162 | - * |
| 1163 | - * The caller is responsible to call g_object_unref() |
| 1164 | - * when done with the returned object. |
| 1165 | - * |
| 1166 | - * Return value: the #ThunarFile for @file or %NULL on errors. |
| 1167 | - **/ |
| 1168 | -ThunarFile * |
| 1169 | -thunar_file_get_with_info (GFile *gfile, |
| 1170 | - GFileInfo *info, |
| 1171 | - gboolean not_mounted) |
| 1172 | -{ |
| 1173 | - ThunarFile *file; |
| 1174 | - |
| 1175 | - _thunar_return_val_if_fail (G_IS_FILE (gfile), NULL); |
| 1176 | - _thunar_return_val_if_fail (G_IS_FILE_INFO (info), NULL); |
| 1177 | - |
| 1178 | - /* check if we already have a cached version of that file */ |
| 1179 | - file = thunar_file_cache_lookup (gfile); |
| 1180 | - if (G_UNLIKELY (file != NULL)) |
| 1181 | - { |
| 1182 | - /* take a reference for the caller */ |
| 1183 | - g_object_ref (file); |
| 1184 | - } |
| 1185 | - else |
| 1186 | - { |
| 1187 | - /* allocate a new object */ |
| 1188 | - file = g_object_new (THUNAR_TYPE_FILE, NULL); |
| 1189 | - file->gfile = g_object_ref (gfile); |
| 1190 | - |
| 1191 | - /* reset the file */ |
| 1192 | - thunar_file_info_clear (file); |
| 1193 | - |
| 1194 | - /* set the passed info */ |
| 1195 | - file->info = g_object_ref (info); |
| 1196 | - |
| 1197 | - /* update the file from the information */ |
| 1198 | - thunar_file_info_reload (file, NULL); |
| 1199 | - |
| 1200 | - /* update the mounted info */ |
| 1201 | - if (not_mounted) |
| 1202 | - FLAG_UNSET (file, THUNAR_FILE_FLAG_IS_MOUNTED); |
| 1203 | - |
| 1204 | - /* setup lock until the file is inserted */ |
| 1205 | - G_LOCK (file_cache_mutex); |
| 1206 | - |
| 1207 | - /* insert the file into the cache */ |
| 1208 | - g_hash_table_insert (file_cache, g_object_ref (file->gfile), file); |
| 1209 | - |
| 1210 | - /* done inserting in the cache */ |
| 1211 | - G_UNLOCK (file_cache_mutex); |
| 1212 | - } |
| 1213 | - |
| 1214 | - return file; |
| 1215 | -} |
| 1216 | - |
| 1217 | - |
| 1218 | - |
| 1219 | - |
| 1220 | - |
| 1221 | -/** |
| 1222 | - * thunar_file_get_for_uri: |
| 1223 | - * @uri : an URI or an absolute filename. |
| 1224 | - * @error : return location for errors or %NULL. |
| 1225 | - * |
| 1226 | - * Convenience wrapper function for thunar_file_get_for_path(), as its |
| 1227 | - * often required to determine a #ThunarFile for a given @uri. |
| 1228 | - * |
| 1229 | - * The caller is responsible to free the returned object using |
| 1230 | - * g_object_unref() when no longer needed. |
| 1231 | - * |
| 1232 | - * Return value: the #ThunarFile for the given @uri or %NULL if |
| 1233 | - * unable to determine. |
| 1234 | - **/ |
| 1235 | -ThunarFile* |
| 1236 | -thunar_file_get_for_uri (const gchar *uri, |
| 1237 | - GError **error) |
| 1238 | -{ |
| 1239 | - ThunarFile *file; |
| 1240 | - GFile *path; |
| 1241 | - |
| 1242 | - _thunar_return_val_if_fail (uri != NULL, NULL); |
| 1243 | - _thunar_return_val_if_fail (error == NULL || *error == NULL, NULL); |
| 1244 | - |
| 1245 | - path = g_file_new_for_commandline_arg (uri); |
| 1246 | - file = thunar_file_get (path, error); |
| 1247 | - g_object_unref (path); |
| 1248 | - |
| 1249 | - return file; |
| 1250 | -} |
| 1251 | - |
| 1252 | - |
| 1253 | - |
| 1254 | -/** |
| 1255 | - * thunar_file_get_async: |
| 1256 | - **/ |
| 1257 | -void |
| 1258 | -thunar_file_get_async (GFile *location, |
| 1259 | - GCancellable *cancellable, |
| 1260 | - ThunarFileGetFunc func, |
| 1261 | - gpointer user_data) |
| 1262 | -{ |
| 1263 | - ThunarFile *file; |
| 1264 | - ThunarFileGetData *data; |
| 1265 | - |
| 1266 | - _thunar_return_if_fail (G_IS_FILE (location)); |
| 1267 | - _thunar_return_if_fail (func != NULL); |
| 1268 | - |
| 1269 | - /* check if we already have a cached version of that file */ |
| 1270 | - file = thunar_file_cache_lookup (location); |
| 1271 | - if (G_UNLIKELY (file != NULL)) |
| 1272 | - { |
| 1273 | - /* call the return function with the file from the cache */ |
| 1274 | - (func) (location, file, NULL, user_data); |
| 1275 | - } |
| 1276 | - else |
| 1277 | - { |
| 1278 | - /* allocate get data */ |
| 1279 | - data = g_slice_new0 (ThunarFileGetData); |
| 1280 | - data->user_data = user_data; |
| 1281 | - data->func = func; |
| 1282 | - if (cancellable != NULL) |
| 1283 | - data->cancellable = g_object_ref (cancellable); |
| 1284 | - |
| 1285 | - /* load the file information asynchronously */ |
| 1286 | - g_file_query_info_async (location, |
| 1287 | - THUNARX_FILE_INFO_NAMESPACE, |
| 1288 | - G_FILE_QUERY_INFO_NONE, |
| 1289 | - G_PRIORITY_DEFAULT, |
| 1290 | - cancellable, |
| 1291 | - thunar_file_get_async_finish, |
| 1292 | - data); |
| 1293 | - } |
| 1294 | -} |
| 1295 | - |
| 1296 | - |
| 1297 | - |
| 1298 | -/** |
| 1299 | - * thunar_file_get_file: |
| 1300 | - * @file : a #ThunarFile instance. |
| 1301 | - * |
| 1302 | - * Returns the #GFile that refers to the location of @file. |
| 1303 | - * |
| 1304 | - * The returned #GFile is owned by @file and must not be released |
| 1305 | - * with g_object_unref(). |
| 1306 | - * |
| 1307 | - * Return value: the #GFile corresponding to @file. |
| 1308 | - **/ |
| 1309 | -GFile * |
| 1310 | -thunar_file_get_file (const ThunarFile *file) |
| 1311 | -{ |
| 1312 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 1313 | - _thunar_return_val_if_fail (G_IS_FILE (file->gfile), NULL); |
| 1314 | - return file->gfile; |
| 1315 | -} |
| 1316 | - |
| 1317 | - |
| 1318 | - |
| 1319 | -/** |
| 1320 | - * thunar_file_get_info: |
| 1321 | - * @file : a #ThunarFile instance. |
| 1322 | - * |
| 1323 | - * Returns the #GFileInfo for @file. |
| 1324 | - * |
| 1325 | - * Note, that there's no reference taken for the caller on the |
| 1326 | - * returned #GFileInfo, so if you need the object for a longer |
| 1327 | - * perioud, you'll need to take a reference yourself using the |
| 1328 | - * g_object_ref() method. |
| 1329 | - * |
| 1330 | - * Return value: the #GFileInfo for @file or %NULL. |
| 1331 | - **/ |
| 1332 | -GFileInfo * |
| 1333 | -thunar_file_get_info (const ThunarFile *file) |
| 1334 | -{ |
| 1335 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 1336 | - _thunar_return_val_if_fail (file->info == NULL || G_IS_FILE_INFO (file->info), NULL); |
| 1337 | - return file->info; |
| 1338 | -} |
| 1339 | - |
| 1340 | - |
| 1341 | - |
| 1342 | -/** |
| 1343 | - * thunar_file_get_parent: |
| 1344 | - * @file : a #ThunarFile instance. |
| 1345 | - * @error : return location for errors. |
| 1346 | - * |
| 1347 | - * Determines the parent #ThunarFile for @file. If @file has no parent or |
| 1348 | - * the user is not allowed to open the parent folder of @file, %NULL will |
| 1349 | - * be returned and @error will be set to point to a #GError that |
| 1350 | - * describes the cause. Else, the #ThunarFile will be returned, and |
| 1351 | - * the caller must call g_object_unref() on it. |
| 1352 | - * |
| 1353 | - * You may want to call thunar_file_has_parent() first to |
| 1354 | - * determine whether @file has a parent. |
| 1355 | - * |
| 1356 | - * Return value: the parent #ThunarFile or %NULL. |
| 1357 | - **/ |
| 1358 | -ThunarFile* |
| 1359 | -thunar_file_get_parent (const ThunarFile *file, |
| 1360 | - GError **error) |
| 1361 | -{ |
| 1362 | - ThunarFile *parent = NULL; |
| 1363 | - GFile *parent_file; |
| 1364 | - |
| 1365 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 1366 | - _thunar_return_val_if_fail (error == NULL || *error == NULL, NULL); |
| 1367 | - |
| 1368 | - parent_file = g_file_get_parent (file->gfile); |
| 1369 | - |
| 1370 | - if (parent_file == NULL) |
| 1371 | - { |
| 1372 | - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT, _("The root folder has no parent")); |
| 1373 | - return NULL; |
| 1374 | - } |
| 1375 | - |
| 1376 | - parent = thunar_file_get (parent_file, error); |
| 1377 | - g_object_unref (parent_file); |
| 1378 | - |
| 1379 | - return parent; |
| 1380 | -} |
| 1381 | - |
| 1382 | - |
| 1383 | - |
| 1384 | -/** |
| 1385 | - * thunar_file_check_loaded: |
| 1386 | - * @file : a #ThunarFile instance. |
| 1387 | - * |
| 1388 | - * Check if @file has its information loaded, if not, try this once else |
| 1389 | - * return %FALSE. |
| 1390 | - * |
| 1391 | - * Return value: %TRUE on success, else %FALSE. |
| 1392 | - **/ |
| 1393 | -gboolean |
| 1394 | -thunar_file_check_loaded (ThunarFile *file) |
| 1395 | -{ |
| 1396 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 1397 | - |
| 1398 | - if (G_UNLIKELY (file->info == NULL)) |
| 1399 | - thunar_file_load (file, NULL, NULL); |
| 1400 | - |
| 1401 | - return (file->info != NULL); |
| 1402 | -} |
| 1403 | - |
| 1404 | - |
| 1405 | - |
| 1406 | -/** |
| 1407 | - * thunar_file_execute: |
| 1408 | - * @file : a #ThunarFile instance. |
| 1409 | - * @working_directory : the working directory used to resolve relative filenames |
| 1410 | - * in @file_list. |
| 1411 | - * @parent : %NULL, a #GdkScreen or #GtkWidget. |
| 1412 | - * @file_list : the list of #GFile<!---->s to supply to @file on execution. |
| 1413 | - * @error : return location for errors or %NULL. |
| 1414 | - * |
| 1415 | - * Tries to execute @file on the specified @screen. If @file is executable |
| 1416 | - * and could have been spawned successfully, %TRUE is returned, else %FALSE |
| 1417 | - * will be returned and @error will be set to point to the error location. |
| 1418 | - * |
| 1419 | - * Return value: %TRUE on success, else %FALSE. |
| 1420 | - **/ |
| 1421 | -gboolean |
| 1422 | -thunar_file_execute (ThunarFile *file, |
| 1423 | - GFile *working_directory, |
| 1424 | - gpointer parent, |
| 1425 | - GList *file_list, |
| 1426 | - GError **error) |
| 1427 | -{ |
| 1428 | - gboolean snotify = FALSE; |
| 1429 | - gboolean terminal; |
| 1430 | - gboolean result = FALSE; |
| 1431 | - GKeyFile *key_file; |
| 1432 | - GError *err = NULL; |
| 1433 | - GFile *file_parent; |
| 1434 | - gchar *icon_name = NULL; |
| 1435 | - gchar *name; |
| 1436 | - gchar *type; |
| 1437 | - gchar *url; |
| 1438 | - gchar *location; |
| 1439 | - gchar *escaped_location; |
| 1440 | - gchar **argv = NULL; |
| 1441 | - gchar *exec; |
| 1442 | - gchar *directory = NULL; |
| 1443 | - gboolean is_secure = FALSE; |
| 1444 | - |
| 1445 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 1446 | - _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
| 1447 | - |
| 1448 | - location = thunar_g_file_get_location (file->gfile); |
| 1449 | - |
| 1450 | - if (thunar_file_is_desktop_file (file, &is_secure)) |
| 1451 | - { |
| 1452 | - /* parse file first, even if it is insecure */ |
| 1453 | - key_file = thunar_g_file_query_key_file (file->gfile, NULL, &err); |
| 1454 | - if (key_file == NULL) |
| 1455 | - { |
| 1456 | - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, |
| 1457 | - _("Failed to parse the desktop file: %s"), err->message); |
| 1458 | - g_error_free (err); |
| 1459 | - return FALSE; |
| 1460 | - } |
| 1461 | - |
| 1462 | - type = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TYPE, NULL); |
| 1463 | - if (G_LIKELY (exo_str_is_equal (type, "Application"))) |
| 1464 | - { |
| 1465 | - exec = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL); |
| 1466 | - if (G_LIKELY (exec != NULL)) |
| 1467 | - { |
| 1468 | - /* if the .desktop file is not secure, ask user what to do */ |
| 1469 | - if (is_secure || thunar_dialogs_show_insecure_program (parent, _("Untrusted application launcher"), file, exec)) |
| 1470 | - { |
| 1471 | - /* parse other fields */ |
| 1472 | - name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, NULL, NULL); |
| 1473 | - icon_name = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, NULL); |
| 1474 | - directory = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_PATH, NULL); |
| 1475 | - terminal = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TERMINAL, NULL); |
| 1476 | - snotify = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY, NULL); |
| 1477 | - |
| 1478 | - result = thunar_exec_parse (exec, file_list, icon_name, name, location, terminal, NULL, &argv, error); |
| 1479 | - |
| 1480 | - g_free (name); |
| 1481 | - } |
| 1482 | - else |
| 1483 | - { |
| 1484 | - /* fall-through to free value and leave without execution */ |
| 1485 | - result = TRUE; |
| 1486 | - } |
| 1487 | - |
| 1488 | - g_free (exec); |
| 1489 | - } |
| 1490 | - else |
| 1491 | - { |
| 1492 | - /* TRANSLATORS: `Exec' is a field name in a .desktop file. Don't translate it. */ |
| 1493 | - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, |
| 1494 | - _("No Exec field specified")); |
| 1495 | - } |
| 1496 | - } |
| 1497 | - else if (exo_str_is_equal (type, "Link")) |
| 1498 | - { |
| 1499 | - url = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_URL, NULL); |
| 1500 | - if (G_LIKELY (url != NULL)) |
| 1501 | - { |
| 1502 | - /* if the .desktop file is not secure, ask user what to do */ |
| 1503 | - if (is_secure || thunar_dialogs_show_insecure_program (parent, _("Untrusted link launcher"), file, url)) |
| 1504 | - { |
| 1505 | - /* pass the URL to the webbrowser, this could be a bit strange, |
| 1506 | - * but then at least we are on the secure side */ |
| 1507 | - argv = g_new (gchar *, 3); |
| 1508 | - argv[0] = g_strdup ("exo-open"); |
| 1509 | - argv[1] = url; |
| 1510 | - argv[2] = NULL; |
| 1511 | - } |
| 1512 | - |
| 1513 | - result = TRUE; |
| 1514 | - } |
| 1515 | - else |
| 1516 | - { |
| 1517 | - /* TRANSLATORS: `URL' is a field name in a .desktop file. Don't translate it. */ |
| 1518 | - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, |
| 1519 | - _("No URL field specified")); |
| 1520 | - } |
| 1521 | - } |
| 1522 | - else |
| 1523 | - { |
| 1524 | - g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, _("Invalid desktop file")); |
| 1525 | - } |
| 1526 | - |
| 1527 | - g_free (type); |
| 1528 | - g_key_file_free (key_file); |
| 1529 | - } |
| 1530 | - else |
| 1531 | - { |
| 1532 | - /* fake the Exec line */ |
| 1533 | - escaped_location = g_shell_quote (location); |
| 1534 | - exec = g_strconcat (escaped_location, " %F", NULL); |
| 1535 | - result = thunar_exec_parse (exec, file_list, NULL, NULL, NULL, FALSE, NULL, &argv, error); |
| 1536 | - g_free (escaped_location); |
| 1537 | - g_free (exec); |
| 1538 | - } |
| 1539 | - |
| 1540 | - if (G_LIKELY (result && argv != NULL)) |
| 1541 | - { |
| 1542 | - /* use other directory if the Path from the desktop file was not set */ |
| 1543 | - if (G_LIKELY (directory == NULL)) |
| 1544 | - { |
| 1545 | - /* determine the working directory */ |
| 1546 | - if (G_LIKELY (working_directory != NULL)) |
| 1547 | - { |
| 1548 | - /* copy the working directory provided to this method */ |
| 1549 | - directory = g_file_get_path (working_directory); |
| 1550 | - } |
| 1551 | - else if (file_list != NULL) |
| 1552 | - { |
| 1553 | - /* use the directory of the first list item */ |
| 1554 | - file_parent = g_file_get_parent (file_list->data); |
| 1555 | - directory = (file_parent != NULL) ? thunar_g_file_get_location (file_parent) : NULL; |
| 1556 | - g_object_unref (file_parent); |
| 1557 | - } |
| 1558 | - else |
| 1559 | - { |
| 1560 | - /* use the directory of the executable file */ |
| 1561 | - parent = g_file_get_parent (file->gfile); |
| 1562 | - directory = (parent != NULL) ? thunar_g_file_get_location (parent) : NULL; |
| 1563 | - g_object_unref (parent); |
| 1564 | - } |
| 1565 | - } |
| 1566 | - |
| 1567 | - /* execute the command */ |
| 1568 | - result = xfce_spawn_on_screen (thunar_util_parse_parent (parent, NULL), |
| 1569 | - directory, argv, NULL, G_SPAWN_SEARCH_PATH, |
| 1570 | - snotify, gtk_get_current_event_time (), icon_name, error); |
| 1571 | - } |
| 1572 | - |
| 1573 | - /* clean up */ |
| 1574 | - g_strfreev (argv); |
| 1575 | - g_free (location); |
| 1576 | - g_free (directory); |
| 1577 | - g_free (icon_name); |
| 1578 | - |
| 1579 | - return result; |
| 1580 | -} |
| 1581 | - |
| 1582 | - |
| 1583 | - |
| 1584 | -/** |
| 1585 | - * thunar_file_launch: |
| 1586 | - * @file : a #ThunarFile instance. |
| 1587 | - * @parent : a #GtkWidget or a #GdkScreen on which to launch the @file. |
| 1588 | - * May also be %NULL in which case the default #GdkScreen will |
| 1589 | - * be used. |
| 1590 | - * @startup_id : startup id for the new window (send over for dbus) or %NULL. |
| 1591 | - * @error : return location for errors or %NULL. |
| 1592 | - * |
| 1593 | - * If @file is an executable file, tries to execute it. Else if @file is |
| 1594 | - * a directory, opens a new #ThunarWindow to display the directory. Else, |
| 1595 | - * the default handler for @file is determined and run. |
| 1596 | - * |
| 1597 | - * The @parent can be either a #GtkWidget or a #GdkScreen, on which to |
| 1598 | - * launch the @file. If @parent is a #GtkWidget, the chooser dialog (if |
| 1599 | - * no default application is available for @file) will be transient for |
| 1600 | - * @parent. Else if @parent is a #GdkScreen it specifies the screen on |
| 1601 | - * which to launch @file. |
| 1602 | - * |
| 1603 | - * Return value: %TRUE on success, else %FALSE. |
| 1604 | - **/ |
| 1605 | -gboolean |
| 1606 | -thunar_file_launch (ThunarFile *file, |
| 1607 | - gpointer parent, |
| 1608 | - const gchar *startup_id, |
| 1609 | - GError **error) |
| 1610 | -{ |
| 1611 | - GdkAppLaunchContext *context; |
| 1612 | - ThunarApplication *application; |
| 1613 | - GAppInfo *app_info; |
| 1614 | - gboolean succeed; |
| 1615 | - GList path_list; |
| 1616 | - GdkScreen *screen; |
| 1617 | - |
| 1618 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 1619 | - _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
| 1620 | - _thunar_return_val_if_fail (parent == NULL || GDK_IS_SCREEN (parent) || GTK_IS_WIDGET (parent), FALSE); |
| 1621 | - |
| 1622 | - screen = thunar_util_parse_parent (parent, NULL); |
| 1623 | - |
| 1624 | - /* check if we have a folder here */ |
| 1625 | - if (thunar_file_is_directory (file)) |
| 1626 | - { |
| 1627 | - application = thunar_application_get (); |
| 1628 | - thunar_application_open_window (application, file, screen, startup_id); |
| 1629 | - g_object_unref (G_OBJECT (application)); |
| 1630 | - return TRUE; |
| 1631 | - } |
| 1632 | - |
| 1633 | - /* check if we should execute the file */ |
| 1634 | - if (thunar_file_is_executable (file)) |
| 1635 | - return thunar_file_execute (file, NULL, parent, NULL, error); |
| 1636 | - |
| 1637 | - /* determine the default application to open the file */ |
| 1638 | - /* TODO We should probably add a cancellable argument to thunar_file_launch() */ |
| 1639 | - app_info = thunar_file_get_default_handler (THUNAR_FILE (file)); |
| 1640 | - |
| 1641 | - /* display the application chooser if no application is defined for this file |
| 1642 | - * type yet */ |
| 1643 | - if (G_UNLIKELY (app_info == NULL)) |
| 1644 | - { |
| 1645 | - thunar_show_chooser_dialog (parent, file, TRUE); |
| 1646 | - return TRUE; |
| 1647 | - } |
| 1648 | - |
| 1649 | - /* HACK: check if we're not trying to launch another file manager again, possibly |
| 1650 | - * ourselfs which will end in a loop */ |
| 1651 | - if (g_strcmp0 (g_app_info_get_id (app_info), "exo-file-manager.desktop") == 0 |
| 1652 | - || g_strcmp0 (g_app_info_get_id (app_info), "Thunar.desktop") == 0 |
| 1653 | - || g_strcmp0 (g_app_info_get_name (app_info), "exo-file-manager") == 0) |
| 1654 | - { |
| 1655 | - g_object_unref (G_OBJECT (app_info)); |
| 1656 | - thunar_show_chooser_dialog (parent, file, TRUE); |
| 1657 | - return TRUE; |
| 1658 | - } |
| 1659 | - |
| 1660 | - /* fake a path list */ |
| 1661 | - path_list.data = file->gfile; |
| 1662 | - path_list.next = path_list.prev = NULL; |
| 1663 | - |
| 1664 | - /* create a launch context */ |
| 1665 | - context = gdk_app_launch_context_new (); |
| 1666 | - gdk_app_launch_context_set_screen (context, screen); |
| 1667 | - gdk_app_launch_context_set_timestamp (context, gtk_get_current_event_time ()); |
| 1668 | - |
| 1669 | - /* otherwise try to execute the application */ |
| 1670 | - succeed = g_app_info_launch (app_info, &path_list, G_APP_LAUNCH_CONTEXT (context), error); |
| 1671 | - |
| 1672 | - /* destroy the launch context */ |
| 1673 | - g_object_unref (context); |
| 1674 | - |
| 1675 | - /* release the handler reference */ |
| 1676 | - g_object_unref (G_OBJECT (app_info)); |
| 1677 | - |
| 1678 | - return succeed; |
| 1679 | -} |
| 1680 | - |
| 1681 | - |
| 1682 | - |
| 1683 | -/** |
| 1684 | - * thunar_file_rename: |
| 1685 | - * @file : a #ThunarFile instance. |
| 1686 | - * @name : the new file name in UTF-8 encoding. |
| 1687 | - * @error : return location for errors or %NULL. |
| 1688 | - * |
| 1689 | - * Tries to rename @file to the new @name. If @file cannot be renamed, |
| 1690 | - * %FALSE will be returned and @error will be set accordingly. Else, if |
| 1691 | - * the operation succeeds, %TRUE will be returned, and @file will have |
| 1692 | - * a new URI and a new display name. |
| 1693 | - * |
| 1694 | - * When offering a rename action in the user interface, the implementation |
| 1695 | - * should first check whether the file is available, using the |
| 1696 | - * thunar_file_is_renameable() method. |
| 1697 | - * |
| 1698 | - * Return value: %TRUE on success, else %FALSE. |
| 1699 | - **/ |
| 1700 | -gboolean |
| 1701 | -thunar_file_rename (ThunarFile *file, |
| 1702 | - const gchar *name, |
| 1703 | - GCancellable *cancellable, |
| 1704 | - gboolean called_from_job, |
| 1705 | - GError **error) |
| 1706 | -{ |
| 1707 | - ThunarApplication *application; |
| 1708 | - ThunarThumbnailCache *thumbnail_cache; |
| 1709 | - GKeyFile *key_file; |
| 1710 | - GError *err = NULL; |
| 1711 | - GFile *previous_file; |
| 1712 | - GFile *renamed_file; |
| 1713 | - gboolean is_secure; |
| 1714 | - const gchar * const *languages; |
| 1715 | - guint i; |
| 1716 | - gboolean name_set = FALSE; |
| 1717 | - |
| 1718 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 1719 | - _thunar_return_val_if_fail (g_utf8_validate (name, -1, NULL), FALSE); |
| 1720 | - _thunar_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); |
| 1721 | - _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
| 1722 | - |
| 1723 | - /* check if this file is a desktop entry */ |
| 1724 | - if (thunar_file_is_desktop_file (file, &is_secure) |
| 1725 | - && is_secure) |
| 1726 | - { |
| 1727 | - /* try to load the desktop entry into a key file */ |
| 1728 | - key_file = thunar_g_file_query_key_file (file->gfile, cancellable, &err); |
| 1729 | - if (key_file == NULL) |
| 1730 | - { |
| 1731 | - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, |
| 1732 | - _("Failed to parse the desktop file: %s"), err->message); |
| 1733 | - g_error_free (err); |
| 1734 | - return FALSE; |
| 1735 | - } |
| 1736 | - |
| 1737 | - /* check if we can set the language name */ |
| 1738 | - languages = g_get_language_names (); |
| 1739 | - if (languages != NULL) |
| 1740 | - { |
| 1741 | - for (i = 0; !name_set && languages[i] != NULL; i++) |
| 1742 | - { |
| 1743 | - /* skip C language */ |
| 1744 | - if (g_ascii_strcasecmp (languages[i], "C") == 0) |
| 1745 | - continue; |
| 1746 | - |
| 1747 | - /* change the translated Name field of the desktop entry */ |
| 1748 | - g_key_file_set_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, |
| 1749 | - G_KEY_FILE_DESKTOP_KEY_NAME, |
| 1750 | - languages[i], name); |
| 1751 | - |
| 1752 | - /* done */ |
| 1753 | - name_set = TRUE; |
| 1754 | - } |
| 1755 | - } |
| 1756 | - |
| 1757 | - if (!name_set) |
| 1758 | - { |
| 1759 | - /* change the Name field of the desktop entry */ |
| 1760 | - g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP, |
| 1761 | - G_KEY_FILE_DESKTOP_KEY_NAME, name); |
| 1762 | - } |
| 1763 | - |
| 1764 | - /* write the changes back to the file */ |
| 1765 | - if (thunar_g_file_write_key_file (file->gfile, key_file, cancellable, &err)) |
| 1766 | - { |
| 1767 | - /* reload file information */ |
| 1768 | - thunar_file_load (file, NULL, NULL); |
| 1769 | - |
| 1770 | - if (!called_from_job) |
| 1771 | - { |
| 1772 | - /* tell the associated folder that the file was renamed */ |
| 1773 | - thunarx_file_info_renamed (THUNARX_FILE_INFO (file)); |
| 1774 | - |
| 1775 | - /* notify everybody that the file has changed */ |
| 1776 | - thunar_file_changed (file); |
| 1777 | - } |
| 1778 | - |
| 1779 | - /* release the key file and return with success */ |
| 1780 | - g_key_file_free (key_file); |
| 1781 | - return TRUE; |
| 1782 | - } |
| 1783 | - else |
| 1784 | - { |
| 1785 | - /* propagate the error message and return with failure */ |
| 1786 | - g_propagate_error (error, err); |
| 1787 | - g_key_file_free (key_file); |
| 1788 | - return FALSE; |
| 1789 | - } |
| 1790 | - } |
| 1791 | - else |
| 1792 | - { |
| 1793 | - /* remember the previous file */ |
| 1794 | - previous_file = g_object_ref (file->gfile); |
| 1795 | - |
| 1796 | - /* try to rename the file */ |
| 1797 | - renamed_file = g_file_set_display_name (file->gfile, name, cancellable, error); |
| 1798 | - |
| 1799 | - /* notify the thumbnail cache that we can now also move the thumbnail */ |
| 1800 | - application = thunar_application_get (); |
| 1801 | - thumbnail_cache = thunar_application_get_thumbnail_cache (application); |
| 1802 | - thunar_thumbnail_cache_move_file (thumbnail_cache, previous_file, renamed_file); |
| 1803 | - g_object_unref (thumbnail_cache); |
| 1804 | - g_object_unref (application); |
| 1805 | - |
| 1806 | - /* check if we succeeded */ |
| 1807 | - if (renamed_file != NULL) |
| 1808 | - { |
| 1809 | - /* set the new file */ |
| 1810 | - file->gfile = renamed_file; |
| 1811 | - |
| 1812 | - /* reload file information */ |
| 1813 | - thunar_file_load (file, NULL, NULL); |
| 1814 | - |
| 1815 | - /* need to re-register the monitor handle for the new uri */ |
| 1816 | - thunar_file_watch_reconnect (file); |
| 1817 | - |
| 1818 | - G_LOCK (file_cache_mutex); |
| 1819 | - |
| 1820 | - /* drop the previous entry from the cache */ |
| 1821 | - g_hash_table_remove (file_cache, previous_file); |
| 1822 | - |
| 1823 | - /* drop the reference on the previous file */ |
| 1824 | - g_object_unref (previous_file); |
| 1825 | - |
| 1826 | - /* insert the new entry */ |
| 1827 | - g_hash_table_insert (file_cache, g_object_ref (file->gfile), file); |
| 1828 | - |
| 1829 | - G_UNLOCK (file_cache_mutex); |
| 1830 | - |
| 1831 | - if (!called_from_job) |
| 1832 | - { |
| 1833 | - /* tell the associated folder that the file was renamed */ |
| 1834 | - thunarx_file_info_renamed (THUNARX_FILE_INFO (file)); |
| 1835 | - |
| 1836 | - /* emit the file changed signal */ |
| 1837 | - thunar_file_changed (file); |
| 1838 | - } |
| 1839 | - |
| 1840 | - return TRUE; |
| 1841 | - } |
| 1842 | - else |
| 1843 | - { |
| 1844 | - g_object_unref (previous_file); |
| 1845 | - |
| 1846 | - return FALSE; |
| 1847 | - } |
| 1848 | - } |
| 1849 | -} |
| 1850 | - |
| 1851 | - |
| 1852 | - |
| 1853 | -/** |
| 1854 | - * thunar_file_accepts_drop: |
| 1855 | - * @file : a #ThunarFile instance. |
| 1856 | - * @file_list : the list of #GFile<!---->s that will be droppped. |
| 1857 | - * @context : the current #GdkDragContext, which is used for the drop. |
| 1858 | - * @suggested_action_return : return location for the suggested #GdkDragAction or %NULL. |
| 1859 | - * |
| 1860 | - * Checks whether @file can accept @path_list for the given @context and |
| 1861 | - * returns the #GdkDragAction<!---->s that can be used or 0 if no actions |
| 1862 | - * apply. |
| 1863 | - * |
| 1864 | - * If any #GdkDragAction<!---->s apply and @suggested_action_return is not |
| 1865 | - * %NULL, the suggested #GdkDragAction for this drop will be stored to the |
| 1866 | - * location pointed to by @suggested_action_return. |
| 1867 | - * |
| 1868 | - * Return value: the #GdkDragAction<!---->s supported for the drop or |
| 1869 | - * 0 if no drop is possible. |
| 1870 | - **/ |
| 1871 | -GdkDragAction |
| 1872 | -thunar_file_accepts_drop (ThunarFile *file, |
| 1873 | - GList *file_list, |
| 1874 | - GdkDragContext *context, |
| 1875 | - GdkDragAction *suggested_action_return) |
| 1876 | -{ |
| 1877 | - GdkDragAction suggested_action; |
| 1878 | - GdkDragAction actions; |
| 1879 | - ThunarFile *ofile; |
| 1880 | - GFile *parent_file; |
| 1881 | - GList *lp; |
| 1882 | - guint n; |
| 1883 | - |
| 1884 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), 0); |
| 1885 | - _thunar_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), 0); |
| 1886 | - |
| 1887 | - /* we can never drop an empty list */ |
| 1888 | - if (G_UNLIKELY (file_list == NULL)) |
| 1889 | - return 0; |
| 1890 | - |
| 1891 | - /* default to whatever GTK+ thinks for the suggested action */ |
| 1892 | - suggested_action = context->suggested_action; |
| 1893 | - |
| 1894 | - /* check if we have a writable directory here or an executable file */ |
| 1895 | - if (thunar_file_is_directory (file) && thunar_file_is_writable (file)) |
| 1896 | - { |
| 1897 | - /* determine the possible actions */ |
| 1898 | - actions = context->actions & (GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK); |
| 1899 | - |
| 1900 | - /* cannot create symbolic links in the trash or copy to the trash */ |
| 1901 | - if (thunar_file_is_trashed (file)) |
| 1902 | - actions &= ~(GDK_ACTION_COPY | GDK_ACTION_LINK); |
| 1903 | - |
| 1904 | - /* check up to 100 of the paths (just in case somebody tries to |
| 1905 | - * drag around his music collection with 5000 files). |
| 1906 | - */ |
| 1907 | - for (lp = file_list, n = 0; lp != NULL && n < 100; lp = lp->next, ++n) |
| 1908 | - { |
| 1909 | - /* we cannot drop a file on itself */ |
| 1910 | - if (G_UNLIKELY (g_file_equal (file->gfile, lp->data))) |
| 1911 | - return 0; |
| 1912 | - |
| 1913 | - /* check whether source and destination are the same */ |
| 1914 | - parent_file = g_file_get_parent (lp->data); |
| 1915 | - if (G_LIKELY (parent_file != NULL)) |
| 1916 | - { |
| 1917 | - if (g_file_equal (file->gfile, parent_file)) |
| 1918 | - { |
| 1919 | - g_object_unref (parent_file); |
| 1920 | - return 0; |
| 1921 | - } |
| 1922 | - else |
| 1923 | - g_object_unref (parent_file); |
| 1924 | - } |
| 1925 | - |
| 1926 | - /* copy/move/link within the trash not possible */ |
| 1927 | - if (G_UNLIKELY (thunar_g_file_is_trashed (lp->data) && thunar_file_is_trashed (file))) |
| 1928 | - return 0; |
| 1929 | - } |
| 1930 | - |
| 1931 | - /* if the source offers both copy and move and the GTK+ suggested action is copy, try to be smart telling whether |
| 1932 | - * we should copy or move by default by checking whether the source and target are on the same disk. |
| 1933 | - */ |
| 1934 | - if ((actions & (GDK_ACTION_COPY | GDK_ACTION_MOVE)) != 0 |
| 1935 | - && (suggested_action == GDK_ACTION_COPY)) |
| 1936 | - { |
| 1937 | - /* default to move as suggested action */ |
| 1938 | - suggested_action = GDK_ACTION_MOVE; |
| 1939 | - |
| 1940 | - /* check for up to 100 files, for the reason state above */ |
| 1941 | - for (lp = file_list, n = 0; lp != NULL && n < 100; lp = lp->next, ++n) |
| 1942 | - { |
| 1943 | - /* dropping from the trash always suggests move */ |
| 1944 | - if (G_UNLIKELY (thunar_g_file_is_trashed (lp->data))) |
| 1945 | - break; |
| 1946 | - |
| 1947 | - /* determine the cached version of the source file */ |
| 1948 | - ofile = thunar_file_cache_lookup (lp->data); |
| 1949 | - |
| 1950 | - /* we have only move if we know the source and both the source and the target |
| 1951 | - * are on the same disk, and the source file is owned by the current user. |
| 1952 | - */ |
| 1953 | - if (ofile == NULL |
| 1954 | - || !thunar_file_same_filesystem (file, ofile) |
| 1955 | - || (ofile->info != NULL |
| 1956 | - && g_file_info_get_attribute_uint32 (ofile->info, |
| 1957 | - G_FILE_ATTRIBUTE_UNIX_UID) != effective_user_id)) |
| 1958 | - { |
| 1959 | - /* default to copy and get outa here */ |
| 1960 | - suggested_action = GDK_ACTION_COPY; |
| 1961 | - break; |
| 1962 | - } |
| 1963 | - } |
| 1964 | - } |
| 1965 | - } |
| 1966 | - else if (thunar_file_is_executable (file)) |
| 1967 | - { |
| 1968 | - /* determine the possible actions */ |
| 1969 | - actions = context->actions & (GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_PRIVATE); |
| 1970 | - } |
| 1971 | - else |
| 1972 | - return 0; |
| 1973 | - |
| 1974 | - /* determine the preferred action based on the context */ |
| 1975 | - if (G_LIKELY (suggested_action_return != NULL)) |
| 1976 | - { |
| 1977 | - /* determine a working action */ |
| 1978 | - if (G_LIKELY ((suggested_action & actions) != 0)) |
| 1979 | - *suggested_action_return = suggested_action; |
| 1980 | - else if ((actions & GDK_ACTION_ASK) != 0) |
| 1981 | - *suggested_action_return = GDK_ACTION_ASK; |
| 1982 | - else if ((actions & GDK_ACTION_COPY) != 0) |
| 1983 | - *suggested_action_return = GDK_ACTION_COPY; |
| 1984 | - else if ((actions & GDK_ACTION_LINK) != 0) |
| 1985 | - *suggested_action_return = GDK_ACTION_LINK; |
| 1986 | - else if ((actions & GDK_ACTION_MOVE) != 0) |
| 1987 | - *suggested_action_return = GDK_ACTION_MOVE; |
| 1988 | - else |
| 1989 | - *suggested_action_return = GDK_ACTION_PRIVATE; |
| 1990 | - } |
| 1991 | - |
| 1992 | - /* yeppa, we can drop here */ |
| 1993 | - return actions; |
| 1994 | -} |
| 1995 | - |
| 1996 | - |
| 1997 | - |
| 1998 | -/** |
| 1999 | - * thunar_file_get_date: |
| 2000 | - * @file : a #ThunarFile instance. |
| 2001 | - * @date_type : the kind of date you are interested in. |
| 2002 | - * |
| 2003 | - * Queries the given @date_type from @file and returns the result. |
| 2004 | - * |
| 2005 | - * Return value: the time for @file of the given @date_type. |
| 2006 | - **/ |
| 2007 | -guint64 |
| 2008 | -thunar_file_get_date (const ThunarFile *file, |
| 2009 | - ThunarFileDateType date_type) |
| 2010 | -{ |
| 2011 | - const gchar *attribute; |
| 2012 | - |
| 2013 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), 0); |
| 2014 | - |
| 2015 | - if (file->info == NULL) |
| 2016 | - return 0; |
| 2017 | - |
| 2018 | - switch (date_type) |
| 2019 | - { |
| 2020 | - case THUNAR_FILE_DATE_ACCESSED: |
| 2021 | - attribute = G_FILE_ATTRIBUTE_TIME_ACCESS; |
| 2022 | - break; |
| 2023 | - case THUNAR_FILE_DATE_CHANGED: |
| 2024 | - attribute = G_FILE_ATTRIBUTE_TIME_CHANGED; |
| 2025 | - break; |
| 2026 | - case THUNAR_FILE_DATE_MODIFIED: |
| 2027 | - attribute = G_FILE_ATTRIBUTE_TIME_MODIFIED; |
| 2028 | - break; |
| 2029 | - default: |
| 2030 | - _thunar_assert_not_reached (); |
| 2031 | - } |
| 2032 | - |
| 2033 | - return g_file_info_get_attribute_uint64 (file->info, attribute); |
| 2034 | -} |
| 2035 | - |
| 2036 | - |
| 2037 | - |
| 2038 | -/** |
| 2039 | - * thunar_file_get_date_string: |
| 2040 | - * @file : a #ThunarFile instance. |
| 2041 | - * @date_type : the kind of date you are interested to know about @file. |
| 2042 | - * @date_style : the style used to format the date. |
| 2043 | - * |
| 2044 | - * Tries to determine the @date_type of @file, and if @file supports the |
| 2045 | - * given @date_type, it'll be formatted as string and returned. The |
| 2046 | - * caller is responsible for freeing the string using the g_free() |
| 2047 | - * function. |
| 2048 | - * |
| 2049 | - * Return value: the @date_type of @file formatted as string. |
| 2050 | - **/ |
| 2051 | -gchar* |
| 2052 | -thunar_file_get_date_string (const ThunarFile *file, |
| 2053 | - ThunarFileDateType date_type, |
| 2054 | - ThunarDateStyle date_style) |
| 2055 | -{ |
| 2056 | - return thunar_util_humanize_file_time (thunar_file_get_date (file, date_type), date_style); |
| 2057 | -} |
| 2058 | - |
| 2059 | - |
| 2060 | - |
| 2061 | -/** |
| 2062 | - * thunar_file_get_mode_string: |
| 2063 | - * @file : a #ThunarFile instance. |
| 2064 | - * |
| 2065 | - * Returns the mode of @file as text. You'll need to free |
| 2066 | - * the result using g_free() when you're done with it. |
| 2067 | - * |
| 2068 | - * Return value: the mode of @file as string. |
| 2069 | - **/ |
| 2070 | -gchar* |
| 2071 | -thunar_file_get_mode_string (const ThunarFile *file) |
| 2072 | -{ |
| 2073 | - ThunarFileMode mode; |
| 2074 | - GFileType kind; |
| 2075 | - gchar *text; |
| 2076 | - |
| 2077 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 2078 | - |
| 2079 | - kind = thunar_file_get_kind (file); |
| 2080 | - mode = thunar_file_get_mode (file); |
| 2081 | - text = g_new (gchar, 11); |
| 2082 | - |
| 2083 | - /* file type */ |
| 2084 | - /* TODO earlier versions of Thunar had 'P' for ports and |
| 2085 | - * 'D' for doors. Do we still need those? */ |
| 2086 | - switch (kind) |
| 2087 | - { |
| 2088 | - case G_FILE_TYPE_SYMBOLIC_LINK: text[0] = 'l'; break; |
| 2089 | - case G_FILE_TYPE_REGULAR: text[0] = '-'; break; |
| 2090 | - case G_FILE_TYPE_DIRECTORY: text[0] = 'd'; break; |
| 2091 | - case G_FILE_TYPE_SPECIAL: |
| 2092 | - case G_FILE_TYPE_UNKNOWN: |
| 2093 | - default: |
| 2094 | - if (S_ISCHR (mode)) |
| 2095 | - text[0] = 'c'; |
| 2096 | - else if (S_ISSOCK (mode)) |
| 2097 | - text[0] = 's'; |
| 2098 | - else if (S_ISFIFO (mode)) |
| 2099 | - text[0] = 'f'; |
| 2100 | - else if (S_ISBLK (mode)) |
| 2101 | - text[0] = 'b'; |
| 2102 | - else |
| 2103 | - text[0] = ' '; |
| 2104 | - } |
| 2105 | - |
| 2106 | - /* permission flags */ |
| 2107 | - text[1] = (mode & THUNAR_FILE_MODE_USR_READ) ? 'r' : '-'; |
| 2108 | - text[2] = (mode & THUNAR_FILE_MODE_USR_WRITE) ? 'w' : '-'; |
| 2109 | - text[3] = (mode & THUNAR_FILE_MODE_USR_EXEC) ? 'x' : '-'; |
| 2110 | - text[4] = (mode & THUNAR_FILE_MODE_GRP_READ) ? 'r' : '-'; |
| 2111 | - text[5] = (mode & THUNAR_FILE_MODE_GRP_WRITE) ? 'w' : '-'; |
| 2112 | - text[6] = (mode & THUNAR_FILE_MODE_GRP_EXEC) ? 'x' : '-'; |
| 2113 | - text[7] = (mode & THUNAR_FILE_MODE_OTH_READ) ? 'r' : '-'; |
| 2114 | - text[8] = (mode & THUNAR_FILE_MODE_OTH_WRITE) ? 'w' : '-'; |
| 2115 | - text[9] = (mode & THUNAR_FILE_MODE_OTH_EXEC) ? 'x' : '-'; |
| 2116 | - |
| 2117 | - /* special flags */ |
| 2118 | - if (G_UNLIKELY (mode & THUNAR_FILE_MODE_SUID)) |
| 2119 | - text[3] = 's'; |
| 2120 | - if (G_UNLIKELY (mode & THUNAR_FILE_MODE_SGID)) |
| 2121 | - text[6] = 's'; |
| 2122 | - if (G_UNLIKELY (mode & THUNAR_FILE_MODE_STICKY)) |
| 2123 | - text[9] = 't'; |
| 2124 | - |
| 2125 | - text[10] = '\0'; |
| 2126 | - |
| 2127 | - return text; |
| 2128 | -} |
| 2129 | - |
| 2130 | - |
| 2131 | - |
| 2132 | -/** |
| 2133 | - * thunar_file_get_size_string: |
| 2134 | - * @file : a #ThunarFile instance. |
| 2135 | - * |
| 2136 | - * Returns the size of the file as text in a human readable |
| 2137 | - * format. You'll need to free the result using g_free() |
| 2138 | - * if you're done with it. |
| 2139 | - * |
| 2140 | - * Return value: the size of @file in a human readable |
| 2141 | - * format. |
| 2142 | - **/ |
| 2143 | -gchar * |
| 2144 | -thunar_file_get_size_string (const ThunarFile *file) |
| 2145 | -{ |
| 2146 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 2147 | - return g_format_size (thunar_file_get_size (file)); |
| 2148 | -} |
| 2149 | - |
| 2150 | - |
| 2151 | - |
| 2152 | -/** |
| 2153 | - * thunar_file_get_volume: |
| 2154 | - * @file : a #ThunarFile instance. |
| 2155 | - * |
| 2156 | - * Attempts to determine the #GVolume on which @file is located. If @file cannot |
| 2157 | - * determine it's volume, then %NULL will be returned. Else a #GVolume instance |
| 2158 | - * is returned which has to be released by the caller using g_object_unref(). |
| 2159 | - * |
| 2160 | - * Return value: the #GVolume for @file or %NULL. |
| 2161 | - **/ |
| 2162 | -GVolume* |
| 2163 | -thunar_file_get_volume (const ThunarFile *file) |
| 2164 | -{ |
| 2165 | - GVolume *volume = NULL; |
| 2166 | - GMount *mount; |
| 2167 | - |
| 2168 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 2169 | - |
| 2170 | - /* TODO make this function call asynchronous */ |
| 2171 | - mount = g_file_find_enclosing_mount (file->gfile, NULL, NULL); |
| 2172 | - if (mount != NULL) |
| 2173 | - { |
| 2174 | - volume = g_mount_get_volume (mount); |
| 2175 | - g_object_unref (mount); |
| 2176 | - } |
| 2177 | - |
| 2178 | - return volume; |
| 2179 | -} |
| 2180 | - |
| 2181 | - |
| 2182 | - |
| 2183 | -/** |
| 2184 | - * thunar_file_get_group: |
| 2185 | - * @file : a #ThunarFile instance. |
| 2186 | - * |
| 2187 | - * Determines the #ThunarGroup for @file. If there's no |
| 2188 | - * group associated with @file or if the system is unable to |
| 2189 | - * determine the group, %NULL will be returned. |
| 2190 | - * |
| 2191 | - * The caller is responsible for freeing the returned object |
| 2192 | - * using g_object_unref(). |
| 2193 | - * |
| 2194 | - * Return value: the #ThunarGroup for @file or %NULL. |
| 2195 | - **/ |
| 2196 | -ThunarGroup * |
| 2197 | -thunar_file_get_group (const ThunarFile *file) |
| 2198 | -{ |
| 2199 | - guint32 gid; |
| 2200 | - |
| 2201 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 2202 | - |
| 2203 | - /* TODO what are we going to do on non-UNIX systems? */ |
| 2204 | - gid = g_file_info_get_attribute_uint32 (file->info, |
| 2205 | - G_FILE_ATTRIBUTE_UNIX_GID); |
| 2206 | - |
| 2207 | - return thunar_user_manager_get_group_by_id (user_manager, gid); |
| 2208 | -} |
| 2209 | - |
| 2210 | - |
| 2211 | - |
| 2212 | -/** |
| 2213 | - * thunar_file_get_user: |
| 2214 | - * @file : a #ThunarFile instance. |
| 2215 | - * |
| 2216 | - * Determines the #ThunarUser for @file. If there's no |
| 2217 | - * user associated with @file or if the system is unable |
| 2218 | - * to determine the user, %NULL will be returned. |
| 2219 | - * |
| 2220 | - * The caller is responsible for freeing the returned object |
| 2221 | - * using g_object_unref(). |
| 2222 | - * |
| 2223 | - * Return value: the #ThunarUser for @file or %NULL. |
| 2224 | - **/ |
| 2225 | -ThunarUser* |
| 2226 | -thunar_file_get_user (const ThunarFile *file) |
| 2227 | -{ |
| 2228 | - guint32 uid; |
| 2229 | - |
| 2230 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 2231 | - |
| 2232 | - /* TODO what are we going to do on non-UNIX systems? */ |
| 2233 | - uid = g_file_info_get_attribute_uint32 (file->info, |
| 2234 | - G_FILE_ATTRIBUTE_UNIX_UID); |
| 2235 | - |
| 2236 | - return thunar_user_manager_get_user_by_id (user_manager, uid); |
| 2237 | -} |
| 2238 | - |
| 2239 | - |
| 2240 | - |
| 2241 | -/** |
| 2242 | - * thunar_file_get_content_type: |
| 2243 | - * @file : a #ThunarFile. |
| 2244 | - * |
| 2245 | - * Returns the content type of @file. |
| 2246 | - * |
| 2247 | - * Return value: content type of @file. |
| 2248 | - **/ |
| 2249 | -const gchar * |
| 2250 | -thunar_file_get_content_type (ThunarFile *file) |
| 2251 | -{ |
| 2252 | - GFileInfo *info; |
| 2253 | - GError *err = NULL; |
| 2254 | - const gchar *content_type = NULL; |
| 2255 | - |
| 2256 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 2257 | - |
| 2258 | - if (G_UNLIKELY (file->content_type == NULL)) |
| 2259 | - { |
| 2260 | - G_LOCK (file_content_type_mutex); |
| 2261 | - |
| 2262 | - /* make sure we weren't waiting for a lock */ |
| 2263 | - if (G_UNLIKELY (file->content_type != NULL)) |
| 2264 | - goto bailout; |
| 2265 | - |
| 2266 | - /* make sure this is not loaded in the general info */ |
| 2267 | - _thunar_assert (file->info == NULL |
| 2268 | - || !g_file_info_has_attribute (file->info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE)); |
| 2269 | - |
| 2270 | - if (G_UNLIKELY (file->kind == G_FILE_TYPE_DIRECTORY)) |
| 2271 | - { |
| 2272 | - /* this we known for sure */ |
| 2273 | - file->content_type = g_strdup ("inode/directory"); |
| 2274 | - } |
| 2275 | - else |
| 2276 | - { |
| 2277 | - /* async load the content-type */ |
| 2278 | - info = g_file_query_info (file->gfile, |
| 2279 | - G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, |
| 2280 | - G_FILE_QUERY_INFO_NONE, |
| 2281 | - NULL, &err); |
| 2282 | - |
| 2283 | - if (G_LIKELY (info != NULL)) |
| 2284 | - { |
| 2285 | - /* store the new content type */ |
| 2286 | - content_type = g_file_info_get_content_type (info); |
| 2287 | - if (G_UNLIKELY (content_type != NULL)) |
| 2288 | - file->content_type = g_strdup (content_type); |
| 2289 | - g_object_unref (G_OBJECT (info)); |
| 2290 | - } |
| 2291 | - else |
| 2292 | - { |
| 2293 | - g_warning ("Content type loading failed for %s: %s", |
| 2294 | - thunar_file_get_display_name (file), |
| 2295 | - err->message); |
| 2296 | - g_error_free (err); |
| 2297 | - } |
| 2298 | - |
| 2299 | - /* always provide a fallback */ |
| 2300 | - if (file->content_type == NULL) |
| 2301 | - file->content_type = g_strdup (DEFAULT_CONTENT_TYPE); |
| 2302 | - } |
| 2303 | - |
| 2304 | - bailout: |
| 2305 | - |
| 2306 | - G_UNLOCK (file_content_type_mutex); |
| 2307 | - } |
| 2308 | - |
| 2309 | - return file->content_type; |
| 2310 | -} |
| 2311 | - |
| 2312 | - |
| 2313 | - |
| 2314 | -gboolean |
| 2315 | -thunar_file_load_content_type (ThunarFile *file) |
| 2316 | -{ |
| 2317 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), TRUE); |
| 2318 | - |
| 2319 | - if (file->content_type != NULL) |
| 2320 | - return FALSE; |
| 2321 | - |
| 2322 | - thunar_file_get_content_type (file); |
| 2323 | - |
| 2324 | - return TRUE; |
| 2325 | -} |
| 2326 | - |
| 2327 | - |
| 2328 | - |
| 2329 | -/** |
| 2330 | - * thunar_file_get_symlink_target: |
| 2331 | - * @file : a #ThunarFile. |
| 2332 | - * |
| 2333 | - * Returns the path of the symlink target or %NULL if the @file |
| 2334 | - * is not a symlink. |
| 2335 | - * |
| 2336 | - * Return value: path of the symlink target or %NULL. |
| 2337 | - **/ |
| 2338 | -const gchar * |
| 2339 | -thunar_file_get_symlink_target (const ThunarFile *file) |
| 2340 | -{ |
| 2341 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 2342 | - |
| 2343 | - if (file->info == NULL) |
| 2344 | - return NULL; |
| 2345 | - |
| 2346 | - return g_file_info_get_symlink_target (file->info); |
| 2347 | -} |
| 2348 | - |
| 2349 | - |
| 2350 | - |
| 2351 | -/** |
| 2352 | - * thunar_file_get_basename: |
| 2353 | - * @file : a #ThunarFile. |
| 2354 | - * |
| 2355 | - * Returns the basename of the @file in UTF-8 encoding. |
| 2356 | - * |
| 2357 | - * Return value: UTF-8 encoded basename of the @file. |
| 2358 | - **/ |
| 2359 | -const gchar * |
| 2360 | -thunar_file_get_basename (const ThunarFile *file) |
| 2361 | -{ |
| 2362 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 2363 | - return file->basename; |
| 2364 | -} |
| 2365 | - |
| 2366 | - |
| 2367 | - |
| 2368 | -/** |
| 2369 | - * thunar_file_is_symlink: |
| 2370 | - * @file : a #ThunarFile. |
| 2371 | - * |
| 2372 | - * Returns %TRUE if @file is a symbolic link. |
| 2373 | - * |
| 2374 | - * Return value: %TRUE if @file is a symbolic link. |
| 2375 | - **/ |
| 2376 | -gboolean |
| 2377 | -thunar_file_is_symlink (const ThunarFile *file) |
| 2378 | -{ |
| 2379 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2380 | - |
| 2381 | - if (file->info == NULL) |
| 2382 | - return FALSE; |
| 2383 | - |
| 2384 | - return g_file_info_get_is_symlink (file->info); |
| 2385 | -} |
| 2386 | - |
| 2387 | - |
| 2388 | - |
| 2389 | -/** |
| 2390 | - * thunar_file_get_size: |
| 2391 | - * @file : a #ThunarFile instance. |
| 2392 | - * |
| 2393 | - * Tries to determine the size of @file in bytes and |
| 2394 | - * returns the size. |
| 2395 | - * |
| 2396 | - * Return value: the size of @file in bytes. |
| 2397 | - **/ |
| 2398 | -guint64 |
| 2399 | -thunar_file_get_size (const ThunarFile *file) |
| 2400 | -{ |
| 2401 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), 0); |
| 2402 | - |
| 2403 | - if (file->info == NULL) |
| 2404 | - return 0; |
| 2405 | - |
| 2406 | - return g_file_info_get_size (file->info); |
| 2407 | -} |
| 2408 | - |
| 2409 | - |
| 2410 | - |
| 2411 | -/** |
| 2412 | - * thunar_file_get_default_handler: |
| 2413 | - * @file : a #ThunarFile instance. |
| 2414 | - * |
| 2415 | - * Returns the default #GAppInfo for @file or %NULL if there is none. |
| 2416 | - * |
| 2417 | - * The caller is responsible to free the returned #GAppInfo using |
| 2418 | - * g_object_unref(). |
| 2419 | - * |
| 2420 | - * Return value: Default #GAppInfo for @file or %NULL if there is none. |
| 2421 | - **/ |
| 2422 | -GAppInfo * |
| 2423 | -thunar_file_get_default_handler (const ThunarFile *file) |
| 2424 | -{ |
| 2425 | - const gchar *content_type; |
| 2426 | - GAppInfo *app_info = NULL; |
| 2427 | - gboolean must_support_uris = FALSE; |
| 2428 | - gchar *path; |
| 2429 | - |
| 2430 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 2431 | - |
| 2432 | - content_type = thunar_file_get_content_type (THUNAR_FILE (file)); |
| 2433 | - if (content_type != NULL) |
| 2434 | - { |
| 2435 | - path = g_file_get_path (file->gfile); |
| 2436 | - must_support_uris = (path == NULL); |
| 2437 | - g_free (path); |
| 2438 | - |
| 2439 | - app_info = g_app_info_get_default_for_type (content_type, must_support_uris); |
| 2440 | - } |
| 2441 | - |
| 2442 | - if (app_info == NULL) |
| 2443 | - app_info = g_file_query_default_handler (file->gfile, NULL, NULL); |
| 2444 | - |
| 2445 | - return app_info; |
| 2446 | -} |
| 2447 | - |
| 2448 | - |
| 2449 | - |
| 2450 | -/** |
| 2451 | - * thunar_file_get_kind: |
| 2452 | - * @file : a #ThunarFile instance. |
| 2453 | - * |
| 2454 | - * Returns the kind of @file. |
| 2455 | - * |
| 2456 | - * Return value: the kind of @file. |
| 2457 | - **/ |
| 2458 | -GFileType |
| 2459 | -thunar_file_get_kind (const ThunarFile *file) |
| 2460 | -{ |
| 2461 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), G_FILE_TYPE_UNKNOWN); |
| 2462 | - return file->kind; |
| 2463 | -} |
| 2464 | - |
| 2465 | - |
| 2466 | - |
| 2467 | -GFile * |
| 2468 | -thunar_file_get_target_location (const ThunarFile *file) |
| 2469 | -{ |
| 2470 | - const gchar *uri; |
| 2471 | - |
| 2472 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 2473 | - |
| 2474 | - if (file->info == NULL) |
| 2475 | - return g_object_ref (file->gfile); |
| 2476 | - |
| 2477 | - uri = g_file_info_get_attribute_string (file->info, |
| 2478 | - G_FILE_ATTRIBUTE_STANDARD_TARGET_URI); |
| 2479 | - |
| 2480 | - return (uri != NULL) ? g_file_new_for_uri (uri) : NULL; |
| 2481 | -} |
| 2482 | - |
| 2483 | - |
| 2484 | - |
| 2485 | -/** |
| 2486 | - * thunar_file_get_mode: |
| 2487 | - * @file : a #ThunarFile instance. |
| 2488 | - * |
| 2489 | - * Returns the permission bits of @file. |
| 2490 | - * |
| 2491 | - * Return value: the permission bits of @file. |
| 2492 | - **/ |
| 2493 | -ThunarFileMode |
| 2494 | -thunar_file_get_mode (const ThunarFile *file) |
| 2495 | -{ |
| 2496 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), 0); |
| 2497 | - |
| 2498 | - if (file->info == NULL) |
| 2499 | - return 0; |
| 2500 | - |
| 2501 | - if (g_file_info_has_attribute (file->info, G_FILE_ATTRIBUTE_UNIX_MODE)) |
| 2502 | - return g_file_info_get_attribute_uint32 (file->info, G_FILE_ATTRIBUTE_UNIX_MODE); |
| 2503 | - else |
| 2504 | - return thunar_file_is_directory (file) ? 0777 : 0666; |
| 2505 | -} |
| 2506 | - |
| 2507 | - |
| 2508 | - |
| 2509 | -gboolean |
| 2510 | -thunar_file_is_mounted (const ThunarFile *file) |
| 2511 | -{ |
| 2512 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2513 | - return FLAG_IS_SET (file, THUNAR_FILE_FLAG_IS_MOUNTED); |
| 2514 | -} |
| 2515 | - |
| 2516 | - |
| 2517 | - |
| 2518 | -gboolean |
| 2519 | -thunar_file_exists (const ThunarFile *file) |
| 2520 | -{ |
| 2521 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2522 | - return g_file_query_exists (file->gfile, NULL); |
| 2523 | -} |
| 2524 | - |
| 2525 | - |
| 2526 | - |
| 2527 | -/** |
| 2528 | - * thunar_file_is_directory: |
| 2529 | - * @file : a #ThunarFile instance. |
| 2530 | - * |
| 2531 | - * Checks whether @file refers to a directory. |
| 2532 | - * |
| 2533 | - * Return value: %TRUE if @file is a directory. |
| 2534 | - **/ |
| 2535 | -gboolean |
| 2536 | -thunar_file_is_directory (const ThunarFile *file) |
| 2537 | -{ |
| 2538 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2539 | - return file->kind == G_FILE_TYPE_DIRECTORY; |
| 2540 | -} |
| 2541 | - |
| 2542 | - |
| 2543 | - |
| 2544 | -/** |
| 2545 | - * thunar_file_is_shortcut: |
| 2546 | - * @file : a #ThunarFile instance. |
| 2547 | - * |
| 2548 | - * Checks whether @file refers to a shortcut to something else. |
| 2549 | - * |
| 2550 | - * Return value: %TRUE if @file is a shortcut. |
| 2551 | - **/ |
| 2552 | -gboolean |
| 2553 | -thunar_file_is_shortcut (const ThunarFile *file) |
| 2554 | -{ |
| 2555 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2556 | - return file->kind == G_FILE_TYPE_SHORTCUT; |
| 2557 | -} |
| 2558 | - |
| 2559 | - |
| 2560 | - |
| 2561 | -/** |
| 2562 | - * thunar_file_is_mountable: |
| 2563 | - * @file : a #ThunarFile instance. |
| 2564 | - * |
| 2565 | - * Checks whether @file refers to a mountable file/directory. |
| 2566 | - * |
| 2567 | - * Return value: %TRUE if @file is a mountable file/directory. |
| 2568 | - **/ |
| 2569 | -gboolean |
| 2570 | -thunar_file_is_mountable (const ThunarFile *file) |
| 2571 | -{ |
| 2572 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2573 | - return file->kind == G_FILE_TYPE_MOUNTABLE; |
| 2574 | -} |
| 2575 | - |
| 2576 | - |
| 2577 | - |
| 2578 | -/** |
| 2579 | - * thunar_file_is_local: |
| 2580 | - * @file : a #ThunarFile instance. |
| 2581 | - * |
| 2582 | - * Returns %TRUE if @file is a local file with the |
| 2583 | - * file:// URI scheme. |
| 2584 | - * |
| 2585 | - * Return value: %TRUE if @file is local. |
| 2586 | - **/ |
| 2587 | -gboolean |
| 2588 | -thunar_file_is_local (const ThunarFile *file) |
| 2589 | -{ |
| 2590 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2591 | - return g_file_has_uri_scheme (file->gfile, "file"); |
| 2592 | -} |
| 2593 | - |
| 2594 | - |
| 2595 | - |
| 2596 | -/** |
| 2597 | - * thunar_file_is_parent: |
| 2598 | - * @file : a #ThunarFile instance. |
| 2599 | - * @child : another #ThunarFile instance. |
| 2600 | - * |
| 2601 | - * Determines whether @file is the parent directory of @child. |
| 2602 | - * |
| 2603 | - * Return value: %TRUE if @file is the parent of @child. |
| 2604 | - **/ |
| 2605 | -gboolean |
| 2606 | -thunar_file_is_parent (const ThunarFile *file, |
| 2607 | - const ThunarFile *child) |
| 2608 | -{ |
| 2609 | - gboolean is_parent = FALSE; |
| 2610 | - GFile *parent; |
| 2611 | - |
| 2612 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2613 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (child), FALSE); |
| 2614 | - |
| 2615 | - parent = g_file_get_parent (child->gfile); |
| 2616 | - if (parent != NULL) |
| 2617 | - { |
| 2618 | - is_parent = g_file_equal (file->gfile, parent); |
| 2619 | - g_object_unref (parent); |
| 2620 | - } |
| 2621 | - |
| 2622 | - return is_parent; |
| 2623 | -} |
| 2624 | - |
| 2625 | - |
| 2626 | - |
| 2627 | -/** |
| 2628 | - * thunar_file_is_ancestor: |
| 2629 | - * @file : a #ThunarFile instance. |
| 2630 | - * @ancestor : another #GFile instance. |
| 2631 | - * |
| 2632 | - * Determines whether @file is somewhere inside @ancestor, |
| 2633 | - * possibly with intermediate folders. |
| 2634 | - * |
| 2635 | - * Return value: %TRUE if @ancestor contains @file as a |
| 2636 | - * child, grandchild, great grandchild, etc. |
| 2637 | - **/ |
| 2638 | -gboolean |
| 2639 | -thunar_file_is_gfile_ancestor (const ThunarFile *file, |
| 2640 | - GFile *ancestor) |
| 2641 | -{ |
| 2642 | - gboolean is_ancestor = FALSE; |
| 2643 | - GFile *current = NULL; |
| 2644 | - GFile *tmp; |
| 2645 | - |
| 2646 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2647 | - _thunar_return_val_if_fail (G_IS_FILE (ancestor), FALSE); |
| 2648 | - |
| 2649 | - for (current = g_object_ref (file->gfile); |
| 2650 | - is_ancestor == FALSE && current != NULL; |
| 2651 | - tmp = g_file_get_parent (current), g_object_unref (current), current = tmp) |
| 2652 | - { |
| 2653 | - if (G_UNLIKELY (g_file_equal (current, ancestor))) |
| 2654 | - is_ancestor = TRUE; |
| 2655 | - } |
| 2656 | - |
| 2657 | - if (current != NULL) |
| 2658 | - g_object_unref (current); |
| 2659 | - |
| 2660 | - return is_ancestor; |
| 2661 | -} |
| 2662 | - |
| 2663 | - |
| 2664 | - |
| 2665 | -/** |
| 2666 | - * thunar_file_is_ancestor: |
| 2667 | - * @file : a #ThunarFile instance. |
| 2668 | - * @ancestor : another #ThunarFile instance. |
| 2669 | - * |
| 2670 | - * Determines whether @file is somewhere inside @ancestor, |
| 2671 | - * possibly with intermediate folders. |
| 2672 | - * |
| 2673 | - * Return value: %TRUE if @ancestor contains @file as a |
| 2674 | - * child, grandchild, great grandchild, etc. |
| 2675 | - **/ |
| 2676 | -gboolean |
| 2677 | -thunar_file_is_ancestor (const ThunarFile *file, |
| 2678 | - const ThunarFile *ancestor) |
| 2679 | -{ |
| 2680 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2681 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (ancestor), FALSE); |
| 2682 | - |
| 2683 | - return thunar_file_is_gfile_ancestor (file, ancestor->gfile); |
| 2684 | -} |
| 2685 | - |
| 2686 | - |
| 2687 | - |
| 2688 | -/** |
| 2689 | - * thunar_file_is_executable: |
| 2690 | - * @file : a #ThunarFile instance. |
| 2691 | - * |
| 2692 | - * Determines whether the owner of the current process is allowed |
| 2693 | - * to execute the @file (or enter the directory refered to by |
| 2694 | - * @file). On UNIX it also returns %TRUE if @file refers to a |
| 2695 | - * desktop entry. |
| 2696 | - * |
| 2697 | - * Return value: %TRUE if @file can be executed. |
| 2698 | - **/ |
| 2699 | -gboolean |
| 2700 | -thunar_file_is_executable (const ThunarFile *file) |
| 2701 | -{ |
| 2702 | - gboolean can_execute = FALSE; |
| 2703 | - const gchar *content_type; |
| 2704 | - |
| 2705 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2706 | - |
| 2707 | - if (file->info == NULL) |
| 2708 | - return FALSE; |
| 2709 | - |
| 2710 | - if (g_file_info_get_attribute_boolean (file->info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE)) |
| 2711 | - { |
| 2712 | - /* get the content type of the file */ |
| 2713 | - content_type = thunar_file_get_content_type (THUNAR_FILE (file)); |
| 2714 | - if (G_LIKELY (content_type != NULL)) |
| 2715 | - { |
| 2716 | -#ifdef G_OS_WIN32 |
| 2717 | - /* check for .exe, .bar or .com */ |
| 2718 | - can_execute = g_content_type_can_be_executable (content_type); |
| 2719 | -#else |
| 2720 | - /* check if the content type is save to execute, we don't use |
| 2721 | - * g_content_type_can_be_executable() for unix because it also returns |
| 2722 | - * true for "text/plain" and we don't want that */ |
| 2723 | - if (g_content_type_is_a (content_type, "application/x-executable") |
| 2724 | - || g_content_type_is_a (content_type, "application/x-shellscript")) |
| 2725 | - { |
| 2726 | - can_execute = TRUE; |
| 2727 | - } |
| 2728 | -#endif |
| 2729 | - } |
| 2730 | - } |
| 2731 | - |
| 2732 | - return can_execute || thunar_file_is_desktop_file (file, NULL); |
| 2733 | -} |
| 2734 | - |
| 2735 | - |
| 2736 | - |
| 2737 | -/** |
| 2738 | - * thunar_file_is_readable: |
| 2739 | - * @file : a #ThunarFile instance. |
| 2740 | - * |
| 2741 | - * Determines whether the owner of the current process is allowed |
| 2742 | - * to read the @file. |
| 2743 | - * |
| 2744 | - * Return value: %TRUE if @file can be read. |
| 2745 | - **/ |
| 2746 | -static gboolean |
| 2747 | -thunar_file_is_readable (const ThunarFile *file) |
| 2748 | -{ |
| 2749 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2750 | - |
| 2751 | - if (file->info == NULL) |
| 2752 | - return FALSE; |
| 2753 | - |
| 2754 | - if (!g_file_info_has_attribute (file->info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ)) |
| 2755 | - return TRUE; |
| 2756 | - |
| 2757 | - return g_file_info_get_attribute_boolean (file->info, |
| 2758 | - G_FILE_ATTRIBUTE_ACCESS_CAN_READ); |
| 2759 | -} |
| 2760 | - |
| 2761 | - |
| 2762 | - |
| 2763 | -/** |
| 2764 | - * thunar_file_is_writable: |
| 2765 | - * @file : a #ThunarFile instance. |
| 2766 | - * |
| 2767 | - * Determines whether the owner of the current process is allowed |
| 2768 | - * to write the @file. |
| 2769 | - * |
| 2770 | - * Return value: %TRUE if @file can be read. |
| 2771 | - **/ |
| 2772 | -gboolean |
| 2773 | -thunar_file_is_writable (const ThunarFile *file) |
| 2774 | -{ |
| 2775 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2776 | - |
| 2777 | - if (file->info == NULL) |
| 2778 | - return FALSE; |
| 2779 | - |
| 2780 | - if (!g_file_info_has_attribute (file->info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE)) |
| 2781 | - return TRUE; |
| 2782 | - |
| 2783 | - return g_file_info_get_attribute_boolean (file->info, |
| 2784 | - G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE); |
| 2785 | -} |
| 2786 | - |
| 2787 | - |
| 2788 | - |
| 2789 | -/** |
| 2790 | - * thunar_file_is_hidden: |
| 2791 | - * @file : a #ThunarFile instance. |
| 2792 | - * |
| 2793 | - * Checks whether @file can be considered a hidden file. |
| 2794 | - * |
| 2795 | - * Return value: %TRUE if @file is a hidden file, else %FALSE. |
| 2796 | - **/ |
| 2797 | -gboolean |
| 2798 | -thunar_file_is_hidden (const ThunarFile *file) |
| 2799 | -{ |
| 2800 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2801 | - |
| 2802 | - if (file->info == NULL) |
| 2803 | - return FALSE; |
| 2804 | - |
| 2805 | - return g_file_info_get_is_hidden (file->info) |
| 2806 | - || g_file_info_get_is_backup (file->info); |
| 2807 | -} |
| 2808 | - |
| 2809 | - |
| 2810 | - |
| 2811 | -/** |
| 2812 | - * thunar_file_is_home: |
| 2813 | - * @file : a #ThunarFile. |
| 2814 | - * |
| 2815 | - * Checks whether @file refers to the users home directory. |
| 2816 | - * |
| 2817 | - * Return value: %TRUE if @file is the users home directory. |
| 2818 | - **/ |
| 2819 | -gboolean |
| 2820 | -thunar_file_is_home (const ThunarFile *file) |
| 2821 | -{ |
| 2822 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2823 | - return thunar_g_file_is_home (file->gfile); |
| 2824 | -} |
| 2825 | - |
| 2826 | - |
| 2827 | - |
| 2828 | -/** |
| 2829 | - * thunar_file_is_regular: |
| 2830 | - * @file : a #ThunarFile. |
| 2831 | - * |
| 2832 | - * Checks whether @file refers to a regular file. |
| 2833 | - * |
| 2834 | - * Return value: %TRUE if @file is a regular file. |
| 2835 | - **/ |
| 2836 | -gboolean |
| 2837 | -thunar_file_is_regular (const ThunarFile *file) |
| 2838 | -{ |
| 2839 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2840 | - return file->kind == G_FILE_TYPE_REGULAR; |
| 2841 | -} |
| 2842 | - |
| 2843 | - |
| 2844 | - |
| 2845 | -/** |
| 2846 | - * thunar_file_is_trashed: |
| 2847 | - * @file : a #ThunarFile instance. |
| 2848 | - * |
| 2849 | - * Returns %TRUE if @file is a local file that resides in |
| 2850 | - * the trash bin. |
| 2851 | - * |
| 2852 | - * Return value: %TRUE if @file is in the trash, or |
| 2853 | - * the trash folder itself. |
| 2854 | - **/ |
| 2855 | -gboolean |
| 2856 | -thunar_file_is_trashed (const ThunarFile *file) |
| 2857 | -{ |
| 2858 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2859 | - return thunar_g_file_is_trashed (file->gfile); |
| 2860 | -} |
| 2861 | - |
| 2862 | - |
| 2863 | - |
| 2864 | -/** |
| 2865 | - * thunar_file_is_desktop_file: |
| 2866 | - * @file : a #ThunarFile. |
| 2867 | - * @is_secure : if %NULL do a simple check, else it will set this boolean |
| 2868 | - * to indicate if the desktop file is safe see bug #5012 |
| 2869 | - * for more info. |
| 2870 | - * |
| 2871 | - * Returns %TRUE if @file is a .desktop file. The @is_secure return value |
| 2872 | - * will tell if the .desktop file is also secure. |
| 2873 | - * |
| 2874 | - * Return value: %TRUE if @file is a .desktop file. |
| 2875 | - **/ |
| 2876 | -gboolean |
| 2877 | -thunar_file_is_desktop_file (const ThunarFile *file, |
| 2878 | - gboolean *is_secure) |
| 2879 | -{ |
| 2880 | - const gchar * const *data_dirs; |
| 2881 | - guint n; |
| 2882 | - gchar *path; |
| 2883 | - |
| 2884 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2885 | - |
| 2886 | - if (file->info == NULL) |
| 2887 | - return FALSE; |
| 2888 | - |
| 2889 | - /* only allow regular files with a .desktop extension */ |
| 2890 | - if (!g_str_has_suffix (file->basename, ".desktop") |
| 2891 | - || file->kind != G_FILE_TYPE_REGULAR) |
| 2892 | - return FALSE; |
| 2893 | - |
| 2894 | - /* don't check more if not needed */ |
| 2895 | - if (is_secure == NULL) |
| 2896 | - return TRUE; |
| 2897 | - |
| 2898 | - /* desktop files outside xdg directories need to be executable for security reasons */ |
| 2899 | - if (g_file_info_get_attribute_boolean (file->info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE)) |
| 2900 | - { |
| 2901 | - /* has +x */ |
| 2902 | - *is_secure = TRUE; |
| 2903 | - } |
| 2904 | - else |
| 2905 | - { |
| 2906 | - /* assume the file is not safe */ |
| 2907 | - *is_secure = FALSE; |
| 2908 | - |
| 2909 | - /* deskopt files in xdg directories are also fine... */ |
| 2910 | - if (g_file_is_native (thunar_file_get_file (file))) |
| 2911 | - { |
| 2912 | - data_dirs = g_get_system_data_dirs (); |
| 2913 | - if (G_LIKELY (data_dirs != NULL)) |
| 2914 | - { |
| 2915 | - path = g_file_get_path (thunar_file_get_file (file)); |
| 2916 | - for (n = 0; data_dirs[n] != NULL; n++) |
| 2917 | - { |
| 2918 | - if (g_str_has_prefix (path, data_dirs[n])) |
| 2919 | - { |
| 2920 | - /* has known prefix, can launch without problems */ |
| 2921 | - *is_secure = TRUE; |
| 2922 | - break; |
| 2923 | - } |
| 2924 | - } |
| 2925 | - g_free (path); |
| 2926 | - } |
| 2927 | - } |
| 2928 | - } |
| 2929 | - |
| 2930 | - return TRUE; |
| 2931 | -} |
| 2932 | - |
| 2933 | - |
| 2934 | - |
| 2935 | -/** |
| 2936 | - * thunar_file_get_display_name: |
| 2937 | - * @file : a #ThunarFile instance. |
| 2938 | - * |
| 2939 | - * Returns the @file name in the UTF-8 encoding, which is |
| 2940 | - * suitable for displaying the file name in the GUI. |
| 2941 | - * |
| 2942 | - * Return value: the @file name suitable for display. |
| 2943 | - **/ |
| 2944 | -const gchar * |
| 2945 | -thunar_file_get_display_name (const ThunarFile *file) |
| 2946 | -{ |
| 2947 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 2948 | - return file->display_name; |
| 2949 | -} |
| 2950 | - |
| 2951 | - |
| 2952 | - |
| 2953 | -/** |
| 2954 | - * thunar_file_get_deletion_date: |
| 2955 | - * @file : a #ThunarFile instance. |
| 2956 | - * @date_style : the style used to format the date. |
| 2957 | - * |
| 2958 | - * Returns the deletion date of the @file if the @file |
| 2959 | - * is located in the trash. Otherwise %NULL will be |
| 2960 | - * returned. |
| 2961 | - * |
| 2962 | - * The caller is responsible to free the returned string |
| 2963 | - * using g_free() when no longer needed. |
| 2964 | - * |
| 2965 | - * Return value: the deletion date of @file if @file is |
| 2966 | - * in the trash, %NULL otherwise. |
| 2967 | - **/ |
| 2968 | -gchar* |
| 2969 | -thunar_file_get_deletion_date (const ThunarFile *file, |
| 2970 | - ThunarDateStyle date_style) |
| 2971 | -{ |
| 2972 | - const gchar *date; |
| 2973 | - time_t deletion_time; |
| 2974 | - |
| 2975 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 2976 | - _thunar_return_val_if_fail (G_IS_FILE_INFO (file->info), NULL); |
| 2977 | - |
| 2978 | - date = g_file_info_get_attribute_string (file->info, G_FILE_ATTRIBUTE_TRASH_DELETION_DATE); |
| 2979 | - if (G_UNLIKELY (date == NULL)) |
| 2980 | - return NULL; |
| 2981 | - |
| 2982 | - /* try to parse the DeletionDate (RFC 3339 string) */ |
| 2983 | - deletion_time = thunar_util_time_from_rfc3339 (date); |
| 2984 | - |
| 2985 | - /* humanize the time value */ |
| 2986 | - return thunar_util_humanize_file_time (deletion_time, date_style); |
| 2987 | -} |
| 2988 | - |
| 2989 | - |
| 2990 | - |
| 2991 | -/** |
| 2992 | - * thunar_file_get_original_path: |
| 2993 | - * @file : a #ThunarFile instance. |
| 2994 | - * |
| 2995 | - * Returns the original path of the @file if the @file |
| 2996 | - * is located in the trash. Otherwise %NULL will be |
| 2997 | - * returned. |
| 2998 | - * |
| 2999 | - * Return value: the original path of @file if @file is |
| 3000 | - * in the trash, %NULL otherwise. |
| 3001 | - **/ |
| 3002 | -const gchar * |
| 3003 | -thunar_file_get_original_path (const ThunarFile *file) |
| 3004 | -{ |
| 3005 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 3006 | - |
| 3007 | - if (file->info == NULL) |
| 3008 | - return NULL; |
| 3009 | - |
| 3010 | - return g_file_info_get_attribute_byte_string (file->info, G_FILE_ATTRIBUTE_TRASH_ORIG_PATH); |
| 3011 | -} |
| 3012 | - |
| 3013 | - |
| 3014 | - |
| 3015 | -/** |
| 3016 | - * thunar_file_get_item_count: |
| 3017 | - * @file : a #ThunarFile instance. |
| 3018 | - * |
| 3019 | - * Returns the number of items in the trash, if @file refers to the |
| 3020 | - * trash root directory. Otherwise returns 0. |
| 3021 | - * |
| 3022 | - * Return value: number of files in the trash if @file is the trash |
| 3023 | - * root dir, 0 otherwise. |
| 3024 | - **/ |
| 3025 | -guint32 |
| 3026 | -thunar_file_get_item_count (const ThunarFile *file) |
| 3027 | -{ |
| 3028 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), 0); |
| 3029 | - |
| 3030 | - if (file->info == NULL) |
| 3031 | - return 0; |
| 3032 | - |
| 3033 | - return g_file_info_get_attribute_uint32 (file->info, |
| 3034 | - G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT); |
| 3035 | -} |
| 3036 | - |
| 3037 | - |
| 3038 | - |
| 3039 | -/** |
| 3040 | - * thunar_file_is_chmodable: |
| 3041 | - * @file : a #ThunarFile instance. |
| 3042 | - * |
| 3043 | - * Determines whether the owner of the current process is allowed |
| 3044 | - * to changed the file mode of @file. |
| 3045 | - * |
| 3046 | - * Return value: %TRUE if the mode of @file can be changed. |
| 3047 | - **/ |
| 3048 | -gboolean |
| 3049 | -thunar_file_is_chmodable (const ThunarFile *file) |
| 3050 | -{ |
| 3051 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 3052 | - |
| 3053 | - /* we can only change the mode if we the euid is |
| 3054 | - * a) equal to the file owner id |
| 3055 | - * or |
| 3056 | - * b) the super-user id |
| 3057 | - * and the file is not in the trash. |
| 3058 | - */ |
| 3059 | - if (file->info == NULL) |
| 3060 | - { |
| 3061 | - return (effective_user_id == 0 && !thunar_file_is_trashed (file)); |
| 3062 | - } |
| 3063 | - else |
| 3064 | - { |
| 3065 | - return ((effective_user_id == 0 |
| 3066 | - || effective_user_id == g_file_info_get_attribute_uint32 (file->info, |
| 3067 | - G_FILE_ATTRIBUTE_UNIX_UID)) |
| 3068 | - && !thunar_file_is_trashed (file)); |
| 3069 | - } |
| 3070 | -} |
| 3071 | - |
| 3072 | - |
| 3073 | - |
| 3074 | -/** |
| 3075 | - * thunar_file_is_renameable: |
| 3076 | - * @file : a #ThunarFile instance. |
| 3077 | - * |
| 3078 | - * Determines whether @file can be renamed using |
| 3079 | - * #thunar_file_rename(). Note that the return |
| 3080 | - * value is just a guess and #thunar_file_rename() |
| 3081 | - * may fail even if this method returns %TRUE. |
| 3082 | - * |
| 3083 | - * Return value: %TRUE if @file can be renamed. |
| 3084 | - **/ |
| 3085 | -gboolean |
| 3086 | -thunar_file_is_renameable (const ThunarFile *file) |
| 3087 | -{ |
| 3088 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 3089 | - |
| 3090 | - if (file->info == NULL) |
| 3091 | - return FALSE; |
| 3092 | - |
| 3093 | - return g_file_info_get_attribute_boolean (file->info, |
| 3094 | - G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME); |
| 3095 | -} |
| 3096 | - |
| 3097 | - |
| 3098 | - |
| 3099 | -gboolean |
| 3100 | -thunar_file_can_be_trashed (const ThunarFile *file) |
| 3101 | -{ |
| 3102 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 3103 | - |
| 3104 | - if (file->info == NULL) |
| 3105 | - return FALSE; |
| 3106 | - |
| 3107 | - return g_file_info_get_attribute_boolean (file->info, |
| 3108 | - G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH); |
| 3109 | -} |
| 3110 | - |
| 3111 | - |
| 3112 | - |
| 3113 | -/** |
| 3114 | - * thunar_file_get_emblem_names: |
| 3115 | - * @file : a #ThunarFile instance. |
| 3116 | - * |
| 3117 | - * Determines the names of the emblems that should be displayed for |
| 3118 | - * @file. The returned list is owned by the caller, but the list |
| 3119 | - * items - the name strings - are owned by @file. So the caller |
| 3120 | - * must call g_list_free(), but don't g_free() the list items. |
| 3121 | - * |
| 3122 | - * Note that the strings contained in the returned list are |
| 3123 | - * not garantied to exist over the next iteration of the main |
| 3124 | - * loop. So in case you need the list of emblem names for |
| 3125 | - * a longer time, you'll need to take a copy of the strings. |
| 3126 | - * |
| 3127 | - * Return value: the names of the emblems for @file. |
| 3128 | - **/ |
| 3129 | -GList* |
| 3130 | -thunar_file_get_emblem_names (ThunarFile *file) |
| 3131 | -{ |
| 3132 | - guint32 uid; |
| 3133 | - gchar **emblem_names; |
| 3134 | - GList *emblems = NULL; |
| 3135 | - |
| 3136 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 3137 | - |
| 3138 | - /* leave if there is no info */ |
| 3139 | - if (file->info == NULL) |
| 3140 | - return NULL; |
| 3141 | - |
| 3142 | - /* determine the custom emblems */ |
| 3143 | - emblem_names = g_file_info_get_attribute_stringv (file->info, "metadata::emblems"); |
| 3144 | - if (G_UNLIKELY (emblem_names != NULL)) |
| 3145 | - { |
| 3146 | - for (; *emblem_names != NULL; ++emblem_names) |
| 3147 | - emblems = g_list_append (emblems, *emblem_names); |
| 3148 | - } |
| 3149 | - |
| 3150 | - if (thunar_file_is_symlink (file)) |
| 3151 | - emblems = g_list_prepend (emblems, THUNAR_FILE_EMBLEM_NAME_SYMBOLIC_LINK); |
| 3152 | - |
| 3153 | - /* determine the user ID of the file owner */ |
| 3154 | - /* TODO what are we going to do here on non-UNIX systems? */ |
| 3155 | - uid = file->info != NULL |
| 3156 | - ? g_file_info_get_attribute_uint32 (file->info, G_FILE_ATTRIBUTE_UNIX_UID) |
| 3157 | - : 0; |
| 3158 | - |
| 3159 | - /* we add "cant-read" if either (a) the file is not readable or (b) a directory, that lacks the |
| 3160 | - * x-bit, see http://bugzilla.xfce.org/show_bug.cgi?id=1408 for the details about this change. |
| 3161 | - */ |
| 3162 | - if (!thunar_file_is_readable (file) |
| 3163 | - || (thunar_file_is_directory (file) |
| 3164 | - && thunar_file_denies_access_permission (file, THUNAR_FILE_MODE_USR_EXEC, |
| 3165 | - THUNAR_FILE_MODE_GRP_EXEC, |
| 3166 | - THUNAR_FILE_MODE_OTH_EXEC))) |
| 3167 | - { |
| 3168 | - emblems = g_list_prepend (emblems, THUNAR_FILE_EMBLEM_NAME_CANT_READ); |
| 3169 | - } |
| 3170 | - else if (G_UNLIKELY (uid == effective_user_id && !thunar_file_is_writable (file))) |
| 3171 | - { |
| 3172 | - /* we own the file, but we cannot write to it, that's why we mark it as "cant-write", so |
| 3173 | - * users won't be surprised when opening the file in a text editor, but are unable to save. |
| 3174 | - */ |
| 3175 | - emblems = g_list_prepend (emblems, THUNAR_FILE_EMBLEM_NAME_CANT_WRITE); |
| 3176 | - } |
| 3177 | - |
| 3178 | - return emblems; |
| 3179 | -} |
| 3180 | - |
| 3181 | - |
| 3182 | - |
| 3183 | -/** |
| 3184 | - * thunar_file_set_emblem_names: |
| 3185 | - * @file : a #ThunarFile instance. |
| 3186 | - * @emblem_names : a #GList of emblem names. |
| 3187 | - * |
| 3188 | - * Sets the custom emblem name list of @file to @emblem_names |
| 3189 | - * and stores them in the @file<!---->s metadata. |
| 3190 | - **/ |
| 3191 | -void |
| 3192 | -thunar_file_set_emblem_names (ThunarFile *file, |
| 3193 | - GList *emblem_names) |
| 3194 | -{ |
| 3195 | - GList *lp; |
| 3196 | - gchar **emblems = NULL; |
| 3197 | - gint n; |
| 3198 | - GFileInfo *info; |
| 3199 | - |
| 3200 | - _thunar_return_if_fail (THUNAR_IS_FILE (file)); |
| 3201 | - _thunar_return_if_fail (G_IS_FILE_INFO (file->info)); |
| 3202 | - |
| 3203 | - /* allocate a zero-terminated array for the emblem names */ |
| 3204 | - emblems = g_new0 (gchar *, g_list_length (emblem_names) + 1); |
| 3205 | - |
| 3206 | - /* turn the emblem_names list into a zero terminated array */ |
| 3207 | - for (lp = emblem_names, n = 0; lp != NULL; lp = lp->next) |
| 3208 | - { |
| 3209 | - /* skip special emblems */ |
| 3210 | - if (strcmp (lp->data, THUNAR_FILE_EMBLEM_NAME_SYMBOLIC_LINK) == 0 |
| 3211 | - || strcmp (lp->data, THUNAR_FILE_EMBLEM_NAME_CANT_READ) == 0 |
| 3212 | - || strcmp (lp->data, THUNAR_FILE_EMBLEM_NAME_CANT_WRITE) == 0 |
| 3213 | - || strcmp (lp->data, THUNAR_FILE_EMBLEM_NAME_DESKTOP) == 0) |
| 3214 | - continue; |
| 3215 | - |
| 3216 | - /* add the emblem to our list */ |
| 3217 | - emblems[n++] = g_strdup (lp->data); |
| 3218 | - } |
| 3219 | - |
| 3220 | - /* set the value in the current info */ |
| 3221 | - if (n == 0) |
| 3222 | - g_file_info_remove_attribute (file->info, "metadata::emblems"); |
| 3223 | - else |
| 3224 | - g_file_info_set_attribute_stringv (file->info, "metadata::emblems", emblems); |
| 3225 | - |
| 3226 | - /* set meta data to the daemon */ |
| 3227 | - info = g_file_info_new (); |
| 3228 | - g_file_info_set_attribute_stringv (info, "metadata::emblems", emblems); |
| 3229 | - g_file_set_attributes_async (file->gfile, info, |
| 3230 | - G_FILE_QUERY_INFO_NONE, |
| 3231 | - G_PRIORITY_DEFAULT, |
| 3232 | - NULL, |
| 3233 | - thunar_file_set_emblem_names_ready, |
| 3234 | - file); |
| 3235 | - g_object_unref (G_OBJECT (info)); |
| 3236 | - |
| 3237 | - g_strfreev (emblems); |
| 3238 | -} |
| 3239 | - |
| 3240 | - |
| 3241 | - |
| 3242 | -/** |
| 3243 | - * thunar_file_set_custom_icon: |
| 3244 | - * @file : a #ThunarFile instance. |
| 3245 | - * @custom_icon : the new custom icon for the @file. |
| 3246 | - * @error : return location for errors or %NULL. |
| 3247 | - * |
| 3248 | - * Tries to change the custom icon of the .desktop file referred |
| 3249 | - * to by @file. If that fails, %FALSE is returned and the |
| 3250 | - * @error is set accordingly. |
| 3251 | - * |
| 3252 | - * Return value: %TRUE if the icon of @file was changed, %FALSE otherwise. |
| 3253 | - **/ |
| 3254 | -gboolean |
| 3255 | -thunar_file_set_custom_icon (ThunarFile *file, |
| 3256 | - const gchar *custom_icon, |
| 3257 | - GError **error) |
| 3258 | -{ |
| 3259 | - GKeyFile *key_file; |
| 3260 | - |
| 3261 | - _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
| 3262 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE); |
| 3263 | - _thunar_return_val_if_fail (custom_icon != NULL, FALSE); |
| 3264 | - |
| 3265 | - key_file = thunar_g_file_query_key_file (file->gfile, NULL, error); |
| 3266 | - |
| 3267 | - if (key_file == NULL) |
| 3268 | - return FALSE; |
| 3269 | - |
| 3270 | - g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP, |
| 3271 | - G_KEY_FILE_DESKTOP_KEY_ICON, custom_icon); |
| 3272 | - |
| 3273 | - if (thunar_g_file_write_key_file (file->gfile, key_file, NULL, error)) |
| 3274 | - { |
| 3275 | - /* tell everybody that we have changed */ |
| 3276 | - thunar_file_changed (file); |
| 3277 | - |
| 3278 | - g_key_file_free (key_file); |
| 3279 | - return TRUE; |
| 3280 | - } |
| 3281 | - else |
| 3282 | - { |
| 3283 | - g_key_file_free (key_file); |
| 3284 | - return FALSE; |
| 3285 | - } |
| 3286 | -} |
| 3287 | - |
| 3288 | - |
| 3289 | -/** |
| 3290 | - * thunar_file_is_desktop: |
| 3291 | - * @file : a #ThunarFile. |
| 3292 | - * |
| 3293 | - * Checks whether @file refers to the users desktop directory. |
| 3294 | - * |
| 3295 | - * Return value: %TRUE if @file is the users desktop directory. |
| 3296 | - **/ |
| 3297 | -gboolean |
| 3298 | -thunar_file_is_desktop (const ThunarFile *file) |
| 3299 | -{ |
| 3300 | - GFile *desktop; |
| 3301 | - gboolean is_desktop = FALSE; |
| 3302 | - |
| 3303 | - desktop = g_file_new_for_path (g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP)); |
| 3304 | - is_desktop = g_file_equal (file->gfile, desktop); |
| 3305 | - g_object_unref (desktop); |
| 3306 | - |
| 3307 | - return is_desktop; |
| 3308 | -} |
| 3309 | - |
| 3310 | - |
| 3311 | - |
| 3312 | -const gchar * |
| 3313 | -thunar_file_get_thumbnail_path (ThunarFile *file) |
| 3314 | -{ |
| 3315 | - GChecksum *checksum; |
| 3316 | - gchar *basename; |
| 3317 | - gchar *uri; |
| 3318 | - |
| 3319 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 3320 | - |
| 3321 | - /* if the thumbstate is known to be not there, return null */ |
| 3322 | - if (thunar_file_get_thumb_state (file) == THUNAR_FILE_THUMB_STATE_NONE) |
| 3323 | - return NULL; |
| 3324 | - |
| 3325 | - if (G_UNLIKELY (file->thumbnail_path == NULL)) |
| 3326 | - { |
| 3327 | - checksum = g_checksum_new (G_CHECKSUM_MD5); |
| 3328 | - if (G_LIKELY (checksum != NULL)) |
| 3329 | - { |
| 3330 | - uri = thunar_file_dup_uri (file); |
| 3331 | - g_checksum_update (checksum, (const guchar *) uri, strlen (uri)); |
| 3332 | - g_free (uri); |
| 3333 | - |
| 3334 | - basename = g_strconcat (g_checksum_get_string (checksum), ".png", NULL); |
| 3335 | - g_checksum_free (checksum); |
| 3336 | - |
| 3337 | - file->thumbnail_path = g_build_filename (xfce_get_homedir (), ".thumbnails", |
| 3338 | - "normal", basename, NULL); |
| 3339 | - |
| 3340 | - g_free (basename); |
| 3341 | - } |
| 3342 | - } |
| 3343 | - |
| 3344 | - return file->thumbnail_path; |
| 3345 | -} |
| 3346 | - |
| 3347 | - |
| 3348 | - |
| 3349 | -/** |
| 3350 | - * thunar_file_get_thumb_state: |
| 3351 | - * @file : a #ThunarFile. |
| 3352 | - * |
| 3353 | - * Returns the current #ThunarFileThumbState for @file. This |
| 3354 | - * method is intended to be used by #ThunarIconFactory only. |
| 3355 | - * |
| 3356 | - * Return value: the #ThunarFileThumbState for @file. |
| 3357 | - **/ |
| 3358 | -ThunarFileThumbState |
| 3359 | -thunar_file_get_thumb_state (const ThunarFile *file) |
| 3360 | -{ |
| 3361 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), THUNAR_FILE_THUMB_STATE_UNKNOWN); |
| 3362 | - return FLAG_GET_THUMB_STATE (file); |
| 3363 | -} |
| 3364 | - |
| 3365 | - |
| 3366 | - |
| 3367 | -/** |
| 3368 | - * thunar_file_set_thumb_state: |
| 3369 | - * @file : a #ThunarFile. |
| 3370 | - * @thumb_state : the new #ThunarFileThumbState. |
| 3371 | - * |
| 3372 | - * Sets the #ThunarFileThumbState for @file to @thumb_state. |
| 3373 | - * This will cause a "file-changed" signal to be emitted from |
| 3374 | - * #ThunarFileMonitor. |
| 3375 | - **/ |
| 3376 | -void |
| 3377 | -thunar_file_set_thumb_state (ThunarFile *file, |
| 3378 | - ThunarFileThumbState state) |
| 3379 | -{ |
| 3380 | - _thunar_return_if_fail (THUNAR_IS_FILE (file)); |
| 3381 | - |
| 3382 | - /* check if the state changes */ |
| 3383 | - if (thunar_file_get_thumb_state (file) == state) |
| 3384 | - return; |
| 3385 | - |
| 3386 | - /* set the new thumbnail state */ |
| 3387 | - FLAG_SET_THUMB_STATE (file, state); |
| 3388 | - |
| 3389 | - /* remove path if the type is not supported */ |
| 3390 | - if (state == THUNAR_FILE_THUMB_STATE_NONE |
| 3391 | - && file->thumbnail_path != NULL) |
| 3392 | - { |
| 3393 | - g_free (file->thumbnail_path); |
| 3394 | - file->thumbnail_path = NULL; |
| 3395 | - } |
| 3396 | - |
| 3397 | - /* if the file has a thumbnail, reload it */ |
| 3398 | - if (state == THUNAR_FILE_THUMB_STATE_READY) |
| 3399 | - thunar_file_monitor_file_changed (file); |
| 3400 | -} |
| 3401 | - |
| 3402 | - |
| 3403 | - |
| 3404 | -/** |
| 3405 | - * thunar_file_get_custom_icon: |
| 3406 | - * @file : a #ThunarFile instance. |
| 3407 | - * |
| 3408 | - * Queries the custom icon from @file if any, else %NULL is returned. |
| 3409 | - * The custom icon can be either a themed icon name or an absolute path |
| 3410 | - * to an icon file in the local file system. |
| 3411 | - * |
| 3412 | - * Return value: the custom icon for @file or %NULL. |
| 3413 | - **/ |
| 3414 | -const gchar * |
| 3415 | -thunar_file_get_custom_icon (const ThunarFile *file) |
| 3416 | -{ |
| 3417 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 3418 | - return file->custom_icon_name; |
| 3419 | -} |
| 3420 | - |
| 3421 | - |
| 3422 | - |
| 3423 | -/** |
| 3424 | - * thunar_file_get_preview_icon: |
| 3425 | - * @file : a #ThunarFile instance. |
| 3426 | - * |
| 3427 | - * Returns the preview icon for @file if any, else %NULL is returned. |
| 3428 | - * |
| 3429 | - * Return value: the custom icon for @file or %NULL, the GIcon is owner |
| 3430 | - * by the file, so do not unref it. |
| 3431 | - **/ |
| 3432 | -GIcon * |
| 3433 | -thunar_file_get_preview_icon (const ThunarFile *file) |
| 3434 | -{ |
| 3435 | - GObject *icon; |
| 3436 | - |
| 3437 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 3438 | - _thunar_return_val_if_fail (G_IS_FILE_INFO (file->info), NULL); |
| 3439 | - |
| 3440 | - icon = g_file_info_get_attribute_object (file->info, G_FILE_ATTRIBUTE_PREVIEW_ICON); |
| 3441 | - if (G_LIKELY (icon != NULL)) |
| 3442 | - return G_ICON (icon); |
| 3443 | - |
| 3444 | - return NULL; |
| 3445 | -} |
| 3446 | - |
| 3447 | - |
| 3448 | - |
| 3449 | -GFilesystemPreviewType |
| 3450 | -thunar_file_get_preview_type (const ThunarFile *file) |
| 3451 | -{ |
| 3452 | - GFilesystemPreviewType preview; |
| 3453 | - GFileInfo *info; |
| 3454 | - |
| 3455 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), G_FILESYSTEM_PREVIEW_TYPE_NEVER); |
| 3456 | - _thunar_return_val_if_fail (G_IS_FILE (file->gfile), G_FILESYSTEM_PREVIEW_TYPE_NEVER); |
| 3457 | - |
| 3458 | - info = g_file_query_filesystem_info (file->gfile, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, NULL, NULL); |
| 3459 | - if (G_LIKELY (info != NULL)) |
| 3460 | - { |
| 3461 | - preview = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW); |
| 3462 | - g_object_unref (G_OBJECT (info)); |
| 3463 | - } |
| 3464 | - else |
| 3465 | - { |
| 3466 | - /* assume we don't know */ |
| 3467 | - preview = G_FILESYSTEM_PREVIEW_TYPE_NEVER; |
| 3468 | - } |
| 3469 | - |
| 3470 | - return preview; |
| 3471 | -} |
| 3472 | - |
| 3473 | - |
| 3474 | - |
| 3475 | -static const gchar * |
| 3476 | -thunar_file_get_icon_name_for_state (const gchar *icon_name, |
| 3477 | - ThunarFileIconState icon_state) |
| 3478 | -{ |
| 3479 | - if (exo_str_is_empty (icon_name)) |
| 3480 | - return NULL; |
| 3481 | - |
| 3482 | - /* check if we have an accept icon for the icon we found */ |
| 3483 | - if (icon_state != THUNAR_FILE_ICON_STATE_DEFAULT |
| 3484 | - && (strcmp (icon_name, "inode-directory") == 0 |
| 3485 | - || strcmp (icon_name, "folder") == 0)) |
| 3486 | - { |
| 3487 | - if (icon_state == THUNAR_FILE_ICON_STATE_DROP) |
| 3488 | - return "folder-drag-accept"; |
| 3489 | - else if (icon_state == THUNAR_FILE_ICON_STATE_OPEN) |
| 3490 | - return "folder-open"; |
| 3491 | - } |
| 3492 | - |
| 3493 | - return icon_name; |
| 3494 | -} |
| 3495 | - |
| 3496 | - |
| 3497 | - |
| 3498 | -/** |
| 3499 | - * thunar_file_get_icon_name: |
| 3500 | - * @file : a #ThunarFile instance. |
| 3501 | - * @icon_state : the state of the @file<!---->s icon we are interested in. |
| 3502 | - * @icon_theme : the #GtkIconTheme on which to lookup up the icon name. |
| 3503 | - * |
| 3504 | - * Returns the name of the icon that can be used to present @file, based |
| 3505 | - * on the given @icon_state and @icon_theme. |
| 3506 | - * |
| 3507 | - * Return value: the icon name for @file in @icon_theme. |
| 3508 | - **/ |
| 3509 | -const gchar * |
| 3510 | -thunar_file_get_icon_name (ThunarFile *file, |
| 3511 | - ThunarFileIconState icon_state, |
| 3512 | - GtkIconTheme *icon_theme) |
| 3513 | -{ |
| 3514 | - GFile *icon_file; |
| 3515 | - GIcon *icon = NULL; |
| 3516 | - const gchar * const *names; |
| 3517 | - gchar *icon_name = NULL; |
| 3518 | - gchar *path; |
| 3519 | - const gchar *special_names[] = { NULL, "folder", NULL }; |
| 3520 | - guint i; |
| 3521 | - const gchar *special_dir; |
| 3522 | - GFileInfo *fileinfo; |
| 3523 | - |
| 3524 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL); |
| 3525 | - _thunar_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL); |
| 3526 | - |
| 3527 | - /* return cached name */ |
| 3528 | - if (G_LIKELY (file->icon_name != NULL)) |
| 3529 | - return thunar_file_get_icon_name_for_state (file->icon_name, icon_state); |
| 3530 | - |
| 3531 | - /* the system root folder has a special icon */ |
| 3532 | - if (thunar_file_is_directory (file)) |
| 3533 | - { |
| 3534 | - if (G_LIKELY (thunar_file_is_local (file))) |
| 3535 | - { |
| 3536 | - path = g_file_get_path (file->gfile); |
| 3537 | - if (G_LIKELY (path != NULL)) |
| 3538 | - { |
| 3539 | - if (strcmp (path, G_DIR_SEPARATOR_S) == 0) |
| 3540 | - *special_names = "drive-harddisk"; |
| 3541 | - else if (strcmp (path, xfce_get_homedir ()) == 0) |
| 3542 | - *special_names = "user-home"; |
| 3543 | - else |
| 3544 | - { |
| 3545 | - for (i = 0; i < G_N_ELEMENTS (thunar_file_dirs); i++) |
| 3546 | - { |
| 3547 | - special_dir = g_get_user_special_dir (thunar_file_dirs[i].type); |
| 3548 | - if (special_dir != NULL |
| 3549 | - && strcmp (path, special_dir) == 0) |
| 3550 | - { |
| 3551 | - *special_names = thunar_file_dirs[i].icon_name; |
| 3552 | - break; |
| 3553 | - } |
| 3554 | - } |
| 3555 | - } |
| 3556 | - |
| 3557 | - g_free (path); |
| 3558 | - } |
| 3559 | - } |
| 3560 | - else if (!thunar_file_has_parent (file)) |
| 3561 | - { |
| 3562 | - if (g_file_has_uri_scheme (file->gfile, "trash")) |
| 3563 | - { |
| 3564 | - special_names[0] = thunar_file_get_item_count (file) > 0 ? "user-trash-full" : "user-trash"; |
| 3565 | - special_names[1] = "user-trash"; |
| 3566 | - } |
| 3567 | - else if (g_file_has_uri_scheme (file->gfile, "recent")) |
| 3568 | - { |
| 3569 | - special_names[0] = "document-open-recent"; |
| 3570 | - } |
| 3571 | - else if (g_file_has_uri_scheme (file->gfile, "computer")) |
| 3572 | - { |
| 3573 | - special_names[0] = "computer"; |
| 3574 | - } |
| 3575 | - } |
| 3576 | - |
| 3577 | - if (*special_names != NULL) |
| 3578 | - { |
| 3579 | - names = special_names; |
| 3580 | - goto check_names; |
| 3581 | - } |
| 3582 | - } |
| 3583 | - else if (thunar_file_is_mountable (file)) |
| 3584 | - { |
| 3585 | - /* query the icon (computer:// backend) */ |
| 3586 | - fileinfo = g_file_query_info (file->gfile, |
| 3587 | - G_FILE_ATTRIBUTE_STANDARD_ICON, |
| 3588 | - G_FILE_QUERY_INFO_NONE, NULL, NULL); |
| 3589 | - if (G_LIKELY (fileinfo != NULL)) |
| 3590 | - { |
| 3591 | - /* take the icon from the info */ |
| 3592 | - icon = g_file_info_get_icon (fileinfo); |
| 3593 | - if (G_LIKELY (icon != NULL)) |
| 3594 | - g_object_ref (icon); |
| 3595 | - |
| 3596 | - /* release */ |
| 3597 | - g_object_unref (G_OBJECT (fileinfo)); |
| 3598 | - |
| 3599 | - if (G_LIKELY (icon != NULL)) |
| 3600 | - goto check_icon; |
| 3601 | - } |
| 3602 | - } |
| 3603 | - |
| 3604 | - /* try again later */ |
| 3605 | - if (file->info == NULL) |
| 3606 | - return NULL; |
| 3607 | - |
| 3608 | - /* lookup for content type, just like gio does for local files */ |
| 3609 | - icon = g_content_type_get_icon (thunar_file_get_content_type (file)); |
| 3610 | - if (G_LIKELY (icon != NULL)) |
| 3611 | - { |
| 3612 | - check_icon: |
| 3613 | - |
| 3614 | - if (G_IS_THEMED_ICON (icon)) |
| 3615 | - { |
| 3616 | - names = g_themed_icon_get_names (G_THEMED_ICON (icon)); |
| 3617 | - |
| 3618 | - check_names: |
| 3619 | - |
| 3620 | - if (G_LIKELY (names != NULL)) |
| 3621 | - { |
| 3622 | - for (i = 0; names[i] != NULL; ++i) |
| 3623 | - if (*names[i] != '(' /* see gnome bug 688042 */ |
| 3624 | - && gtk_icon_theme_has_icon (icon_theme, names[i])) |
| 3625 | - { |
| 3626 | - icon_name = g_strdup (names[i]); |
| 3627 | - break; |
| 3628 | - } |
| 3629 | - } |
| 3630 | - } |
| 3631 | - else if (G_IS_FILE_ICON (icon)) |
| 3632 | - { |
| 3633 | - icon_file = g_file_icon_get_file (G_FILE_ICON (icon)); |
| 3634 | - if (icon_file != NULL) |
| 3635 | - icon_name = g_file_get_path (icon_file); |
| 3636 | - } |
| 3637 | - |
| 3638 | - if (G_LIKELY (icon != NULL)) |
| 3639 | - g_object_unref (icon); |
| 3640 | - } |
| 3641 | - |
| 3642 | - /* store new name, or empty string to avoid recursion */ |
| 3643 | - if (G_LIKELY (icon_name != NULL)) |
| 3644 | - file->icon_name = icon_name; |
| 3645 | - else |
| 3646 | - file->icon_name = g_strdup (""); |
| 3647 | - |
| 3648 | - return thunar_file_get_icon_name_for_state (file->icon_name, icon_state); |
| 3649 | -} |
| 3650 | - |
| 3651 | - |
| 3652 | - |
| 3653 | -/** |
| 3654 | - * thunar_file_watch: |
| 3655 | - * @file : a #ThunarFile instance. |
| 3656 | - * |
| 3657 | - * Tells @file to watch itself for changes. Not all #ThunarFile |
| 3658 | - * implementations must support this, but if a #ThunarFile |
| 3659 | - * implementation implements the thunar_file_watch() method, |
| 3660 | - * it must also implement the thunar_file_unwatch() method. |
| 3661 | - * |
| 3662 | - * The #ThunarFile base class implements automatic "ref |
| 3663 | - * counting" for watches, that says, you can call thunar_file_watch() |
| 3664 | - * multiple times, but the virtual method will be invoked only |
| 3665 | - * once. This also means that you MUST call thunar_file_unwatch() |
| 3666 | - * for every thunar_file_watch() invokation, else the application |
| 3667 | - * will abort. |
| 3668 | - **/ |
| 3669 | -void |
| 3670 | -thunar_file_watch (ThunarFile *file) |
| 3671 | -{ |
| 3672 | - ThunarFileWatch *file_watch; |
| 3673 | - |
| 3674 | - _thunar_return_if_fail (THUNAR_IS_FILE (file)); |
| 3675 | - |
| 3676 | - file_watch = g_object_get_qdata (G_OBJECT (file), thunar_file_watch_quark); |
| 3677 | - if (file_watch == NULL) |
| 3678 | - { |
| 3679 | - file_watch = g_slice_new (ThunarFileWatch); |
| 3680 | - file_watch->watch_count = 1; |
| 3681 | - |
| 3682 | - /* create a file or directory monitor */ |
| 3683 | - file_watch->monitor = g_file_monitor (file->gfile, G_FILE_MONITOR_WATCH_MOUNTS, NULL, NULL); |
| 3684 | - if (G_LIKELY (file_watch->monitor != NULL)) |
| 3685 | - { |
| 3686 | - /* watch monitor for file changes */ |
| 3687 | - g_signal_connect (file_watch->monitor, "changed", G_CALLBACK (thunar_file_monitor), file); |
| 3688 | - } |
| 3689 | - |
| 3690 | - /* attach to file */ |
| 3691 | - g_object_set_qdata_full (G_OBJECT (file), thunar_file_watch_quark, file_watch, thunar_file_watch_destroyed); |
| 3692 | - } |
| 3693 | - else |
| 3694 | - { |
| 3695 | - /* increase watch count */ |
| 3696 | - _thunar_return_if_fail (G_IS_FILE_MONITOR (file_watch->monitor)); |
| 3697 | - file_watch->watch_count++; |
| 3698 | - } |
| 3699 | -} |
| 3700 | - |
| 3701 | - |
| 3702 | - |
| 3703 | -/** |
| 3704 | - * thunar_file_unwatch: |
| 3705 | - * @file : a #ThunarFile instance. |
| 3706 | - * |
| 3707 | - * See thunar_file_watch() for a description of how watching |
| 3708 | - * #ThunarFile<!---->s works. |
| 3709 | - **/ |
| 3710 | -void |
| 3711 | -thunar_file_unwatch (ThunarFile *file) |
| 3712 | -{ |
| 3713 | - ThunarFileWatch *file_watch; |
| 3714 | - |
| 3715 | - _thunar_return_if_fail (THUNAR_IS_FILE (file)); |
| 3716 | - |
| 3717 | - file_watch = g_object_get_qdata (G_OBJECT (file), thunar_file_watch_quark); |
| 3718 | - if (file_watch != NULL) |
| 3719 | - { |
| 3720 | - /* remove if this was the last ref */ |
| 3721 | - if (--file_watch->watch_count == 0) |
| 3722 | - g_object_set_qdata (G_OBJECT (file), thunar_file_watch_quark, NULL); |
| 3723 | - } |
| 3724 | - else |
| 3725 | - { |
| 3726 | - _thunar_assert_not_reached (); |
| 3727 | - } |
| 3728 | -} |
| 3729 | - |
| 3730 | - |
| 3731 | - |
| 3732 | -/** |
| 3733 | - * thunar_file_reload: |
| 3734 | - * @file : a #ThunarFile instance. |
| 3735 | - * |
| 3736 | - * Tells @file to reload its internal state, e.g. by reacquiring |
| 3737 | - * the file info from the underlying media. |
| 3738 | - * |
| 3739 | - * You must be able to handle the case that @file is |
| 3740 | - * destroyed during the reload call. |
| 3741 | - **/ |
| 3742 | -void |
| 3743 | -thunar_file_reload (ThunarFile *file) |
| 3744 | -{ |
| 3745 | - _thunar_return_if_fail (THUNAR_IS_FILE (file)); |
| 3746 | - |
| 3747 | - /* clear file pxmap cache */ |
| 3748 | - thunar_icon_factory_clear_pixmap_cache (file); |
| 3749 | - |
| 3750 | - if (!thunar_file_load (file, NULL, NULL)) |
| 3751 | - { |
| 3752 | - /* destroy the file if we cannot query any file information */ |
| 3753 | - thunar_file_destroy (file); |
| 3754 | - return; |
| 3755 | - } |
| 3756 | - |
| 3757 | - /* ... and tell others */ |
| 3758 | - thunar_file_changed (file); |
| 3759 | - |
| 3760 | -} |
| 3761 | - |
| 3762 | - |
| 3763 | - |
| 3764 | -/** |
| 3765 | - * thunar_file_destroy: |
| 3766 | - * @file : a #ThunarFile instance. |
| 3767 | - * |
| 3768 | - * Emits the ::destroy signal notifying all reference holders |
| 3769 | - * that they should release their references to the @file. |
| 3770 | - * |
| 3771 | - * This method is very similar to what gtk_object_destroy() |
| 3772 | - * does for #GtkObject<!---->s. |
| 3773 | - **/ |
| 3774 | -void |
| 3775 | -thunar_file_destroy (ThunarFile *file) |
| 3776 | -{ |
| 3777 | - _thunar_return_if_fail (THUNAR_IS_FILE (file)); |
| 3778 | - |
| 3779 | - if (!FLAG_IS_SET (file, THUNAR_FILE_FLAG_IN_DESTRUCTION)) |
| 3780 | - { |
| 3781 | - /* take an additional reference on the file, as the file-destroyed |
| 3782 | - * invocation may already release the last reference. |
| 3783 | - */ |
| 3784 | - g_object_ref (G_OBJECT (file)); |
| 3785 | - |
| 3786 | - /* tell the file monitor that this file was destroyed */ |
| 3787 | - thunar_file_monitor_file_destroyed (file); |
| 3788 | - |
| 3789 | - /* run the dispose handler */ |
| 3790 | - g_object_run_dispose (G_OBJECT (file)); |
| 3791 | - |
| 3792 | - /* release our reference */ |
| 3793 | - g_object_unref (G_OBJECT (file)); |
| 3794 | - } |
| 3795 | -} |
| 3796 | - |
| 3797 | - |
| 3798 | - |
| 3799 | -/** |
| 3800 | - * thunar_file_compare_by_name: |
| 3801 | - * @file_a : the first #ThunarFile. |
| 3802 | - * @file_b : the second #ThunarFile. |
| 3803 | - * @case_sensitive : whether the comparison should be case-sensitive. |
| 3804 | - * |
| 3805 | - * Compares @file_a and @file_b by their display names. If @case_sensitive |
| 3806 | - * is %TRUE the comparison will be case-sensitive. |
| 3807 | - * |
| 3808 | - * Return value: -1 if @file_a should be sorted before @file_b, 1 if |
| 3809 | - * @file_b should be sorted before @file_a, 0 if equal. |
| 3810 | - **/ |
| 3811 | -gint |
| 3812 | -thunar_file_compare_by_name (const ThunarFile *file_a, |
| 3813 | - const ThunarFile *file_b, |
| 3814 | - gboolean case_sensitive) |
| 3815 | -{ |
| 3816 | - gint result = 0; |
| 3817 | - |
| 3818 | -#ifdef G_ENABLE_DEBUG |
| 3819 | - /* probably too expensive to do the instance check every time |
| 3820 | - * this function is called, so only for debugging builds. |
| 3821 | - */ |
| 3822 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file_a), 0); |
| 3823 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file_b), 0); |
| 3824 | -#endif |
| 3825 | - |
| 3826 | - /* case insensitive checking */ |
| 3827 | - if (G_LIKELY (!case_sensitive)) |
| 3828 | - result = strcmp (file_a->collate_key_nocase, file_b->collate_key_nocase); |
| 3829 | - |
| 3830 | - /* fall-back to case sensitive */ |
| 3831 | - if (result == 0) |
| 3832 | - result = strcmp (file_a->collate_key, file_b->collate_key); |
| 3833 | - |
| 3834 | - /* this happens in the trash */ |
| 3835 | - if (result == 0) |
| 3836 | - { |
| 3837 | - result = g_strcmp0 (thunar_file_get_original_path (file_a), |
| 3838 | - thunar_file_get_original_path (file_b)); |
| 3839 | - } |
| 3840 | - |
| 3841 | - return result; |
| 3842 | -} |
| 3843 | - |
| 3844 | - |
| 3845 | - |
| 3846 | -static gboolean |
| 3847 | -thunar_file_same_filesystem (const ThunarFile *file_a, |
| 3848 | - const ThunarFile *file_b) |
| 3849 | -{ |
| 3850 | - const gchar *filesystem_id_a; |
| 3851 | - const gchar *filesystem_id_b; |
| 3852 | - |
| 3853 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file_a), FALSE); |
| 3854 | - _thunar_return_val_if_fail (THUNAR_IS_FILE (file_b), FALSE); |
| 3855 | - |
| 3856 | - /* return false if we have no information about one of the files */ |
| 3857 | - if (file_a->info == NULL || file_b->info == NULL) |
| 3858 | - return FALSE; |
| 3859 | - |
| 3860 | - /* determine the filesystem IDs */ |
| 3861 | - filesystem_id_a = g_file_info_get_attribute_string (file_a->info, |
| 3862 | - G_FILE_ATTRIBUTE_ID_FILESYSTEM); |
| 3863 | - |
| 3864 | - filesystem_id_b = g_file_info_get_attribute_string (file_b->info, |
| 3865 | - G_FILE_ATTRIBUTE_ID_FILESYSTEM); |
| 3866 | - |
| 3867 | - /* compare the filesystem IDs */ |
| 3868 | - return exo_str_is_equal (filesystem_id_a, filesystem_id_b); |
| 3869 | -} |
| 3870 | - |
| 3871 | - |
| 3872 | - |
| 3873 | -/** |
| 3874 | - * thunar_file_cache_lookup: |
| 3875 | - * @file : a #GFile. |
| 3876 | - * |
| 3877 | - * Looks up the #ThunarFile for @file in the internal file |
| 3878 | - * cache and returns the file present for @file in the |
| 3879 | - * cache or %NULL if no #ThunarFile is cached for @file. |
| 3880 | - * |
| 3881 | - * Note that no reference is taken for the caller. |
| 3882 | - * |
| 3883 | - * This method should not be used but in very rare cases. |
| 3884 | - * Consider using thunar_file_get() instead. |
| 3885 | - * |
| 3886 | - * Return value: the #ThunarFile for @file in the internal |
| 3887 | - * cache, or %NULL. |
| 3888 | - **/ |
| 3889 | -ThunarFile * |
| 3890 | -thunar_file_cache_lookup (const GFile *file) |
| 3891 | -{ |
| 3892 | - ThunarFile *cached_file; |
| 3893 | - |
| 3894 | - _thunar_return_val_if_fail (G_IS_FILE (file), NULL); |
| 3895 | - |
| 3896 | - G_LOCK (file_cache_mutex); |
| 3897 | - |
| 3898 | - /* allocate the ThunarFile cache on-demand */ |
| 3899 | - if (G_UNLIKELY (file_cache == NULL)) |
| 3900 | - { |
| 3901 | - file_cache = g_hash_table_new_full (g_file_hash, |
| 3902 | - (GEqualFunc) g_file_equal, |
| 3903 | - (GDestroyNotify) g_object_unref, |
| 3904 | - NULL); |
| 3905 | - } |
| 3906 | - |
| 3907 | - cached_file = g_hash_table_lookup (file_cache, file); |
| 3908 | - |
| 3909 | - G_UNLOCK (file_cache_mutex); |
| 3910 | - |
| 3911 | - return cached_file; |
| 3912 | -} |
| 3913 | - |
| 3914 | - |
| 3915 | - |
| 3916 | -gchar * |
| 3917 | -thunar_file_cached_display_name (const GFile *file) |
| 3918 | -{ |
| 3919 | - ThunarFile *cached_file; |
| 3920 | - gchar *display_name; |
| 3921 | - |
| 3922 | - /* check if we have a ThunarFile for it in the cache (usually is the case) */ |
| 3923 | - cached_file = thunar_file_cache_lookup (file); |
| 3924 | - if (cached_file != NULL) |
| 3925 | - { |
| 3926 | - /* determine the display name of the file */ |
| 3927 | - display_name = g_strdup (thunar_file_get_display_name (cached_file)); |
| 3928 | - } |
| 3929 | - else |
| 3930 | - { |
| 3931 | - /* determine something a hopefully good approximation of the display name */ |
| 3932 | - display_name = thunar_g_file_get_display_name (G_FILE (file)); |
| 3933 | - } |
| 3934 | - |
| 3935 | - return display_name; |
| 3936 | -} |
| 3937 | - |
| 3938 | - |
| 3939 | - |
| 3940 | -static gint |
| 3941 | -compare_app_infos (gconstpointer a, |
| 3942 | - gconstpointer b) |
| 3943 | -{ |
| 3944 | - return g_app_info_equal (G_APP_INFO (a), G_APP_INFO (b)) ? 0 : 1; |
| 3945 | -} |
| 3946 | - |
| 3947 | - |
| 3948 | - |
| 3949 | -/** |
| 3950 | - * thunar_file_list_get_applications: |
| 3951 | - * @file_list : a #GList of #ThunarFile<!---->s. |
| 3952 | - * |
| 3953 | - * Returns the #GList of #GAppInfo<!---->s that can be used to open |
| 3954 | - * all #ThunarFile<!---->s in the given @file_list. |
| 3955 | - * |
| 3956 | - * The caller is responsible to free the returned list using something like: |
| 3957 | - * <informalexample><programlisting> |
| 3958 | - * g_list_free_full (list, g_object_unref); |
| 3959 | - * </programlisting></informalexample> |
| 3960 | - * |
| 3961 | - * Return value: the list of #GAppInfo<!---->s that can be used to open all |
| 3962 | - * items in the @file_list. |
| 3963 | - **/ |
| 3964 | -GList* |
| 3965 | -thunar_file_list_get_applications (GList *file_list) |
| 3966 | -{ |
| 3967 | - GList *applications = NULL; |
| 3968 | - GList *list; |
| 3969 | - GList *next; |
| 3970 | - GList *ap; |
| 3971 | - GList *lp; |
| 3972 | - const gchar *previous_type = NULL; |
| 3973 | - const gchar *current_type; |
| 3974 | - |
| 3975 | - /* determine the set of applications that can open all files */ |
| 3976 | - for (lp = file_list; lp != NULL; lp = lp->next) |
| 3977 | - { |
| 3978 | - current_type = thunar_file_get_content_type (lp->data); |
| 3979 | - |
| 3980 | - /* no need to check anything if this file has the same mimetype as the previous file */ |
| 3981 | - if (current_type != NULL && previous_type != NULL) |
| 3982 | - if (G_LIKELY (g_content_type_equals (previous_type, current_type))) |
| 3983 | - continue; |
| 3984 | - |
| 3985 | - /* store the previous type */ |
| 3986 | - previous_type = current_type; |
| 3987 | - |
| 3988 | - /* determine the list of applications that can open this file */ |
| 3989 | - if (G_UNLIKELY (current_type != NULL)) |
| 3990 | - list = g_app_info_get_all_for_type (current_type); |
| 3991 | - else |
| 3992 | - list = NULL; |
| 3993 | - |
| 3994 | - if (G_UNLIKELY (applications == NULL)) |
| 3995 | - { |
| 3996 | - /* first file, so just use the applications list */ |
| 3997 | - applications = list; |
| 3998 | - } |
| 3999 | - else |
| 4000 | - { |
| 4001 | - /* keep only the applications that are also present in list */ |
| 4002 | - for (ap = applications; ap != NULL; ap = next) |
| 4003 | - { |
| 4004 | - /* grab a pointer on the next application */ |
| 4005 | - next = ap->next; |
| 4006 | - |
| 4007 | - /* check if the application is present in list */ |
| 4008 | - if (g_list_find_custom (list, ap->data, compare_app_infos) == NULL) |
| 4009 | - { |
| 4010 | - /* drop our reference on the application */ |
| 4011 | - g_object_unref (G_OBJECT (ap->data)); |
| 4012 | - |
| 4013 | - /* drop this application from the list */ |
| 4014 | - applications = g_list_delete_link (applications, ap); |
| 4015 | - } |
| 4016 | - } |
| 4017 | - |
| 4018 | - /* release the list of applications for this file */ |
| 4019 | - g_list_free_full (list, g_object_unref); |
| 4020 | - } |
| 4021 | - |
| 4022 | - /* check if the set is still not empty */ |
| 4023 | - if (G_LIKELY (applications == NULL)) |
| 4024 | - break; |
| 4025 | - } |
| 4026 | - |
| 4027 | - /* remove hidden applications */ |
| 4028 | - for (ap = applications; ap != NULL; ap = next) |
| 4029 | - { |
| 4030 | - /* grab a pointer on the next application */ |
| 4031 | - next = ap->next; |
| 4032 | - |
| 4033 | - if (!thunar_g_app_info_should_show (ap->data)) |
| 4034 | - { |
| 4035 | - /* drop our reference on the application */ |
| 4036 | - g_object_unref (G_OBJECT (ap->data)); |
| 4037 | - |
| 4038 | - /* drop this application from the list */ |
| 4039 | - applications = g_list_delete_link (applications, ap); |
| 4040 | - } |
| 4041 | - } |
| 4042 | - |
| 4043 | - return applications; |
| 4044 | -} |
| 4045 | - |
| 4046 | - |
| 4047 | - |
| 4048 | -/** |
| 4049 | - * thunar_file_list_to_thunar_g_file_list: |
| 4050 | - * @file_list : a #GList of #ThunarFile<!---->s. |
| 4051 | - * |
| 4052 | - * Transforms the @file_list to a #GList of #GFile<!---->s for |
| 4053 | - * the #ThunarFile<!---->s contained within @file_list. |
| 4054 | - * |
| 4055 | - * The caller is responsible to free the returned list using |
| 4056 | - * thunar_g_file_list_free() when no longer needed. |
| 4057 | - * |
| 4058 | - * Return value: the list of #GFile<!---->s for @file_list. |
| 4059 | - **/ |
| 4060 | -GList* |
| 4061 | -thunar_file_list_to_thunar_g_file_list (GList *file_list) |
| 4062 | -{ |
| 4063 | - GList *list = NULL; |
| 4064 | - GList *lp; |
| 4065 | - |
| 4066 | - for (lp = g_list_last (file_list); lp != NULL; lp = lp->prev) |
| 4067 | - list = g_list_prepend (list, g_object_ref (THUNAR_FILE (lp->data)->gfile)); |
| 4068 | - |
| 4069 | - return list; |
| 4070 | -} |
| 4071 | |
| 4072 | === modified file '.pc/applied-patches' |
| 4073 | --- .pc/applied-patches 2014-10-31 07:27:27 +0000 |
| 4074 | +++ .pc/applied-patches 2015-01-06 18:59:01 +0000 |
| 4075 | @@ -1,7 +1,2 @@ |
| 4076 | 01_support-non-multiarch-modules.patch |
| 4077 | -02_fix-default-application-selection.patch |
| 4078 | -git-xfdesktop-4.11.patch |
| 4079 | -gtk3-bookmarks.patch |
| 4080 | -git-save-keyboard-shortcuts.patch |
| 4081 | menu-icon-tweaks.patch |
| 4082 | -git-force-toolbr-icons.patch |
| 4083 | |
| 4084 | === removed directory '.pc/git-force-toolbr-icons.patch' |
| 4085 | === removed directory '.pc/git-force-toolbr-icons.patch/thunar' |
| 4086 | === removed file '.pc/git-force-toolbr-icons.patch/thunar/thunar-window.c' |
| 4087 | --- .pc/git-force-toolbr-icons.patch/thunar/thunar-window.c 2014-04-05 08:22:40 +0000 |
| 4088 | +++ .pc/git-force-toolbr-icons.patch/thunar/thunar-window.c 1970-01-01 00:00:00 +0000 |
| 4089 | @@ -1,3846 +0,0 @@ |
| 4090 | -/* vi:set et ai sw=2 sts=2 ts=2: */ |
| 4091 | -/*- |
| 4092 | - * Copyright (c) 2005-2007 Benedikt Meurer <benny@xfce.org> |
| 4093 | - * Copyright (c) 2009-2011 Jannis Pohlmann <jannis@xfce.org> |
| 4094 | - * |
| 4095 | - * This program is free software; you can redistribute it and/or |
| 4096 | - * modify it under the terms of the GNU General Public License as |
| 4097 | - * published by the Free Software Foundation; either version 2 of |
| 4098 | - * the License, or (at your option) any later version. |
| 4099 | - * |
| 4100 | - * This program is distributed in the hope that it will be useful, |
| 4101 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 4102 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 4103 | - * GNU General Public License for more details. |
| 4104 | - * |
| 4105 | - * You should have received a copy of the GNU General Public |
| 4106 | - * License along with this program; if not, write to the Free |
| 4107 | - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 4108 | - * Boston, MA 02110-1301, USA. |
| 4109 | - */ |
| 4110 | - |
| 4111 | -#ifdef HAVE_CONFIG_H |
| 4112 | -#include <config.h> |
| 4113 | -#endif |
| 4114 | - |
| 4115 | -#ifdef HAVE_UNISTD_H |
| 4116 | -#include <unistd.h> |
| 4117 | -#endif |
| 4118 | -#ifdef HAVE_LOCALE_H |
| 4119 | -#include <locale.h> |
| 4120 | -#endif |
| 4121 | - |
| 4122 | -#include <gdk/gdkkeysyms.h> |
| 4123 | -#include <libxfce4ui/libxfce4ui.h> |
| 4124 | - |
| 4125 | -#include <thunar/thunar-application.h> |
| 4126 | -#include <thunar/thunar-browser.h> |
| 4127 | -#include <thunar/thunar-clipboard-manager.h> |
| 4128 | -#include <thunar/thunar-compact-view.h> |
| 4129 | -#include <thunar/thunar-details-view.h> |
| 4130 | -#include <thunar/thunar-dialogs.h> |
| 4131 | -#include <thunar/thunar-shortcuts-pane.h> |
| 4132 | -#include <thunar/thunar-gio-extensions.h> |
| 4133 | -#include <thunar/thunar-gobject-extensions.h> |
| 4134 | -#include <thunar/thunar-gtk-extensions.h> |
| 4135 | -#include <thunar/thunar-icon-view.h> |
| 4136 | -#include <thunar/thunar-launcher.h> |
| 4137 | -#include <thunar/thunar-location-buttons.h> |
| 4138 | -#include <thunar/thunar-location-dialog.h> |
| 4139 | -#include <thunar/thunar-location-entry.h> |
| 4140 | -#include <thunar/thunar-marshal.h> |
| 4141 | -#include <thunar/thunar-pango-extensions.h> |
| 4142 | -#include <thunar/thunar-preferences-dialog.h> |
| 4143 | -#include <thunar/thunar-preferences.h> |
| 4144 | -#include <thunar/thunar-private.h> |
| 4145 | -#include <thunar/thunar-util.h> |
| 4146 | -#include <thunar/thunar-statusbar.h> |
| 4147 | -#include <thunar/thunar-stock.h> |
| 4148 | -#include <thunar/thunar-trash-action.h> |
| 4149 | -#include <thunar/thunar-tree-pane.h> |
| 4150 | -#include <thunar/thunar-window.h> |
| 4151 | -#include <thunar/thunar-window-ui.h> |
| 4152 | -#include <thunar/thunar-device-monitor.h> |
| 4153 | - |
| 4154 | -#include <glib.h> |
| 4155 | - |
| 4156 | - |
| 4157 | - |
| 4158 | -/* Property identifiers */ |
| 4159 | -enum |
| 4160 | -{ |
| 4161 | - PROP_0, |
| 4162 | - PROP_CURRENT_DIRECTORY, |
| 4163 | - PROP_SHOW_HIDDEN, |
| 4164 | - PROP_UI_MANAGER, |
| 4165 | - PROP_ZOOM_LEVEL, |
| 4166 | -}; |
| 4167 | - |
| 4168 | -/* Signal identifiers */ |
| 4169 | -enum |
| 4170 | -{ |
| 4171 | - BACK, |
| 4172 | - RELOAD, |
| 4173 | - TOGGLE_SIDEPANE, |
| 4174 | - TOGGLE_MENUBAR, |
| 4175 | - ZOOM_IN, |
| 4176 | - ZOOM_OUT, |
| 4177 | - ZOOM_RESET, |
| 4178 | - TAB_CHANGE, |
| 4179 | - LAST_SIGNAL, |
| 4180 | -}; |
| 4181 | - |
| 4182 | - |
| 4183 | - |
| 4184 | -static void thunar_window_dispose (GObject *object); |
| 4185 | -static void thunar_window_finalize (GObject *object); |
| 4186 | -static void thunar_window_get_property (GObject *object, |
| 4187 | - guint prop_id, |
| 4188 | - GValue *value, |
| 4189 | - GParamSpec *pspec); |
| 4190 | -static void thunar_window_set_property (GObject *object, |
| 4191 | - guint prop_id, |
| 4192 | - const GValue *value, |
| 4193 | - GParamSpec *pspec); |
| 4194 | -static gboolean thunar_window_back (ThunarWindow *window); |
| 4195 | -static gboolean thunar_window_reload (ThunarWindow *window); |
| 4196 | -static gboolean thunar_window_toggle_sidepane (ThunarWindow *window); |
| 4197 | -static gboolean thunar_window_toggle_menubar (ThunarWindow *window); |
| 4198 | -static void thunar_window_toggle_menubar_deactivate (GtkWidget *menubar, |
| 4199 | - ThunarWindow *window); |
| 4200 | -static gboolean thunar_window_zoom_in (ThunarWindow *window); |
| 4201 | -static gboolean thunar_window_zoom_out (ThunarWindow *window); |
| 4202 | -static gboolean thunar_window_zoom_reset (ThunarWindow *window); |
| 4203 | -static gboolean thunar_window_tab_change (ThunarWindow *window, |
| 4204 | - gint nth); |
| 4205 | -static void thunar_window_realize (GtkWidget *widget); |
| 4206 | -static void thunar_window_unrealize (GtkWidget *widget); |
| 4207 | -static gboolean thunar_window_configure_event (GtkWidget *widget, |
| 4208 | - GdkEventConfigure *event); |
| 4209 | -static void thunar_window_notebook_switch_page (GtkWidget *notebook, |
| 4210 | - GtkWidget *page, |
| 4211 | - guint page_num, |
| 4212 | - ThunarWindow *window); |
| 4213 | -static void thunar_window_notebook_page_added (GtkWidget *notebook, |
| 4214 | - GtkWidget *page, |
| 4215 | - guint page_num, |
| 4216 | - ThunarWindow *window); |
| 4217 | -static void thunar_window_notebook_page_removed (GtkWidget *notebook, |
| 4218 | - GtkWidget *page, |
| 4219 | - guint page_num, |
| 4220 | - ThunarWindow *window); |
| 4221 | -static gboolean thunar_window_notebook_button_press_event (GtkWidget *notebook, |
| 4222 | - GdkEventButton *event, |
| 4223 | - ThunarWindow *window); |
| 4224 | -static gboolean thunar_window_notebook_popup_menu (GtkWidget *notebook, |
| 4225 | - ThunarWindow *window); |
| 4226 | -static gpointer thunar_window_notebook_create_window (GtkWidget *notebook, |
| 4227 | - GtkWidget *page, |
| 4228 | - gint x, |
| 4229 | - gint y, |
| 4230 | - ThunarWindow *window); |
| 4231 | -static void thunar_window_notebook_insert (ThunarWindow *window, |
| 4232 | - ThunarFile *directory); |
| 4233 | -static void thunar_window_merge_custom_preferences (ThunarWindow *window); |
| 4234 | -static gboolean thunar_window_bookmark_merge (gpointer user_data); |
| 4235 | -static void thunar_window_merge_go_actions (ThunarWindow *window); |
| 4236 | -static void thunar_window_install_location_bar (ThunarWindow *window, |
| 4237 | - GType type); |
| 4238 | -static void thunar_window_install_sidepane (ThunarWindow *window, |
| 4239 | - GType type); |
| 4240 | -static void thunar_window_start_open_location (ThunarWindow *window, |
| 4241 | - const gchar *initial_text); |
| 4242 | -static void thunar_window_action_open_new_tab (GtkAction *action, |
| 4243 | - ThunarWindow *window); |
| 4244 | -static void thunar_window_action_open_new_window (GtkAction *action, |
| 4245 | - ThunarWindow *window); |
| 4246 | -static void thunar_window_action_empty_trash (GtkAction *action, |
| 4247 | - ThunarWindow *window); |
| 4248 | -static void thunar_window_action_detach_tab (GtkAction *action, |
| 4249 | - ThunarWindow *window); |
| 4250 | -static void thunar_window_action_close_all_windows (GtkAction *action, |
| 4251 | - ThunarWindow *window); |
| 4252 | -static void thunar_window_action_close_tab (GtkAction *action, |
| 4253 | - ThunarWindow *window); |
| 4254 | -static void thunar_window_action_close_window (GtkAction *action, |
| 4255 | - ThunarWindow *window); |
| 4256 | -static void thunar_window_action_preferences (GtkAction *action, |
| 4257 | - ThunarWindow *window); |
| 4258 | -static void thunar_window_action_reload (GtkAction *action, |
| 4259 | - ThunarWindow *window); |
| 4260 | -static void thunar_window_action_pathbar_changed (GtkToggleAction *action, |
| 4261 | - ThunarWindow *window); |
| 4262 | -static void thunar_window_action_toolbar_changed (GtkToggleAction *action, |
| 4263 | - ThunarWindow *window); |
| 4264 | -static void thunar_window_action_shortcuts_changed (GtkToggleAction *action, |
| 4265 | - ThunarWindow *window); |
| 4266 | -static void thunar_window_action_tree_changed (GtkToggleAction *action, |
| 4267 | - ThunarWindow *window); |
| 4268 | -static void thunar_window_action_statusbar_changed (GtkToggleAction *action, |
| 4269 | - ThunarWindow *window); |
| 4270 | -static void thunar_window_action_menubar_changed (GtkToggleAction *action, |
| 4271 | - ThunarWindow *window); |
| 4272 | -static void thunar_window_action_zoom_in (GtkAction *action, |
| 4273 | - ThunarWindow *window); |
| 4274 | -static void thunar_window_action_zoom_out (GtkAction *action, |
| 4275 | - ThunarWindow *window); |
| 4276 | -static void thunar_window_action_zoom_reset (GtkAction *action, |
| 4277 | - ThunarWindow *window); |
| 4278 | -static void thunar_window_action_view_changed (GtkRadioAction *action, |
| 4279 | - GtkRadioAction *current, |
| 4280 | - ThunarWindow *window); |
| 4281 | -static void thunar_window_action_go_up (GtkAction *action, |
| 4282 | - ThunarWindow *window); |
| 4283 | -static void thunar_window_action_open_home (GtkAction *action, |
| 4284 | - ThunarWindow *window); |
| 4285 | -static void thunar_window_action_open_desktop (GtkAction *action, |
| 4286 | - ThunarWindow *window); |
| 4287 | -static void thunar_window_action_open_templates (GtkAction *action, |
| 4288 | - ThunarWindow *window); |
| 4289 | -static void thunar_window_action_open_file_system (GtkAction *action, |
| 4290 | - ThunarWindow *window); |
| 4291 | -static void thunar_window_action_open_trash (GtkAction *action, |
| 4292 | - ThunarWindow *window); |
| 4293 | -static void thunar_window_action_open_network (GtkAction *action, |
| 4294 | - ThunarWindow *window); |
| 4295 | -static void thunar_window_action_open_bookmark (GtkAction *action, |
| 4296 | - ThunarWindow *window); |
| 4297 | -static void thunar_window_action_open_location (GtkAction *action, |
| 4298 | - ThunarWindow *window); |
| 4299 | -static void thunar_window_action_contents (GtkAction *action, |
| 4300 | - ThunarWindow *window); |
| 4301 | -static void thunar_window_action_about (GtkAction *action, |
| 4302 | - ThunarWindow *window); |
| 4303 | -static void thunar_window_action_show_hidden (GtkToggleAction *action, |
| 4304 | - ThunarWindow *window); |
| 4305 | -static void thunar_window_current_directory_changed (ThunarFile *current_directory, |
| 4306 | - ThunarWindow *window); |
| 4307 | -static void thunar_window_connect_proxy (GtkUIManager *manager, |
| 4308 | - GtkAction *action, |
| 4309 | - GtkWidget *proxy, |
| 4310 | - ThunarWindow *window); |
| 4311 | -static void thunar_window_disconnect_proxy (GtkUIManager *manager, |
| 4312 | - GtkAction *action, |
| 4313 | - GtkWidget *proxy, |
| 4314 | - ThunarWindow *window); |
| 4315 | -static void thunar_window_menu_item_selected (GtkWidget *menu_item, |
| 4316 | - ThunarWindow *window); |
| 4317 | -static void thunar_window_menu_item_deselected (GtkWidget *menu_item, |
| 4318 | - ThunarWindow *window); |
| 4319 | -static void thunar_window_update_custom_actions (ThunarView *view, |
| 4320 | - GParamSpec *pspec, |
| 4321 | - ThunarWindow *window); |
| 4322 | -static void thunar_window_notify_loading (ThunarView *view, |
| 4323 | - GParamSpec *pspec, |
| 4324 | - ThunarWindow *window); |
| 4325 | -static void thunar_window_device_pre_unmount (ThunarDeviceMonitor *device_monitor, |
| 4326 | - ThunarDevice *device, |
| 4327 | - GFile *root_file, |
| 4328 | - ThunarWindow *window); |
| 4329 | -static void thunar_window_device_changed (ThunarDeviceMonitor *device_monitor, |
| 4330 | - ThunarDevice *device, |
| 4331 | - ThunarWindow *window); |
| 4332 | -static gboolean thunar_window_merge_idle (gpointer user_data); |
| 4333 | -static void thunar_window_merge_idle_destroy (gpointer user_data); |
| 4334 | -static gboolean thunar_window_save_paned (ThunarWindow *window); |
| 4335 | -static gboolean thunar_window_save_geometry_timer (gpointer user_data); |
| 4336 | -static void thunar_window_save_geometry_timer_destroy (gpointer user_data); |
| 4337 | -static void thunar_window_set_zoom_level (ThunarWindow *window, |
| 4338 | - ThunarZoomLevel zoom_level); |
| 4339 | - |
| 4340 | - |
| 4341 | - |
| 4342 | -struct _ThunarWindowClass |
| 4343 | -{ |
| 4344 | - GtkWindowClass __parent__; |
| 4345 | - |
| 4346 | - /* internal action signals */ |
| 4347 | - gboolean (*back) (ThunarWindow *window); |
| 4348 | - gboolean (*reload) (ThunarWindow *window); |
| 4349 | - gboolean (*toggle_sidepane) (ThunarWindow *window); |
| 4350 | - gboolean (*toggle_menubar) (ThunarWindow *window); |
| 4351 | - gboolean (*zoom_in) (ThunarWindow *window); |
| 4352 | - gboolean (*zoom_out) (ThunarWindow *window); |
| 4353 | - gboolean (*zoom_reset) (ThunarWindow *window); |
| 4354 | - gboolean (*tab_change) (ThunarWindow *window, |
| 4355 | - gint idx); |
| 4356 | -}; |
| 4357 | - |
| 4358 | -struct _ThunarWindow |
| 4359 | -{ |
| 4360 | - GtkWindow __parent__; |
| 4361 | - |
| 4362 | - /* support for custom preferences actions */ |
| 4363 | - ThunarxProviderFactory *provider_factory; |
| 4364 | - guint custom_preferences_merge_id; |
| 4365 | - |
| 4366 | - /* UI manager merge ID for go menu actions */ |
| 4367 | - guint go_items_actions_merge_id; |
| 4368 | - |
| 4369 | - /* UI manager merge ID for the bookmark actions */ |
| 4370 | - guint bookmark_items_actions_merge_id; |
| 4371 | - GtkActionGroup *bookmark_action_group; |
| 4372 | - GFile *bookmark_file; |
| 4373 | - GFileMonitor *bookmark_monitor; |
| 4374 | - guint bookmark_reload_idle_id; |
| 4375 | - |
| 4376 | - ThunarClipboardManager *clipboard; |
| 4377 | - |
| 4378 | - ThunarPreferences *preferences; |
| 4379 | - |
| 4380 | - ThunarIconFactory *icon_factory; |
| 4381 | - |
| 4382 | - GtkActionGroup *action_group; |
| 4383 | - GtkUIManager *ui_manager; |
| 4384 | - |
| 4385 | - /* to be able to change folder on "device-pre-unmount" if required */ |
| 4386 | - ThunarDeviceMonitor *device_monitor; |
| 4387 | - |
| 4388 | - /* closures for the menu_item_selected()/menu_item_deselected() callbacks */ |
| 4389 | - GClosure *menu_item_selected_closure; |
| 4390 | - GClosure *menu_item_deselected_closure; |
| 4391 | - |
| 4392 | - /* custom menu actions for the file menu */ |
| 4393 | - GtkActionGroup *custom_actions; |
| 4394 | - guint custom_merge_id; |
| 4395 | - |
| 4396 | - GtkWidget *table; |
| 4397 | - GtkWidget *menubar; |
| 4398 | - GtkWidget *spinner; |
| 4399 | - GtkWidget *paned; |
| 4400 | - GtkWidget *sidepane; |
| 4401 | - GtkWidget *view_box; |
| 4402 | - GtkWidget *notebook; |
| 4403 | - GtkWidget *view; |
| 4404 | - GtkWidget *statusbar; |
| 4405 | - |
| 4406 | - GType view_type; |
| 4407 | - GSList *view_bindings; |
| 4408 | - |
| 4409 | - /* support for two different styles of location bars */ |
| 4410 | - GtkWidget *location_bar; |
| 4411 | - GtkWidget *location_toolbar; |
| 4412 | - |
| 4413 | - ThunarLauncher *launcher; |
| 4414 | - |
| 4415 | - ThunarFile *current_directory; |
| 4416 | - |
| 4417 | - /* zoom-level support */ |
| 4418 | - ThunarZoomLevel zoom_level; |
| 4419 | - |
| 4420 | - /* menu merge idle source */ |
| 4421 | - guint merge_idle_id; |
| 4422 | - |
| 4423 | - /* support to remember window geometry */ |
| 4424 | - guint save_geometry_timer_id; |
| 4425 | - |
| 4426 | - /* support to toggle side pane using F9, |
| 4427 | - * see the toggle_sidepane() function. |
| 4428 | - */ |
| 4429 | - GType toggle_sidepane_type; |
| 4430 | -}; |
| 4431 | - |
| 4432 | - |
| 4433 | - |
| 4434 | -static GtkActionEntry action_entries[] = |
| 4435 | -{ |
| 4436 | - { "file-menu", NULL, N_ ("_File"), NULL, }, |
| 4437 | - { "new-tab", "tab-new", N_ ("New _Tab"), "<control>T", N_ ("Open a new tab for the displayed location"), G_CALLBACK (thunar_window_action_open_new_tab), }, |
| 4438 | - { "new-window", "window-new", N_ ("New _Window"), "<control>N", N_ ("Open a new Thunar window for the displayed location"), G_CALLBACK (thunar_window_action_open_new_window), }, |
| 4439 | - { "sendto-menu", NULL, N_ ("_Send To"), NULL, }, |
| 4440 | - { "empty-trash", NULL, N_ ("_Empty Trash"), NULL, N_ ("Delete all files and folders in the Trash"), G_CALLBACK (thunar_window_action_empty_trash), }, |
| 4441 | - { "detach-tab", NULL, N_ ("Detac_h Tab"), NULL, N_ ("Open current folder in a new window"), G_CALLBACK (thunar_window_action_detach_tab), }, |
| 4442 | - { "close-all-windows", NULL, N_ ("Close _All Windows"), "<control><shift>W", N_ ("Close all Thunar windows"), G_CALLBACK (thunar_window_action_close_all_windows), }, |
| 4443 | - { "close-tab", GTK_STOCK_CLOSE, N_ ("C_lose Tab"), "<control>W", N_ ("Close this folder"), G_CALLBACK (thunar_window_action_close_tab), }, |
| 4444 | - { "close-window", GTK_STOCK_QUIT, N_ ("_Close Window"), "<control>Q", N_ ("Close this window"), G_CALLBACK (thunar_window_action_close_window), }, |
| 4445 | - { "edit-menu", NULL, N_ ("_Edit"), NULL, }, |
| 4446 | - { "preferences", GTK_STOCK_PREFERENCES, N_ ("Pr_eferences..."), NULL, N_ ("Edit Thunars Preferences"), G_CALLBACK (thunar_window_action_preferences), }, |
| 4447 | - { "view-menu", NULL, N_ ("_View"), NULL, }, |
| 4448 | - { "reload", GTK_STOCK_REFRESH, N_ ("_Reload"), "<control>R", N_ ("Reload the current folder"), G_CALLBACK (thunar_window_action_reload), }, |
| 4449 | - { "view-location-selector-menu", NULL, N_ ("_Location Selector"), NULL, }, |
| 4450 | - { "view-side-pane-menu", NULL, N_ ("_Side Pane"), NULL, }, |
| 4451 | - { "zoom-in", GTK_STOCK_ZOOM_IN, N_ ("Zoom I_n"), "<control>plus", N_ ("Show the contents in more detail"), G_CALLBACK (thunar_window_action_zoom_in), }, |
| 4452 | - { "zoom-out", GTK_STOCK_ZOOM_OUT, N_ ("Zoom _Out"), "<control>minus", N_ ("Show the contents in less detail"), G_CALLBACK (thunar_window_action_zoom_out), }, |
| 4453 | - { "zoom-reset", GTK_STOCK_ZOOM_100, N_ ("Normal Si_ze"), "<control>0", N_ ("Show the contents at the normal size"), G_CALLBACK (thunar_window_action_zoom_reset), }, |
| 4454 | - { "go-menu", NULL, N_ ("_Go"), NULL, }, |
| 4455 | - { "open-parent", GTK_STOCK_GO_UP, N_ ("Open _Parent"), "<alt>Up", N_ ("Open the parent folder"), G_CALLBACK (thunar_window_action_go_up), }, |
| 4456 | - { "open-home", GTK_STOCK_HOME, N_ ("_Home"), "<alt>Home", N_ ("Go to the home folder"), G_CALLBACK (thunar_window_action_open_home), }, |
| 4457 | - { "open-desktop", THUNAR_STOCK_DESKTOP, N_ ("Desktop"), NULL, N_ ("Go to the desktop folder"), G_CALLBACK (thunar_window_action_open_desktop), }, |
| 4458 | - { "open-file-system", GTK_STOCK_HARDDISK, N_ ("File System"), NULL, N_ ("Browse the file system"), G_CALLBACK (thunar_window_action_open_file_system), }, |
| 4459 | - { "open-network", GTK_STOCK_NETWORK, N_("B_rowse Network"), NULL, N_ ("Browse local network connections"), G_CALLBACK (thunar_window_action_open_network), }, |
| 4460 | - { "open-templates", THUNAR_STOCK_TEMPLATES, N_("T_emplates"), NULL, N_ ("Go to the templates folder"), G_CALLBACK (thunar_window_action_open_templates), }, |
| 4461 | - { "open-location", NULL, N_ ("_Open Location..."), "<control>L", N_ ("Specify a location to open"), G_CALLBACK (thunar_window_action_open_location), }, |
| 4462 | - { "help-menu", NULL, N_ ("_Help"), NULL, }, |
| 4463 | - { "contents", GTK_STOCK_HELP, N_ ("_Contents"), "F1", N_ ("Display Thunar user manual"), G_CALLBACK (thunar_window_action_contents), }, |
| 4464 | - { "about", GTK_STOCK_ABOUT, N_ ("_About"), NULL, N_ ("Display information about Thunar"), G_CALLBACK (thunar_window_action_about), }, |
| 4465 | -}; |
| 4466 | - |
| 4467 | -static const GtkToggleActionEntry toggle_action_entries[] = |
| 4468 | -{ |
| 4469 | - { "show-hidden", NULL, N_ ("Show _Hidden Files"), "<control>H", N_ ("Toggles the display of hidden files in the current window"), G_CALLBACK (thunar_window_action_show_hidden), FALSE, }, |
| 4470 | - { "view-location-selector-pathbar", NULL, N_ ("_Pathbar Style"), NULL, N_ ("Modern approach with buttons that correspond to folders"), G_CALLBACK (thunar_window_action_pathbar_changed), FALSE, }, |
| 4471 | - { "view-location-selector-toolbar", NULL, N_ ("_Toolbar Style"), NULL, N_ ("Traditional approach with location bar and navigation buttons"), G_CALLBACK (thunar_window_action_toolbar_changed), FALSE, }, |
| 4472 | - { "view-side-pane-shortcuts", NULL, N_ ("_Shortcuts"), "<control>B", N_ ("Toggles the visibility of the shortcuts pane"), G_CALLBACK (thunar_window_action_shortcuts_changed), FALSE, }, |
| 4473 | - { "view-side-pane-tree", NULL, N_ ("_Tree"), "<control>E", N_ ("Toggles the visibility of the tree pane"), G_CALLBACK (thunar_window_action_tree_changed), FALSE, }, |
| 4474 | - { "view-statusbar", NULL, N_ ("St_atusbar"), NULL, N_ ("Change the visibility of this window's statusbar"), G_CALLBACK (thunar_window_action_statusbar_changed), FALSE, }, |
| 4475 | - { "view-menubar", NULL, N_ ("_Menubar"), "<control>M", N_ ("Change the visibility of this window's menubar"), G_CALLBACK (thunar_window_action_menubar_changed), TRUE, }, |
| 4476 | -}; |
| 4477 | - |
| 4478 | - |
| 4479 | - |
| 4480 | -static guint window_signals[LAST_SIGNAL]; |
| 4481 | - |
| 4482 | - |
| 4483 | - |
| 4484 | -G_DEFINE_TYPE_WITH_CODE (ThunarWindow, thunar_window, GTK_TYPE_WINDOW, |
| 4485 | - G_IMPLEMENT_INTERFACE (THUNAR_TYPE_BROWSER, NULL)) |
| 4486 | - |
| 4487 | - |
| 4488 | - |
| 4489 | -static void |
| 4490 | -thunar_window_class_init (ThunarWindowClass *klass) |
| 4491 | -{ |
| 4492 | - GtkWidgetClass *gtkwidget_class; |
| 4493 | - GtkBindingSet *binding_set; |
| 4494 | - GObjectClass *gobject_class; |
| 4495 | - guint i; |
| 4496 | - |
| 4497 | - gobject_class = G_OBJECT_CLASS (klass); |
| 4498 | - gobject_class->dispose = thunar_window_dispose; |
| 4499 | - gobject_class->finalize = thunar_window_finalize; |
| 4500 | - gobject_class->get_property = thunar_window_get_property; |
| 4501 | - gobject_class->set_property = thunar_window_set_property; |
| 4502 | - |
| 4503 | - gtkwidget_class = GTK_WIDGET_CLASS (klass); |
| 4504 | - gtkwidget_class->realize = thunar_window_realize; |
| 4505 | - gtkwidget_class->unrealize = thunar_window_unrealize; |
| 4506 | - gtkwidget_class->configure_event = thunar_window_configure_event; |
| 4507 | - |
| 4508 | - klass->back = thunar_window_back; |
| 4509 | - klass->reload = thunar_window_reload; |
| 4510 | - klass->toggle_sidepane = thunar_window_toggle_sidepane; |
| 4511 | - klass->toggle_menubar = thunar_window_toggle_menubar; |
| 4512 | - klass->zoom_in = thunar_window_zoom_in; |
| 4513 | - klass->zoom_out = thunar_window_zoom_out; |
| 4514 | - klass->zoom_reset = thunar_window_zoom_reset; |
| 4515 | - klass->tab_change = thunar_window_tab_change; |
| 4516 | - |
| 4517 | - /** |
| 4518 | - * ThunarWindow:current-directory: |
| 4519 | - * |
| 4520 | - * The directory currently displayed within this #ThunarWindow |
| 4521 | - * or %NULL. |
| 4522 | - **/ |
| 4523 | - g_object_class_install_property (gobject_class, |
| 4524 | - PROP_CURRENT_DIRECTORY, |
| 4525 | - g_param_spec_object ("current-directory", |
| 4526 | - "current-directory", |
| 4527 | - "current-directory", |
| 4528 | - THUNAR_TYPE_FILE, |
| 4529 | - EXO_PARAM_READWRITE)); |
| 4530 | - |
| 4531 | - /** |
| 4532 | - * ThunarWindow:show-hidden: |
| 4533 | - * |
| 4534 | - * Whether to show hidden files in the current window. |
| 4535 | - **/ |
| 4536 | - g_object_class_install_property (gobject_class, |
| 4537 | - PROP_SHOW_HIDDEN, |
| 4538 | - g_param_spec_boolean ("show-hidden", |
| 4539 | - "show-hidden", |
| 4540 | - "show-hidden", |
| 4541 | - FALSE, |
| 4542 | - EXO_PARAM_READABLE)); |
| 4543 | - |
| 4544 | - /** |
| 4545 | - * ThunarWindow:ui-manager: |
| 4546 | - * |
| 4547 | - * The #GtkUIManager used for this #ThunarWindow. This property |
| 4548 | - * can only be read and is garantied to always contain a valid |
| 4549 | - * #GtkUIManager instance (thus it's never %NULL). |
| 4550 | - **/ |
| 4551 | - g_object_class_install_property (gobject_class, |
| 4552 | - PROP_UI_MANAGER, |
| 4553 | - g_param_spec_object ("ui-manager", |
| 4554 | - "ui-manager", |
| 4555 | - "ui-manager", |
| 4556 | - GTK_TYPE_UI_MANAGER, |
| 4557 | - EXO_PARAM_READABLE)); |
| 4558 | - |
| 4559 | - /** |
| 4560 | - * ThunarWindow:zoom-level: |
| 4561 | - * |
| 4562 | - * The #ThunarZoomLevel applied to the #ThunarView currently |
| 4563 | - * shown within this window. |
| 4564 | - **/ |
| 4565 | - g_object_class_install_property (gobject_class, |
| 4566 | - PROP_ZOOM_LEVEL, |
| 4567 | - g_param_spec_enum ("zoom-level", |
| 4568 | - "zoom-level", |
| 4569 | - "zoom-level", |
| 4570 | - THUNAR_TYPE_ZOOM_LEVEL, |
| 4571 | - THUNAR_ZOOM_LEVEL_NORMAL, |
| 4572 | - EXO_PARAM_READWRITE)); |
| 4573 | - |
| 4574 | - /** |
| 4575 | - * ThunarWindow::back: |
| 4576 | - * @window : a #ThunarWindow instance. |
| 4577 | - * |
| 4578 | - * Emitted whenever the user requests to go to the |
| 4579 | - * previous visited folder. This is an internal |
| 4580 | - * signal used to bind the action to keys. |
| 4581 | - **/ |
| 4582 | - window_signals[BACK] = |
| 4583 | - g_signal_new (I_("back"), |
| 4584 | - G_TYPE_FROM_CLASS (klass), |
| 4585 | - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, |
| 4586 | - G_STRUCT_OFFSET (ThunarWindowClass, back), |
| 4587 | - g_signal_accumulator_true_handled, NULL, |
| 4588 | - _thunar_marshal_BOOLEAN__VOID, |
| 4589 | - G_TYPE_BOOLEAN, 0); |
| 4590 | - |
| 4591 | - /** |
| 4592 | - * ThunarWindow::reload: |
| 4593 | - * @window : a #ThunarWindow instance. |
| 4594 | - * |
| 4595 | - * Emitted whenever the user requests to reload the contents |
| 4596 | - * of the currently displayed folder. This is an internal |
| 4597 | - * signal used to bind the action to keys. |
| 4598 | - **/ |
| 4599 | - window_signals[RELOAD] = |
| 4600 | - g_signal_new (I_("reload"), |
| 4601 | - G_TYPE_FROM_CLASS (klass), |
| 4602 | - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, |
| 4603 | - G_STRUCT_OFFSET (ThunarWindowClass, reload), |
| 4604 | - g_signal_accumulator_true_handled, NULL, |
| 4605 | - _thunar_marshal_BOOLEAN__VOID, |
| 4606 | - G_TYPE_BOOLEAN, 0); |
| 4607 | - |
| 4608 | - /** |
| 4609 | - * ThunarWindow::toggle-sidepane: |
| 4610 | - * @window : a #ThunarWindow instance. |
| 4611 | - * |
| 4612 | - * Emitted whenever the user toggles the visibility of the |
| 4613 | - * sidepane. This is an internal signal used to bind the |
| 4614 | - * action to keys. |
| 4615 | - **/ |
| 4616 | - window_signals[TOGGLE_SIDEPANE] = |
| 4617 | - g_signal_new (I_("toggle-sidepane"), |
| 4618 | - G_TYPE_FROM_CLASS (klass), |
| 4619 | - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, |
| 4620 | - G_STRUCT_OFFSET (ThunarWindowClass, toggle_sidepane), |
| 4621 | - g_signal_accumulator_true_handled, NULL, |
| 4622 | - _thunar_marshal_BOOLEAN__VOID, |
| 4623 | - G_TYPE_BOOLEAN, 0); |
| 4624 | - |
| 4625 | - /** |
| 4626 | - * ThunarWindow::toggle-sidepane: |
| 4627 | - * @window : a #ThunarWindow instance. |
| 4628 | - * |
| 4629 | - * Emitted whenever the user toggles the visibility of the |
| 4630 | - * sidepane. This is an internal signal used to bind the |
| 4631 | - * action to keys. |
| 4632 | - **/ |
| 4633 | - window_signals[TOGGLE_MENUBAR] = |
| 4634 | - g_signal_new (I_("toggle-menubar"), |
| 4635 | - G_TYPE_FROM_CLASS (klass), |
| 4636 | - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, |
| 4637 | - G_STRUCT_OFFSET (ThunarWindowClass, toggle_menubar), |
| 4638 | - g_signal_accumulator_true_handled, NULL, |
| 4639 | - _thunar_marshal_BOOLEAN__VOID, |
| 4640 | - G_TYPE_BOOLEAN, 0); |
| 4641 | - |
| 4642 | - /** |
| 4643 | - * ThunarWindow::zoom-in: |
| 4644 | - * @window : a #ThunarWindow instance. |
| 4645 | - * |
| 4646 | - * Emitted whenever the user requests to zoom in. This |
| 4647 | - * is an internal signal used to bind the action to keys. |
| 4648 | - **/ |
| 4649 | - window_signals[ZOOM_IN] = |
| 4650 | - g_signal_new (I_("zoom-in"), |
| 4651 | - G_TYPE_FROM_CLASS (klass), |
| 4652 | - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, |
| 4653 | - G_STRUCT_OFFSET (ThunarWindowClass, zoom_in), |
| 4654 | - g_signal_accumulator_true_handled, NULL, |
| 4655 | - _thunar_marshal_BOOLEAN__VOID, |
| 4656 | - G_TYPE_BOOLEAN, 0); |
| 4657 | - |
| 4658 | - /** |
| 4659 | - * ThunarWindow::zoom-out: |
| 4660 | - * @window : a #ThunarWindow instance. |
| 4661 | - * |
| 4662 | - * Emitted whenever the user requests to zoom out. This |
| 4663 | - * is an internal signal used to bind the action to keys. |
| 4664 | - **/ |
| 4665 | - window_signals[ZOOM_OUT] = |
| 4666 | - g_signal_new (I_("zoom-out"), |
| 4667 | - G_TYPE_FROM_CLASS (klass), |
| 4668 | - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, |
| 4669 | - G_STRUCT_OFFSET (ThunarWindowClass, zoom_out), |
| 4670 | - g_signal_accumulator_true_handled, NULL, |
| 4671 | - _thunar_marshal_BOOLEAN__VOID, |
| 4672 | - G_TYPE_BOOLEAN, 0); |
| 4673 | - |
| 4674 | - /** |
| 4675 | - * ThunarWindow::zoom-reset: |
| 4676 | - * @window : a #ThunarWindow instance. |
| 4677 | - * |
| 4678 | - * Emitted whenever the user requests reset the zoom level. |
| 4679 | - * This is an internal signal used to bind the action to keys. |
| 4680 | - **/ |
| 4681 | - window_signals[ZOOM_RESET] = |
| 4682 | - g_signal_new (I_("zoom-reset"), |
| 4683 | - G_TYPE_FROM_CLASS (klass), |
| 4684 | - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, |
| 4685 | - G_STRUCT_OFFSET (ThunarWindowClass, zoom_reset), |
| 4686 | - g_signal_accumulator_true_handled, NULL, |
| 4687 | - _thunar_marshal_BOOLEAN__VOID, |
| 4688 | - G_TYPE_BOOLEAN, 0); |
| 4689 | - |
| 4690 | - /** |
| 4691 | - * ThunarWindow::tab-chage: |
| 4692 | - * @window : a #ThunarWindow instance. |
| 4693 | - * @idx : tab index, |
| 4694 | - * |
| 4695 | - * Emitted whenever the user uses a Alt+N combination to |
| 4696 | - * switch tabs. |
| 4697 | - **/ |
| 4698 | - window_signals[TAB_CHANGE] = |
| 4699 | - g_signal_new (I_("tab-change"), |
| 4700 | - G_TYPE_FROM_CLASS (klass), |
| 4701 | - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, |
| 4702 | - G_STRUCT_OFFSET (ThunarWindowClass, tab_change), |
| 4703 | - g_signal_accumulator_true_handled, NULL, |
| 4704 | - _thunar_marshal_BOOLEAN__INT, |
| 4705 | - G_TYPE_BOOLEAN, 1, |
| 4706 | - G_TYPE_INT); |
| 4707 | - |
| 4708 | - /* setup the key bindings for the windows */ |
| 4709 | - binding_set = gtk_binding_set_by_class (klass); |
| 4710 | - gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "back", 0); |
| 4711 | - gtk_binding_entry_add_signal (binding_set, GDK_F5, 0, "reload", 0); |
| 4712 | - gtk_binding_entry_add_signal (binding_set, GDK_F9, 0, "toggle-sidepane", 0); |
| 4713 | - gtk_binding_entry_add_signal (binding_set, GDK_F10, 0, "toggle-menubar", 0); |
| 4714 | - gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_CONTROL_MASK, "zoom-in", 0); |
| 4715 | - gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, GDK_CONTROL_MASK, "zoom-out", 0); |
| 4716 | - gtk_binding_entry_add_signal (binding_set, GDK_KP_0, GDK_CONTROL_MASK, "zoom-reset", 0); |
| 4717 | - gtk_binding_entry_add_signal (binding_set, GDK_KP_Insert, GDK_CONTROL_MASK, "zoom-reset", 0); |
| 4718 | - |
| 4719 | - /* setup the key bindings for Alt+N */ |
| 4720 | - for (i = 0; i < 10; i++) |
| 4721 | - { |
| 4722 | - gtk_binding_entry_add_signal (binding_set, GDK_0 + i, GDK_MOD1_MASK, |
| 4723 | - "tab-change", 1, G_TYPE_UINT, i - 1); |
| 4724 | - } |
| 4725 | -} |
| 4726 | - |
| 4727 | - |
| 4728 | - |
| 4729 | -static inline gint |
| 4730 | -view_type2index (GType type) |
| 4731 | -{ |
| 4732 | - /* this necessary for platforms where sizeof(GType) != sizeof(gint), |
| 4733 | - * see http://bugzilla.xfce.org/show_bug.cgi?id=2726 for details. |
| 4734 | - */ |
| 4735 | - if (sizeof (GType) == sizeof (gint)) |
| 4736 | - { |
| 4737 | - /* no need to map anything */ |
| 4738 | - return (gint) type; |
| 4739 | - } |
| 4740 | - else |
| 4741 | - { |
| 4742 | - /* map from types to unique indices */ |
| 4743 | - if (G_LIKELY (type == THUNAR_TYPE_COMPACT_VIEW)) |
| 4744 | - return 0; |
| 4745 | - else if (type == THUNAR_TYPE_DETAILS_VIEW) |
| 4746 | - return 1; |
| 4747 | - else |
| 4748 | - return 2; |
| 4749 | - } |
| 4750 | -} |
| 4751 | - |
| 4752 | - |
| 4753 | - |
| 4754 | -static inline GType |
| 4755 | -view_index2type (gint idx) |
| 4756 | -{ |
| 4757 | - /* this necessary for platforms where sizeof(GType) != sizeof(gint), |
| 4758 | - * see http://bugzilla.xfce.org/show_bug.cgi?id=2726 for details. |
| 4759 | - */ |
| 4760 | - if (sizeof (GType) == sizeof (gint)) |
| 4761 | - { |
| 4762 | - /* no need to map anything */ |
| 4763 | - return (GType) idx; |
| 4764 | - } |
| 4765 | - else |
| 4766 | - { |
| 4767 | - /* map from indices to unique types */ |
| 4768 | - switch (idx) |
| 4769 | - { |
| 4770 | - case 0: return THUNAR_TYPE_COMPACT_VIEW; |
| 4771 | - case 1: return THUNAR_TYPE_DETAILS_VIEW; |
| 4772 | - default: return THUNAR_TYPE_ICON_VIEW; |
| 4773 | - } |
| 4774 | - } |
| 4775 | -} |
| 4776 | - |
| 4777 | - |
| 4778 | - |
| 4779 | -static void |
| 4780 | -thunar_window_init (ThunarWindow *window) |
| 4781 | -{ |
| 4782 | - GtkRadioAction *radio_action; |
| 4783 | - GtkAccelGroup *accel_group; |
| 4784 | - GtkWidget *label; |
| 4785 | - GtkWidget *infobar; |
| 4786 | - GtkWidget *item; |
| 4787 | - GtkAction *action; |
| 4788 | - gboolean last_show_hidden; |
| 4789 | - gboolean last_menubar_visible; |
| 4790 | - GSList *group; |
| 4791 | - gchar *last_location_bar; |
| 4792 | - gchar *last_side_pane; |
| 4793 | - GType type; |
| 4794 | - gint last_separator_position; |
| 4795 | - gint last_window_width; |
| 4796 | - gint last_window_height; |
| 4797 | - gboolean last_window_maximized; |
| 4798 | - gboolean last_statusbar_visible; |
| 4799 | - GtkRcStyle *style; |
| 4800 | - |
| 4801 | - /* unset the view type */ |
| 4802 | - window->view_type = G_TYPE_NONE; |
| 4803 | - |
| 4804 | - /* grab a reference on the provider factory */ |
| 4805 | - window->provider_factory = thunarx_provider_factory_get_default (); |
| 4806 | - |
| 4807 | - /* grab a reference on the preferences */ |
| 4808 | - window->preferences = thunar_preferences_get (); |
| 4809 | - |
| 4810 | - /* get all properties for init */ |
| 4811 | - g_object_get (G_OBJECT (window->preferences), |
| 4812 | - "last-show-hidden", &last_show_hidden, |
| 4813 | - "last-window-width", &last_window_width, |
| 4814 | - "last-window-height", &last_window_height, |
| 4815 | - "last-window-maximized", &last_window_maximized, |
| 4816 | - "last-menubar-visible", &last_menubar_visible, |
| 4817 | - "last-separator-position", &last_separator_position, |
| 4818 | - "last-location-bar", &last_location_bar, |
| 4819 | - "last-side-pane", &last_side_pane, |
| 4820 | - "last-statusbar-visible", &last_statusbar_visible, |
| 4821 | - NULL); |
| 4822 | - |
| 4823 | - /* connect to the volume monitor */ |
| 4824 | - window->device_monitor = thunar_device_monitor_get (); |
| 4825 | - g_signal_connect (window->device_monitor, "device-pre-unmount", G_CALLBACK (thunar_window_device_pre_unmount), window); |
| 4826 | - g_signal_connect (window->device_monitor, "device-removed", G_CALLBACK (thunar_window_device_changed), window); |
| 4827 | - g_signal_connect (window->device_monitor, "device-changed", G_CALLBACK (thunar_window_device_changed), window); |
| 4828 | - |
| 4829 | - /* allocate a closure for the menu_item_selected() callback */ |
| 4830 | - window->menu_item_selected_closure = g_cclosure_new_object (G_CALLBACK (thunar_window_menu_item_selected), G_OBJECT (window)); |
| 4831 | - g_closure_ref (window->menu_item_selected_closure); |
| 4832 | - g_closure_sink (window->menu_item_selected_closure); |
| 4833 | - |
| 4834 | - /* allocate a closure for the menu_item_deselected() callback */ |
| 4835 | - window->menu_item_deselected_closure = g_cclosure_new_object (G_CALLBACK (thunar_window_menu_item_deselected), G_OBJECT (window)); |
| 4836 | - g_closure_ref (window->menu_item_deselected_closure); |
| 4837 | - g_closure_sink (window->menu_item_deselected_closure); |
| 4838 | - window->icon_factory = thunar_icon_factory_get_default (); |
| 4839 | - |
| 4840 | - /* setup the action group for this window */ |
| 4841 | - window->action_group = gtk_action_group_new ("ThunarWindow"); |
| 4842 | - gtk_action_group_set_translation_domain (window->action_group, GETTEXT_PACKAGE); |
| 4843 | - gtk_action_group_add_actions (window->action_group, action_entries, G_N_ELEMENTS (action_entries), GTK_WIDGET (window)); |
| 4844 | - gtk_action_group_add_toggle_actions (window->action_group, toggle_action_entries, G_N_ELEMENTS (toggle_action_entries), GTK_WIDGET (window)); |
| 4845 | - |
| 4846 | - /* initialize the "show-hidden" action using the last value from the preferences */ |
| 4847 | - action = gtk_action_group_get_action (window->action_group, "show-hidden"); |
| 4848 | - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), last_show_hidden); |
| 4849 | - |
| 4850 | - /* |
| 4851 | - * add view options |
| 4852 | - */ |
| 4853 | - radio_action = gtk_radio_action_new ("view-as-icons", _("View as _Icons"), _("Display folder content in an icon view"), |
| 4854 | - NULL, view_type2index (THUNAR_TYPE_ICON_VIEW)); |
| 4855 | - gtk_action_group_add_action_with_accel (window->action_group, GTK_ACTION (radio_action), "<control>1"); |
| 4856 | - gtk_radio_action_set_group (radio_action, NULL); |
| 4857 | - group = gtk_radio_action_get_group (radio_action); |
| 4858 | - g_object_unref (G_OBJECT (radio_action)); |
| 4859 | - |
| 4860 | - radio_action = gtk_radio_action_new ("view-as-detailed-list", _("View as _Detailed List"), _("Display folder content in a detailed list view"), |
| 4861 | - NULL, view_type2index (THUNAR_TYPE_DETAILS_VIEW)); |
| 4862 | - gtk_action_group_add_action_with_accel (window->action_group, GTK_ACTION (radio_action), "<control>2"); |
| 4863 | - gtk_radio_action_set_group (radio_action, group); |
| 4864 | - group = gtk_radio_action_get_group (radio_action); |
| 4865 | - g_object_unref (G_OBJECT (radio_action)); |
| 4866 | - |
| 4867 | - radio_action = gtk_radio_action_new ("view-as-compact-list", _("View as _Compact List"), _("Display folder content in a compact list view"), |
| 4868 | - NULL, view_type2index (THUNAR_TYPE_COMPACT_VIEW)); |
| 4869 | - gtk_action_group_add_action_with_accel (window->action_group, GTK_ACTION (radio_action), "<control>3"); |
| 4870 | - gtk_radio_action_set_group (radio_action, group); |
| 4871 | - group = gtk_radio_action_get_group (radio_action); |
| 4872 | - g_object_unref (G_OBJECT (radio_action)); |
| 4873 | - |
| 4874 | - window->ui_manager = gtk_ui_manager_new (); |
| 4875 | - g_signal_connect (G_OBJECT (window->ui_manager), "connect-proxy", G_CALLBACK (thunar_window_connect_proxy), window); |
| 4876 | - g_signal_connect (G_OBJECT (window->ui_manager), "disconnect-proxy", G_CALLBACK (thunar_window_disconnect_proxy), window); |
| 4877 | - gtk_ui_manager_insert_action_group (window->ui_manager, window->action_group, 0); |
| 4878 | - gtk_ui_manager_add_ui_from_string (window->ui_manager, thunar_window_ui, thunar_window_ui_length, NULL); |
| 4879 | - |
| 4880 | - accel_group = gtk_ui_manager_get_accel_group (window->ui_manager); |
| 4881 | - gtk_window_add_accel_group (GTK_WINDOW (window), accel_group); |
| 4882 | - |
| 4883 | - /* setup the launcher support */ |
| 4884 | - window->launcher = thunar_launcher_new (); |
| 4885 | - thunar_launcher_set_widget (window->launcher, GTK_WIDGET (window)); |
| 4886 | - thunar_component_set_ui_manager (THUNAR_COMPONENT (window->launcher), window->ui_manager); |
| 4887 | - exo_binding_new (G_OBJECT (window), "current-directory", G_OBJECT (window->launcher), "current-directory"); |
| 4888 | - g_signal_connect_swapped (G_OBJECT (window->launcher), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window); |
| 4889 | - g_signal_connect_swapped (G_OBJECT (window->launcher), "open-new-tab", G_CALLBACK (thunar_window_notebook_insert), window); |
| 4890 | - |
| 4891 | - /* determine the default window size from the preferences */ |
| 4892 | - gtk_window_set_default_size (GTK_WINDOW (window), last_window_width, last_window_height); |
| 4893 | - |
| 4894 | - /* restore the maxized state of the window */ |
| 4895 | - if (G_UNLIKELY (last_window_maximized)) |
| 4896 | - gtk_window_maximize (GTK_WINDOW (window)); |
| 4897 | - |
| 4898 | - window->table = gtk_table_new (6, 1, FALSE); |
| 4899 | - gtk_container_add (GTK_CONTAINER (window), window->table); |
| 4900 | - gtk_widget_show (window->table); |
| 4901 | - |
| 4902 | - window->menubar = gtk_ui_manager_get_widget (window->ui_manager, "/main-menu"); |
| 4903 | - gtk_table_attach (GTK_TABLE (window->table), window->menubar, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); |
| 4904 | - |
| 4905 | - /* update menubar visibiliy */ |
| 4906 | - action = gtk_action_group_get_action (window->action_group, "view-menubar"); |
| 4907 | - g_signal_connect (G_OBJECT (window->menubar), "deactivate", G_CALLBACK (thunar_window_toggle_menubar_deactivate), window); |
| 4908 | - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), last_menubar_visible); |
| 4909 | - |
| 4910 | - /* append the menu item for the spinner */ |
| 4911 | - item = gtk_menu_item_new (); |
| 4912 | - gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE); |
| 4913 | - gtk_menu_item_set_right_justified (GTK_MENU_ITEM (item), TRUE); |
| 4914 | - gtk_menu_shell_append (GTK_MENU_SHELL (window->menubar), item); |
| 4915 | - gtk_widget_show (item); |
| 4916 | - |
| 4917 | - /* place the spinner into the menu item */ |
| 4918 | - window->spinner = gtk_spinner_new (); |
| 4919 | - gtk_container_add (GTK_CONTAINER (item), window->spinner); |
| 4920 | - exo_binding_new (G_OBJECT (window->spinner), "active", |
| 4921 | - G_OBJECT (window->spinner), "visible"); |
| 4922 | - |
| 4923 | - /* check if we need to add the root warning */ |
| 4924 | - if (G_UNLIKELY (geteuid () == 0)) |
| 4925 | - { |
| 4926 | - /* add the bar for the root warning */ |
| 4927 | - infobar = gtk_info_bar_new (); |
| 4928 | - gtk_info_bar_set_message_type (GTK_INFO_BAR (infobar), GTK_MESSAGE_WARNING); |
| 4929 | - gtk_table_attach (GTK_TABLE (window->table), infobar, 0, 1, 2, 3, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); |
| 4930 | - gtk_widget_show (infobar); |
| 4931 | - |
| 4932 | - /* add the label with the root warning */ |
| 4933 | - label = gtk_label_new (_("Warning, you are using the root account, you may harm your system.")); |
| 4934 | - gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (infobar))), label); |
| 4935 | - gtk_widget_show (label); |
| 4936 | - } |
| 4937 | - |
| 4938 | - window->paned = gtk_hpaned_new (); |
| 4939 | - gtk_container_set_border_width (GTK_CONTAINER (window->paned), 0); |
| 4940 | - gtk_table_attach (GTK_TABLE (window->table), window->paned, 0, 1, 4, 5, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); |
| 4941 | - gtk_widget_show (window->paned); |
| 4942 | - |
| 4943 | - /* determine the last separator position and apply it to the paned view */ |
| 4944 | - gtk_paned_set_position (GTK_PANED (window->paned), last_separator_position); |
| 4945 | - g_signal_connect_swapped (window->paned, "accept-position", G_CALLBACK (thunar_window_save_paned), window); |
| 4946 | - g_signal_connect_swapped (window->paned, "button-release-event", G_CALLBACK (thunar_window_save_paned), window); |
| 4947 | - |
| 4948 | - window->view_box = gtk_table_new (3, 1, FALSE); |
| 4949 | - gtk_paned_pack2 (GTK_PANED (window->paned), window->view_box, TRUE, FALSE); |
| 4950 | - gtk_widget_show (window->view_box); |
| 4951 | - |
| 4952 | - /* tabs */ |
| 4953 | - window->notebook = gtk_notebook_new (); |
| 4954 | - gtk_table_attach (GTK_TABLE (window->view_box), window->notebook, 0, 1, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); |
| 4955 | - g_signal_connect (G_OBJECT (window->notebook), "switch-page", G_CALLBACK (thunar_window_notebook_switch_page), window); |
| 4956 | - g_signal_connect (G_OBJECT (window->notebook), "page-added", G_CALLBACK (thunar_window_notebook_page_added), window); |
| 4957 | - g_signal_connect (G_OBJECT (window->notebook), "page-removed", G_CALLBACK (thunar_window_notebook_page_removed), window); |
| 4958 | - g_signal_connect_after (G_OBJECT (window->notebook), "button-press-event", G_CALLBACK (thunar_window_notebook_button_press_event), window); |
| 4959 | - g_signal_connect (G_OBJECT (window->notebook), "popup-menu", G_CALLBACK (thunar_window_notebook_popup_menu), window); |
| 4960 | - g_signal_connect (G_OBJECT (window->notebook), "create-window", G_CALLBACK (thunar_window_notebook_create_window), window); |
| 4961 | - gtk_notebook_set_show_border (GTK_NOTEBOOK (window->notebook), FALSE); |
| 4962 | - gtk_notebook_set_homogeneous_tabs (GTK_NOTEBOOK (window->notebook), TRUE); |
| 4963 | - gtk_notebook_set_scrollable (GTK_NOTEBOOK (window->notebook), TRUE); |
| 4964 | - gtk_container_set_border_width (GTK_CONTAINER (window->notebook), 0); |
| 4965 | - gtk_notebook_set_group_name (GTK_NOTEBOOK (window->notebook), "thunar-tabs"); |
| 4966 | - gtk_widget_show (window->notebook); |
| 4967 | - |
| 4968 | - /* drop the notebook borders */ |
| 4969 | - style = gtk_rc_style_new (); |
| 4970 | - style->xthickness = style->ythickness = 0; |
| 4971 | - gtk_widget_modify_style (window->notebook, style); |
| 4972 | - g_object_unref (G_OBJECT (style)); |
| 4973 | - |
| 4974 | - /* determine the selected location selector */ |
| 4975 | - if (exo_str_is_equal (last_location_bar, g_type_name (THUNAR_TYPE_LOCATION_BUTTONS))) |
| 4976 | - type = THUNAR_TYPE_LOCATION_BUTTONS; |
| 4977 | - else if (exo_str_is_equal (last_location_bar, g_type_name (THUNAR_TYPE_LOCATION_ENTRY))) |
| 4978 | - type = THUNAR_TYPE_LOCATION_ENTRY; |
| 4979 | - else |
| 4980 | - type = G_TYPE_NONE; |
| 4981 | - g_free (last_location_bar); |
| 4982 | - |
| 4983 | - /* activate the selected location selector */ |
| 4984 | - action = gtk_action_group_get_action (window->action_group, "view-location-selector-pathbar"); |
| 4985 | - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), (type == THUNAR_TYPE_LOCATION_BUTTONS)); |
| 4986 | - action = gtk_action_group_get_action (window->action_group, "view-location-selector-toolbar"); |
| 4987 | - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), (type == THUNAR_TYPE_LOCATION_ENTRY)); |
| 4988 | - |
| 4989 | - /* determine the selected side pane (FIXME: Should probably be last-shortcuts-visible and last-tree-visible preferences) */ |
| 4990 | - if (exo_str_is_equal (last_side_pane, g_type_name (THUNAR_TYPE_SHORTCUTS_PANE))) |
| 4991 | - type = THUNAR_TYPE_SHORTCUTS_PANE; |
| 4992 | - else if (exo_str_is_equal (last_side_pane, g_type_name (THUNAR_TYPE_TREE_PANE))) |
| 4993 | - type = THUNAR_TYPE_TREE_PANE; |
| 4994 | - else |
| 4995 | - type = G_TYPE_NONE; |
| 4996 | - g_free (last_side_pane); |
| 4997 | - |
| 4998 | - /* activate the selected side pane */ |
| 4999 | - action = gtk_action_group_get_action (window->action_group, "view-side-pane-shortcuts"); |
| 5000 | - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), (type == THUNAR_TYPE_SHORTCUTS_PANE)); |
The diff has been truncated for viewing.


It'd be really nice if you could explain in d/changelog why the patches are dropped.