Since the shaders need to be updated for using with GLES (libANGLE at
least), default to WGL for now. Unfortunately it is not that common for
Windows to have GLES support, in which the easiest way to obtain such
support is via Google's libANGLE.
It turns out that the problem of the WGL window not drawing was due to
the fact that I messed up where I placed SwapBuffers() during the
conversion... doh:|
At the same time, stop storing the HDC in the GdkWin32GLContextWGL, but
instead always create it along the surface we created, so that it is ready
for use for operating with WGL when we are not dealing with "surfaceless"
contexts. If we are dealing with "surfaceless" contexts, just use the
HDC of the dummy window that we created when we created the
Gdk(Win32)Display.
WGL contexts should now be in working order at this point.
This commit attempts to split GdkWin32GLContext into two parts, one for
WGL and the other for EGL (ANGLE), and attempts to simplify things a
bit, by:
* We are already creating a Win32 window to capture display changes,
so we can just use that to act as our dummy window that we use to
find out the pixel format that the system supports for WGL. We also
use it to obtain the dummy legacy WGL context that we will always
require to create our more advanced Core WGL contexts.
* Like what is done in X11, store up the WGL pixel format or the
EGLConfig in our GdkWin32Display.
* Ensure we do not create the dummy WGL context unnecessarily.
In this way, we can successfully create the WGL/EGL contexts, however
there are some issues at this point:
* For WGL, the code successfully initializes and realizes the WGL
Contexts, but for some reason things became invisible. When running
gtk4-demo, this can be verified by seeing the mouse cursor changing
when moved to spots where one can resize the window, although they
were invisible.
* For EGL, the code initializes EGL but could not realize the EGL
context as shaders failed to compile. It seems like the shader issue
is definitely outside the scope of this MR.
nvidia sets the default draw buffer to GL_NONE if EGL contexts are
initially bound to EGL_NO_SURFACE which is exactly what we are doing. So
bind them to GL_BACK when drawing, as they should be.
See https://phabricator.services.mozilla.com/D118743 for a discussion
about EGL_NO_CONTEXT and draw buffers.
This way, one can force using WGL on Windows even if EGL support was
enabled. Also update the help text for gl-egl as it will apply for
Windows, albeit a bit later.
This has the benefit that we can refactor it and make sure we deal with
GdkDisplay::init_gl() not being called at all because
GDK_DEBUG=gl-disable had been specified.
It's not used there, but both backends have independent
immplementationgs for it.
I want to get rid of GdkGLContextX11 and moving code from it is the
first step.
Now that we have the display's context to hook into, we can use it to
construct other GL contexts and don't need a GdkSurface vfunc anymore.
This has the added benefit that backends can have different GdkGLContext
classes on the display and get new GLContexts generated from them, so
we get multiple GL backend support per GDK backend for free.
I originally wanted to make this a vfunc on GdkGLContextClass, but
it turns out all the abckends would just call g_object_new() anyway.
Instead of
Display::make_gl_context_current()
we now have
GLContext::clear_current()
GLContext::make_current()
This fits better with the backends (we can actually implement
clearCurrent on macOS now) and makes it easier to implement different GL
backends for backends (like EGL/GLX on X11).
We also pass a surfaceless boolean to make_current() so the calling code
can decide if a surface needs to be bound or not, because the backends
were all doing whatever, which was very counterproductive.
The code to create and manage a fake egl surface to bind to is
complex and completely untested because everyone seems to support this
extension.
nvidia and Mesa do support it and according to Mesa devs, adding support
in a new driver is rather simple and Mesa drivers gain that feature
automatically, so all future drivers shoould have it.
... or more exactly: Only use paint contexts with
gdk_cairo_draw_from_gl().
Instead of paint contexts being the only contexts who call swapBuffer(),
any context can be used for this, when it's used with
begin_frame()/end_frame().
This removes 2 features:
1. We no longer need a big sharing hierarchy. All contexts are now
shared with gdk_display_get_gl_context().
2. There is no longer a difference between attached and non-attached
contexts. All contexts work the same way.
Do not treat the context as already current when the value
of context::in-frame changes.
This is so we can bind to EGL_NO_SURFACE if context::in-frame == false
and to context::surface if context::in-frame == true.
This allows getting rid of the attached property in future commits.
The vfunc is called to initialize GL and it returns a "base" context
that GDK then uses as the context all others are shared with. So the GL
context share tree now looks like:
+ context from init_gl
- context1
- context2
...
So this is a flat tree now, the complexity is gone.
The only caveat is that backends now need to create a GL context when
initializing GL so some refactoring was needed.
Two new functions have been added:
* gdk_display_prepare_gl()
This is public API and can be used to ensure that GL has been
initialized or if not, retrieve an error to display (or debug-print).
* gdk_display_get_gl_context()
This is a private function to retrieve the base context from
init_gl(). It replaces gdk_surface_get_shared_data_context().
Create it during init and then reuse it for all contexts.
While doing that, also improve error reporting - that's not used yet but
will in later commits.
This is not used yet, but it allows surfaceless GL contexts.
For that purpose, we need to make the display a construct-only property,
so that it can be set when the surface isn't.
This adds a bunch of very picky checks in the constructor so nothing bad
can happen.
... and move some members from the GdkDisplay struct.
We've always wanted to add one to isolate the display from the backends
a bit more, but so far it's never happened.
Now that I'm about to add more data to GdkDisplay, it's a good excuse to
start.
We try EGL first, but are very picky about what we accept.
If that fails, we try to go with GLX instead.
And if that also fails, we try EGL again, but this time accept anything.
The idea here is that EGL is the preferred method going forward, but GLX is
the tried and tested method that we know works. So if we detect issues with
EGL, we want to avoid using it in favor of GLX.
Also add a GDK_DEBUG=gl-egl option to force EGL at all costs and not try
GLX.
That way, we can give a useful error message when things break down for
users.
These error messages could still be improved in places (like looking at
the actual EGL error codes), but that seemed overkill.
Query the EGL_VISUAL_ID from the egl Config and select a config with the
matching Visual.
This is currently broken on Mesa because it does not expose any RGBA
X Visuals in any EGL config, so we always end up with opaque Windows.
https://gitlab.freedesktop.org/mesa/mesa/-/issues/149
This reverts commit c35a6725b9.
This approach doesn't work because if NVIDIA doesn't work for EGL, the
EGL implementation won't be provided by NVIDIA, so checking the vendor
doesn't work.
Instead, use the display's "leader surface" when no surface is required,
because we have it lying around.
Really, we want to use EGL_NO_SURFACE, but if that's not supported...
Instead of going via GdkVisual, doing a preselection and letting the GL
initialization improve it, let the GL initialization pick an X Visual
directly using X Visual code directly.
The code should select the same visuals as before as it tries to apply
the same logic, but it's a rewrite, so I expect I messed something up.
1. We're using EGL most of the time anyway, so if we wanted to cache
things, we'd need to port it there.
2. Our GL handling is massively configurable, so determining when to use
the cache and when not is a challenge.
3. It makes startup nondeterministic and depend on whether a GTK4 app
has previously been started on this display and nobody thinks about
that when debugging.
4. The only benefit of the caching is delaying GL initialization - which
made sense in GTK3 where almost no app used GL but doesn't make sense
in GTK4 where almost every app uses GL.
So unless I find a big benefit to reintroducing it, this cache will be
gone for good.
Avoids having to use private data, though the benefit is somewhat
limited as we still have to put the destructor in the egl code and can't
just put it in gdk_surface_x11_finalize().
We only have one config, because we use the same Visual everywhere.
Store this config in the GdkDisplayX11 struct for easy access.
Also do this on initialize, because if creating the config fails, we
want to switch to GLX instead of failing to do GL at all.
This also simplifies a lot of code as we can share Visual, Colormap, etc
across surfaces.
There's no need to use g_object_set_data() for it.
We can also stop caching it elsewhere because we know the display has
it.
And finally, we can remove the display->have_egl boolean and use
display->egl_display != NULL instead. We initialize the display at
startup, so that variable is the perfect indicator.
We need to initialize GL to select the Visual we are going to use for
all our Windows.
As the Visual needs to be known before we know if we are even gonna use
GL later, we can't avoid initializing it.
Note that this previously happened, too. It was just hidden behind the
GdkScreen initialization.
We don't want to bind ourselves to GTK3 - both because we don't want to
accidentally cause bugs in a different codebase and because we want to
deviate from it.
While doing so, also store visuals as visuals and not as integers.
And only store one Visual because GTK4 only uses one visual.
And then remove the code that is leftover for dealing with the
compatibility Visual for GTK3.
PS: I'm kinda proud of my STRINGIFY_WITHOUT_BRACKETS hack.
The old code was ordering visuals by depth, but considering that these
days we either use the default visual or a 32bit RGBA visual, that
reordering does not have an effect anymore.
In theory, the only effect is that the GLX Visual selection might select
a different replacement Visual when it checks for improved GL Visuals, but
even there I can't come up with a case where that matters, because
again, the visuals are only reordered by depth and we want to keep the
depth.
In any case, make this a separate commit so bisecting can find this
problem if it ever shows up.
Instead of the display telling the screen to tell the visuals to tell
the display to initialize itself, just init the display directly.
What a concept.
If the pointer capability is added, pointer swipe and pinch gestures
will be created. However, if the pointer capability is removed, the
gesture objects won't be destroyed.
If the pointer capability is removed and added several times in a row,
for example due to plugging and unplugging physical mouse, this can lead
to leaking the old gesture objects.
In order to prevent that, this change makes the seat destroy swipe and
pinch gestures when the pointer capability is withdrawn.
It's only used during DND to allow use of the root window's cow window
as a DND target, because apparently gnome-shell used to think that was a
great idea to DND to the overview.
Somebody complain to gnome-shell devs about it not being a good idea if
they want it fixed.
Potentially using Wayland is a better idea though.
This reverts 85ae875dcb
Related: https://bugzilla.gnome.org/show_bug.cgi?id=601731
Make _gdk_win32_display_get_monitor_scale_factor() less complex, by:
* Drop the preceding underscore.
* Dropping an unused parameter.
* Using a GdkSurface instead of a HWND, as the HWND that we pass into
this function might have been taken from a GdkSurface, which are now
always created with CS_OWNDC. This means if a GdkSurface was passed
in, we ensure that we only acquire the DC from the HWND once, and do
not attempt to call ReleaseDC() on it.
* Store the HDC that we acquire from the GdkSurface's HWND into the
surface, and use that as the HDC we need for our GdkGLContext.
* Drop the gl_hwnd from GdkWin32Display, as that is really should be
stored in the GdkSurface.
* For functions that were updated, name GdkWin32Display variables as
display_win32 and GdkSurface variables as surface, to unify things.
* Stop calling ReleaseDC() on the HDC that we use for OpenGL, since
they were acquired from HWND's created with CS_OWNDC.
It apparently worked by chance in the past, but now causes e.g.
alphanumeric characters to be interpreted as half-width katakana
when using the Japanese IME.
We must call gdk_drag_drop_done() when the drag ends,
successfully or not. Without this, we get an unwarranted
emission of ::cancel after a successful drop.
Since only the first call to gdk_drag_drop_done() is taking
effect, it is safe to call as a fallback, after emitting
::dnd-finished. If the application connects to that signal
and calls gdk_drag_drop_done() itself, its call will take
precedence.
This matches what the X11 implementation does.
Determine the root_x and root_y coordinates of the drag surface by
relying on the coordinates of the surface where the drag is being
carried out, plus the coordinates that we receive from the drag event,
which is in-line with what the X11 backend does.
This will prevent the drag surface from being initially drawn at the
correct position, but jumping towards the top-left corner of the screen
shortly afterwards.
The DnD support will still need some more updates to function correctly
on Windows, but at least this is a small improvement.
Fixes issue #3798.
This gets the basic mechanics of the drop portion of DnD working on the
macOS backend. You can drag, for example, from TextEdit into GNOME
Text Editor when using the macOS backend.
Other content formats are supported, and match what is currently
supported by the clipboard backend as the implementation to read
from the pasteboard is shared.
Currently, we look up the GdkDrag for the new GdkDrop. However,
nothing is stashing the drag away for further lookup. More work is
needed on GdkMacosDrag for that to be doable.
We will want to be able to reuse the pasteboard reading code from
the macOS DnD drop backend. This just removes the pasteboard
bits from the implementation and allows that to be passed in as in
both clipboard and DnD cases we'll have a specific NSPasteboard
to read from.
If we are undergoing a surface move, just apply the next_layout anyways,
even if we are not moving a toplevel surface.
Update the way how we obtain the x and y coordinates of a surface, if it
is a toplevel, apply the x and y coordinates from the results from we
obtained the underlying Win32 HWND, as we did before. But if it is a
popup, use gdk_win32_surface_get_geometry() to obtain the correct x and
y coordinates to place our popup surface.
Also correct how we compute the shadow dimensions, and the final popup
rectangle as we attempt to layout the popup surface, since GDK-Win32
keeps track of the shadow dimensions in system (unscaled) units, not GDK
units.
Fixes issue #3793.
The releasing of grabs while a button is pressed (e.g. after starting dnd, or
dragging the window, or going to overview with a pressed button, etc...) was
generalized here in https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/1879.
However we shouldn't break all grabs here. In the case of grabbing popups,
compositors will still emit crossing events between client surfaces (e.g.
popping up and selecting a menu item via press-drag-release), breaking all
grabs here means inconsistent client state, that was
https://gitlab.gnome.org/GNOME/gtk/-/issues/2746.
That was fixed in mutter, by essentially making implicit grabs
owner_events=FALSE, however that breaks the mentioned use pattern entirely.
Mutter is changing this behavior back, so GTK should handle these crossing
events.
The grab that we are interested in breaking here is the implicit pointer
one. Popups will be dismissed via other means if the compositor says their
active grab needs breaking. This still leaves dnd/move/resize drags in
one place, while not allowing #2746 to happen with popups.
Add support to share the WGL context in GDK with the WGL context in GStreamer,
so that we can also use OpenGL in the gstreamer media backend to playback
videos. For now OpenGL/ES is not supported for this under Windows.
The process of setting this up in Windows is a little bit more involved, as:
* The OpenGL support in GstGL requires a GL 4.1 Core context, but we may just
get the GL version from wglCreateContextAttribsARB() that we pass into the
attributes, which is 3.2 by default. So, try to ask for a 4.1 Core context
first if we are asking for anything less.
* There is only one GstDisplay available for Windows, so we just use
gst_gl_display_new().
* We must explicitly tell libepoxy that we are using wglMakeCurrent() outside
of libepoxy that is being used in GdkGL, otherwise we would end up crashing
as the GL/WGL function pointers would become invalid.
* We must also deactivate temporarily the underlying WGL context that was made
current by gdk_gl_context_make_current() so that when
gst_gl_display_create_context() calls wglShareLists(), we won't get bitten
by error 0xaa (resource busy), as some drivers don't handle this well when
the GL context is current in another thread.
For the last two points we make use of macros defined by the platforms that the
build is done for to help us carry out the necessary tasks as needed.
Thanks to Matthew Waters for the info on integrating GstGL and windowing
toolkits on Windows.
Check that we are indeed running inside an Xorg server before enabling
the workaround.
XWayland or other nested X servers deadlock when that workaround is
applied.
Remove a boatload of "or %NULL" from nullable parameters
and return values. gi-docgen generates suitable text from
the annotation that we don't need to duplicate.
This adds a few missing nullable annotations too.