Commit Graph

208 Commits

Author SHA1 Message Date
Christian Hergert
91f5bfd211 macos: leave note about monitor discovery 2022-02-28 11:36:27 -08:00
Christian Hergert
63f20b173d macos: external access to display name helpers
These can be handy to print debug information when we don't have a
GdkMacosMonitor to work with.
2022-02-28 11:36:27 -08:00
Christian Hergert
25b3bd64af macos: fix redisplay of GdkPopup
This broke recently during the configure cleanups and also needed to have
the tail directions fixed again.
2022-02-28 11:36:27 -08:00
Christian Hergert
fc4d36e50a macos: fix cairo renderer with double buffering
If we are double buffering surfaces with IOSurface then we need to copy
the area that was damaged in the previous frame to the back buffer. This
can be done with IOSurface but we need to hold the read-only lock so that
we don't cause the underlying IOSurface contents to be invalidated.

Additionally, since this is only used in the context of rendering to a
GdkMacosSurface, we know the life-time of the cairo_surface_t and can
simply lock/unlock the IOSurface buffer from begin_frame/end_frame to have
the buffer flushing semantics we want.

To ensure that we don't over damage, we store the damage in begin_frame
(and copy it) and then subtract it from the next frames damage to determine
the smallest amount we need to copy (taking scale factor into account).

We don't care to modify the damage region to swapBuffers because they
already have the right contents and could potentially fall into another
tile anyway and we'd like to avoid damaging that.

Fixes #4735
2022-02-28 11:36:27 -08:00
Christian Hergert
dbede0b115 macos: add readonly IOSurfaceLock helper
This can be used to lock a surface for reading to avoid causing the
surface contents to be invalidated. This is needed when reading back from
a front-buffer to the back-buffer as is needed when using Cairo surfaces
to implement something similar to BufferAge.
2022-02-28 11:36:27 -08:00
Christian Hergert
1e40033852 macos: short-circuit on NSEventPhaseMayBegin
We only need to send a single event in this case, so just short-circuit
instead of trying to return an additional event.
2022-02-28 11:36:27 -08:00
Christian Hergert
478bf45320 macos: support mix-rate monitors
Previously, a single CVDisplayLink was used to drive updates for all
surfaces across all monitors. It used a 'best guess' rate which would
allow for updates across monitors of mixed rates. This is undesirable for
situations where you might have a 144hz monitor as it does not allow for
reaching up to that frame rate.

Instead, we want to use a per-monitor CVDisplayLink which will fire at the
rate of the monitor down to the level of updates we require. This commit
does just that.

When a surface crosses onto a new monitor, that monitor is used to drive
the GdkFrameClock.

Fixes #4732
2022-02-28 11:36:27 -08:00
Christian Hergert
dac0b7d609 macos: use video mode for refresh rate and interval
Using the mode allows better detection of refresh rate and refresh
interval for the CVDisplayLink bridge to GdkFrameClock. Using it can help
ensure that our 144hz displays can actually reach that rather than falling
back to just 60hz.

This will also need future commits to rework the displaylink source to be
per-monitor.
2022-02-28 11:36:27 -08:00
Christian Hergert
d14987e819 macos: send stop event when fingers touch
When the fingers are placed on the touchpad, we get a scroll event with
the phase NSEventPhaseMayBegin. We can use this to synthesize an is_stop
event. This results in the scrolledwindow stopping scroll with stop
gestures.

This can cause another warning as well, however, which should be addressed
from #4730.

Fixes #4733
2022-02-28 11:36:27 -08:00
Christian Hergert
3a0077f65f macos: remove emulated scroll events
We don't appear to actually need the emulated scroll events and they get
in the way of proper scrolling with the touchpad.

Fixes #4734
2022-02-28 11:36:27 -08:00
Christian Hergert
03882ef8e5 macos: do not inherit parents frame clock
Windows can end up on different monitors despite having a parent or
transient-for ancestor. We want them to be driven by the CVDisplayLink
for the best-monitor, and so this needs to be unshared.
2022-02-28 11:36:27 -08:00
Christian Hergert
505e10f3ea macos: calculate best monitor when changing screens
When we change screens, we can keep track of the best monitor so that we
can use it to register CVDisplayLink callbacks.
2022-02-28 11:36:27 -08:00
Christian Hergert
1e01444de8 macos: remove duplicated opaque_region field
This can be relied upon from GdkSurface and we do not need to keep a copy
of it. Just remove it and use the GdkSurface.opaque_region field.
2022-02-28 11:36:27 -08:00
Christian Hergert
4404c43cd3 macos: use display id when creating CVDisplayLink
Currently we're using a display link that is for all active displays which
is just the display server trying to find some timings that try to overlap
as many as possible.

