Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,36 @@ public Color getDescriptionWindowColor() {
}


/**
* Returns the description window, if it has been created.
*
* @return The description window, or {@code null} if it has not been
* created yet.
*/
AutoCompleteDescWindow getDescWindow() {
return descWindow;
}


/**
* Disposes of the description window, if it has been created, and
* discards our reference to it so it is lazily recreated the next time
* it's needed. Simply hiding the description window is not enough here;
* on some Linux/X11 window managers, quickly toggling a {@code JWindow}
* visible and then invisible can leave a blank "ghost" window on screen
* that never gets un-mapped or repainted. Disposing of the native peer
* avoids that.
*
* @see AutoCompletion#setShowDescWindow(boolean)
*/
void disposeDescWindow() {
if (descWindow != null) {
descWindow.dispose();
descWindow = null;
}
}


/**
* Returns the default list cell renderer used when a completion provider
* does not supply its own.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,11 @@ public boolean isPopupVisible() {
return popupWindow != null && popupWindow.isVisible();
}

// Returns the completion popup window, or null if not created yet.
AutoCompletePopupWindow getPopupWindow() {
return popupWindow;
}


/**
* Refreshes the popup window. First, this method gets the possible
Expand Down Expand Up @@ -1151,6 +1156,11 @@ protected void setPopupVisible(boolean visible) {
*/
public void setShowDescWindow(boolean show) {
hidePopupWindow(); // Needed to force it to take effect
if (!show && popupWindow != null) {
// Dispose (rather than hide) the desc window on toggle-off, to avoid a
// Linux/X11 "ghost" window bug when hiding it instead; see issue #84.
popupWindow.disposeDescWindow();
}
showDescWindow = show;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* This library is distributed under a modified BSD license. See the included
* LICENSE.md file for details.
*/
package org.fife.ui.autocomplete;

import java.awt.GraphicsEnvironment;
import javax.swing.JFrame;
import javax.swing.JTextArea;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;


class AutoCompletionTest {

private JFrame frame;


@BeforeEach
void setUp() {
Assumptions.assumeFalse(GraphicsEnvironment.isHeadless());
}


@AfterEach
void tearDown() {
if (frame != null) {
frame.dispose();
frame = null;
}
}


/**
* Regression test for https://github.com/bobbylight/AutoComplete/issues/84 -
* merely hiding the description window when it's toggled off could leave
* a blank "ghost" window on screen on some Linux/X11 window managers.
* The fix disposes of the description window's native peer instead of
* just hiding it, so it must be lazily recreated the next time it's
* shown.
*/
@Test
void setShowDescWindow_false_disposesExistingDescWindow() {

DefaultCompletionProvider provider = new DefaultCompletionProvider();
provider.addCompletion(new BasicCompletion(provider, "foo", "foo's summary"));
provider.addCompletion(new BasicCompletion(provider, "foobar", "foobar's summary"));

AutoCompletion ac = new AutoCompletion(provider);
ac.setShowDescWindow(true);
ac.setAutoCompleteEnabled(true);

JTextArea textArea = new JTextArea();
ac.install(textArea);

frame = new JFrame();
frame.add(textArea);
frame.pack();
frame.setVisible(true);

textArea.setText("foo");
textArea.setCaretPosition(textArea.getText().length());
ac.doCompletion();

AutoCompletePopupWindow popupWindow = ac.getPopupWindow();
Assertions.assertNotNull(popupWindow,
"Popup window should have been created by doCompletion()");
AutoCompleteDescWindow descWindow = popupWindow.getDescWindow();
Assertions.assertNotNull(descWindow,
"Description window should have been created since showDescWindow was true");
Assertions.assertTrue(descWindow.isDisplayable(),
"Description window's native peer should exist while showing");

ac.setShowDescWindow(false);

Assertions.assertNull(popupWindow.getDescWindow(),
"Description window should be disposed and discarded, not just hidden");
Assertions.assertFalse(descWindow.isDisplayable(),
"Description window's native peer should be destroyed by dispose()");

}


}
Loading