meta-wayland-popup.c 9.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*
 * Wayland Support
 *
 * Copyright (C) 2013 Intel Corporation
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * Copyright © 2008 Kristian Høgsberg
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that copyright
 * notice and this permission notice appear in supporting documentation, and
 * that the name of the copyright holders not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  The copyright holders make no representations
 * about the suitability of this software for any purpose.  It is provided "as
 * is" without express or implied warranty.
 *
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 * OF THIS SOFTWARE.
 */

#include "config.h"

Jonas Ådahl's avatar
Jonas Ådahl committed
45
#include "wayland/meta-wayland-popup.h"
46

Jonas Ådahl's avatar
Jonas Ådahl committed
47
48
49
#include "wayland/meta-wayland-pointer.h"
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-surface.h"
50

51
52
53
G_DEFINE_INTERFACE (MetaWaylandPopupSurface, meta_wayland_popup_surface,
                    G_TYPE_OBJECT);

54
55
56
57
58
59
60
61
62
63
64
struct _MetaWaylandPopupGrab
{
  MetaWaylandPointerGrab  generic;

  struct wl_client       *grab_client;
  struct wl_list          all_popups;
};

struct _MetaWaylandPopup
{
  MetaWaylandPopupGrab *grab;
65
66
  MetaWaylandPopupSurface *popup_surface;
  struct wl_list link;
67
68
};

69
70
71
72
73
74
75
static void
meta_wayland_popup_grab_begin (MetaWaylandPopupGrab *grab,
                               MetaWaylandSurface   *surface);

static void
meta_wayland_popup_grab_end (MetaWaylandPopupGrab *grab);

76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
static void
meta_wayland_popup_surface_default_init (MetaWaylandPopupSurfaceInterface *iface)
{
}

static void
meta_wayland_popup_surface_done (MetaWaylandPopupSurface *popup_surface)
{
  META_WAYLAND_POPUP_SURFACE_GET_IFACE (popup_surface)->done (popup_surface);
}

static void
meta_wayland_popup_surface_dismiss (MetaWaylandPopupSurface *popup_surface)
{
  META_WAYLAND_POPUP_SURFACE_GET_IFACE (popup_surface)->dismiss (popup_surface);
}

static MetaWaylandSurface *
meta_wayland_popup_surface_get_surface (MetaWaylandPopupSurface *popup_surface)
{
  return META_WAYLAND_POPUP_SURFACE_GET_IFACE (popup_surface)->get_surface (popup_surface);
}

99
100
101
102
103
static void
popup_grab_focus (MetaWaylandPointerGrab *grab,
		  MetaWaylandSurface     *surface)
{
  MetaWaylandPopupGrab *popup_grab = (MetaWaylandPopupGrab*)grab;
104
  MetaWaylandSeat *seat = meta_wayland_pointer_get_seat (grab->pointer);
105
  MetaWaylandPointer *pointer = grab->pointer;
106
107
108
109
110
111
112
113
114

  /*
   * We rely on having a pointer grab even when the seat doesn't have
   * the pointer capability. In this case, we shouldn't update any pointer focus
   * since there is no such thing when the seat doesn't have the pointer
   * capability.
   */
  if (!meta_wayland_seat_has_pointer (seat))
    return;
115

116
117
118
  if (pointer->button_count > 0)
    return;

119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  /* Popup grabs are in owner-events mode (ie, events for the same client
     are reported as normal) */
  if (surface &&
      wl_resource_get_client (surface->resource) == popup_grab->grab_client)
    meta_wayland_pointer_set_focus (grab->pointer, surface);
  else
    meta_wayland_pointer_set_focus (grab->pointer, NULL);
}

static void
popup_grab_motion (MetaWaylandPointerGrab *grab,
		   const ClutterEvent     *event)
{
  meta_wayland_pointer_send_motion (grab->pointer, event);
}

static void
popup_grab_button (MetaWaylandPointerGrab *grab,
		   const ClutterEvent     *event)
{
  MetaWaylandPointer *pointer = grab->pointer;

  if (pointer->focus_surface)
    meta_wayland_pointer_send_button (grab->pointer, event);
  else if (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE &&
	   pointer->button_count == 0)
    meta_wayland_pointer_end_popup_grab (grab->pointer);
}

148
149
150
151
152
153
static void
popup_grab_cancel (MetaWaylandPointerGrab *grab)
{
  meta_wayland_pointer_end_popup_grab (grab->pointer);
}

154
155
156
static MetaWaylandPointerGrabInterface popup_grab_interface = {
  popup_grab_focus,
  popup_grab_motion,
157
158
  popup_grab_button,
  popup_grab_cancel
159
160
161
};

MetaWaylandPopupGrab *
162
163
meta_wayland_popup_grab_create (MetaWaylandPointer      *pointer,
                                MetaWaylandPopupSurface *popup_surface)
164
{
165
166
  MetaWaylandSurface *surface =
    meta_wayland_popup_surface_get_surface (popup_surface);
167
  struct wl_client *client = wl_resource_get_client (surface->resource);
168
169
170
171
172
173
174
175
  MetaWaylandPopupGrab *grab;

  grab = g_slice_new0 (MetaWaylandPopupGrab);
  grab->generic.interface = &popup_grab_interface;
  grab->generic.pointer = pointer;
  grab->grab_client = client;
  wl_list_init (&grab->all_popups);

176
177
  meta_wayland_popup_grab_begin (grab, surface);

178
179
180
181
182
183
  return grab;
}

