26
26
27
27
#include <gdk/gdkkeysyms.h>
28
28
#include <gtk/gtk.h>
29
+ #include <gdk/gdkwayland.h>
29
30
#include <glib/gi18n.h>
30
31
#include <gio/gio.h>
31
32
#include <math.h>
@@ -148,6 +149,7 @@ typedef struct {
148
149
guint expand_timeout_source ;
149
150
guint popup_menu_action_index ;
150
151
guint update_places_on_idle_id ;
152
+ gboolean unmount_dialog_active ;
151
153
152
154
} NemoPlacesSidebar ;
153
155
@@ -217,6 +219,7 @@ static void nemo_places_sidebar_style_set (GtkWidget
217
219
static gboolean eject_or_unmount_bookmark (NemoPlacesSidebar * sidebar ,
218
220
GtkTreePath * path );
219
221
static gboolean eject_or_unmount_selection (NemoPlacesSidebar * sidebar );
222
+ static gboolean idle_unmount_dialog (gpointer user_data );
220
223
static void check_unmount_and_eject (GMount * mount ,
221
224
GVolume * volume ,
222
225
GDrive * drive ,
@@ -227,6 +230,7 @@ static void update_places (NemoPlacesSidebar *sideb
227
230
static void update_places_on_idle (NemoPlacesSidebar * sidebar );
228
231
static void rebuild_menu (NemoPlacesSidebar * sidebar );
229
232
static void actions_changed (gpointer user_data );
233
+
230
234
/* Identifiers for target types */
231
235
enum {
232
236
GTK_TREE_MODEL_ROW ,
@@ -2739,6 +2743,211 @@ show_unmount_progress_aborted_cb (GMountOperation *op,
2739
2743
nemo_application_notify_unmount_done (app , NULL );
2740
2744
}
2741
2745
2746
+ // Start code for unmount dialog on Wayland
2747
+ typedef struct {
2748
+ GtkMountOperation * op ;
2749
+ GtkWindow * parent_window ;
2750
+ NemoPlacesSidebar * sidebar_ref ;
2751
+ gboolean cancelled ;
2752
+ gchar * primary_text ;
2753
+ gchar * secondary_text ;
2754
+ GArray * processes ;
2755
+ gint ref_count ;
2756
+ } UnmountDialogData ;
2757
+
2758
+ static UnmountDialogData *
2759
+ unmount_dialog_data_ref (UnmountDialogData * data )
2760
+ {
2761
+ if (data ) {
2762
+ data -> ref_count ++ ;
2763
+ }
2764
+ return data ;
2765
+ }
2766
+
2767
+ static void
2768
+ unmount_dialog_data_unref (UnmountDialogData * data )
2769
+ {
2770
+ if (data == NULL ) {
2771
+ return ;
2772
+ }
2773
+
2774
+ data -> ref_count -- ;
2775
+ if (data -> ref_count == 0 ) {
2776
+ if (data -> op ) {
2777
+ g_object_unref (G_OBJECT (data -> op ));
2778
+ }
2779
+ if (data -> processes ) {
2780
+ g_array_free (data -> processes , TRUE);
2781
+ }
2782
+ if (data -> sidebar_ref ) {
2783
+ g_object_unref (data -> sidebar_ref );
2784
+ }
2785
+ g_free (data -> primary_text );
2786
+ g_free (data -> secondary_text );
2787
+ g_free (data );
2788
+ }
2789
+ }
2790
+
2791
+ static void
2792
+ mount_op_finalized_cb (gpointer user_data ,
2793
+ GObject * where_the_object_was )
2794
+ {
2795
+ UnmountDialogData * data = (UnmountDialogData * )user_data ;
2796
+ if (data && data -> sidebar_ref ) {
2797
+ NemoPlacesSidebar * sidebar = NEMO_PLACES_SIDEBAR (data -> sidebar_ref );
2798
+ if (NEMO_IS_PLACES_SIDEBAR (sidebar )) {
2799
+ sidebar -> unmount_dialog_active = FALSE;
2800
+ }
2801
+ }
2802
+
2803
+ if (data ) {
2804
+ data -> cancelled = TRUE;
2805
+ if (data -> op == GTK_MOUNT_OPERATION (where_the_object_was )) {
2806
+ data -> op = NULL ;
2807
+ } else {
2808
+ g_warning ("mount_op_finalized_cb: Finalized GtkMountOperation (0x%p) is not the one stored in UnmountDialogData (0x%p). This is unexpected." ,
2809
+ where_the_object_was , data -> op );
2810
+ if (data -> op != NULL ) {
2811
+ data -> op = NULL ;
2812
+ }
2813
+ }
2814
+ }
2815
+ unmount_dialog_data_unref (data );
2816
+ }
2817
+
2818
+ static void
2819
+ on_show_processes_wayland_workaround (GtkMountOperation * op ,
2820
+ const gchar * message ,
2821
+ GArray * processes ,
2822
+ GArray * choices ,
2823
+ gpointer user_data )
2824
+ {
2825
+ NemoPlacesSidebar * sidebar = NEMO_PLACES_SIDEBAR (user_data );
2826
+
2827
+ if (sidebar -> unmount_dialog_active ) {
2828
+ g_signal_stop_emission_by_name (op , "show-processes" );
2829
+ return ;
2830
+ }
2831
+ sidebar -> unmount_dialog_active = TRUE;
2832
+
2833
+ /* Schedule unmount dialog in main loop to avoid Wayland reentrancy */
2834
+ UnmountDialogData * data = g_new0 (UnmountDialogData , 1 );
2835
+ data -> op = GTK_MOUNT_OPERATION (op );
2836
+ g_object_ref (G_OBJECT (op ));
2837
+ data -> cancelled = FALSE;
2838
+ data -> sidebar_ref = g_object_ref (sidebar );
2839
+ data -> parent_window = GTK_WINDOW (sidebar -> window );
2840
+ /* Split message into first line and rest */
2841
+ char * newline_pos = strchr (message , '\n' );
2842
+ if (newline_pos != NULL ) {
2843
+ /* Found a newline - split the message */
2844
+ int first_line_len = newline_pos - message ;
2845
+ data -> primary_text = g_strndup (message , first_line_len );
2846
+ data -> secondary_text = g_strdup (newline_pos );
2847
+ } else {
2848
+ /* No newline found - use whole message as primary text */
2849
+ data -> primary_text = g_strdup (message );
2850
+ }
2851
+ /* Process using volume */
2852
+ if (processes && processes -> len > 0 ) {
2853
+ GArray * filtered = g_array_new (FALSE, FALSE, sizeof (GPid ));
2854
+ for (guint i = 0 ; i < processes -> len ; ++ i ) {
2855
+ GPid pid = g_array_index (processes , GPid , i );
2856
+ g_array_append_val (filtered , pid );
2857
+ }
2858
+ data -> processes = filtered ;
2859
+ } else {
2860
+ data -> processes = NULL ;
2861
+ }
2862
+
2863
+ /* Set a weak reference on the mount operation to know if it gets destroyed */
2864
+ g_object_weak_ref (G_OBJECT (op ), mount_op_finalized_cb , unmount_dialog_data_ref (data ));
2865
+ g_signal_stop_emission_by_name (op , "show-processes" );
2866
+ g_idle_add_full (G_PRIORITY_HIGH_IDLE , idle_unmount_dialog , unmount_dialog_data_ref (data ), NULL );
2867
+ }
2868
+
2869
+ static gboolean
2870
+ idle_unmount_dialog (gpointer user_data )
2871
+ {
2872
+ UnmountDialogData * data = user_data ;
2873
+ gint response = GTK_RESPONSE_NONE ;
2874
+
2875
+ /* If data->op is NULL, it means mount_op_finalized_cb was called and nulled it.
2876
+ * If data->cancelled is TRUE, it also means mount_op_finalized_cb was called.
2877
+ */
2878
+ if (data -> op == NULL || data -> cancelled ) {
2879
+ if (data -> sidebar_ref ) { // Reset flag if sidebar still exists
2880
+ NemoPlacesSidebar * sidebar = NEMO_PLACES_SIDEBAR (data -> sidebar_ref );
2881
+ if (NEMO_IS_PLACES_SIDEBAR (sidebar )) {
2882
+ sidebar -> unmount_dialog_active = FALSE;
2883
+ }
2884
+ }
2885
+ return G_SOURCE_REMOVE ;
2886
+ }
2887
+
2888
+ if (data -> processes && data -> processes -> len > 0 ) {
2889
+ GString * plist = g_string_new ("" );
2890
+ g_string_append (plist , "\n" );
2891
+ for (guint i = 0 ; i < data -> processes -> len ; i ++ ) {
2892
+ GPid pid = g_array_index (data -> processes , GPid , i );
2893
+ gchar * comm = NULL ;
2894
+ gchar procfile [64 ];
2895
+ g_snprintf (procfile , sizeof (procfile ), "/proc/%d/comm" , pid );
2896
+ if (!g_file_get_contents (procfile , & comm , NULL , NULL )) {
2897
+ g_free (comm );
2898
+ comm = g_strdup_printf ("%d" , pid );
2899
+ } else {
2900
+ g_strchomp (comm );
2901
+ }
2902
+ g_string_append_printf (plist , "%s\n" , comm );
2903
+ g_free (comm );
2904
+ }
2905
+ gchar * plist_text = g_string_free (plist , FALSE);
2906
+ gchar * new_secondary = g_strdup_printf ("%s\n%s" , data -> secondary_text , plist_text );
2907
+ g_free (plist_text );
2908
+ g_free (data -> secondary_text );
2909
+ data -> secondary_text = new_secondary ;
2910
+ }
2911
+
2912
+ GtkWindow * parent = data -> parent_window ;
2913
+ GtkWidget * dialog = gtk_message_dialog_new (parent ,
2914
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT ,
2915
+ GTK_MESSAGE_WARNING ,
2916
+ GTK_BUTTONS_NONE ,
2917
+ "%s" , data -> primary_text );
2918
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog ), "%s" , data -> secondary_text );
2919
+ gtk_dialog_add_buttons (GTK_DIALOG (dialog ),
2920
+ _ ("_Unmount" ), GTK_RESPONSE_YES ,
2921
+ _ ("_Cancel" ), GTK_RESPONSE_NO ,
2922
+ NULL );
2923
+ gtk_widget_show_all (dialog );
2924
+ response = gtk_dialog_run (GTK_DIALOG (dialog ));
2925
+ gtk_widget_destroy (dialog );
2926
+ if (data -> sidebar_ref ) { // Reset flag now that dialog is done
2927
+ NemoPlacesSidebar * sidebar = NEMO_PLACES_SIDEBAR (data -> sidebar_ref );
2928
+ if (NEMO_IS_PLACES_SIDEBAR (sidebar )) {
2929
+ sidebar -> unmount_dialog_active = FALSE;
2930
+ }
2931
+ }
2932
+
2933
+ /* data->op could have become NULL if mount_op_finalized_cb was called
2934
+ * while gtk_dialog_run() was blocking.
2935
+ */
2936
+ if (data -> op == NULL || data -> cancelled ) {
2937
+ g_warning ("Mount operation was cancelled or finalized while dialog was open. Not replying." );
2938
+ } else {
2939
+ /* data->op is still valid here, and data->cancelled is false */
2940
+ GMountOperation * mount_op = G_MOUNT_OPERATION (data -> op );
2941
+ if (response == GTK_RESPONSE_YES )
2942
+ g_mount_operation_reply (mount_op , G_MOUNT_OPERATION_HANDLED );
2943
+ else
2944
+ g_mount_operation_reply (mount_op , G_MOUNT_OPERATION_ABORTED );
2945
+ }
2946
+
2947
+ // End wayland code for umount dialog
2948
+ return G_SOURCE_REMOVE ;
2949
+ }
2950
+
2742
2951
static GMountOperation *
2743
2952
get_unmount_operation (NemoPlacesSidebar * sidebar )
2744
2953
{
@@ -2749,7 +2958,11 @@ get_unmount_operation (NemoPlacesSidebar *sidebar)
2749
2958
G_CALLBACK (show_unmount_progress_cb ), sidebar );
2750
2959
g_signal_connect (mount_op , "aborted" ,
2751
2960
G_CALLBACK (show_unmount_progress_aborted_cb ), sidebar );
2752
-
2961
+ GdkDisplay * display = gtk_widget_get_display (GTK_WIDGET (sidebar ));
2962
+ if (GDK_IS_WAYLAND_DISPLAY (display )) {
2963
+ g_signal_connect (mount_op , "show-processes" ,
2964
+ G_CALLBACK (on_show_processes_wayland_workaround ), sidebar );
2965
+ }
2753
2966
return mount_op ;
2754
2967
}
2755
2968
@@ -4130,6 +4343,8 @@ nemo_places_sidebar_init (NemoPlacesSidebar *sidebar)
4130
4343
4131
4344
sidebar -> update_places_on_idle_id = 0 ;
4132
4345
4346
+ sidebar -> unmount_dialog_active = FALSE;
4347
+
4133
4348
sidebar -> my_computer_expanded = g_settings_get_boolean (nemo_window_state ,
4134
4349
NEMO_WINDOW_STATE_MY_COMPUTER_EXPANDED );
4135
4350
sidebar -> bookmarks_expanded = g_settings_get_boolean (nemo_window_state ,
0 commit comments