summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2022-03-16 20:03:38 +0000
committerMatthias Clasen <mclasen@redhat.com>2022-03-16 20:03:38 +0000
commit17e0618ff65cb301e6aad08af3a0fe544c1c6026 (patch)
tree536b1f999199ee46dd10749da6f620177e9de599
parent38bbcb74115b69263a63fae3a70bc6c11e701814 (diff)
parent73d5f7061b3021ccf0c66807ed33630b4fc6ac2e (diff)
downloadgtk+-17e0618ff65cb301e6aad08af3a0fe544c1c6026.tar.gz
Merge branch 'wip/chergert/for-4-6' into 'gtk-4-6'
backport macOS fixes to gtk-4-6 See merge request GNOME/gtk!4578
-rw-r--r--gdk/macos/GdkMacosView.c14
-rw-r--r--gdk/macos/GdkMacosWindow.c36
-rw-r--r--gdk/macos/GdkMacosWindow.h1
-rw-r--r--gdk/macos/gdkdisplaylinksource.c85
-rw-r--r--gdk/macos/gdkdisplaylinksource.h17
-rw-r--r--gdk/macos/gdkmacosbuffer-private.h2
-rw-r--r--gdk/macos/gdkmacosbuffer.c41
-rw-r--r--gdk/macos/gdkmacoscairocontext.c120
-rw-r--r--gdk/macos/gdkmacosdisplay-feedback.c105
-rw-r--r--gdk/macos/gdkmacosdisplay-private.h27
-rw-r--r--gdk/macos/gdkmacosdisplay-settings.c10
-rw-r--r--gdk/macos/gdkmacosdisplay-translate.c114
-rw-r--r--gdk/macos/gdkmacosdisplay-wm.c82
-rw-r--r--gdk/macos/gdkmacosdisplay.c263
-rw-r--r--gdk/macos/gdkmacosglcontext-private.h2
-rw-r--r--gdk/macos/gdkmacosglcontext.c19
-rw-r--r--gdk/macos/gdkmacosmonitor-private.h19
-rw-r--r--gdk/macos/gdkmacosmonitor.c177
-rw-r--r--gdk/macos/gdkmacospopupsurface.c41
-rw-r--r--gdk/macos/gdkmacossurface-private.h11
-rw-r--r--gdk/macos/gdkmacossurface.c328
-rw-r--r--gdk/macos/gdkmacostoplevelsurface.c45
-rw-r--r--gdk/macos/meson.build1
-rw-r--r--gtk/gtkscrolledwindow.c29
24 files changed, 1055 insertions, 534 deletions
diff --git a/gdk/macos/GdkMacosView.c b/gdk/macos/GdkMacosView.c
index 52a55a7cef..18de78aa19 100644
--- a/gdk/macos/GdkMacosView.c
+++ b/gdk/macos/GdkMacosView.c
@@ -24,6 +24,7 @@
#import "GdkMacosLayer.h"
#import "GdkMacosView.h"
+#import "GdkMacosWindow.h"
@implementation GdkMacosView
@@ -56,6 +57,19 @@
return NO;
}
+-(void)mouseDown:(NSEvent *)nsevent
+{
+ if ([(GdkMacosWindow *)[self window] needsMouseDownQuirk])
+ /* We should only hit this when we are trying to click through
+ * the shadow of a window into another window. Just request
+ * that the application not activate this window on mouseUp.
+ * See gdkmacosdisplay-translate.c for the other half of this.
+ */
+ [NSApp preventWindowOrdering];
+ else
+ [super mouseDown:nsevent];
+}
+
-(void)setFrame:(NSRect)rect
{
[super setFrame:rect];
diff --git a/gdk/macos/GdkMacosWindow.c b/gdk/macos/GdkMacosWindow.c
index f879decbc9..23b3f5a3f3 100644
--- a/gdk/macos/GdkMacosWindow.c
+++ b/gdk/macos/GdkMacosWindow.c
@@ -253,7 +253,8 @@ typedef NSString *CALayerContentsGravity;
-(BOOL)canBecomeKeyWindow
{
- return GDK_IS_TOPLEVEL (gdk_surface) || GDK_IS_POPUP (gdk_surface);
+ return GDK_IS_TOPLEVEL (gdk_surface) ||
+ (GDK_IS_POPUP (gdk_surface) && GDK_SURFACE (gdk_surface)->input_region != NULL);
}
-(void)showAndMakeKey:(BOOL)makeKey
@@ -261,9 +262,12 @@ typedef NSString *CALayerContentsGravity;
inShowOrHide = YES;
if (makeKey && [self canBecomeKeyWindow])
- [self makeKeyAndOrderFront:nil];
+ [self makeKeyAndOrderFront:self];
else
- [self orderFront:nil];
+ [self orderFront:self];
+
+ if (makeKey && [self canBecomeMainWindow])
+ [self makeMainWindow];
inShowOrHide = NO;
@@ -373,9 +377,17 @@ typedef NSString *CALayerContentsGravity;
_gdk_macos_surface_configure ([self gdkSurface]);
}
-- (void)windowDidResize:(NSNotification *)notification
+-(void)windowDidResize:(NSNotification *)notification
{
- _gdk_macos_surface_configure ([self gdkSurface]);
+ _gdk_macos_surface_configure (gdk_surface);
+
+ /* If we're using server-side decorations, this notification is coming
+ * in from a display-side change. We need to request a layout in
+ * addition to the configure event.
+ */
+ if (GDK_IS_MACOS_TOPLEVEL_SURFACE (gdk_surface) &&
+ GDK_MACOS_TOPLEVEL_SURFACE (gdk_surface)->decorated)
+ gdk_surface_request_layout (GDK_SURFACE (gdk_surface));
}
/* Used by gdkmacosdisplay-translate.c to decide if our sendEvent() handler
@@ -668,7 +680,12 @@ typedef NSString *CALayerContentsGravity;
is_opaque = (([self styleMask] & NSWindowStyleMaskTitled) != 0);
if (was_fullscreen != is_fullscreen)
- _gdk_macos_surface_update_fullscreen_state (gdk_surface);
+ {
+ if (was_fullscreen)
+ [self setFrame:lastUnfullscreenFrame display:NO];
+
+ _gdk_macos_surface_update_fullscreen_state (gdk_surface);
+ }
if (was_opaque != is_opaque)
{
@@ -753,7 +770,6 @@ typedef NSString *CALayerContentsGravity;
-(void)windowWillExitFullScreen:(NSNotification *)aNotification
{
- [self setFrame:lastUnfullscreenFrame display:NO];
}
-(void)windowDidExitFullScreen:(NSNotification *)aNotification
@@ -814,4 +830,10 @@ typedef NSString *CALayerContentsGravity;
[(GdkMacosView *)[self contentView] swapBuffer:buffer withDamage:damage];
}
+-(BOOL)needsMouseDownQuirk
+{
+ return GDK_IS_MACOS_TOPLEVEL_SURFACE (gdk_surface) &&
+ !GDK_MACOS_TOPLEVEL_SURFACE (gdk_surface)->decorated;
+}
+
@end
diff --git a/gdk/macos/GdkMacosWindow.h b/gdk/macos/GdkMacosWindow.h
index cb8b2efad1..3a514ea857 100644
--- a/gdk/macos/GdkMacosWindow.h
+++ b/gdk/macos/GdkMacosWindow.h
@@ -69,5 +69,6 @@
-(BOOL)trackManualResize;
-(void)setDecorated:(BOOL)decorated;
-(void)swapBuffer:(GdkMacosBuffer *)buffer withDamage:(const cairo_region_t *)damage;
+-(BOOL)needsMouseDownQuirk;
@end
diff --git a/gdk/macos/gdkdisplaylinksource.c b/gdk/macos/gdkdisplaylinksource.c
index 292b8be519..6a613b40a4 100644
--- a/gdk/macos/gdkdisplaylinksource.c
+++ b/gdk/macos/gdkdisplaylinksource.c
@@ -26,7 +26,9 @@
#include "gdkdisplaylinksource.h"
+#include "gdkdebug.h"
#include "gdkmacoseventsource-private.h"
+#include "gdkmacosmonitor-private.h"
#include "gdk-private.h"
static gint64 host_to_frame_clock_time (gint64 val);
@@ -65,7 +67,7 @@ gdk_display_link_source_dispatch (GSource *source,
impl->needs_dispatch = FALSE;
- if (callback != NULL)
+ if (!impl->paused && callback != NULL)
ret = callback (user_data);
return ret;
@@ -76,7 +78,9 @@ gdk_display_link_source_finalize (GSource *source)
{
GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
- CVDisplayLinkStop (impl->display_link);
+ if (!impl->paused)
+ CVDisplayLinkStop (impl->display_link);
+
CVDisplayLinkRelease (impl->display_link);
}
@@ -90,12 +94,18 @@ static GSourceFuncs gdk_display_link_source_funcs = {
void
gdk_display_link_source_pause (GdkDisplayLinkSource *source)
{
+ g_return_if_fail (source->paused == FALSE);
+
+ source->paused = TRUE;
CVDisplayLinkStop (source->display_link);
}
void
gdk_display_link_source_unpause (GdkDisplayLinkSource *source)
{
+ g_return_if_fail (source->paused == TRUE);
+
+ source->paused = FALSE;
CVDisplayLinkStart (source->display_link);
}
@@ -147,6 +157,7 @@ gdk_display_link_source_frame_cb (CVDisplayLinkRef display_link,
/**
* gdk_display_link_source_new:
+ * @display_id: the identifier of the monitor
*
* Creates a new `GSource` that will activate the dispatch function upon
* notification from a CVDisplayLink that a new frame should be drawn.
@@ -159,41 +170,61 @@ gdk_display_link_source_frame_cb (CVDisplayLinkRef display_link,
* Returns: (transfer full): A newly created `GSource`
*/
GSource *
-gdk_display_link_source_new (void)
+gdk_display_link_source_new (CGDirectDisplayID display_id,
+ CGDisplayModeRef mode)
{
GdkDisplayLinkSource *impl;
GSource *source;
- CVReturn ret;
- double period;
+ char *name;
source = g_source_new (&gdk_display_link_source_funcs, sizeof *impl);
impl = (GdkDisplayLinkSource *)source;
+ impl->display_id = display_id;
+ impl->paused = TRUE;
- /*
- * Create our link based on currently connected displays.
- * If there are multiple displays, this will be something that tries
- * to work for all of them. In the future, we may want to explore multiple
- * links based on the connected displays.
+ /* Create DisplayLink for timing information for the display in
+ * question so that we can produce graphics for that display at whatever
+ * rate it can provide.
*/
- ret = CVDisplayLinkCreateWithActiveCGDisplays (&impl->display_link);
- if (ret != kCVReturnSuccess)
+ if (CVDisplayLinkCreateWithCGDisplay (display_id, &impl->display_link) != kCVReturnSuccess)
{
g_warning ("Failed to initialize CVDisplayLink!");
- return source;
+ goto failure;
}
- /*
- * Determine our nominal period between frames.
- */
- period = CVDisplayLinkGetActualOutputVideoRefreshPeriod (impl->display_link);
- if (period == 0.0)
- period = 1.0 / 60.0;
- impl->refresh_interval = period * 1000000L;
- impl->refresh_rate = 1.0 / period * 1000L;
-
- /*
- * Wire up our callback to be executed within the high-priority thread.
- */
+ impl->refresh_rate = CGDisplayModeGetRefreshRate (mode) * 1000.0;
+
+ if (impl->refresh_rate == 0)
+ {
+ const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod (impl->display_link);
+ if (!(time.flags & kCVTimeIsIndefinite))
+ impl->refresh_rate = (double)time.timeScale / (double)time.timeValue * 1000.0;
+ }
+
+ if (impl->refresh_rate != 0)
+ {
+ impl->refresh_interval = 1000000.0 / (double)impl->refresh_rate * 1000.0;
+ }
+ else
+ {
+ double period = CVDisplayLinkGetActualOutputVideoRefreshPeriod (impl->display_link);
+
+ if (period == 0.0)
+ period = 1.0 / 60.0;
+
+ impl->refresh_rate = 1.0 / period * 1000L;
+ impl->refresh_interval = period * 1000000L;
+ }
+
+ name = _gdk_macos_monitor_get_connector_name (display_id);
+ GDK_NOTE (MISC,
+ g_message ("Monitor \"%s\" discovered with Refresh Rate %d and Interval %"G_GINT64_FORMAT,
+ name ? name : "unknown",
+ impl->refresh_rate,
+ impl->refresh_interval));
+ g_free (name);
+
+ /* Wire up our callback to be executed within the high-priority thread. */
CVDisplayLinkSetOutputCallback (impl->display_link,
gdk_display_link_source_frame_cb,
source);
@@ -201,6 +232,10 @@ gdk_display_link_source_new (void)
g_source_set_static_name (source, "[gdk] quartz frame clock");
return source;
+
+failure:
+ g_source_unref (source);
+ return NULL;
}
static gint64
diff --git a/gdk/macos/gdkdisplaylinksource.h b/gdk/macos/gdkdisplaylinksource.h
index ed769b59f8..6f465907a2 100644
--- a/gdk/macos/gdkdisplaylinksource.h
+++ b/gdk/macos/gdkdisplaylinksource.h
@@ -30,17 +30,20 @@ G_BEGIN_DECLS
typedef struct
{
- GSource source;
+ GSource source;
- CVDisplayLinkRef display_link;
- gint64 refresh_interval;
- guint refresh_rate;
+ CGDirectDisplayID display_id;
+ CVDisplayLinkRef display_link;
+ gint64 refresh_interval;
+ guint refresh_rate;
+ guint paused : 1;
- volatile gint64 presentation_time;
- volatile guint needs_dispatch;
+ volatile gint64 presentation_time;
+ volatile guint needs_dispatch;
} GdkDisplayLinkSource;
-GSource *gdk_display_link_source_new (void);
+GSource *gdk_display_link_source_new (CGDirectDisplayID display_id,
+ CGDisplayModeRef mode);
void gdk_display_link_source_pause (GdkDisplayLinkSource *source);
void gdk_display_link_source_unpause (GdkDisplayLinkSource *source);
diff --git a/gdk/macos/gdkmacosbuffer-private.h b/gdk/macos/gdkmacosbuffer-private.h
index 6be201147c..4b446a7212 100644
--- a/gdk/macos/gdkmacosbuffer-private.h
+++ b/gdk/macos/gdkmacosbuffer-private.h
@@ -41,6 +41,8 @@ GdkMacosBuffer *_gdk_macos_buffer_new (int width
IOSurfaceRef _gdk_macos_buffer_get_native (GdkMacosBuffer *self);
void _gdk_macos_buffer_lock (GdkMacosBuffer *self);
void _gdk_macos_buffer_unlock (GdkMacosBuffer *self);
+void _gdk_macos_buffer_read_lock (GdkMacosBuffer *self);
+void _gdk_macos_buffer_read_unlock (GdkMacosBuffer *self);
guint _gdk_macos_buffer_get_width (GdkMacosBuffer *self);
guint _gdk_macos_buffer_get_height (GdkMacosBuffer *self);
guint _gdk_macos_buffer_get_stride (GdkMacosBuffer *self);
diff --git a/gdk/macos/gdkmacosbuffer.c b/gdk/macos/gdkmacosbuffer.c
index ac99302ee4..eb8a719dbc 100644
--- a/gdk/macos/gdkmacosbuffer.c
+++ b/gdk/macos/gdkmacosbuffer.c
@@ -192,6 +192,45 @@ _gdk_macos_buffer_unlock (GdkMacosBuffer *self)
IOSurfaceUnlock (self->surface, 0, NULL);
}
+/**
+ * _gdk_macos_buffer_lock_readonly:
+ *
+ * Like _gdk_macos_buffer_lock() but uses the read-only flag to
+ * indicate we are not interested in retrieving the updates from
+ * the GPU before modifying the CPU-side cache.
+ *
+ * Must be used with _gdk_macos_buffer_unlock_readonly().
+ */
+void
+_gdk_macos_buffer_read_lock (GdkMacosBuffer *self)
+{
+ kern_return_t ret;
+
+ g_return_if_fail (GDK_IS_MACOS_BUFFER (self));
+ g_return_if_fail (self->lock_count == 0);
+
+ self->lock_count++;
+
+ ret = IOSurfaceLock (self->surface, kIOSurfaceLockReadOnly, NULL);
+
+ g_return_if_fail (ret == KERN_SUCCESS);
+}
+
+void
+_gdk_macos_buffer_read_unlock (GdkMacosBuffer *self)
+{
+ kern_return_t ret;
+
+ g_return_if_fail (GDK_IS_MACOS_BUFFER (self));
+ g_return_if_fail (self->lock_count == 1);
+
+ self->lock_count--;
+
+ ret = IOSurfaceUnlock (self->surface, kIOSurfaceLockReadOnly, NULL);
+
+ g_return_if_fail (ret == KERN_SUCCESS);
+}
+
guint
_gdk_macos_buffer_get_width (GdkMacosBuffer *self)
{
@@ -242,7 +281,7 @@ _gdk_macos_buffer_set_damage (GdkMacosBuffer *self,
return;
g_clear_pointer (&self->damage, cairo_region_destroy);
- self->damage = cairo_region_reference (damage);
+ self->damage = cairo_region_copy (damage);
}
gpointer
diff --git a/gdk/macos/gdkmacoscairocontext.c b/gdk/macos/gdkmacoscairocontext.c
index 041f1193e6..31eecd5df6 100644
--- a/gdk/macos/gdkmacoscairocontext.c
+++ b/gdk/macos/gdkmacoscairocontext.c
@@ -42,19 +42,6 @@ struct _GdkMacosCairoContextClass
G_DEFINE_TYPE (GdkMacosCairoContext, _gdk_macos_cairo_context, GDK_TYPE_CAIRO_CONTEXT)
-static const cairo_user_data_key_t buffer_key;
-
-static void
-unlock_buffer (gpointer data)
-{
- GdkMacosBuffer *buffer = data;
-
- g_assert (GDK_IS_MACOS_BUFFER (buffer));
-
- _gdk_macos_buffer_unlock (buffer);
- g_clear_object (&buffer);
-}
-
static cairo_t *
_gdk_macos_cairo_context_cairo_create (GdkCairoContext *cairo_context)
{
@@ -106,12 +93,9 @@ _gdk_macos_cairo_context_cairo_create (GdkCairoContext *cairo_context)
stride);
cairo_surface_set_device_scale (image_surface, scale, scale);
- /* Lock the buffer so we can modify it safely */
- _gdk_macos_buffer_lock (buffer);
- cairo_surface_set_user_data (image_surface,
- &buffer_key,
- g_object_ref (buffer),
- unlock_buffer);
+ /* The buffer should already be locked at this point, and will
+ * be unlocked as part of end_frame.
+ */
if (!(cr = cairo_create (image_surface)))
goto failure;
@@ -159,40 +143,120 @@ failure:
}
static void
+copy_surface_data (GdkMacosBuffer *from,
+ GdkMacosBuffer *to,
+ const cairo_region_t *region,
+ int scale)
+{
+ const guint8 *from_base;
+ guint8 *to_base;
+ guint from_stride;
+ guint to_stride;
+ guint n_rects;
+
+ g_assert (GDK_IS_MACOS_BUFFER (from));
+ g_assert (GDK_IS_MACOS_BUFFER (to));
+ g_assert (region != NULL);
+ g_assert (!cairo_region_is_empty (region));
+
+ from_base = _gdk_macos_buffer_get_data (from);
+ from_stride = _gdk_macos_buffer_get_stride (from);
+
+ to_base = _gdk_macos_buffer_get_data (to);
+ to_stride = _gdk_macos_buffer_get_stride (to);
+
+ n_rects = cairo_region_num_rectangles (region);
+
+ for (guint i = 0; i < n_rects; i++)
+ {
+ cairo_rectangle_int_t rect;
+ int y2;
+
+ cairo_region_get_rectangle (region, i, &rect);
+
+ rect.y *= scale;
+ rect.height *= scale;
+ rect.x *= scale;
+ rect.width *= scale;
+
+ y2 = rect.y + rect.height;
+
+ for (int y = rect.y; y < y2; y++)
+ memcpy (&to_base[y * to_stride + rect.x * 4],
+ &from_base[y * from_stride + rect.x * 4],
+ rect.width * 4);
+ }
+}
+
+static void
_gdk_macos_cairo_context_begin_frame (GdkDrawContext *draw_context,
gboolean prefers_high_depth,
cairo_region_t *region)
{
GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context;
GdkMacosBuffer *buffer;
- GdkSurface *surface;
+ GdkMacosSurface *surface;
g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (self));
[CATransaction begin];
[CATransaction setDisableActions:YES];
- surface = gdk_draw_context_get_surface (draw_context);
- buffer = _gdk_macos_surface_get_buffer (GDK_MACOS_SURFACE (surface));
+ surface = GDK_MACOS_SURFACE (gdk_draw_context_get_surface (draw_context));
+ buffer = _gdk_macos_surface_get_buffer (surface);
_gdk_macos_buffer_set_damage (buffer, region);
_gdk_macos_buffer_set_flipped (buffer, FALSE);
+
+ _gdk_macos_buffer_lock (buffer);
+
+ /* If there is damage that was on the previous frame that is not on
+ * this frame, we need to copy that rendered region over to the back
+ * buffer so that when swapping buffers, we still have that content.
+ * This is done with a read-only lock on the IOSurface to avoid
+ * invalidating the buffer contents.
+ */
+ if (surface->front != NULL)
+ {
+ const cairo_region_t *previous = _gdk_macos_buffer_get_damage (surface->front);
+
+ if (previous != NULL)
+ {
+ cairo_region_t *copy;
+
+ copy = cairo_region_copy (previous);
+ cairo_region_subtract (copy, region);
+
+ if (!cairo_region_is_empty (copy))
+ {
+ int scale = gdk_surface_get_scale_factor (GDK_SURFACE (surface));
+
+ _gdk_macos_buffer_read_lock (surface->front);
+ copy_surface_data (surface->front, buffer, copy, scale);
+ _gdk_macos_buffer_read_unlock (surface->front);
+ }
+
+ cairo_region_destroy (copy);
+ }
+ }
}
static void
_gdk_macos_cairo_context_end_frame (GdkDrawContext *draw_context,
cairo_region_t *painted)
{
+ GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context;
+ GdkMacosSurface *surface;
GdkMacosBuffer *buffer;
- GdkSurface *surface;
- g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (draw_context));
+ g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (self));
- surface = gdk_draw_context_get_surface (draw_context);
- buffer = _gdk_macos_surface_get_buffer (GDK_MACOS_SURFACE (surface));
+ surface = GDK_MACOS_SURFACE (gdk_draw_context_get_surface (draw_context));
+ buffer = _gdk_macos_surface_get_buffer (surface);
+
+ _gdk_macos_buffer_unlock (buffer);
- _gdk_macos_surface_swap_buffers (GDK_MACOS_SURFACE (surface), painted);
- _gdk_macos_buffer_set_damage (buffer, NULL);
+ _gdk_macos_surface_swap_buffers (surface, painted);
[CATransaction commit];
}
diff --git a/gdk/macos/gdkmacosdisplay-feedback.c b/gdk/macos/gdkmacosdisplay-feedback.c
new file mode 100644
index 0000000000..868ac0fbcd
--- /dev/null
+++ b/gdk/macos/gdkmacosdisplay-feedback.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright © 2022 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include <AppKit/AppKit.h>
+
+#include "gdkmacosdisplay-private.h"
+#include "gdkmacossurface-private.h"
+
+static void
+gdk_macos_display_user_defaults_changed_cb (CFNotificationCenterRef center,
+ void *observer,
+ CFStringRef name,
+ const void *object,
+ CFDictionaryRef userInfo)
+{
+ GdkMacosDisplay *self = observer;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+
+ _gdk_macos_display_reload_settings (self);
+}
+
+static void
+gdk_macos_display_monitors_changed_cb (CFNotificationCenterRef center,
+ void *observer,
+ CFStringRef name,
+ const void *object,
+ CFDictionaryRef userInfo)
+{
+ GdkMacosDisplay *self = observer;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+
+ _gdk_macos_display_reload_monitors (self);
+
+ /* Now we need to update all our surface positions since they
+ * probably just changed origins.
+ */
+ for (const GList *iter = _gdk_macos_display_get_surfaces (self);
+ iter != NULL;
+ iter = iter->next)
+ {
+ GdkMacosSurface *surface = iter->data;
+
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+
+ _gdk_macos_surface_monitor_changed (surface);
+ }
+}
+
+
+void
+_gdk_macos_display_feedback_init (GdkMacosDisplay *self)
+{
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+
+ CFNotificationCenterAddObserver (CFNotificationCenterGetLocalCenter (),
+ self,
+ gdk_macos_display_monitors_changed_cb,
+ CFSTR ("NSApplicationDidChangeScreenParametersNotification"),
+ NULL,
+ CFNotificationSuspensionBehaviorDeliverImmediately);
+
+ CFNotificationCenterAddObserver (CFNotificationCenterGetDistributedCenter (),
+ self,
+ gdk_macos_display_user_defaults_changed_cb,
+ CFSTR ("NSUserDefaultsDidChangeNotification"),
+ NULL,
+ CFNotificationSuspensionBehaviorDeliverImmediately);
+}
+
+void
+_gdk_macos_display_feedback_destroy (GdkMacosDisplay *self)
+{
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+
+ CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
+ self,
+ CFSTR ("NSApplicationDidChangeScreenParametersNotification"),
+ NULL);
+
+ CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
+ self,
+ CFSTR ("NSUserDefaultsDidChangeNotification"),
+ NULL);
+
+}
diff --git a/gdk/macos/gdkmacosdisplay-private.h b/gdk/macos/gdkmacosdisplay-private.h
index be2290b89a..83ae435e49 100644
--- a/gdk/macos/gdkmacosdisplay-private.h
+++ b/gdk/macos/gdkmacosdisplay-private.h
@@ -43,6 +43,8 @@ G_BEGIN_DECLS
#define GIC_FILTER_PASSTHRU 0
#define GIC_FILTER_FILTERED 1
+#define GDK_MACOS_EVENT_DROP (GdkEvent *)GSIZE_TO_POINTER(1)
+
struct _GdkMacosDisplay
{
GdkDisplay parent_instance;
@@ -68,16 +70,6 @@ struct _GdkMacosDisplay
*/
GQueue sorted_surfaces;
- /* Our CVDisplayLink based GSource which we use to freeze/thaw the
- * GdkFrameClock for the surface.
- */
- GSource *frame_source;
-
- /* A queue of surfaces which we know are awaiting frames to be drawn. This
- * uses the GdkMacosSurface.frame link.
- */
- GQueue awaiting_frames;
-
/* The surface that is receiving keyboard events */
GdkMacosSurface *keyboard_surface;
@@ -92,6 +84,14 @@ struct _GdkMacosDisplay
int min_y;
int max_x;
int max_y;
+
+ /* A GSource to select a new main/key window */
+ guint select_key_in_idle;
+
+ /* Note if we have a key window that is not a GdkMacosWindow
+ * such as a NSPanel used for native dialogs.
+ */
+ guint key_window_is_foregin : 1;
};
struct _GdkMacosDisplayClass
@@ -124,6 +124,8 @@ GdkMonitor *_gdk_macos_display_get_monitor_at_display_coords (GdkMacosDisp
int y);
GdkEvent *_gdk_macos_display_translate (GdkMacosDisplay *self,
NSEvent *event);
+void _gdk_macos_display_feedback_init (GdkMacosDisplay *self);
+void _gdk_macos_display_feedback_destroy (GdkMacosDisplay *self);
void _gdk_macos_display_break_all_grabs (GdkMacosDisplay *self,
guint32 time);
GdkModifierType _gdk_macos_display_get_current_keyboard_modifiers (GdkMacosDisplay *self);
@@ -136,10 +138,6 @@ GdkMacosSurface *_gdk_macos_display_get_surface_at_display_coords (GdkMacosDisp
void _gdk_macos_display_reload_monitors (GdkMacosDisplay *self);
void _gdk_macos_display_surface_removed (GdkMacosDisplay *self,
GdkMacosSurface *surface);
-void _gdk_macos_display_add_frame_callback (GdkMacosDisplay *self,
- GdkMacosSurface *surface);
-void _gdk_macos_display_remove_frame_callback (GdkMacosDisplay *self,
- GdkMacosSurface *surface);
NSWindow *_gdk_macos_display_find_native_under_pointer (GdkMacosDisplay *self,
int *x,
int *y);
@@ -155,7 +153,6 @@ void _gdk_macos_display_surface_resigned_key (GdkMacosDisp
GdkMacosSurface *surface);
void _gdk_macos_display_surface_became_key (GdkMacosDisplay *self,
GdkMacosSurface *surface);
-int _gdk_macos_display_get_nominal_refresh_rate (GdkMacosDisplay *self);
void _gdk_macos_display_clear_sorting (GdkMacosDisplay *self);
const GList *_gdk_macos_display_get_surfaces (GdkMacosDisplay *self);
void _gdk_macos_display_send_button_event (GdkMacosDisplay *self,
diff --git a/gdk/macos/gdkmacosdisplay-settings.c b/gdk/macos/gdkmacosdisplay-settings.c
index e6714f0a14..53d6df0672 100644
--- a/gdk/macos/gdkmacosdisplay-settings.c
+++ b/gdk/macos/gdkmacosdisplay-settings.c
@@ -34,7 +34,7 @@ typedef struct
const char *font_name;
int xft_dpi;
int double_click_time;
- int cursor_blink_timeout;
+ int cursor_blink_time;
guint enable_animations : 1;
guint shell_shows_desktop : 1;
guint shell_shows_menubar : 1;
@@ -65,9 +65,9 @@ _gdk_macos_settings_load (GdkMacosSettings *settings)
ival = [defaults integerForKey:@"NSTextInsertionPointBlinkPeriod"];
if (ival > 0)
- settings->cursor_blink_timeout = ival;
+ settings->cursor_blink_time = ival;
else
- settings->cursor_blink_timeout = 1000;
+ settings->cursor_blink_time = 1000;
settings->primary_button_warps_slider =
[[NSUserDefaults standardUserDefaults] boolForKey:@"AppleScrollerPagingBehavior"] == YES;
@@ -124,9 +124,9 @@ _gdk_macos_display_get_setting (GdkMacosDisplay *self,
g_value_set_int (value, current_settings.xft_dpi);
ret = TRUE;
}
- else if (strcmp (setting, "gtk-cursor-blink-timeout") == 0)
+ else if (strcmp (setting, "gtk-cursor-blink-time") == 0)
{
- g_value_set_int (value, current_settings.cursor_blink_timeout);
+ g_value_set_int (value, current_settings.cursor_blink_time);
ret = TRUE;
}
else if (strcmp (setting, "gtk-double-click-time") == 0)
diff --git a/gdk/macos/gdkmacosdisplay-translate.c b/gdk/macos/gdkmacosdisplay-translate.c
index 8e3cd90b82..7a0b84ccdb 100644
--- a/gdk/macos/gdkmacosdisplay-translate.c
+++ b/gdk/macos/gdkmacosdisplay-translate.c
@@ -612,6 +612,8 @@ fill_scroll_event (GdkMacosDisplay *self,
GdkModifierType state;
GdkDevice *pointer;
GdkEvent *ret = NULL;
+ NSEventPhase phase;
+ NSEventPhase momentumPhase;
GdkSeat *seat;
double dx;
double dy;
@@ -619,11 +621,31 @@ fill_scroll_event (GdkMacosDisplay *self,
g_assert (GDK_IS_MACOS_SURFACE (surface));
g_assert (nsevent != NULL);
+ phase = [nsevent phase];
+ momentumPhase = [nsevent momentumPhase];
+
+ /* Ignore kinetic scroll events from the display server as we already
+ * handle those internally.
+ */
+ if (phase == 0 && momentumPhase != 0)
+ return GDK_MACOS_EVENT_DROP;
+
seat = gdk_display_get_default_seat (GDK_DISPLAY (self));
pointer = gdk_seat_get_pointer (seat);
state = _gdk_macos_display_get_current_mouse_modifiers (self) |
_gdk_macos_display_get_current_keyboard_modifiers (self);
+ /* If we are starting a new phase, send a stop so any previous
+ * scrolling immediately stops.
+ */
+ if (phase == NSEventPhaseMayBegin)
+ return gdk_scroll_event_new (GDK_SURFACE (surface),
+ pointer,
+ NULL,
+ get_time_from_ns_event (nsevent),
+ state,
+ 0.0, 0.0, TRUE);
+
dx = [nsevent deltaX];
dy = [nsevent deltaY];
@@ -667,34 +689,32 @@ fill_scroll_event (GdkMacosDisplay *self,
dy = 0.0;
}
- if (dx != 0.0 || dy != 0.0)
+ if ((dx != 0.0 || dy != 0.0) && ![nsevent hasPreciseScrollingDeltas])
{
- if ([nsevent hasPreciseScrollingDeltas])
- {
- GdkEvent *emulated;
-
- emulated = gdk_scroll_event_new_discrete (GDK_SURFACE (surface),
- pointer,
- NULL,
- get_time_from_ns_event (nsevent),
- state,
- direction,
- TRUE);
- _gdk_event_queue_append (GDK_DISPLAY (self), emulated);
- }
- else
- {
- g_assert (ret == NULL);
-
- ret = gdk_scroll_event_new (GDK_SURFACE (surface),
- pointer,
- NULL,
- get_time_from_ns_event (nsevent),
- state,
- -dx * 32,
- -dy * 32,
- FALSE);
- }
+ g_assert (ret == NULL);
+
+ ret = gdk_scroll_event_new_discrete (GDK_SURFACE (surface),
+ pointer,
+ NULL,
+ get_time_from_ns_event (nsevent),
+ state,
+ direction,
+ FALSE);
+ }
+
+ if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled)
+ {
+ /* The user must have released their fingers in a touchpad
+ * scroll, so try to send a scroll is_stop event.
+ */
+ if (ret != NULL)
+ _gdk_event_queue_append (GDK_DISPLAY (self), g_steal_pointer (&ret));
+ ret = gdk_scroll_event_new (GDK_SURFACE (surface),
+ pointer,
+ NULL,
+ get_time_from_ns_event (nsevent),
+ state,
+ 0.0, 0.0, TRUE);
}
return g_steal_pointer (&ret);
@@ -1066,6 +1086,7 @@ _gdk_macos_display_translate (GdkMacosDisplay *self,
GdkMacosSurface *surface;
GdkMacosWindow *window;
NSEventType event_type;
+ NSWindow *event_window;
GdkEvent *ret = NULL;
int x;
int y;
@@ -1108,6 +1129,15 @@ _gdk_macos_display_translate (GdkMacosDisplay *self,
return NULL;
}
+ /* If the event was delivered to NSWindow that is foreign (or rather,
+ * Cocoa native), then we should pass the event along to that window.
+ */
+ if ((event_window = [nsevent window]) && !GDK_IS_MACOS_WINDOW (event_window))
+ return NULL;
+
+ /* If we can't find a GdkSurface to deliver the event to, then we
+ * should pass it along to the NSApp.
+ */
if (!(surface = find_surface_for_ns_event (self, nsevent, &x, &y)))
return NULL;
@@ -1139,15 +1169,31 @@ _gdk_macos_display_translate (GdkMacosDisplay *self,
if (test_resize (nsevent, surface, x, y))
return NULL;
- if ((event_type == NSEventTypeRightMouseDown ||
- event_type == NSEventTypeOtherMouseDown ||
- event_type == NSEventTypeLeftMouseDown))
+ if (event_type == NSEventTypeRightMouseDown ||
+ event_type == NSEventTypeOtherMouseDown ||
+ event_type == NSEventTypeLeftMouseDown)
{
if (![NSApp isActive])
[NSApp activateIgnoringOtherApps:YES];
if (![window isKeyWindow])
- [window makeKeyWindow];
+ {
+ NSWindow *orig_window = [nsevent window];
+
+ /* To get NSApp to supress activating the window we might
+ * have clicked through the shadow of, we need to dispatch
+ * the event and handle it in GdkMacosView:mouseDown to call
+ * [NSApp preventWindowOrdering]. Calling it here will not
+ * do anything as the event is not registered.
+ */
+ if (orig_window &&
+ GDK_IS_MACOS_WINDOW (orig_window) &&
+ [(GdkMacosWindow *)orig_window needsMouseDownQuirk])
+ [NSApp sendEvent:nsevent];
+
+ [window showAndMakeKey:YES];
+ _gdk_macos_display_clear_sorting (self);
+ }
}
switch ((int)event_type)
@@ -1180,7 +1226,11 @@ _gdk_macos_display_translate (GdkMacosDisplay *self,
GdkDevice *pointer = gdk_seat_get_pointer (seat);
GdkDeviceGrabInfo *grab = _gdk_display_get_last_device_grab (GDK_DISPLAY (self), pointer);
- if (grab == NULL)
+ if ([(GdkMacosWindow *)window isInManualResizeOrMove])
+ {
+ ret = GDK_MACOS_EVENT_DROP;
+ }
+ else if (grab == NULL)
{
if (event_type == NSEventTypeMouseExited)
[[NSCursor arrowCursor] set];
diff --git a/gdk/macos/gdkmacosdisplay-wm.c b/gdk/macos/gdkmacosdisplay-wm.c
index a0dd6dddae..4f0672013c 100644
--- a/gdk/macos/gdkmacosdisplay-wm.c
+++ b/gdk/macos/gdkmacosdisplay-wm.c
@@ -20,10 +20,13 @@
#include "config.h"
#include "gdkmacosdisplay-private.h"
-#include "gdkmacosmonitor.h"
+#include "gdkmacosmonitor-private.h"
#include "gdkmacossurface-private.h"
#include "gdkmacostoplevelsurface-private.h"
+#define WARP_OFFSET_X 15
+#define WARP_OFFSET_Y 15
+
static void
_gdk_macos_display_position_toplevel_with_parent (GdkMacosDisplay *self,
GdkMacosSurface *surface,
@@ -33,52 +36,49 @@ _gdk_macos_display_position_toplevel_with_parent (GdkMacosDisplay *self,
{
GdkRectangle surface_rect;
GdkRectangle parent_rect;
- GdkRectangle workarea;
GdkMonitor *monitor;
g_assert (GDK_IS_MACOS_DISPLAY (self));
g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (surface));
g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (parent));
- /* If x/y is set, we should place relative to parent */
- if (GDK_SURFACE (surface)->x != 0 || GDK_SURFACE (surface)->y != 0)
- {
- *x = parent->root_x + GDK_SURFACE (surface)->x;
- *y = parent->root_y + GDK_SURFACE (surface)->y;
- return;
- }
+ monitor = _gdk_macos_surface_get_best_monitor (parent);
/* Try to center on top of the parent but also try to make the whole thing
* visible in case that lands us under the topbar/panel/etc.
*/
- surface_rect.x = surface->root_x + surface->shadow_left;
- surface_rect.y = surface->root_y + surface->shadow_top;
+ parent_rect.x = parent->root_x + parent->shadow_left;
+ parent_rect.y = parent->root_y + parent->shadow_top;
+ parent_rect.width = GDK_SURFACE (parent)->width - parent->shadow_left - parent->shadow_right;
+ parent_rect.height = GDK_SURFACE (parent)->height - parent->shadow_top - parent->shadow_bottom;
+
surface_rect.width = GDK_SURFACE (surface)->width - surface->shadow_left - surface->shadow_right;
surface_rect.height = GDK_SURFACE (surface)->height - surface->shadow_top - surface->shadow_bottom;
-
- parent_rect.x = parent->root_x + surface->shadow_left;
- parent_rect.y = parent->root_y + surface->shadow_top;
- parent_rect.width = GDK_SURFACE (parent)->width - surface->shadow_left - surface->shadow_right;
- parent_rect.height = GDK_SURFACE (parent)->height - surface->shadow_top - surface->shadow_bottom;
-
- /* Try to place centered atop parent */
surface_rect.x = parent_rect.x + ((parent_rect.width - surface_rect.width) / 2);
surface_rect.y = parent_rect.y + ((parent_rect.height - surface_rect.height) / 2);
- /* Now make sure that we don't overlap the top-bar */
- monitor = _gdk_macos_surface_get_best_monitor (parent);
- gdk_macos_monitor_get_workarea (monitor, &workarea);
-
- if (surface_rect.x < workarea.x)
- surface_rect.x = workarea.x;
-
- if (surface_rect.y < workarea.y)
- surface_rect.y = workarea.y;
+ _gdk_macos_monitor_clamp (GDK_MACOS_MONITOR (monitor), &surface_rect);
*x = surface_rect.x - surface->shadow_left;
*y = surface_rect.y - surface->shadow_top;
}
+static inline gboolean
+has_surface_at_origin (const GList *surfaces,
+ int x,
+ int y)
+{
+ for (const GList *iter = surfaces; iter; iter = iter->next)
+ {
+ GdkMacosSurface *surface = iter->data;
+
+ if (surface->root_x == x && surface->root_y == y)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static void
_gdk_macos_display_position_toplevel (GdkMacosDisplay *self,
GdkMacosSurface *surface,
@@ -87,6 +87,7 @@ _gdk_macos_display_position_toplevel (GdkMacosDisplay *self,
{
cairo_rectangle_int_t surface_rect;
GdkRectangle workarea;
+ const GList *surfaces;
GdkMonitor *monitor;
CGPoint mouse;
@@ -103,16 +104,29 @@ _gdk_macos_display_position_toplevel (GdkMacosDisplay *self,
surface_rect.x = workarea.x + ((workarea.width - surface_rect.width) / 2);
surface_rect.y = workarea.y + ((workarea.height - surface_rect.height) / 2);
- if (surface_rect.x < workarea.x)
- surface_rect.x = workarea.x;
-
- if (surface_rect.y < workarea.y)
- surface_rect.y = workarea.y;
-
- /* TODO: If there is another window at this same position, perhaps we should move it */
+ _gdk_macos_monitor_clamp (GDK_MACOS_MONITOR (surface->best_monitor), &surface_rect);
*x = surface_rect.x - surface->shadow_left;
*y = surface_rect.y - surface->shadow_top;
+
+ /* Try to see if there are any other surfaces at this origin and if so,
+ * adjust until we get something better.
+ */
+ surfaces = _gdk_macos_display_get_surfaces (self);
+ while (has_surface_at_origin (surfaces, *x, *y))
+ {
+ *x += WARP_OFFSET_X;
+ *y += WARP_OFFSET_Y;
+
+ /* If we reached the bottom right, just bail and try the workspace origin */
+ if (*x + surface->shadow_left + WARP_OFFSET_X > workarea.x + workarea.width ||
+ *y + surface->shadow_top + WARP_OFFSET_Y > workarea.y + workarea.height)
+ {
+ *x = workarea.x - surface->shadow_left;
+ *y = workarea.y - surface->shadow_top;
+ return;
+ }
+ }
}
/*<private>
diff --git a/gdk/macos/gdkmacosdisplay.c b/gdk/macos/gdkmacosdisplay.c
index 74095504a2..d85a744563 100644
--- a/gdk/macos/gdkmacosdisplay.c
+++ b/gdk/macos/gdkmacosdisplay.c
@@ -156,49 +156,11 @@ gdk_macos_display_update_bounds (GdkMacosDisplay *self)
self->width = self->max_x - self->min_x;
self->height = self->max_y - self->min_y;
- GDK_END_MACOS_ALLOC_POOL;
-}
-
-static void
-gdk_macos_display_monitors_changed_cb (CFNotificationCenterRef center,
- void *observer,
- CFStringRef name,
- const void *object,
- CFDictionaryRef userInfo)
-{
- GdkMacosDisplay *self = observer;
-
- g_assert (GDK_IS_MACOS_DISPLAY (self));
-
- _gdk_macos_display_reload_monitors (self);
-
- /* Now we need to update all our surface positions since they
- * probably just changed origins.
- */
- for (const GList *iter = _gdk_macos_display_get_surfaces (self);
- iter != NULL;
- iter = iter->next)
- {
- GdkMacosSurface *surface = iter->data;
-
- g_assert (GDK_IS_MACOS_SURFACE (surface));
-
- _gdk_macos_surface_monitor_changed (surface);
- }
-}
+ GDK_NOTE (MISC,
+ g_message ("Displays reconfigured to bounds %d,%d %dx%d",
+ self->min_x, self->min_y, self->width, self->height));
-static void
-gdk_macos_display_user_defaults_changed_cb (CFNotificationCenterRef center,
- void *observer,
- CFStringRef name,
- const void *object,
- CFDictionaryRef userInfo)
-{
- GdkMacosDisplay *self = observer;
-
- g_assert (GDK_IS_MACOS_DISPLAY (self));
-
- _gdk_macos_display_reload_settings (self);
+ GDK_END_MACOS_ALLOC_POOL;
}
void
@@ -273,56 +235,6 @@ gdk_macos_display_load_seat (GdkMacosDisplay *self)
g_object_unref (seat);
}
-static gboolean
-gdk_macos_display_frame_cb (gpointer data)
-{
- GdkMacosDisplay *self = data;
- GdkDisplayLinkSource *source;
- gint64 presentation_time;
- gint64 now;
- GList *iter;
-
- g_assert (GDK_IS_MACOS_DISPLAY (self));
-
- source = (GdkDisplayLinkSource *)self->frame_source;
-
- presentation_time = source->presentation_time;
- now = g_source_get_time ((GSource *)source);
-
- iter = self->awaiting_frames.head;
-
- while (iter != NULL)
- {
- GdkMacosSurface *surface = iter->data;
-
- g_assert (GDK_IS_MACOS_SURFACE (surface));
-
- iter = iter->next;
-
- _gdk_macos_surface_publish_timings (surface,
- source->presentation_time,
- source->refresh_interval);
-
- _gdk_macos_display_remove_frame_callback (self, surface);
-
- if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (surface)))
- gdk_surface_thaw_updates (GDK_SURFACE (surface));
- }
-
- return G_SOURCE_CONTINUE;
-}
-
-static void
-gdk_macos_display_load_display_link (GdkMacosDisplay *self)
-{
- self->frame_source = gdk_display_link_source_new ();
- g_source_set_callback (self->frame_source,
- gdk_macos_display_frame_cb,
- self,
- NULL);
- g_source_attach (self->frame_source, NULL);
-}
-
static const char *
gdk_macos_display_get_name (GdkDisplay *display)
{
@@ -398,11 +310,15 @@ gdk_macos_display_queue_events (GdkDisplay *display)
g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
- if ((nsevent = _gdk_macos_event_source_get_pending ()))
+ while ((nsevent = _gdk_macos_event_source_get_pending ()))
{
GdkEvent *event = _gdk_macos_display_translate (self, nsevent);
- if (event != NULL)
+ if (event == GDK_MACOS_EVENT_DROP)
+ {
+ [nsevent release];
+ }
+ else if (event != NULL)
{
push_nsevent (event, nsevent);
_gdk_windowing_got_event (GDK_DISPLAY (self),
@@ -426,7 +342,6 @@ _gdk_macos_display_surface_added (GdkMacosDisplay *self,
g_assert (GDK_IS_MACOS_SURFACE (surface));
g_assert (!queue_contains (&self->sorted_surfaces, &surface->sorted));
g_assert (!queue_contains (&self->main_surfaces, &surface->main));
- g_assert (!queue_contains (&self->awaiting_frames, &surface->frame));
g_assert (surface->sorted.data == surface);
g_assert (surface->main.data == surface);
g_assert (surface->frame.data == surface);
@@ -453,9 +368,6 @@ _gdk_macos_display_surface_removed (GdkMacosDisplay *self,
if (queue_contains (&self->main_surfaces, &surface->main))
_gdk_macos_display_surface_resigned_main (self, surface);
- if (queue_contains (&self->awaiting_frames, &surface->frame))
- g_queue_unlink (&self->awaiting_frames, &surface->frame);
-
g_return_if_fail (self->keyboard_surface != surface);
}
@@ -501,6 +413,38 @@ _gdk_macos_display_surface_became_key (GdkMacosDisplay *self,
gdk_surface_request_motion (GDK_SURFACE (surface));
}
+static gboolean
+select_key_in_idle_cb (gpointer data)
+{
+ GdkMacosDisplay *self = data;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+
+ self->select_key_in_idle = 0;
+
+ /* Don't steal focus from NSPanel, etc */
+ if (self->key_window_is_foregin)
+ return G_SOURCE_REMOVE;
+
+ if (self->keyboard_surface == NULL)
+ {
+ const GList *surfaces = _gdk_macos_display_get_surfaces (self);
+
+ for (const GList *iter = surfaces; iter; iter = iter->next)
+ {
+ GdkMacosSurface *surface = iter->data;
+
+ if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (surface)))
+ {
+ [surface->window showAndMakeKey:YES];
+ break;
+ }
+ }
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
void
_gdk_macos_display_surface_resigned_key (GdkMacosDisplay *self,
GdkMacosSurface *surface)
@@ -545,6 +489,9 @@ _gdk_macos_display_surface_resigned_key (GdkMacosDisplay *self,
}
_gdk_macos_display_clear_sorting (self);
+
+ if (self->select_key_in_idle == 0)
+ self->select_key_in_idle = g_idle_add (select_key_in_idle_cb, self);
}
/* Raises a transient window.
@@ -583,8 +530,6 @@ void
_gdk_macos_display_surface_resigned_main (GdkMacosDisplay *self,
GdkMacosSurface *surface)
{
- GdkMacosSurface *new_surface = NULL;
-
g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
@@ -592,40 +537,6 @@ _gdk_macos_display_surface_resigned_main (GdkMacosDisplay *self,
g_queue_unlink (&self->main_surfaces, &surface->main);
_gdk_macos_display_clear_sorting (self);
-
- if (GDK_SURFACE (surface)->transient_for &&
- gdk_surface_get_mapped (GDK_SURFACE (surface)->transient_for))
- {
- new_surface = GDK_MACOS_SURFACE (GDK_SURFACE (surface)->transient_for);
- }
- else
- {
- const GList *surfaces = _gdk_macos_display_get_surfaces (self);
-
- for (const GList *iter = surfaces; iter; iter = iter->next)
- {
- GdkMacosSurface *item = iter->data;
-
- g_assert (GDK_IS_MACOS_SURFACE (item));
-
- if (item == surface)
- continue;
-
- if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (item)))
- {
- new_surface = item;
- break;
- }
- }
- }
-
- if (new_surface != NULL)
- {
- NSWindow *nswindow = _gdk_macos_surface_get_native (new_surface);
- [nswindow makeKeyAndOrderFront:nswindow];
- }
-
- _gdk_macos_display_clear_sorting (self);
}
static GdkSurface *
@@ -686,20 +597,12 @@ gdk_macos_display_finalize (GObject *object)
{
GdkMacosDisplay *self = (GdkMacosDisplay *)object;
- CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
- self,
- CFSTR ("NSApplicationDidChangeScreenParametersNotification"),
- NULL);
-
- CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
- self,
- CFSTR ("NSUserDefaultsDidChangeNotification"),
- NULL);
+ _gdk_macos_display_feedback_destroy (self);
+ g_clear_handle_id (&self->select_key_in_idle, g_source_remove);
g_clear_pointer (&self->active_drags, g_hash_table_unref);
g_clear_pointer (&self->active_drops, g_hash_table_unref);
g_clear_object (&GDK_DISPLAY (self)->clipboard);
- g_clear_pointer (&self->frame_source, g_source_unref);
g_clear_object (&self->monitors);
g_clear_pointer (&self->name, g_free);
@@ -774,24 +677,10 @@ _gdk_macos_display_open (const char *display_name)
gdk_macos_display_load_seat (self);
gdk_macos_display_load_clipboard (self);
-
- /* Load CVDisplayLink before monitors to access refresh rates */
- gdk_macos_display_load_display_link (self);
_gdk_macos_display_reload_monitors (self);
- CFNotificationCenterAddObserver (CFNotificationCenterGetLocalCenter (),
- self,
- gdk_macos_display_monitors_changed_cb,
- CFSTR ("NSApplicationDidChangeScreenParametersNotification"),
- NULL,
- CFNotificationSuspensionBehaviorDeliverImmediately);
-
- CFNotificationCenterAddObserver (CFNotificationCenterGetDistributedCenter (),
- self,
- gdk_macos_display_user_defaults_changed_cb,
- CFSTR ("NSUserDefaultsDidChangeNotification"),
- NULL,
- CFNotificationSuspensionBehaviorDeliverImmediately);
+ /* Initialize feedback from display server */
+ _gdk_macos_display_feedback_init (self);
if (event_source == NULL)
{
@@ -803,6 +692,8 @@ _gdk_macos_display_open (const char *display_name)
gdk_display_emit_opened (GDK_DISPLAY (self));
+ [NSApp activateIgnoringOtherApps:YES];
+
return GDK_DISPLAY (self);
}
@@ -1033,42 +924,6 @@ _gdk_macos_display_get_surface_at_display_coords (GdkMacosDisplay *self,
return _gdk_macos_display_get_surface_at_coords (self, x_gdk, y_gdk, surface_x, surface_y);
}
-void
-_gdk_macos_display_add_frame_callback (GdkMacosDisplay *self,
- GdkMacosSurface *surface)
-{
- g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
- g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
-
- if (!queue_contains (&self->awaiting_frames, &surface->frame))
- {
- /* Processing frames is always head to tail, so push to the
- * head so that we don't possibly re-enter this right after
- * adding to the queue.
- */
- g_queue_push_head_link (&self->awaiting_frames, &surface->frame);
-
- if (self->awaiting_frames.length == 1)
- gdk_display_link_source_unpause ((GdkDisplayLinkSource *)self->frame_source);
- }
-}
-
-void
-_gdk_macos_display_remove_frame_callback (GdkMacosDisplay *self,
- GdkMacosSurface *surface)
-{
- g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
- g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
-
- if (queue_contains (&self->awaiting_frames, &surface->frame))
- {
- g_queue_unlink (&self->awaiting_frames, &surface->frame);
-
- if (self->awaiting_frames.length == 0)
- gdk_display_link_source_pause ((GdkDisplayLinkSource *)self->frame_source);
- }
-}
-
NSWindow *
_gdk_macos_display_find_native_under_pointer (GdkMacosDisplay *self,
int *x,
@@ -1088,17 +943,6 @@ _gdk_macos_display_find_native_under_pointer (GdkMacosDisplay *self,
return NULL;
}
-int
-_gdk_macos_display_get_nominal_refresh_rate (GdkMacosDisplay *self)
-{
- g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (self), 60 * 1000);
-
- if (self->frame_source == NULL)
- return 60 * 1000;
-
- return ((GdkDisplayLinkSource *)self->frame_source)->refresh_rate;
-}
-
void
_gdk_macos_display_clear_sorting (GdkMacosDisplay *self)
{
@@ -1120,11 +964,16 @@ _gdk_macos_display_get_surfaces (GdkMacosDisplay *self)
NSArray *array = [NSApp orderedWindows];
GQueue sorted = G_QUEUE_INIT;
+ self->key_window_is_foregin = FALSE;
+
for (id obj in array)
{
NSWindow *nswindow = (NSWindow *)obj;
GdkMacosSurface *surface;
+ if ([nswindow isKeyWindow])
+ self->key_window_is_foregin = !GDK_IS_MACOS_WINDOW (nswindow);
+
if (!GDK_IS_MACOS_WINDOW (nswindow))
continue;
diff --git a/gdk/macos/gdkmacosglcontext-private.h b/gdk/macos/gdkmacosglcontext-private.h
index 8b3eac2ca6..7355ffef90 100644
--- a/gdk/macos/gdkmacosglcontext-private.h
+++ b/gdk/macos/gdkmacosglcontext-private.h
@@ -38,8 +38,6 @@ struct _GdkMacosGLContext
{
GdkGLContext parent_instance;
- cairo_region_t *damage;
-
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
CGLContextObj cgl_context;
G_GNUC_END_IGNORE_DEPRECATIONS
diff --git a/gdk/macos/gdkmacosglcontext.c b/gdk/macos/gdkmacosglcontext.c
index 5baff95a9b..ff7ae975c8 100644
--- a/gdk/macos/gdkmacosglcontext.c
+++ b/gdk/macos/gdkmacosglcontext.c
@@ -469,6 +469,7 @@ gdk_macos_gl_context_begin_frame (GdkDrawContext *context,
buffer = _gdk_macos_surface_get_buffer (GDK_MACOS_SURFACE (surface));
_gdk_macos_buffer_set_flipped (buffer, TRUE);
+ _gdk_macos_buffer_set_damage (buffer, region);
/* Create our render target and bind it */
gdk_gl_context_make_current (GDK_GL_CONTEXT (self));
@@ -476,9 +477,6 @@ gdk_macos_gl_context_begin_frame (GdkDrawContext *context,
GDK_DRAW_CONTEXT_CLASS (gdk_macos_gl_context_parent_class)->begin_frame (context, prefers_high_depth, region);
- g_clear_pointer (&self->damage, cairo_region_destroy);
- self->damage = g_steal_pointer (&copy);
-
gdk_gl_context_make_current (GDK_GL_CONTEXT (self));
CHECK_GL (NULL, glBindFramebuffer (GL_FRAMEBUFFER, self->fbo));
}
@@ -531,8 +529,6 @@ gdk_macos_gl_context_surface_resized (GdkDrawContext *draw_context)
g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
- g_clear_pointer (&self->damage, cairo_region_destroy);
-
if (self->cgl_context != NULL)
CGLUpdateContext (self->cgl_context);
}
@@ -587,9 +583,16 @@ static cairo_region_t *
gdk_macos_gl_context_get_damage (GdkGLContext *context)
{
GdkMacosGLContext *self = (GdkMacosGLContext *)context;
+ const cairo_region_t *damage;
+ GdkMacosBuffer *buffer;
+ GdkSurface *surface;
- if (self->damage)
- return cairo_region_copy (self->damage);
+ g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
+
+ if ((surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context))) &&
+ (buffer = GDK_MACOS_SURFACE (surface)->front) &&
+ (damage = _gdk_macos_buffer_get_damage (buffer)))
+ return cairo_region_copy (damage);
return GDK_GL_CONTEXT_CLASS (gdk_macos_gl_context_parent_class)->get_damage (context);
}
@@ -619,8 +622,6 @@ gdk_macos_gl_context_dispose (GObject *gobject)
CGLDestroyContext (cgl_context);
}
- g_clear_pointer (&self->damage, cairo_region_destroy);
-
G_OBJECT_CLASS (gdk_macos_gl_context_parent_class)->dispose (gobject);
}
diff --git a/gdk/macos/gdkmacosmonitor-private.h b/gdk/macos/gdkmacosmonitor-private.h
index e15f17352d..1a4e197f76 100644
--- a/gdk/macos/gdkmacosmonitor-private.h
+++ b/gdk/macos/gdkmacosmonitor-private.h
@@ -24,16 +24,25 @@
#include "gdkmacosdisplay.h"
#include "gdkmacosmonitor.h"
+#include "gdkmacossurface.h"
#include "gdkmonitorprivate.h"
G_BEGIN_DECLS
-GdkMacosMonitor *_gdk_macos_monitor_new (GdkMacosDisplay *display,
- CGDirectDisplayID screen_id);
-CGDirectDisplayID _gdk_macos_monitor_get_screen_id (GdkMacosMonitor *self);
-gboolean _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self);
-CGColorSpaceRef _gdk_macos_monitor_copy_colorspace (GdkMacosMonitor *self);
+char *_gdk_macos_monitor_get_localized_name (NSScreen *screen);
+char *_gdk_macos_monitor_get_connector_name (CGDirectDisplayID screen_id);
+GdkMacosMonitor *_gdk_macos_monitor_new (GdkMacosDisplay *display,
+ CGDirectDisplayID screen_id);
+CGDirectDisplayID _gdk_macos_monitor_get_screen_id (GdkMacosMonitor *self);
+gboolean _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self);
+CGColorSpaceRef _gdk_macos_monitor_copy_colorspace (GdkMacosMonitor *self);
+void _gdk_macos_monitor_add_frame_callback (GdkMacosMonitor *self,
+ GdkMacosSurface *surface);
+void _gdk_macos_monitor_remove_frame_callback (GdkMacosMonitor *self,
+ GdkMacosSurface *surface);
+void _gdk_macos_monitor_clamp (GdkMacosMonitor *self,
+ GdkRectangle *area);
G_END_DECLS
diff --git a/gdk/macos/gdkmacosmonitor.c b/gdk/macos/gdkmacosmonitor.c
index 6df1da0edc..a9aba3634b 100644
--- a/gdk/macos/gdkmacosmonitor.c
+++ b/gdk/macos/gdkmacosmonitor.c
@@ -22,16 +22,21 @@
#include <gdk/gdk.h>
#include <math.h>
+#include "gdkdisplaylinksource.h"
#include "gdkmacosdisplay-private.h"
#include "gdkmacosmonitor-private.h"
+#include "gdkmacossurface-private.h"
#include "gdkmacosutils-private.h"
struct _GdkMacosMonitor
{
- GdkMonitor parent_instance;
- CGDirectDisplayID screen_id;
- NSRect workarea;
- guint has_opengl : 1;
+ GdkMonitor parent_instance;
+ CGDirectDisplayID screen_id;
+ GdkDisplayLinkSource *display_link;
+ NSRect workarea;
+ GQueue awaiting_frames;
+ guint has_opengl : 1;
+ guint in_frame : 1;
};
struct _GdkMacosMonitorClass
@@ -76,8 +81,25 @@ gdk_macos_monitor_get_workarea (GdkMonitor *monitor,
}
static void
+gdk_macos_monitor_dispose (GObject *object)
+{
+ GdkMacosMonitor *self = (GdkMacosMonitor *)object;
+
+ if (self->display_link)
+ {
+ g_source_destroy ((GSource *)self->display_link);
+ g_clear_pointer ((GSource **)&self->display_link, g_source_unref);
+ }
+
+ G_OBJECT_CLASS (gdk_macos_monitor_parent_class)->dispose (object);
+}
+
+static void
gdk_macos_monitor_class_init (GdkMacosMonitorClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gdk_macos_monitor_dispose;
}
static void
@@ -138,8 +160,8 @@ GetSubpixelLayout (CGDirectDisplayID screen_id)
return GDK_SUBPIXEL_LAYOUT_UNKNOWN;
}
-static char *
-GetLocalizedName (NSScreen *screen)
+char *
+_gdk_macos_monitor_get_localized_name (NSScreen *screen)
{
#ifdef AVAILABLE_MAC_OS_X_VERSION_10_15_AND_LATER
GDK_BEGIN_MACOS_ALLOC_POOL;
@@ -160,8 +182,8 @@ GetLocalizedName (NSScreen *screen)
#endif
}
-static char *
-GetConnectorName (CGDirectDisplayID screen_id)
+char *
+_gdk_macos_monitor_get_connector_name (CGDirectDisplayID screen_id)
{
guint unit = CGDisplayUnitNumber (screen_id);
return g_strdup_printf ("unit-%u", unit);
@@ -188,6 +210,68 @@ find_screen (CGDirectDisplayID screen_id)
return screen;
}
+static gboolean
+gdk_macos_monitor_display_link_cb (GdkMacosMonitor *self)
+{
+ gint64 presentation_time;
+ gint64 refresh_interval;
+ gint64 now;
+ GList *iter;
+
+ g_assert (GDK_IS_MACOS_MONITOR (self));
+ g_assert (!self->display_link->paused);
+
+ self->in_frame = TRUE;
+
+ presentation_time = self->display_link->presentation_time;
+ refresh_interval = self->display_link->refresh_interval;
+ now = g_source_get_time ((GSource *)self->display_link);
+
+ iter = self->awaiting_frames.head;
+
+ while (iter != NULL)
+ {
+ GdkMacosSurface *surface = iter->data;
+
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+
+ iter = iter->next;
+
+ g_queue_unlink (&self->awaiting_frames, &surface->frame);
+ _gdk_macos_surface_frame_presented (surface, presentation_time, refresh_interval);
+ }
+
+ if (self->awaiting_frames.length == 0 && !self->display_link->paused)
+ gdk_display_link_source_pause (self->display_link);
+
+ self->in_frame = FALSE;
+
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+_gdk_macos_monitor_reset_display_link (GdkMacosMonitor *self,
+ CGDisplayModeRef mode)
+{
+ GSource *source;
+
+ g_assert (GDK_IS_MACOS_MONITOR (self));
+
+ if (self->display_link)
+ {
+ g_source_destroy ((GSource *)self->display_link);
+ g_clear_pointer ((GSource **)&self->display_link, g_source_unref);
+ }
+
+ source = gdk_display_link_source_new (self->screen_id, mode);
+ self->display_link = (GdkDisplayLinkSource *)source;
+ g_source_set_callback (source,
+ (GSourceFunc) gdk_macos_monitor_display_link_cb,
+ self,
+ NULL);
+ g_source_attach (source, NULL);
+}
+
gboolean
_gdk_macos_monitor_reconfigure (GdkMacosMonitor *self)
{
@@ -222,8 +306,8 @@ _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self)
pixel_width = CGDisplayModeGetPixelWidth (mode);
has_opengl = CGDisplayUsesOpenGLAcceleration (self->screen_id);
subpixel_layout = GetSubpixelLayout (self->screen_id);
- name = GetLocalizedName (screen);
- connector = GetConnectorName (self->screen_id);
+ name = _gdk_macos_monitor_get_localized_name (screen);
+ connector = _gdk_macos_monitor_get_connector_name (self->screen_id);
if (width != 0 && pixel_width != 0)
scale_factor = MAX (1, pixel_width / width);
@@ -241,7 +325,7 @@ _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self)
* setting (which is also used by the frame clock).
*/
if (!(refresh_rate = CGDisplayModeGetRefreshRate (mode)))
- refresh_rate = _gdk_macos_display_get_nominal_refresh_rate (display);
+ refresh_rate = 60 * 1000;
gdk_monitor_set_connector (GDK_MONITOR (self), connector);
gdk_monitor_set_model (GDK_MONITOR (self), name);
@@ -261,6 +345,9 @@ _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self)
*/
self->has_opengl = !!has_opengl;
+ /* Create a new display link to receive feedback about when to render */
+ _gdk_macos_monitor_reset_display_link (self, mode);
+
CGDisplayModeRelease (mode);
g_free (name);
g_free (connector);
@@ -302,3 +389,71 @@ _gdk_macos_monitor_copy_colorspace (GdkMacosMonitor *self)
return CGDisplayCopyColorSpace (self->screen_id);
}
+
+void
+_gdk_macos_monitor_add_frame_callback (GdkMacosMonitor *self,
+ GdkMacosSurface *surface)
+{
+ g_return_if_fail (GDK_IS_MACOS_MONITOR (self));
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
+ g_return_if_fail (surface->frame.data == (gpointer)surface);
+ g_return_if_fail (surface->frame.prev == NULL);
+ g_return_if_fail (surface->frame.next == NULL);
+ g_return_if_fail (self->awaiting_frames.head != &surface->frame);
+ g_return_if_fail (self->awaiting_frames.tail != &surface->frame);
+
+ /* Processing frames is always head to tail, so push to the
+ * head so that we don't possibly re-enter this right after
+ * adding to the queue.
+ */
+ if (!queue_contains (&self->awaiting_frames, &surface->frame))
+ {
+ g_queue_push_head_link (&self->awaiting_frames, &surface->frame);
+
+ if (!self->in_frame && self->awaiting_frames.length == 1)
+ gdk_display_link_source_unpause (self->display_link);
+ }
+}
+
+void
+_gdk_macos_monitor_remove_frame_callback (GdkMacosMonitor *self,
+ GdkMacosSurface *surface)
+{
+ g_return_if_fail (GDK_IS_MACOS_MONITOR (self));
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
+ g_return_if_fail (surface->frame.data == (gpointer)surface);
+
+ if (queue_contains (&self->awaiting_frames, &surface->frame))
+ {
+ g_queue_unlink (&self->awaiting_frames, &surface->frame);
+
+ if (!self->in_frame && self->awaiting_frames.length == 0)
+ gdk_display_link_source_pause (self->display_link);
+ }
+}
+
+void
+_gdk_macos_monitor_clamp (GdkMacosMonitor *self,
+ GdkRectangle *area)
+{
+ GdkRectangle workarea;
+ GdkRectangle geom;
+
+ g_return_if_fail (GDK_IS_MACOS_MONITOR (self));
+ g_return_if_fail (area != NULL);
+
+ gdk_macos_monitor_get_workarea (GDK_MONITOR (self), &workarea);
+ gdk_monitor_get_geometry (GDK_MONITOR (self), &geom);
+
+ if (area->x + area->width > workarea.x + workarea.width)
+ area->x = workarea.x + workarea.width - area->width;
+
+ if (area->x < workarea.x)
+ area->x = workarea.x;
+
+ if (area->y + area->height > workarea.y + workarea.height)
+ area->y = workarea.y + workarea.height - area->height;
+
+ if (area->y < workarea.y)
+ area->y = workarea.y;
+}
diff --git a/gdk/macos/gdkmacospopupsurface.c b/gdk/macos/gdkmacospopupsurface.c
index 477961503f..061af9d85d 100644
--- a/gdk/macos/gdkmacospopupsurface.c
+++ b/gdk/macos/gdkmacospopupsurface.c
@@ -34,6 +34,7 @@ struct _GdkMacosPopupSurface
{
GdkMacosSurface parent_instance;
GdkPopupLayout *layout;
+ guint attached : 1;
};
struct _GdkMacosPopupSurfaceClass
@@ -87,6 +88,9 @@ gdk_macos_popup_surface_layout (GdkMacosPopupSurface *self,
gdk_surface_get_origin (GDK_SURFACE (self)->parent, &x, &y);
+ GDK_SURFACE (self)->x = final_rect.x;
+ GDK_SURFACE (self)->y = final_rect.y;
+
x += final_rect.x;
y += final_rect.y;
@@ -135,6 +139,9 @@ gdk_macos_popup_surface_present (GdkPopup *popup,
if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self)))
return TRUE;
+ if (!self->attached && GDK_SURFACE (self)->parent != NULL)
+ _gdk_macos_popup_surface_attach_to_parent (self);
+
if (GDK_SURFACE (self)->autohide)
{
GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (popup));
@@ -201,6 +208,19 @@ enum {
};
static void
+_gdk_macos_popup_surface_hide (GdkSurface *surface)
+{
+ GdkMacosPopupSurface *self = (GdkMacosPopupSurface *)surface;
+
+ g_assert (GDK_IS_MACOS_POPUP_SURFACE (self));
+
+ if (self->attached)
+ _gdk_macos_popup_surface_detach_from_parent (self);
+
+ GDK_SURFACE_CLASS (_gdk_macos_popup_surface_parent_class)->hide (surface);
+}
+
+static void
_gdk_macos_popup_surface_finalize (GObject *object)
{
GdkMacosPopupSurface *self = (GdkMacosPopupSurface *)object;
@@ -267,12 +287,15 @@ static void
_gdk_macos_popup_surface_class_init (GdkMacosPopupSurfaceClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkSurfaceClass *surface_class = GDK_SURFACE_CLASS (klass);
object_class->finalize = _gdk_macos_popup_surface_finalize;
object_class->get_property = _gdk_macos_popup_surface_get_property;
object_class->set_property = _gdk_macos_popup_surface_set_property;
- gdk_popup_install_properties (object_class, 1);
+ surface_class->hide = _gdk_macos_popup_surface_hide;
+
+ gdk_popup_install_properties (object_class, LAST_PROP);
}
static void
@@ -323,14 +346,8 @@ _gdk_macos_popup_surface_new (GdkMacosDisplay *display,
[window setOpaque:NO];
[window setBackgroundColor:[NSColor clearColor]];
[window setDecorated:NO];
-
-#if 0
- /* NOTE: We could set these to be popup level, but then
- * [NSApp orderedWindows] would not give us the windows
- * back with the stacking order applied.
- */
+ [window setExcludedFromWindowsMenu:YES];
[window setLevel:NSPopUpMenuWindowLevel];
-#endif
self = g_object_new (GDK_TYPE_MACOS_POPUP_SURFACE,
"display", display,
@@ -361,6 +378,8 @@ _gdk_macos_popup_surface_attach_to_parent (GdkMacosPopupSurface *self)
[parent addChildWindow:window ordered:NSWindowAbove];
+ self->attached = TRUE;
+
_gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (surface->display));
}
}
@@ -382,6 +401,8 @@ _gdk_macos_popup_surface_detach_from_parent (GdkMacosPopupSurface *self)
[parent removeChildWindow:window];
+ self->attached = FALSE;
+
_gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (surface->display));
}
}
@@ -391,9 +412,7 @@ _gdk_macos_popup_surface_reposition (GdkMacosPopupSurface *self)
{
g_return_if_fail (GDK_IS_MACOS_POPUP_SURFACE (self));
- if (self->layout == NULL ||
- !gdk_surface_get_mapped (GDK_SURFACE (self)) ||
- GDK_SURFACE (self)->parent == NULL)
+ if (self->layout == NULL || GDK_SURFACE (self)->parent == NULL)
return;
gdk_macos_popup_surface_layout (self,
diff --git a/gdk/macos/gdkmacossurface-private.h b/gdk/macos/gdkmacossurface-private.h
index 2abc199698..5f1f551f93 100644
--- a/gdk/macos/gdkmacossurface-private.h
+++ b/gdk/macos/gdkmacossurface-private.h
@@ -49,7 +49,7 @@ struct _GdkMacosSurface
GdkMacosBuffer *buffer;
GdkMacosBuffer *front;
GPtrArray *monitors;
- cairo_region_t *opaque_region;
+ GdkMonitor *best_monitor;
char *title;
int root_x;
@@ -75,6 +75,9 @@ struct _GdkMacosSurface
guint geometry_dirty : 1;
guint next_frame_set : 1;
guint show_on_next_swap : 1;
+ guint in_change_monitor : 1;
+ guint in_frame : 1;
+ guint awaiting_frame : 1;
};
struct _GdkMacosSurfaceClass
@@ -116,11 +119,11 @@ void _gdk_macos_surface_resize (GdkMacosSurface
int width,
int height);
void _gdk_macos_surface_update_fullscreen_state (GdkMacosSurface *self);
-void _gdk_macos_surface_update_position (GdkMacosSurface *self);
-void _gdk_macos_surface_show (GdkMacosSurface *self);
-void _gdk_macos_surface_publish_timings (GdkMacosSurface *self,
+void _gdk_macos_surface_request_frame (GdkMacosSurface *self);
+void _gdk_macos_surface_frame_presented (GdkMacosSurface *self,
gint64 predicted_presentation_time,
gint64 refresh_interval);
+void _gdk_macos_surface_show (GdkMacosSurface *self);
void _gdk_macos_surface_synthesize_null_key (GdkMacosSurface *self);
void _gdk_macos_surface_move (GdkMacosSurface *self,
int x,
diff --git a/gdk/macos/gdkmacossurface.c b/gdk/macos/gdkmacossurface.c
index 5998c4162f..449a3b35a5 100644
--- a/gdk/macos/gdkmacossurface.c
+++ b/gdk/macos/gdkmacossurface.c
@@ -27,6 +27,7 @@
#include "gdkmacossurface-private.h"
+#include "gdkdebug.h"
#include "gdkdeviceprivate.h"
#include "gdkdisplay.h"
#include "gdkeventsprivate.h"
@@ -63,6 +64,79 @@ window_is_fullscreen (GdkMacosSurface *self)
return ([self->window styleMask] & NSWindowStyleMaskFullScreen) != 0;
}
+void
+_gdk_macos_surface_request_frame (GdkMacosSurface *self)
+{
+ g_assert (GDK_IS_MACOS_SURFACE (self));
+
+ if (self->awaiting_frame)
+ return;
+
+ if (self->best_monitor != NULL)
+ {
+ self->awaiting_frame = TRUE;
+ _gdk_macos_monitor_add_frame_callback (GDK_MACOS_MONITOR (self->best_monitor), self);
+ gdk_surface_freeze_updates (GDK_SURFACE (self));
+ }
+}
+
+static void
+_gdk_macos_surface_cancel_frame (GdkMacosSurface *self)
+{
+ g_assert (GDK_IS_MACOS_SURFACE (self));
+
+ if (!self->awaiting_frame)
+ return;
+
+ if (self->best_monitor != NULL)
+ {
+ self->awaiting_frame = FALSE;
+ _gdk_macos_monitor_remove_frame_callback (GDK_MACOS_MONITOR (self->best_monitor), self);
+ gdk_surface_thaw_updates (GDK_SURFACE (self));
+ }
+}
+
+void
+_gdk_macos_surface_frame_presented (GdkMacosSurface *self,
+ gint64 presentation_time,
+ gint64 refresh_interval)
+{
+ GdkFrameTimings *timings;
+ GdkFrameClock *frame_clock;
+
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+
+ self->awaiting_frame = FALSE;
+
+ if (GDK_SURFACE_DESTROYED (self))
+ return;
+
+ frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self));
+
+ if (self->pending_frame_counter)
+ {
+ timings = gdk_frame_clock_get_timings (frame_clock, self->pending_frame_counter);
+
+ if (timings != NULL)
+ {
+ timings->presentation_time = presentation_time - refresh_interval;
+ timings->complete = TRUE;
+ }
+
+ self->pending_frame_counter = 0;
+ }
+
+ timings = gdk_frame_clock_get_current_timings (frame_clock);
+
+ if (timings != NULL)
+ {
+ timings->refresh_interval = refresh_interval;
+ timings->predicted_presentation_time = presentation_time;
+ }
+
+ if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self)))
+ gdk_surface_thaw_updates (GDK_SURFACE (self));
+}
void
_gdk_macos_surface_reposition_children (GdkMacosSurface *self)
@@ -84,9 +158,6 @@ _gdk_macos_surface_reposition_children (GdkMacosSurface *self)
if (GDK_IS_MACOS_POPUP_SURFACE (child))
_gdk_macos_popup_surface_reposition (GDK_MACOS_POPUP_SURFACE (child));
}
-
- if (GDK_IS_POPUP (self) && self->did_initial_present)
- gdk_surface_request_layout (GDK_SURFACE (self));
}
static void
@@ -115,12 +186,6 @@ gdk_macos_surface_set_opaque_region (GdkSurface *surface,
g_assert (GDK_IS_MACOS_SURFACE (self));
- if (region != self->opaque_region)
- {
- g_clear_pointer (&self->opaque_region, cairo_region_destroy);
- self->opaque_region = cairo_region_copy (region);
- }
-
if ((nsview = _gdk_macos_surface_get_view (GDK_MACOS_SURFACE (surface))))
[(GdkMacosView *)nsview setOpaqueRegion:region];
}
@@ -137,9 +202,9 @@ gdk_macos_surface_hide (GdkSurface *surface)
self->show_on_next_swap = FALSE;
- _gdk_macos_display_remove_frame_callback (GDK_MACOS_DISPLAY (surface->display), self);
+ _gdk_macos_surface_cancel_frame (self);
- was_mapped = GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self));
+ was_mapped = GDK_SURFACE_IS_MAPPED (surface);
was_key = [self->window isKeyWindow];
seat = gdk_display_get_default_seat (surface->display);
@@ -154,17 +219,21 @@ gdk_macos_surface_hide (GdkSurface *surface)
if (was_key)
{
+ GdkSurface *parent;
+
+ if (GDK_IS_TOPLEVEL (surface))
+ parent = surface->transient_for;
+ else
+ parent = surface->parent;
+
/* Return key input to the parent window if necessary */
- if (surface->parent != NULL && GDK_SURFACE_IS_MAPPED (surface->parent))
+ if (parent != NULL && GDK_SURFACE_IS_MAPPED (parent))
{
- GdkMacosWindow *parentWindow = GDK_MACOS_SURFACE (surface->parent)->window;
+ GdkMacosWindow *parentWindow = GDK_MACOS_SURFACE (parent)->window;
[parentWindow showAndMakeKey:YES];
}
}
-
- if (was_mapped)
- gdk_surface_freeze_updates (GDK_SURFACE (self));
}
static int
@@ -208,6 +277,7 @@ gdk_macos_surface_begin_frame (GdkMacosSurface *self)
{
g_assert (GDK_IS_MACOS_SURFACE (self));
+ self->in_frame = TRUE;
}
static void
@@ -228,11 +298,9 @@ gdk_macos_surface_end_frame (GdkMacosSurface *self)
if ((timings = gdk_frame_clock_get_current_timings (frame_clock)))
self->pending_frame_counter = timings->frame_counter;
- if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self)))
- {
- _gdk_macos_display_add_frame_callback (GDK_MACOS_DISPLAY (display), self);
- gdk_surface_freeze_updates (GDK_SURFACE (self));
- }
+ self->in_frame = FALSE;
+
+ _gdk_macos_surface_request_frame (self);
}
static void
@@ -406,6 +474,9 @@ gdk_macos_surface_destroy (GdkSurface *surface,
GdkMacosWindow *window = g_steal_pointer (&self->window);
GdkFrameClock *frame_clock;
+ _gdk_macos_surface_cancel_frame (self);
+ g_clear_object (&self->best_monitor);
+
if ((frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self))))
{
g_signal_handlers_disconnect_by_func (frame_clock,
@@ -417,7 +488,6 @@ gdk_macos_surface_destroy (GdkSurface *surface,
}
g_clear_pointer (&self->title, g_free);
- g_clear_pointer (&self->opaque_region, cairo_region_destroy);
if (window != NULL)
[window close];
@@ -559,7 +629,7 @@ _gdk_macos_surface_new (GdkMacosDisplay *display,
g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
if (parent != NULL)
- frame_clock = g_object_ref (gdk_surface_get_frame_clock (parent));
+ frame_clock = g_object_ref (parent->frame_clock);
else
frame_clock = _gdk_frame_clock_idle_new ();
@@ -619,14 +689,16 @@ _gdk_macos_surface_get_shadow (GdkMacosSurface *self,
gboolean
_gdk_macos_surface_is_opaque (GdkMacosSurface *self)
{
+ GdkSurface *surface = (GdkSurface *)self;
+
g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), FALSE);
- if (self->opaque_region != NULL &&
- cairo_region_num_rectangles (self->opaque_region) == 1)
+ if (surface->opaque_region != NULL &&
+ cairo_region_num_rectangles (surface->opaque_region) == 1)
{
cairo_rectangle_int_t extents;
- cairo_region_get_extents (self->opaque_region, &extents);
+ cairo_region_get_extents (surface->opaque_region, &extents);
return (extents.x == 0 &&
extents.y == 0 &&
@@ -746,8 +818,9 @@ _gdk_macos_surface_update_fullscreen_state (GdkMacosSurface *self)
void
_gdk_macos_surface_configure (GdkMacosSurface *self)
{
- GdkMacosDisplay *display;
GdkSurface *surface = (GdkSurface *)self;
+ GdkMacosDisplay *display;
+ GdkMacosSurface *parent;
NSRect frame_rect;
NSRect content_rect;
@@ -756,6 +829,13 @@ _gdk_macos_surface_configure (GdkMacosSurface *self)
if (GDK_SURFACE_DESTROYED (self))
return;
+ if (surface->parent != NULL)
+ parent = GDK_MACOS_SURFACE (surface->parent);
+ else if (surface->transient_for != NULL)
+ parent = GDK_MACOS_SURFACE (surface->transient_for);
+ else
+ parent = NULL;
+
display = GDK_MACOS_DISPLAY (GDK_SURFACE (self)->display);
frame_rect = [self->window frame];
content_rect = [self->window contentRectForFrameRect:frame_rect];
@@ -765,10 +845,10 @@ _gdk_macos_surface_configure (GdkMacosSurface *self)
content_rect.origin.y + content_rect.size.height,
&self->root_x, &self->root_y);
- if (surface->parent != NULL)
+ if (parent != NULL)
{
- surface->x = self->root_x - GDK_MACOS_SURFACE (surface->parent)->root_x;
- surface->y = self->root_y - GDK_MACOS_SURFACE (surface->parent)->root_y;
+ surface->x = self->root_x - parent->root_x;
+ surface->y = self->root_y - parent->root_y;
}
else
{
@@ -786,7 +866,6 @@ _gdk_macos_surface_configure (GdkMacosSurface *self)
g_clear_object (&self->front);
_gdk_surface_update_size (surface);
- gdk_surface_request_layout (surface);
gdk_surface_invalidate_rect (surface, NULL);
}
@@ -794,41 +873,6 @@ _gdk_macos_surface_configure (GdkMacosSurface *self)
}
void
-_gdk_macos_surface_publish_timings (GdkMacosSurface *self,
- gint64 presentation_time,
- gint64 refresh_interval)
-{
- GdkFrameTimings *timings;
- GdkFrameClock *frame_clock;
-
- g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
-
- if (!(frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self))))
- return;
-
- if (self->pending_frame_counter)
- {
- timings = gdk_frame_clock_get_timings (frame_clock, self->pending_frame_counter);
-
- if (timings != NULL)
- {
- timings->presentation_time = presentation_time - refresh_interval;
- timings->complete = TRUE;
- }
-
- self->pending_frame_counter = 0;
- }
-
- timings = gdk_frame_clock_get_current_timings (frame_clock);
-
- if (timings != NULL)
- {
- timings->refresh_interval = refresh_interval;
- timings->predicted_presentation_time = presentation_time;
- }
-}
-
-void
_gdk_macos_surface_show (GdkMacosSurface *self)
{
gboolean was_mapped;
@@ -838,22 +882,17 @@ _gdk_macos_surface_show (GdkMacosSurface *self)
if (GDK_SURFACE_DESTROYED (self))
return;
- was_mapped = GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self));
-
- if (!was_mapped)
- gdk_surface_set_is_mapped (GDK_SURFACE (self), TRUE);
-
_gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (GDK_SURFACE (self)->display));
-
self->show_on_next_swap = TRUE;
+ was_mapped = GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self));
+
if (!was_mapped)
{
- if (gdk_surface_get_mapped (GDK_SURFACE (self)))
- {
- _gdk_macos_surface_configure (self);
- gdk_surface_thaw_updates (GDK_SURFACE (self));
- }
+ gdk_surface_set_is_mapped (GDK_SURFACE (self), TRUE);
+ gdk_surface_request_layout (GDK_SURFACE (self));
+ gdk_surface_invalidate_rect (GDK_SURFACE (self), NULL);
+ gdk_surface_thaw_updates (GDK_SURFACE (self));
}
}
@@ -906,36 +945,59 @@ _gdk_macos_surface_move_resize (GdkMacosSurface *self,
GdkDisplay *display;
NSRect content_rect;
NSRect frame_rect;
+ gboolean ignore_move;
+ gboolean ignore_size;
+ GdkRectangle current;
g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
- if ((x == -1 || (x == self->root_x)) &&
- (y == -1 || (y == self->root_y)) &&
- (width == -1 || (width == surface->width)) &&
- (height == -1 || (height == surface->height)))
+ /* Query for up-to-date values in case we're racing against
+ * an incoming frame notify which could be queued behind whatever
+ * we're processing right now.
+ */
+ frame_rect = [self->window frame];
+ content_rect = [self->window contentRectForFrameRect:frame_rect];
+ _gdk_macos_display_from_display_coords (GDK_MACOS_DISPLAY (GDK_SURFACE (self)->display),
+ content_rect.origin.x, content_rect.origin.y,
+ &current.x, &current.y);
+ current.width = content_rect.size.width;
+ current.height = content_rect.size.height;
+
+ /* Check if we can ignore the operation all together */
+ ignore_move = (x == -1 || (x == current.x)) &&
+ (y == -1 || (y == current.y));
+ ignore_size = (width == -1 || (width == current.width)) &&
+ (height == -1 || (height == current.height));
+
+ if (ignore_move && ignore_size)
return;
display = gdk_surface_get_display (surface);
if (width == -1)
- width = surface->width;
+ width = current.width;
if (height == -1)
- height = surface->height;
+ height = current.height;
if (x == -1)
- x = self->root_x;
+ x = current.x;
if (y == -1)
- y = self->root_y;
+ y = current.y;
_gdk_macos_display_to_display_coords (GDK_MACOS_DISPLAY (display),
x, y + height,
&x, &y);
- content_rect = NSMakeRect (x, y, width, height);
+ if (!ignore_move)
+ content_rect.origin = NSMakePoint (x, y);
+
+ if (!ignore_size)
+ content_rect.size = NSMakeSize (width, height);
+
frame_rect = [self->window frameRectForContentRect:content_rect];
- [self->window setFrame:frame_rect display:YES];
+ [self->window setFrame:frame_rect display:NO];
}
void
@@ -990,14 +1052,24 @@ void
_gdk_macos_surface_monitor_changed (GdkMacosSurface *self)
{
GListModel *monitors;
+ GdkMonitor *best = NULL;
GdkRectangle rect;
GdkRectangle intersect;
GdkDisplay *display;
GdkMonitor *monitor;
guint n_monitors;
+ int best_area = 0;
g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+ if (self->in_change_monitor)
+ return;
+
+ self->in_change_monitor = TRUE;
+
+ _gdk_macos_surface_cancel_frame (self);
+ _gdk_macos_surface_configure (self);
+
rect.x = self->root_x;
rect.y = self->root_y;
rect.width = GDK_SURFACE (self)->width;
@@ -1037,29 +1109,10 @@ _gdk_macos_surface_monitor_changed (GdkMacosSurface *self)
g_clear_object (&self->buffer);
g_clear_object (&self->front);
- _gdk_macos_surface_configure (self);
-
- gdk_surface_invalidate_rect (GDK_SURFACE (self), NULL);
-}
-
-GdkMonitor *
-_gdk_macos_surface_get_best_monitor (GdkMacosSurface *self)
-{
- GdkMonitor *best = NULL;
- GdkRectangle rect;
- int best_area = 0;
-
- g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL);
-
- rect.x = self->root_x;
- rect.y = self->root_y;
- rect.width = GDK_SURFACE (self)->width;
- rect.height = GDK_SURFACE (self)->height;
-
+ /* Determine the best-fit monitor */
for (guint i = 0; i < self->monitors->len; i++)
{
- GdkMonitor *monitor = g_ptr_array_index (self->monitors, i);
- GdkRectangle intersect;
+ monitor = g_ptr_array_index (self->monitors, i);
if (gdk_rectangle_intersect (&monitor->geometry, &rect, &intersect))
{
@@ -1067,13 +1120,62 @@ _gdk_macos_surface_get_best_monitor (GdkMacosSurface *self)
if (area > best_area)
{
- best = monitor;
best_area = area;
+ best = monitor;
}
}
}
- return best;
+ if (g_set_object (&self->best_monitor, best))
+ {
+ GDK_NOTE (MISC,
+ g_message ("Surface \"%s\" moved to monitor \"%s\"",
+ self->title ? self->title : "unknown",
+ gdk_monitor_get_connector (best)));
+
+ _gdk_macos_surface_configure (self);
+
+ if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self)))
+ {
+ _gdk_macos_surface_request_frame (self);
+ gdk_surface_request_layout (GDK_SURFACE (self));
+ }
+
+ for (const GList *iter = GDK_SURFACE (self)->children;
+ iter != NULL;
+ iter = iter->next)
+ {
+ GdkMacosSurface *child = iter->data;
+ GdkRectangle area;
+
+ g_set_object (&child->best_monitor, best);
+
+ area.x = self->root_x + GDK_SURFACE (child)->x + child->shadow_left;
+ area.y = self->root_y + GDK_SURFACE (child)->y + child->shadow_top;
+ area.width = GDK_SURFACE (child)->width - child->shadow_left - child->shadow_right;
+ area.height = GDK_SURFACE (child)->height - child->shadow_top - child->shadow_bottom;
+
+ _gdk_macos_monitor_clamp (GDK_MACOS_MONITOR (best), &area);
+
+ area.x -= child->shadow_left;
+ area.y -= child->shadow_top;
+
+ _gdk_macos_surface_move (child, area.x, area.y);
+ gdk_surface_invalidate_rect (GDK_SURFACE (child), NULL);
+ }
+ }
+
+ gdk_surface_invalidate_rect (GDK_SURFACE (self), NULL);
+
+ self->in_change_monitor = FALSE;
+}
+
+GdkMonitor *
+_gdk_macos_surface_get_best_monitor (GdkMacosSurface *self)
+{
+ g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL);
+
+ return self->best_monitor;
}
NSView *
@@ -1149,11 +1251,15 @@ _gdk_macos_surface_get_buffer (GdkMacosSurface *self)
static void
_gdk_macos_surface_do_delayed_show (GdkMacosSurface *self)
{
+ GdkSurface *surface = (GdkSurface *)self;
+
g_assert (GDK_IS_MACOS_SURFACE (self));
self->show_on_next_swap = FALSE;
[self->window showAndMakeKey:YES];
- gdk_surface_request_motion (GDK_SURFACE (self));
+
+ _gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (surface->display));
+ gdk_surface_request_motion (surface);
}
void
diff --git a/gdk/macos/gdkmacostoplevelsurface.c b/gdk/macos/gdkmacostoplevelsurface.c
index 27289787ca..1759077563 100644
--- a/gdk/macos/gdkmacostoplevelsurface.c
+++ b/gdk/macos/gdkmacostoplevelsurface.c
@@ -174,6 +174,14 @@ _gdk_macos_toplevel_surface_present (GdkToplevel *toplevel,
_gdk_macos_surface_set_geometry_hints (GDK_MACOS_SURFACE (self), &geometry, mask);
gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height);
+
+ GDK_NOTE (MISC,
+ g_message ("Resizing \"%s\" to %dx%d",
+ GDK_MACOS_SURFACE (self)->title ?
+ GDK_MACOS_SURFACE (self)->title :
+ "untitled",
+ width, height));
+
_gdk_macos_surface_resize (GDK_MACOS_SURFACE (self), width, height);
/* Maximized state */
@@ -202,6 +210,13 @@ _gdk_macos_toplevel_surface_present (GdkToplevel *toplevel,
GDK_MACOS_SURFACE (self),
&x, &y);
+ GDK_NOTE (MISC,
+ g_message ("Placing new toplevel \"%s\" at %d,%d",
+ GDK_MACOS_SURFACE (self)->title ?
+ GDK_MACOS_SURFACE (self)->title :
+ "untitled",
+ x, y));
+
_gdk_macos_surface_move (GDK_MACOS_SURFACE (self), x, y);
}
@@ -421,7 +436,8 @@ _gdk_macos_toplevel_surface_compute_size (GdkSurface *surface)
GDK_TOPLEVEL_STATE_RIGHT_TILED |
GDK_TOPLEVEL_STATE_BOTTOM_TILED |
GDK_TOPLEVEL_STATE_LEFT_TILED |
- GDK_TOPLEVEL_STATE_MINIMIZED))
+ GDK_TOPLEVEL_STATE_MINIMIZED) ||
+ [macos_surface->window inLiveResize])
return FALSE;
/* If we delayed a user resize until the beginning of the frame,
@@ -632,10 +648,10 @@ _gdk_macos_toplevel_surface_new (GdkMacosDisplay *display,
GdkMacosWindow *window;
GdkMacosSurface *self;
- NSScreen *screen;
NSUInteger style_mask;
NSRect content_rect;
- NSRect screen_rect;
+ NSRect visible_frame;
+ NSScreen *screen;
int nx;
int ny;
@@ -648,14 +664,17 @@ _gdk_macos_toplevel_surface_new (GdkMacosDisplay *display,
NSWindowStyleMaskMiniaturizable |
NSWindowStyleMaskResizable);
- _gdk_macos_display_to_display_coords (display, x, y, &nx, &ny);
+ if (parent != NULL)
+ {
+ x += GDK_MACOS_SURFACE (parent)->root_x;
+ y += GDK_MACOS_SURFACE (parent)->root_y;
+ }
- screen = _gdk_macos_display_get_screen_at_display_coords (display, nx, ny);
- screen_rect = [screen visibleFrame];
- nx -= screen_rect.origin.x;
- ny -= screen_rect.origin.y;
- content_rect = NSMakeRect (nx, ny - height, width, height);
+ _gdk_macos_display_to_display_coords (display, x, y + height, &nx, &ny);
+ screen = _gdk_macos_display_get_screen_at_display_coords (display, nx, ny);
+ visible_frame = [screen visibleFrame];
+ content_rect = NSMakeRect (nx - visible_frame.origin.x, ny - visible_frame.origin.y, width, height);
window = [[GdkMacosWindow alloc] initWithContentRect:content_rect
styleMask:style_mask
backing:NSBackingStoreBuffered
@@ -691,13 +710,21 @@ _gdk_macos_toplevel_surface_attach_to_parent (GdkMacosToplevelSurface *self)
{
NSWindow *parent = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface->transient_for));
NSWindow *window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
+ int x, y;
[parent addChildWindow:window ordered:NSWindowAbove];
if (GDK_SURFACE (self)->modal_hint)
[window setLevel:NSModalPanelWindowLevel];
+ surface->x = 0;
+ surface->y = 0;
+
_gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (surface->display));
+ _gdk_macos_display_position_surface (GDK_MACOS_DISPLAY (surface->display),
+ GDK_MACOS_SURFACE (surface),
+ &x, &y);
+ _gdk_macos_surface_move (GDK_MACOS_SURFACE (surface), x, y);
}
}
diff --git a/gdk/macos/meson.build b/gdk/macos/meson.build
index d17a60ac09..bd7bbb5324 100644
--- a/gdk/macos/meson.build
+++ b/gdk/macos/meson.build
@@ -8,6 +8,7 @@ gdk_macos_sources = files([
'gdkmacoscursor.c',
'gdkmacosdevice.c',
'gdkmacosdisplay.c',
+ 'gdkmacosdisplay-feedback.c',
'gdkmacosdisplay-settings.c',
'gdkmacosdisplay-translate.c',
'gdkmacosdisplay-wm.c',
diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
index ee8c2b0ba4..4879fee68d 100644
--- a/gtk/gtkscrolledwindow.c
+++ b/gtk/gtkscrolledwindow.c
@@ -1226,16 +1226,15 @@ check_update_scrollbar_proximity (GtkScrolledWindow *sw,
}
static double
-get_scroll_unit (GtkScrolledWindow *sw,
- GtkOrientation orientation)
+get_scroll_unit (GtkScrolledWindow *sw,
+ GtkOrientation orientation,
+ GtkEventControllerScroll *scroll)
{
- double scroll_unit;
-
-#ifndef GDK_WINDOWING_MACOS
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (sw);
GtkScrollbar *scrollbar;
GtkAdjustment *adj;
double page_size;
+ double scroll_unit;
if (orientation == GTK_ORIENTATION_HORIZONTAL)
scrollbar = GTK_SCROLLBAR (priv->hscrollbar);
@@ -1248,8 +1247,16 @@ get_scroll_unit (GtkScrolledWindow *sw,
adj = gtk_scrollbar_get_adjustment (scrollbar);
page_size = gtk_adjustment_get_page_size (adj);
scroll_unit = pow (page_size, 2.0 / 3.0);
-#else
- scroll_unit = 1;
+
+#ifdef GDK_WINDOWING_MACOS
+ {
+ GdkEvent *event = gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (scroll));
+
+ if (event != NULL &&
+ gdk_event_get_event_type (event) == GDK_SCROLL &&
+ gdk_scroll_event_get_direction (event) == GDK_SCROLL_SMOOTH)
+ scroll_unit = 1;
+ }
#endif
return scroll_unit;
@@ -1397,7 +1404,7 @@ scrolled_window_scroll (GtkScrolledWindow *scrolled_window,
double scroll_unit;
adj = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->hscrollbar));
- scroll_unit = get_scroll_unit (scrolled_window, GTK_ORIENTATION_HORIZONTAL);
+ scroll_unit = get_scroll_unit (scrolled_window, GTK_ORIENTATION_HORIZONTAL, scroll);
new_value = priv->unclamped_hadj_value + delta_x * scroll_unit;
_gtk_scrolled_window_set_adjustment_value (scrolled_window, adj,
@@ -1412,7 +1419,7 @@ scrolled_window_scroll (GtkScrolledWindow *scrolled_window,
double scroll_unit;
adj = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->vscrollbar));
- scroll_unit = get_scroll_unit (scrolled_window, GTK_ORIENTATION_VERTICAL);
+ scroll_unit = get_scroll_unit (scrolled_window, GTK_ORIENTATION_VERTICAL, scroll);
new_value = priv->unclamped_vadj_value + delta_y * scroll_unit;
_gtk_scrolled_window_set_adjustment_value (scrolled_window, adj,
@@ -1470,8 +1477,8 @@ scroll_controller_decelerate (GtkEventControllerScroll *scroll,
shifted = (state & GDK_SHIFT_MASK) != 0;
- unit_x = get_scroll_unit (scrolled_window, GTK_ORIENTATION_HORIZONTAL);
- unit_y = get_scroll_unit (scrolled_window, GTK_ORIENTATION_VERTICAL);
+ unit_x = get_scroll_unit (scrolled_window, GTK_ORIENTATION_HORIZONTAL, scroll);
+ unit_y = get_scroll_unit (scrolled_window, GTK_ORIENTATION_VERTICAL, scroll);
if (shifted)
{