That was fine for a prototype, but we really need to do better for
situations with mixed frame rate (such as 60hz and 120hz promotion
displays). Additionally, the 144hz external monitor I have will never
reach 144hz using the current design.

This is just the first step in changing this, but the goal is to have
one of these attached to each GdkMacosMonitor which we can then use to
thaw surfaces specific to that monitor.
2022-02-28 11:36:27 -08:00
Christian Hergert
92a7c7cdc3 macos: move feedback mechanisms into separate file
We will eventually be needing additional feedback from the display server
which would be nice to keep away from the rest of GdkMacosDisplay for
cleanliness sake. Particularly for feedback from mission control and other
environment factors that requires private API for proper integration.
2022-02-28 11:36:23 -08:00
Matthias Clasen
c76b4bdc77 Merge branch 'wip/chergert/macos-add-window-accessor' into 'main'
macos: add getter for NSWindow with macOS windowing

See merge request GNOME/gtk!4509
2022-02-26 03:17:59 +00:00
Christian Hergert
99a40de8ad macos: add getter for NSWindow with macOS windowing
There may be various reasons that an application could need access to the
underlying NSWindow that is being used to display the GdkMacosSurface
contents. This provides a minimal API to do that without exposing our
implementation details through public API.

As our rendering system is likely to change over time, we very much want
to keep GdkMacosView, GdkMacosLayer, GdkMacosTile, and GdkMacosWindow all
private implementation details which are subject to change.

As this is public API, we are a bit long-winded with the name so it is
clear what is being accessed without polluting symbol names with things
like "ns" as we used to.
2022-02-25 11:36:39 -08:00
Matthias Clasen
fc47b913b1 Merge branch 'wip/chergert/macos-fix-popover-tails' into 'main'
macos: fix positioning of popover tails

See merge request GNOME/gtk!4515
2022-02-25 15:50:15 +00:00
Matthias Clasen
7d8b3357a5 Merge branch 'wip/chergert/better-positioning' into 'main'
macos: fix positioning of popover tails

See merge request GNOME/gtk!4516
2022-02-25 15:49:50 +00:00
Matthias Clasen
e0b98bc7de Merge branch 'wip/chergert/macos-fix-titled-resize' into 'main'
macos: fix origin during live resize of titled window

See merge request GNOME/gtk!4519
2022-02-25 15:49:07 +00:00
Matthias Clasen
493b145496 Merge branch 'wip/chergert/macos-unfullscreen' into 'main'
macos: restore unfullscreen frame with style mask

See merge request GNOME/gtk!4518
2022-02-25 15:48:44 +00:00
Christian Hergert
a56828237a macos: fix origin during live resize of titled window
When using server-side-decorations, we need to avoid potential cycles with
compute-size as it may not have the new sizing information yet. We can
just short circuit during "live resize" to get that effect.

Fixes poor window resizing from top-left on titled windows.
2022-02-24 23:29:18 -08:00
Christian Hergert
56e2a7e8bb macos: restore unfullscreen frame with style mask
This doesn't give us appropriate results if we use the window delegate.
Instead, we need to adjust the frame at the same time we change the
style mask so that we end up in the same location.
2022-02-24 22:32:43 -08:00
Christian Hergert
f278f3610b macos: fix kinetic scrolling with overshoot
Previously we had issues on macos where the overshoot would keep showing.
To fix this we need to actually use discrete events instead of the
generated deltas from macOS in the scroll wheel case. Additionally, we need
to drop the kinetic momentum events from macOS and rely on the gtk kinetic
events which are already happening anyway. We also need to submit the
is_stop event for the GDK_SCROLL_SMOOTH case when we detect it.

To keep the discrete scroll events correct, we need to alter the hack in
gtkscrolledwindow.c to use the same path as other platforms except for
when a smooth scroll event is in place. In the future, I would imagine that
this falls into the boundary of high-precision scrolling and would share
the same code paths as other platforms.

