Skip to content

Commit a9eda46

Browse files
trancexpressiloveeclipse
authored andcommitted
Add search capabilities to WebKit based Browser
This changes adds a search dialog to WebKit browsers. The search dialog is opened with Ctrl+F and has next/previous word matching capabilities. The search dialog is not available for Browsers in a Shell with the SWT.TOOL style. The search capabilities can be disabled with the following system property: -Dorg.eclipse.swt.internal.webkitgtk.disableBrowserSearch=true Fixes: #2222
1 parent de1f3ef commit a9eda46

File tree

2 files changed

+151
-0
lines changed

2 files changed

+151
-0
lines changed

bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebKit.java

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.function.*;
2626

2727
import org.eclipse.swt.*;
28+
import org.eclipse.swt.events.*;
2829
import org.eclipse.swt.graphics.*;
2930
import org.eclipse.swt.internal.*;
3031
import org.eclipse.swt.internal.gtk.*;
@@ -96,6 +97,13 @@ class WebKit extends WebBrowser {
9697
URI tlsErrorUri;
9798
String tlsErrorType;
9899

100+
private final ControlListener browserMoveListener = ControlListener.controlMovedAdapter(this::browserShellMoved);
101+
private Point searchShellLocation;
102+
private Shell searchShell;
103+
private String searchText;
104+
private Cursor searchCursor;
105+
private long searchCursorHandle;
106+
99107
boolean firstLoad = true;
100108
static boolean FirstCreate = true;
101109

@@ -201,6 +209,9 @@ class WebKit extends WebBrowser {
201209
/** Flag indicating whether TLS errors (like self-signed certificates) are to be ignored. */
202210
static final boolean ignoreTls;
203211

212+
/** Flag that disables browser searching added on top of the WebKit browser. */
213+
static final boolean disableBrowserSearch;
214+
204215
static {
205216
Proc2 = new Callback (WebKit.class, "Proc", 2); //$NON-NLS-1$
206217
Proc3 = new Callback (WebKit.class, "Proc", 3); //$NON-NLS-1$
@@ -248,6 +259,7 @@ class WebKit extends WebBrowser {
248259
NativePendingCookies = null;
249260
}
250261
ignoreTls = "true".equals(System.getProperty("org.eclipse.swt.internal.webkitgtk.ignoretlserrors"));
262+
disableBrowserSearch = "true".equals(System.getProperty("org.eclipse.swt.internal.webkitgtk.disableBrowserSearch"));
251263
}
252264

253265
@Override
@@ -784,13 +796,33 @@ public void create (Composite parent, int style) {
784796
onResize (event);
785797
break;
786798
}
799+
case SWT.KeyDown: {
800+
if (!disableBrowserSearch && event.keyCode == 'f' && (event.stateMask & SWT.CTRL) == SWT.CTRL) {
801+
openSearchDialog();
802+
}
803+
break;
804+
}
787805
}
788806
};
789807
browser.addListener (SWT.Dispose, listener);
790808
browser.addListener (SWT.FocusIn, listener);
791809
browser.addListener (SWT.KeyDown, listener);
792810
browser.addListener (SWT.Resize, listener);
793811

812+
browser.addDisposeListener(e -> {
813+
closeSearchDialog();
814+
if (searchCursor != null && !searchCursor.isDisposed()) {
815+
searchCursor.dispose();
816+
}
817+
if (searchCursorHandle != 0) {
818+
OS.g_object_unref(searchCursorHandle);
819+
searchCursorHandle = 0;
820+
}
821+
});
822+
browser.addControlListener(ControlListener.controlResizedAdapter(this::browserShellMoved));
823+
browser.addControlListener(ControlListener.controlMovedAdapter(this::browserShellMoved));
824+
browser.getShell().addControlListener(browserMoveListener);
825+
794826
/*
795827
* Bug in WebKitGTK. MouseOver/MouseLeave events are not consistently sent from
796828
* the DOM when the mouse enters and exits the browser control, see
@@ -835,6 +867,9 @@ public boolean close () {
835867
// false = blocks disposal. In Browser.java, user is told widget was not disposed.
836868
// See Snippet326.
837869
boolean close (boolean showPrompters) {
870+
if (browser != null && !browser.isDisposed()) {
871+
browser.getShell().removeControlListener(browserMoveListener);
872+
}
838873
// don't execute any JavaScript if it's disabled or requested to get disabled
839874
// we need to check jsEnabledOnNextPage here because jsEnabled is updated asynchronously
840875
// and may not reflect the proper state (bug 571746 and bug 567881)
@@ -2665,6 +2700,119 @@ private void webkit_settings_set(byte [] property, int value) {
26652700
OS.g_object_set(settings, property, value, 0);
26662701
}
26672702

2703+
private void browserShellMoved(ControlEvent e) {
2704+
closeSearchDialog();
2705+
searchShellLocation = null;
2706+
}
2707+
2708+
private void closeSearchDialog() {
2709+
if (searchShell != null && !searchShell.isDisposed()) {
2710+
searchShellLocation = searchShell.getLocation();
2711+
searchShell.close();
2712+
if (searchText != null && webView != 0) {
2713+
long findController = WebKitGTK.webkit_web_view_get_find_controller(webView);
2714+
WebKitGTK.webkit_find_controller_search_finish(findController);
2715+
}
2716+
searchText = null;
2717+
}
2718+
}
2719+
2720+
private void openSearchDialog() {
2721+
if (webView == 0 || (searchShell != null && !searchShell.isDisposed())) {
2722+
return;
2723+
}
2724+
Shell browserShell = browser.getShell();
2725+
if (browserShell == null || browserShell.isDisposed() || (browserShell.getStyle() & SWT.TOOL) == SWT.TOOL) {
2726+
/*
2727+
* We don't provide search capabilities for browsers in a pop-up.
2728+
* We could cause issues with pop-up focus handling when the search shell is opened.
2729+
*/
2730+
return;
2731+
}
2732+
if (searchCursorHandle == 0) {
2733+
searchCursorHandle = GDK.gdk_cursor_new_from_name(GDK.gdk_display_get_default(), "fleur");
2734+
searchCursor = Cursor.gtk_new(Display.getCurrent(), searchCursorHandle);
2735+
}
2736+
Shell shell = new Shell(browserShell, SWT.TOOL | SWT.MODELESS);
2737+
Rectangle browserArea = browser.getClientArea();
2738+
int height = 45;
2739+
Point location;
2740+
if (searchShellLocation != null) {
2741+
location = searchShellLocation;
2742+
} else {
2743+
location = browser.toDisplay(0, 0);
2744+
location.y += Math.max(0, browserArea.height - height);
2745+
}
2746+
shell.setLocation(location);
2747+
shell.setSize(250, height);
2748+
GridLayout l = new GridLayout();
2749+
l.marginWidth = 8;
2750+
l.marginHeight = 8;
2751+
l.numColumns = 4;
2752+
shell.setLayout(l);
2753+
Text text = new Text(shell, SWT.BORDER);
2754+
text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
2755+
Cursor defaultCursor = Display.getCurrent().getSystemCursor(SWT.CURSOR_ARROW);
2756+
Button next = new Button(shell, SWT.FLAT | SWT.ARROW | SWT.DOWN);
2757+
next.setCursor(defaultCursor);
2758+
Button previous = new Button(shell, SWT.FLAT | SWT.ARROW | SWT.UP);
2759+
previous.setCursor(defaultCursor);
2760+
shell.setCursor(searchCursor);
2761+
boolean[] mouseDown = new boolean[1];
2762+
int[] xPos = new int[1];
2763+
int[] yPos = new int[1];
2764+
shell.addMouseListener(new MouseAdapter() {
2765+
@Override
2766+
public void mouseUp(MouseEvent arg0) {
2767+
mouseDown[0] = false;
2768+
}
2769+
@Override
2770+
public void mouseDown(MouseEvent e) {
2771+
mouseDown[0] = true;
2772+
xPos[0] = e.x;
2773+
yPos[0] = e.y;
2774+
}
2775+
});
2776+
shell.addMouseMoveListener(e -> {
2777+
if (mouseDown[0]) {
2778+
shell.setLocation(shell.getLocation().x + (e.x - xPos[0]), shell.getLocation().y + (e.y - yPos[0]));
2779+
}
2780+
});
2781+
long findController = WebKitGTK.webkit_web_view_get_find_controller(webView);
2782+
Runnable searchNext = () -> search(findController, text::getText, WebKitGTK::webkit_find_controller_search_next);
2783+
Runnable searchPrevious = () -> search(findController, text::getText, WebKitGTK::webkit_find_controller_search_previous);
2784+
next.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> searchNext.run()));
2785+
previous.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> searchPrevious.run()));
2786+
text.addKeyListener(KeyListener.keyPressedAdapter(e -> {
2787+
if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
2788+
searchNext.run();
2789+
}
2790+
}));
2791+
shell.addDisposeListener(e -> {
2792+
searchShellLocation = searchShell.getLocation();
2793+
WebKitGTK.webkit_find_controller_search_finish(findController);
2794+
searchShell = null;
2795+
});
2796+
shell.open();
2797+
searchShell = shell;
2798+
}
2799+
2800+
private void search(long findController, Supplier<String> currentText, Consumer<Long> incrementSearch) {
2801+
int maxMatchesCount = WebKitGTK.G_MAXUINT; // TODO: how to set no max count here?
2802+
int searchOptions = WebKitGTK.WEBKIT_FIND_OPTIONS_WRAP_AROUND;
2803+
String text = currentText.get();
2804+
if (!text.equals(searchText)) {
2805+
if (searchText != null) {
2806+
WebKitGTK.webkit_find_controller_search_finish(findController);
2807+
}
2808+
searchText = text;
2809+
byte[] textToSearch = Converter.wcsToMbcs(searchText, true);
2810+
WebKitGTK.webkit_find_controller_search(findController, textToSearch, searchOptions, maxMatchesCount);
2811+
} else {
2812+
incrementSearch.accept(Long.valueOf(findController));
2813+
}
2814+
}
2815+
26682816
static Object convertToJava (long ctx, long value) {
26692817
int type = WebKitGTK.JSValueGetType (ctx, value);
26702818
switch (type) {

bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/internal/webkit/WebKitGTK.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ public class WebKitGTK extends C {
9090
public static final int WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START = 0;
9191
public static final int WEBKIT_USER_CONTENT_INJECT_TOP_FRAME = 1;
9292

93+
public static final int G_MAXUINT = 65535;
94+
public static final int WEBKIT_FIND_OPTIONS_WRAP_AROUND = 1 << 4;
95+
9396
/** Signals */
9497

9598
// Authentication.

0 commit comments

Comments
 (0)