Modify the sample to show the correct value of the user agent when using
WebKit backend as this got broken by calling it inside an event handler
executed later but before the idle event handler could dispatch the
result of JS executed from inside WebKit AddScriptMessageHandler()
implementation, resulting in misinterpreting this result ("{}") as the
user agent string.
The real fix is, of course, to deal with the JS execution results coming
out of order in some way.
It defaults to $root_cache_path/Cache which is fine and our existing
attempt to set it didn't work (and resulted in an error message) anyhow
as it must be under $root_cache_path now.
It is now defined as
@executable_path/../Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework
in the framework itself, which means that we don't need to change it at
all for the main application and the wx library it uses.
We still need to change it for the helper application, but the command
doing it must be adjusted.
Avoid crashes if some functions are called before the browser is fully
initialized -- this is relatively likely to happen as the existing code
may not wait for wxEVT_WEBVIEW_CREATED before calling them, as must be
done with wxWebViewChromium.
wxWebViewChromium creation is asynchronous and the object can't be
really used until OnAfterCreated() is called, so expose this in the
public API via a new event sent when the object becomes actually usable.
As a side effect, add a convenient wxWebViewEvent ctor taking wxWebView
as argument and calling SetEventObject() itself, instead of forcing all
code creating wxWebViewEvents to do it.
While the window was somehow resized on its own under Mac (and only
there) after the initial creation, it didn't have the correct size
initially if we didn't give it to it, so provide a Mac-specific
implementation of wxEVT_SIZE handler too, which fixes this and allows to
remove an ugly Mac-specific workaround from the sample.
Instead of just declaring the function inline in the common code, do it
in a header included from both common C++ and Mac Objective C++ sources.
No real changes.
We can't wait for OnBeforeClose() to be called in the dtor there, or,
IOW, we can't count on it being called before the object is destroyed
and hence we can't update the flag in it neither.
Don't do it and just hope that the ClientHandler object always gets
destroyed soon after wxWebViewChromium itself anyhow because it's only
referenced by an autorelease pool.
It's not clear if this really should be doing something as previously
existing code definitely didn't, but it seems like actually storing the
flag should be no worse and at least now it compiles (due to the added
casts to IMP).
Use variables defined in our .props files instead of hard-coded values
and use DPI aware manifest instead of using "compatibility" one with
which the sample didn't work correctly in high DPI.
Use "wxCEF" prefix for this class to avoid any conflicts by using
non-wx-prefixed name.
Also replace wxWebViewChromiumImplData with wxCEF::ImplData as this is
shorter and more consistent with ClientHandler.
Finally stop using anonymous namespace for wxBrowserProcessHandler and
wxCefApp, as we can now put them into the same wxCEF namespace.
Ensure that CefLifeSpanHandler::OnBeforeClose() is called before
returning from wxWebViewChromium dtor, as otherwise we may try to shut
down CEF before the browser object is destroyed.
Under MSW it's enough to destroy the window ourselves to make this
happen, but under GTK/X11 we need to manually pump the messages, as
OnBeforeClose() is only called when the X event notifying about the
actual window destruction arrives.
Also make the code cleaner by using flags in wxWebViewChromiumImplData
instead of reusing m_clientHandler pointer to indicate that DoClose()
was called.
Restart the timer if it's already running but its expiration time is
beyond the specified delay, otherwise we could be waiting for too long.
This commit is best viewed ignoring whitespace-only changes.
Make browser creation actually work by postponing it until the host
window is realized and so has a valid X11 Window.
Remove unnecessary code manually creating GTK widget and just use the
standard wxGTK wxWindow instead.
Add code for setting the visual compatible with CEF to avoid X11 errors,
see https://github.com/chromiumembedded/cef/issues/3564, with many
thanks to Jiří Janoušek for finding and solving this problem originally.
Adjust the sample to handle wxWebView::Create() failure (not very
gracefully, but still better than just crashing) and to avoid using it
until it is fully created.
Update documentation to mention GTK limitations.
At least when using wxGTK Chromium helper process can't be executed once
GTK is initialized because doing this creates background threads and
Chromium code aborts if there are any threads running.
As we don't want to initialize CEF unconditionally before initializing
GTK in all applications (even those not using CEF), the only solution is
to detect if we need to run a Chromium helper process ourselves before
GTK initialization, i.e. before wxApp creation, which means that it
can't be done via the existing wxModule mechanism because modules are
initialized after creating the global application instance.
So add a way to hijack wxWidgets initialization entirely if some special
command line option (such as Chromium "--type=xxx") is specified and use
it in wxWebViewChromium to call CefExecuteProcess() before initializing
GTK or even wxWidgets itself -- as it won't be needed in a CEF helper
process anyhow.
Fixes hiding a wxGLCanvas on Wayland, either directly (`->Show(false)`)
or indirectly (e.g. when it is contained in a wxNotebook).
On Wayland, unlike on X11, to show the canvas on the screen, we need to
create a Wayland subsurface. This subsurface is detached from the GTK
widget associated to the canvas, thus it is not automatically mapped or
unmapped when the associated GTK widget is.
Rather, we need to manually keep it in sync with the widget's state.
Knowing what has to be done to map and unmap the canvas, while dealing
with edge cases properly, is not easy to someone not used to Wayland.
When the canvas is mapped, we have this graph of resources:
EGL Surface (m_surface)
|
|
v
wl_egl window (m_wlEGLWindow)
|
|
v
Canvas wl_surface GDK's toplevel window wl_surface
(m_wlSurface) (gdk_wayland_window_get_wl_surface(w))
\ which is shown to the user
\ ^
\ /
\ /
v /
Subsurface (m_wlSubsurface) to overlay
the canvas onto the toplevel window
A simple way would be to destroy everything (m_surface, m_wlEGLWindow,
m_wlSurface, m_wlSubsurface) on unmap, and re-create it again on map.
Inefficiencies aside, this mostly works. However, it can mess with the
current OpenGL context. For example, suppose we have a (fragile)
program that places a canvas inside one of wxNotebook's tabs, and makes
the OpenGL context current only once at startup (e.g. on wxEVT_SHOW).
Switching between tabs will destroy and re-create the EGL Surface, so
the canvas will not be properly rendered when going back to its tab.
So we need to be smarter, and find some way to hide the subsurface
instead. The obvious way would be to unmap the canvas wl_surface
(m_wlSurface), as according to the Wayland spec., "a sub-surface is
hidden [...] if a NULL wl_buffer is applied [to the canvas surface]."
(https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_subsurface)
However, as far as I can tell, this can't be done. There's no API to
hide an wl_egl window, and directly applying a NULL wl_buffer to the
canvas surface initially hides it, but seems to breaks the associated
window so that it crashes when one attempts to show it again.
So what remains, is destroying the overlay subsurface (m_wlSubsurface).
When doing it, to the spec, "the wl_surface is unmapped immediately.".
And not only does this work, but it also deals with the annoying fact
that on current GTK3 versions, when the GDK's toplevel window is
unmapped, its wl_surface is not just unmapped, but entirely destroyed.
(Side note: This may not have been intended, and has been changed for
GTK4, see: 5d3cec5441)
So we'd have to re-create the subsurface because of this anyway.
So, this works nicely, and as far as I can tell (documentation is a bit
scarce), there's no problem to leaving m_wlSurface (and its associated
m_wlEGLWindow and m_surface) unmapped in this way.
Fixes#22580.
Closes#23835.
Make the wxString(std::string_view) constructor explicit.
Otherwise, when comparing a std::string_view with a const char *, the
cast to wxString will be considered as a candidate for the comparison,
ultimately causing an "ambiguous overload for 'operator=='" error.
For example, this sample only builds if the constructor is explicit:
#include <wx/string.h>
#include <string_view>
int main() {
std::string_view view = "abc";
const char *str = "abc";
return view == str;
}
However, making the constructor explicit will break assignment:
std::string_view view = "abc";
wxString s;
s = view; // Error: no match for "operator="
That we can fix by implementing operator=(std::string_view)
That, however, introduces another ambiguity:
std::string str = "abc";
wxString s;
s = str; // Ambiguous between s = wxString(str)
and s = std::string_view(str)
That we can fix by implementing operator=(std::string)
Finally, note that some rather obscure ambiguities remain, such as:
wxString s;
s = {"abc", 2}; // Ambiguous between s = wxString("abc", 2)
and s = std::string_view("abc", 2)
Avoiding them is not simple (https://cplusplus.github.io/LWG/issue2946)
and doesn't add much value.
Closes#23834.