With all of these in place, kinetic scrolling with overshoot appears the
same on macOS as other platforms.
2022-02-24 18:58:48 -08:00
Christian Hergert
c111e633e9 macos: remove unused code 2022-02-24 18:58:07 -08:00
Christian Hergert
eea7cf30bb macos: create new windows with slight origin offset
When creating new windows, it is better if we create them with a slight
offset to where they were created before so that they are visible to the
user separately from what they might be overshadowing.
2022-02-24 18:58:07 -08:00
Christian Hergert
36bdcfaccb macos: fix positioning of popover tails
This broke with the previous fixes for initial window positioning. We need
the initial positioning so that tails will be displayed correctly when the
popover surface is displayed.
2022-02-24 16:29:53 -08:00
Matthias Clasen
bcb6cf04ed Merge branch 'wip/chergert/macos-window-manager' into 'main'
macos: improve placement of windows

See merge request GNOME/gtk!4510
2022-02-23 03:53:33 +00:00
Christian Hergert
89a351fd66 macos: improve placement of windows
This does some very basic window management so that we place surfaces in
locations where they can actually be interacted with correctly.
2022-02-22 18:43:46 -08:00
Christian Hergert
e1d3d01e2f macos: update CGL context when surface resizes 2022-02-22 13:15:25 -08:00
Christian Hergert
76a58c40db macos: force pixel format without depth/stencil
We don't need either depth or stencil buffers, so we want a pixel format
without them so that things like glClear() can do less work.
2022-02-22 13:09:30 -08:00
Christian Hergert
df8e2bc0a0 macos: only invalidate tiles when size changes
If the size changes, we need to relayout the tiles. Otherwise we can keep
using what we had before. Generally, that shouldn't happen, but the
previous check was failing in a number of ways.
2022-02-22 12:01:29 -08:00
Christian Hergert
42164fa8bb macos: reload IOSurface when monitor configuration changes
We also want to reload buffer contents if the display server changes the
monitor configuration, such as after changing resolution or orientation.
2022-02-22 12:01:29 -08:00
Christian Hergert
6016e17a38 macos: double buffer IOSurface
It looks like, particularly on the M1, we might need to double buffer the
contents of the IOSurface<->OpenGL texture bindings. This doesn't appear
to show up on the Intel macbooks I've tried, but I've seen it in the wild
on an M1.
2022-02-22 12:01:29 -08:00
Christian Hergert
b2de83efcb macos: restore key window after hiding popup
This fixes the focus returning to the parent window after the popup has
been hidden in the form of being a "Key Window" in macOS.
2022-02-22 12:01:29 -08:00
Christian Hergert
493f90499b macos: fix window drag across mixed-scale monitors
If we have a 2x scale laptop with a 1x scale external display, we would
need to create a new IOSurface for the external display once it crosses
a boundary, otherwise we won't have something capable of displaying
correctly on the second monitor.
2022-02-22 12:01:29 -08:00
Christian Hergert
8b71cff71d macos: use CALayer and IOSurface for rendering
This provides a major shift in how we draw both when accelerated OpenGL
as well as software rendering with Cairo. In short, it uses tiles of Core
Animation's CALayer to display contents from an OpenGL or Cairo rendering
so that the window can provide partial damage updates. Partial damage is
not generally available when using OpenGL as the whole buffer is flipped
even if you only submitted a small change using a scissor rect.

Thankfully, this speeds up Cairo rendering a bit too by using IOSurface to
upload contents to the display server. We use the tiling system we do for
OpenGL which reduces overall complexity and differences between them.

A New Buffer
============

GdkMacosBuffer is a wrapper around an IOSurfaceRef. The term buffer was
used because 1) surface is already used and 2) it loosely maps to a
front/back buffer semantic.

However, it appears that IOSurfaceRef contents are being retained in
some fashion (likely in the compositor result) so we can update the same
IOSurfaceRef without flipping as long as we're fast. This appears to be
what Chromium does as well, but Firefox uses two IOSurfaceRef and flips
between them. We would like to avoid two surfaces because it doubles the
GPU VRAM requirements of the application.

Changes to Windows
==================

