[nautilus/wip/antoniof/modernize-properties-dialog: 13/17] properties-window: use AdwActionRow and GtkSwitch for executable bit
- From: António Fernandes <antoniof src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [nautilus/wip/antoniof/modernize-properties-dialog: 13/17] properties-window: use AdwActionRow and GtkSwitch for executable bit
- Date: Sun, 2 Jan 2022 19:23:06 +0000 (UTC)
commit 4d34264ad0a6f34a4540be820803f31f38c5d755
Author: Peter Eisenmann <p3732 getgoogleoff me>
Date: Sun Dec 19 01:24:11 2021 +0100
properties-window: use AdwActionRow and GtkSwitch for executable bit
For a simpler user interface represent the executable bit with a
GtkSwitch.
The previously used GtkCheckButton had an "inconsistent" state, which
was used when the executable bit was not set for all files or not set
for all of user/group/other. Since GtkSwitch does not have such a
special state, a separate GtkRevealer combined with a tooltip is used
to handle this case.
Part of #1326
src/nautilus-properties-window.c | 267 +++++++++----------------
src/resources/ui/nautilus-properties-window.ui | 55 +++--
2 files changed, 131 insertions(+), 191 deletions(-)
---
diff --git a/src/nautilus-properties-window.c b/src/nautilus-properties-window.c
index 17d63bc8a..cb2c2f654 100644
--- a/src/nautilus-properties-window.c
+++ b/src/nautilus-properties-window.c
@@ -165,8 +165,10 @@ struct _NautilusPropertiesWindow
AdwComboRow *others_folder_access_row;
AdwComboRow *others_file_access_row;
- GtkWidget *execute_label;
- GtkWidget *execute_checkbox;
+ GtkWidget *execution_list_box;
+ AdwComboRow *execution_row;
+ GtkRevealer *execution_inconsistent_revealer;
+ GtkSwitch *execution_switch;
GtkWidget *security_context_title_label;
GtkWidget *security_context_value_label;
@@ -190,7 +192,6 @@ struct _NautilusPropertiesWindow
GroupChange *group_change;
OwnerChange *owner_change;
- GList *permission_buttons;
GList *permission_rows;
GList *change_permission_combos;
GHashTable *initial_permissions;
@@ -264,10 +265,12 @@ typedef struct
PermissionValue folder_permissions[NUM_PERMISSION_TYPE];
PermissionValue file_permissions[NUM_PERMISSION_TYPE];
+ PermissionValue file_exec_permissions;
gboolean has_files;
gboolean has_folders;
gboolean can_set_all_folder_permission;
gboolean can_set_all_file_permission;
+ gboolean can_set_any_file_permission;
gboolean is_multi_file_window;
} TargetPermissions;
@@ -481,8 +484,8 @@ static void schedule_directory_contents_update (NautilusPropertiesWindow *self);
static void directory_contents_value_field_update (NautilusPropertiesWindow *self);
static void file_changed_callback (NautilusFile *file,
gpointer user_data);
-static void permission_button_update (GtkCheckButton *button,
- NautilusPropertiesWindow *self);
+static void update_execution_row (GtkWidget *row,
+ TargetPermissions *target_perm);
static void update_permission_row (AdwComboRow *row,
TargetPermissions *target_perm);
static void value_field_update (GtkLabel *field,
@@ -1073,6 +1076,27 @@ permission_from_vfs (PermissionType type,
return perm;
}
+static PermissionValue
+exec_permission_from_vfs (guint32 vfs_perm)
+{
+ guint32 perm_user = vfs_perm & UNIX_PERM_USER_EXEC;
+ guint32 perm_group = vfs_perm & UNIX_PERM_GROUP_EXEC;
+ guint32 perm_other = vfs_perm & UNIX_PERM_OTHER_EXEC;
+
+ if (perm_user && perm_group && perm_other)
+ {
+ return PERMISSION_EXEC;
+ }
+ else if (perm_user || perm_group || perm_other)
+ {
+ return PERMISSION_INCONSISTENT;
+ }
+ else
+ {
+ return PERMISSION_NONE;
+ }
+}
+
static TargetPermissions *
get_target_permissions (NautilusPropertiesWindow *self)
{
@@ -1118,6 +1142,16 @@ get_target_permissions (NautilusPropertiesWindow *self)
}
else
{
+ PermissionValue exec_permissions = exec_permission_from_vfs (vfs_permissions);
+
+ if (!p->has_files)
+ {
+ p->file_exec_permissions = exec_permissions;
+ }
+ else if (exec_permissions != p->file_exec_permissions)
+ {
+ p->file_exec_permissions = PERMISSION_INCONSISTENT;
+ }
for (PermissionType type = PERMISSION_USER ; type < NUM_PERMISSION_TYPE; type += 1)
{
PermissionValue permissions = permission_from_vfs (type, vfs_permissions)
@@ -1135,6 +1169,7 @@ get_target_permissions (NautilusPropertiesWindow *self)
}
p->can_set_all_file_permission &= can_set_permissions;
+ p->can_set_any_file_permission |= can_set_permissions;
p->has_files = TRUE;
}
}
@@ -1201,9 +1236,7 @@ properties_window_update (NautilusPropertiesWindow *self,
TargetPermissions *target_perm = get_target_permissions (self);
update_owner_row (self->owner_row, target_perm);
update_group_row (self->group_row, target_perm);
- g_list_foreach (self->permission_buttons,
- (GFunc) permission_button_update,
- self);
+ update_execution_row (GTK_WIDGET (self->execution_row), target_perm);
g_list_foreach (self->permission_rows,
(GFunc) update_permission_row,
target_perm);
@@ -2917,183 +2950,69 @@ initial_permission_state_consistent (NautilusPropertiesWindow *self,
}
static void
-permission_button_toggled (GtkCheckButton *button,
- NautilusPropertiesWindow *self)
+execution_bit_changed (NautilusPropertiesWindow *self,
+ GParamSpec *params,
+ GtkWidget *widget)
{
- FilterType filter_type;
- guint32 permission_mask;
- gboolean inconsistent;
- gboolean on;
+ const guint32 permission_mask = UNIX_PERM_USER_EXEC | UNIX_PERM_GROUP_EXEC | UNIX_PERM_OTHER_EXEC;
+ const FilterType filter_type = FILES_ONLY;
- permission_mask = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button),
- "permission"));
- filter_type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button),
- "filter-type"));
+ /* if activated from switch, switch state is already toggled, thus invert value via XOR. */
+ gboolean active = gtk_switch_get_state (self->execution_switch) ^ GTK_IS_SWITCH (widget);
- if (gtk_check_button_get_active (button)
- && !gtk_check_button_get_inconsistent (button))
- {
- /* Go to the initial state unless the initial state was
- * consistent, or we support recursive apply */
- inconsistent = TRUE;
- on = TRUE;
+ gboolean inconsistent = gtk_revealer_get_child_revealed (self->execution_inconsistent_revealer);
+ gboolean initial_inconsistent = !initial_permission_state_consistent (self, permission_mask,
filter_type);
- if (initial_permission_state_consistent (self, permission_mask, filter_type))
- {
- inconsistent = FALSE;
- on = TRUE;
- }
- }
- else if (gtk_check_button_get_inconsistent (button)
- && !gtk_check_button_get_active (button))
- {
- inconsistent = FALSE;
- on = TRUE;
- }
- else
- {
- inconsistent = FALSE;
- on = FALSE;
- }
-
- g_signal_handlers_block_by_func (G_OBJECT (button),
- G_CALLBACK (permission_button_toggled),
- self);
-
- gtk_check_button_set_active (button, on);
- gtk_check_button_set_inconsistent (button, inconsistent);
-
- g_signal_handlers_unblock_by_func (G_OBJECT (button),
- G_CALLBACK (permission_button_toggled),
- self);
+ /* If original execution permissions were inconsistent, circle through
+ * states: inconsistent -> on -> off -> inconsistent -> … */
+ gboolean set_executable = !active && (inconsistent || !initial_inconsistent);
+ gboolean set_inconsistent = !active && !inconsistent && initial_inconsistent;
update_permissions (self,
- on ? permission_mask : 0,
+ set_executable ? permission_mask : 0,
permission_mask,
filter_type,
- inconsistent);
+ set_inconsistent);
}
static void
-permission_button_update (GtkCheckButton *button,
- NautilusPropertiesWindow *self)
+update_execution_row (GtkWidget *row,
+ TargetPermissions *target_perm)
{
- GList *l;
- gboolean all_set;
- gboolean all_unset;
- gboolean all_cannot_set;
- FilterType filter_type;
- gboolean no_match;
- gboolean sensitive;
- guint32 button_permission;
-
- button_permission = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button),
- "permission"));
- filter_type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button),
- "filter-type"));
- all_set = TRUE;
- all_unset = TRUE;
- all_cannot_set = TRUE;
- no_match = TRUE;
- for (l = self->target_files; l != NULL; l = l->next)
- {
- NautilusFile *file = NAUTILUS_FILE (l->data);
- guint32 file_permissions;
-
- if (!nautilus_file_can_get_permissions (file) ||
- !file_matches_filter_type (file, filter_type))
- {
- continue;
- }
-
- no_match = FALSE;
-
- file_permissions = nautilus_file_get_permissions (file);
-
- if ((file_permissions & button_permission) == button_permission)
- {
- all_unset = FALSE;
- }
- else if ((file_permissions & button_permission) == 0)
- {
- all_set = FALSE;
- }
- else
- {
- all_unset = FALSE;
- all_set = FALSE;
- }
+ NautilusPropertiesWindow *self = target_perm->window;
- if (nautilus_file_can_set_permissions (file))
- {
- all_cannot_set = FALSE;
- }
+ if (target_perm->has_folders)
+ {
+ gtk_widget_hide (self->execution_list_box);
}
+ else
+ {
+ gboolean inconsistent = target_perm->file_exec_permissions == PERMISSION_INCONSISTENT;
- sensitive = !all_cannot_set;
-
- g_signal_handlers_block_by_func (G_OBJECT (button),
- G_CALLBACK (permission_button_toggled),
- self);
-
- gtk_check_button_set_active (button, !all_unset);
- /* if actually inconsistent, or default value for file buttons
- * if no files are selected. (useful for recursive apply) */
- gtk_check_button_set_inconsistent (button,
- (!all_unset && !all_set) ||
- ((filter_type == FILES_ONLY) && no_match));
- gtk_widget_set_sensitive (GTK_WIDGET (button), sensitive);
-
- g_signal_handlers_unblock_by_func (G_OBJECT (button),
- G_CALLBACK (permission_button_toggled),
- self);
-}
-
-static void
-setup_execute_checkbox_with_label (NautilusPropertiesWindow *self,
- guint32 permission_to_check)
-{
-#if 0 && NAUTILUS_A11Y_NEEDS_GTK4_REIMPLEMENTATION
- gboolean a11y_enabled;
- GtkLabel *label_for;
-
- label_for = GTK_LABEL (self->execute_label);
-#endif
- gtk_widget_show (self->execute_label);
- gtk_widget_show (self->execute_checkbox);
-
- /* Load up the check_button with data we'll need when updating its state. */
- g_object_set_data (G_OBJECT (self->execute_checkbox), "permission",
- GINT_TO_POINTER (permission_to_check));
- g_object_set_data (G_OBJECT (self->execute_checkbox), "filter-type",
- GINT_TO_POINTER (FILES_ONLY));
-
- self->permission_buttons =
- g_list_prepend (self->permission_buttons,
- self->execute_checkbox);
+ gtk_revealer_set_reveal_child (self->execution_inconsistent_revealer, inconsistent);
+ gtk_widget_set_has_tooltip (row, inconsistent);
- g_signal_connect_object (self->execute_checkbox, "toggled",
- G_CALLBACK (permission_button_toggled),
- self,
- 0);
+ /* Only toggle switch if permissions are consistent. This still allows switching in case
+ * not all permissions can be set. */
+ if (!inconsistent)
+ {
+ g_signal_handlers_block_by_func (self->execution_switch,
+ G_CALLBACK (execution_bit_changed),
+ self);
-#if 0 && NAUTILUS_A11Y_NEEDS_GTK4_REIMPLEMENTATION
- a11y_enabled = GTK_IS_ACCESSIBLE (gtk_widget_get_accessible (self->execute_checkbox));
- if (a11y_enabled && label_for != NULL)
- {
- AtkObject *atk_widget;
- AtkObject *atk_label;
+ gtk_switch_set_state (self->execution_switch,
+ target_perm->file_exec_permissions == PERMISSION_EXEC);
- atk_label = gtk_widget_get_accessible (GTK_WIDGET (label_for));
- atk_widget = gtk_widget_get_accessible (self->execute_checkbox);
+ g_signal_handlers_unblock_by_func (self->execution_switch,
+ G_CALLBACK (execution_bit_changed),
+ self);
+ }
- /* Create the label -> widget relation */
- atk_object_add_relationship (atk_label, ATK_RELATION_LABEL_FOR, atk_widget);
+ gtk_widget_set_sensitive (row,
+ target_perm->can_set_any_file_permission);
- /* Create the widget -> label relation */
- atk_object_add_relationship (atk_widget, ATK_RELATION_LABELLED_BY, atk_label);
+ gtk_widget_show (self->execution_list_box);
}
-#endif
}
static void
@@ -3432,11 +3351,13 @@ create_simple_permissions (NautilusPropertiesWindow *self)
PERMISSION_OTHER, filter_type);
}
- if (filter_type == FILES_ONLY)
- {
- setup_execute_checkbox_with_label (self,
- UNIX_PERM_USER_EXEC | UNIX_PERM_GROUP_EXEC |
UNIX_PERM_OTHER_EXEC);
- }
+ /* Connect execution bit switch, independent of whether it will be visible or not. */
+ g_signal_connect_swapped (self->execution_row, "activated",
+ G_CALLBACK (execution_bit_changed),
+ self);
+ g_signal_connect_swapped (self->execution_switch, "notify::active",
+ G_CALLBACK (execution_bit_changed),
+ self);
}
static void
@@ -4668,8 +4589,6 @@ real_dispose (GObject *object)
stop_deep_count_for_file (self, self->deep_count_files->data);
}
- g_clear_list (&self->permission_buttons, NULL);
-
g_clear_list (&self->permission_rows, NULL);
g_clear_list (&self->change_permission_combos, NULL);
@@ -4938,8 +4857,10 @@ nautilus_properties_window_class_init (NautilusPropertiesWindowClass *klass)
gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow, others_access_row);
gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow, others_folder_access_row);
gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow, others_file_access_row);
- gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow, execute_label);
- gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow, execute_checkbox);
+ gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow, execution_list_box);
+ gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow, execution_row);
+ gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow,
execution_inconsistent_revealer);
+ gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow, execution_switch);
gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow,
security_context_title_label);
gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow,
security_context_value_label);
gtk_widget_class_bind_template_child (widget_class, NautilusPropertiesWindow,
change_permissions_button_box);
diff --git a/src/resources/ui/nautilus-properties-window.ui b/src/resources/ui/nautilus-properties-window.ui
index 386d4168d..cd36a96a0 100644
--- a/src/resources/ui/nautilus-properties-window.ui
+++ b/src/resources/ui/nautilus-properties-window.ui
@@ -798,17 +798,49 @@
</object>
</child>
<child>
- <object class="GtkLabel" id="execute_label">
+ <object class="GtkListBox" id="execution_list_box">
<property name="visible">False</property>
- <property name="margin_top">12</property>
- <property name="label" translatable="yes">Execute</property>
- <property name="xalign">1</property>
+ <property name="selection-mode">none</property>
+ <child>
+ <object class="AdwActionRow" id="execution_row">
+ <property name="activatable">True</property>
+ <property name="title" translatable="yes">_Executable as
Program</property>
+ <property name="tooltip-text" translatable="yes">Not all files are
marked executable for all users</property>
+ <property name="use-underline">True</property>
+ <child>
+ <object class="GtkBox">
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkRevealer"
id="execution_inconsistent_revealer">
+ <property name="transition-type">crossfade</property>
+ <property name="reveal-child">False</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="label"
translatable="yes">Inconsistent</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSwitch" id="execution_switch">
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
<style>
- <class name="dim-label"/>
+ <class name="boxed-list"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">6</property>
+ <property name="column-span">2</property>
</layout>
</object>
</child>
@@ -858,19 +890,6 @@
</layout>
</object>
</child>
- <child>
- <object class="GtkCheckButton" id="execute_checkbox">
- <property name="visible">False</property>
- <property name="label" translatable="yes">Allow _executing file as
program</property>
- <property name="use_underline">True</property>
- <property name="focusable">True</property>
- <property name="margin_top">12</property>
- <layout>
- <property name="column">1</property>
- <property name="row">6</property>
- </layout>
- </object>
- </child>
</object>
</child>
</object>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]