|
25 | 25 | import java.util.function.*;
|
26 | 26 |
|
27 | 27 | import org.eclipse.swt.*;
|
| 28 | +import org.eclipse.swt.events.*; |
28 | 29 | import org.eclipse.swt.graphics.*;
|
29 | 30 | import org.eclipse.swt.internal.*;
|
30 | 31 | import org.eclipse.swt.internal.gtk.*;
|
@@ -96,6 +97,11 @@ class WebKit extends WebBrowser {
|
96 | 97 | URI tlsErrorUri;
|
97 | 98 | String tlsErrorType;
|
98 | 99 |
|
| 100 | + private final ControlListener browserMoveListener = ControlListener.controlMovedAdapter(this::browserShellMoved); |
| 101 | + private Point searchShellLocation; |
| 102 | + private Shell searchShell; |
| 103 | + private String searchText; |
| 104 | + |
99 | 105 | boolean firstLoad = true;
|
100 | 106 | static boolean FirstCreate = true;
|
101 | 107 |
|
@@ -201,6 +207,9 @@ class WebKit extends WebBrowser {
|
201 | 207 | /** Flag indicating whether TLS errors (like self-signed certificates) are to be ignored. */
|
202 | 208 | static final boolean ignoreTls;
|
203 | 209 |
|
| 210 | + /** Flag that disables browser searching added on top of the WebKit browser. */ |
| 211 | + static final boolean disableBrowserSearch; |
| 212 | + |
204 | 213 | static {
|
205 | 214 | Proc2 = new Callback (WebKit.class, "Proc", 2); //$NON-NLS-1$
|
206 | 215 | Proc3 = new Callback (WebKit.class, "Proc", 3); //$NON-NLS-1$
|
@@ -248,6 +257,7 @@ class WebKit extends WebBrowser {
|
248 | 257 | NativePendingCookies = null;
|
249 | 258 | }
|
250 | 259 | ignoreTls = "true".equals(System.getProperty("org.eclipse.swt.internal.webkitgtk.ignoretlserrors"));
|
| 260 | + disableBrowserSearch = "true".equals(System.getProperty("org.eclipse.swt.internal.webkitgtk.disableBrowserSearch")); |
251 | 261 | }
|
252 | 262 |
|
253 | 263 | @Override
|
@@ -784,13 +794,24 @@ public void create (Composite parent, int style) {
|
784 | 794 | onResize (event);
|
785 | 795 | break;
|
786 | 796 | }
|
| 797 | + case SWT.KeyDown: { |
| 798 | + if (!disableBrowserSearch && event.keyCode == 'f' && (event.stateMask & SWT.CTRL) == SWT.CTRL) { |
| 799 | + openSearchDialog(); |
| 800 | + } |
| 801 | + break; |
| 802 | + } |
787 | 803 | }
|
788 | 804 | };
|
789 | 805 | browser.addListener (SWT.Dispose, listener);
|
790 | 806 | browser.addListener (SWT.FocusIn, listener);
|
791 | 807 | browser.addListener (SWT.KeyDown, listener);
|
792 | 808 | browser.addListener (SWT.Resize, listener);
|
793 | 809 |
|
| 810 | + browser.addDisposeListener(e -> closeSearchDialog()); |
| 811 | + browser.addControlListener(ControlListener.controlResizedAdapter(this::browserShellMoved)); |
| 812 | + browser.addControlListener(ControlListener.controlMovedAdapter(this::browserShellMoved)); |
| 813 | + browser.getShell().addControlListener(browserMoveListener); |
| 814 | + |
794 | 815 | /*
|
795 | 816 | * Bug in WebKitGTK. MouseOver/MouseLeave events are not consistently sent from
|
796 | 817 | * the DOM when the mouse enters and exits the browser control, see
|
@@ -835,6 +856,9 @@ public boolean close () {
|
835 | 856 | // false = blocks disposal. In Browser.java, user is told widget was not disposed.
|
836 | 857 | // See Snippet326.
|
837 | 858 | boolean close (boolean showPrompters) {
|
| 859 | + if (browser != null && !browser.isDisposed()) { |
| 860 | + browser.getShell().removeControlListener(browserMoveListener); |
| 861 | + } |
838 | 862 | // don't execute any JavaScript if it's disabled or requested to get disabled
|
839 | 863 | // we need to check jsEnabledOnNextPage here because jsEnabled is updated asynchronously
|
840 | 864 | // and may not reflect the proper state (bug 571746 and bug 567881)
|
@@ -2665,6 +2689,115 @@ private void webkit_settings_set(byte [] property, int value) {
|
2665 | 2689 | OS.g_object_set(settings, property, value, 0);
|
2666 | 2690 | }
|
2667 | 2691 |
|
| 2692 | +private void browserShellMoved(ControlEvent e) { |
| 2693 | + closeSearchDialog(); |
| 2694 | + searchShellLocation = null; |
| 2695 | +} |
| 2696 | + |
| 2697 | +private void closeSearchDialog() { |
| 2698 | + if (searchShell != null && !searchShell.isDisposed()) { |
| 2699 | + searchShellLocation = searchShell.getLocation(); |
| 2700 | + searchShell.close(); |
| 2701 | + if (searchText != null && webView != 0) { |
| 2702 | + long findController = WebKitGTK.webkit_web_view_get_find_controller(webView); |
| 2703 | + WebKitGTK.webkit_find_controller_search_finish(findController); |
| 2704 | + } |
| 2705 | + searchText = null; |
| 2706 | + } |
| 2707 | +} |
| 2708 | + |
| 2709 | +private void openSearchDialog() { |
| 2710 | + if (webView == 0 || (searchShell != null && !searchShell.isDisposed())) { |
| 2711 | + return; |
| 2712 | + } |
| 2713 | + Shell browserShell = browser.getShell(); |
| 2714 | + if (browserShell == null || browserShell.isDisposed() || (browserShell.getStyle() & SWT.TOOL) == SWT.TOOL) { |
| 2715 | + /* |
| 2716 | + * We don't provide search capabilities for browsers in a pop-up. |
| 2717 | + * We could cause issues with pop-up focus handling when the search shell is opened. |
| 2718 | + */ |
| 2719 | + return; |
| 2720 | + } |
| 2721 | + Shell shell = new Shell(browserShell, SWT.TOOL | SWT.MODELESS); |
| 2722 | + Rectangle browserArea = browser.getClientArea(); |
| 2723 | + int height = 45; |
| 2724 | + Point location; |
| 2725 | + if (searchShellLocation != null) { |
| 2726 | + location = searchShellLocation; |
| 2727 | + } else { |
| 2728 | + location = browser.toDisplay(0, 0); |
| 2729 | + location.y += Math.max(0, browserArea.height - height); |
| 2730 | + } |
| 2731 | + shell.setLocation(location); |
| 2732 | + shell.setSize(250, height); |
| 2733 | + GridLayout l = new GridLayout(); |
| 2734 | + l.marginWidth = 8; |
| 2735 | + l.marginHeight = 8; |
| 2736 | + l.numColumns = 4; |
| 2737 | + shell.setLayout(l); |
| 2738 | + Text text = new Text(shell, SWT.BORDER); |
| 2739 | + text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); |
| 2740 | + Cursor defaultCursor = Display.getCurrent().getSystemCursor(SWT.CURSOR_ARROW); |
| 2741 | + Button next = new Button(shell, SWT.FLAT | SWT.ARROW | SWT.DOWN); |
| 2742 | + next.setCursor(defaultCursor); |
| 2743 | + Button previous = new Button(shell, SWT.FLAT | SWT.ARROW | SWT.UP); |
| 2744 | + previous.setCursor(defaultCursor); |
| 2745 | + shell.setCursor(Display.getCurrent().getSystemCursor(SWT.CURSOR_SIZEALL)); |
| 2746 | + boolean[] mouseDown = new boolean[1]; |
| 2747 | + int[] xPos = new int[1]; |
| 2748 | + int[] yPos = new int[1]; |
| 2749 | + shell.addMouseListener(new MouseAdapter() { |
| 2750 | + @Override |
| 2751 | + public void mouseUp(MouseEvent arg0) { |
| 2752 | + mouseDown[0] = false; |
| 2753 | + } |
| 2754 | + @Override |
| 2755 | + public void mouseDown(MouseEvent e) { |
| 2756 | + mouseDown[0] = true; |
| 2757 | + xPos[0] = e.x; |
| 2758 | + yPos[0] = e.y; |
| 2759 | + } |
| 2760 | + }); |
| 2761 | + shell.addMouseMoveListener(e -> { |
| 2762 | + if (mouseDown[0]) { |
| 2763 | + shell.setLocation(shell.getLocation().x + (e.x - xPos[0]), shell.getLocation().y + (e.y - yPos[0])); |
| 2764 | + } |
| 2765 | + }); |
| 2766 | + long findController = WebKitGTK.webkit_web_view_get_find_controller(webView); |
| 2767 | + Runnable searchNext = () -> search(findController, text::getText, WebKitGTK::webkit_find_controller_search_next); |
| 2768 | + Runnable searchPrevious = () -> search(findController, text::getText, WebKitGTK::webkit_find_controller_search_previous); |
| 2769 | + next.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> searchNext.run())); |
| 2770 | + previous.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> searchPrevious.run())); |
| 2771 | + text.addKeyListener(KeyListener.keyPressedAdapter(e -> { |
| 2772 | + if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) { |
| 2773 | + searchNext.run(); |
| 2774 | + } |
| 2775 | + })); |
| 2776 | + shell.addDisposeListener(e -> { |
| 2777 | + searchShellLocation = searchShell.getLocation(); |
| 2778 | + WebKitGTK.webkit_find_controller_search_finish(findController); |
| 2779 | + searchShell = null; |
| 2780 | + }); |
| 2781 | + shell.open(); |
| 2782 | + searchShell = shell; |
| 2783 | +} |
| 2784 | + |
| 2785 | +private void search(long findController, Supplier<String> currentText, Consumer<Long> incrementSearch) { |
| 2786 | + int maxMatchesCount = WebKitGTK.G_MAXUINT; // TODO: how to set no max count here? |
| 2787 | + int searchOptions = WebKitGTK.WEBKIT_FIND_OPTIONS_WRAP_AROUND; |
| 2788 | + String text = currentText.get(); |
| 2789 | + if (!text.equals(searchText)) { |
| 2790 | + if (searchText != null) { |
| 2791 | + WebKitGTK.webkit_find_controller_search_finish(findController); |
| 2792 | + } |
| 2793 | + searchText = text; |
| 2794 | + byte[] textToSearch = Converter.wcsToMbcs(searchText, true); |
| 2795 | + WebKitGTK.webkit_find_controller_search(findController, textToSearch, searchOptions, maxMatchesCount); |
| 2796 | + } else { |
| 2797 | + incrementSearch.accept(Long.valueOf(findController)); |
| 2798 | + } |
| 2799 | +} |
| 2800 | + |
2668 | 2801 | static Object convertToJava (long ctx, long value) {
|
2669 | 2802 | int type = WebKitGTK.JSValueGetType (ctx, value);
|
2670 | 2803 | switch (type) {
|
|
0 commit comments