1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-2007 Peter Mattis, Spencer Kimball,
3  * Josh MacDonald, Ryan Lortie
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /*
20  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
21  * file for a list of people on the GTK+ Team.  See the ChangeLog
22  * files for a list of changes.  These files are distributed with
23  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
24  */
25 
26 #include "config.h"
27 
28 #include "gdksurface-broadway.h"
29 
30 #include "gdkbroadwaydisplay.h"
31 #include "gdkdeviceprivate.h"
32 #include "gdkdisplay-broadway.h"
33 #include "gdkdevice-broadway.h"
34 #include "gdkdisplay.h"
35 #include "gdkdragsurfaceprivate.h"
36 #include "gdkeventsource.h"
37 #include "gdkframeclockidleprivate.h"
38 #include "gdkinternals.h"
39 #include "gdkpopupprivate.h"
40 #include "gdkprivate-broadway.h"
41 #include "gdksurfaceprivate.h"
42 #include "gdktextureprivate.h"
43 #include "gdktoplevelprivate.h"
44 #include "gdk-private.h"
45 
46 #include <graphene.h>
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <string.h>
50 
51 /* Forward declarations */
52 static void        gdk_broadway_surface_finalize   (GObject            *object);
53 
54 G_DEFINE_TYPE (GdkBroadwaySurface, gdk_broadway_surface, GDK_TYPE_SURFACE)
55 
56 GType gdk_broadway_toplevel_get_type (void) G_GNUC_CONST;
57 GType gdk_broadway_popup_get_type (void) G_GNUC_CONST;
58 GType gdk_broadway_drag_surface_get_type (void) G_GNUC_CONST;
59 
60 #define GDK_TYPE_BROADWAY_TOPLEVEL (gdk_broadway_toplevel_get_type ())
61 #define GDK_TYPE_BROADWAY_POPUP (gdk_broadway_popup_get_type ())
62 #define GDK_TYPE_BROADWAY_DRAG_SURFACE (gdk_broadway_drag_surface_get_type ())
63 
64 /* We need to flush in an idle rather than AFTER_PAINT, as the clock
65    is frozen during e.g. surface resizes so the paint will not happen
66    and the surface resize request is never flushed. */
67 static void
queue_flush(GdkSurface * surface)68 queue_flush (GdkSurface *surface)
69 {
70   gdk_broadway_display_flush_in_idle (gdk_surface_get_display (surface));
71 }
72 
73 static void
gdk_broadway_surface_init(GdkBroadwaySurface * impl)74 gdk_broadway_surface_init (GdkBroadwaySurface *impl)
75 {
76 }
77 
78 static void
gdk_broadway_surface_finalize(GObject * object)79 gdk_broadway_surface_finalize (GObject *object)
80 {
81   GdkBroadwaySurface *impl;
82   GdkBroadwayDisplay *broadway_display;
83 
84   g_return_if_fail (GDK_IS_BROADWAY_SURFACE (object));
85 
86   impl = GDK_BROADWAY_SURFACE (object);
87 
88   _gdk_broadway_surface_grab_check_destroy (GDK_SURFACE (impl));
89 
90   broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (GDK_SURFACE (impl)));
91 
92   g_hash_table_remove (broadway_display->id_ht, GINT_TO_POINTER (impl->id));
93 
94   if (impl->cursor)
95     g_object_unref (impl->cursor);
96 
97   broadway_display->toplevels = g_list_remove (broadway_display->toplevels, impl);
98 
99   G_OBJECT_CLASS (gdk_broadway_surface_parent_class)->finalize (object);
100 }
101 
102 static gboolean
thaw_updates_cb(GdkSurface * surface)103 thaw_updates_cb (GdkSurface *surface)
104 {
105   if (!GDK_SURFACE_DESTROYED (surface))
106     gdk_surface_thaw_updates (surface);
107   g_object_unref (surface);
108   return G_SOURCE_REMOVE;
109 }
110 
111 void
_gdk_broadway_roundtrip_notify(GdkSurface * surface,guint32 tag,gboolean local_reply)112 _gdk_broadway_roundtrip_notify (GdkSurface  *surface,
113                                 guint32      tag,
114                                 gboolean     local_reply)
115 {
116   GdkBroadwaySurface *impl = GDK_BROADWAY_SURFACE (surface);
117   GdkFrameClock *clock = gdk_surface_get_frame_clock (surface);
118   GdkFrameTimings *timings;
119 
120   timings = gdk_frame_clock_get_timings (clock, impl->pending_frame_counter);
121   impl->pending_frame_counter = 0;
122 
123   /* If there is no remote web client, rate limit update to once a second */
124   if (local_reply)
125     g_timeout_add_seconds (1, (GSourceFunc)thaw_updates_cb, g_object_ref (surface));
126   else
127     gdk_surface_thaw_updates (surface);
128 
129   if (timings)
130     {
131       timings->refresh_interval = 33333; /* default to 1/30th of a second */
132       // This isn't quite right, since we've done a roundtrip back too, can we do better?
133       timings->presentation_time = g_get_monotonic_time ();
134       timings->complete = TRUE;
135 
136 
137 #ifdef G_ENABLE_DEBUG
138       if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0)
139         _gdk_frame_clock_debug_print_timings (clock, timings);
140 
141   if (GDK_PROFILER_IS_RUNNING)
142     _gdk_frame_clock_add_timings_to_profiler (clock, timings);
143 #endif
144     }
145 }
146 
147 static void
on_frame_clock_after_paint(GdkFrameClock * clock,GdkSurface * surface)148 on_frame_clock_after_paint (GdkFrameClock *clock,
149                             GdkSurface    *surface)
150 {
151   GdkDisplay *display = gdk_surface_get_display (surface);
152   GdkBroadwaySurface *impl = GDK_BROADWAY_SURFACE (surface);
153   GdkBroadwayDisplay *broadway_display;
154 
155   impl->pending_frame_counter = gdk_frame_clock_get_frame_counter (clock);
156   gdk_surface_freeze_updates (surface);
157 
158   broadway_display = GDK_BROADWAY_DISPLAY (display);
159 
160   _gdk_broadway_server_roundtrip (broadway_display->server, impl->id, _gdk_display_get_next_serial (display));
161 
162   gdk_display_flush (display);
163 }
164 
165 static void
on_frame_clock_before_paint(GdkFrameClock * clock,GdkSurface * surface)166 on_frame_clock_before_paint (GdkFrameClock *clock,
167                              GdkSurface    *surface)
168 {
169   GdkFrameTimings *timings = gdk_frame_clock_get_current_timings (clock);
170   gint64 presentation_time;
171   gint64 refresh_interval;
172 
173   if (surface->update_freeze_count > 0)
174     return;
175 
176   gdk_frame_clock_get_refresh_info (clock,
177                                     timings->frame_time,
178                                     &refresh_interval, &presentation_time);
179   if (presentation_time != 0)
180     {
181       timings->predicted_presentation_time = presentation_time + refresh_interval;
182     }
183   else
184     {
185       timings->predicted_presentation_time = timings->frame_time + refresh_interval / 2 + refresh_interval;
186     }
187 }
188 
189 static void
connect_frame_clock(GdkSurface * surface)190 connect_frame_clock (GdkSurface *surface)
191 {
192   GdkFrameClock *frame_clock = gdk_surface_get_frame_clock (surface);
193 
194   g_signal_connect (frame_clock, "before-paint",
195                     G_CALLBACK (on_frame_clock_before_paint), surface);
196   g_signal_connect (frame_clock, "after-paint",
197                     G_CALLBACK (on_frame_clock_after_paint), surface);
198 }
199 
200 static void
disconnect_frame_clock(GdkSurface * surface)201 disconnect_frame_clock (GdkSurface *surface)
202 {
203   GdkFrameClock *frame_clock = gdk_surface_get_frame_clock (surface);
204 
205   g_signal_handlers_disconnect_by_func (frame_clock,
206                                         on_frame_clock_before_paint, surface);
207   g_signal_handlers_disconnect_by_func (frame_clock,
208                                         on_frame_clock_after_paint, surface);
209 }
210 
211 GdkSurface *
_gdk_broadway_display_create_surface(GdkDisplay * display,GdkSurfaceType surface_type,GdkSurface * parent,int x,int y,int width,int height)212 _gdk_broadway_display_create_surface (GdkDisplay     *display,
213                                       GdkSurfaceType  surface_type,
214                                       GdkSurface     *parent,
215                                       int             x,
216                                       int             y,
217                                       int             width,
218                                       int             height)
219 {
220   GdkBroadwayDisplay *broadway_display;
221   GdkFrameClock *frame_clock;
222   GdkSurface *surface;
223   GdkBroadwaySurface *impl;
224   GType type;
225 
226   if (parent)
227     frame_clock = g_object_ref (gdk_surface_get_frame_clock (parent));
228   else
229     frame_clock = _gdk_frame_clock_idle_new ();
230 
231   switch (surface_type)
232     {
233     case GDK_SURFACE_TOPLEVEL:
234       type = GDK_TYPE_BROADWAY_TOPLEVEL;
235       break;
236     case GDK_SURFACE_POPUP:
237       type = GDK_TYPE_BROADWAY_POPUP;
238       break;
239     case GDK_SURFACE_TEMP:
240       type = GDK_TYPE_BROADWAY_DRAG_SURFACE;
241       break;
242     default:
243       g_assert_not_reached ();
244       break;
245     }
246 
247   surface = g_object_new (type,
248                           "display", display,
249                           "frame-clock", frame_clock,
250                           NULL);
251 
252   g_object_unref (frame_clock);
253 
254   surface->parent = parent;
255   surface->x = x;
256   surface->y = y;
257   surface->width = width;
258   surface->height = height;
259 
260   broadway_display = GDK_BROADWAY_DISPLAY (display);
261 
262   impl = GDK_BROADWAY_SURFACE (surface);
263   impl->root_x = x;
264   impl->root_y = y;
265   if (parent)
266     {
267       impl->root_x += GDK_BROADWAY_SURFACE (parent)->root_x;
268       impl->root_y += GDK_BROADWAY_SURFACE (parent)->root_y;
269     }
270 
271   impl->id = _gdk_broadway_server_new_surface (broadway_display->server,
272                                                impl->root_x,
273                                                impl->root_y,
274                                                surface->width,
275                                                surface->height);
276   g_hash_table_insert (broadway_display->id_ht, GINT_TO_POINTER(impl->id), surface);
277 
278   g_object_ref (surface);
279 
280   if (!surface->parent)
281     broadway_display->toplevels = g_list_prepend (broadway_display->toplevels, impl);
282 
283   connect_frame_clock (surface);
284 
285   /* We treat the real parent as a default transient for to get stacking right */
286   if (parent)
287     {
288       impl->transient_for = GDK_BROADWAY_SURFACE (parent)->id;
289       _gdk_broadway_server_surface_set_transient_for (broadway_display->server, impl->id, impl->transient_for);
290     }
291 
292   return surface;
293 }
294 
295 static cairo_surface_t *
gdk_broadway_surface_ref_cairo_surface(GdkSurface * surface)296 gdk_broadway_surface_ref_cairo_surface (GdkSurface *surface)
297 {
298   if (GDK_IS_BROADWAY_SURFACE (surface) &&
299       GDK_SURFACE_DESTROYED (surface))
300     return NULL;
301 
302   return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
303 }
304 
305 static void
_gdk_broadway_surface_destroy(GdkSurface * surface,gboolean foreign_destroy)306 _gdk_broadway_surface_destroy (GdkSurface *surface,
307                                gboolean    foreign_destroy)
308 {
309   GdkBroadwaySurface *impl;
310   GdkBroadwayDisplay *broadway_display;
311 
312   g_return_if_fail (GDK_IS_SURFACE (surface));
313 
314   impl = GDK_BROADWAY_SURFACE (surface);
315 
316   disconnect_frame_clock (surface);
317 
318   if (impl->node_data)
319     g_array_unref (impl->node_data);
320   if (impl->node_data_textures)
321     g_ptr_array_unref (impl->node_data_textures);
322 
323   _gdk_broadway_surface_grab_check_destroy (surface);
324 
325   broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (surface));
326   g_hash_table_remove (broadway_display->id_ht, GINT_TO_POINTER (impl->id));
327 
328   _gdk_broadway_server_destroy_surface (broadway_display->server, impl->id);
329 }
330 
331 void
gdk_broadway_surface_set_nodes(GdkSurface * surface,GArray * nodes,GPtrArray * node_textures)332 gdk_broadway_surface_set_nodes (GdkSurface *surface,
333                                 GArray     *nodes,
334                                 GPtrArray  *node_textures)
335 {
336   GdkBroadwaySurface *impl;
337   GdkBroadwayDisplay *broadway_display;
338 
339   g_return_if_fail (GDK_IS_SURFACE (surface));
340 
341   impl = GDK_BROADWAY_SURFACE (surface);
342 
343   broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (surface));
344 
345   if (nodes)
346     g_array_ref (nodes);
347   if (impl->node_data)
348     g_array_unref (impl->node_data);
349   impl->node_data = nodes;
350 
351   if (node_textures)
352     g_ptr_array_ref (node_textures);
353   if (impl->node_data_textures)
354     g_ptr_array_unref (impl->node_data_textures);
355   impl->node_data_textures = node_textures;
356 
357   gdk_broadway_server_surface_set_nodes (broadway_display->server, impl->id, impl->node_data);
358 }
359 
360 /* This function is called when the XSurface is really gone.
361  */
362 static void
gdk_broadway_surface_destroy_notify(GdkSurface * surface)363 gdk_broadway_surface_destroy_notify (GdkSurface *surface)
364 {
365   if (!GDK_SURFACE_DESTROYED (surface))
366     _gdk_surface_destroy (surface, TRUE);
367 
368   g_object_unref (surface);
369 }
370 
371 static void
gdk_broadway_surface_show(GdkSurface * surface,gboolean already_mapped)372 gdk_broadway_surface_show (GdkSurface *surface,
373                            gboolean    already_mapped)
374 {
375   GdkBroadwaySurface *impl;
376   GdkBroadwayDisplay *broadway_display;
377 
378   impl = GDK_BROADWAY_SURFACE (surface);
379   impl->visible = TRUE;
380 
381   /* FIXME: update state ? */
382 
383   broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (surface));
384   if (_gdk_broadway_server_surface_show (broadway_display->server, impl->id))
385     queue_flush (surface);
386 
387 }
388 
389 static void
gdk_broadway_surface_hide(GdkSurface * surface)390 gdk_broadway_surface_hide (GdkSurface *surface)
391 {
392   GdkBroadwaySurface *impl;
393   GdkBroadwayDisplay *broadway_display;
394 
395   impl = GDK_BROADWAY_SURFACE (surface);
396   impl->visible = FALSE;
397 
398   /* FIXME: update state ? */
399 
400   broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (surface));
401 
402   _gdk_broadway_surface_grab_check_unmap (surface,
403                                          _gdk_broadway_server_get_next_serial (broadway_display->server));
404 
405   if (_gdk_broadway_server_surface_hide (broadway_display->server, impl->id))
406     queue_flush (surface);
407 
408   _gdk_surface_clear_update_area (surface);
409 }
410 
411 static int
gdk_broadway_surface_get_scale_factor(GdkSurface * surface)412 gdk_broadway_surface_get_scale_factor (GdkSurface *surface)
413 {
414   GdkBroadwayDisplay *broadway_display;
415 
416   if (GDK_SURFACE_DESTROYED (surface))
417     return 1;
418 
419   broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (surface));
420 
421   return broadway_display->scale_factor;
422 }
423 
424 static void
sync_child_root_pos(GdkSurface * parent)425 sync_child_root_pos (GdkSurface *parent)
426 {
427   GdkBroadwaySurface *parent_impl = GDK_BROADWAY_SURFACE (parent);
428   GdkBroadwayDisplay *broadway_display;
429   GList *l;
430 
431   broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (parent));
432 
433   for (l = parent->children; l; l = l->next)
434     {
435       GdkBroadwaySurface *child_impl = l->data;
436       GdkSurface *child = GDK_SURFACE (child_impl);
437       int root_x, root_y;
438 
439       root_x = child->x + parent_impl->root_x;
440       root_y = child->y + parent_impl->root_y;
441 
442       if (root_x != child_impl->root_x ||
443           root_y != child_impl->root_y)
444         {
445           child_impl->root_x = root_x;
446           child_impl->root_y = root_y;
447 
448           _gdk_broadway_server_surface_move_resize (broadway_display->server,
449                                                     child_impl->id,
450                                                     TRUE,
451                                                     child_impl->root_x, child_impl->root_y,
452                                                     child->width, child->height);
453           sync_child_root_pos (child);
454         }
455     }
456 }
457 
458 /* x, y is relative to parent */
459 static void
gdk_broadway_surface_move_resize_internal(GdkSurface * surface,gboolean with_move,int x,int y,int width,int height)460 gdk_broadway_surface_move_resize_internal (GdkSurface *surface,
461                                            gboolean    with_move,
462                                            int         x,
463                                            int         y,
464                                            int         width,
465                                            int         height)
466 {
467   GdkBroadwaySurface *impl = GDK_BROADWAY_SURFACE (surface);
468   GdkBroadwayDisplay *broadway_display;
469   gboolean size_changed;
470 
471   if (with_move)
472     {
473       surface->x = x;
474       surface->y = y;
475       impl->root_x = x;
476       impl->root_y = y;
477       if (surface->parent)
478         {
479           GdkBroadwaySurface *parent_impl = GDK_BROADWAY_SURFACE (surface->parent);
480           impl->root_x += parent_impl->root_x;
481           impl->root_y += parent_impl->root_y;
482         }
483     }
484 
485   size_changed = FALSE;
486 
487   broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (surface));
488 
489   if (width > 0 || height > 0)
490     {
491       if (width < 1)
492         width = 1;
493 
494       if (height < 1)
495         height = 1;
496 
497       if (width != surface->width ||
498           height != surface->height)
499         {
500           size_changed = TRUE;
501 
502           /* Resize clears the content */
503           impl->dirty = TRUE;
504           impl->last_synced = FALSE;
505 
506           surface->width = width;
507           surface->height = height;
508         }
509     }
510 
511   _gdk_broadway_server_surface_move_resize (broadway_display->server,
512                                             impl->id,
513                                             with_move,
514                                             impl->root_x, impl->root_y,
515                                             surface->width, surface->height);
516   sync_child_root_pos (surface);
517 
518   queue_flush (surface);
519   if (size_changed)
520     {
521       surface->resize_count++;
522       _gdk_surface_update_size (surface);
523     }
524 }
525 
526 void
gdk_broadway_surface_move_resize(GdkSurface * surface,int x,int y,int width,int height)527 gdk_broadway_surface_move_resize (GdkSurface *surface,
528                                   int         x,
529                                   int         y,
530                                   int         width,
531                                   int         height)
532 {
533   gdk_broadway_surface_move_resize_internal (surface, TRUE,
534                                              x, y,
535                                              width, height);
536 }
537 
538 static void
gdk_broadway_surface_toplevel_resize(GdkSurface * surface,int width,int height)539 gdk_broadway_surface_toplevel_resize (GdkSurface *surface,
540                                       int         width,
541                                       int         height)
542 {
543   gdk_broadway_surface_move_resize_internal (surface, FALSE,
544                                              0, 0,
545                                              width, height);
546 }
547 
548 static void
gdk_broadway_surface_move(GdkSurface * surface,int x,int y)549 gdk_broadway_surface_move (GdkSurface *surface,
550                            int         x,
551                            int         y)
552 {
553   gdk_broadway_surface_move_resize_internal (surface, TRUE, x, y, -1, -1);
554 }
555 
556 static void
gdk_broadway_surface_layout_popup(GdkSurface * surface,int width,int height,GdkPopupLayout * layout)557 gdk_broadway_surface_layout_popup (GdkSurface     *surface,
558                                    int             width,
559                                    int             height,
560                                    GdkPopupLayout *layout)
561 {
562   GdkBroadwaySurface *impl = GDK_BROADWAY_SURFACE (surface);
563   GdkMonitor *monitor;
564   GdkRectangle bounds;
565   GdkRectangle final_rect;
566   int x, y;
567 
568   monitor = gdk_surface_get_layout_monitor (surface, layout,
569                                             gdk_monitor_get_geometry);
570   gdk_monitor_get_geometry (monitor, &bounds);
571 
572   gdk_surface_layout_popup_helper (surface,
573                                    width,
574                                    height,
575                                    impl->shadow_left,
576                                    impl->shadow_right,
577                                    impl->shadow_top,
578                                    impl->shadow_bottom,
579                                    monitor,
580                                    &bounds,
581                                    layout,
582                                    &final_rect);
583 
584   x = final_rect.x;
585   y = final_rect.y;
586 
587   if (final_rect.width != surface->width ||
588       final_rect.height != surface->height)
589     {
590       gdk_broadway_surface_move_resize (surface,
591                                         x,
592                                         y,
593                                         final_rect.width,
594                                         final_rect.height);
595     }
596   else
597     {
598       gdk_broadway_surface_move (surface, x, y);
599     }
600 }
601 
602 static void
show_popup(GdkSurface * surface)603 show_popup (GdkSurface *surface)
604 {
605   gdk_surface_set_is_mapped (surface, TRUE);
606   gdk_broadway_surface_show (surface, FALSE);
607   gdk_surface_invalidate_rect (surface, NULL);
608 }
609 
610 static void
show_grabbing_popup(GdkSeat * seat,GdkSurface * surface,gpointer user_data)611 show_grabbing_popup (GdkSeat    *seat,
612                      GdkSurface *surface,
613                      gpointer    user_data)
614 {
615   show_popup (surface);
616 }
617 
618 static gboolean
gdk_broadway_surface_present_popup(GdkSurface * surface,int width,int height,GdkPopupLayout * layout)619 gdk_broadway_surface_present_popup (GdkSurface     *surface,
620                                     int             width,
621                                     int             height,
622                                     GdkPopupLayout *layout)
623 {
624   gdk_broadway_surface_layout_popup (surface, width, height, layout);
625 
626   if (GDK_SURFACE_IS_MAPPED (surface))
627     return TRUE;
628 
629   if (surface->autohide)
630     {
631       gdk_seat_grab (gdk_display_get_default_seat (surface->display),
632                      surface,
633                      GDK_SEAT_CAPABILITY_ALL,
634                      TRUE,
635                      NULL, NULL,
636                      show_grabbing_popup, NULL);
637     }
638   else
639     {
640       show_popup (surface);
641     }
642 
643   return GDK_SURFACE_IS_MAPPED (surface);
644 }
645 
646 static void
gdk_broadway_surface_focus(GdkSurface * surface,guint32 timestamp)647 gdk_broadway_surface_focus (GdkSurface *surface,
648                             guint32    timestamp)
649 {
650   GdkBroadwaySurface *impl;
651   GdkBroadwayDisplay *broadway_display;
652 
653   g_return_if_fail (GDK_IS_SURFACE (surface));
654 
655   if (GDK_SURFACE_DESTROYED (surface))
656     return;
657 
658   impl = GDK_BROADWAY_SURFACE (surface);
659   broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (surface));
660   _gdk_broadway_server_surface_focus (broadway_display->server,
661                                       impl->id);
662 }
663 
664 static void
gdk_broadway_surface_set_geometry_hints(GdkSurface * surface,const GdkGeometry * geometry,GdkSurfaceHints geom_mask)665 gdk_broadway_surface_set_geometry_hints (GdkSurface        *surface,
666                                          const GdkGeometry *geometry,
667                                          GdkSurfaceHints    geom_mask)
668 {
669   GdkBroadwaySurface *impl;
670 
671   impl = GDK_BROADWAY_SURFACE (surface);
672 
673   impl->geometry_hints = *geometry;
674   impl->geometry_hints_mask = geom_mask;
675 }
676 
677 static void
gdk_broadway_surface_set_title(GdkSurface * surface,const char * title)678 gdk_broadway_surface_set_title (GdkSurface  *surface,
679                                 const char *title)
680 {
681 }
682 
683 static void
gdk_broadway_surface_set_startup_id(GdkSurface * surface,const char * startup_id)684 gdk_broadway_surface_set_startup_id (GdkSurface  *surface,
685                                      const char *startup_id)
686 {
687 }
688 
689 static void
gdk_broadway_surface_set_transient_for(GdkSurface * surface,GdkSurface * parent)690 gdk_broadway_surface_set_transient_for (GdkSurface *surface,
691                                         GdkSurface *parent)
692 {
693   GdkBroadwayDisplay *display;
694   GdkBroadwaySurface *impl;
695   int parent_id;
696 
697   impl = GDK_BROADWAY_SURFACE (surface);
698 
699   /* We treat the real parent as a default transient for to get stacking right */
700   if (parent == NULL)
701     parent = surface->parent;
702 
703   parent_id = 0;
704   if (parent)
705     parent_id = GDK_BROADWAY_SURFACE (parent)->id;
706 
707   impl->transient_for = parent_id;
708 
709   display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (surface));
710   _gdk_broadway_server_surface_set_transient_for (display->server, impl->id, impl->transient_for);
711 }
712 
713 static void
gdk_broadway_surface_get_geometry(GdkSurface * surface,int * x,int * y,int * width,int * height)714 gdk_broadway_surface_get_geometry (GdkSurface *surface,
715                                    int        *x,
716                                    int        *y,
717                                    int        *width,
718                                    int        *height)
719 {
720   g_return_if_fail (GDK_IS_SURFACE (surface));
721 
722   /* TODO: These should really roundtrip to the client to get the current data */
723 
724   if (x)
725     *x = surface->x;
726   if (y)
727     *y = surface->y;
728   if (width)
729     *width = surface->width;
730   if (height)
731     *height = surface->height;
732 
733 }
734 
735 static void
gdk_broadway_surface_get_root_coords(GdkSurface * surface,int x,int y,int * root_x,int * root_y)736 gdk_broadway_surface_get_root_coords (GdkSurface *surface,
737                                       int         x,
738                                       int         y,
739                                       int        *root_x,
740                                       int        *root_y)
741 {
742   GdkBroadwaySurface *impl;
743 
744   impl = GDK_BROADWAY_SURFACE (surface);
745 
746   if (root_x)
747     *root_x = x + impl->root_x;
748   if (root_y)
749     *root_y = y + impl->root_y;
750 }
751 
752 static gboolean
gdk_broadway_surface_get_device_state(GdkSurface * surface,GdkDevice * device,double * x,double * y,GdkModifierType * mask)753 gdk_broadway_surface_get_device_state (GdkSurface      *surface,
754                                        GdkDevice       *device,
755                                        double          *x,
756                                        double          *y,
757                                        GdkModifierType *mask)
758 {
759   g_return_val_if_fail (surface == NULL || GDK_IS_SURFACE (surface), FALSE);
760 
761   if (GDK_SURFACE_DESTROYED (surface))
762     return FALSE;
763 
764   gdk_broadway_device_query_state (device, surface, x, y, mask);
765 
766   return *x >= 0 && *y >= 0 && *x < surface->width && *y < surface->height;
767 }
768 
769 static void
gdk_broadway_surface_set_input_region(GdkSurface * surface,cairo_region_t * shape_region)770 gdk_broadway_surface_set_input_region (GdkSurface     *surface,
771                                        cairo_region_t *shape_region)
772 {
773 }
774 
775 static void
gdk_broadway_surface_minimize(GdkSurface * surface)776 gdk_broadway_surface_minimize (GdkSurface *surface)
777 {
778   if (GDK_SURFACE_DESTROYED (surface))
779     return;
780 }
781 
782 static void
gdk_broadway_surface_unminimize(GdkSurface * surface)783 gdk_broadway_surface_unminimize (GdkSurface *surface)
784 {
785   if (GDK_SURFACE_DESTROYED (surface))
786     return;
787 }
788 
789 static void
gdk_broadway_surface_maximize(GdkSurface * surface)790 gdk_broadway_surface_maximize (GdkSurface *surface)
791 {
792   GdkBroadwaySurface *impl;
793   GdkDisplay *display;
794   GdkRectangle geom;
795 
796   if (GDK_SURFACE_DESTROYED (surface))
797     return;
798 
799   impl = GDK_BROADWAY_SURFACE (surface);
800 
801   if (impl->maximized)
802     return;
803 
804   impl->maximized = TRUE;
805 
806   gdk_synthesize_surface_state (surface, 0, GDK_TOPLEVEL_STATE_MAXIMIZED);
807 
808   impl->pre_maximize_x = surface->x;
809   impl->pre_maximize_y = surface->y;
810   impl->pre_maximize_width = surface->width;
811   impl->pre_maximize_height = surface->height;
812 
813   display = gdk_surface_get_display (surface);
814   gdk_monitor_get_geometry (GDK_BROADWAY_DISPLAY (display)->monitor, &geom);
815 
816   gdk_broadway_surface_move_resize (surface,
817                                     geom.x, geom.y,
818                                     geom.width, geom.height);
819 }
820 
821 static void
gdk_broadway_surface_unmaximize(GdkSurface * surface)822 gdk_broadway_surface_unmaximize (GdkSurface *surface)
823 {
824   GdkBroadwaySurface *impl;
825 
826   if (GDK_SURFACE_DESTROYED (surface))
827     return;
828 
829   impl = GDK_BROADWAY_SURFACE (surface);
830 
831   if (!impl->maximized)
832     return;
833 
834   impl->maximized = FALSE;
835 
836   gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_MAXIMIZED, 0);
837 
838   gdk_broadway_surface_move_resize (surface,
839                                     impl->pre_maximize_x,
840                                     impl->pre_maximize_y,
841                                     impl->pre_maximize_width,
842                                     impl->pre_maximize_height);
843 }
844 
845 typedef struct _MoveResizeData MoveResizeData;
846 
847 struct _MoveResizeData
848 {
849   GdkDisplay *display;
850 
851   GdkSurface *moveresize_surface;
852   GdkSurface *moveresize_emulation_surface;
853   gboolean is_resize;
854   GdkSurfaceEdge resize_edge;
855   int moveresize_button;
856   int moveresize_x;
857   int moveresize_y;
858   int moveresize_orig_x;
859   int moveresize_orig_y;
860   int moveresize_orig_width;
861   int moveresize_orig_height;
862   long moveresize_process_time;
863   GdkSurfaceHints moveresize_geom_mask;
864   GdkGeometry moveresize_geometry;
865   BroadwayInputMsg *moveresize_pending_event;
866 };
867 
868 static MoveResizeData *
get_move_resize_data(GdkDisplay * display,gboolean create)869 get_move_resize_data (GdkDisplay *display,
870                       gboolean    create)
871 {
872   GdkBroadwayDisplay *broadway_display;
873   MoveResizeData *mv_resize;
874 
875   broadway_display = GDK_BROADWAY_DISPLAY (display);
876 
877   mv_resize = broadway_display->move_resize_data;
878 
879   if (!mv_resize && create)
880     {
881       mv_resize = g_new0 (MoveResizeData, 1);
882       mv_resize->display = display;
883 
884       broadway_display->move_resize_data = mv_resize;
885     }
886 
887   return mv_resize;
888 }
889 
890 static void
update_pos(MoveResizeData * mv_resize,int new_root_x,int new_root_y)891 update_pos (MoveResizeData *mv_resize,
892             int             new_root_x,
893             int             new_root_y)
894 {
895   int dx, dy;
896 
897   dx = new_root_x - mv_resize->moveresize_x;
898   dy = new_root_y - mv_resize->moveresize_y;
899 
900   if (mv_resize->is_resize)
901     {
902       int x, y, w, h;
903 
904       x = mv_resize->moveresize_orig_x;
905       y = mv_resize->moveresize_orig_y;
906 
907       w = mv_resize->moveresize_orig_width;
908       h = mv_resize->moveresize_orig_height;
909 
910       switch (mv_resize->resize_edge)
911         {
912         case GDK_SURFACE_EDGE_NORTH_WEST:
913           x += dx;
914           y += dy;
915           w -= dx;
916           h -= dy;
917           break;
918         case GDK_SURFACE_EDGE_NORTH:
919           y += dy;
920           h -= dy;
921           break;
922         case GDK_SURFACE_EDGE_NORTH_EAST:
923           y += dy;
924           h -= dy;
925           w += dx;
926           break;
927         case GDK_SURFACE_EDGE_SOUTH_WEST:
928           h += dy;
929           x += dx;
930           w -= dx;
931           break;
932         case GDK_SURFACE_EDGE_SOUTH_EAST:
933           w += dx;
934           h += dy;
935           break;
936         case GDK_SURFACE_EDGE_SOUTH:
937           h += dy;
938           break;
939         case GDK_SURFACE_EDGE_EAST:
940           w += dx;
941           break;
942         case GDK_SURFACE_EDGE_WEST:
943           x += dx;
944           w -= dx;
945           break;
946         default:
947           break;
948         }
949 
950       x = MAX (x, 0);
951       y = MAX (y, 0);
952       w = MAX (w, 1);
953       h = MAX (h, 1);
954 
955       if (mv_resize->moveresize_geom_mask)
956         {
957           gdk_surface_constrain_size (&mv_resize->moveresize_geometry,
958                                      mv_resize->moveresize_geom_mask,
959                                      w, h, &w, &h);
960         }
961 
962       gdk_broadway_surface_move_resize (mv_resize->moveresize_surface,
963                                         x, y, w, h);
964     }
965   else
966     {
967       int x, y;
968 
969       x = mv_resize->moveresize_orig_x + dx;
970       y = mv_resize->moveresize_orig_y + dy;
971 
972       gdk_broadway_surface_move (mv_resize->moveresize_surface, x, y);
973     }
974 }
975 
976 static void
finish_drag(MoveResizeData * mv_resize)977 finish_drag (MoveResizeData *mv_resize)
978 {
979   gdk_surface_destroy (mv_resize->moveresize_emulation_surface);
980   mv_resize->moveresize_emulation_surface = NULL;
981   g_object_unref (mv_resize->moveresize_surface);
982   mv_resize->moveresize_surface = NULL;
983   g_clear_pointer (&mv_resize->moveresize_pending_event, g_free);
984 }
985 
986 static gboolean
moveresize_lookahead(GdkDisplay * display,MoveResizeData * mv_resize,BroadwayInputMsg * event)987 moveresize_lookahead (GdkDisplay *display,
988                       MoveResizeData *mv_resize,
989                       BroadwayInputMsg *event)
990 {
991   GdkBroadwayDisplay *broadway_display;
992 
993   broadway_display = GDK_BROADWAY_DISPLAY (display);
994 
995   return !_gdk_broadway_server_lookahead_event (broadway_display->server, "mb");
996 }
997 
998 gboolean
_gdk_broadway_moveresize_handle_event(GdkDisplay * display,BroadwayInputMsg * event)999 _gdk_broadway_moveresize_handle_event (GdkDisplay *display,
1000                                        BroadwayInputMsg *event)
1001 {
1002   guint button_mask = 0;
1003   MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
1004 
1005   if (!mv_resize || !mv_resize->moveresize_surface)
1006     return FALSE;
1007 
1008   button_mask = GDK_BUTTON1_MASK << (mv_resize->moveresize_button - 1);
1009 
1010   switch (event->base.type)
1011     {
1012     case BROADWAY_EVENT_TOUCH:
1013       if (event->touch.touch_type == 2) /* END */
1014         {
1015           update_pos (mv_resize,
1016                       event->touch.root_x,
1017                       event->touch.root_y);
1018 
1019           finish_drag (mv_resize);
1020         }
1021       else if (event->touch.touch_type == 1) /* UPDATE */
1022         {
1023           if (mv_resize->moveresize_surface->resize_count > 0)
1024             {
1025               if (mv_resize->moveresize_pending_event)
1026                 *mv_resize->moveresize_pending_event = *event;
1027               else
1028                 mv_resize->moveresize_pending_event =
1029                   g_memdup2 (event, sizeof (BroadwayInputMsg));
1030 
1031               break;
1032             }
1033           update_pos (mv_resize,
1034                       event->touch.root_x,
1035                       event->touch.root_y);
1036         }
1037 
1038       break;
1039 
1040     case BROADWAY_EVENT_POINTER_MOVE:
1041       if (mv_resize->moveresize_surface->resize_count > 0)
1042         {
1043           if (mv_resize->moveresize_pending_event)
1044             *mv_resize->moveresize_pending_event = *event;
1045           else
1046             mv_resize->moveresize_pending_event =
1047               g_memdup2 (event, sizeof (BroadwayInputMsg));
1048 
1049           break;
1050         }
1051       if (!moveresize_lookahead (display, mv_resize, event))
1052         break;
1053 
1054       update_pos (mv_resize,
1055                   event->pointer.root_x,
1056                   event->pointer.root_y);
1057 
1058       /* This should never be triggered in normal cases, but in the
1059        * case where the drag started without an implicit grab being
1060        * in effect, we could miss the release if it occurs before
1061        * we grab the pointer; this ensures that we will never
1062        * get a permanently stuck grab.
1063        */
1064       if ((event->pointer.state & button_mask) == 0)
1065         finish_drag (mv_resize);
1066       break;
1067 
1068     case BROADWAY_EVENT_BUTTON_RELEASE:
1069       update_pos (mv_resize,
1070                   event->pointer.root_x,
1071                   event->pointer.root_y);
1072 
1073       if (event->button.button == mv_resize->moveresize_button)
1074         finish_drag (mv_resize);
1075       break;
1076     default:
1077       break;
1078     }
1079   return TRUE;
1080 }
1081 
1082 gboolean
_gdk_broadway_moveresize_configure_done(GdkDisplay * display,GdkSurface * surface)1083 _gdk_broadway_moveresize_configure_done (GdkDisplay *display,
1084                                          GdkSurface  *surface)
1085 {
1086   BroadwayInputMsg *tmp_event;
1087   MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
1088 
1089   if (!mv_resize || surface != mv_resize->moveresize_surface)
1090     return FALSE;
1091 
1092   if (mv_resize->moveresize_pending_event)
1093     {
1094       tmp_event = mv_resize->moveresize_pending_event;
1095       mv_resize->moveresize_pending_event = NULL;
1096       _gdk_broadway_moveresize_handle_event (display, tmp_event);
1097       g_free (tmp_event);
1098     }
1099 
1100   return TRUE;
1101 }
1102 
1103 static void
create_moveresize_surface(MoveResizeData * mv_resize,guint32 timestamp)1104 create_moveresize_surface (MoveResizeData *mv_resize,
1105                            guint32         timestamp)
1106 {
1107   GdkGrabStatus status;
1108   GdkSeat *seat;
1109   GdkDevice *pointer;
1110 
1111   g_assert (mv_resize->moveresize_emulation_surface == NULL);
1112 
1113   mv_resize->moveresize_emulation_surface =
1114       _gdk_broadway_display_create_surface (mv_resize->display,
1115                                             GDK_SURFACE_TEMP,
1116                                             NULL,
1117                                             -100, -100, 1, 1);
1118 
1119   gdk_broadway_surface_show (mv_resize->moveresize_emulation_surface, FALSE);
1120 
1121   seat = gdk_display_get_default_seat (mv_resize->display);
1122   pointer = gdk_seat_get_pointer (seat);
1123 
1124   G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1125   status = gdk_device_grab (pointer,
1126                             mv_resize->moveresize_emulation_surface,
1127                             FALSE,
1128                             GDK_BUTTON_RELEASE_MASK |
1129                             GDK_POINTER_MOTION_MASK,
1130                             NULL,
1131                             timestamp);
1132   G_GNUC_END_IGNORE_DEPRECATIONS;
1133 
1134   if (status != GDK_GRAB_SUCCESS)
1135     {
1136       /* If this fails, some other client has grabbed the surface
1137        * already.
1138        */
1139       finish_drag (mv_resize);
1140     }
1141 
1142   mv_resize->moveresize_process_time = 0;
1143 }
1144 
1145 static void
calculate_unmoving_origin(MoveResizeData * mv_resize)1146 calculate_unmoving_origin (MoveResizeData *mv_resize)
1147 {
1148   gdk_surface_get_geometry (mv_resize->moveresize_surface,
1149                             &mv_resize->moveresize_orig_x,
1150                             &mv_resize->moveresize_orig_y,
1151                             NULL, NULL);
1152 }
1153 
1154 static void
gdk_broadway_toplevel_begin_resize(GdkToplevel * toplevel,GdkSurfaceEdge edge,GdkDevice * device,int button,double x,double y,guint32 timestamp)1155 gdk_broadway_toplevel_begin_resize (GdkToplevel    *toplevel,
1156                                     GdkSurfaceEdge  edge,
1157                                     GdkDevice      *device,
1158                                     int             button,
1159                                     double          x,
1160                                     double          y,
1161                                     guint32         timestamp)
1162 {
1163   GdkSurface *surface = GDK_SURFACE (toplevel);
1164   GdkBroadwaySurface *impl = GDK_BROADWAY_SURFACE (surface);
1165   MoveResizeData *mv_resize;
1166 
1167   if (GDK_SURFACE_DESTROYED (surface))
1168     return;
1169 
1170   if (impl->maximized)
1171     return;
1172 
1173   mv_resize = get_move_resize_data (gdk_surface_get_display (surface), TRUE);
1174 
1175   if (mv_resize->moveresize_surface != NULL)
1176     return; /* already a drag operation in progress */
1177 
1178   mv_resize->is_resize = TRUE;
1179   mv_resize->moveresize_button = button;
1180   mv_resize->resize_edge = edge;
1181   mv_resize->moveresize_x = x + surface->x;
1182   mv_resize->moveresize_y = y + surface->y;
1183   mv_resize->moveresize_surface = g_object_ref (surface);
1184 
1185   mv_resize->moveresize_orig_width = gdk_surface_get_width (surface);
1186   mv_resize->moveresize_orig_height = gdk_surface_get_height (surface);
1187 
1188   mv_resize->moveresize_geom_mask = impl->geometry_hints_mask;
1189   mv_resize->moveresize_geometry = impl->geometry_hints;
1190 
1191   calculate_unmoving_origin (mv_resize);
1192 
1193   create_moveresize_surface (mv_resize, timestamp);
1194 }
1195 
1196 static void
gdk_broadway_toplevel_begin_move(GdkToplevel * toplevel,GdkDevice * device,int button,double x,double y,guint32 timestamp)1197 gdk_broadway_toplevel_begin_move (GdkToplevel *toplevel,
1198                                   GdkDevice   *device,
1199                                   int          button,
1200                                   double       x,
1201                                   double       y,
1202                                   guint32      timestamp)
1203 {
1204   GdkSurface *surface = GDK_SURFACE (toplevel);
1205   GdkBroadwaySurface *impl = GDK_BROADWAY_SURFACE (surface);
1206   MoveResizeData *mv_resize;
1207 
1208   if (GDK_SURFACE_DESTROYED (surface))
1209     return;
1210 
1211   if (impl->maximized)
1212     return;
1213 
1214   mv_resize = get_move_resize_data (gdk_surface_get_display (surface), TRUE);
1215 
1216   if (mv_resize->moveresize_surface != NULL)
1217     return; /* already a drag operation in progress */
1218 
1219   mv_resize->is_resize = FALSE;
1220   mv_resize->moveresize_button = button;
1221   mv_resize->moveresize_x = x + surface->x;
1222   mv_resize->moveresize_y = y + surface->y;
1223   mv_resize->moveresize_surface = g_object_ref (surface);
1224 
1225   mv_resize->moveresize_orig_width = gdk_surface_get_width (surface);
1226   mv_resize->moveresize_orig_height = gdk_surface_get_height (surface);
1227 
1228   mv_resize->moveresize_geom_mask = impl->geometry_hints_mask;
1229   mv_resize->moveresize_geometry = impl->geometry_hints;
1230 
1231   calculate_unmoving_origin (mv_resize);
1232 
1233   create_moveresize_surface (mv_resize, timestamp);
1234 }
1235 
1236 static gboolean
gdk_broadway_surface_beep(GdkSurface * surface)1237 gdk_broadway_surface_beep (GdkSurface *surface)
1238 {
1239   return FALSE;
1240 }
1241 
1242 static void
gdk_broadway_surface_class_init(GdkBroadwaySurfaceClass * klass)1243 gdk_broadway_surface_class_init (GdkBroadwaySurfaceClass *klass)
1244 {
1245   GObjectClass *object_class = G_OBJECT_CLASS (klass);
1246   GdkSurfaceClass *impl_class = GDK_SURFACE_CLASS (klass);
1247 
1248   object_class->finalize = gdk_broadway_surface_finalize;
1249 
1250   impl_class->ref_cairo_surface = gdk_broadway_surface_ref_cairo_surface;
1251   impl_class->hide = gdk_broadway_surface_hide;
1252   impl_class->get_geometry = gdk_broadway_surface_get_geometry;
1253   impl_class->get_root_coords = gdk_broadway_surface_get_root_coords;
1254   impl_class->get_device_state = gdk_broadway_surface_get_device_state;
1255   impl_class->set_input_region = gdk_broadway_surface_set_input_region;
1256   impl_class->destroy = _gdk_broadway_surface_destroy;
1257   impl_class->beep = gdk_broadway_surface_beep;
1258   impl_class->destroy_notify = gdk_broadway_surface_destroy_notify;
1259   impl_class->drag_begin = _gdk_broadway_surface_drag_begin;
1260   impl_class->get_scale_factor = gdk_broadway_surface_get_scale_factor;
1261 }
1262 
1263 #define LAST_PROP 1
1264 
1265 typedef struct
1266 {
1267   GdkBroadwaySurface parent_instance;
1268 } GdkBroadwayPopup;
1269 
1270 typedef struct
1271 {
1272   GdkBroadwaySurfaceClass parent_class;
1273 } GdkBroadwayPopupClass;
1274 
1275 static void gdk_broadway_popup_iface_init (GdkPopupInterface *iface);
1276 
G_DEFINE_TYPE_WITH_CODE(GdkBroadwayPopup,gdk_broadway_popup,GDK_TYPE_BROADWAY_SURFACE,G_IMPLEMENT_INTERFACE (GDK_TYPE_POPUP,gdk_broadway_popup_iface_init))1277 G_DEFINE_TYPE_WITH_CODE (GdkBroadwayPopup, gdk_broadway_popup, GDK_TYPE_BROADWAY_SURFACE,
1278                          G_IMPLEMENT_INTERFACE (GDK_TYPE_POPUP,
1279                                                 gdk_broadway_popup_iface_init))
1280 
1281 static void
1282 gdk_broadway_popup_init (GdkBroadwayPopup *popup)
1283 {
1284 }
1285 
1286 static void
gdk_broadway_popup_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1287 gdk_broadway_popup_get_property (GObject    *object,
1288                                  guint       prop_id,
1289                                  GValue     *value,
1290                                  GParamSpec *pspec)
1291 {
1292   GdkSurface *surface = GDK_SURFACE (object);
1293 
1294   switch (prop_id)
1295     {
1296     case LAST_PROP + GDK_POPUP_PROP_PARENT:
1297       g_value_set_object (value, surface->parent);
1298       break;
1299 
1300     case LAST_PROP + GDK_POPUP_PROP_AUTOHIDE:
1301       g_value_set_boolean (value, surface->autohide);
1302       break;
1303 
1304     default:
1305       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1306       break;
1307     }
1308 }
1309 
1310 static void
gdk_broadway_popup_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1311 gdk_broadway_popup_set_property (GObject      *object,
1312                                  guint         prop_id,
1313                                  const GValue *value,
1314                                  GParamSpec   *pspec)
1315 {
1316   GdkSurface *surface = GDK_SURFACE (object);
1317 
1318   switch (prop_id)
1319     {
1320     case LAST_PROP + GDK_POPUP_PROP_PARENT:
1321       surface->parent = g_value_dup_object (value);
1322       if (surface->parent != NULL)
1323         surface->parent->children = g_list_prepend (surface->parent->children, surface);
1324       break;
1325 
1326     case LAST_PROP + GDK_POPUP_PROP_AUTOHIDE:
1327       surface->autohide = g_value_get_boolean (value);
1328       break;
1329 
1330     default:
1331       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1332       break;
1333     }
1334 }
1335 
1336 static void
gdk_broadway_popup_class_init(GdkBroadwayPopupClass * class)1337 gdk_broadway_popup_class_init (GdkBroadwayPopupClass *class)
1338 {
1339   GObjectClass *object_class = G_OBJECT_CLASS (class);
1340 
1341   object_class->get_property = gdk_broadway_popup_get_property;
1342   object_class->set_property = gdk_broadway_popup_set_property;
1343 
1344   gdk_popup_install_properties (object_class, 1);
1345 }
1346 
1347 static gboolean
gdk_broadway_popup_present(GdkPopup * popup,int width,int height,GdkPopupLayout * layout)1348 gdk_broadway_popup_present (GdkPopup       *popup,
1349                             int             width,
1350                             int             height,
1351                             GdkPopupLayout *layout)
1352 {
1353   return gdk_broadway_surface_present_popup (GDK_SURFACE (popup), width, height, layout);
1354 }
1355 
1356 static GdkGravity
gdk_broadway_popup_get_surface_anchor(GdkPopup * popup)1357 gdk_broadway_popup_get_surface_anchor (GdkPopup *popup)
1358 {
1359   return GDK_SURFACE (popup)->popup.surface_anchor;
1360 }
1361 
1362 static GdkGravity
gdk_broadway_popup_get_rect_anchor(GdkPopup * popup)1363 gdk_broadway_popup_get_rect_anchor (GdkPopup *popup)
1364 {
1365   return GDK_SURFACE (popup)->popup.rect_anchor;
1366 }
1367 
1368 static int
gdk_broadway_popup_get_position_x(GdkPopup * popup)1369 gdk_broadway_popup_get_position_x (GdkPopup *popup)
1370 {
1371   return GDK_SURFACE (popup)->x;
1372 }
1373 
1374 static int
gdk_broadway_popup_get_position_y(GdkPopup * popup)1375 gdk_broadway_popup_get_position_y (GdkPopup *popup)
1376 {
1377   return GDK_SURFACE (popup)->y;
1378 }
1379 
1380 static void
gdk_broadway_popup_iface_init(GdkPopupInterface * iface)1381 gdk_broadway_popup_iface_init (GdkPopupInterface *iface)
1382 {
1383   iface->present = gdk_broadway_popup_present;
1384   iface->get_surface_anchor = gdk_broadway_popup_get_surface_anchor;
1385   iface->get_rect_anchor = gdk_broadway_popup_get_rect_anchor;
1386   iface->get_position_x = gdk_broadway_popup_get_position_x;
1387   iface->get_position_y = gdk_broadway_popup_get_position_y;
1388 }
1389 
1390 typedef struct
1391 {
1392   GdkBroadwaySurface parent_instance;
1393 } GdkBroadwayToplevel;
1394 
1395 typedef struct
1396 {
1397   GdkBroadwaySurfaceClass parent_class;
1398 } GdkBroadwayToplevelClass;
1399 
1400 static void gdk_broadway_toplevel_iface_init (GdkToplevelInterface *iface);
1401 
G_DEFINE_TYPE_WITH_CODE(GdkBroadwayToplevel,gdk_broadway_toplevel,GDK_TYPE_BROADWAY_SURFACE,G_IMPLEMENT_INTERFACE (GDK_TYPE_TOPLEVEL,gdk_broadway_toplevel_iface_init))1402 G_DEFINE_TYPE_WITH_CODE (GdkBroadwayToplevel, gdk_broadway_toplevel, GDK_TYPE_BROADWAY_SURFACE,
1403                          G_IMPLEMENT_INTERFACE (GDK_TYPE_TOPLEVEL,
1404                                                 gdk_broadway_toplevel_iface_init))
1405 
1406 static void
1407 gdk_broadway_toplevel_init (GdkBroadwayToplevel *toplevel)
1408 {
1409 }
1410 
1411 static void
gdk_broadway_toplevel_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1412 gdk_broadway_toplevel_set_property (GObject      *object,
1413                                     guint         prop_id,
1414                                     const GValue *value,
1415                                     GParamSpec   *pspec)
1416 {
1417   GdkSurface *surface = GDK_SURFACE (object);
1418 
1419   switch (prop_id)
1420     {
1421     case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE:
1422       gdk_broadway_surface_set_title (surface, g_value_get_string (value));
1423       g_object_notify_by_pspec (G_OBJECT (surface), pspec);
1424       break;
1425 
1426     case LAST_PROP + GDK_TOPLEVEL_PROP_STARTUP_ID:
1427       gdk_broadway_surface_set_startup_id (surface, g_value_get_string (value));
1428       g_object_notify_by_pspec (G_OBJECT (surface), pspec);
1429       break;
1430 
1431     case LAST_PROP + GDK_TOPLEVEL_PROP_TRANSIENT_FOR:
1432       gdk_broadway_surface_set_transient_for (surface, g_value_get_object (value));
1433       g_object_notify_by_pspec (G_OBJECT (surface), pspec);
1434       break;
1435 
1436     case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL:
1437       break;
1438 
1439     case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
1440       break;
1441 
1442     case LAST_PROP + GDK_TOPLEVEL_PROP_DECORATED:
1443       break;
1444 
1445     case LAST_PROP + GDK_TOPLEVEL_PROP_DELETABLE:
1446       break;
1447 
1448     case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
1449       break;
1450 
1451     default:
1452       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1453       break;
1454     }
1455 }
1456 
1457 static void
gdk_broadway_toplevel_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1458 gdk_broadway_toplevel_get_property (GObject    *object,
1459                                     guint       prop_id,
1460                                     GValue     *value,
1461                                     GParamSpec *pspec)
1462 {
1463   GdkSurface *surface = GDK_SURFACE (object);
1464 
1465   switch (prop_id)
1466     {
1467     case LAST_PROP + GDK_TOPLEVEL_PROP_STATE:
1468       g_value_set_flags (value, surface->state);
1469       break;
1470 
1471     case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE:
1472       g_value_set_string (value, "");
1473       break;
1474 
1475     case LAST_PROP + GDK_TOPLEVEL_PROP_STARTUP_ID:
1476       g_value_set_string (value, "");
1477       break;
1478 
1479     case LAST_PROP + GDK_TOPLEVEL_PROP_TRANSIENT_FOR:
1480       g_value_set_object (value, surface->transient_for);
1481       break;
1482 
1483     case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
1484       g_value_set_pointer (value, NULL);
1485       break;
1486 
1487     case LAST_PROP + GDK_TOPLEVEL_PROP_DECORATED:
1488       break;
1489 
1490     case LAST_PROP + GDK_TOPLEVEL_PROP_DELETABLE:
1491       break;
1492 
1493     case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
1494       g_value_set_boolean (value, surface->shortcuts_inhibited);
1495       break;
1496 
1497     default:
1498       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1499       break;
1500     }
1501 }
1502 
1503 static void
gdk_broadway_toplevel_class_init(GdkBroadwayToplevelClass * class)1504 gdk_broadway_toplevel_class_init (GdkBroadwayToplevelClass *class)
1505 {
1506   GObjectClass *object_class = G_OBJECT_CLASS (class);
1507 
1508   object_class->get_property = gdk_broadway_toplevel_get_property;
1509   object_class->set_property = gdk_broadway_toplevel_set_property;
1510 
1511   gdk_toplevel_install_properties (object_class, 1);
1512 }
1513 
1514 static void
show_surface(GdkSurface * surface)1515 show_surface (GdkSurface *surface)
1516 {
1517   gboolean was_mapped;
1518 
1519   if (surface->destroyed)
1520     return;
1521 
1522   was_mapped = GDK_SURFACE_IS_MAPPED (surface);
1523 
1524   if (!was_mapped)
1525     gdk_surface_set_is_mapped (surface, TRUE);
1526 
1527   gdk_broadway_surface_show (surface, FALSE);
1528 
1529   if (!was_mapped)
1530     gdk_surface_invalidate_rect (surface, NULL);
1531 }
1532 
1533 static void
gdk_broadway_toplevel_present(GdkToplevel * toplevel,GdkToplevelLayout * layout)1534 gdk_broadway_toplevel_present (GdkToplevel       *toplevel,
1535                                GdkToplevelLayout *layout)
1536 {
1537   GdkSurface *surface = GDK_SURFACE (toplevel);
1538   GdkBroadwaySurface *impl = GDK_BROADWAY_SURFACE (surface);
1539   GdkDisplay *display = gdk_surface_get_display (surface);
1540   GdkMonitor *monitor;
1541   GdkToplevelSize size;
1542   int bounds_width, bounds_height;
1543   int width, height;
1544   GdkGeometry geometry;
1545   GdkSurfaceHints mask;
1546   gboolean maximize;
1547 
1548   gdk_broadway_surface_unminimize (surface);
1549 
1550   monitor = gdk_display_get_monitor_at_surface (display, surface);
1551   if (monitor)
1552     {
1553       GdkRectangle monitor_geometry;
1554 
1555       gdk_monitor_get_geometry (monitor, &monitor_geometry);
1556       bounds_width = monitor_geometry.width;
1557       bounds_height = monitor_geometry.height;
1558     }
1559   else
1560     {
1561       bounds_width = G_MAXINT;
1562       bounds_height = G_MAXINT;
1563     }
1564 
1565   gdk_toplevel_size_init (&size, bounds_width, bounds_height);
1566   gdk_toplevel_notify_compute_size (toplevel, &size);
1567   g_warn_if_fail (size.width > 0);
1568   g_warn_if_fail (size.height > 0);
1569   width = size.width;
1570   height = size.height;
1571 
1572   if (gdk_toplevel_layout_get_resizable (layout))
1573     {
1574       geometry.min_width = size.min_width;
1575       geometry.min_height = size.min_height;
1576       mask = GDK_HINT_MIN_SIZE;
1577     }
1578   else
1579     {
1580       geometry.max_width = geometry.min_width = width;
1581       geometry.max_height = geometry.min_height = height;
1582       mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
1583     }
1584   gdk_broadway_surface_set_geometry_hints (surface, &geometry, mask);
1585   gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height);
1586   gdk_broadway_surface_toplevel_resize (surface, width, height);
1587 
1588   if (gdk_toplevel_layout_get_maximized (layout, &maximize))
1589     {
1590       if (maximize)
1591         gdk_broadway_surface_maximize (surface);
1592       else
1593         gdk_broadway_surface_unmaximize (surface);
1594     }
1595 
1596   if (size.shadow.is_valid)
1597     {
1598       impl->shadow_left = size.shadow.left;
1599       impl->shadow_right = size.shadow.right;
1600       impl->shadow_top = size.shadow.top;
1601       impl->shadow_bottom = size.shadow.bottom;
1602     }
1603 
1604   show_surface (surface);
1605 }
1606 
1607 static gboolean
gdk_broadway_toplevel_minimize(GdkToplevel * toplevel)1608 gdk_broadway_toplevel_minimize (GdkToplevel *toplevel)
1609 {
1610   gdk_broadway_surface_minimize (GDK_SURFACE (toplevel));
1611 
1612   return TRUE;
1613 }
1614 
1615 static gboolean
gdk_broadway_toplevel_lower(GdkToplevel * toplevel)1616 gdk_broadway_toplevel_lower (GdkToplevel *toplevel)
1617 {
1618   return FALSE;
1619 }
1620 
1621 static void
gdk_broadway_toplevel_focus(GdkToplevel * toplevel,guint32 timestamp)1622 gdk_broadway_toplevel_focus (GdkToplevel *toplevel,
1623                              guint32      timestamp)
1624 {
1625   gdk_broadway_surface_focus (GDK_SURFACE (toplevel), timestamp);
1626 }
1627 
1628 static gboolean
gdk_broadway_toplevel_show_window_menu(GdkToplevel * toplevel,GdkEvent * event)1629 gdk_broadway_toplevel_show_window_menu (GdkToplevel *toplevel,
1630                                         GdkEvent    *event)
1631 {
1632   return FALSE;
1633 }
1634 
1635 static void
gdk_broadway_toplevel_iface_init(GdkToplevelInterface * iface)1636 gdk_broadway_toplevel_iface_init (GdkToplevelInterface *iface)
1637 {
1638   iface->present = gdk_broadway_toplevel_present;
1639   iface->minimize = gdk_broadway_toplevel_minimize;
1640   iface->lower = gdk_broadway_toplevel_lower;
1641   iface->focus = gdk_broadway_toplevel_focus;
1642   iface->show_window_menu = gdk_broadway_toplevel_show_window_menu;
1643   iface->begin_resize = gdk_broadway_toplevel_begin_resize;
1644   iface->begin_move = gdk_broadway_toplevel_begin_move;
1645 }
1646 
1647 typedef struct
1648 {
1649   GdkBroadwaySurface parent_instance;
1650 } GdkBroadwayDragSurface;
1651 
1652 typedef struct
1653 {
1654   GdkBroadwaySurfaceClass parent_class;
1655 } GdkBroadwayDragSurfaceClass;
1656 
1657 static void gdk_broadway_drag_surface_iface_init (GdkDragSurfaceInterface *iface);
1658 
G_DEFINE_TYPE_WITH_CODE(GdkBroadwayDragSurface,gdk_broadway_drag_surface,GDK_TYPE_BROADWAY_SURFACE,G_IMPLEMENT_INTERFACE (GDK_TYPE_DRAG_SURFACE,gdk_broadway_drag_surface_iface_init))1659 G_DEFINE_TYPE_WITH_CODE (GdkBroadwayDragSurface, gdk_broadway_drag_surface, GDK_TYPE_BROADWAY_SURFACE,
1660                          G_IMPLEMENT_INTERFACE (GDK_TYPE_DRAG_SURFACE,
1661                                                 gdk_broadway_drag_surface_iface_init))
1662 
1663 static void
1664 gdk_broadway_drag_surface_init (GdkBroadwayDragSurface *surface)
1665 {
1666 }
1667 
1668 static void
gdk_broadway_drag_surface_class_init(GdkBroadwayDragSurfaceClass * class)1669 gdk_broadway_drag_surface_class_init (GdkBroadwayDragSurfaceClass *class)
1670 {
1671 }
1672 
1673 static gboolean
gdk_broadway_drag_surface_present(GdkDragSurface * drag_surface,int width,int height)1674 gdk_broadway_drag_surface_present (GdkDragSurface *drag_surface,
1675                                    int             width,
1676                                    int             height)
1677 {
1678   GdkSurface *surface = GDK_SURFACE (drag_surface);
1679 
1680   gdk_broadway_surface_toplevel_resize (surface, width, height);
1681   show_surface (surface);
1682 
1683   return TRUE;
1684 }
1685 
1686 static void
gdk_broadway_drag_surface_iface_init(GdkDragSurfaceInterface * iface)1687 gdk_broadway_drag_surface_iface_init (GdkDragSurfaceInterface *iface)
1688 {
1689   iface->present = gdk_broadway_drag_surface_present;
1690 }
1691