Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dragging item from archiver onto pcmanfm's side pane freezes the archiver #45

Open
CasperVector opened this issue Mar 6, 2019 · 29 comments

Comments

@CasperVector
Copy link

CasperVector commented Mar 6, 2019

  • Open pcmanfm with the side pane enabled, open a compressed file with engrampa, and drag an item from the compressed file across the side pane.
  • As soon as the mouse pointer reaches the side pane, even before the item is dropped, an error dialog shows up; meanwhile, the shape of the pointer changes from the normal "hand" (if originally outside of the file list area in pcmanfm) or the "hand with plus sign" (if originally inside the file list) to the "hand with chain sign".
  • The desktop becomes unresponsive to mouse clicks and most keystrokes, until engrampa is killed, after which the pointer shape returns normal. Similar symptom also happens with xarchiver, but not with thunar.
  • The issue can be worked around by reverting the changes in 1d7738c; actually, disabling the if(!dd->waiting_data) { ... } branch when either dest or dest_path is zero prevents the symptom from occuring. However, I am totally unfamiliar with the drag-and-drop protocols, and therefore unsure whether this fixes the root cause of this issue and does not cause undesirable side effects.
@CasperVector
Copy link
Author

A patch which seems most unintrusive to me:

diff -ur libfm-1.3.2/src/gtk/fm-dnd-dest.c libfm-1.3.2/src/gtk/fm-dnd-dest.c
--- libfm-1.3.2/src/gtk/fm-dnd-dest.c	2022-10-31 01:05:49.931057670 +0800
+++ libfm-1.3.2/src/gtk/fm-dnd-dest.c	2022-10-31 01:07:27.667579011 +0800
@@ -979,7 +979,7 @@
         if (dd->context != drag_context)
             clear_src_cache(dd);
         action = 0;
