blob: a0331e2ca331a9c2ab4690f9ec11335242e51bea [file] [log] [blame]
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001/*
2 * Copyright © 2010 Intel Corporation
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26
27#include "wayland-server.h"
28#include "compositor.h"
29
30struct wlsc_move_grab {
31 struct wl_grab grab;
32 int32_t dx, dy;
33};
34
35static void
36move_grab_motion(struct wl_grab *grab,
37 uint32_t time, int32_t x, int32_t y)
38{
39 struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab;
40 struct wlsc_surface *es =
41 (struct wlsc_surface *) grab->input_device->pointer_focus;
42
43 es->x = x + move->dx;
44 es->y = y + move->dy;
45 wlsc_surface_update_matrix(es);
46}
47
48static void
49move_grab_button(struct wl_grab *grab,
50 uint32_t time, int32_t button, int32_t state)
51{
52}
53
54static void
55move_grab_end(struct wl_grab *grab, uint32_t time)
56{
57 free(grab);
58}
59
60static const struct wl_grab_interface move_grab_interface = {
61 move_grab_motion,
62 move_grab_button,
63 move_grab_end
64};
65
66void
67shell_move(struct wl_client *client, struct wl_shell *shell,
68 struct wl_surface *surface,
69 struct wl_input_device *device, uint32_t time)
70{
71 struct wlsc_input_device *wd = (struct wlsc_input_device *) device;
72 struct wlsc_surface *es = (struct wlsc_surface *) surface;
73 struct wlsc_move_grab *move;
74
75 move = malloc(sizeof *move);
76 if (!move) {
77 wl_client_post_no_memory(client);
78 return;
79 }
80
81 move->grab.interface = &move_grab_interface;
82 move->dx = es->x - wd->input_device.grab_x;
83 move->dy = es->y - wd->input_device.grab_y;
84
85 if (wl_input_device_update_grab(&wd->input_device,
86 &move->grab, surface, time) < 0)
87 return;
88
89 wlsc_input_device_set_pointer_image(wd, WLSC_POINTER_DRAGGING);
90}
91
92struct wlsc_resize_grab {
93 struct wl_grab grab;
94 uint32_t edges;
95 int32_t dx, dy, width, height;
96};
97
98static void
99resize_grab_motion(struct wl_grab *grab,
100 uint32_t time, int32_t x, int32_t y)
101{
102 struct wlsc_resize_grab *resize = (struct wlsc_resize_grab *) grab;
103 struct wl_input_device *device = grab->input_device;
104 struct wlsc_compositor *ec =
105 (struct wlsc_compositor *) device->compositor;
106 struct wl_surface *surface = device->pointer_focus;
107 int32_t width, height;
108
109 if (resize->edges & WL_GRAB_RESIZE_LEFT) {
110 width = device->grab_x - x + resize->width;
111 } else if (resize->edges & WL_GRAB_RESIZE_RIGHT) {
112 width = x - device->grab_x + resize->width;
113 } else {
114 width = resize->width;
115 }
116
117 if (resize->edges & WL_GRAB_RESIZE_TOP) {
118 height = device->grab_y - y + resize->height;
119 } else if (resize->edges & WL_GRAB_RESIZE_BOTTOM) {
120 height = y - device->grab_y + resize->height;
121 } else {
122 height = resize->height;
123 }
124
125 wl_client_post_event(surface->client, &ec->shell.object,
126 WL_SHELL_CONFIGURE, time, resize->edges,
127 surface, width, height);
128}
129
130static void
131resize_grab_button(struct wl_grab *grab,
132 uint32_t time, int32_t button, int32_t state)
133{
134}
135
136static void
137resize_grab_end(struct wl_grab *grab, uint32_t time)
138{
139 free(grab);
140}
141
142static const struct wl_grab_interface resize_grab_interface = {
143 resize_grab_motion,
144 resize_grab_button,
145 resize_grab_end
146};
147
148void
149shell_resize(struct wl_client *client, struct wl_shell *shell,
150 struct wl_surface *surface,
151 struct wl_input_device *device, uint32_t time, uint32_t edges)
152{
153 struct wlsc_input_device *wd = (struct wlsc_input_device *) device;
154 struct wlsc_resize_grab *resize;
155 enum wlsc_pointer_type pointer = WLSC_POINTER_LEFT_PTR;
156 struct wlsc_surface *es = (struct wlsc_surface *) surface;
157
158 resize = malloc(sizeof *resize);
159 if (!resize) {
160 wl_client_post_no_memory(client);
161 return;
162 }
163
164 resize->grab.interface = &resize_grab_interface;
165 resize->edges = edges;
166 resize->dx = es->x - wd->input_device.grab_x;
167 resize->dy = es->y - wd->input_device.grab_y;
168 resize->width = es->width;
169 resize->height = es->height;
170
171 if (edges == 0 || edges > 15 ||
172 (edges & 3) == 3 || (edges & 12) == 12)
173 return;
174
175 switch (edges) {
176 case WL_GRAB_RESIZE_TOP:
177 pointer = WLSC_POINTER_TOP;
178 break;
179 case WL_GRAB_RESIZE_BOTTOM:
180 pointer = WLSC_POINTER_BOTTOM;
181 break;
182 case WL_GRAB_RESIZE_LEFT:
183 pointer = WLSC_POINTER_LEFT;
184 break;
185 case WL_GRAB_RESIZE_TOP_LEFT:
186 pointer = WLSC_POINTER_TOP_LEFT;
187 break;
188 case WL_GRAB_RESIZE_BOTTOM_LEFT:
189 pointer = WLSC_POINTER_BOTTOM_LEFT;
190 break;
191 case WL_GRAB_RESIZE_RIGHT:
192 pointer = WLSC_POINTER_RIGHT;
193 break;
194 case WL_GRAB_RESIZE_TOP_RIGHT:
195 pointer = WLSC_POINTER_TOP_RIGHT;
196 break;
197 case WL_GRAB_RESIZE_BOTTOM_RIGHT:
198 pointer = WLSC_POINTER_BOTTOM_RIGHT;
199 break;
200 }
201
202 if (wl_input_device_update_grab(&wd->input_device,
203 &resize->grab, surface, time) < 0)
204 return;
205
206 wlsc_input_device_set_pointer_image(wd, pointer);
207}
208
209static void
210wl_drag_set_pointer_focus(struct wl_drag *drag,
211 struct wl_surface *surface, uint32_t time,
212 int32_t x, int32_t y, int32_t sx, int32_t sy);
213
214static void
215destroy_drag(struct wl_resource *resource, struct wl_client *client)
216{
217 struct wl_drag *drag =
218 container_of(resource, struct wl_drag, resource);
219
220 wl_list_remove(&drag->drag_focus_listener.link);
221 if (drag->grab.input_device)
222 wl_input_device_end_grab(drag->grab.input_device, get_time());
223
224 free(drag);
225}
226
227
228static void
229wl_drag_set_pointer_focus(struct wl_drag *drag,
230 struct wl_surface *surface, uint32_t time,
231 int32_t x, int32_t y, int32_t sx, int32_t sy)
232{
233 char **p, **end;
234
235 if (drag->drag_focus == surface)
236 return;
237
238 if (drag->drag_focus &&
239 (!surface || drag->drag_focus->client != surface->client))
240 wl_client_post_event(drag->drag_focus->client,
241 &drag->drag_offer.object,
242 WL_DRAG_OFFER_POINTER_FOCUS,
243 time, NULL, 0, 0, 0, 0);
244
245 if (surface &&
246 (!drag->drag_focus ||
247 drag->drag_focus->client != surface->client)) {
248 wl_client_post_global(surface->client,
249 &drag->drag_offer.object);
250
251 end = drag->types.data + drag->types.size;
252 for (p = drag->types.data; p < end; p++)
253 wl_client_post_event(surface->client,
254 &drag->drag_offer.object,
255 WL_DRAG_OFFER_OFFER, *p);
256 }
257
258 if (surface) {
259 wl_client_post_event(surface->client,
260 &drag->drag_offer.object,
261 WL_DRAG_OFFER_POINTER_FOCUS,
262 time, surface,
263 x, y, sx, sy);
264
265 }
266
267 drag->drag_focus = surface;
268 drag->pointer_focus_time = time;
269 drag->target = NULL;
270
271 wl_list_remove(&drag->drag_focus_listener.link);
272 if (surface)
273 wl_list_insert(surface->destroy_listener_list.prev,
274 &drag->drag_focus_listener.link);
275}
276
277static void
278drag_offer_accept(struct wl_client *client,
279 struct wl_drag_offer *offer, uint32_t time, const char *type)
280{
281 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
282 char **p, **end;
283
284 /* If the client responds to drag pointer_focus or motion
285 * events after the pointer has left the surface, we just
286 * discard the accept requests. The drag source just won't
287 * get the corresponding 'target' events and eventually the
288 * next surface/root will start sending events. */
289 if (time < drag->pointer_focus_time)
290 return;
291
292 drag->target = client;
293 drag->type = NULL;
294 end = drag->types.data + drag->types.size;
295 for (p = drag->types.data; p < end; p++)
296 if (type && strcmp(*p, type) == 0)
297 drag->type = *p;
298
299 wl_client_post_event(drag->source->client, &drag->resource.object,
300 WL_DRAG_TARGET, drag->type);
301}
302
303static void
304drag_offer_receive(struct wl_client *client,
305 struct wl_drag_offer *offer, int fd)
306{
307 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
308
309 wl_client_post_event(drag->source->client, &drag->resource.object,
310 WL_DRAG_FINISH, fd);
311 close(fd);
312}
313
314static void
315drag_offer_reject(struct wl_client *client, struct wl_drag_offer *offer)
316{
317 struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
318
319 wl_client_post_event(drag->source->client, &drag->resource.object,
320 WL_DRAG_REJECT);
321}
322
323static const struct wl_drag_offer_interface drag_offer_interface = {
324 drag_offer_accept,
325 drag_offer_receive,
326 drag_offer_reject
327};
328
329static void
330drag_offer(struct wl_client *client, struct wl_drag *drag, const char *type)
331{
332 char **p;
333
334 p = wl_array_add(&drag->types, sizeof *p);
335 if (p)
336 *p = strdup(type);
337 if (!p || !*p)
338 wl_client_post_no_memory(client);
339}
340
341static void
342drag_grab_motion(struct wl_grab *grab,
343 uint32_t time, int32_t x, int32_t y)
344{
345 struct wl_drag *drag = container_of(grab, struct wl_drag, grab);
346 struct wlsc_surface *es;
347 int32_t sx, sy;
348
349 es = pick_surface(grab->input_device, &sx, &sy);
350 wl_drag_set_pointer_focus(drag, &es->surface, time, x, y, sx, sy);
351 if (es)
352 wl_client_post_event(es->surface.client,
353 &drag->drag_offer.object,
354 WL_DRAG_OFFER_MOTION,
355 time, x, y, sx, sy);
356}
357
358static void
359drag_grab_button(struct wl_grab *grab,
360 uint32_t time, int32_t button, int32_t state)
361{
362}
363
364static void
365drag_grab_end(struct wl_grab *grab, uint32_t time)
366{
367 struct wl_drag *drag = container_of(grab, struct wl_drag, grab);
368
369 if (drag->target)
370 wl_client_post_event(drag->target,
371 &drag->drag_offer.object,
372 WL_DRAG_OFFER_DROP);
373
374 wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
375}
376
377static const struct wl_grab_interface drag_grab_interface = {
378 drag_grab_motion,
379 drag_grab_button,
380 drag_grab_end
381};
382
383static void
384drag_activate(struct wl_client *client,
385 struct wl_drag *drag,
386 struct wl_surface *surface,
387 struct wl_input_device *device, uint32_t time)
388{
389 struct wl_display *display = wl_client_get_display (client);
390 struct wlsc_surface *target;
391 int32_t sx, sy;
392
393 if (wl_input_device_update_grab(device,
394 &drag->grab, surface, time) < 0)
395 return;
396
397 drag->grab.interface = &drag_grab_interface;
398
399 drag->source = surface;
400
401 drag->drag_offer.object.interface = &wl_drag_offer_interface;
402 drag->drag_offer.object.implementation =
403 (void (**)(void)) &drag_offer_interface;
404
405 wl_display_add_object(display, &drag->drag_offer.object);
406
407 target = pick_surface(device, &sx, &sy);
408 wl_drag_set_pointer_focus(drag, &target->surface, time,
409 device->x, device->y, sx, sy);
410}
411
412static void
413drag_destroy(struct wl_client *client, struct wl_drag *drag)
414{
415 wl_resource_destroy(&drag->resource, client);
416}
417
418static const struct wl_drag_interface drag_interface = {
419 drag_offer,
420 drag_activate,
421 drag_destroy,
422};
423
424static void
425drag_handle_surface_destroy(struct wl_listener *listener,
426 struct wl_surface *surface, uint32_t time)
427{
428 struct wl_drag *drag =
429 container_of(listener, struct wl_drag, drag_focus_listener);
430
431 if (drag->drag_focus == surface)
432 wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
433}
434
435static void
436shell_create_drag(struct wl_client *client,
437 struct wl_shell *shell, uint32_t id)
438{
439 struct wl_drag *drag;
440
441 drag = malloc(sizeof *drag);
442 if (drag == NULL) {
443 wl_client_post_no_memory(client);
444 return;
445 }
446
447 memset(drag, 0, sizeof *drag);
448 drag->resource.object.id = id;
449 drag->resource.object.interface = &wl_drag_interface;
450 drag->resource.object.implementation =
451 (void (**)(void)) &drag_interface;
452
453 drag->resource.destroy = destroy_drag;
454
455 drag->drag_focus_listener.func = drag_handle_surface_destroy;
456 wl_list_init(&drag->drag_focus_listener.link);
457
458 wl_client_add_resource(client, &drag->resource);
459}
460
461const static struct wl_shell_interface shell_interface = {
462 shell_move,
463 shell_resize,
464 shell_create_drag
465};
466
467int
468wlsc_shell_init(struct wlsc_compositor *ec)
469{
470 struct wl_shell *shell = &ec->shell;
471
472 shell->object.interface = &wl_shell_interface;
473 shell->object.implementation = (void (**)(void)) &shell_interface;
474 wl_display_add_object(ec->wl_display, &shell->object);
475 if (wl_display_add_global(ec->wl_display, &shell->object, NULL))
476 return -1;
477
478 return 0;
479}