mirror of https://github.com/adamdruppe/arsd.git
more improvements to input handling and web
This commit is contained in:
parent
2501e6e575
commit
7d81f250fe
185
minigui.d
185
minigui.d
|
@ -1925,6 +1925,18 @@ class Widget : ReflectableProperties {
|
|||
return StyleInformation(this);
|
||||
}
|
||||
|
||||
int focusableWidgets(scope int delegate(Widget) dg) {
|
||||
foreach(widget; WidgetStream(this)) {
|
||||
if(widget.tabStop && !widget.hidden) {
|
||||
int result = dg(widget);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: I kinda want to hide events from implementation widgets
|
||||
// so it just catches them all and stops propagation...
|
||||
// i guess i can do it with a event listener on star.
|
||||
|
@ -7084,7 +7096,7 @@ class HorizontalLayout : Layout {
|
|||
|
||||
}
|
||||
|
||||
version(Windows)
|
||||
version(win32_widgets)
|
||||
private
|
||||
extern(Windows)
|
||||
LRESULT DoubleBufferWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) nothrow {
|
||||
|
@ -7944,6 +7956,12 @@ class Window : Widget {
|
|||
Window.newWindowCreated(this);
|
||||
}
|
||||
|
||||
version(custom_widgets)
|
||||
override void defaultEventHandler_click(ClickEvent event) {
|
||||
if(event.target && event.target.tabStop)
|
||||
event.target.focus();
|
||||
}
|
||||
|
||||
private static void delegate(Window) newWindowCreated;
|
||||
|
||||
version(win32_widgets)
|
||||
|
@ -8082,13 +8100,13 @@ class Window : Widget {
|
|||
}
|
||||
win = new SimpleWindow(width, height, title, OpenGlOptions.no, Resizability.allowResizing, WindowTypes.normal, WindowFlags.dontAutoShow | WindowFlags.managesChildWindowFocus);
|
||||
|
||||
/+
|
||||
///+
|
||||
// for input proxy
|
||||
auto display = XDisplayConnection.get;
|
||||
auto inputProxy = XCreateSimpleWindow(display, win.window, -1, -1, 1, 1, 0, 0, 0);
|
||||
XSelectInput(display, inputProxy, EventMask.KeyPressMask | EventMask.KeyReleaseMask);
|
||||
XMapWindow(display, inputProxy);
|
||||
import std.stdio; writefln("input proxy: 0x%0x", inputProxy);
|
||||
//import std.stdio; writefln("input proxy: 0x%0x", inputProxy);
|
||||
this.inputProxy = new SimpleWindow(inputProxy);
|
||||
|
||||
XEvent lastEvent;
|
||||
|
@ -8108,8 +8126,11 @@ class Window : Widget {
|
|||
if(auto nw = cast(NestedChildWindowWidget) focusedWidget) {
|
||||
auto thing = nw.focusableWindow();
|
||||
if(thing && thing.window) {
|
||||
import std.stdio; writeln("sending event ", lastEvent.xkey);
|
||||
XSendEvent(XDisplayConnection.get, thing.window, false, 0, &lastEvent);
|
||||
lastEvent.xkey.window = thing.window;
|
||||
// import std.stdio; writeln("sending event ", lastEvent.xkey);
|
||||
trapXErrors( {
|
||||
XSendEvent(XDisplayConnection.get, thing.window, false, 0, &lastEvent);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8121,7 +8142,7 @@ class Window : Widget {
|
|||
},
|
||||
);
|
||||
// done
|
||||
+/
|
||||
//+/
|
||||
|
||||
|
||||
|
||||
|
@ -8133,13 +8154,7 @@ class Window : Widget {
|
|||
SimpleWindow inputProxy;
|
||||
|
||||
private SimpleWindow setRequestedInputFocus() {
|
||||
// return inputProxy;
|
||||
|
||||
if(auto fw = cast(NestedChildWindowWidget) focusedWidget) {
|
||||
// sdpyPrintDebugString("heaven");
|
||||
return fw.focusableWindow;
|
||||
}
|
||||
return win;
|
||||
return inputProxy;
|
||||
}
|
||||
|
||||
/// ditto
|
||||
|
@ -8173,14 +8188,15 @@ class Window : Widget {
|
|||
event.ctrlKey = (ev.modifierState & ModifierState.ctrl) ? true : false;
|
||||
event.dispatch();
|
||||
|
||||
return !event.defaultPrevented;
|
||||
return !event.propagationStopped;
|
||||
}
|
||||
|
||||
// returns true if propagation should continue into nested things.... prolly not a great thing to do.
|
||||
bool dispatchCharEvent(dchar ch) {
|
||||
if(focusedWidget) {
|
||||
auto event = new CharEvent(focusedWidget, ch);
|
||||
event.dispatch();
|
||||
return !event.defaultPrevented;
|
||||
return !event.propagationStopped;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -8343,18 +8359,29 @@ class Window : Widget {
|
|||
}
|
||||
|
||||
static Widget getFirstFocusable(Widget start) {
|
||||
if(start.tabStop && !start.hidden)
|
||||
return start;
|
||||
if(start is null)
|
||||
return null;
|
||||
|
||||
if(!start.hidden)
|
||||
foreach(child; start.children) {
|
||||
auto f = getFirstFocusable(child);
|
||||
if(f !is null)
|
||||
return f;
|
||||
foreach(widget; &start.focusableWidgets) {
|
||||
return widget;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static Widget getLastFocusable(Widget start) {
|
||||
if(start is null)
|
||||
return null;
|
||||
|
||||
Widget last;
|
||||
foreach(widget; &start.focusableWidgets) {
|
||||
last = widget;
|
||||
}
|
||||
|
||||
return last;
|
||||
}
|
||||
|
||||
|
||||
mixin Emits!ClosingEvent;
|
||||
mixin Emits!ClosedEvent;
|
||||
}
|
||||
|
@ -10457,9 +10484,10 @@ class Menu : Window {
|
|||
if(!menuParent.parentWindow.win.closed) {
|
||||
if(auto maw = cast(MouseActivatedWidget) menuParent) {
|
||||
maw.setDynamicState(DynamicState.depressed, false);
|
||||
maw.setDynamicState(DynamicState.hover, false);
|
||||
maw.redraw();
|
||||
}
|
||||
menuParent.parentWindow.win.focus();
|
||||
// menuParent.parentWindow.win.focus();
|
||||
}
|
||||
clickListener.disconnect();
|
||||
}
|
||||
|
@ -14225,6 +14253,117 @@ interface ReflectableProperties {
|
|||
}
|
||||
}
|
||||
|
||||
private struct Stack(T) {
|
||||
this(int maxSize) {
|
||||
internalLength = 0;
|
||||
arr = initialBuffer[];
|
||||
}
|
||||
|
||||
///.
|
||||
void push(T t) {
|
||||
if(internalLength >= arr.length) {
|
||||
auto oldarr = arr;
|
||||
if(arr.length < 4096)
|
||||
arr = new T[arr.length * 2];
|
||||
else
|
||||
arr = new T[arr.length + 4096];
|
||||
arr[0 .. oldarr.length] = oldarr[];
|
||||
}
|
||||
|
||||
arr[internalLength] = t;
|
||||
internalLength++;
|
||||
}
|
||||
|
||||
///.
|
||||
T pop() {
|
||||
assert(internalLength);
|
||||
internalLength--;
|
||||
return arr[internalLength];
|
||||
}
|
||||
|
||||
///.
|
||||
T peek() {
|
||||
assert(internalLength);
|
||||
return arr[internalLength - 1];
|
||||
}
|
||||
|
||||
///.
|
||||
@property bool empty() {
|
||||
return internalLength ? false : true;
|
||||
}
|
||||
|
||||
///.
|
||||
private T[] arr;
|
||||
private size_t internalLength;
|
||||
private T[64] initialBuffer;
|
||||
// the static array is allocated with this object, so if we have a small stack (which we prolly do; dom trees usually aren't insanely deep),
|
||||
// using this saves us a bunch of trips to the GC. In my last profiling, I got about a 50x improvement in the push()
|
||||
// function thanks to this, and push() was actually one of the slowest individual functions in the code!
|
||||
}
|
||||
|
||||
/// This is the lazy range that walks the tree for you. It tries to go in the lexical order of the source: node, then children from first to last, each recursively.
|
||||
private struct WidgetStream {
|
||||
|
||||
///.
|
||||
@property Widget front() {
|
||||
return current.widget;
|
||||
}
|
||||
|
||||
/// Use Widget.tree instead.
|
||||
this(Widget start) {
|
||||
current.widget = start;
|
||||
current.childPosition = -1;
|
||||
isEmpty = false;
|
||||
stack = typeof(stack)(0);
|
||||
}
|
||||
|
||||
/*
|
||||
Handle it
|
||||
handle its children
|
||||
|
||||
*/
|
||||
|
||||
///.
|
||||
void popFront() {
|
||||
more:
|
||||
if(isEmpty) return;
|
||||
|
||||
// FIXME: the profiler says this function is somewhat slow (noticeable because it can be called a lot of times)
|
||||
|
||||
current.childPosition++;
|
||||
if(current.childPosition >= current.widget.children.length) {
|
||||
if(stack.empty())
|
||||
isEmpty = true;
|
||||
else {
|
||||
current = stack.pop();
|
||||
goto more;
|
||||
}
|
||||
} else {
|
||||
stack.push(current);
|
||||
current.widget = current.widget.children[current.childPosition];
|
||||
current.childPosition = -1;
|
||||
}
|
||||
}
|
||||
|
||||
///.
|
||||
@property bool empty() {
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct Current {
|
||||
Widget widget;
|
||||
int childPosition;
|
||||
}
|
||||
|
||||
Current current;
|
||||
|
||||
Stack!(Current) stack;
|
||||
|
||||
bool isEmpty;
|
||||
}
|
||||
|
||||
|
||||
/+
|
||||
|
||||
|
|
|
@ -360,7 +360,7 @@ class WebViewWidget_CEF : WebViewWidgetBase {
|
|||
//semaphore = new Semaphore;
|
||||
assert(CefApp.active);
|
||||
|
||||
this(new MiniguiCefClient(openNewWindow), parent);
|
||||
this(new MiniguiCefClient(openNewWindow), parent, false);
|
||||
|
||||
cef_window_info_t window_info;
|
||||
window_info.parent_window = containerWindow.nativeWindowHandle;
|
||||
|
@ -398,7 +398,7 @@ class WebViewWidget_CEF : WebViewWidgetBase {
|
|||
.destroy(this); // but this is ok to do some memory management cleanup
|
||||
}
|
||||
|
||||
private this(MiniguiCefClient client, Widget parent) {
|
||||
private this(MiniguiCefClient client, Widget parent, bool isDevTools) {
|
||||
super(parent);
|
||||
|
||||
this.client = client;
|
||||
|
@ -407,22 +407,56 @@ class WebViewWidget_CEF : WebViewWidgetBase {
|
|||
|
||||
mapping[containerWindow.nativeWindowHandle()] = this;
|
||||
|
||||
|
||||
this.parentWindow.addEventListener((FocusEvent fe) {
|
||||
if(!browserHandle) return;
|
||||
//browserHandle.get_host.set_focus(true);
|
||||
|
||||
executeJavascript("if(window.__arsdPreviouslyFocusedNode) window.__arsdPreviouslyFocusedNode.focus(); window.dispatchEvent(new FocusEvent(\"focus\"));");
|
||||
this.addEventListener(delegate(KeyDownEvent ke) {
|
||||
if(ke.key == Key.Tab)
|
||||
ke.preventDefault();
|
||||
});
|
||||
this.parentWindow.addEventListener((BlurEvent be) {
|
||||
|
||||
this.addEventListener((FocusEvent fe) {
|
||||
if(!browserHandle) return;
|
||||
|
||||
executeJavascript("if(document.activeElement) { window.__arsdPreviouslyFocusedNode = document.activeElement; document.activeElement.blur(); } window.dispatchEvent(new FocusEvent(\"blur\"));");
|
||||
XFocusChangeEvent ev;
|
||||
ev.type = arsd.simpledisplay.EventType.FocusIn;
|
||||
ev.display = XDisplayConnection.get;
|
||||
ev.window = ozone;
|
||||
ev.mode = NotifyModes.NotifyNormal;
|
||||
ev.detail = NotifyDetail.NotifyVirtual;
|
||||
|
||||
trapXErrors( {
|
||||
XSendEvent(XDisplayConnection.get, ozone, false, 0, cast(XEvent*) &ev);
|
||||
});
|
||||
|
||||
// this also works if the message is buggy and it avoids weirdness from raising window etc
|
||||
//executeJavascript("if(window.__arsdPreviouslyFocusedNode) window.__arsdPreviouslyFocusedNode.focus(); window.dispatchEvent(new FocusEvent(\"focus\"));");
|
||||
});
|
||||
this.addEventListener((BlurEvent be) {
|
||||
if(!browserHandle) return;
|
||||
|
||||
XFocusChangeEvent ev;
|
||||
ev.type = arsd.simpledisplay.EventType.FocusOut;
|
||||
ev.display = XDisplayConnection.get;
|
||||
ev.window = ozone;
|
||||
ev.mode = NotifyModes.NotifyNormal;
|
||||
ev.detail = NotifyDetail.NotifyNonlinearVirtual;
|
||||
|
||||
trapXErrors( {
|
||||
XSendEvent(XDisplayConnection.get, ozone, false, 0, cast(XEvent*) &ev);
|
||||
});
|
||||
|
||||
//executeJavascript("if(document.activeElement) { window.__arsdPreviouslyFocusedNode = document.activeElement; document.activeElement.blur(); } window.dispatchEvent(new FocusEvent(\"blur\"));");
|
||||
});
|
||||
|
||||
bool closeAttempted = false;
|
||||
|
||||
if(isDevTools)
|
||||
this.parentWindow.addEventListener((scope ClosingEvent ce) {
|
||||
this.parentWindow.hide();
|
||||
ce.preventDefault();
|
||||
});
|
||||
else
|
||||
this.parentWindow.addEventListener((scope ClosingEvent ce) {
|
||||
if(devTools)
|
||||
devTools.close();
|
||||
if(!closeAttempted && browserHandle) {
|
||||
browserHandle.get_host.close_browser(true);
|
||||
ce.preventDefault();
|
||||
|
@ -450,6 +484,7 @@ class WebViewWidget_CEF : WebViewWidgetBase {
|
|||
}
|
||||
|
||||
private NativeWindowHandle browserWindow;
|
||||
private NativeWindowHandle ozone;
|
||||
private RC!cef_browser_t browserHandle;
|
||||
|
||||
private static WebViewWidget[NativeWindowHandle] mapping;
|
||||
|
@ -475,9 +510,37 @@ class WebViewWidget_CEF : WebViewWidgetBase {
|
|||
browserHandle.get_main_frame.execute_java_script(&c, &u, line);
|
||||
}
|
||||
|
||||
private Window devTools;
|
||||
override void showDevTools() {
|
||||
if(!browserHandle) return;
|
||||
browserHandle.get_host.show_dev_tools(null /* window info */, client.passable, null /* settings */, null /* inspect element at coordinates */);
|
||||
|
||||
if(devTools is null) {
|
||||
auto host = browserHandle.get_host;
|
||||
|
||||
if(host.has_dev_tools()) {
|
||||
host.close_dev_tools();
|
||||
return;
|
||||
}
|
||||
|
||||
cef_window_info_t windowinfo;
|
||||
version(linux) {
|
||||
auto sw = new Window("DevTools");
|
||||
//sw.win.beingOpenKeepsAppOpen = false;
|
||||
devTools = sw;
|
||||
|
||||
auto wv = new WebViewWidget_CEF(client, sw, true);
|
||||
|
||||
sw.show();
|
||||
|
||||
windowinfo.parent_window = wv.containerWindow.nativeWindowHandle;
|
||||
}
|
||||
host.show_dev_tools(&windowinfo, client.passable, null /* settings */, null /* inspect element at coordinates */);
|
||||
} else {
|
||||
if(devTools.hidden)
|
||||
devTools.show();
|
||||
else
|
||||
devTools.hide();
|
||||
}
|
||||
}
|
||||
|
||||
// FYI the cef browser host also allows things like custom spelling dictionaries and getting navigation entries.
|
||||
|
@ -534,7 +597,7 @@ version(cef) {
|
|||
cef_dictionary_value_t** extra_info,
|
||||
int* no_javascript_access
|
||||
) {
|
||||
|
||||
sdpyPrintDebugString("on_before_popup");
|
||||
if(this.client.openNewWindow is null)
|
||||
return 1; // new windows disabled
|
||||
|
||||
|
@ -551,7 +614,7 @@ version(cef) {
|
|||
scope WebViewWidget delegate(Widget, BrowserSettings) accept = (parent, passed_settings) {
|
||||
ret = 0;
|
||||
if(parent !is null) {
|
||||
auto widget = new WebViewWidget_CEF(this.client, parent);
|
||||
auto widget = new WebViewWidget_CEF(this.client, parent, false);
|
||||
(*windowInfo).parent_window = widget.containerWindow.nativeWindowHandle;
|
||||
|
||||
passed_settings.set(browser_settings);
|
||||
|
@ -589,10 +652,13 @@ version(cef) {
|
|||
import arsd.simpledisplay : Window;
|
||||
Window root;
|
||||
Window parent;
|
||||
Window ozone;
|
||||
uint c = 0;
|
||||
auto display = XDisplayConnection.get;
|
||||
Window* children;
|
||||
XQueryTree(display, handle, &root, &parent, &children, &c);
|
||||
if(c == 1)
|
||||
ozone = children[0];
|
||||
XFree(children);
|
||||
} else static assert(0);
|
||||
|
||||
|
@ -600,8 +666,9 @@ version(cef) {
|
|||
auto wv = *wvp;
|
||||
wv.browserWindow = handle;
|
||||
wv.browserHandle = RC!cef_browser_t(ptr);
|
||||
wv.ozone = ozone ? ozone : handle;
|
||||
|
||||
wv.browserWindowWrapped = new SimpleWindow(wv.browserWindow);
|
||||
wv.browserWindowWrapped = new SimpleWindow(wv.ozone);
|
||||
/+
|
||||
XSelectInput(XDisplayConnection.get, handle, EventMask.FocusChangeMask);
|
||||
|
||||
|
@ -831,17 +898,70 @@ version(cef) {
|
|||
}
|
||||
}
|
||||
|
||||
class MiniguiRequestHandler : CEF!cef_request_handler_t {
|
||||
override int on_before_browse(RC!(cef_browser_t), RC!(cef_frame_t), RC!(cef_request_t), int, int) nothrow {
|
||||
return 0;
|
||||
}
|
||||
override int on_open_urlfrom_tab(RC!(cef_browser_t), RC!(cef_frame_t), const(cef_string_utf16_t)*, cef_window_open_disposition_t, int) nothrow {
|
||||
return 0;
|
||||
}
|
||||
override cef_resource_request_handler_t* get_resource_request_handler(RC!(cef_browser_t), RC!(cef_frame_t), RC!(cef_request_t), int, int, const(cef_string_utf16_t)*, int*) nothrow {
|
||||
return null;
|
||||
}
|
||||
override int get_auth_credentials(RC!(cef_browser_t), const(cef_string_utf16_t)*, int, const(cef_string_utf16_t)*, int, const(cef_string_utf16_t)*, const(cef_string_utf16_t)*, RC!(cef_auth_callback_t)) nothrow {
|
||||
// this is for http basic auth popup.....
|
||||
return 0;
|
||||
}
|
||||
override int on_quota_request(RC!(cef_browser_t), const(cef_string_utf16_t)*, long, RC!(cef_callback_t)) nothrow {
|
||||
return 0;
|
||||
}
|
||||
override int on_certificate_error(RC!(cef_browser_t), cef_errorcode_t, const(cef_string_utf16_t)*, RC!(cef_sslinfo_t), RC!(cef_callback_t)) nothrow {
|
||||
return 0;
|
||||
}
|
||||
override int on_select_client_certificate(RC!(cef_browser_t), int, const(cef_string_utf16_t)*, int, ulong, cef_x509certificate_t**, RC!(cef_select_client_certificate_callback_t)) nothrow {
|
||||
return 0;
|
||||
}
|
||||
override void on_plugin_crashed(RC!(cef_browser_t), const(cef_string_utf16_t)*) nothrow {
|
||||
|
||||
}
|
||||
override void on_render_view_ready(RC!(cef_browser_t) p) nothrow {
|
||||
|
||||
}
|
||||
override void on_render_process_terminated(RC!(cef_browser_t), cef_termination_status_t) nothrow {
|
||||
|
||||
}
|
||||
override void on_document_available_in_main_frame(RC!(cef_browser_t) browser) nothrow {
|
||||
browser.runOnWebView(delegate(wv) {
|
||||
wv.executeJavascript("console.log('here');");
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class MiniguiFocusHandler : CEF!cef_focus_handler_t {
|
||||
override void on_take_focus(RC!(cef_browser_t) browser, int next) nothrow {
|
||||
// sdpyPrintDebugString("take");
|
||||
browser.runOnWebView(delegate(wv) {
|
||||
Widget f;
|
||||
if(next) {
|
||||
f = Window.getFirstFocusable(wv.parentWindow);
|
||||
} else {
|
||||
foreach(w; &wv.parentWindow.focusableWidgets) {
|
||||
if(w is wv)
|
||||
break;
|
||||
f = w;
|
||||
}
|
||||
}
|
||||
if(f)
|
||||
f.focus();
|
||||
});
|
||||
}
|
||||
override int on_set_focus(RC!(cef_browser_t) browser, cef_focus_source_t source) nothrow {
|
||||
/+
|
||||
browser.runOnWebView((ev) {
|
||||
sdpyPrintDebugString("setting");
|
||||
ev.parentWindow.focusedWidget = ev;
|
||||
ev.focus(); // even this can steal focus from other parts of my application!
|
||||
});
|
||||
+/
|
||||
//sdpyPrintDebugString("setting");
|
||||
|
||||
return 1; // otherwise, cancel because this bullshit tends to steal focus from other applications and i never, ever, ever want that to happen.
|
||||
// seems to happen because of race condition in it getting a focus event and then stealing the focus from the parent
|
||||
|
@ -850,7 +970,12 @@ version(cef) {
|
|||
// it also breaks its own pop up menus and drop down boxes to allow this! wtf
|
||||
}
|
||||
override void on_got_focus(RC!(cef_browser_t) browser) nothrow {
|
||||
// sdpyPrintDebugString("got");
|
||||
browser.runOnWebView((ev) {
|
||||
// this sometimes steals from the app too but it is relatively acceptable
|
||||
// steals when i mouse in from the side of the window quickly, but still
|
||||
// i want the minigui state to match so i'll allow it
|
||||
ev.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -865,6 +990,7 @@ version(cef) {
|
|||
MiniguiDownloadHandler downloadHandler;
|
||||
MiniguiKeyboardHandler keyboardHandler;
|
||||
MiniguiFocusHandler focusHandler;
|
||||
MiniguiRequestHandler requestHandler;
|
||||
this(void delegate(scope OpenNewWindowParams) openNewWindow) {
|
||||
this.openNewWindow = openNewWindow;
|
||||
lsh = new MiniguiCefLifeSpanHandler(this);
|
||||
|
@ -874,6 +1000,7 @@ version(cef) {
|
|||
downloadHandler = new MiniguiDownloadHandler();
|
||||
keyboardHandler = new MiniguiKeyboardHandler();
|
||||
focusHandler = new MiniguiFocusHandler();
|
||||
requestHandler = new MiniguiRequestHandler();
|
||||
}
|
||||
|
||||
override cef_audio_handler_t* get_audio_handler() {
|
||||
|
@ -917,10 +1044,12 @@ version(cef) {
|
|||
override cef_render_handler_t* get_render_handler() {
|
||||
// this thing might work for an off-screen thing
|
||||
// like to an image or to a video stream maybe
|
||||
//
|
||||
// might be useful to have it render here then send it over too for remote X sharing a process
|
||||
return null;
|
||||
}
|
||||
override cef_request_handler_t* get_request_handler() {
|
||||
return null;
|
||||
return requestHandler.returnable;
|
||||
}
|
||||
override int on_process_message_received(RC!cef_browser_t, RC!cef_frame_t, cef_process_id_t, RC!cef_process_message_t) {
|
||||
return 0; // return 1 if you can actually handle the message
|
||||
|
|
|
@ -12296,6 +12296,13 @@ version(X11) {
|
|||
if(width == 0 || height == 0) {
|
||||
XSetClipMask(display, gc, None);
|
||||
|
||||
if(xrenderPicturePainter) {
|
||||
|
||||
XRectangle[1] rects;
|
||||
rects[0] = XRectangle(short.min, short.min, short.max, short.max);
|
||||
XRenderSetPictureClipRectangles(display, xrenderPicturePainter, 0, 0, rects.ptr, cast(int) rects.length);
|
||||
}
|
||||
|
||||
version(with_xft) {
|
||||
if(xftFont is null || xftDraw is null)
|
||||
return;
|
||||
|
@ -12306,6 +12313,9 @@ version(X11) {
|
|||
rects[0] = XRectangle(cast(short)(x), cast(short)(y), cast(short) width, cast(short) height);
|
||||
XSetClipRectangles(XDisplayConnection.get, gc, 0, 0, rects.ptr, 1, 0);
|
||||
|
||||
if(xrenderPicturePainter)
|
||||
XRenderSetPictureClipRectangles(display, xrenderPicturePainter, 0, 0, rects.ptr, cast(int) rects.length);
|
||||
|
||||
version(with_xft) {
|
||||
if(xftFont is null || xftDraw is null)
|
||||
return;
|
||||
|
@ -12572,6 +12582,12 @@ version(X11) {
|
|||
XRenderPictureAttributes attrs;
|
||||
// FIXME: I can prolly reuse this as long as the pixmap itself is valid.
|
||||
xrenderPicturePainter = XRenderCreatePicture(display, d, Sprite.RGB24, 0, &attrs);
|
||||
|
||||
// need to initialize the clip
|
||||
XRectangle[1] rects;
|
||||
rects[0] = XRectangle(cast(short)(_clipRectangle.left), cast(short)(_clipRectangle.top), cast(short) _clipRectangle.width, cast(short) _clipRectangle.height);
|
||||
|
||||
XRenderSetPictureClipRectangles(display, xrenderPicturePainter, 0, 0, rects.ptr, cast(int) rects.length);
|
||||
}
|
||||
|
||||
XRenderComposite(
|
||||
|
@ -13613,6 +13629,35 @@ mixin DynamicLoad!(XRandr, "Xrandr", 2, XRandrLibrarySuccessfullyLoaded) XRandrL
|
|||
}
|
||||
}
|
||||
|
||||
/++
|
||||
Platform-specific for X11. Traps errors for the duration of `dg`. Avoid calling this from inside a call to this.
|
||||
|
||||
Please note that it returns
|
||||
+/
|
||||
XErrorEvent[] trapXErrors(scope void delegate() dg) {
|
||||
|
||||
static XErrorEvent[] errorBuffer;
|
||||
|
||||
static extern(C) int handler (Display* dpy, XErrorEvent* evt) nothrow {
|
||||
errorBuffer ~= *evt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto savedErrorHandler = XSetErrorHandler(&handler);
|
||||
|
||||
try {
|
||||
dg();
|
||||
} finally {
|
||||
XSync(XDisplayConnection.get, 0/*False*/);
|
||||
XSetErrorHandler(savedErrorHandler);
|
||||
}
|
||||
|
||||
auto bfr = errorBuffer;
|
||||
errorBuffer = null;
|
||||
|
||||
return bfr;
|
||||
}
|
||||
|
||||
/// Platform-specific for X11. A singleton class (well, all its methods are actually static... so more like a namespace) wrapping a `Display*`.
|
||||
class XDisplayConnection {
|
||||
private __gshared Display* display;
|
||||
|
@ -16986,6 +17031,9 @@ extern(C) {
|
|||
extern(C) alias XIOErrorHandler = int function (Display* display);
|
||||
}
|
||||
|
||||
extern(C) nothrow
|
||||
alias XErrorHandler = int function(Display*, XErrorEvent*);
|
||||
|
||||
extern(C) nothrow @nogc {
|
||||
struct Screen{
|
||||
XExtData *ext_data; /* hook for extension to hang data */
|
||||
|
@ -17190,8 +17238,6 @@ struct Visual
|
|||
byte pad;
|
||||
}
|
||||
|
||||
alias XErrorHandler = int function(Display*, XErrorEvent*);
|
||||
|
||||
struct XRectangle {
|
||||
short x;
|
||||
short y;
|
||||
|
|
Loading…
Reference in New Issue