-        if(!dd->waiting_data) /* we're still waiting for "drag-data-received" signal */
+        if(dest_path && !dd->waiting_data) /* we're still waiting for "drag-data-received" signal */
         {
             /* retrieve the source files */
             gtk_drag_get_data(dd->widget, drag_context, target, time(NULL));

@CasperVector
Copy link
Author

Sorry, incomplete check...

diff -ur libfm-1.3.2/src/gtk/fm-dnd-dest.c libfm-1.3.2/src/gtk/fm-dnd-dest.c
--- libfm-1.3.2/src/gtk/fm-dnd-dest.c	2022-10-31 01:05:49.931057670 +0800
+++ libfm-1.3.2/src/gtk/fm-dnd-dest.c	2022-10-31 01:07:27.667579011 +0800
@@ -979,7 +979,7 @@
         if (dd->context != drag_context)
             clear_src_cache(dd);
         action = 0;
-        if(!dd->waiting_data) /* we're still waiting for "drag-data-received" signal */
+        if(dest && dest_path && !dd->waiting_data) /* we're still waiting for "drag-data-received" signal */
         {
             /* retrieve the source files */
             gtk_drag_get_data(dd->widget, drag_context, target, time(NULL));

@dirkf
Copy link

dirkf commented Mar 17, 2024

Did you build and test this? It doesn't seem to have a PR yet.

@cwendling
Copy link

@CasperVector it probably will work, but doesn't that just effectively revert 1d7738c? I'm not sure the reason behind that commit, and it's from 2012, but it sill might be interesting to see why that was done like so.

@fulalas
Copy link

fulalas commented Oct 9, 2024

@CasperVector, I just tried your patch, but unfortunately it didn't fix the issue for me. Once I drag a file from a extractor application like engrampa over pcmanfm panel, it shows this error just like it happens without your patch:

error

I also tried to combine with this other patch mentioned here but it didn't change anything :(

@CasperVector
Copy link
Author

CasperVector commented Oct 13, 2024

@CasperVector it probably will work, but doesn't that just effectively revert 1d7738c? I'm not sure the reason behind that commit, and it's from 2012, but it sill might be interesting to see why that was done like so.

Sorry, I did not research (and now probably cannot afford to; I have been extremely busy with my day job for nearly an entire year) the commit you mentioned. But I can confirm my patch works on Devuan Chimaera and Devuan Daedalus (and probably the corresponding Debian releases), both against libfm 1.3.2.

@CasperVector
Copy link
Author

@CasperVector, I just tried your patch, but unfortunately it didn't fix the issue for me. Once I drag a file from a extractor application like engrampa over pcmanfm panel, it shows this error just like it happens without your patch:

error

I also tried to combine with this other patch mentioned here but it didn't change anything :(

I think the error popup is expected when you (drag and) drop an entry in a compressed file onto the pcmanfm's side pane; what my patch does is to prevent the desktop freeze when the entry is dragged across the pane. I do not know which you mean, but as is said in the previous message, the patch is confirmed to work in the environments I use.

@dirkf
Copy link

dirkf commented Oct 13, 2024

... the error popup is expected ...

That's what I thought.

@fulalas
Copy link

fulalas commented Oct 13, 2024

what my patch does is to prevent the desktop freeze

Now I see!

the error popup is expected when you (drag and) drop

Sure, but it happens just by hovering (no drop) over the panel, which clearly is not the expected behavior.

@CasperVector
Copy link
Author

Sure, but it happens just by hovering (no drop) over the panel, which clearly is not the expected behavior.

That is exactly what my patch attempts to prevent. So both my patch and the other patch you mentioned probably need some refinement, preferably by someone capable (and having the time) of debugging your case (either locally or remotely).

@fulalas
Copy link

fulalas commented Oct 14, 2024

This is intriguing. Are you building against GTK2 or GTK3?

@CasperVector
Copy link
Author

I think it should be GTK3; my Devuan Chimaera (previous) and Devuan Daedalus (current) enviroments do not use GTK2.

@fulalas
Copy link

fulalas commented Oct 14, 2024

@CasperVector, I think I found the cause of the issue. Try this patch -- don't need to use your patch nor this one.

--- src/gtk/fm-places-view.c    2024-10-14 15:43:41.175374415 +0200
+++ src/gtk/fm-places-view.c.patched    2024-10-14 15:43:34.074374079 +0200
@@ -251,6 +251,15 @@
     gboolean ret = FALSE;
     GdkDragAction action = 0;
 
+    GdkWindow* source_window = gdk_drag_context_get_source_window(drag_context);
+    GtkWidget* source_widget = NULL;
+    if (source_window != NULL) {
+        gdk_window_get_user_data(source_window, (gpointer*)&source_widget);
+
+        if (source_widget == NULL)
+            return FALSE;
+    }
+
     target = gtk_drag_dest_find_target(dest_widget, drag_context, NULL);
     if(target == GDK_NONE)
         return FALSE;

Explanation: engrampa window (and potentially other extractors) has source_widget == NULL so it causes the error. What my patch does is preventing any action when source_widget == NULL.

After applying my patch, I tested drag and dropping from engrampa to the file section of pcmanfm and it's still extracting, so no regression. Also, when drag and dropping a folder from pcmanfm to the side panel, it's still creating a bookmark, so again no regression here.

Let me know if you find any issues.

Thanks!

@CasperVector
Copy link
Author

CasperVector commented Oct 14, 2024

I can confirm your latest patch also prevents the freeze, and (just like in your test) does not suffer from the two regressions. Even better, it also eliminates the error popup in your screenshot, and corresponds to a clear explanation of the root cause. Many thanks!

@fulalas
Copy link

fulalas commented Oct 14, 2024

Cool!

@dirkf
Copy link

dirkf commented Oct 14, 2024

In the library source file gtkdragdest.c, gtk_drag_dest_find_target() gets the source widget (if any) using gtk_drag_get_source_widget(). That seems to be a documented part of the API.

What happens if the patch is made like this:

     gboolean ret = FALSE;
     GdkDragAction action = 0;
 
+    GtkWidget* source_widget = gtk_drag_get_source_widget (drag_context);
+    if (source_widget == NULL) {
+        return FALSE;
+    }
+
     target = gtk_drag_dest_find_target(dest_widget, drag_context, NULL);
     if(target == GDK_NONE)
         return FALSE;

One possibility is that the GTK call hangs because that's where it hangs in the bug. Otherwise it's a few lines shorter (and could be 1 line shorter by collapsing the declaration: if (NULL == gtk_drag_get_source_widget (drag_context)) { ....

@fulalas
Copy link

fulalas commented Oct 14, 2024

@dirkf, even better! I confirm it works!

@CasperVector
Copy link
Author

I can confirm the same. Thanks!

@dirkf
Copy link

dirkf commented Oct 15, 2024

So this is a solution that works for PCManFM without affecting other packages: time for a PR?

The originally suggested patch seems to be good practice too, even if it doesn't solve the issue, so maybe include both commits?

@fulalas
Copy link

fulalas commented Oct 15, 2024

So this is a solution that works for PCManFM without affecting other packages: time for a PR?

Well, it might affect packages that depend on libfm, although very unlikely to cause any issue due to the nature of the changes we made.

The originally suggested patch seems to be good practice too, even if it doesn't solve the issue, so maybe include both commits?

I don't see any need for this other patch made by zhuyaliang. I wouldn't include it.

But yes, I'm happy to suggest your code in a PR. Maybe just removing the curly brackets to keep consistency across the code. :)

@dirkf
Copy link

dirkf commented Oct 15, 2024

That was just the Gnome style that I pulled in. Some style guides mandate {} even for a single statement block, to avoid confusion, eg if additional statements are added later, and, reluctantly, I've come to agree. But unless it's dangerously bad, maintainers should match the existing style.

I also don't much like val == NULL (vs !val) since NULL in C should be a null pointer constant (0, or ((void*)0)) that always compares falsy in a conditional expression. In other languages with multiple null/falsy values, comparing to any one of them is a "code smell", but maybe the Gnomes have/had to support some non-conforming C compiler with a truthy NULL; the principle above applies.

Unfortunately we still haven't discovered the dangerous bug, whereby GTK could hang the UI when this patch is absent. Probably we won't, now, but, if calling gtk_drag_dest_find_target() is what provoked the hang, there are these possibilities:

  • gtk_drag_get_source_widget() hangs: but we know it doesn't (:-)
  • gtk_drag_dest_get_target_list() hangs
  • gdk_drag_context_list_targets() hangs
  • one of the object lists returned by the above two being compared in the nested loop must somehow have become self-linked (there are no checks against this).

Since GTK must be many times more exercised than PCManFM, I wonder if the latter might be incorrectly setting some data (the possible targets in the Places widget, say) so as to pass to or cause a circular list in GTK. Some years ago the Windows user APIs were overhauled to check user-supplied data more strictly; I think I would want my library code to validate a user-supplied linked list before processing it or handing it out to other API users.

@ib
Copy link
Member

ib commented Nov 16, 2024

In principle, there is no freeze. 😉

If you drag very carefully on an entry in the side pane, you can see that dropping is actually possible there.

The patch suggested by @dirkf simply disables any drop on the side pane from other applications, which isn't what we want.

The freeze happens during a drop attempt between entries, because libfm needs a call to fm_dnd_dest_get_default_action() for its own drops (from folder view to side pane), where it calls gtk_drag_get_data() due to 1d7738c - a call that goes to the archiver, although it is not intended for it.

So for XDirectSave, we just need to make sure that the GdkDragAction is determined without getting lost in libfm's drop code:

--- a/src/gtk/fm-dnd-dest.c
+++ b/src/gtk/fm-dnd-dest.c
@@ -939,6 +939,10 @@ GdkDragAction fm_dnd_dest_get_default_action(FmDndDest* dd,
     FmPath* dest_path;
     int can_drop;
 
+    /* this is XDirectSave */
+    if(target == dest_target_atom[FM_DND_DEST_TARGET_XDS])
+        return GDK_ACTION_COPY;
+
     if(!dest || !(dest_path = fm_file_info_get_path(dest)))
         /* query drag sources in any case */
         goto query_sources;
@@ -968,10 +972,6 @@ GdkDragAction fm_dnd_dest_get_default_action(FmDndDest* dd,
         return GDK_ACTION_COPY;
     }
 
-    /* this is XDirectSave */
-    if(target == dest_target_atom[FM_DND_DEST_TARGET_XDS])
-        return GDK_ACTION_COPY;
-
     /* we have no valid data, query it now */
     if(!dd->src_files || dd->context != drag_context)
     {

Indirectly, @CasperVector's patch already did this (because dest is NULL in case of XDirectSave), but I think it's clearer and easier to understand this way.

Please test and report back.

@dirkf
Copy link

dirkf commented Nov 16, 2024

From https://old.reddit.com/r/gnome/comments/1c8vy11/any_drag_and_drop_archive_managers/l0ju1tm/

... X11 said "hey, let's turn this around, so the target can write and the source can read" and they invented XDirectSave (I can't even find a spec for this thing) where the target writes the directory path to the source and then the source saves the files in that directory.
...

Anyhow, is it possible that this fix also enables folder (name) drag-drop from PCManFM to XFCE Terminal, as with Thunar?

@ib
Copy link
Member

ib commented Nov 16, 2024

is it possible that this fix also enables folder (name) drag-drop from PCManFM to XFCE Terminal, as with Thunar?

What do you mean? Is there a bug report for this?

@dirkf
Copy link

dirkf commented Nov 16, 2024

Thanks for your interest. I'm not aware of one (I did look here and in the PCManFM SF tracker), but making LibFM XDirectSave-aware seemed like it might be a solution, since you can drag a file on to the XFCE terminal window from Thunar, which in turn doesn't have this drag-drop bug. Apasrt from the original author, no-one could know whether this functionality in PCManFM is broken or was never intended to exist.

@ib
Copy link
Member

ib commented Nov 16, 2024

folder (name) drag-drop from PCManFM to XFCE Terminal […] no-one could know whether this functionality in PCManFM is broken or was never intended to exist

Works for me with both Thunar and PCManFM.

@dirkf
Copy link

dirkf commented Nov 17, 2024

OK, thx, it does now with 1.3.2-1 versions of PCManFM/LibFM (seems like what I had before) and the supporting libs now in a fully updated MX-Linux 23; it surely used not to work.

With the above configuration, while it is true that dragging an archive entry to the Places pane may work if drag is made directly to a writable Place, the UI can nonetheless be locked. Personally I wouldn't mind not being able to drag-drop to a Place, but it would be a pity to have disabled drag-drop to an item in the Directory Tree pane. The current failing behaviour is similar to my earlier description, but I now see these characteristics (maybe overlooked when preparing that description):

  • when the drag-cursor enters an empty area of the Places pane the cursor changes from the drag-copy icon to the drag-link icon
  • no mouse actions or application keyboard entry are effective ("the UI is locked")
  • Alt+Tab and Alt+F4 can be used to select the archiver error dialog and close it (presumably because these are acting through the WM) but the UI remains "locked", with the drag-link cursor
  • it's now possible to close the archiver main window (and so the archiver application) in the same way, which "unlocks" the UI, as before the test.

The error dialog is similar to what appears when dropping the entry on Filesystem Root as an unprivileged user, but in that case the UI is not "locked", so that the dialog can be dismissed. In the failing case the dialog is raised without the user dropping the entry: that's clearly wrong when the user had no intention of dropping the entry in the empty area of the Places pane. The drop handler is being invoked incorrectly.

If as you say fm_dnd_dest_get_default_action() is being called during the drag, when its dd->dest_file can be NULL and then some sort of deadlock is occurring because the XDirectSave case should have been handled first, that certainly matches the observed behaviour. I'd just ask whether the function needs some further protection against that condition, in case it's called with dd->dest_file NULL and target != dest_target_atom[FM_DND_DEST_TARGET_XDS].

@ib
Copy link
Member

ib commented Nov 17, 2024

the UI can nonetheless be locked

Please give me an example.

If it's an unwritable location, it's up to the archiver to detect it and report the error.

The current failing behaviour is similar to my earlier description

If you test my patch, you will notice that none of this happens anymore (at least not with Xarchiver). The target is responsible for indicating whether a drop is possible at all, and the source is responsible for indicating whether the drop was successful or not.

when the drag-cursor enters an empty area of the Places pane the cursor changes from the drag-copy icon to the drag-link icon

I've already fixed this as well. Besides the above patch, I currently have four others in my local repository to make drag and drop look more like it should.

but the UI remains "locked"

This is due to a drag-finish during a drag-received during a drag-motion, i.e. the drag is finished without a drop action that the archiver is still waiting for, roughly speaking.

I'd just ask whether the function needs some further protection against that condition, in case it's called with dd->dest_file NULL and target != dest_target_atom[FM_DND_DEST_TARGET_XDS].

Not unless someone reports a bug caused by an internal drag and drop.

@dirkf
Copy link

dirkf commented Nov 17, 2024

Please give me an example.

That was exactly the original report:

  • As soon as the mouse pointer reaches the side pane, even before the item is dropped, an error dialog shows up; meanwhile, the shape of the pointer changes from the normal "hand" (if originally outside of the file list area in pcmanfm) or the "hand with plus sign" (if originally inside the file list) to the "hand with chain sign".
  • The desktop becomes unresponsive to mouse clicks and most keystrokes, until engrampa is killed, after which the pointer shape returns normal. Similar symptom also happens with xarchiver, but not with thunar.

That is, the problem that your patch will correct. I observed the deadlock in these cases:

  • empty area of Places Pane,
  • border between items in Places Pane, presumably a sub-case of the above,
  • but not when dragging to a USB drive in the Places Pane, so my original issue could have been the second case above with careless dragging.

Dragging to these Places without infringing on the above doesn't cause a deadlock, nor dragging to any part (that I tried) of the Directory Tree Pane.

... a drag-finish during a drag-received during a drag-motion, i.e. the drag is finished without a drop action that the archiver is still waiting for

This seems like a critical error that a GUI framework ought to be detecting and preventing or mitigating, but obviously is out of scope here.

Many thanks for your work, which should also fix these long-standing PCManFM issues:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants