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

Drag/drop in data browser or display editor results in dead mouse on Linux #3132

Open
kasemir opened this issue Sep 5, 2024 · 21 comments
Open

Comments

@kasemir
Copy link
Collaborator

kasemir commented Sep 5, 2024

There is a strange side effect of drag & drop on Linux.

  1. Create a new display or open existing display in editor.

  2. Drag & drop something by either dragging a new “label” from the widget palette into the editor pane, or by moving existing widgets around in the tree view. As a result, the editor will be “dirty”.

  3. Try to close the dirty editor. As expected, a dialog appears: “..has been modified. Save before closing?”.
    But the No/Yes/Cancel buttons in the dialog do not react to mouse clicks, at least not on RHEL 9.4.
    When running RHEL 8.7 via a Thinlinc remove desktop, nothing in the desktop reacts to the mouse.
    It is possible to use cursor keys, escape/spare/enter to interact with the dialog, but the mouse is mostly dead.

There is no problem when using drag&drop, then saving via File/Save or Ctrl-S.
There’s also no problem when dragging a PV into the data browser. The “Add PV” dialog triggered by the PV drop functions fine.

The problem appears only when using drag&drop in the display editor, then trying to close the dirty editor right away, on Linux.
Tried JFX 20.0.2+3, 21.0.3+2, 22.0.2 and 24-ea+5, same problem.
With 20.0.2, both -Djdk.gtk.version=2 and 3 exhibit the same problem.

No problem on Mac OS, don't know about Windows.

@shroffk
Copy link
Member

shroffk commented Sep 5, 2024

can't reproduce this on windows (using the master branch with javafx 21)

@kasemir
Copy link
Collaborator Author

kasemir commented Sep 5, 2024

Thanks for checking! Do you see this on your Linux systems?

@shroffk
Copy link
Member

shroffk commented Sep 5, 2024

Yes, I can reproduce this.
I tried on the new training VM and was not able to reproduce it... but I was able to reproduce it on my testbed workstations.
As you mention this is only related to drag and drop.

There is just one warning I observe

(java:2686605): Gdk-WARNING **: 12:06:21.633: XSetErrorHandler() called with a GDK error trap pushed. Don't do that.

@shroffk
Copy link
Member

shroffk commented Sep 5, 2024

The problem appears only when using drag&drop in the display editor, then trying to close the dirty editor right away

I see this only when dragging and dropping initiated from the widget panel.

When I drag and drop a PV name from another application it works fine... in the above case, once you have dragged and dropped a widget if you then proceed to do another drag and drop ( a pv from a pv table) then the problem resolves itself

@kasemir
Copy link
Collaborator Author

kasemir commented Sep 5, 2024

Since this only happens on Linux, I'm not sure if there's an issue in the Linux version of JavaFX, or if there's an error in the usage of the D&D API in the display editor, something that's generally wrong, but out of pure luck it doesn't matter on Mac and Windows.

@kasemir
Copy link
Collaborator Author

kasemir commented Sep 5, 2024

I see this only when dragging and dropping initiated from the widget panel.

Do you see it when re-ordering widgets in the widget tree view of the editor?
Or really only in the drag from the widget palette?

@shroffk
Copy link
Member

shroffk commented Sep 5, 2024

I can reproduce it when moving widgets.
It also matters if I maintain selection, if in the above example...

If I drag and drop a widget or move it in the widget tree and then loose the selection then the problem does not happen for me

@kasemir
Copy link
Collaborator Author

kasemir commented Sep 5, 2024

then loose the selection then the problem does not happen

Indeed! Not sure what that means...

@kasemir
Copy link
Collaborator Author

kasemir commented Sep 6, 2024

I’ve tried various things to no avail.

Disabled D&D from the palette and the drag response in the editor pane, so only the widget tree does any D&D, in case there’s some conflict between them. Simplified D&D from the widget tree to drag a simple” TEST" string, no custom drag data, no drag image.
Turns out that simply starting a drag (mouse down, move by a pixel, release) triggers the problem.

Your observation regarding the selection is very interesting. After the drag, manually clearing or changing the selection indeed avoids the problem. But when I automatically clear the selection in the “okToClose” handler just before the "..Save before closing?” dialog, the problem persists. .. unless I wait 100ms after clearing the selection, then perform the rest of the okToClose code.

I’m starting to think this is internal to JFX on Linux. Since it’s fine on Windows, Mac, and even with some Linux setups, there may not be any error in the display editor code.

It’s also no show stopper because we have workarounds: De-select widgets, File/Save/CTRL-S to clear the ‘dirty’ state, or use keyboard for dialog buttons in the "..Save before closing?” dialog.

I happened to run into this error because I had to move some widget to the "front" in several displays, so I opened in editor, moved widget in tree view, close ... and was stuck, not being able to press "OK" on the save prompt. But that’s a special scenario, not how you typically use the editor. Besides, relying on the "Save before closing?" dialog to save your changes is like relying on the safety switch in the microwave when you simply open its door without pressing "Stop". Bad idea, https://xkcd.com/2886/, https://arxiv.org/abs/1504.02165

@georgweiss
Copy link
Collaborator

georgweiss commented Sep 12, 2024

Not sure if related or same issue:
Drag-n-drop of "PV" from OPI to Data Browser displays same issue. 100% reproducible on Ubuntu/XFCE it seems. Dialog in Data Browser launches, but mouse interaction is not pssible.

@kasemir
Copy link
Collaborator Author

kasemir commented Sep 12, 2024

Good catch! Yes, I think that's the same issue. The dialog still allows keyboard interaction, but no mouse, right?

For the "Save before closing?" dialog I can hack around it by clearing the selection as Kunal had determined and waiting a little, shown below. But again that's a hack and not sure what one would do for the databrowser's add-PV dialog.

Still, this suggests there's something happening when starting the drag on Linux.
Doesn't matter if there's an actual drop.
The dialog might be triggered by the drop as in this new data browser example, but just starting a drag in an already dirty editor, moving by a pixel and aborting, then closing the editor, will result in the mouse-deaf "Save before closing?" dialog.

diff --git a/app/display/editor/src/main/java/org/csstudio/display/builder/editor/app/DisplayEditorInstance.java b/app/display/editor/src/main/java/org/csstudio/display/builder/editor/app/DisplayEditorInstance.java
index 1d2b607c4..2a82f88ff 100644
--- a/app/display/editor/src/main/java/org/csstudio/display/builder/editor/app/DisplayEditorInstance.java
+++ b/app/display/editor/src/main/java/org/csstudio/display/builder/editor/app/DisplayEditorInstance.java
@@ -16,7 +16,11 @@ import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
 
 import org.csstudio.display.builder.editor.DisplayEditor;
 import org.csstudio.display.builder.editor.EditorGUI;
@@ -105,7 +109,31 @@ public class DisplayEditorInstance implements AppInstance
 
         extendToolbar();
 
-        dock_item = new DockItemWithInput(this, editor_gui.getParentNode(), null, FilenameSupport.file_extensions, this::doSave);
+        dock_item = new DockItemWithInput(this, editor_gui.getParentNode(), null, FilenameSupport.file_extensions, this::doSave)
+               {
+               @Override
+               public Future<Boolean> okToClose()
+               {
+                       FutureTask<Boolean> clear_selection = new FutureTask<>(() ->
+                       {
+                       System.out.println("OK TO CLOSE?>>>");
+                       editor_gui.getDisplayEditor().getWidgetSelectionHandler().clear();   
+                       return Boolean.TRUE;
+                       });
+                       Platform.runLater(clear_selection);
+                       
+                       try
+                       {
+                                       clear_selection.get();
+                               }
+                       catch (Exception ex)
+                       {
+                               // Ignore
+                               }
+                       
+                       return super.okToClose();
+               }
+               };
         dock_pane.addTab(dock_item);
 
         // Update tab's title when model has been loaded
@@ -474,22 +502,6 @@ public class DisplayEditorInstance implements AppInstance
         }
     }
 
