/* * Copyright © 2020 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 . * * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "config.h" #include #include #include #import "GdkMacosCairoView.h" #include "gdkdeviceprivate.h" #include "gdkdisplay.h" #include "gdkframeclockidleprivate.h" #include "gdkinternals.h" #include "gdksurfaceprivate.h" #include "gdkmacosdevice.h" #include "gdkmacosdevice-private.h" #include "gdkmacosdisplay-private.h" #include "gdkmacosdrag-private.h" #include "gdkmacosdragsurface-private.h" #include "gdkmacosglcontext-private.h" #include "gdkmacosmonitor-private.h" #include "gdkmacospopupsurface-private.h" #include "gdkmacossurface-private.h" #include "gdkmacostoplevelsurface-private.h" #include "gdkmacosutils-private.h" G_DEFINE_ABSTRACT_TYPE (GdkMacosSurface, gdk_macos_surface, GDK_TYPE_SURFACE) enum { PROP_0, PROP_NATIVE, LAST_PROP }; static GParamSpec *properties [LAST_PROP]; static gboolean window_is_fullscreen (GdkMacosSurface *self) { g_assert (GDK_IS_MACOS_SURFACE (self)); return ([self->window styleMask] & NSWindowStyleMaskFullScreen) != 0; } void _gdk_macos_surface_reposition_children (GdkMacosSurface *self) { g_assert (GDK_IS_MACOS_SURFACE (self)); if (GDK_SURFACE_DESTROYED (self)) return; if (!gdk_surface_get_mapped (GDK_SURFACE (self))) return; for (const GList *iter = GDK_SURFACE (self)->children; iter != NULL; iter = iter->next) { GdkMacosSurface *child = iter->data; g_assert (GDK_IS_MACOS_SURFACE (child)); 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 gdk_macos_surface_set_input_region (GdkSurface *surface, cairo_region_t *region) { } static void gdk_macos_surface_set_opaque_region (GdkSurface *surface, cairo_region_t *region) { GdkMacosSurface *self = (GdkMacosSurface *)surface; NSView *nsview; 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))) && GDK_IS_MACOS_CAIRO_VIEW (nsview)) [(GdkMacosCairoView *)nsview setOpaqueRegion:region]; } static void gdk_macos_surface_hide (GdkSurface *surface) { GdkMacosSurface *self = (GdkMacosSurface *)surface; GdkSeat *seat; gboolean was_mapped; g_assert (GDK_IS_MACOS_SURFACE (self)); was_mapped = GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self)); seat = gdk_display_get_default_seat (surface->display); gdk_seat_ungrab (seat); [self->window hide]; _gdk_surface_clear_update_area (surface); if (was_mapped) gdk_surface_freeze_updates (GDK_SURFACE (self)); } static int gdk_macos_surface_get_scale_factor (GdkSurface *surface) { GdkMacosSurface *self = (GdkMacosSurface *)surface; g_assert (GDK_IS_MACOS_SURFACE (self)); return [self->window backingScaleFactor]; } void _gdk_macos_surface_set_shadow (GdkMacosSurface *surface, int top, int right, int bottom, int left) { GdkMacosSurface *self = (GdkMacosSurface *)surface; g_assert (GDK_IS_MACOS_SURFACE (self)); if (self->shadow_top == top && self->shadow_right == right && self->shadow_bottom == bottom && self->shadow_left == left) return; self->shadow_top = top; self->shadow_right = right; self->shadow_bottom = bottom; self->shadow_left = left; if (top || right || bottom || left) [self->window setHasShadow:NO]; } static void gdk_macos_surface_begin_frame (GdkMacosSurface *self) { g_assert (GDK_IS_MACOS_SURFACE (self)); } static void gdk_macos_surface_end_frame (GdkMacosSurface *self) { GdkFrameTimings *timings; GdkFrameClock *frame_clock; GdkDisplay *display; g_assert (GDK_IS_MACOS_SURFACE (self)); display = gdk_surface_get_display (GDK_SURFACE (self)); frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self)); if ((timings = gdk_frame_clock_get_current_timings (frame_clock))) self->pending_frame_counter = timings->frame_counter; _gdk_macos_display_add_frame_callback (GDK_MACOS_DISPLAY (display), self); gdk_surface_freeze_updates (GDK_SURFACE (self)); } static void gdk_macos_surface_before_paint (GdkMacosSurface *self, GdkFrameClock *frame_clock) { GdkSurface *surface = (GdkSurface *)self; g_assert (GDK_IS_MACOS_SURFACE (self)); g_assert (GDK_IS_FRAME_CLOCK (frame_clock)); if (surface->update_freeze_count > 0) return; gdk_macos_surface_begin_frame (self); } static void gdk_macos_surface_after_paint (GdkMacosSurface *self, GdkFrameClock *frame_clock) { GdkSurface *surface = (GdkSurface *)self; g_assert (GDK_IS_MACOS_SURFACE (self)); g_assert (GDK_IS_FRAME_CLOCK (frame_clock)); if (surface->update_freeze_count > 0) return; gdk_macos_surface_end_frame (self); } static void gdk_macos_surface_get_root_coords (GdkSurface *surface, int x, int y, int *root_x, int *root_y) { GdkMacosSurface *self = (GdkMacosSurface *)surface; g_assert (GDK_IS_MACOS_SURFACE (self)); if (root_x) *root_x = self->root_x + x; if (root_y) *root_y = self->root_y + y; } static gboolean gdk_macos_surface_get_device_state (GdkSurface *surface, GdkDevice *device, double *x, double *y, GdkModifierType *mask) { GdkDisplay *display; NSWindow *nswindow; NSPoint point; g_assert (GDK_IS_MACOS_SURFACE (surface)); g_assert (GDK_IS_MACOS_DEVICE (device)); g_assert (x != NULL); g_assert (y != NULL); g_assert (mask != NULL); if (GDK_SURFACE_DESTROYED (surface)) return FALSE; display = gdk_surface_get_display (surface); nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface)); point = [nswindow mouseLocationOutsideOfEventStream]; *mask = _gdk_macos_display_get_current_keyboard_modifiers (GDK_MACOS_DISPLAY (display)) | _gdk_macos_display_get_current_mouse_modifiers (GDK_MACOS_DISPLAY (display)); *x = point.x; *y = surface->height - point.y; return *x >= 0 && *y >= 0 && *x < surface->width && *y < surface->height; } static void gdk_macos_surface_get_geometry (GdkSurface *surface, int *x, int *y, int *width, int *height) { g_assert (GDK_IS_MACOS_SURFACE (surface)); if (x != NULL) *x = surface->x; if (y != NULL) *y = surface->y; if (width != NULL) *width = surface->width; if (height != NULL) *height = surface->height; } static GdkDrag * gdk_macos_surface_drag_begin (GdkSurface *surface, GdkDevice *device, GdkContentProvider *content, GdkDragAction actions, double dx, double dy) { GdkMacosSurface *self = (GdkMacosSurface *)surface; GdkMacosSurface *drag_surface; GdkMacosDrag *drag; GdkCursor *cursor; GdkSeat *seat; double px; double py; int sx; int sy; g_assert (GDK_IS_MACOS_SURFACE (self)); g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self) || GDK_IS_MACOS_POPUP_SURFACE (self)); g_assert (GDK_IS_MACOS_DEVICE (device)); g_assert (GDK_IS_CONTENT_PROVIDER (content)); seat = gdk_device_get_seat (device); gdk_macos_device_query_state (device, surface, NULL, &px, &py, NULL); _gdk_macos_surface_get_root_coords (GDK_MACOS_SURFACE (surface), &sx, &sy); drag_surface = _gdk_macos_surface_new (GDK_MACOS_DISPLAY (surface->display), GDK_SURFACE_TEMP, surface, sx, sy, 1, 1); drag = g_object_new (GDK_TYPE_MACOS_DRAG, "drag-surface", drag_surface, "surface", surface, "device", device, "content", content, "actions", actions, NULL); g_clear_object (&drag_surface); cursor = gdk_drag_get_cursor (GDK_DRAG (drag), gdk_drag_get_selected_action (GDK_DRAG (drag))); gdk_drag_set_cursor (GDK_DRAG (drag), cursor); if (!_gdk_macos_drag_begin (drag)) { g_object_unref (drag); return NULL; } /* Hold a reference until drop_done is called */ g_object_ref (drag); return GDK_DRAG (g_steal_pointer (&drag)); } static GdkGLContext * gdk_macos_surface_create_gl_context (GdkSurface *surface, gboolean attached, GdkGLContext *share, GError **error) { GdkMacosSurface *self = (GdkMacosSurface *)surface; g_assert (GDK_IS_MACOS_SURFACE (self)); g_assert (!share || GDK_IS_GL_CONTEXT (share)); return _gdk_macos_gl_context_new (self, attached, share, error); } static void gdk_macos_surface_destroy (GdkSurface *surface, gboolean foreign_destroy) { GDK_BEGIN_MACOS_ALLOC_POOL; GdkMacosSurface *self = (GdkMacosSurface *)surface; GdkMacosWindow *window = g_steal_pointer (&self->window); GdkFrameClock *frame_clock; if ((frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self)))) { g_signal_handlers_disconnect_by_func (frame_clock, G_CALLBACK (gdk_macos_surface_before_paint), self); g_signal_handlers_disconnect_by_func (frame_clock, G_CALLBACK (gdk_macos_surface_before_paint), self); } g_clear_pointer (&self->title, g_free); g_clear_pointer (&self->opaque_region, cairo_region_destroy); if (window != NULL) [window close]; _gdk_macos_display_surface_removed (GDK_MACOS_DISPLAY (surface->display), self); g_clear_pointer (&self->monitors, g_ptr_array_unref); g_assert (self->sorted.prev == NULL); g_assert (self->sorted.next == NULL); g_assert (self->frame.prev == NULL); g_assert (self->frame.next == NULL); g_assert (self->main.prev == NULL); g_assert (self->main.next == NULL); GDK_END_MACOS_ALLOC_POOL; } static void gdk_macos_surface_constructed (GObject *object) { GdkMacosSurface *self = (GdkMacosSurface *)object; GdkFrameClock *frame_clock; g_assert (GDK_IS_MACOS_SURFACE (self)); G_OBJECT_CLASS (gdk_macos_surface_parent_class)->constructed (object); if (self->window != NULL) { NSRect bounds = [[self->window contentView] bounds]; GDK_SURFACE (self)->width = bounds.size.width; GDK_SURFACE (self)->height = bounds.size.height; _gdk_macos_surface_update_position (self); } if ((frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self)))) { g_signal_connect_object (frame_clock, "before-paint", G_CALLBACK (gdk_macos_surface_before_paint), self, G_CONNECT_SWAPPED); g_signal_connect_object (frame_clock, "after-paint", G_CALLBACK (gdk_macos_surface_after_paint), self, G_CONNECT_SWAPPED); } } static void gdk_macos_surface_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GdkMacosSurface *self = GDK_MACOS_SURFACE (object); switch (prop_id) { case PROP_NATIVE: g_value_set_pointer (value, self->window); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void gdk_macos_surface_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GdkMacosSurface *self = GDK_MACOS_SURFACE (object); switch (prop_id) { case PROP_NATIVE: self->window = g_value_get_pointer (value); [self->window setGdkSurface:self]; break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void gdk_macos_surface_class_init (GdkMacosSurfaceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GdkSurfaceClass *surface_class = GDK_SURFACE_CLASS (klass); object_class->constructed = gdk_macos_surface_constructed; object_class->get_property = gdk_macos_surface_get_property; object_class->set_property = gdk_macos_surface_set_property; surface_class->create_gl_context = gdk_macos_surface_create_gl_context; surface_class->destroy = gdk_macos_surface_destroy; surface_class->drag_begin = gdk_macos_surface_drag_begin; surface_class->get_device_state = gdk_macos_surface_get_device_state; surface_class->get_geometry = gdk_macos_surface_get_geometry; surface_class->get_root_coords = gdk_macos_surface_get_root_coords; surface_class->get_scale_factor = gdk_macos_surface_get_scale_factor; surface_class->hide = gdk_macos_surface_hide; surface_class->set_input_region = gdk_macos_surface_set_input_region; surface_class->set_opaque_region = gdk_macos_surface_set_opaque_region; properties [PROP_NATIVE] = g_param_spec_pointer ("native", "Native", "The native NSWindow", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, properties); } static void gdk_macos_surface_init (GdkMacosSurface *self) { self->frame.data = self; self->main.data = self; self->sorted.data = self; self->monitors = g_ptr_array_new_with_free_func (g_object_unref); } GdkMacosSurface * _gdk_macos_surface_new (GdkMacosDisplay *display, GdkSurfaceType surface_type, GdkSurface *parent, int x, int y, int width, int height) { GdkFrameClock *frame_clock; GdkMacosSurface *ret; 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)); else frame_clock = _gdk_frame_clock_idle_new (); switch (surface_type) { case GDK_SURFACE_TOPLEVEL: ret = _gdk_macos_toplevel_surface_new (display, parent, frame_clock, x, y, width, height); break; case GDK_SURFACE_POPUP: ret = _gdk_macos_popup_surface_new (display, parent, frame_clock, x, y, width, height); break; case GDK_SURFACE_TEMP: ret = _gdk_macos_drag_surface_new (display, frame_clock, x, y, width, height); break; default: g_warn_if_reached (); ret = NULL; } if (ret != NULL) { gdk_surface_freeze_updates (GDK_SURFACE (ret)); _gdk_macos_surface_monitor_changed (ret); } g_object_unref (frame_clock); return g_steal_pointer (&ret); } void _gdk_macos_surface_get_shadow (GdkMacosSurface *self, int *top, int *right, int *bottom, int *left) { g_return_if_fail (GDK_IS_MACOS_SURFACE (self)); if (top) *top = self->shadow_top; if (left) *left = self->shadow_left; if (bottom) *bottom = self->shadow_bottom; if (right) *right = self->shadow_right; } const char * _gdk_macos_surface_get_title (GdkMacosSurface *self) { return self->title; } void _gdk_macos_surface_set_title (GdkMacosSurface *self, const char *title) { g_return_if_fail (GDK_IS_MACOS_SURFACE (self)); if (title == NULL) title = ""; if (g_strcmp0 (self->title, title) != 0) { g_free (self->title); self->title = g_strdup (title); GDK_BEGIN_MACOS_ALLOC_POOL; [self->window setTitle:[NSString stringWithUTF8String:title]]; GDK_END_MACOS_ALLOC_POOL; } } CGDirectDisplayID _gdk_macos_surface_get_screen_id (GdkMacosSurface *self) { g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), (CGDirectDisplayID)-1); if (self->window != NULL) { NSScreen *screen = [self->window screen]; return [[[screen deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue]; } return (CGDirectDisplayID)-1; } NSWindow * _gdk_macos_surface_get_native (GdkMacosSurface *self) { g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL); return (NSWindow *)self->window; } void _gdk_macos_surface_set_geometry_hints (GdkMacosSurface *self, const GdkGeometry *geometry, GdkSurfaceHints geom_mask) { NSSize max_size; NSSize min_size; g_return_if_fail (GDK_IS_MACOS_SURFACE (self)); g_return_if_fail (geometry != NULL); g_return_if_fail (self->window != NULL); if (geom_mask & GDK_HINT_MAX_SIZE) max_size = NSMakeSize (geometry->max_width, geometry->max_height); else max_size = NSMakeSize (FLT_MAX, FLT_MAX); [self->window setContentMaxSize:max_size]; if (geom_mask & GDK_HINT_MIN_SIZE) min_size = NSMakeSize (geometry->min_width, geometry->min_height); else min_size = NSMakeSize (1, 1); [self->window setContentMinSize:min_size]; } void _gdk_macos_surface_resize (GdkMacosSurface *self, int width, int height) { g_return_if_fail (GDK_IS_MACOS_SURFACE (self)); _gdk_macos_surface_move_resize (self, -1, -1, width, height); } void _gdk_macos_surface_update_fullscreen_state (GdkMacosSurface *self) { GdkToplevelState state; gboolean is_fullscreen; gboolean was_fullscreen; g_return_if_fail (GDK_IS_MACOS_SURFACE (self)); state = GDK_SURFACE (self)->state; is_fullscreen = window_is_fullscreen (self); was_fullscreen = (state & GDK_TOPLEVEL_STATE_FULLSCREEN) != 0; if (is_fullscreen != was_fullscreen) { if (is_fullscreen) gdk_synthesize_surface_state (GDK_SURFACE (self), 0, GDK_TOPLEVEL_STATE_FULLSCREEN); else gdk_synthesize_surface_state (GDK_SURFACE (self), GDK_TOPLEVEL_STATE_FULLSCREEN, 0); } } void _gdk_macos_surface_update_position (GdkMacosSurface *self) { GdkSurface *surface = GDK_SURFACE (self); GdkDisplay *display = gdk_surface_get_display (surface); NSRect frame_rect = [self->window frame]; NSRect content_rect = [self->window contentRectForFrameRect:frame_rect]; _gdk_macos_display_from_display_coords (GDK_MACOS_DISPLAY (display), content_rect.origin.x, content_rect.origin.y + content_rect.size.height, &self->root_x, &self->root_y); if (surface->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; } else { surface->x = self->root_x; surface->y = self->root_y; } } void _gdk_macos_surface_thaw (GdkMacosSurface *self, gint64 presentation_time, gint64 refresh_interval) { GdkFrameTimings *timings; GdkFrameClock *frame_clock; g_return_if_fail (GDK_IS_MACOS_SURFACE (self)); gdk_surface_thaw_updates (GDK_SURFACE (self)); 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; } } void _gdk_macos_surface_show (GdkMacosSurface *self) { gboolean was_mapped; g_return_if_fail (GDK_IS_MACOS_SURFACE (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->window showAndMakeKey:YES]; if (!was_mapped) { if (gdk_surface_get_mapped (GDK_SURFACE (self))) { _gdk_macos_surface_update_position (self); gdk_surface_invalidate_rect (GDK_SURFACE (self), NULL); gdk_surface_thaw_updates (GDK_SURFACE (self)); } } [[self->window contentView] setNeedsDisplay:YES]; } CGContextRef _gdk_macos_surface_acquire_context (GdkMacosSurface *self, gboolean clear_scale, gboolean antialias) { CGContextRef cg_context; g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL); if (GDK_SURFACE_DESTROYED (self)) return NULL; if (!(cg_context = [[NSGraphicsContext currentContext] CGContext])) return NULL; CGContextSaveGState (cg_context); if (!antialias) CGContextSetAllowsAntialiasing (cg_context, antialias); if (clear_scale) { CGSize scale; scale = CGSizeMake (1.0, 1.0); scale = CGContextConvertSizeToDeviceSpace (cg_context, scale); CGContextScaleCTM (cg_context, 1.0 / scale.width, 1.0 / scale.height); } return cg_context; } void _gdk_macos_surface_release_context (GdkMacosSurface *self, CGContextRef cg_context) { g_return_if_fail (GDK_IS_MACOS_SURFACE (self)); CGContextRestoreGState (cg_context); CGContextSetAllowsAntialiasing (cg_context, TRUE); } void _gdk_macos_surface_synthesize_null_key (GdkMacosSurface *self) { GdkTranslatedKey translated = {0}; GdkTranslatedKey no_lock = {0}; GdkDisplay *display; GdkEvent *event; GdkSeat *seat; g_return_if_fail (GDK_IS_MACOS_SURFACE (self)); translated.keyval = GDK_KEY_VoidSymbol; no_lock.keyval = GDK_KEY_VoidSymbol; display = gdk_surface_get_display (GDK_SURFACE (self)); seat = gdk_display_get_default_seat (display); event = gdk_key_event_new (GDK_KEY_PRESS, GDK_SURFACE (self), gdk_seat_get_keyboard (seat), GDK_CURRENT_TIME, 0, 0, FALSE, &translated, &no_lock); _gdk_event_queue_append (display, event); } void _gdk_macos_surface_move (GdkMacosSurface *self, int x, int y) { g_return_if_fail (GDK_IS_MACOS_SURFACE (self)); _gdk_macos_surface_move_resize (self, x, y, -1, -1); } void _gdk_macos_surface_move_resize (GdkMacosSurface *self, int x, int y, int width, int height) { GdkSurface *surface = (GdkSurface *)self; GdkDisplay *display; NSRect content_rect; NSRect frame_rect; gboolean size_changed; 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))) return; display = gdk_surface_get_display (surface); if (width == -1) width = surface->width; if (height == -1) height = surface->height; if (x == -1) x = self->root_x; if (y == -1) y = self->root_y; size_changed = height != surface->height || width != surface->width; if (GDK_IS_MACOS_SURFACE (surface->parent)) { surface->x = x - GDK_MACOS_SURFACE (surface->parent)->root_x; surface->y = y - GDK_MACOS_SURFACE (surface->parent)->root_y; } else { surface->x = x; surface->y = y; } _gdk_macos_display_to_display_coords (GDK_MACOS_DISPLAY (display), x, y + height, &x, &y); content_rect = NSMakeRect (x, y, width, height); frame_rect = [self->window frameRectForContentRect:content_rect]; [self->window setFrame:frame_rect display:YES]; if (size_changed) gdk_surface_invalidate_rect (surface, NULL); } gboolean _gdk_macos_surface_is_tracking (GdkMacosSurface *self, NSTrackingArea *area) { GdkMacosBaseView *view; g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), FALSE); if (self->window == NULL) return FALSE; view = (GdkMacosBaseView *)[self->window contentView]; if (view == NULL) return FALSE; return [view trackingArea] == area; } void _gdk_macos_surface_monitor_changed (GdkMacosSurface *self) { GListModel *monitors; GdkRectangle rect; GdkRectangle intersect; GdkDisplay *display; GdkMonitor *monitor; guint n_monitors; g_return_if_fail (GDK_IS_MACOS_SURFACE (self)); rect.x = self->root_x; rect.y = self->root_y; rect.width = GDK_SURFACE (self)->width; rect.height = GDK_SURFACE (self)->height; for (guint i = self->monitors->len; i > 0; i--) { monitor = g_ptr_array_index (self->monitors, i-1); if (!gdk_rectangle_intersect (&monitor->geometry, &rect, &intersect)) { g_object_ref (monitor); g_ptr_array_remove_index (self->monitors, i-1); gdk_surface_leave_monitor (GDK_SURFACE (self), monitor); g_object_unref (monitor); } } display = gdk_surface_get_display (GDK_SURFACE (self)); monitors = gdk_display_get_monitors (display); n_monitors = g_list_model_get_n_items (monitors); for (guint i = 0; i < n_monitors; i++) { monitor = g_list_model_get_item (monitors, i); if (!g_ptr_array_find (self->monitors, monitor, NULL)) { gdk_surface_enter_monitor (GDK_SURFACE (self), monitor); g_ptr_array_add (self->monitors, g_object_ref (monitor)); } g_object_unref (monitor); } } 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; for (guint i = 0; i < self->monitors->len; i++) { GdkMonitor *monitor = g_ptr_array_index (self->monitors, i); GdkRectangle intersect; if (gdk_rectangle_intersect (&monitor->geometry, &rect, &intersect)) { int area = intersect.width * intersect.height; if (area > best_area) { best = monitor; best_area = area; } } } return best; } NSView * _gdk_macos_surface_get_view (GdkMacosSurface *self) { g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL); if (self->window == NULL) return NULL; return [self->window contentView]; } void _gdk_macos_surface_set_opacity (GdkMacosSurface *self, double opacity) { g_return_if_fail (GDK_IS_MACOS_SURFACE (self)); if (self->window != NULL) [self->window setAlphaValue:opacity]; } void _gdk_macos_surface_get_root_coords (GdkMacosSurface *self, int *x, int *y) { GdkSurface *surface; int out_x = 0; int out_y = 0; g_return_if_fail (GDK_IS_MACOS_SURFACE (self)); for (surface = GDK_SURFACE (self); surface; surface = surface->parent) { out_x += surface->x; out_y += surface->y; } if (x) *x = out_x; if (y) *y = out_y; }