Previously, the NSWindow would dynamically change between different
types of NSView based on the renderer being used. This is no longer
necessary as we just have a single NSView type, GdkMacosView, which
inherits from GdkMacosBaseView just to keep the tedius stuff separate
from the machinery of GdkMacosView. We can merge those someday if we
are okay with that.

Changes to Views
================

GdkMacosCairoView, GdkMacosCairoSubView, GdkMacosGLView have all been
removed and replaced with GdkMacosView. This new view has a single
CALayer (GdkMacosLayer) attached to it which itself has sublayers.

The contents of the CALayer is populated with an IOSurfaceRef which
we allocated with the GdkMacosSurface. The surface is replaced when
the NSWindow resizes.

Changes to Layers
=================

We now have a dedicated GdkMacosLayer which contains sublayers of
GdkMacosTile. The tile has a maximum size of 128x128 pixels in device
units.

The GdkMacosTile is partitioned by splitting both the transparent
region (window bounds minus opaque area) and then by splitting the
opaque area.

A tile has either translucent contents (and therefore is not opaque) or
has opaque contents (and therefore is opaque). An opaque tile never
contains transparent contents. As such, the opaque tiles contain a black
background so that Core Animation will consider the tile's bounds as
opaque. This can be verified with "Quartz Debug -> Show opaque regions".

Changes to Cairo
================

GTK 4 cannot currently use cairo-quartz because of how CSS borders are
rendered. It simply causes errors in the cairo_quartz_surface_t backend.

Since we are restricted to using cairo_image_surface_t (which happens to
be faster anyway) we can use the IOSurfaceBaseAddress() to obtain a
mapping of the IOSurfaceRef in user-space. It always uses BGRA 32-bit
with alpha channel even if we will discard the alpha channel as that is
necessary to hit the fast paths in other parts of the platform. Note
that while Cairo says CAIRO_FORMAT_ARGB32, it is really 32-bit BGRA on
little-endian as we expect.

OpenGL will render flipped (Quartz Native Co-ordinates) while Cairo
renders with 0,O in the top-left. We could use cairo_translate() and
cairo_scale() to reverse this, but it looks like some cairo things may
not look quite as right if we do so. To reduce the chances of one-off
bugs this continues to draw as Cairo would normally, but instead uses
an CGAffineTransform in the tiles and some CGRect translation when
swapping buffers to get the same effect.

Changes to OpenGL
=================

To simplify things, removal of all NSOpenGL* related components have
been removed and we strictly use the Core GL (CGL*) API. This probably
should have been done long ago anyay.

Most examples found in the browsers to use IOSurfaceRef with OpenGL are
using Legacy GL and there is still work underway to make this fit in
with the rest of how the GSK GL renderer works.

Since IOSurfaceRef bound to a texture/framebuffer will not have a
default framebuffer ID of 0, we needed to add a default framebuffer id
to the GdkGLContext. GskGLRenderer can use this to setup the command
queue in such a way that our IOSurface destination has been
glBindFramebuffer() as if it were the default drawable.

This stuff is pretty slight-of-hand, so where things are and what needs
flushing when and where has been a bit of an experiment to see what
actually works to get synchronization across subsystems.

Efficient Damages
=================

After we draw with Cairo, we unlock the IOSurfaceRef and the contents
are uploaded to the GPU. To make the contents visible to the app,
we must clear the tiles contents with `layer.contents=nil;` and then
re-apply the IOSurfaceRef. Since the buffer has likely not changed, we
only do this if the tile overlaps the damage region.

This gives the effect of having more tightly controlled damage regions
even though updating the layer would damage be the whole window (as it
is with OpenGL/Metal today with the exception of scissor-rect).

This too can be verified usign "Quartz Debug -> Flash screen udpates".

Frame Synchronized Resize
=========================

In GTK 4, we have the ability to perform sizing changes from compute-size
during the layout phase. Since the macOS backend already tracks window
resizes manually, we can avoid doing the setFrame: immediately and instead
do it within the frame clock's layout phase.

Doing so gives us vastly better resize experience as we're more likely to
get the size-change and updated-contents in the same frame on screen. It
makes things feel "connected" in a way they weren't before.

Some additional effort to tweak gravity during the process is also
necessary but we were already doing that in the GTK 4 backend.

Backporting
===========

