Compare commits
No commits in common. "upstream-4.20.7" and "usagebars" have entirely different histories.
upstream-4
...
usagebars
86 changed files with 23543 additions and 35236 deletions
96
NEWS
96
NEWS
|
|
@ -1,99 +1,3 @@
|
|||
4.20.7 (2026-01-23)
|
||||
======
|
||||
- Prevent crash on unmount (#1778)
|
||||
- Show 'queued' message only for queued jobs (#1755)
|
||||
- Prevent crash on non-local symlinks (#1757)
|
||||
- Fix g_object_unref warning
|
||||
- Fix symlink resolve for desktop files (#1757)
|
||||
- Translation Updates:
|
||||
Albanian, Arabic, Asturian, Basque, Belarusian, Bulgarian, Catalan,
|
||||
Chinese (China), Chinese (Taiwan), Czech, Danish, Dutch, English
|
||||
(United Kingdom), Estonian, Finnish, French, Galician, Georgian,
|
||||
German, Greek, Hungarian, Indonesian, Interlingue, Japanese, Kazakh,
|
||||
Malay, Norwegian Bokmål, Occitan (post 1500), Polish, Portuguese
|
||||
(Brazil), Romanian, Serbian, Slovenian, Spanish, Swedish, Thai,
|
||||
Turkish, Venetian, Vietnamese
|
||||
|
||||
4.20.6 (2025-10-16)
|
||||
======
|
||||
- Prevent GFileMonitor leak for folders (#1724)
|
||||
- Don't use variables for strings in ngettext (#1683)
|
||||
- Fix 'MOUNTED' state on file reload when unmounted
|
||||
- Translation Updates:
|
||||
Albanian, Arabic, Armenian, Armenian (Armenia), Asturian, Basque,
|
||||
Belarusian, Bengali, Bulgarian, Catalan, Chinese (China), Chinese
|
||||
(Hong Kong), Chinese (Taiwan), Czech, Danish, Dutch, Eastern
|
||||
Armenian, English (Australia), English (United Kingdom), Esperanto,
|
||||
Estonian, Finnish, French, Galician, Georgian, German, Greek,
|
||||
Hungarian, Icelandic, Indonesian, Interlingue, Japanese, Kazakh,
|
||||
Latvian, Malay, Norwegian Bokmål, Norwegian Nynorsk, Occitan (post
|
||||
1500), Persian (Iran), Polish, Portuguese (Brazil), Romanian,
|
||||
Serbian, Slovenian, Spanish, Swedish, Thai, Turkish, Venetian,
|
||||
Vietnamese
|
||||
|
||||
4.20.5 (2025-09-14)
|
||||
======
|
||||
- Update shortcut model asynchronously (#1022)
|
||||
- Clear selection before updating selection (#1672)
|
||||
- Translation Updates:
|
||||
Chinese (China), English (United Kingdom), Finnish, Greek, Occitan
|
||||
(post 1500), Polish
|
||||
|
||||
4.20.4 (2025-07-18)
|
||||
======
|
||||
- Improve file add/remove checks for ThunarFolder (#1649)
|
||||
- Properly update view after hidden file rename
|
||||
- Always reload ThunarFiles on change notice (#1650)
|
||||
- Directly notify after file reload (#1650)
|
||||
- Set initial state of "Restore" button (#1663)
|
||||
- Fix quoting when running shell scripts in a terminal (#1661)
|
||||
- Avoid use-after-free in rename dialog when file is changed
|
||||
- Fix a GFile leak in _thunar_io_jobs_rename
|
||||
- Fix use-after-free in thunar_renamer_dialog_response (#1458)
|
||||
- Fix use-after-free on exit with search tabs open (#1593)
|
||||
- Translation Updates:
|
||||
Arabic, Chinese (China), Danish, Esperanto, Galician, Georgian,
|
||||
Greek, Norwegian Bokmål, Polish, Portuguese (Brazil), Spanish,
|
||||
Turkish, Vietnamese
|
||||
|
||||
4.20.3 (2025-05-16)
|
||||
======
|
||||
- Always warn user before permanent deleting files
|
||||
- Fix string leaks when UCAs use a submenu
|
||||
- Fix a potential leak in thunar_action_manager_append_custom_actions
|
||||
- Fix leaks with ThunarMenuX objects
|
||||
- Fix thunarx_menu_get_items leak when multiple UCAs share a submenu
|
||||
- Fix refresh on row-changed in list view (#1584)
|
||||
- Add missing NULL check before unref call
|
||||
- Fix popup position of DnD menu
|
||||
- UCA: Correct PWD for submenu folder items (#1615)
|
||||
- wayland: Fix popup menu not closing (#1592)
|
||||
- Check if file exists before opening its location (#1257)
|
||||
- Prevent popups on wrong window (#1591)
|
||||
- thunar-tpa: Fix libxfce4panel include
|
||||
- Prevent criticals when switching current view (#1344)
|
||||
- Fix crash when destroying folder in list view (#1330) (#1568)
|
||||
- Fix crash in properties dialog (#1585)
|
||||
- Fix invalid filenames when copying to exFAT FS (#1570)
|
||||
- Fix typo in preferences dialog
|
||||
- Hide shortcuts editor when accel map uninitialized (#1488)
|
||||
- Update statusbar when searching (#1560)
|
||||
- Always update statusbar on file changes in list view (#1560)
|
||||
- Fix item activation on double-click in list view (#1567)
|
||||
- Use 'malloc_trim' after search (#1552)
|
||||
- Fix missing dialog for folder errors in list view (#1538)
|
||||
- Fix leak on search update
|
||||
- Fix missing dialog window icon (#1506)
|
||||
- Fix leaks on "cancel search"
|
||||
- Properly check if a file can be trashed (#1554)
|
||||
- Translation Updates:
|
||||
Albanian, Bulgarian, Catalan, Chinese (China), Chinese (Taiwan),
|
||||
Czech, Danish, Dutch, English (United Kingdom), Estonian, Finnish,
|
||||
French, Georgian, German, Greek, Hebrew, Hungarian, Italian,
|
||||
Japanese, Norwegian Bokmål, Occitan (post 1500), Polish, Portuguese,
|
||||
Portuguese (Brazil), Romanian, Serbian, Slovenian, Swedish, Turkish,
|
||||
Venetian, Vietnamese
|
||||
|
||||
4.20.2 (2025-02-10)
|
||||
======
|
||||
- Fix wrong selection after rename in list view (#1415)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ dnl ***************************
|
|||
m4_define([thunarx_verinfo], [0:0:0])
|
||||
m4_define([thunarx_version_api], [3])
|
||||
|
||||
XDT_VERSION_INIT([4.20.7])
|
||||
XDT_VERSION_INIT([4.20.2])
|
||||
|
||||
dnl ***************************
|
||||
dnl *** Initialize autoconf ***
|
||||
|
|
@ -123,7 +123,7 @@ AC_SYS_LARGEFILE()
|
|||
dnl **********************************
|
||||
dnl *** Check for standard headers ***
|
||||
dnl **********************************
|
||||
AC_CHECK_HEADERS([ctype.h errno.h fcntl.h grp.h limits.h locale.h malloc.h memory.h \
|
||||
AC_CHECK_HEADERS([ctype.h errno.h fcntl.h grp.h limits.h locale.h memory.h \
|
||||
paths.h pwd.h sched.h signal.h stdarg.h stdlib.h string.h \
|
||||
sys/mman.h sys/param.h sys/stat.h sys/time.h sys/types.h \
|
||||
sys/uio.h sys/wait.h time.h])
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <libxfce4panel/libxfce4panel.h>
|
||||
#include <libxfce4panel/xfce-panel-macros.h>
|
||||
#include <libxfce4ui/libxfce4ui.h>
|
||||
#include <libxfce4util/libxfce4util.h>
|
||||
#include <thunar-tpa/thunar-tpa-bindings.h>
|
||||
|
|
|
|||
|
|
@ -222,13 +222,12 @@ find_submenu_by_name (gchar *name, GList *items)
|
|||
if (thunarx_menu_items != NULL)
|
||||
{
|
||||
ThunarxMenu *submenu = find_submenu_by_name (name, thunarx_menu_items);
|
||||
thunarx_menu_item_list_free (thunarx_menu_items);
|
||||
|
||||
if (submenu != NULL)
|
||||
{
|
||||
g_free (item_name);
|
||||
return submenu;
|
||||
}
|
||||
thunarx_menu_item_list_free (thunarx_menu_items);
|
||||
}
|
||||
}
|
||||
g_free (item_name);
|
||||
|
|
@ -298,11 +297,7 @@ thunar_uca_provider_get_file_menu_items (ThunarxMenuProvider *menu_provider,
|
|||
gchar *sub_menu_path = g_strdup (sub_menus_as_array[0]);
|
||||
|
||||
for (int j = 1; j <= i; j++)
|
||||
{
|
||||
gchar *prev_path = sub_menu_path;
|
||||
sub_menu_path = g_strconcat (prev_path, "/", sub_menus_as_array[j], NULL);
|
||||
g_free (prev_path);
|
||||
}
|
||||
sub_menu_path = g_strconcat (sub_menu_path, "/", sub_menus_as_array[j], NULL);
|
||||
|
||||
/* Check if the full path already exists */
|
||||
submenu = find_submenu_by_name (sub_menu_path, items);
|
||||
|
|
@ -386,36 +381,6 @@ thunar_uca_provider_get_file_menu_items (ThunarxMenuProvider *menu_provider,
|
|||
|
||||
|
||||
|
||||
static void
|
||||
set_folder_quarks_recursive (GList *items)
|
||||
{
|
||||
GList *lp;
|
||||
GList *thunarx_menu_items;
|
||||
|
||||
for (lp = g_list_first (items); lp != NULL; lp = lp->next)
|
||||
{
|
||||
ThunarxMenu *item_menu = NULL;
|
||||
g_object_get (G_OBJECT (lp->data), "menu", &item_menu, NULL);
|
||||
|
||||
if (item_menu != NULL)
|
||||
{
|
||||
/* Some submenu found .. lets walk through it recursively */
|
||||
thunarx_menu_items = thunarx_menu_get_items (item_menu);
|
||||
g_object_unref (item_menu);
|
||||
|
||||
if (thunarx_menu_items != NULL)
|
||||
{
|
||||
set_folder_quarks_recursive (thunarx_menu_items);
|
||||
thunarx_menu_item_list_free (thunarx_menu_items);
|
||||
}
|
||||
}
|
||||
else
|
||||
g_object_set_qdata (G_OBJECT (lp->data), thunar_uca_folder_quark, GUINT_TO_POINTER (TRUE));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static GList *
|
||||
thunar_uca_provider_get_folder_menu_items (ThunarxMenuProvider *menu_provider,
|
||||
GtkWidget *window,
|
||||
|
|
@ -423,6 +388,7 @@ thunar_uca_provider_get_folder_menu_items (ThunarxMenuProvider *menu_provider,
|
|||
{
|
||||
GList *items;
|
||||
GList files;
|
||||
GList *lp;
|
||||
|
||||
/* fake a file list... */
|
||||
files.data = folder;
|
||||
|
|
@ -432,8 +398,9 @@ thunar_uca_provider_get_folder_menu_items (ThunarxMenuProvider *menu_provider,
|
|||
/* ...and use the get_file_menu_items() method */
|
||||
items = thunarx_menu_provider_get_file_menu_items (menu_provider, window, &files);
|
||||
|
||||
/* mark the menu items as folder menu items, so we can properly detect the working directory */
|
||||
set_folder_quarks_recursive (items);
|
||||
/* mark the menu items, so we can properly detect the working directory */
|
||||
for (lp = items; lp != NULL; lp = lp->next)
|
||||
g_object_set_qdata (G_OBJECT (lp->data), thunar_uca_folder_quark, GUINT_TO_POINTER (TRUE));
|
||||
|
||||
return items;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ ie
|
|||
is
|
||||
it
|
||||
ja
|
||||
ka
|
||||
kk
|
||||
ko
|
||||
lt
|
||||
|
|
@ -60,7 +59,6 @@ ug
|
|||
uk
|
||||
ur_PK
|
||||
ur
|
||||
vec
|
||||
vi
|
||||
zh_CN
|
||||
zh_HK
|
||||
|
|
|
|||
880
po/en_AU.po
880
po/en_AU.po
File diff suppressed because it is too large
Load diff
884
po/en_GB.po
884
po/en_GB.po
File diff suppressed because it is too large
Load diff
862
po/fa_IR.po
862
po/fa_IR.po
File diff suppressed because it is too large
Load diff
879
po/hy_AM.po
879
po/hy_AM.po
File diff suppressed because it is too large
Load diff
1444
po/pt_BR.po
1444
po/pt_BR.po
File diff suppressed because it is too large
Load diff
891
po/zh_CN.po
891
po/zh_CN.po
File diff suppressed because it is too large
Load diff
858
po/zh_HK.po
858
po/zh_HK.po
File diff suppressed because it is too large
Load diff
884
po/zh_TW.po
884
po/zh_TW.po
File diff suppressed because it is too large
Load diff
|
|
@ -172,6 +172,8 @@ thunar_SOURCES = \
|
|||
thunar-shortcuts-icon-renderer.h \
|
||||
thunar-shortcuts-model.c \
|
||||
thunar-shortcuts-model.h \
|
||||
thunar-shortcuts-progress-renderer.c \
|
||||
thunar-shortcuts-progress-renderer.h \
|
||||
thunar-shortcuts-pane.c \
|
||||
thunar-shortcuts-pane.h \
|
||||
thunar-shortcuts-view.c \
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ main (int argc, char **argv)
|
|||
application = thunar_application_get ();
|
||||
|
||||
/* use the Thunar icon as default for new windows */
|
||||
gtk_window_set_default_icon_name ("org.xfce.thunar");
|
||||
gtk_window_set_default_icon_name ("Thunar");
|
||||
|
||||
/* do further processing inside gapplication */
|
||||
g_application_run (G_APPLICATION (application), argc, argv);
|
||||
|
|
|
|||
|
|
@ -1525,17 +1525,7 @@ thunar_action_manager_action_open_location (ThunarActionManager *action_mgr)
|
|||
return TRUE;
|
||||
|
||||
for (lp = action_mgr->files_to_process; lp != NULL; lp = lp->next)
|
||||
{
|
||||
ThunarFile *file = lp->data;
|
||||
if (thunar_file_exists (file))
|
||||
gfiles = g_list_prepend (gfiles, thunar_file_get_file (file));
|
||||
else
|
||||
{
|
||||
GError *error = g_error_new (G_FILE_ERROR, G_FILE_ERROR_NOENT, _("File does not exist anymore"));
|
||||
thunar_dialogs_show_error (action_mgr->widget, error, _("Failed to open location for \"%s\""), thunar_file_get_display_name (file));
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
gfiles = g_list_prepend (gfiles, thunar_file_get_file (THUNAR_FILE (lp->data)));
|
||||
|
||||
thunar_window_open_files_in_location (THUNAR_WINDOW (action_mgr->widget), gfiles);
|
||||
|
||||
|
|
@ -1668,7 +1658,7 @@ thunar_action_manager_append_menu_item (ThunarActionManager *action_mgr,
|
|||
|
||||
case THUNAR_ACTION_MANAGER_ACTION_OPEN_IN_TAB:
|
||||
n = action_mgr->n_files_to_process > 0 ? action_mgr->n_files_to_process : 1;
|
||||
label_text = g_strdup_printf (ngettext ("Open in new _Tab", "Open in %d New _Tabs", n), n);
|
||||
label_text = g_strdup_printf (ngettext (action_entry->menu_item_label_text, "Open in %d New _Tabs", n), n);
|
||||
tooltip_text = g_strdup_printf (ngettext ("Open the selected directory in new tab",
|
||||
"Open the selected directories in %d new tabs", n),
|
||||
n);
|
||||
|
|
@ -1679,7 +1669,7 @@ thunar_action_manager_append_menu_item (ThunarActionManager *action_mgr,
|
|||
|
||||
case THUNAR_ACTION_MANAGER_ACTION_OPEN_IN_WINDOW:
|
||||
n = action_mgr->n_files_to_process > 0 ? action_mgr->n_files_to_process : 1;
|
||||
label_text = g_strdup_printf (ngettext ("Open in new _Window", "Open in %d New _Windows", n), n);
|
||||
label_text = g_strdup_printf (ngettext (action_entry->menu_item_label_text, "Open in %d New _Windows", n), n);
|
||||
tooltip_text = g_strdup_printf (ngettext ("Open the selected directory in new window",
|
||||
"Open the selected directories in %d new windows", n),
|
||||
n);
|
||||
|
|
@ -1717,7 +1707,7 @@ thunar_action_manager_append_menu_item (ThunarActionManager *action_mgr,
|
|||
if (!show_item && !force)
|
||||
return NULL;
|
||||
|
||||
label_text = ngettext ("Ma_ke Link", "Ma_ke Links", action_mgr->n_files_to_process);
|
||||
label_text = ngettext (action_entry->menu_item_label_text, "Ma_ke Links", action_mgr->n_files_to_process);
|
||||
tooltip_text = ngettext ("Create a symbolic link for the selected file",
|
||||
"Create a symbolic link for each selected file", action_mgr->n_files_to_process);
|
||||
item = xfce_gtk_menu_item_new (label_text, tooltip_text, action_entry->accel_path, action_entry->callback,
|
||||
|
|
@ -2401,10 +2391,6 @@ thunar_action_manager_append_custom_actions (ThunarActionManager *action_mgr,
|
|||
_thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE);
|
||||
_thunar_return_val_if_fail (GTK_IS_MENU (menu), FALSE);
|
||||
|
||||
/* This may occur when the thunar-window is build */
|
||||
if (G_UNLIKELY (action_mgr->files_to_process == NULL))
|
||||
return FALSE;
|
||||
|
||||
/* determine the toplevel window we belong to */
|
||||
window = gtk_widget_get_toplevel (action_mgr->widget);
|
||||
|
||||
|
|
@ -2416,6 +2402,10 @@ thunar_action_manager_append_custom_actions (ThunarActionManager *action_mgr,
|
|||
if (G_UNLIKELY (providers == NULL))
|
||||
return FALSE;
|
||||
|
||||
/* This may occur when the thunar-window is build */
|
||||
if (G_UNLIKELY (action_mgr->files_to_process == NULL))
|
||||
return FALSE;
|
||||
|
||||
/* load the menu items offered by the menu providers */
|
||||
for (lp_provider = providers; lp_provider != NULL; lp_provider = lp_provider->next)
|
||||
{
|
||||
|
|
@ -2676,7 +2666,7 @@ thunar_action_manager_action_trash_delete (ThunarActionManager *action_mgr)
|
|||
/* when shift modifier is pressed, we delete (as well via context menu) */
|
||||
if (gtk_get_current_event_state (&event_state) && (event_state & GDK_SHIFT_MASK) != 0)
|
||||
thunar_action_manager_action_delete (action_mgr);
|
||||
else if (thunar_action_manager_show_trash (action_mgr))
|
||||
else if (thunar_g_vfs_is_uri_scheme_supported ("trash") && !thunar_file_is_trashed (action_mgr->current_directory))
|
||||
thunar_action_manager_action_move_to_trash (action_mgr);
|
||||
else
|
||||
thunar_action_manager_action_delete (action_mgr);
|
||||
|
|
|
|||
|
|
@ -27,9 +27,6 @@
|
|||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_MALLOC_H
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#ifdef HAVE_MEMORY_H
|
||||
#include <memory.h>
|
||||
#endif
|
||||
|
|
@ -2441,7 +2438,7 @@ unlink_stub (GList *source_path_list,
|
|||
* @parent : a #GdkScreen, a #GtkWidget or %NULL.
|
||||
* @file_list : the list of #ThunarFile<!---->s that should be deleted.
|
||||
* @permanently : whether to unlink the files permanently.
|
||||
* @warn : whether to warn the user if moving files to trash.
|
||||
* @warn : whether to warn the user if deleting permanently.
|
||||
* @log_mode : log mode
|
||||
*
|
||||
* Deletes all files in the @file_list and takes care of all user interaction.
|
||||
|
|
@ -2462,7 +2459,7 @@ thunar_application_unlink_files (ThunarApplication *application,
|
|||
{
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *message_area;
|
||||
GtkWindow *window = NULL;
|
||||
GtkWindow *window;
|
||||
GdkScreen *screen;
|
||||
GList *path_list = NULL;
|
||||
GList *lp;
|
||||
|
|
@ -2492,7 +2489,7 @@ thunar_application_unlink_files (ThunarApplication *application,
|
|||
return FALSE;
|
||||
|
||||
/* ask the user to confirm if deleting permanently */
|
||||
if (G_UNLIKELY (permanently))
|
||||
if (G_UNLIKELY (permanently) && warn)
|
||||
{
|
||||
/* parse the parent pointer */
|
||||
screen = thunar_util_parse_parent (parent, &window);
|
||||
|
|
@ -2558,6 +2555,12 @@ thunar_application_unlink_files (ThunarApplication *application,
|
|||
else
|
||||
operation_canceled = TRUE;
|
||||
}
|
||||
else if (G_UNLIKELY (permanently))
|
||||
{
|
||||
thunar_application_launch (application, parent, "edit-delete",
|
||||
_("Deleting files..."), unlink_stub,
|
||||
path_list, path_list, TRUE, FALSE, log_mode, NULL);
|
||||
}
|
||||
else if (G_LIKELY (!permanently) && warn)
|
||||
{
|
||||
/* parse the parent pointer */
|
||||
|
|
@ -2757,7 +2760,7 @@ thunar_application_empty_trash (ThunarApplication *application,
|
|||
const gchar *startup_id)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
GtkWindow *window = NULL;
|
||||
GtkWindow *window;
|
||||
GdkScreen *screen;
|
||||
GList file_list;
|
||||
gint response;
|
||||
|
|
@ -2905,28 +2908,3 @@ thunar_application_get_thumbnail_cache (ThunarApplication *application)
|
|||
|
||||
return g_object_ref (application->thumbnail_cache);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gboolean
|
||||
thunar_application_malloc_trim_idle (gpointer application_ptr)
|
||||
{
|
||||
#ifdef __GLIBC__
|
||||
/* Workaround to make the kernel reclaim memory which is not used by Thunar anymore. */
|
||||
/* When using glibc, after releasing bigger memory chunks it seems to be required to call that 'garbage collector'. */
|
||||
/* More information here: https://gitlab.xfce.org/xfce/thunar/-/issues/1552#note_101990 */
|
||||
malloc_trim (0);
|
||||
#endif
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
thunar_application_malloc_trim_on_idle (ThunarApplication *application)
|
||||
{
|
||||
_thunar_return_if_fail (THUNAR_IS_APPLICATION (application));
|
||||
|
||||
g_idle_add (thunar_application_malloc_trim_idle, application);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -205,9 +205,6 @@ thunar_application_get_thumbnail_cache (ThunarApplication *application);
|
|||
gboolean
|
||||
thunar_application_accel_map_init (ThunarApplication *application);
|
||||
|
||||
void
|
||||
thunar_application_malloc_trim_on_idle (ThunarApplication *application);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_APPLICATION_H__ */
|
||||
|
|
|
|||
|
|
@ -1238,9 +1238,6 @@ thunar_details_view_row_activated (GtkTreeView *tree_view,
|
|||
|
||||
_thunar_return_if_fail (THUNAR_IS_DETAILS_VIEW (details_view));
|
||||
|
||||
/* ensure that the path is selected on double-click events */
|
||||
thunar_details_view_select_path (THUNAR_STANDARD_VIEW (details_view), path);
|
||||
|
||||
window = gtk_widget_get_toplevel (GTK_WIDGET (details_view));
|
||||
action_mgr = thunar_window_get_action_manager (THUNAR_WINDOW (window));
|
||||
thunar_action_manager_activate_selected_files (action_mgr, THUNAR_ACTION_MANAGER_CHANGE_DIRECTORY, NULL);
|
||||
|
|
@ -1312,7 +1309,7 @@ thunar_details_view_row_changed (GtkTreeView *tree_view,
|
|||
{
|
||||
_thunar_return_if_fail (THUNAR_IS_DETAILS_VIEW (details_view));
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (details_view->tree_view));
|
||||
gtk_widget_queue_draw (GTK_WIDGET (details_view));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ thunar_dialogs_show_create (gpointer parent,
|
|||
const gchar *title)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
GtkWindow *window = NULL;
|
||||
GtkWindow *window;
|
||||
GdkScreen *screen;
|
||||
GError *error = NULL;
|
||||
gchar *name = NULL;
|
||||
|
|
@ -225,7 +225,7 @@ thunar_dialogs_show_rename_file (gpointer parent,
|
|||
ThunarIconFactory *icon_factory;
|
||||
GtkIconTheme *icon_theme;
|
||||
gint scale_factor;
|
||||
gchar *filename;
|
||||
const gchar *filename;
|
||||
const gchar *text;
|
||||
ThunarJob *job = NULL;
|
||||
GtkWidget *dialog;
|
||||
|
|
@ -234,7 +234,7 @@ thunar_dialogs_show_rename_file (gpointer parent,
|
|||
GtkWidget *grid;
|
||||
XfceFilenameInput *filename_input;
|
||||
GtkEntry *filename_input_entry;
|
||||
GtkWindow *window = NULL;
|
||||
GtkWindow *window;
|
||||
GdkScreen *screen;
|
||||
GdkPixbuf *icon;
|
||||
cairo_surface_t *surface;
|
||||
|
|
@ -250,9 +250,8 @@ thunar_dialogs_show_rename_file (gpointer parent,
|
|||
/* parse the parent window and screen */
|
||||
screen = thunar_util_parse_parent (parent, &window);
|
||||
|
||||
/* Get the filename of the file. We create our own copy of the string because the file
|
||||
* can be modified by another process while the rename is in progress (issue #1639). */
|
||||
filename = g_strdup (thunar_file_get_basename (file));
|
||||
/* get the filename of the file */
|
||||
filename = thunar_file_get_basename (file);
|
||||
|
||||
/* create a new dialog window */
|
||||
title = g_strdup_printf (_("Rename \"%s\""), filename);
|
||||
|
|
@ -386,8 +385,6 @@ thunar_dialogs_show_rename_file (gpointer parent,
|
|||
gtk_widget_destroy (dialog);
|
||||
}
|
||||
|
||||
g_free (filename);
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
|
|
@ -485,7 +482,7 @@ thunar_dialogs_show_error (gpointer parent,
|
|||
...)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
GtkWindow *window = NULL;
|
||||
GtkWindow *window;
|
||||
GdkScreen *screen;
|
||||
va_list args;
|
||||
gchar *primary_text;
|
||||
|
|
@ -1044,7 +1041,7 @@ thunar_dialogs_show_insecure_program (gpointer parent,
|
|||
const gchar *command)
|
||||
{
|
||||
GdkScreen *screen;
|
||||
GtkWindow *window = NULL;
|
||||
GtkWindow *window;
|
||||
gint response;
|
||||
GtkWidget *dialog;
|
||||
GString *secondary;
|
||||
|
|
@ -1239,7 +1236,7 @@ thunar_dialog_ask_execute (const ThunarFile *file,
|
|||
gboolean single_file)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
GtkWindow *window = NULL;
|
||||
GtkWindow *window;
|
||||
GdkScreen *screen;
|
||||
gint response;
|
||||
gchar *dialog_text;
|
||||
|
|
|
|||
|
|
@ -230,9 +230,8 @@ struct _ThunarFile
|
|||
/* flags for thumbnail state etc */
|
||||
ThunarFileFlags flags;
|
||||
|
||||
/* event source id and variable to rate-limit file-changed signals */
|
||||
guint signal_changed_source_id;
|
||||
gboolean signal_change_requested;
|
||||
/* event source id used to rate-limit file-changed signals */
|
||||
guint signal_changed_source_id;
|
||||
|
||||
/* Number of files in this directory (only used if this #Thunarfile is a directory) */
|
||||
/* Note that this feature was added into #ThunarFile on purpose, because having inside #ThunarFolder caused lag when
|
||||
|
|
@ -1205,7 +1204,6 @@ thunar_file_load (ThunarFile *file,
|
|||
{
|
||||
GError *err = NULL;
|
||||
GFileInfo *info = NULL;
|
||||
gboolean mounted = TRUE;
|
||||
|
||||
_thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
|
||||
_thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
|
@ -1223,12 +1221,12 @@ thunar_file_load (ThunarFile *file,
|
|||
G_FILE_QUERY_INFO_NONE,
|
||||
cancellable, &err);
|
||||
|
||||
/* check if mounted (but do not update the file until after it has been cleared) */
|
||||
/* update the mounted info */
|
||||
if (err != NULL
|
||||
&& err->domain == G_IO_ERROR
|
||||
&& err->code == G_IO_ERROR_NOT_MOUNTED)
|
||||
{
|
||||
mounted = FALSE;
|
||||
FLAG_UNSET (file, THUNAR_FILE_FLAG_IS_MOUNTED);
|
||||
g_clear_error (&err);
|
||||
}
|
||||
|
||||
|
|
@ -1256,10 +1254,6 @@ thunar_file_load (ThunarFile *file,
|
|||
/* update the file from the information */
|
||||
thunar_file_info_reload (file, cancellable);
|
||||
|
||||
/* update the mounted info */
|
||||
if (mounted == FALSE)
|
||||
FLAG_UNSET (file, THUNAR_FILE_FLAG_IS_MOUNTED);
|
||||
|
||||
/* (re)insert the file into the cache */
|
||||
if (file->kind != G_FILE_TYPE_UNKNOWN)
|
||||
{
|
||||
|
|
@ -1747,15 +1741,11 @@ thunar_file_execute (ThunarFile *file,
|
|||
{
|
||||
/* fake the Exec line */
|
||||
escaped_location = g_shell_quote (location);
|
||||
exec = g_strconcat (escaped_location, " %F", NULL);
|
||||
command = xfce_expand_desktop_entry_field_codes (exec, uri_list, NULL, NULL, NULL, FALSE);
|
||||
if (in_terminal)
|
||||
{
|
||||
gchar *escaped = g_shell_quote (command);
|
||||
g_free (command);
|
||||
command = g_strconcat ("exo-open --launch TerminalEmulator ", escaped, NULL);
|
||||
g_free (escaped);
|
||||
}
|
||||
exec = g_strconcat ("exo-open --launch TerminalEmulator ", escaped_location, " %F", NULL);
|
||||
else
|
||||
exec = g_strconcat (escaped_location, " %F", NULL);
|
||||
command = xfce_expand_desktop_entry_field_codes (exec, uri_list, NULL, NULL, NULL, FALSE);
|
||||
result = g_shell_parse_argv (command, NULL, &argv, error);
|
||||
g_free (escaped_location);
|
||||
g_free (exec);
|
||||
|
|
@ -2117,8 +2107,7 @@ thunar_file_accepts_drop (ThunarFile *file,
|
|||
{
|
||||
/* default to copy and get outta here */
|
||||
suggested_action = GDK_ACTION_COPY;
|
||||
if (parent_thunar_file != NULL)
|
||||
g_object_unref (parent_thunar_file);
|
||||
g_object_unref (parent_thunar_file);
|
||||
break;
|
||||
}
|
||||
if (parent_thunar_file != NULL)
|
||||
|
|
@ -5424,23 +5413,24 @@ thunar_file_reset_thumbnail (ThunarFile *file,
|
|||
|
||||
|
||||
static gboolean
|
||||
thunar_file_changed_signal_timeout (gpointer data)
|
||||
thunar_file_changed_signal_emit (gpointer data)
|
||||
{
|
||||
ThunarFile *file = THUNAR_FILE (data);
|
||||
_thunar_return_val_if_fail (THUNAR_IS_FILE (file), G_SOURCE_REMOVE);
|
||||
|
||||
/* emit the changed signal on thunarx level, if required */
|
||||
if (file->signal_change_requested)
|
||||
thunarx_file_info_changed (THUNARX_FILE_INFO (file));
|
||||
|
||||
file->signal_change_requested = FALSE;
|
||||
file->signal_changed_source_id = 0;
|
||||
/* emit the changed signal on thunarx level */
|
||||
thunarx_file_info_changed (THUNARX_FILE_INFO (data));
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_file_changed_signal_destroy (gpointer data)
|
||||
{
|
||||
THUNAR_FILE (data)->signal_changed_source_id = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_file_changed:
|
||||
* @file : a #ThunarFile instance.
|
||||
|
|
@ -5451,17 +5441,10 @@ thunar_file_changed_signal_timeout (gpointer data)
|
|||
void
|
||||
thunar_file_changed (ThunarFile *file)
|
||||
{
|
||||
/* in case a timeout is running, the change-signal will be delayed (performance) */
|
||||
if (file->signal_changed_source_id != 0)
|
||||
if (file->signal_changed_source_id == 0)
|
||||
{
|
||||
file->signal_change_requested = TRUE;
|
||||
return;
|
||||
file->signal_changed_source_id = g_timeout_add_full (G_PRIORITY_DEFAULT, FILE_CHANGED_SIGNAL_RATE_LIMIT,
|
||||
thunar_file_changed_signal_emit,
|
||||
file, thunar_file_changed_signal_destroy);
|
||||
}
|
||||
|
||||
/* handle the first request directly */
|
||||
thunarx_file_info_changed (THUNARX_FILE_INFO (file));
|
||||
|
||||
/* start a timer to throttle consecutive calls */
|
||||
file->signal_changed_source_id = g_timeout_add (FILE_CHANGED_SIGNAL_RATE_LIMIT,
|
||||
thunar_file_changed_signal_timeout, file);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,10 +149,10 @@ struct _ThunarFolder
|
|||
/* Files which were changed recently. The key is a ThunarFile; value is NULL (unimportant)*/
|
||||
GHashTable *changed_files_map;
|
||||
|
||||
/* Files which were added recently. The key is a ThunarFile; value is NULL (unimportant)*/
|
||||
/* Files which were changed recently. The key is a ThunarFile; value is NULL (unimportant)*/
|
||||
GHashTable *added_files_map;
|
||||
|
||||
/* Files which were removed recently. The key is a ThunarFile; value is NULL (unimportant)*/
|
||||
/* Files which were changed recently. The key is a ThunarFile; value is NULL (unimportant)*/
|
||||
GHashTable *removed_files_map;
|
||||
|
||||
/* Files inside this folder. The key is a ThunarFile; value is NULL (unimportant)*/
|
||||
|
|
@ -409,10 +409,7 @@ thunar_folder_finalize (GObject *object)
|
|||
g_source_remove (folder->files_update_timeout_source_id);
|
||||
|
||||
if (folder->monitor != NULL)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_data (folder->monitor, folder);
|
||||
g_object_unref (folder->monitor);
|
||||
}
|
||||
g_signal_handlers_disconnect_by_data (folder->monitor, folder);
|
||||
|
||||
if (folder->corresponding_file)
|
||||
{
|
||||
|
|
@ -597,25 +594,17 @@ _thunar_folder_files_update_timeout (gpointer data)
|
|||
g_hash_table_remove_all (files);
|
||||
g_hash_table_remove_all (folder->added_files_map);
|
||||
|
||||
/* reload files which were changed and send a 'changed' signal for them, if required */
|
||||
/* send a 'changed' signal for all files which changed */
|
||||
g_hash_table_iter_init (&iter, folder->changed_files_map);
|
||||
while (g_hash_table_iter_next (&iter, &key, NULL))
|
||||
{
|
||||
/* block 'changed' signals for this file until reload is done, in order to prevent recursion */
|
||||
g_signal_handlers_block_by_func (G_OBJECT (key), G_CALLBACK (thunar_folder_file_changed), folder);
|
||||
thunar_file_reload (THUNAR_FILE (key));
|
||||
g_signal_handlers_unblock_by_func (G_OBJECT (key), G_CALLBACK (thunar_folder_file_changed), folder);
|
||||
|
||||
/* only send the 'changed' signal for files which are already part of this folder */
|
||||
if (!g_hash_table_contains (folder->files_map, key))
|
||||
continue;
|
||||
|
||||
g_hash_table_add (files, g_object_ref (key));
|
||||
}
|
||||
|
||||
if (g_hash_table_size (files) > 0)
|
||||
g_signal_emit (G_OBJECT (folder), folder_signals[FILES_CHANGED], 0, files);
|
||||
|
||||
g_signal_emit (G_OBJECT (folder), folder_signals[FILES_CHANGED], 0, files);
|
||||
g_hash_table_destroy (files);
|
||||
g_hash_table_remove_all (folder->changed_files_map);
|
||||
|
||||
|
|
@ -656,10 +645,6 @@ thunar_folder_add_file (ThunarFolder *folder,
|
|||
if (g_hash_table_remove (folder->removed_files_map, file))
|
||||
return;
|
||||
|
||||
/* Do nothing if we already have the file in our internal map */
|
||||
if (g_hash_table_lookup (folder->files_map, file) != NULL)
|
||||
return;
|
||||
|
||||
g_hash_table_add (folder->added_files_map, g_object_ref (file));
|
||||
|
||||
if (folder->files_update_timeout_source_id == 0)
|
||||
|
|
@ -676,10 +661,6 @@ thunar_folder_remove_file (ThunarFolder *folder,
|
|||
if (g_hash_table_remove (folder->added_files_map, file))
|
||||
return;
|
||||
|
||||
/* Do nothing if we dont have the file yet in our internal map */
|
||||
if (g_hash_table_lookup (folder->files_map, file) == NULL)
|
||||
return;
|
||||
|
||||
g_hash_table_add (folder->removed_files_map, g_object_ref (file));
|
||||
|
||||
if (folder->files_update_timeout_source_id == 0)
|
||||
|
|
@ -1087,12 +1068,16 @@ thunar_folder_monitor (GFileMonitor *monitor,
|
|||
case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
|
||||
if (event_file_thunar != NULL)
|
||||
{
|
||||
/* this will trigger a reload if the file and send a 'file-changed' signal */
|
||||
thunar_folder_file_changed (folder, event_file_thunar);
|
||||
/* If we have that file in our internal map, reload it and send a file-changed signal */
|
||||
if (g_hash_table_lookup (folder->files_map, event_file_thunar) != NULL)
|
||||
{
|
||||
thunar_folder_file_changed (folder, event_file_thunar);
|
||||
|
||||
#if DEBUG_FILE_CHANGES
|
||||
thunar_file_infos_equal (event_file_thunar, event_file);
|
||||
thunar_file_infos_equal (event_file_thunar, event_file);
|
||||
#endif
|
||||
thunar_file_reload (event_file_thunar);
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -194,91 +194,9 @@ thunar_g_file_new_for_bookmarks (void)
|
|||
|
||||
|
||||
|
||||
/* internal version, for recursive execution. Uses a lookup table to detect loops */
|
||||
static GFile *
|
||||
_thunar_g_file_resolve_symlink_internal (GFile *file, GHashTable *lookup_table)
|
||||
{
|
||||
g_autoptr (GHashTable) lookup_history = NULL;
|
||||
g_autoptr (GFileInfo) info = NULL;
|
||||
|
||||
_thunar_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||
|
||||
if (lookup_table == NULL)
|
||||
lookup_history = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
else
|
||||
lookup_history = g_hash_table_ref (lookup_table);
|
||||
|
||||
/* Resolve the link target recursively, until the target we found is not a symlink */
|
||||
char *file_uri = g_file_get_uri (file);
|
||||
|
||||
if (file_uri == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Detect loops: if the file already was seen, return NULL */
|
||||
if (g_hash_table_contains (lookup_history, file_uri))
|
||||
{
|
||||
g_info ("Symlink loop detected - resolve symlink aborted");
|
||||
g_free (file_uri);
|
||||
return NULL;
|
||||
}
|
||||
g_hash_table_add (lookup_history, file_uri);
|
||||
|
||||
info = g_file_query_info (file,
|
||||
G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET "," G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK,
|
||||
G_FILE_QUERY_INFO_NONE, NULL, NULL);
|
||||
if (info == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Not a symlink: return that file */
|
||||
if (!g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK))
|
||||
return g_object_ref (file);
|
||||
|
||||
/* It's a symlink, get the target */
|
||||
const char *target_path = g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET);
|
||||
if (target_path == NULL)
|
||||
{
|
||||
g_info ("Failed to read target path from symlink: %s", g_file_get_path (file));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The target is as well a symlink ... so lets use recursion */
|
||||
if (g_path_is_absolute (target_path))
|
||||
{
|
||||
g_autoptr (GFile) target = g_file_new_for_path (target_path);
|
||||
return _thunar_g_file_resolve_symlink_internal (target, lookup_history);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Resolve a possible relative path */
|
||||
g_autoptr (GFile) target = NULL;
|
||||
g_autoptr (GFile) parent = NULL;
|
||||
g_autoptr (GFile) parent_resolved = NULL;
|
||||
|
||||
parent = g_file_get_parent (file);
|
||||
if (parent == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Resolve parent, if required */
|
||||
parent_resolved = _thunar_g_file_resolve_symlink_internal (parent, lookup_history);
|
||||
|
||||
if (parent_resolved == NULL)
|
||||
{
|
||||
g_info ("Failed to resolve parent of symlink");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
target = g_file_resolve_relative_path (parent_resolved, target_path);
|
||||
|
||||
/* Sicne as well that file might be a symlink, we need to use recursion */
|
||||
return _thunar_g_file_resolve_symlink_internal (target, lookup_history);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_g_file_resolve_symlink:
|
||||
* @file : a #GFile
|
||||
* @file : a #GFile.
|
||||
*
|
||||
* Returns the resolved symlink target of @file as a new #GFile.
|
||||
* If @file is not a symlink, @file will just be returned
|
||||
|
|
@ -288,7 +206,27 @@ _thunar_g_file_resolve_symlink_internal (GFile *file, GHashTable *lookup_table)
|
|||
GFile *
|
||||
thunar_g_file_resolve_symlink (GFile *file)
|
||||
{
|
||||
return _thunar_g_file_resolve_symlink_internal (file, NULL);
|
||||
gchar *basename;
|
||||
GFile *parent = NULL;
|
||||
GFile *target = NULL;
|
||||
|
||||
_thunar_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||
|
||||
parent = g_file_get_parent (file);
|
||||
if (parent == NULL)
|
||||
return NULL;
|
||||
|
||||
basename = g_file_get_basename (file);
|
||||
if (basename == NULL)
|
||||
{
|
||||
g_object_unref (parent);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
target = g_file_resolve_relative_path (parent, basename);
|
||||
g_object_unref (parent);
|
||||
g_free (basename);
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1822,10 +1760,8 @@ thunar_g_file_get_content_type (GFile *gfile)
|
|||
g_object_unref (info);
|
||||
info = NULL;
|
||||
if (link_target != NULL)
|
||||
{
|
||||
info = thunar_g_file_get_content_type_querry_info (link_target, err);
|
||||
g_object_unref (link_target);
|
||||
}
|
||||
info = thunar_g_file_get_content_type_querry_info (link_target, err);
|
||||
g_object_unref (link_target);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -151,8 +151,6 @@ thunar_gtk_menu_thunarx_menu_item_new (GObject *thunarx_menu_item,
|
|||
g_free (icon_name);
|
||||
if (icon != NULL)
|
||||
g_object_unref (icon);
|
||||
if (thunarx_menu != NULL)
|
||||
g_object_unref (thunarx_menu);
|
||||
|
||||
return gtk_menu_item;
|
||||
}
|
||||
|
|
@ -189,7 +187,7 @@ thunar_gtk_menu_clean (GtkMenu *menu)
|
|||
* thunar_gtk_menu_run:
|
||||
* @menu : a #GtkMenu.
|
||||
*
|
||||
* Convenience wrapper for thunar_gtk_menu_run_at_event() to run a menu for the current event
|
||||
* Conveniance wrapper for thunar_gtk_menu_run_at_event_pointer, to run a menu for the current event
|
||||
**/
|
||||
void
|
||||
thunar_gtk_menu_run (GtkMenu *menu)
|
||||
|
|
@ -209,51 +207,6 @@ thunar_gtk_menu_run (GtkMenu *menu)
|
|||
|
||||
|
||||
|
||||
static void
|
||||
thunar_gtk_menu_popup_at_pointer (GtkMenu *menu,
|
||||
GdkEvent *event)
|
||||
{
|
||||
GdkWindow *window;
|
||||
GdkWindow *toplevel = NULL;
|
||||
GdkDevice *device;
|
||||
GdkRectangle rect = { 0, 0, 1, 1 };
|
||||
|
||||
/* fallback if event not set or event not holding a GdkSeat */
|
||||
if (event == NULL || gdk_event_get_seat (event) == NULL)
|
||||
{
|
||||
gtk_menu_popup_at_pointer (menu, event);
|
||||
return;
|
||||
}
|
||||
|
||||
/* create popup rect */
|
||||
window = gdk_event_get_window (event);
|
||||
if (window != NULL)
|
||||
{
|
||||
/* Ensure that we have the toplevel window to work around a GTK3 Wayland bug
|
||||
* that prevents the user from dismissing the menu via click in some cases.
|
||||
* See: https://gitlab.xfce.org/xfce/thunar/-/issues/1592 */
|
||||
toplevel = gdk_window_get_toplevel (window);
|
||||
|
||||
device = gdk_event_get_device (event);
|
||||
|
||||
if (device != NULL && gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
|
||||
device = gdk_device_get_associated_device (device);
|
||||
|
||||
if (device != NULL)
|
||||
gdk_window_get_device_position (toplevel, device, &rect.x, &rect.y, NULL);
|
||||
}
|
||||
|
||||
/* pop up the menu at the rectangle below the mouse cursor */
|
||||
gtk_menu_popup_at_rect (menu,
|
||||
toplevel,
|
||||
&rect,
|
||||
GDK_GRAVITY_NORTH_WEST,
|
||||
GDK_GRAVITY_NORTH_WEST,
|
||||
event);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* thunar_gtk_menu_run_at_event:
|
||||
* @menu : a #GtkMenu.
|
||||
|
|
@ -268,8 +221,7 @@ thunar_gtk_menu_popup_at_pointer (GtkMenu *menu,
|
|||
*
|
||||
**/
|
||||
void
|
||||
thunar_gtk_menu_run_at_event (GtkMenu *menu,
|
||||
GdkEvent *event)
|
||||
thunar_gtk_menu_run_at_event (GtkMenu *menu, GdkEvent *event)
|
||||
{
|
||||
GMainLoop *loop;
|
||||
gulong signal_id;
|
||||
|
|
@ -282,7 +234,7 @@ thunar_gtk_menu_run_at_event (GtkMenu *menu,
|
|||
/* run an internal main loop */
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
signal_id = g_signal_connect_swapped (G_OBJECT (menu), "deactivate", G_CALLBACK (g_main_loop_quit), loop);
|
||||
thunar_gtk_menu_popup_at_pointer (menu, event);
|
||||
gtk_menu_popup_at_pointer (menu, event);
|
||||
gtk_menu_reposition (menu);
|
||||
gtk_grab_add (GTK_WIDGET (menu));
|
||||
g_main_loop_run (loop);
|
||||
|
|
|
|||
|
|
@ -1371,7 +1371,6 @@ _thunar_io_jobs_rename (ThunarJob *job,
|
|||
const gchar *display_name;
|
||||
ThunarFile *file;
|
||||
GError *err = NULL;
|
||||
GFile *old_file;
|
||||
gchar *old_file_uri;
|
||||
ThunarOperationLogMode log_mode;
|
||||
ThunarJobOperation *operation;
|
||||
|
|
@ -1404,10 +1403,8 @@ _thunar_io_jobs_rename (ThunarJob *job,
|
|||
if (log_mode == THUNAR_OPERATION_LOG_OPERATIONS)
|
||||
{
|
||||
operation = thunar_job_operation_new (THUNAR_JOB_OPERATION_KIND_RENAME);
|
||||
old_file = g_file_new_for_uri (old_file_uri);
|
||||
thunar_job_operation_add (operation, old_file, thunar_file_get_file (file));
|
||||
thunar_job_operation_add (operation, g_file_new_for_uri (old_file_uri), thunar_file_get_file (file));
|
||||
thunar_job_operation_history_commit (operation);
|
||||
g_object_unref (old_file);
|
||||
g_object_unref (operation);
|
||||
}
|
||||
}
|
||||
|
|
@ -1608,7 +1605,7 @@ _thunar_search_folder (ThunarStandardViewModel *model,
|
|||
|
||||
if (exo_job_is_cancelled (EXO_JOB (job)))
|
||||
{
|
||||
thunar_g_list_free_full (files_found);
|
||||
g_list_free (files_found);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -259,7 +259,6 @@ thunar_preferences_dialog_init (ThunarPreferencesDialog *dialog)
|
|||
GtkWidget *vbox;
|
||||
GtkWidget *infobar;
|
||||
GEnumClass *type;
|
||||
GList *windows;
|
||||
gchar *date;
|
||||
gint row = 0;
|
||||
|
||||
|
|
@ -1421,29 +1420,16 @@ thunar_preferences_dialog_init (ThunarPreferencesDialog *dialog)
|
|||
gtk_widget_show (vbox);
|
||||
|
||||
frame = g_object_new (GTK_TYPE_FRAME, "border-width", 0, "shadow-type", GTK_SHADOW_IN, NULL);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
|
||||
gtk_widget_show (frame);
|
||||
|
||||
/* check if the accel map has been initialized which is done in thunar-window.c */
|
||||
windows = thunar_application_get_windows (thunar_application_get ());
|
||||
if (windows != NULL)
|
||||
{
|
||||
grid = xfce_shortcuts_editor_new (13,
|
||||
_("Window"), thunar_window_get_action_entries (), (size_t) THUNAR_WINDOW_N_ACTIONS,
|
||||
_("View"), thunar_standard_view_get_action_entries (), (size_t) THUNAR_STANDARD_VIEW_N_ACTIONS,
|
||||
_("Launcher"), thunar_action_manager_get_action_entries (), (size_t) THUNAR_ACTION_MANAGER_N_ACTIONS,
|
||||
_("Status Bar"), thunar_statusbar_get_action_entries (), (size_t) THUNAR_STATUS_BAR_N_ACTIONS);
|
||||
gtk_container_add (GTK_CONTAINER (frame), grid);
|
||||
gtk_widget_show (grid);
|
||||
|
||||
g_list_free (windows);
|
||||
}
|
||||
else
|
||||
{
|
||||
label = gtk_label_new (_("The Shortcuts Editor requires a Thunar window to be present."));
|
||||
gtk_container_add (GTK_CONTAINER (frame), label);
|
||||
gtk_widget_show (label);
|
||||
}
|
||||
grid = xfce_shortcuts_editor_new (13,
|
||||
_("Window"), thunar_window_get_action_entries (), (size_t) THUNAR_WINDOW_N_ACTIONS,
|
||||
_("View"), thunar_standard_view_get_action_entries (), (size_t) THUNAR_STANDARD_VIEW_N_ACTIONS,
|
||||
_("Launcher"), thunar_action_manager_get_action_entries (), (size_t) THUNAR_ACTION_MANAGER_N_ACTIONS,
|
||||
_("Status Bar"), thunar_statusbar_get_action_entries (), (size_t) THUNAR_STATUS_BAR_N_ACTIONS);
|
||||
gtk_container_add (GTK_CONTAINER (frame), grid);
|
||||
gtk_widget_show (grid);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -381,7 +381,6 @@ thunar_progress_dialog_add_job (ThunarProgressDialog *dialog,
|
|||
else
|
||||
{
|
||||
dialog->views_waiting = g_list_append (dialog->views_waiting, view);
|
||||
thunar_job_freeze (job);
|
||||
}
|
||||
g_list_free (job_list);
|
||||
|
||||
|
|
|
|||
|
|
@ -658,10 +658,7 @@ thunar_progress_view_new_with_job (ThunarJob *job)
|
|||
_thunar_return_val_if_fail (job == NULL || THUNAR_IS_JOB (job), NULL);
|
||||
|
||||
view = g_object_new (THUNAR_TYPE_PROGRESS_VIEW, "job", job, NULL);
|
||||
|
||||
/* 'thunar_progress_dialog_add_job' will instantly overwrite with "queued", if required */
|
||||
thunar_progress_view_percent (view, 0.0, EXO_JOB (job));
|
||||
|
||||
gtk_label_set_text (GTK_LABEL (view->progress_label), _("Queued"));
|
||||
return GTK_WIDGET (view);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1705,14 +1705,12 @@ thunar_properties_dialog_update_multiple (ThunarPropertiesDialog *dialog)
|
|||
}
|
||||
else if (tmp_parent != NULL)
|
||||
{
|
||||
if (parent_file != NULL)
|
||||
/* we only display the location if they are all equal */
|
||||
if (!g_file_equal (thunar_file_get_file (parent_file), thunar_file_get_file (tmp_parent)))
|
||||
{
|
||||
/* we only display the location if they are all equal */
|
||||
if (!g_file_equal (thunar_file_get_file (parent_file), thunar_file_get_file (tmp_parent)))
|
||||
{
|
||||
g_object_unref (G_OBJECT (parent_file));
|
||||
parent_file = NULL;
|
||||
}
|
||||
if (parent_file != NULL)
|
||||
g_object_unref (G_OBJECT (parent_file));
|
||||
parent_file = NULL;
|
||||
}
|
||||
|
||||
g_object_unref (G_OBJECT (tmp_parent));
|
||||
|
|
|
|||
|
|
@ -853,9 +853,8 @@ thunar_renamer_dialog_response (GtkDialog *dialog,
|
|||
/* perform the rename (returns when done) */
|
||||
thunar_renamer_progress_run (THUNAR_RENAMER_PROGRESS (renamer_dialog->progress), pair_list);
|
||||
|
||||
/* hide the rename progress bar (unless the dialog has been destroyed) */
|
||||
if (gtk_widget_get_realized (GTK_WIDGET (renamer_dialog)))
|
||||
gtk_widget_hide (renamer_dialog->progress);
|
||||
/* hide the rename progress bar */
|
||||
gtk_widget_hide (renamer_dialog->progress);
|
||||
|
||||
/* release the pairs */
|
||||
thunar_renamer_pair_list_free (pair_list);
|
||||
|
|
|
|||
|
|
@ -217,6 +217,8 @@ struct _ThunarShortcutsModel
|
|||
guint bookmarks_idle_id;
|
||||
|
||||
guint busy_timeout_id;
|
||||
|
||||
gboolean bookmark_separator_added;
|
||||
};
|
||||
|
||||
struct _ThunarShortcut
|
||||
|
|
@ -236,15 +238,9 @@ struct _ThunarShortcut
|
|||
ThunarDevice *device;
|
||||
|
||||
guint hidden : 1;
|
||||
guint is_separator : 1;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ThunarShortcutsModel *model;
|
||||
ThunarShortcut *shortcut;
|
||||
gboolean update_visibility;
|
||||
} ThunarShortcutFileGetData;
|
||||
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (ThunarShortcutsModel, thunar_shortcuts_model, G_TYPE_OBJECT,
|
||||
|
|
@ -542,6 +538,12 @@ thunar_shortcuts_model_get_column_type (GtkTreeModel *tree_model,
|
|||
|
||||
case THUNAR_SHORTCUTS_MODEL_COLUMN_HIDDEN:
|
||||
return G_TYPE_BOOLEAN;
|
||||
|
||||
case THUNAR_SHORTCUTS_MODEL_COLUMN_USAGE_PERCENT:
|
||||
return G_TYPE_INT;
|
||||
|
||||
case THUNAR_SHORTCUTS_MODEL_COLUMN_IS_SEPARATOR:
|
||||
return G_TYPE_BOOLEAN;
|
||||
}
|
||||
|
||||
_thunar_assert_not_reached ();
|
||||
|
|
@ -822,6 +824,45 @@ thunar_shortcuts_model_get_value (GtkTreeModel *tree_model,
|
|||
g_value_set_boolean (value, FALSE);
|
||||
break;
|
||||
|
||||
case THUNAR_SHORTCUTS_MODEL_COLUMN_IS_SEPARATOR:
|
||||
g_value_init (value, G_TYPE_BOOLEAN);
|
||||
g_value_set_boolean (value, shortcut->is_separator);
|
||||
break;
|
||||
|
||||
case THUNAR_SHORTCUTS_MODEL_COLUMN_USAGE_PERCENT:
|
||||
g_value_init (value, G_TYPE_INT);
|
||||
if ((shortcut->group & THUNAR_SHORTCUT_GROUP_DEVICES) != 0
|
||||
&& (shortcut->group & THUNAR_SHORTCUT_GROUP_HEADER) == 0)
|
||||
{
|
||||
guint64 fs_free = 0, fs_total = 0;
|
||||
|
||||
if (shortcut->device != NULL)
|
||||
file = thunar_device_get_root (shortcut->device);
|
||||
else if (shortcut->file != NULL)
|
||||
file = g_object_ref (thunar_file_get_file (shortcut->file));
|
||||
else
|
||||
file = NULL;
|
||||
|
||||
if (file != NULL
|
||||
&& thunar_g_file_get_free_space (file, &fs_free, &fs_total)
|
||||
&& fs_total > 0)
|
||||
{
|
||||
g_value_set_int (value, (gint) ((fs_total - fs_free) * 100 / fs_total));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_value_set_int (value, -1);
|
||||
}
|
||||
|
||||
if (file != NULL)
|
||||
g_object_unref (file);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_value_set_int (value, -1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
_thunar_assert_not_reached ();
|
||||
}
|
||||
|
|
@ -1380,6 +1421,18 @@ thunar_shortcuts_model_load_line (GFile *file_path,
|
|||
_thunar_return_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model));
|
||||
_thunar_return_if_fail (name == NULL || g_utf8_validate (name, -1, NULL));
|
||||
|
||||
/* insert a separator before the first remote bookmark */
|
||||
if (!thunar_shortcuts_model_local_file (file_path)
|
||||
&& !model->bookmark_separator_added)
|
||||
{
|
||||
ThunarShortcut *sep = g_slice_new0 (ThunarShortcut);
|
||||
sep->group = THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS;
|
||||
sep->is_separator = TRUE;
|
||||
sep->sort_id = row_num;
|
||||
thunar_shortcuts_model_add_shortcut (model, sep);
|
||||
model->bookmark_separator_added = TRUE;
|
||||
}
|
||||
|
||||
shortcut = g_slice_new0 (ThunarShortcut);
|
||||
shortcut->group = THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS;
|
||||
shortcut->location = g_object_ref (file_path);
|
||||
|
|
@ -1441,6 +1494,9 @@ thunar_shortcuts_model_reload_bookmarks (gpointer data)
|
|||
|
||||
_thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_MODEL (model), FALSE);
|
||||
|
||||
/* reset separator flag */
|
||||
model->bookmark_separator_added = FALSE;
|
||||
|
||||
/* Find all user-defined shortcuts (bookmarks) */
|
||||
for (lp = model->shortcuts; lp != NULL; lp = lp->next)
|
||||
{
|
||||
|
|
@ -1554,40 +1610,13 @@ thunar_shortcuts_model_save_bookmarks (ThunarShortcutsModel *model)
|
|||
|
||||
|
||||
|
||||
static void
|
||||
thunar_shortcuts_model_device_added_callback (GFile *location,
|
||||
ThunarFile *file,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
ThunarShortcutFileGetData *data = user_data;
|
||||
ThunarShortcut *shortcut = data->shortcut;
|
||||
ThunarShortcutsModel *model = data->model;
|
||||
|
||||
if (error == NULL)
|
||||
{
|
||||
shortcut->file = g_object_ref (file);
|
||||
|
||||
/* insert in the model */
|
||||
thunar_shortcuts_model_add_shortcut (model, shortcut);
|
||||
|
||||
if (data->update_visibility)
|
||||
thunar_shortcuts_model_header_visibility (model);
|
||||
}
|
||||
|
||||
g_object_unref (location);
|
||||
g_object_unref (model);
|
||||
g_slice_free (ThunarShortcutFileGetData, data);
|
||||
}
|
||||
|
||||
static void
|
||||
thunar_shortcuts_model_device_added (ThunarDeviceMonitor *device_monitor,
|
||||
ThunarDevice *device,
|
||||
ThunarShortcutsModel *model)
|
||||
{
|
||||
ThunarShortcut *shortcut;
|
||||
ThunarShortcutFileGetData *data;
|
||||
GFile *mount_point;
|
||||
ThunarShortcut *shortcut;
|
||||
GFile *mount_point;
|
||||
|
||||
_thunar_return_if_fail (device_monitor == NULL || THUNAR_DEVICE_MONITOR (device_monitor));
|
||||
_thunar_return_if_fail (device_monitor == NULL || model->device_monitor == device_monitor);
|
||||
|
|
@ -1599,6 +1628,13 @@ thunar_shortcuts_model_device_added (ThunarDeviceMonitor *device_monitor,
|
|||
shortcut->device = g_object_ref (device);
|
||||
shortcut->hidden = thunar_device_get_hidden (device);
|
||||
|
||||
mount_point = thunar_device_get_root (device);
|
||||
if (mount_point != NULL)
|
||||
{
|
||||
shortcut->file = thunar_file_get (mount_point, NULL);
|
||||
g_object_unref (mount_point);
|
||||
}
|
||||
|
||||
switch (thunar_device_get_kind (device))
|
||||
{
|
||||
case THUNAR_DEVICE_KIND_VOLUME:
|
||||
|
|
@ -1614,27 +1650,13 @@ thunar_shortcuts_model_device_added (ThunarDeviceMonitor *device_monitor,
|
|||
break;
|
||||
}
|
||||
|
||||
/* insert in the model */
|
||||
thunar_shortcuts_model_add_shortcut (model, shortcut);
|
||||
|
||||
/* header visibility if call is from monitor */
|
||||
gboolean update_visibility = (device_monitor != NULL && !shortcut->hidden);
|
||||
|
||||
mount_point = thunar_device_get_root (device);
|
||||
if (mount_point != NULL)
|
||||
{
|
||||
data = g_slice_new0 (ThunarShortcutFileGetData);
|
||||
data->shortcut = shortcut;
|
||||
data->model = g_object_ref (model);
|
||||
data->update_visibility = update_visibility;
|
||||
|
||||
thunar_file_get_async (mount_point, NULL, &thunar_shortcuts_model_device_added_callback, data);
|
||||
}
|
||||
else /* some devices (e.g. usb flashdrives) do not have a mountpoint */
|
||||
{
|
||||
/* insert in the model */
|
||||
thunar_shortcuts_model_add_shortcut (model, shortcut);
|
||||
|
||||
if (update_visibility)
|
||||
thunar_shortcuts_model_header_visibility (model);
|
||||
}
|
||||
if (device_monitor != NULL
|
||||
&& !shortcut->hidden)
|
||||
thunar_shortcuts_model_header_visibility (model);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1657,12 +1679,7 @@ thunar_shortcuts_model_device_removed (ThunarDeviceMonitor *device_monitor,
|
|||
break;
|
||||
|
||||
/* something is broken if we don't have a shortcut here */
|
||||
if (lp == NULL)
|
||||
{
|
||||
g_warning ("No shortcut found for device '%s'", thunar_device_get_name (device));
|
||||
return;
|
||||
}
|
||||
|
||||
_thunar_assert (lp != NULL);
|
||||
_thunar_assert (THUNAR_SHORTCUT (lp->data)->device == device);
|
||||
|
||||
/* drop the shortcut from the model */
|
||||
|
|
@ -1696,12 +1713,7 @@ thunar_shortcuts_model_device_changed (ThunarDeviceMonitor *device_monitor,
|
|||
break;
|
||||
|
||||
/* something is broken if we don't have a shortcut here */
|
||||
if (lp == NULL)
|
||||
{
|
||||
g_warning ("No shortcut found for device '%s'", thunar_device_get_name (device));
|
||||
return;
|
||||
}
|
||||
|
||||
_thunar_assert (lp != NULL);
|
||||
_thunar_assert (THUNAR_SHORTCUT (lp->data)->device == device);
|
||||
|
||||
if (G_LIKELY (lp != NULL))
|
||||
|
|
@ -1774,7 +1786,8 @@ thunar_shortcuts_model_file_destroyed (ThunarFile *file,
|
|||
/* remove the thunar file from the list and set the g_file instead */
|
||||
if (shortcut->location == NULL)
|
||||
{
|
||||
shortcut->location = g_object_ref (thunar_file_get_file (file)) ;
|
||||
GFile *g_file = thunar_file_get_file (file);
|
||||
shortcut->location = g_file;
|
||||
}
|
||||
|
||||
if (shortcut->gicon == NULL)
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ typedef enum
|
|||
THUNAR_SHORTCUTS_MODEL_COLUMN_BUSY,
|
||||
THUNAR_SHORTCUTS_MODEL_COLUMN_BUSY_PULSE,
|
||||
THUNAR_SHORTCUTS_MODEL_COLUMN_HIDDEN,
|
||||
THUNAR_SHORTCUTS_MODEL_COLUMN_USAGE_PERCENT,
|
||||
THUNAR_SHORTCUTS_MODEL_COLUMN_IS_SEPARATOR,
|
||||
THUNAR_SHORTCUTS_MODEL_N_COLUMNS,
|
||||
} ThunarShortcutsModelColumn;
|
||||
|
||||
|
|
|
|||
332
thunar/thunar-shortcuts-progress-renderer.c
Normal file
332
thunar/thunar-shortcuts-progress-renderer.c
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2026
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "thunar/thunar-shortcuts-progress-renderer.h"
|
||||
|
||||
/* Height of the usage bar in pixels */
|
||||
#define BAR_HEIGHT 4
|
||||
/* Gap between the text and the bar */
|
||||
#define BAR_TOP_PAD 2
|
||||
/* Corner radius */
|
||||
#define BAR_RADIUS 2
|
||||
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_USAGE_PERCENT,
|
||||
PROP_IS_SEPARATOR,
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct _ThunarShortcutsProgressRendererClass
|
||||
{
|
||||
GtkCellRendererTextClass __parent__;
|
||||
};
|
||||
|
||||
struct _ThunarShortcutsProgressRenderer
|
||||
{
|
||||
GtkCellRendererText __parent__;
|
||||
|
||||
gint usage_percent; /* -1 = no bar, 0..100 = percent used */
|
||||
gboolean is_separator;
|
||||
};
|
||||
|
||||
|
||||
|
||||
G_DEFINE_TYPE (ThunarShortcutsProgressRenderer,
|
||||
thunar_shortcuts_progress_renderer,
|
||||
GTK_TYPE_CELL_RENDERER_TEXT)
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_shortcuts_progress_renderer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ThunarShortcutsProgressRenderer *renderer = THUNAR_SHORTCUTS_PROGRESS_RENDERER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_USAGE_PERCENT:
|
||||
g_value_set_int (value, renderer->usage_percent);
|
||||
break;
|
||||
|
||||
case PROP_IS_SEPARATOR:
|
||||
g_value_set_boolean (value, renderer->is_separator);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_CLASS (thunar_shortcuts_progress_renderer_parent_class)->get_property (object, prop_id, value, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_shortcuts_progress_renderer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ThunarShortcutsProgressRenderer *renderer = THUNAR_SHORTCUTS_PROGRESS_RENDERER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_USAGE_PERCENT:
|
||||
renderer->usage_percent = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_IS_SEPARATOR:
|
||||
renderer->is_separator = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_CLASS (thunar_shortcuts_progress_renderer_parent_class)->set_property (object, prop_id, value, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_shortcuts_progress_renderer_get_preferred_height (GtkCellRenderer *cell,
|
||||
GtkWidget *widget,
|
||||
gint *minimum,
|
||||
gint *natural)
|
||||
{
|
||||
ThunarShortcutsProgressRenderer *renderer = THUNAR_SHORTCUTS_PROGRESS_RENDERER (cell);
|
||||
gint min_h = 0, nat_h = 0;
|
||||
|
||||
/* let the parent (GtkCellRendererText) calculate text height */
|
||||
GTK_CELL_RENDERER_CLASS (thunar_shortcuts_progress_renderer_parent_class)->get_preferred_height (cell, widget, &min_h, &nat_h);
|
||||
|
||||
/* add space for the bar if usage data is available */
|
||||
if (renderer->usage_percent >= 0)
|
||||
{
|
||||
min_h += BAR_TOP_PAD + BAR_HEIGHT;
|
||||
nat_h += BAR_TOP_PAD + BAR_HEIGHT;
|
||||
}
|
||||
|
||||
if (minimum != NULL)
|
||||
*minimum = min_h;
|
||||
if (natural != NULL)
|
||||
*natural = nat_h;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_shortcuts_progress_renderer_render (GtkCellRenderer *cell,
|
||||
cairo_t *cr,
|
||||
GtkWidget *widget,
|
||||
const GdkRectangle *background_area,
|
||||
const GdkRectangle *cell_area,
|
||||
GtkCellRendererState flags)
|
||||
{
|
||||
ThunarShortcutsProgressRenderer *renderer = THUNAR_SHORTCUTS_PROGRESS_RENDERER (cell);
|
||||
GtkStyleContext *context;
|
||||
GdkRGBA bar_bg;
|
||||
GdkRGBA bar_fg;
|
||||
gint text_height;
|
||||
gint bar_y;
|
||||
gint bar_width;
|
||||
gint xpad, ypad;
|
||||
GdkRectangle text_area;
|
||||
|
||||
gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
|
||||
|
||||
/* draw a horizontal line for separator rows */
|
||||
if (renderer->is_separator)
|
||||
{
|
||||
GdkRGBA fg_color;
|
||||
context = gtk_widget_get_style_context (widget);
|
||||
gtk_style_context_get_color (context, gtk_style_context_get_state (context), &fg_color);
|
||||
fg_color.alpha = 0.3;
|
||||
|
||||
cairo_save (cr);
|
||||
gdk_cairo_set_source_rgba (cr, &fg_color);
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
cairo_move_to (cr, cell_area->x + xpad, cell_area->y + cell_area->height / 2 + 0.5);
|
||||
cairo_line_to (cr, cell_area->x + cell_area->width - xpad, cell_area->y + cell_area->height / 2 + 0.5);
|
||||
cairo_stroke (cr);
|
||||
cairo_restore (cr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (renderer->usage_percent >= 0)
|
||||
{
|
||||
/* calculate how much space the bar needs, then shrink cell_area for text */
|
||||
text_area = *cell_area;
|
||||
text_area.height -= (BAR_TOP_PAD + BAR_HEIGHT);
|
||||
|
||||
/* let the parent draw the text in the reduced area */
|
||||
GTK_CELL_RENDERER_CLASS (thunar_shortcuts_progress_renderer_parent_class)->render (
|
||||
cell, cr, widget, background_area, &text_area, flags);
|
||||
|
||||
/* draw the usage bar below the text */
|
||||
text_height = text_area.height;
|
||||
bar_y = cell_area->y + ypad + text_height + BAR_TOP_PAD;
|
||||
bar_width = cell_area->width - 2 * xpad;
|
||||
|
||||
if (bar_width <= 0)
|
||||
return;
|
||||
|
||||
context = gtk_widget_get_style_context (widget);
|
||||
|
||||
/* bar background: semi-transparent grey */
|
||||
bar_bg.red = 0.5;
|
||||
bar_bg.green = 0.5;
|
||||
bar_bg.blue = 0.5;
|
||||
bar_bg.alpha = 0.3;
|
||||
|
||||
/* bar foreground color: red for >90%, otherwise theme selection color */
|
||||
if (renderer->usage_percent > 90)
|
||||
{
|
||||
bar_fg.red = 0.85;
|
||||
bar_fg.green = 0.2;
|
||||
bar_fg.blue = 0.2;
|
||||
bar_fg.alpha = 0.9;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!gtk_style_context_lookup_color (context, "theme_selected_bg_color", &bar_fg)
|
||||
|| bar_fg.alpha < 0.01)
|
||||
{
|
||||
/* fallback blue */
|
||||
bar_fg.red = 0.3;
|
||||
bar_fg.green = 0.5;
|
||||
bar_fg.blue = 0.8;
|
||||
}
|
||||
bar_fg.alpha = 0.9;
|
||||
}
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
/* draw background track (rounded rectangle) */
|
||||
{
|
||||
gdouble x = cell_area->x + xpad;
|
||||
gdouble y = bar_y;
|
||||
gdouble w = bar_width;
|
||||
gdouble h = BAR_HEIGHT;
|
||||
gdouble r = BAR_RADIUS;
|
||||
|
||||
cairo_new_sub_path (cr);
|
||||
cairo_arc (cr, x + w - r, y + r, r, -G_PI_2, 0);
|
||||
cairo_arc (cr, x + w - r, y + h - r, r, 0, G_PI_2);
|
||||
cairo_arc (cr, x + r, y + h - r, r, G_PI_2, G_PI);
|
||||
cairo_arc (cr, x + r, y + r, r, G_PI, 3 * G_PI_2);
|
||||
cairo_close_path (cr);
|
||||
}
|
||||
gdk_cairo_set_source_rgba (cr, &bar_bg);
|
||||
cairo_fill (cr);
|
||||
|
||||
/* draw filled portion (rounded rectangle) */
|
||||
if (renderer->usage_percent > 0)
|
||||
{
|
||||
gdouble x = cell_area->x + xpad;
|
||||
gdouble y = bar_y;
|
||||
gdouble w = bar_width * renderer->usage_percent / 100.0;
|
||||
gdouble h = BAR_HEIGHT;
|
||||
gdouble r = BAR_RADIUS;
|
||||
|
||||
if (w < 2 * r)
|
||||
r = w / 2.0;
|
||||
if (r < 0.5)
|
||||
r = 0;
|
||||
|
||||
cairo_new_sub_path (cr);
|
||||
cairo_arc (cr, x + w - r, y + r, r, -G_PI_2, 0);
|
||||
cairo_arc (cr, x + w - r, y + h - r, r, 0, G_PI_2);
|
||||
cairo_arc (cr, x + r, y + h - r, r, G_PI_2, G_PI);
|
||||
cairo_arc (cr, x + r, y + r, r, G_PI, 3 * G_PI_2);
|
||||
cairo_close_path (cr);
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, &bar_fg);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no usage data: just draw the text normally */
|
||||
GTK_CELL_RENDERER_CLASS (thunar_shortcuts_progress_renderer_parent_class)->render (
|
||||
cell, cr, widget, background_area, cell_area, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_shortcuts_progress_renderer_class_init (ThunarShortcutsProgressRendererClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
|
||||
|
||||
gobject_class->get_property = thunar_shortcuts_progress_renderer_get_property;
|
||||
gobject_class->set_property = thunar_shortcuts_progress_renderer_set_property;
|
||||
|
||||
cell_class->get_preferred_height = thunar_shortcuts_progress_renderer_get_preferred_height;
|
||||
cell_class->render = thunar_shortcuts_progress_renderer_render;
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_USAGE_PERCENT,
|
||||
g_param_spec_int ("usage-percent",
|
||||
"usage-percent",
|
||||
"Disk usage percentage (0-100, -1 = hidden)",
|
||||
-1, 100, -1,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_IS_SEPARATOR,
|
||||
g_param_spec_boolean ("is-separator",
|
||||
"is-separator",
|
||||
"Draw a horizontal line instead of text",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_shortcuts_progress_renderer_init (ThunarShortcutsProgressRenderer *renderer)
|
||||
{
|
||||
renderer->usage_percent = -1;
|
||||
|
||||
/* match the original text renderer settings */
|
||||
g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GtkCellRenderer *
|
||||
thunar_shortcuts_progress_renderer_new (void)
|
||||
{
|
||||
return g_object_new (THUNAR_TYPE_SHORTCUTS_PROGRESS_RENDERER, NULL);
|
||||
}
|
||||
38
thunar/thunar-shortcuts-progress-renderer.h
Normal file
38
thunar/thunar-shortcuts-progress-renderer.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||||
/*-
|
||||
* Copyright (c) 2026
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __THUNAR_SHORTCUTS_PROGRESS_RENDERER_H__
|
||||
#define __THUNAR_SHORTCUTS_PROGRESS_RENDERER_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS;
|
||||
|
||||
typedef struct _ThunarShortcutsProgressRendererClass ThunarShortcutsProgressRendererClass;
|
||||
typedef struct _ThunarShortcutsProgressRenderer ThunarShortcutsProgressRenderer;
|
||||
|
||||
#define THUNAR_TYPE_SHORTCUTS_PROGRESS_RENDERER (thunar_shortcuts_progress_renderer_get_type ())
|
||||
#define THUNAR_SHORTCUTS_PROGRESS_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_SHORTCUTS_PROGRESS_RENDERER, ThunarShortcutsProgressRenderer))
|
||||
|
||||
GType thunar_shortcuts_progress_renderer_get_type (void) G_GNUC_CONST;
|
||||
GtkCellRenderer *thunar_shortcuts_progress_renderer_new (void);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
#endif /* !__THUNAR_SHORTCUTS_PROGRESS_RENDERER_H__ */
|
||||
|
|
@ -44,6 +44,7 @@
|
|||
#include "thunar/thunar-private.h"
|
||||
#include "thunar/thunar-shortcuts-icon-renderer.h"
|
||||
#include "thunar/thunar-shortcuts-model.h"
|
||||
#include "thunar/thunar-shortcuts-progress-renderer.h"
|
||||
#include "thunar/thunar-shortcuts-view.h"
|
||||
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
|
|
@ -319,6 +320,20 @@ thunar_shortcuts_view_navigator_init (ThunarNavigatorIface *iface)
|
|||
|
||||
|
||||
|
||||
static gboolean
|
||||
thunar_shortcuts_view_row_separator (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
gpointer data)
|
||||
{
|
||||
gboolean is_separator = FALSE;
|
||||
gtk_tree_model_get (model, iter,
|
||||
THUNAR_SHORTCUTS_MODEL_COLUMN_IS_SEPARATOR, &is_separator,
|
||||
-1);
|
||||
return is_separator;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_shortcuts_view_init (ThunarShortcutsView *view)
|
||||
{
|
||||
|
|
@ -331,6 +346,8 @@ thunar_shortcuts_view_init (ThunarShortcutsView *view)
|
|||
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE);
|
||||
gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (view), THUNAR_SHORTCUTS_MODEL_COLUMN_TOOLTIP);
|
||||
|
||||
/* no row_separator_func — separator is drawn by the progress renderer */
|
||||
|
||||
/* grab a reference on the provider factory */
|
||||
view->provider_factory = thunarx_provider_factory_get_default ();
|
||||
|
||||
|
|
@ -395,14 +412,14 @@ thunar_shortcuts_view_init (ThunarShortcutsView *view)
|
|||
g_object_bind_property (G_OBJECT (view->preferences), "misc-symbolic-icons-in-sidepane", G_OBJECT (view->icon_renderer), "use-symbolic-icons", G_BINDING_SYNC_CREATE);
|
||||
g_signal_connect_swapped (G_OBJECT (view->preferences), "notify::misc-symbolic-icons-in-sidepane", G_CALLBACK (gtk_widget_queue_draw), view);
|
||||
|
||||
/* allocate the text renderer (ellipsizing as required, but "File System" must fit) */
|
||||
renderer = g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
|
||||
"ellipsize", PANGO_ELLIPSIZE_END,
|
||||
NULL);
|
||||
/* allocate the text+progress renderer for device names with usage bars */
|
||||
renderer = thunar_shortcuts_progress_renderer_new ();
|
||||
g_signal_connect (G_OBJECT (renderer), "edited", G_CALLBACK (thunar_shortcuts_view_renamed), view);
|
||||
gtk_tree_view_column_pack_start (column, renderer, TRUE);
|
||||
gtk_tree_view_column_set_attributes (column, renderer,
|
||||
"text", THUNAR_SHORTCUTS_MODEL_COLUMN_NAME,
|
||||
"usage-percent", THUNAR_SHORTCUTS_MODEL_COLUMN_USAGE_PERCENT,
|
||||
"is-separator", THUNAR_SHORTCUTS_MODEL_COLUMN_IS_SEPARATOR,
|
||||
"visible", THUNAR_SHORTCUTS_MODEL_COLUMN_IS_ITEM,
|
||||
NULL);
|
||||
|
||||
|
|
|
|||
|
|
@ -1500,10 +1500,6 @@ thunar_standard_view_update_selected_files (ThunarStandardView *standard_view,
|
|||
|
||||
/* determine the tree paths for the given files */
|
||||
paths = thunar_standard_view_model_get_paths_for_files (standard_view->model, files_to_select);
|
||||
|
||||
/* unselect all previously selected files - this may free the "files_to_select" list */
|
||||
(*THUNAR_STANDARD_VIEW_GET_CLASS (standard_view)->unselect_all) (standard_view);
|
||||
|
||||
if (G_LIKELY (paths != NULL))
|
||||
{
|
||||
/* determine the first path */
|
||||
|
|
@ -2460,7 +2456,6 @@ thunar_standard_view_update_statusbar_text_idle (gpointer data)
|
|||
GList *selected_items_tree_path_list;
|
||||
GtkTreeIter iter;
|
||||
ThunarFile *file;
|
||||
gchar *statusbar_text;
|
||||
|
||||
_thunar_return_val_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view), FALSE);
|
||||
|
||||
|
|
@ -2483,22 +2478,6 @@ thunar_standard_view_update_statusbar_text_idle (gpointer data)
|
|||
if (thunar_standard_view_model_get_folder (standard_view->model) == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* search mode active */
|
||||
if (standard_view->priv->search_query != NULL)
|
||||
{
|
||||
gint num_files;
|
||||
|
||||
g_object_get (G_OBJECT (standard_view->model), "num-files", &num_files, NULL);
|
||||
|
||||
statusbar_text = g_strdup_printf (ngettext ("%d file found", "%d files found", num_files), num_files);
|
||||
thunar_standard_view_set_statusbar_text (standard_view, statusbar_text);
|
||||
g_free (statusbar_text);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (standard_view), standard_view_props[PROP_STATUSBAR_TEXT]);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
standard_view->priv->statusbar_job = thunar_io_jobs_load_statusbar_text_for_folder (standard_view, thunar_standard_view_model_get_folder (standard_view->model));
|
||||
|
||||
g_signal_connect (standard_view->priv->statusbar_job, "error", G_CALLBACK (thunar_standard_view_update_statusbar_text_error), standard_view);
|
||||
|
|
@ -2508,6 +2487,8 @@ thunar_standard_view_update_statusbar_text_idle (gpointer data)
|
|||
}
|
||||
else if (selected_items_tree_path_list->next == NULL) /* only one item selected */
|
||||
{
|
||||
gchar *statusbar_text;
|
||||
|
||||
/* resolve the iter for the single path */
|
||||
gtk_tree_model_get_iter (GTK_TREE_MODEL (standard_view->model), &iter, selected_items_tree_path_list->data);
|
||||
|
||||
|
|
@ -2568,7 +2549,7 @@ thunar_standard_view_update_statusbar_text (ThunarStandardView *standard_view)
|
|||
/* restart a new one, this way we avoid multiple update when
|
||||
* the user is pressing a key to scroll */
|
||||
standard_view->priv->statusbar_text_idle_id =
|
||||
g_timeout_add_full (G_PRIORITY_DEFAULT, 50, thunar_standard_view_update_statusbar_text_idle,
|
||||
g_timeout_add_full (G_PRIORITY_LOW, 50, thunar_standard_view_update_statusbar_text_idle,
|
||||
standard_view, NULL);
|
||||
}
|
||||
|
||||
|
|
@ -4818,10 +4799,27 @@ thunar_standard_view_cell_layout_data_func (GtkCellLayout *layout,
|
|||
/* since this function is being used for both icon & name renderers;
|
||||
* we need to make sure the right properties are applied to the right renderers */
|
||||
if (THUNAR_IS_TEXT_RENDERER (cell))
|
||||
g_object_set (G_OBJECT (cell),
|
||||
"foreground-rgba", foreground != NULL ? &foreground_rgba : NULL,
|
||||
"highlight-color", background,
|
||||
NULL);
|
||||
{
|
||||
/* set disk usage bar for computer:// items */
|
||||
gint usage = -1;
|
||||
GFile *gfile = thunar_file_get_file (file);
|
||||
if (gfile != NULL && g_file_has_uri_scheme (gfile, "computer"))
|
||||
{
|
||||
GFile *root = thunar_file_get_target_location (file);
|
||||
if (root == NULL)
|
||||
root = gfile;
|
||||
guint64 fs_free = 0, fs_total = 0;
|
||||
if (thunar_g_file_get_free_space (root, &fs_free, &fs_total) && fs_total > 0)
|
||||
usage = (gint) ((fs_total - fs_free) * 100 / fs_total);
|
||||
if (root != gfile)
|
||||
g_object_unref (root);
|
||||
}
|
||||
g_object_set (G_OBJECT (cell),
|
||||
"foreground-rgba", foreground != NULL ? &foreground_rgba : NULL,
|
||||
"highlight-color", background,
|
||||
"usage-percent", usage,
|
||||
NULL);
|
||||
}
|
||||
|
||||
else if (THUNAR_IS_ICON_RENDERER (cell))
|
||||
g_object_set (G_OBJECT (cell),
|
||||
|
|
|
|||
|
|
@ -23,6 +23,11 @@
|
|||
|
||||
#include "thunar/thunar-text-renderer.h"
|
||||
#include "thunar/thunar-util.h"
|
||||
#include <math.h>
|
||||
|
||||
#define USAGE_BAR_HEIGHT 4
|
||||
#define USAGE_BAR_TOP_PAD 2
|
||||
#define USAGE_BAR_RADIUS 2
|
||||
|
||||
|
||||
|
||||
|
|
@ -32,6 +37,7 @@ enum
|
|||
PROP_HIGHLIGHT_COLOR,
|
||||
PROP_ROUNDED_CORNERS,
|
||||
PROP_HIGHLIGHTING_ENABLED,
|
||||
PROP_USAGE_PERCENT,
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -55,6 +61,11 @@ thunar_text_renderer_render (GtkCellRenderer *renderer,
|
|||
const GdkRectangle *background_area,
|
||||
const GdkRectangle *cell_area,
|
||||
GtkCellRendererState flags);
|
||||
static void
|
||||
thunar_text_renderer_get_preferred_height (GtkCellRenderer *cell,
|
||||
GtkWidget *widget,
|
||||
gint *minimum,
|
||||
gint *natural);
|
||||
|
||||
|
||||
|
||||
|
|
@ -77,6 +88,7 @@ struct _ThunarTextRenderer
|
|||
gchar *highlight_color;
|
||||
gboolean rounded_corners;
|
||||
gboolean highlighting_enabled;
|
||||
gint usage_percent; /* -1 = no bar, 0..100 = percent used */
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -98,6 +110,7 @@ thunar_text_renderer_class_init (ThunarTextRendererClass *klass)
|
|||
|
||||
klass->default_render_function = cell_class->render;
|
||||
cell_class->render = thunar_text_renderer_render;
|
||||
cell_class->get_preferred_height = thunar_text_renderer_get_preferred_height;
|
||||
|
||||
/**
|
||||
* ThunarTextRenderer:highlight-color:
|
||||
|
|
@ -136,6 +149,13 @@ thunar_text_renderer_class_init (ThunarTextRendererClass *klass)
|
|||
g_param_spec_boolean ("highlighting-enabled", "highlighting-enabled", "highlighting-enabled",
|
||||
FALSE,
|
||||
EXO_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_USAGE_PERCENT,
|
||||
g_param_spec_int ("usage-percent", "usage-percent",
|
||||
"Disk usage percentage (0-100, -1 = hidden)",
|
||||
-1, 100, -1,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -144,6 +164,7 @@ static void
|
|||
thunar_text_renderer_init (ThunarTextRenderer *text_renderer)
|
||||
{
|
||||
text_renderer->highlight_color = NULL;
|
||||
text_renderer->usage_percent = -1;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -182,6 +203,10 @@ thunar_text_renderer_get_property (GObject *object,
|
|||
g_value_set_boolean (value, text_renderer->highlighting_enabled);
|
||||
break;
|
||||
|
||||
case PROP_USAGE_PERCENT:
|
||||
g_value_set_int (value, text_renderer->usage_percent);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
|
@ -213,6 +238,10 @@ thunar_text_renderer_set_property (GObject *object,
|
|||
text_renderer->highlighting_enabled = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
case PROP_USAGE_PERCENT:
|
||||
text_renderer->usage_percent = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
|
@ -239,6 +268,91 @@ thunar_text_renderer_new (void)
|
|||
|
||||
|
||||
|
||||
static void
|
||||
thunar_text_renderer_get_preferred_height (GtkCellRenderer *cell,
|
||||
GtkWidget *widget,
|
||||
gint *minimum,
|
||||
gint *natural)
|
||||
{
|
||||
gint min_h = 0, nat_h = 0;
|
||||
|
||||
GTK_CELL_RENDERER_CLASS (thunar_text_renderer_parent_class)->get_preferred_height (cell, widget, &min_h, &nat_h);
|
||||
|
||||
if (minimum != NULL) *minimum = min_h;
|
||||
if (natural != NULL) *natural = nat_h;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_text_renderer_draw_usage_bar (cairo_t *cr,
|
||||
GtkWidget *widget,
|
||||
const GdkRectangle *cell_area,
|
||||
gint usage_percent)
|
||||
{
|
||||
GtkStyleContext *context;
|
||||
GdkRGBA bar_bg = { 0.5, 0.5, 0.5, 0.3 };
|
||||
GdkRGBA bar_fg;
|
||||
gint xpad = 2;
|
||||
gdouble x = cell_area->x + xpad;
|
||||
gdouble y = cell_area->y + cell_area->height - USAGE_BAR_HEIGHT;
|
||||
gdouble w = cell_area->width - 2 * xpad;
|
||||
gdouble h = USAGE_BAR_HEIGHT;
|
||||
gdouble r = USAGE_BAR_RADIUS;
|
||||
gdouble fw;
|
||||
|
||||
if (w <= 0)
|
||||
return;
|
||||
|
||||
context = gtk_widget_get_style_context (widget);
|
||||
|
||||
if (usage_percent > 90)
|
||||
{
|
||||
bar_fg.red = 0.85; bar_fg.green = 0.2; bar_fg.blue = 0.2; bar_fg.alpha = 0.9;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!gtk_style_context_lookup_color (context, "theme_selected_bg_color", &bar_fg)
|
||||
|| bar_fg.alpha < 0.01)
|
||||
{ bar_fg.red = 0.3; bar_fg.green = 0.5; bar_fg.blue = 0.8; }
|
||||
bar_fg.alpha = 0.9;
|
||||
}
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
/* background track */
|
||||
cairo_new_sub_path (cr);
|
||||
cairo_arc (cr, x + w - r, y + r, r, -G_PI_2, 0);
|
||||
cairo_arc (cr, x + w - r, y + h - r, r, 0, G_PI_2);
|
||||
cairo_arc (cr, x + r, y + h - r, r, G_PI_2, G_PI);
|
||||
cairo_arc (cr, x + r, y + r, r, G_PI, 3 * G_PI_2);
|
||||
cairo_close_path (cr);
|
||||
gdk_cairo_set_source_rgba (cr, &bar_bg);
|
||||
cairo_fill (cr);
|
||||
|
||||
/* filled portion */
|
||||
if (usage_percent > 0)
|
||||
{
|
||||
fw = w * usage_percent / 100.0;
|
||||
r = USAGE_BAR_RADIUS;
|
||||
if (fw < 2 * r) r = fw / 2.0;
|
||||
if (r < 0.5) r = 0;
|
||||
|
||||
cairo_new_sub_path (cr);
|
||||
cairo_arc (cr, x + fw - r, y + r, r, -G_PI_2, 0);
|
||||
cairo_arc (cr, x + fw - r, y + h - r, r, 0, G_PI_2);
|
||||
cairo_arc (cr, x + r, y + h - r, r, G_PI_2, G_PI);
|
||||
cairo_arc (cr, x + r, y + r, r, G_PI, 3 * G_PI_2);
|
||||
cairo_close_path (cr);
|
||||
gdk_cairo_set_source_rgba (cr, &bar_fg);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
thunar_text_renderer_render (GtkCellRenderer *cell,
|
||||
cairo_t *cr,
|
||||
|
|
@ -247,11 +361,16 @@ thunar_text_renderer_render (GtkCellRenderer *cell,
|
|||
const GdkRectangle *cell_area,
|
||||
GtkCellRendererState flags)
|
||||
{
|
||||
if (THUNAR_TEXT_RENDERER (cell)->highlighting_enabled)
|
||||
ThunarTextRenderer *text_renderer = THUNAR_TEXT_RENDERER (cell);
|
||||
|
||||
if (text_renderer->highlighting_enabled)
|
||||
thunar_util_clip_view_background (cell, cr, background_area, widget, flags);
|
||||
|
||||
/* we only needed to manipulate the background_area, otherwise everything remains the same.
|
||||
Hence, we are simply running the original render function now */
|
||||
THUNAR_TEXT_RENDERER_GET_CLASS (THUNAR_TEXT_RENDERER (cell))
|
||||
/* draw text normally */
|
||||
THUNAR_TEXT_RENDERER_GET_CLASS (text_renderer)
|
||||
->default_render_function (cell, cr, widget, background_area, cell_area, flags);
|
||||
|
||||
/* draw usage bar at the very bottom of the cell, overlapping if needed */
|
||||
if (text_renderer->usage_percent >= 0)
|
||||
thunar_text_renderer_draw_usage_bar (cr, widget, cell_area, text_renderer->usage_percent);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -868,7 +868,6 @@ thunar_transfer_job_copy_node (ThunarTransferJob *job,
|
|||
use_fat_name_scheme =
|
||||
!g_strcmp0 (fs_type, "fat") ||
|
||||
!g_strcmp0 (fs_type, "vfat") ||
|
||||
!g_strcmp0 (fs_type, "exfat") ||
|
||||
!g_strcmp0 (fs_type, "fuse") ||
|
||||
!g_strcmp0 (fs_type, "ntfs") ||
|
||||
!g_strcmp0 (fs_type, "msdos") ||
|
||||
|
|
|
|||
|
|
@ -1717,9 +1717,6 @@ _thunar_tree_view_model_cancel_search_job (ThunarTreeViewModel *model)
|
|||
g_object_unref (model->search_job);
|
||||
model->search_job = NULL;
|
||||
}
|
||||
|
||||
thunar_g_list_free_full (model->search_files);
|
||||
model->search_files = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2519,26 +2516,10 @@ thunar_tree_view_model_sort (ThunarTreeViewModel *model)
|
|||
static void
|
||||
_thunar_tree_view_model_folder_destroy (Node *node)
|
||||
{
|
||||
/* if a subdir gets destroyed, it's handled internally, but if the current_folder
|
||||
* gets destroyed, then we simply set_folder to NULL & cleanup things */
|
||||
/* if a subdir get's destroyed it's handled internally but if the current_folder
|
||||
* get's destroyed then we simply set_folder to NULL & cleanup things */
|
||||
if (node->parent == NULL)
|
||||
{
|
||||
if (node->n_children > 0)
|
||||
{
|
||||
/* set_folder func does not emit row-deleted signal, but instead relies on
|
||||
* ThunarStandardView to disconnect & reconnect the view to quickly update
|
||||
* changes in current_directory. */
|
||||
GList *keys = g_hash_table_get_keys (node->set);
|
||||
|
||||
for (GList *lp = keys; lp != NULL; lp = lp->next)
|
||||
thunar_tree_view_model_dir_remove_file (node, THUNAR_FILE (lp->data));
|
||||
|
||||
g_list_free (keys);
|
||||
}
|
||||
|
||||
/* reset the model */
|
||||
thunar_tree_view_model_set_folder (THUNAR_STANDARD_VIEW_MODEL (node->model), NULL, NULL);
|
||||
}
|
||||
thunar_tree_view_model_set_folder (THUNAR_STANDARD_VIEW_MODEL (node->model), NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2549,13 +2530,26 @@ _thunar_tree_view_model_folder_error (Node *node,
|
|||
{
|
||||
_thunar_return_if_fail (error != NULL);
|
||||
|
||||
if (node->parent == NULL)
|
||||
_thunar_tree_view_model_folder_destroy (node);
|
||||
else
|
||||
thunar_tree_view_model_dir_remove_file (node->parent, node->file);
|
||||
if (node->n_children > 0)
|
||||
{
|
||||
if (node->parent == NULL)
|
||||
{
|
||||
/* set_folder func does not emit row-deleted signal instead relies
|
||||
* on ThunarStandardView to disconnect & reconnect the view quickly update
|
||||
* changes in current_directory. */
|
||||
GList *keys = g_hash_table_get_keys (node->set);
|
||||
|
||||
/* forward the error signal */
|
||||
g_signal_emit_by_name (G_OBJECT (node->model), "error", error);
|
||||
for (GList *lp = keys; lp != NULL; lp = lp->next)
|
||||
thunar_tree_view_model_dir_remove_file (node, THUNAR_FILE (lp->data));
|
||||
|
||||
g_list_free (keys);
|
||||
|
||||
/* reset the model if error is with the current directory */
|
||||
thunar_tree_view_model_set_folder (THUNAR_STANDARD_VIEW_MODEL (node->model), NULL, NULL);
|
||||
}
|
||||
else
|
||||
thunar_tree_view_model_dir_remove_file (node->parent, node->file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2584,8 +2578,6 @@ _thunar_tree_view_model_dir_files_added (Node *node,
|
|||
if (!g_hash_table_contains (node->set, file))
|
||||
thunar_tree_view_model_dir_add_file (node, file);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (node->model), tree_model_props[PROP_NUM_FILES]);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2615,8 +2607,6 @@ _thunar_tree_view_model_dir_files_removed (Node *node,
|
|||
|
||||
thunar_tree_view_model_dir_remove_file (node, file);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (node->model), tree_model_props[PROP_NUM_FILES]);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2851,8 +2841,8 @@ thunar_tree_view_model_dir_files_changed (Node *node_parent,
|
|||
{
|
||||
if (!model->show_hidden)
|
||||
thunar_tree_view_model_dir_remove_file (node_parent, file);
|
||||
|
||||
g_hash_table_add (node_parent->hidden_files, g_object_ref (file));
|
||||
continue;
|
||||
}
|
||||
|
||||
node = thunar_tree_view_model_locate_file (model, file);
|
||||
|
|
@ -3124,12 +3114,9 @@ thunar_tree_view_model_update_search_files (ThunarTreeViewModel *model)
|
|||
g_object_unref (file);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (model), tree_model_props[PROP_NUM_FILES]);
|
||||
|
||||
if (model->search_files != NULL)
|
||||
thunar_g_list_free_full (model->search_files);
|
||||
g_list_free (model->search_files);
|
||||
model->search_files = NULL;
|
||||
|
||||
g_mutex_unlock (&model->mutex_add_search_files);
|
||||
|
||||
return TRUE;
|
||||
|
|
|
|||
|
|
@ -560,8 +560,8 @@ thunar_util_parse_parent (gpointer parent,
|
|||
}
|
||||
else if (GDK_IS_SCREEN (parent))
|
||||
{
|
||||
/* A specific screen was requested. Just return it, without filling 'window_return' */
|
||||
return GDK_SCREEN (parent);
|
||||
/* yep, that's a screen */
|
||||
screen = GDK_SCREEN (parent);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1256,7 +1256,6 @@ thunar_window_init (ThunarWindow *window)
|
|||
window->trash_infobar = gtk_info_bar_new ();
|
||||
gtk_grid_attach (GTK_GRID (window->view_box), window->trash_infobar, 0, 2, 1, 1);
|
||||
window->trash_infobar_restore_button = gtk_info_bar_add_button (GTK_INFO_BAR (window->trash_infobar), _("Restore Selected Items"), RESTORE);
|
||||
gtk_widget_set_sensitive (window->trash_infobar_restore_button, FALSE);
|
||||
window->trash_infobar_empty_button = gtk_info_bar_add_button (GTK_INFO_BAR (window->trash_infobar), _("Empty Trash"), EMPTY);
|
||||
g_signal_connect (window->trash_infobar,
|
||||
"response",
|
||||
|
|
@ -2406,7 +2405,6 @@ thunar_window_switch_current_view (ThunarWindow *window,
|
|||
GSList *view_bindings;
|
||||
ThunarFile *current_directory;
|
||||
ThunarHistory *history;
|
||||
gchar *search_query;
|
||||
|
||||
_thunar_return_if_fail (THUNAR_IS_WINDOW (window));
|
||||
_thunar_return_if_fail (THUNAR_IS_VIEW (new_view));
|
||||
|
|
@ -2438,11 +2436,6 @@ thunar_window_switch_current_view (ThunarWindow *window,
|
|||
window->view_bindings = NULL;
|
||||
g_slist_free_full (view_bindings, g_object_unref);
|
||||
|
||||
/* exit search mode (if the view has no ongoing search operation) */
|
||||
search_query = thunar_standard_view_get_search_query (THUNAR_STANDARD_VIEW (new_view));
|
||||
if (search_query == NULL && window->search_query != NULL)
|
||||
thunar_window_action_cancel_search (window);
|
||||
|
||||
/* update the directory of the current window */
|
||||
current_directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (new_view));
|
||||
thunar_window_set_current_directory (window, current_directory);
|
||||
|
|
@ -2518,13 +2511,15 @@ thunar_window_switch_current_view (ThunarWindow *window,
|
|||
if (thunar_file_is_trash (window->current_directory))
|
||||
gtk_widget_set_sensitive (window->trash_infobar_empty_button, thunar_file_get_item_count (window->current_directory) > 0);
|
||||
|
||||
/* if the view has an ongoing search operation, take that into account */
|
||||
if (search_query != NULL)
|
||||
/* if the view has an ongoing search operation take that into account, otherwise cancel the current search (if there is one) */
|
||||
if (thunar_standard_view_get_search_query (THUNAR_STANDARD_VIEW (window->view)) != NULL)
|
||||
{
|
||||
gchar *str = g_strjoin (NULL, thunar_util_get_search_prefix (), search_query, NULL);
|
||||
gchar *str = g_strjoin (NULL, thunar_util_get_search_prefix (), thunar_standard_view_get_search_query (THUNAR_STANDARD_VIEW (window->view)), NULL);
|
||||
thunar_window_resume_search (window, str);
|
||||
g_free (str);
|
||||
}
|
||||
else if (window->search_query != NULL)
|
||||
thunar_window_action_cancel_search (window);
|
||||
|
||||
/* switch to the new view */
|
||||
thunar_window_notebook_set_current_tab (window, gtk_notebook_page_num (GTK_NOTEBOOK (window->notebook_selected), window->view));
|
||||
|
|
@ -2648,10 +2643,6 @@ thunar_window_notebook_page_removed (GtkWidget *notebook,
|
|||
/* drop connected signals */
|
||||
g_signal_handlers_disconnect_by_data (page, window);
|
||||
|
||||
/* skip selecting another page when the window is being destroyed */
|
||||
if (gtk_widget_in_destruction (GTK_WIDGET (window)))
|
||||
return;
|
||||
|
||||
n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook));
|
||||
if (n_pages == 0)
|
||||
{
|
||||
|
|
@ -2674,7 +2665,8 @@ thunar_window_notebook_page_removed (GtkWidget *notebook,
|
|||
/* page from the other notebook was removed */
|
||||
if (notebook != window->notebook_selected)
|
||||
thunar_window_paned_notebooks_switch (window);
|
||||
else /* this page removed -> select next page */
|
||||
else
|
||||
/* this page removed -> select next page */
|
||||
thunar_window_notebook_select_current_page (window);
|
||||
|
||||
/* update tab visibility */
|
||||
|
|
@ -3678,8 +3670,6 @@ thunar_window_reset_view_type_idle_destroyed (gpointer data)
|
|||
gboolean
|
||||
thunar_window_action_cancel_search (ThunarWindow *window)
|
||||
{
|
||||
ThunarApplication *application;
|
||||
|
||||
_thunar_return_val_if_fail (THUNAR_IS_LOCATION_BAR (window->location_bar), FALSE);
|
||||
_thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE);
|
||||
|
||||
|
|
@ -3718,11 +3708,6 @@ thunar_window_action_cancel_search (ThunarWindow *window)
|
|||
/* bring back the original location bar style (relevant if the bar is hidden) */
|
||||
thunar_window_update_location_bar_visible (window);
|
||||
|
||||
/* tidy up memory after a search */
|
||||
application = thunar_application_get ();
|
||||
thunar_application_malloc_trim_on_idle (application);
|
||||
g_object_unref (application);
|
||||
|
||||
/* required in case of shortcut activation, in order to signal that the accel key got handled */
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue