1 /*
2 * Copyright © 2020 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * SPDX-License-Identifier: LGPL-2.1-or-later
18 */
19
20 #include "config.h"
21
22 #include <AppKit/AppKit.h>
23 #include <float.h>
24 #include <gdk/gdk.h>
25
26 #import "GdkMacosCairoView.h"
27
28 #include "gdkdeviceprivate.h"
29 #include "gdkdisplay.h"
30 #include "gdkframeclockidleprivate.h"
31 #include "gdkinternals.h"
32 #include "gdksurfaceprivate.h"
33
34 #include "gdkmacosdevice.h"
35 #include "gdkmacosdevice-private.h"
36 #include "gdkmacosdisplay-private.h"
37 #include "gdkmacosdrag-private.h"
38 #include "gdkmacosdragsurface-private.h"
39 #include "gdkmacosglcontext-private.h"
40 #include "gdkmacosmonitor-private.h"
41 #include "gdkmacospopupsurface-private.h"
42 #include "gdkmacossurface-private.h"
43 #include "gdkmacostoplevelsurface-private.h"
44 #include "gdkmacosutils-private.h"
45
46 G_DEFINE_ABSTRACT_TYPE (GdkMacosSurface, gdk_macos_surface, GDK_TYPE_SURFACE)
47
48 enum {
49 PROP_0,
50 PROP_NATIVE,
51 LAST_PROP
52 };
53
54 static GParamSpec *properties [LAST_PROP];
55
56 static gboolean
window_is_fullscreen(GdkMacosSurface * self)57 window_is_fullscreen (GdkMacosSurface *self)
58 {
59 g_assert (GDK_IS_MACOS_SURFACE (self));
60
61 return ([self->window styleMask] & NSWindowStyleMaskFullScreen) != 0;
62 }
63
64 void
_gdk_macos_surface_reposition_children(GdkMacosSurface * self)65 _gdk_macos_surface_reposition_children (GdkMacosSurface *self)
66 {
67 g_assert (GDK_IS_MACOS_SURFACE (self));
68
69 if (GDK_SURFACE_DESTROYED (self))
70 return;
71
72 if (!gdk_surface_get_mapped (GDK_SURFACE (self)))
73 return;
74
75 for (const GList *iter = GDK_SURFACE (self)->children;
76 iter != NULL;
77 iter = iter->next)
78 {
79 GdkMacosSurface *child = iter->data;
80
81 g_assert (GDK_IS_MACOS_SURFACE (child));
82
83 if (GDK_IS_MACOS_POPUP_SURFACE (child))
84 _gdk_macos_popup_surface_reposition (GDK_MACOS_POPUP_SURFACE (child));
85 }
86
87 if (GDK_IS_POPUP (self) && self->did_initial_present)
88 gdk_surface_request_layout (GDK_SURFACE (self));
89 }
90
91 static void
gdk_macos_surface_set_input_region(GdkSurface * surface,cairo_region_t * region)92 gdk_macos_surface_set_input_region (GdkSurface *surface,
93 cairo_region_t *region)
94 {
95 }
96
97 static void
gdk_macos_surface_set_opaque_region(GdkSurface * surface,cairo_region_t * region)98 gdk_macos_surface_set_opaque_region (GdkSurface *surface,
99 cairo_region_t *region)
100 {
101 GdkMacosSurface *self = (GdkMacosSurface *)surface;
102 NSView *nsview;
103
104 g_assert (GDK_IS_MACOS_SURFACE (self));
105
106 if (region != self->opaque_region)
107 {
108 g_clear_pointer (&self->opaque_region, cairo_region_destroy);
109 self->opaque_region = cairo_region_copy (region);
110 }
111
112 if ((nsview = _gdk_macos_surface_get_view (GDK_MACOS_SURFACE (surface))) &&
113 GDK_IS_MACOS_CAIRO_VIEW (nsview))
114 [(GdkMacosCairoView *)nsview setOpaqueRegion:region];
115 }
116
117 static void
gdk_macos_surface_hide(GdkSurface * surface)118 gdk_macos_surface_hide (GdkSurface *surface)
119 {
120 GdkMacosSurface *self = (GdkMacosSurface *)surface;
121 GdkSeat *seat;
122 gboolean was_mapped;
123
124 g_assert (GDK_IS_MACOS_SURFACE (self));
125
126 was_mapped = GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self));
127
128 seat = gdk_display_get_default_seat (surface->display);
129 gdk_seat_ungrab (seat);
130
131 [self->window hide];
132
133 _gdk_surface_clear_update_area (surface);
134
135 if (was_mapped)
136 gdk_surface_freeze_updates (GDK_SURFACE (self));
137 }
138
139 static int
gdk_macos_surface_get_scale_factor(GdkSurface * surface)140 gdk_macos_surface_get_scale_factor (GdkSurface *surface)
141 {
142 GdkMacosSurface *self = (GdkMacosSurface *)surface;
143
144 g_assert (GDK_IS_MACOS_SURFACE (self));
145
146 return [self->window backingScaleFactor];
147 }
148
149 void
_gdk_macos_surface_set_shadow(GdkMacosSurface * surface,int top,int right,int bottom,int left)150 _gdk_macos_surface_set_shadow (GdkMacosSurface *surface,
151 int top,
152 int right,
153 int bottom,
154 int left)
155 {
156 GdkMacosSurface *self = (GdkMacosSurface *)surface;
157
158 g_assert (GDK_IS_MACOS_SURFACE (self));
159
160 if (self->shadow_top == top &&
161 self->shadow_right == right &&
162 self->shadow_bottom == bottom &&
163 self->shadow_left == left)
164 return;
165
166 self->shadow_top = top;
167 self->shadow_right = right;
168 self->shadow_bottom = bottom;
169 self->shadow_left = left;
170
171 if (top || right || bottom || left)
172 [self->window setHasShadow:NO];
173 }
174
175 static void
gdk_macos_surface_begin_frame(GdkMacosSurface * self)176 gdk_macos_surface_begin_frame (GdkMacosSurface *self)
177 {
178 g_assert (GDK_IS_MACOS_SURFACE (self));
179
180 }
181
182 static void
gdk_macos_surface_end_frame(GdkMacosSurface * self)183 gdk_macos_surface_end_frame (GdkMacosSurface *self)
184 {
185 GdkFrameTimings *timings;
186 GdkFrameClock *frame_clock;
187 GdkDisplay *display;
188
189 g_assert (GDK_IS_MACOS_SURFACE (self));
190
191 display = gdk_surface_get_display (GDK_SURFACE (self));
192 frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self));
193
194 if ((timings = gdk_frame_clock_get_current_timings (frame_clock)))
195 self->pending_frame_counter = timings->frame_counter;
196
197 _gdk_macos_display_add_frame_callback (GDK_MACOS_DISPLAY (display), self);
198
199 gdk_surface_freeze_updates (GDK_SURFACE (self));
200 }
201
202 static void
gdk_macos_surface_before_paint(GdkMacosSurface * self,GdkFrameClock * frame_clock)203 gdk_macos_surface_before_paint (GdkMacosSurface *self,
204 GdkFrameClock *frame_clock)
205 {
206 GdkSurface *surface = (GdkSurface *)self;
207
208 g_assert (GDK_IS_MACOS_SURFACE (self));
209 g_assert (GDK_IS_FRAME_CLOCK (frame_clock));
210
211 if (surface->update_freeze_count > 0)
212 return;
213
214 gdk_macos_surface_begin_frame (self);
215 }
216
217 static void
gdk_macos_surface_after_paint(GdkMacosSurface * self,GdkFrameClock * frame_clock)218 gdk_macos_surface_after_paint (GdkMacosSurface *self,
219 GdkFrameClock *frame_clock)
220 {
221 GdkSurface *surface = (GdkSurface *)self;
222
223 g_assert (GDK_IS_MACOS_SURFACE (self));
224 g_assert (GDK_IS_FRAME_CLOCK (frame_clock));
225
226 if (surface->update_freeze_count > 0)
227 return;
228
229 gdk_macos_surface_end_frame (self);
230 }
231
232 static void
gdk_macos_surface_get_root_coords(GdkSurface * surface,int x,int y,int * root_x,int * root_y)233 gdk_macos_surface_get_root_coords (GdkSurface *surface,
234 int x,
235 int y,
236 int *root_x,
237 int *root_y)
238 {
239 GdkMacosSurface *self = (GdkMacosSurface *)surface;
240
241 g_assert (GDK_IS_MACOS_SURFACE (self));
242
243 if (root_x)
244 *root_x = self->root_x + x;
245
246 if (root_y)
247 *root_y = self->root_y + y;
248 }
249
250 static gboolean
gdk_macos_surface_get_device_state(GdkSurface * surface,GdkDevice * device,double * x,double * y,GdkModifierType * mask)251 gdk_macos_surface_get_device_state (GdkSurface *surface,
252 GdkDevice *device,
253 double *x,
254 double *y,
255 GdkModifierType *mask)
256 {
257 GdkDisplay *display;
258 NSWindow *nswindow;
259 NSPoint point;
260
261 g_assert (GDK_IS_MACOS_SURFACE (surface));
262 g_assert (GDK_IS_MACOS_DEVICE (device));
263 g_assert (x != NULL);
264 g_assert (y != NULL);
265 g_assert (mask != NULL);
266
267 if (GDK_SURFACE_DESTROYED (surface))
268 return FALSE;
269
270 display = gdk_surface_get_display (surface);
271 nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface));
272 point = [nswindow mouseLocationOutsideOfEventStream];
273
274 *mask = _gdk_macos_display_get_current_keyboard_modifiers (GDK_MACOS_DISPLAY (display))
275 | _gdk_macos_display_get_current_mouse_modifiers (GDK_MACOS_DISPLAY (display));
276
277 *x = point.x;
278 *y = surface->height - point.y;
279
280 return *x >= 0 && *y >= 0 && *x < surface->width && *y < surface->height;
281 }
282
283 static void
gdk_macos_surface_get_geometry(GdkSurface * surface,int * x,int * y,int * width,int * height)284 gdk_macos_surface_get_geometry (GdkSurface *surface,
285 int *x,
286 int *y,
287 int *width,
288 int *height)
289 {
290 g_assert (GDK_IS_MACOS_SURFACE (surface));
291
292 if (x != NULL)
293 *x = surface->x;
294
295 if (y != NULL)
296 *y = surface->y;
297
298 if (width != NULL)
299 *width = surface->width;
300
301 if (height != NULL)
302 *height = surface->height;
303 }
304
305 static GdkDrag *
gdk_macos_surface_drag_begin(GdkSurface * surface,GdkDevice * device,GdkContentProvider * content,GdkDragAction actions,double dx,double dy)306 gdk_macos_surface_drag_begin (GdkSurface *surface,
307 GdkDevice *device,
308 GdkContentProvider *content,
309 GdkDragAction actions,
310 double dx,
311 double dy)
312 {
313 GdkMacosSurface *self = (GdkMacosSurface *)surface;
314 GdkMacosSurface *drag_surface;
315 GdkMacosDrag *drag;
316 GdkCursor *cursor;
317 GdkSeat *seat;
318 double px;
319 double py;
320 int sx;
321 int sy;
322
323 g_assert (GDK_IS_MACOS_SURFACE (self));
324 g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self) ||
325 GDK_IS_MACOS_POPUP_SURFACE (self));
326 g_assert (GDK_IS_MACOS_DEVICE (device));
327 g_assert (GDK_IS_CONTENT_PROVIDER (content));
328
329 seat = gdk_device_get_seat (device);
330 gdk_macos_device_query_state (device, surface, NULL, &px, &py, NULL);
331 _gdk_macos_surface_get_root_coords (GDK_MACOS_SURFACE (surface), &sx, &sy);
332 drag_surface = _gdk_macos_surface_new (GDK_MACOS_DISPLAY (surface->display),
333 GDK_SURFACE_TEMP,
334 surface,
335 sx, sy, 1, 1);
336 drag = g_object_new (GDK_TYPE_MACOS_DRAG,
337 "drag-surface", drag_surface,
338 "surface", surface,
339 "device", device,
340 "content", content,
341 "actions", actions,
342 NULL);
343 g_clear_object (&drag_surface);
344
345 cursor = gdk_drag_get_cursor (GDK_DRAG (drag),
346 gdk_drag_get_selected_action (GDK_DRAG (drag)));
347 gdk_drag_set_cursor (GDK_DRAG (drag), cursor);
348
349 if (!_gdk_macos_drag_begin (drag))
350 {
351 g_object_unref (drag);
352 return NULL;
353 }
354
355 /* Hold a reference until drop_done is called */
356 g_object_ref (drag);
357
358 return GDK_DRAG (g_steal_pointer (&drag));
359 }
360
361 static void
gdk_macos_surface_destroy(GdkSurface * surface,gboolean foreign_destroy)362 gdk_macos_surface_destroy (GdkSurface *surface,
363 gboolean foreign_destroy)
364 {
365 GDK_BEGIN_MACOS_ALLOC_POOL;
366
367 GdkMacosSurface *self = (GdkMacosSurface *)surface;
368 GdkMacosWindow *window = g_steal_pointer (&self->window);
369 GdkFrameClock *frame_clock;
370
371 if ((frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self))))
372 {
373 g_signal_handlers_disconnect_by_func (frame_clock,
374 G_CALLBACK (gdk_macos_surface_before_paint),
375 self);
376 g_signal_handlers_disconnect_by_func (frame_clock,
377 G_CALLBACK (gdk_macos_surface_before_paint),
378 self);
379 }
380
381 g_clear_pointer (&self->title, g_free);
382 g_clear_pointer (&self->opaque_region, cairo_region_destroy);
383
384 if (window != NULL)
385 [window close];
386
387 _gdk_macos_display_surface_removed (GDK_MACOS_DISPLAY (surface->display), self);
388
389 g_clear_pointer (&self->monitors, g_ptr_array_unref);
390
391 g_assert (self->sorted.prev == NULL);
392 g_assert (self->sorted.next == NULL);
393 g_assert (self->frame.prev == NULL);
394 g_assert (self->frame.next == NULL);
395 g_assert (self->main.prev == NULL);
396 g_assert (self->main.next == NULL);
397
398 GDK_END_MACOS_ALLOC_POOL;
399 }
400
401 static void
gdk_macos_surface_constructed(GObject * object)402 gdk_macos_surface_constructed (GObject *object)
403 {
404 GdkMacosSurface *self = (GdkMacosSurface *)object;
405 GdkFrameClock *frame_clock;
406
407 g_assert (GDK_IS_MACOS_SURFACE (self));
408
409 G_OBJECT_CLASS (gdk_macos_surface_parent_class)->constructed (object);
410
411 if (self->window != NULL)
412 {
413 NSRect bounds = [[self->window contentView] bounds];
414
415 GDK_SURFACE (self)->width = bounds.size.width;
416 GDK_SURFACE (self)->height = bounds.size.height;
417 _gdk_macos_surface_update_position (self);
418 }
419
420 if ((frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self))))
421 {
422 g_signal_connect_object (frame_clock,
423 "before-paint",
424 G_CALLBACK (gdk_macos_surface_before_paint),
425 self,
426 G_CONNECT_SWAPPED);
427 g_signal_connect_object (frame_clock,
428 "after-paint",
429 G_CALLBACK (gdk_macos_surface_after_paint),
430 self,
431 G_CONNECT_SWAPPED);
432 }
433 }
434
435 static void
gdk_macos_surface_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)436 gdk_macos_surface_get_property (GObject *object,
437 guint prop_id,
438 GValue *value,
439 GParamSpec *pspec)
440 {
441 GdkMacosSurface *self = GDK_MACOS_SURFACE (object);
442
443 switch (prop_id)
444 {
445 case PROP_NATIVE:
446 g_value_set_pointer (value, self->window);
447 break;
448
449 default:
450 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
451 }
452 }
453
454 static void
gdk_macos_surface_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)455 gdk_macos_surface_set_property (GObject *object,
456 guint prop_id,
457 const GValue *value,
458 GParamSpec *pspec)
459 {
460 GdkMacosSurface *self = GDK_MACOS_SURFACE (object);
461
462 switch (prop_id)
463 {
464 case PROP_NATIVE:
465 self->window = g_value_get_pointer (value);
466 [self->window setGdkSurface:self];
467 break;
468
469 default:
470 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
471 }
472 }
473
474 static void
gdk_macos_surface_class_init(GdkMacosSurfaceClass * klass)475 gdk_macos_surface_class_init (GdkMacosSurfaceClass *klass)
476 {
477 GObjectClass *object_class = G_OBJECT_CLASS (klass);
478 GdkSurfaceClass *surface_class = GDK_SURFACE_CLASS (klass);
479
480 object_class->constructed = gdk_macos_surface_constructed;
481 object_class->get_property = gdk_macos_surface_get_property;
482 object_class->set_property = gdk_macos_surface_set_property;
483
484 surface_class->destroy = gdk_macos_surface_destroy;
485 surface_class->drag_begin = gdk_macos_surface_drag_begin;
486 surface_class->get_device_state = gdk_macos_surface_get_device_state;
487 surface_class->get_geometry = gdk_macos_surface_get_geometry;
488 surface_class->get_root_coords = gdk_macos_surface_get_root_coords;
489 surface_class->get_scale_factor = gdk_macos_surface_get_scale_factor;
490 surface_class->hide = gdk_macos_surface_hide;
491 surface_class->set_input_region = gdk_macos_surface_set_input_region;
492 surface_class->set_opaque_region = gdk_macos_surface_set_opaque_region;
493
494 properties [PROP_NATIVE] =
495 g_param_spec_pointer ("native",
496 "Native",
497 "The native NSWindow",
498 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
499
500 g_object_class_install_properties (object_class, LAST_PROP, properties);
501 }
502
503 static void
gdk_macos_surface_init(GdkMacosSurface * self)504 gdk_macos_surface_init (GdkMacosSurface *self)
505 {
506 self->frame.data = self;
507 self->main.data = self;
508 self->sorted.data = self;
509 self->monitors = g_ptr_array_new_with_free_func (g_object_unref);
510 }
511
512 GdkMacosSurface *
_gdk_macos_surface_new(GdkMacosDisplay * display,GdkSurfaceType surface_type,GdkSurface * parent,int x,int y,int width,int height)513 _gdk_macos_surface_new (GdkMacosDisplay *display,
514 GdkSurfaceType surface_type,
515 GdkSurface *parent,
516 int x,
517 int y,
518 int width,
519 int height)
520 {
521 GdkFrameClock *frame_clock;
522 GdkMacosSurface *ret;
523
524 g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
525
526 if (parent != NULL)
527 frame_clock = g_object_ref (gdk_surface_get_frame_clock (parent));
528 else
529 frame_clock = _gdk_frame_clock_idle_new ();
530
531 switch (surface_type)
532 {
533 case GDK_SURFACE_TOPLEVEL:
534 ret = _gdk_macos_toplevel_surface_new (display, parent, frame_clock, x, y, width, height);
535 break;
536
537 case GDK_SURFACE_POPUP:
538 ret = _gdk_macos_popup_surface_new (display, parent, frame_clock, x, y, width, height);
539 break;
540
541 case GDK_SURFACE_TEMP:
542 ret = _gdk_macos_drag_surface_new (display, frame_clock, x, y, width, height);
543 break;
544
545 default:
546 g_warn_if_reached ();
547 ret = NULL;
548 }
549
550 if (ret != NULL)
551 {
552 gdk_surface_freeze_updates (GDK_SURFACE (ret));
553 _gdk_macos_surface_monitor_changed (ret);
554 }
555
556 g_object_unref (frame_clock);
557
558 return g_steal_pointer (&ret);
559 }
560
561 void
_gdk_macos_surface_get_shadow(GdkMacosSurface * self,int * top,int * right,int * bottom,int * left)562 _gdk_macos_surface_get_shadow (GdkMacosSurface *self,
563 int *top,
564 int *right,
565 int *bottom,
566 int *left)
567 {
568
569 g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
570
571 if (top)
572 *top = self->shadow_top;
573
574 if (left)
575 *left = self->shadow_left;
576
577 if (bottom)
578 *bottom = self->shadow_bottom;
579
580 if (right)
581 *right = self->shadow_right;
582 }
583
584 const char *
_gdk_macos_surface_get_title(GdkMacosSurface * self)585 _gdk_macos_surface_get_title (GdkMacosSurface *self)
586 {
587
588 return self->title;
589 }
590
591 void
_gdk_macos_surface_set_title(GdkMacosSurface * self,const char * title)592 _gdk_macos_surface_set_title (GdkMacosSurface *self,
593 const char *title)
594 {
595 g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
596
597 if (title == NULL)
598 title = "";
599
600 if (g_strcmp0 (self->title, title) != 0)
601 {
602 g_free (self->title);
603 self->title = g_strdup (title);
604
605 GDK_BEGIN_MACOS_ALLOC_POOL;
606 [self->window setTitle:[NSString stringWithUTF8String:title]];
607 GDK_END_MACOS_ALLOC_POOL;
608 }
609 }
610
611 CGDirectDisplayID
_gdk_macos_surface_get_screen_id(GdkMacosSurface * self)612 _gdk_macos_surface_get_screen_id (GdkMacosSurface *self)
613 {
614 g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), (CGDirectDisplayID)-1);
615
616 if (self->window != NULL)
617 {
618 NSScreen *screen = [self->window screen];
619 return [[[screen deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue];
620 }
621
622 return (CGDirectDisplayID)-1;
623 }
624
625 NSWindow *
_gdk_macos_surface_get_native(GdkMacosSurface * self)626 _gdk_macos_surface_get_native (GdkMacosSurface *self)
627 {
628 g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL);
629
630 return (NSWindow *)self->window;
631 }
632
633 void
_gdk_macos_surface_set_geometry_hints(GdkMacosSurface * self,const GdkGeometry * geometry,GdkSurfaceHints geom_mask)634 _gdk_macos_surface_set_geometry_hints (GdkMacosSurface *self,
635 const GdkGeometry *geometry,
636 GdkSurfaceHints geom_mask)
637 {
638 NSSize max_size;
639 NSSize min_size;
640
641 g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
642 g_return_if_fail (geometry != NULL);
643 g_return_if_fail (self->window != NULL);
644
645 if (geom_mask & GDK_HINT_MAX_SIZE)
646 max_size = NSMakeSize (geometry->max_width, geometry->max_height);
647 else
648 max_size = NSMakeSize (FLT_MAX, FLT_MAX);
649 [self->window setContentMaxSize:max_size];
650
651 if (geom_mask & GDK_HINT_MIN_SIZE)
652 min_size = NSMakeSize (geometry->min_width, geometry->min_height);
653 else
654 min_size = NSMakeSize (1, 1);
655 [self->window setContentMinSize:min_size];
656 }
657
658 void
_gdk_macos_surface_resize(GdkMacosSurface * self,int width,int height)659 _gdk_macos_surface_resize (GdkMacosSurface *self,
660 int width,
661 int height)
662 {
663 g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
664
665 _gdk_macos_surface_move_resize (self, -1, -1, width, height);
666 }
667
668 void
_gdk_macos_surface_update_fullscreen_state(GdkMacosSurface * self)669 _gdk_macos_surface_update_fullscreen_state (GdkMacosSurface *self)
670 {
671 GdkToplevelState state;
672 gboolean is_fullscreen;
673 gboolean was_fullscreen;
674
675 g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
676
677 state = GDK_SURFACE (self)->state;
678 is_fullscreen = window_is_fullscreen (self);
679 was_fullscreen = (state & GDK_TOPLEVEL_STATE_FULLSCREEN) != 0;
680
681 if (is_fullscreen != was_fullscreen)
682 {
683 if (is_fullscreen)
684 gdk_synthesize_surface_state (GDK_SURFACE (self), 0, GDK_TOPLEVEL_STATE_FULLSCREEN);
685 else
686 gdk_synthesize_surface_state (GDK_SURFACE (self), GDK_TOPLEVEL_STATE_FULLSCREEN, 0);
687 }
688 }
689
690 void
_gdk_macos_surface_update_position(GdkMacosSurface * self)691 _gdk_macos_surface_update_position (GdkMacosSurface *self)
692 {
693 GdkSurface *surface = GDK_SURFACE (self);
694 GdkDisplay *display = gdk_surface_get_display (surface);
695 NSRect frame_rect = [self->window frame];
696 NSRect content_rect = [self->window contentRectForFrameRect:frame_rect];
697
698 _gdk_macos_display_from_display_coords (GDK_MACOS_DISPLAY (display),
699 content_rect.origin.x,
700 content_rect.origin.y + content_rect.size.height,
701 &self->root_x, &self->root_y);
702
703 if (surface->parent != NULL)
704 {
705 surface->x = self->root_x - GDK_MACOS_SURFACE (surface->parent)->root_x;
706 surface->y = self->root_y - GDK_MACOS_SURFACE (surface->parent)->root_y;
707 }
708 else
709 {
710 surface->x = self->root_x;
711 surface->y = self->root_y;
712 }
713 }
714
715 void
_gdk_macos_surface_thaw(GdkMacosSurface * self,gint64 presentation_time,gint64 refresh_interval)716 _gdk_macos_surface_thaw (GdkMacosSurface *self,
717 gint64 presentation_time,
718 gint64 refresh_interval)
719 {
720 GdkFrameTimings *timings;
721 GdkFrameClock *frame_clock;
722
723 g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
724
725 gdk_surface_thaw_updates (GDK_SURFACE (self));
726
727 frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self));
728
729 if (self->pending_frame_counter)
730 {
731 timings = gdk_frame_clock_get_timings (frame_clock, self->pending_frame_counter);
732
733 if (timings != NULL)
734 {
735 timings->presentation_time = presentation_time - refresh_interval;
736 timings->complete = TRUE;
737 }
738
739 self->pending_frame_counter = 0;
740 }
741
742 timings = gdk_frame_clock_get_current_timings (frame_clock);
743
744 if (timings != NULL)
745 {
746 timings->refresh_interval = refresh_interval;
747 timings->predicted_presentation_time = presentation_time;
748 }
749 }
750
751 void
_gdk_macos_surface_show(GdkMacosSurface * self)752 _gdk_macos_surface_show (GdkMacosSurface *self)
753 {
754 gboolean was_mapped;
755
756 g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
757
758 if (GDK_SURFACE_DESTROYED (self))
759 return;
760
761 was_mapped = GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self));
762
763 if (!was_mapped)
764 gdk_surface_set_is_mapped (GDK_SURFACE (self), TRUE);
765
766 _gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (GDK_SURFACE (self)->display));
767
768 [self->window showAndMakeKey:YES];
769
770 if (!was_mapped)
771 {
772 if (gdk_surface_get_mapped (GDK_SURFACE (self)))
773 {
774 _gdk_macos_surface_update_position (self);
775 gdk_surface_invalidate_rect (GDK_SURFACE (self), NULL);
776 gdk_surface_thaw_updates (GDK_SURFACE (self));
777 }
778 }
779
780 [[self->window contentView] setNeedsDisplay:YES];
781 }
782
783 CGContextRef
_gdk_macos_surface_acquire_context(GdkMacosSurface * self,gboolean clear_scale,gboolean antialias)784 _gdk_macos_surface_acquire_context (GdkMacosSurface *self,
785 gboolean clear_scale,
786 gboolean antialias)
787 {
788 CGContextRef cg_context;
789
790 g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL);
791
792 if (GDK_SURFACE_DESTROYED (self))
793 return NULL;
794
795 if (!(cg_context = [[NSGraphicsContext currentContext] CGContext]))
796 return NULL;
797
798 CGContextSaveGState (cg_context);
799
800 if (!antialias)
801 CGContextSetAllowsAntialiasing (cg_context, antialias);
802
803 if (clear_scale)
804 {
805 CGSize scale;
806
807 scale = CGSizeMake (1.0, 1.0);
808 scale = CGContextConvertSizeToDeviceSpace (cg_context, scale);
809
810 CGContextScaleCTM (cg_context, 1.0 / fabs (scale.width), 1.0 / fabs (scale.height));
811 }
812
813 return cg_context;
814 }
815
816 void
_gdk_macos_surface_release_context(GdkMacosSurface * self,CGContextRef cg_context)817 _gdk_macos_surface_release_context (GdkMacosSurface *self,
818 CGContextRef cg_context)
819 {
820 g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
821
822 CGContextRestoreGState (cg_context);
823 CGContextSetAllowsAntialiasing (cg_context, TRUE);
824 }
825
826 void
_gdk_macos_surface_synthesize_null_key(GdkMacosSurface * self)827 _gdk_macos_surface_synthesize_null_key (GdkMacosSurface *self)
828 {
829 GdkTranslatedKey translated = {0};
830 GdkTranslatedKey no_lock = {0};
831 GdkDisplay *display;
832 GdkEvent *event;
833 GdkSeat *seat;
834
835 g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
836
837 translated.keyval = GDK_KEY_VoidSymbol;
838 no_lock.keyval = GDK_KEY_VoidSymbol;
839
840 display = gdk_surface_get_display (GDK_SURFACE (self));
841 seat = gdk_display_get_default_seat (display);
842 event = gdk_key_event_new (GDK_KEY_PRESS,
843 GDK_SURFACE (self),
844 gdk_seat_get_keyboard (seat),
845 GDK_CURRENT_TIME,
846 0,
847 0,
848 FALSE,
849 &translated,
850 &no_lock);
851 _gdk_event_queue_append (display, event);
852 }
853
854 void
_gdk_macos_surface_move(GdkMacosSurface * self,int x,int y)855 _gdk_macos_surface_move (GdkMacosSurface *self,
856 int x,
857 int y)
858 {
859 g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
860
861 _gdk_macos_surface_move_resize (self, x, y, -1, -1);
862 }
863
864 void
_gdk_macos_surface_move_resize(GdkMacosSurface * self,int x,int y,int width,int height)865 _gdk_macos_surface_move_resize (GdkMacosSurface *self,
866 int x,
867 int y,
868 int width,
869 int height)
870 {
871 GdkSurface *surface = (GdkSurface *)self;
872 GdkDisplay *display;
873 NSRect content_rect;
874 NSRect frame_rect;
875 gboolean size_changed;
876
877 g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
878
879 if ((x == -1 || (x == self->root_x)) &&
880 (y == -1 || (y == self->root_y)) &&
881 (width == -1 || (width == surface->width)) &&
882 (height == -1 || (height == surface->height)))
883 return;
884
885 display = gdk_surface_get_display (surface);
886
887 if (width == -1)
888 width = surface->width;
889
890 if (height == -1)
891 height = surface->height;
892
893 if (x == -1)
894 x = self->root_x;
895
896 if (y == -1)
897 y = self->root_y;
898
899 size_changed = height != surface->height || width != surface->width;
900
901 if (GDK_IS_MACOS_SURFACE (surface->parent))
902 {
903 surface->x = x - GDK_MACOS_SURFACE (surface->parent)->root_x;
904 surface->y = y - GDK_MACOS_SURFACE (surface->parent)->root_y;
905 }
906 else
907 {
908 surface->x = x;
909 surface->y = y;
910 }
911
912 _gdk_macos_display_to_display_coords (GDK_MACOS_DISPLAY (display),
913 x, y + height, &x, &y);
914
915 content_rect = NSMakeRect (x, y, width, height);
916 frame_rect = [self->window frameRectForContentRect:content_rect];
917 [self->window setFrame:frame_rect display:YES];
918
919 if (size_changed)
920 gdk_surface_invalidate_rect (surface, NULL);
921 }
922
923 gboolean
_gdk_macos_surface_is_tracking(GdkMacosSurface * self,NSTrackingArea * area)924 _gdk_macos_surface_is_tracking (GdkMacosSurface *self,
925 NSTrackingArea *area)
926 {
927 GdkMacosBaseView *view;
928
929 g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), FALSE);
930
931 if (self->window == NULL)
932 return FALSE;
933
934 view = (GdkMacosBaseView *)[self->window contentView];
935 if (view == NULL)
936 return FALSE;
937
938 return [view trackingArea] == area;
939 }
940
941 void
_gdk_macos_surface_monitor_changed(GdkMacosSurface * self)942 _gdk_macos_surface_monitor_changed (GdkMacosSurface *self)
943 {
944 GListModel *monitors;
945 GdkRectangle rect;
946 GdkRectangle intersect;
947 GdkDisplay *display;
948 GdkMonitor *monitor;
949 guint n_monitors;
950
951 g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
952
953 rect.x = self->root_x;
954 rect.y = self->root_y;
955 rect.width = GDK_SURFACE (self)->width;
956 rect.height = GDK_SURFACE (self)->height;
957
958 for (guint i = self->monitors->len; i > 0; i--)
959 {
960 monitor = g_ptr_array_index (self->monitors, i-1);
961
962 if (!gdk_rectangle_intersect (&monitor->geometry, &rect, &intersect))
963 {
964 g_object_ref (monitor);
965 g_ptr_array_remove_index (self->monitors, i-1);
966 gdk_surface_leave_monitor (GDK_SURFACE (self), monitor);
967 g_object_unref (monitor);
968 }
969 }
970
971 display = gdk_surface_get_display (GDK_SURFACE (self));
972 monitors = gdk_display_get_monitors (display);
973 n_monitors = g_list_model_get_n_items (monitors);
974
975 for (guint i = 0; i < n_monitors; i++)
976 {
977 monitor = g_list_model_get_item (monitors, i);
978
979 if (!g_ptr_array_find (self->monitors, monitor, NULL))
980 {
981 gdk_surface_enter_monitor (GDK_SURFACE (self), monitor);
982 g_ptr_array_add (self->monitors, g_object_ref (monitor));
983 }
984
985 g_object_unref (monitor);
986 }
987 }
988
989 GdkMonitor *
_gdk_macos_surface_get_best_monitor(GdkMacosSurface * self)990 _gdk_macos_surface_get_best_monitor (GdkMacosSurface *self)
991 {
992 GdkMonitor *best = NULL;
993 GdkRectangle rect;
994 int best_area = 0;
995
996 g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL);
997
998 rect.x = self->root_x;
999 rect.y = self->root_y;
1000 rect.width = GDK_SURFACE (self)->width;
1001 rect.height = GDK_SURFACE (self)->height;
1002
1003 for (guint i = 0; i < self->monitors->len; i++)
1004 {
1005 GdkMonitor *monitor = g_ptr_array_index (self->monitors, i);
1006 GdkRectangle intersect;
1007
1008 if (gdk_rectangle_intersect (&monitor->geometry, &rect, &intersect))
1009 {
1010 int area = intersect.width * intersect.height;
1011
1012 if (area > best_area)
1013 {
1014 best = monitor;
1015 best_area = area;
1016 }
1017 }
1018 }
1019
1020 return best;
1021 }
1022
1023 NSView *
_gdk_macos_surface_get_view(GdkMacosSurface * self)1024 _gdk_macos_surface_get_view (GdkMacosSurface *self)
1025 {
1026 g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL);
1027
1028 if (self->window == NULL)
1029 return NULL;
1030
1031 return [self->window contentView];
1032 }
1033
1034 void
_gdk_macos_surface_set_opacity(GdkMacosSurface * self,double opacity)1035 _gdk_macos_surface_set_opacity (GdkMacosSurface *self,
1036 double opacity)
1037 {
1038 g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
1039
1040 if (self->window != NULL)
1041 [self->window setAlphaValue:opacity];
1042 }
1043
1044 void
_gdk_macos_surface_get_root_coords(GdkMacosSurface * self,int * x,int * y)1045 _gdk_macos_surface_get_root_coords (GdkMacosSurface *self,
1046 int *x,
1047 int *y)
1048 {
1049 GdkSurface *surface;
1050 int out_x = 0;
1051 int out_y = 0;
1052
1053 g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
1054
1055 for (surface = GDK_SURFACE (self); surface; surface = surface->parent)
1056 {
1057 out_x += surface->x;
1058 out_y += surface->y;
1059 }
1060
1061 if (x)
1062 *x = out_x;
1063
1064 if (y)
1065 *y = out_y;
1066 }
1067