The design here has made an attempt to make it possible to backport by
keeping GdkMacosBuffer, GdkMacosLayer, and GdkMacosTile fairly
independent. There may be an opportunity to integrate this into GTK 3's
quartz backend with a fair bit of work. Doing so could improve the
situation for applications which are damage-rich such as The GIMP.
2022-02-22 12:01:29 -08:00
Matthias Clasen
9ea43096d4 Merge branch 'wip/chergert/macos-fix-event-filter' into 'main'
macos: improve event filtering for foreign panels

See merge request GNOME/gtk!4495
2022-02-22 19:36:43 +00:00
Matthias Clasen
e9ffe8f212 Merge branch 'wip/chergert/macos-fix-fullscreen' into 'main'
macos: allow windows to enter fullscreen

See merge request GNOME/gtk!4494
2022-02-22 19:36:20 +00:00
Matthias Clasen
9fccbeaa75 Merge branch 'wip/chergert/macos-fix-backdrop' into 'main'
macos: fix backdrop when displaying popover

See merge request GNOME/gtk!4505
2022-02-22 17:54:20 +00:00
Matthias Clasen
d35bac452b Merge branch 'wip/chergert/macos-fix-toplevel-resize' into 'main'
macos: fix configure, move-resize, and compute-size

See merge request GNOME/gtk!4486
2022-02-22 13:10:34 +00:00
Christian Hergert
c0ede8d46e macos: fix backdrop when displaying popover
Previously, the popover would cause the window to go into the :backdrop
state which is not what we want for consistency with other platforms. This
fixes that by walking up the surface chain when we get notified of
loosing or acquiring "key" input from the display server.
2022-02-22 00:08:37 -08:00
Christian Hergert
db77204a52 macos: improve event filtering for foreign panels
We might have panels with controls in them where the window is running in
another process. The control could have a wrapper window which we would
see from this process. This can happen with the GtkFileChooserNative, but
any NSSavePanel in macOS 10.15+ is out of process (not just sandboxed
applications).
2022-02-18 03:39:52 -08:00
Christian Hergert
4c08d1643f macos: fix configure, move-resize, and compute-size
This significantly cleans up how we handle various move-resize, compute-
size, and configure (notification of changes) in the macOS GDK backend.

Originally when prototyping this backend, there were some bits that came
over from the quartz backend and some bits which did not. It got confusing
and so this makes an attempt to knock down all that technical debt.

It is much simpler now in that the GdkMacosSurface makes requests of the
GdkMacosWindow, and the GdkMacosWindow notifies the GdkMacosSurface of
changes that happen.

User resizes are delayed until the next compute-size so that we are much
closer to the layout phase, reducing chances for in-between frames.

This also improves the situation of leaving maximized state so that a
grab and drag feels like you'd expect on other platforms.

I removed the opacity hack we had in before, because that is all coming
out anyway and it's a bit obnoxious to maintain through the async flows
here.
2022-02-18 02:50:46 -08:00
Christian Hergert
592436503c macos: allow windows to enter fullscreen
This fixes GTK's NSWindow for toplevels so that they are allowed to enter
fullscreen. We were already handlign the state transitions from the
setStyleMask: halper, but we didn't previously tell the window we are
allowed to transition into that.

There is a bit of a mismatch here in that GTK doesn't have any such flag
that determines if a window is "allowed" by policy to enter fullscreen
since window managers on Linux are free to do that at will.
2022-02-18 01:54:10 -08:00
Christian Hergert
853ef43dae macos: fix keyboard input on popovers
GdkPopup can also become the "key" window (just not the "main" window).
2022-02-16 17:53:59 -08:00
Christian Hergert
3c9687fcf1 macos: add helper to check if surface is opaque 2022-02-16 03:08:55 -08:00
Christian Hergert
f207402228 macos: use input_region to specify tracking areas
We want our tracking area to be limited to the input region so that we
don't pass along events outside of them for the window. This improves the
chances we click-out of a popover with a large shadow.

This still doesn't let us pass-through clicks for large shadows on top-
level windows though.
2022-02-16 03:07:51 -08:00
Christian Hergert
a080f1197a macos: ignore mouse events outside tracking area
We also need to ignore events outside the tracking areas when we are
translating them from NSevent into GdkEvent.
2022-02-16 03:06:51 -08:00
Christian Hergert
8f0b9bf5ae macos: fix incorrect signal disconnect 2022-02-16 01:46:25 -08:00