-    private Future<Boolean> okToClose()
-    {
-        if (save_job != null)
-        {
-            final Alert prompt = new Alert(AlertType.CONFIRMATION);
-            prompt.setTitle(Messages.FileChangedHdr);
-            prompt.setResizable(true);
-            prompt.setHeaderText(Messages.AbortSave);
-            DialogHelper.positionDialog(prompt, dock_item.getTabPane(), -200, -200);
-            if (prompt.showAndWait().orElse(ButtonType.CANCEL) != ButtonType.OK)
-                return CompletableFuture.completedFuture(false);
-        }
-
-        return CompletableFuture.completedFuture(true);
-    }
-
     private void dispose()
     {
         dock_item.setInput(null);

@georgweiss
Copy link
Collaborator

georgweiss commented Sep 12, 2024

Yes, the solution is to confirm dialog using keyboard.

@kasemir
Copy link
Collaborator Author

kasemir commented Sep 30, 2024

Drag-n-drop of "PV" from OPI to Data Browser displays same issue.

Also happens with dragging a PV from the data browser's archive search panel into the data browser plot.

@kasemir kasemir changed the title Drag/drop in display editor results in dead mouse on Linux Drag/drop in data browser or display editor results in dead mouse on Linux Oct 4, 2024
@georgweiss
Copy link
Collaborator

Since my users keep reporting on this: tried JavaFX 23 (Java 21) and 24-ea (Java 23) on Ubuntu under xfce. No change :-(

@georgweiss
Copy link
Collaborator

Revisited this and found something possibly related: https://askubuntu.com/questions/934910/mouse-cursor-gets-stuck-in-drag-and-drop-mode/990649#990649. In particular, if a close dialog (as described in the beginning of this thread) is cancelled with ESC key and then relaunched on new close action, the mouse will work.

Modified the DragDropDemo (originally modified from an example from Oracle?) to launch a dialog on close request: same issue, i.e. seems unrelated to Phoebus in general.

Also put together a Swing-based demo of similar type, but issue not reproduced.

Looks like a JavaFX/Linux thing. Will consider creating a ticket on OpenJFX.

@georgweiss
Copy link
Collaborator

georgweiss commented Dec 5, 2024

Just discovered that if a dialog is initialized with Modality.NONE or Modality.WINDOW_MODAL, mouse events work as expected.

Also narrowed this down a bit: issue introduced between OpenJFX 17.0.9 (mouse events work) and 17.0.10 (mouse events blocked).

@georgweiss
Copy link
Collaborator

@abrahamwolk has performed additional testing. Possible culprit:
openjdk/jfx17u@d6b9c7a

Another workaround (with side effects)
-Dsun.awt.disablegrab=true

@georgweiss
Copy link
Collaborator

Seems reporting bug is... buggy:

Screenshot 2024-12-06 at 14 36 32

@georgweiss
Copy link
Collaborator

georgweiss commented Dec 30, 2024

For the sake of traceability and reproducibility, here is the content of the bug report I am unable to submit:

Oracle Java Bug Database

Search

Oracle Technology Network Java Java SE Community Report a Bug

Report Classification

  • Required

      * Issue Type	 Bug      Request for Enhancement      
    
    
    
       	 
       * Component 	
    

JavaFX
Subcomponent
controls#JavaFX Controls

  • Operating System
    Linux
  • Release

17 update releases

Previously worked in the Release
16 update releases
Frequency
Always

Report Details

  • Required
  • Synopsis
    Drag-n-drop gesture may block subsequent mouse events

System / OS / Java Runtime Information
Verified on Ubuntu 20.04, xfce and Gnome. Not seen in Windows and Mac OS.
Issue first identified in JavaFX 17.0.10, not reproducible in 17.0.9. Potential culprit commit: openjdk/jfx17u@d6b9c7a

Subsequent updates still problematic, verified in all major releases up to and including 24EA.

To be noted: if the added Alert dialog is initialized with Modality.NONE or Modality.WINDOW_MODAL, the issue is not reproduced.

Confidential Field (hs_err file)
This field is dedicated to Confidential Data. Please paste the contents of the hs_err file here.

Reproducing the Issue
Steps to Reproduce

  1. Launch sample code as attached.
  2. Perform drag-n-drop gesture.
  3. Close window to trigger close event, which launches modal Alert.
  4. Attempt interaction with Alert.

Expected Result
Alert should handle mouse events.

Actual Result
Alert seems to not receive mouse events. Keyboard input works.

Source code for an executable test case
package hellodraganddrop;

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.*;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Stage;

/**

  • Demonstrates a drag-and-drop feature.
    */
    public class HelloDragAndDrop extends Application {

    @OverRide public void start(Stage stage) {
    stage.setTitle("Hello Drag And Drop");

     Group root = new Group();
     Scene scene = new Scene(root, 400, 200);
     scene.setFill(Color.LIGHTGREEN);
    
     final Text source = new Text(50, 100, "DRAG ME");
     source.setScaleX(2.0);
     source.setScaleY(2.0);
    
     final Text target = new Text(250, 100, "DROP HERE");
     target.setScaleX(2.0);
     target.setScaleY(2.0);
    
     source.setOnDragDetected(new EventHandler <MouseEvent>() {
         public void handle(MouseEvent event) {
             /* drag was detected, start drag-and-drop gesture*/
             System.out.println("onDragDetected");
             
             /* allow any transfer mode */
             Dragboard db = source.startDragAndDrop(TransferMode.ANY);
             
             /* put a string on dragboard */
             ClipboardContent content = new ClipboardContent();
             content.putString(source.getText());
             db.setContent(content);
             
             event.consume();
         }
     });
    
     target.setOnDragOver(new EventHandler <DragEvent>() {
         public void handle(DragEvent event) {
             /* data is dragged over the target */
             System.out.println("onDragOver");
             
             /* accept it only if it is  not dragged from the same node 
              * and if it has a string data */
             if (event.getGestureSource() != target &&
                     event.getDragboard().hasString()) {
                 /* allow for both copying and moving, whatever user chooses */
                 event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
             }
             
             event.consume();
         }
     });
    
     target.setOnDragEntered(new EventHandler <DragEvent>() {
         public void handle(DragEvent event) {
             /* the drag-and-drop gesture entered the target */
             System.out.println("onDragEntered");
             /* show to the user that it is an actual gesture target */
             if (event.getGestureSource() != target &&
                     event.getDragboard().hasString()) {
                 target.setFill(Color.GREEN);
             }
             
             event.consume();
         }
     });
    
     target.setOnDragExited(new EventHandler <DragEvent>() {
         public void handle(DragEvent event) {
             /* mouse moved away, remove the graphical cues */
             target.setFill(Color.BLACK);
             
             event.consume();
         }
     });
     
     target.setOnDragDropped(new EventHandler <DragEvent>() {
         public void handle(DragEvent event) {
             /* data dropped */
             System.out.println("onDragDropped");
             /* if there is a string data on dragboard, read it and use it */
             Dragboard db = event.getDragboard();
             boolean success = false;
             if (db.hasString()) {
                 target.setText(db.getString());
                 success = true;
             }
             /* let the source know whether the string was successfully 
              * transferred and used */
             event.setDropCompleted(success);
             
             event.consume();
         }
     });
    
     source.setOnDragDone(new EventHandler <DragEvent>() {
         public void handle(DragEvent event) {
             /* the drag-and-drop gesture ended */
             System.out.println("onDragDone");
             /* if the data was successfully moved, clear it */
             if (event.getTransferMode() == TransferMode.MOVE) {
                 source.setText("");
             }
             
             event.consume();
         }
     });
    
     root.getChildren().add(source);
     root.getChildren().add(target);
     stage.setScene(scene);
    
    // Addition to demonstrate issue
    

    stage.setOnCloseRequest(e -> new Alert(Alert.AlertType.CONFIRMATION).showAndWait());

     stage.show();
    

    }

    public static void main(String[] args) {
    Application.launch(args);
    }
    }

Workaround
Use keyboard, e.g. ESC to dismiss Alert.

Please ensure that you do not include any personal information outside of the “Submitter Information” section of the bug report. For example, ensure that your username is not part of the paths that might be included in the bug description or in the instructions on how to reproduce the bug.
I understand that the information provided in the above fields may be publicly visible through https://bugs.openjdk.org and https://bugs.java.com

Submitter Information

Oracle respects your desire for privacy. The information from the Submitter Information section of the bug report will not be sold, given, or shared with organizations external to Oracle. Oracle will use data from that section for communications with you to clarify issues regarding the report and/or to provide you with status updates

The information from other sections on the submission form may be made publicly available.

If you are not comfortable with the above conditions, please do not press the Submit button. If you have any questions, please refer to our Privacy Policy.

  • Please enter the text in the box :

Subscribe About Oracle Careers Contact Us Site Maps Legal Notices Terms of Use Your Privacy Rights Cookiepreferenser
Facebook Linked In Twitter Google+ YouTube RSS Feeds

@georgweiss
Copy link
Collaborator

Finally managed - assisted by Oracle - to get a bug report in place:
https://bugs.openjdk.org/browse/JDK-8346932

@kasemir
Copy link
Collaborator Author

kasemir commented Jan 2, 2025

Good start into the new year!

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

3 participants