void
meta_wayland_popup_grab_destroy (MetaWaylandPopupGrab *grab)
{
184
  meta_wayland_popup_grab_end (grab);
185
186
187
  g_slice_free (MetaWaylandPopupGrab, grab);
}

188
static void
189
190
191
192
meta_wayland_popup_grab_begin (MetaWaylandPopupGrab *grab,
                               MetaWaylandSurface   *surface)
{
  MetaWaylandPointer *pointer = grab->generic.pointer;
193
  MetaWindow *window = meta_wayland_surface_get_window (surface);
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217

  meta_wayland_pointer_start_grab (pointer, (MetaWaylandPointerGrab*)grab);
  meta_display_begin_grab_op (window->display,
                              window,
                              META_GRAB_OP_WAYLAND_POPUP,
                              FALSE, /* pointer_already_grabbed */
                              FALSE, /* frame_action */
                              1, /* button. XXX? */
                              0, /* modmask */
                              meta_display_get_current_time_roundtrip (
                                window->display),
                              pointer->grab_x,
                              pointer->grab_y);
}

void
meta_wayland_popup_grab_end (MetaWaylandPopupGrab *grab)
{
  MetaWaylandPopup *popup, *tmp;

  g_assert (grab->generic.interface == &popup_grab_interface);

  wl_list_for_each_safe (popup, tmp, &grab->all_popups, link)
    {
218
      meta_wayland_popup_surface_done (popup->popup_surface);
219
220
221
222
223
224
225
226
227
228
229
230
      meta_wayland_popup_destroy (popup);
    }

  {
    MetaDisplay *display = meta_get_display ();
    meta_display_end_grab_op (display,
                              meta_display_get_current_time_roundtrip (display));
  }

  meta_wayland_pointer_end_grab (grab->generic.pointer);
}

231
232
233
234
235
236
237
238
MetaWaylandSurface *
meta_wayland_popup_grab_get_top_popup (MetaWaylandPopupGrab *grab)
{
  MetaWaylandPopup *popup;

  g_assert (!wl_list_empty (&grab->all_popups));
  popup = wl_container_of (grab->all_popups.next, popup, link);

239
  return meta_wayland_popup_surface_get_surface (popup->popup_surface);
240
241
}

242
243
244
245
246
247
248
249
250
gboolean
meta_wayland_pointer_grab_is_popup_grab (MetaWaylandPointerGrab *grab)
{
  return grab->interface == &popup_grab_interface;
}

void
meta_wayland_popup_destroy (MetaWaylandPopup *popup)
{
251
  meta_wayland_popup_surface_dismiss (popup->popup_surface);
252

253
254
255
256
257
258
259
260
261
262
263
264
  wl_list_remove (&popup->link);
  g_slice_free (MetaWaylandPopup, popup);
}

void
meta_wayland_popup_dismiss (MetaWaylandPopup *popup)
{
  MetaWaylandPopupGrab *popup_grab = popup->grab;

  meta_wayland_popup_destroy (popup);

  if (wl_list_empty (&popup_grab->all_popups))
265
266
267
268
269
270
271
272
273
274
    {
      meta_wayland_pointer_end_popup_grab (popup_grab->generic.pointer);
    }
  else
    {
      MetaWaylandSurface *top_popup_surface;
      MetaWaylandSeat *seat;

      top_popup_surface = meta_wayland_popup_grab_get_top_popup (popup_grab);
      seat = meta_wayland_pointer_get_seat (popup_grab->generic.pointer);
275
276
277

      if (meta_wayland_seat_has_keyboard (seat))
        meta_wayland_keyboard_set_focus (seat->keyboard, top_popup_surface);
278
    }
279
280
}

281
282
283
284
285
286
MetaWaylandSurface *
meta_wayland_popup_get_top_popup (MetaWaylandPopup *popup)
{
  return meta_wayland_popup_grab_get_top_popup (popup->grab);
}

287
MetaWaylandPopup *
288
289
meta_wayland_popup_create (MetaWaylandPopupSurface *popup_surface,
                           MetaWaylandPopupGrab    *grab)
290
{
291
292
  MetaWaylandSurface *surface =
    meta_wayland_popup_surface_get_surface (popup_surface);
293
  MetaWaylandPopup *popup;
294
  MetaWaylandSeat *seat;
295
296
297
298
299
300
301

  /* Don't allow creating popups if the grab has a different client. */
  if (grab->grab_client != wl_resource_get_client (surface->resource))
    return NULL;

  popup = g_slice_new0 (MetaWaylandPopup);
  popup->grab = grab;
302
  popup->popup_surface = popup_surface;
303
304
305

  wl_list_insert (&grab->all_popups, &popup->link);

306
  seat = meta_wayland_pointer_get_seat (grab->generic.pointer);
307
308
  if (meta_wayland_seat_has_keyboard (seat))
    meta_wayland_keyboard_set_focus (seat->keyboard, surface);
309

310
311
  return popup;
}