Change copyrights from Nokia to Digia
[profile/ivi/qtwayland.git] / src / compositor / wayland_wrapper / wlshellsurface.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the Qt Compositor.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
14 **   * Redistributions of source code must retain the above copyright
15 **     notice, this list of conditions and the following disclaimer.
16 **   * Redistributions in binary form must reproduce the above copyright
17 **     notice, this list of conditions and the following disclaimer in
18 **     the documentation and/or other materials provided with the
19 **     distribution.
20 **   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
21 **     of its contributors may be used to endorse or promote products derived
22 **     from this software without specific prior written permission.
23 **
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 #include "wlshellsurface.h"
42
43 #include "wlcompositor.h"
44 #include "wlsurface.h"
45 #include "wlinputdevice.h"
46 #include "wlsubsurface.h"
47
48 #include <QtCore/qglobal.h>
49 #include <QtCore/QDebug>
50
51 namespace Wayland {
52
53 Shell::Shell()
54 {
55 }
56
57 void Shell::bind_func(struct wl_client *client, void *data,
58                             uint32_t version, uint32_t id)
59 {
60     Q_UNUSED(version);
61     wl_client_add_object(client,&wl_shell_interface,&shell_interface,id,data);
62 }
63
64 void Shell::get_shell_surface(struct wl_client *client,
65               struct wl_resource *shell_resource,
66               uint32_t id,
67               struct wl_resource *surface_super)
68 {
69     Q_UNUSED(shell_resource);
70     Surface *surface = resolve<Surface>(surface_super);
71     new ShellSurface(client,id,surface);
72 }
73
74 const struct wl_shell_interface Shell::shell_interface = {
75     Shell::get_shell_surface
76 };
77
78 ShellSurface::ShellSurface(wl_client *client, uint32_t id, Surface *surface)
79     : m_surface(surface)
80     , m_resizeGrabber(0)
81     , m_moveGrabber(0)
82     , m_transientParent(0)
83     , m_xOffset(0)
84     , m_yOffset(0)
85 {
86     m_shellSurface = wl_client_add_object(client,&wl_shell_surface_interface,&shell_surface_interface,id,this);
87     surface->setShellSurface(this);
88 }
89
90 void ShellSurface::sendConfigure(uint32_t edges, int32_t width, int32_t height)
91 {
92     wl_shell_surface_send_configure(m_shellSurface,edges,width,height);
93 }
94
95 Surface *ShellSurface::surface() const
96 {
97     return m_surface;
98 }
99
100 void ShellSurface::adjustPosInResize()
101 {
102     if (m_transientParent)
103         return;
104     if (!m_resizeGrabber || !(m_resizeGrabber->resize_edges & WL_SHELL_SURFACE_RESIZE_TOP_LEFT))
105         return;
106
107     int bottomLeftX = wl_fixed_to_int(m_resizeGrabber->base()->x) + m_resizeGrabber->width;
108     int bottomLeftY = wl_fixed_to_int(m_resizeGrabber->base()->y) + m_resizeGrabber->height;
109     qreal x = surface()->pos().x();
110     qreal y = surface()->pos().y();
111     if (m_resizeGrabber->resize_edges & WL_SHELL_SURFACE_RESIZE_TOP)
112         y = bottomLeftY - surface()->size().height();
113     if (m_resizeGrabber->resize_edges & WL_SHELL_SURFACE_RESIZE_LEFT)
114         x = bottomLeftX - surface()->size().width();
115     QPointF newPos(x,y);
116     surface()->setPos(newPos);
117 }
118
119 QPointF ShellSurface::adjustedPosToTransientParent() const
120 {
121     if (!m_transientParent ||
122             (m_surface->subSurface() && m_surface->subSurface()->parent()))
123         return m_surface->nonAdjustedPos();
124
125     return m_transientParent->surface()->pos() + QPoint(m_xOffset,m_yOffset);
126 }
127
128 void ShellSurface::resetResizeGrabber()
129 {
130     m_resizeGrabber = 0;
131 }
132
133 void ShellSurface::resetMoveGrabber()
134 {
135     m_moveGrabber = 0;
136 }
137
138 ShellSurface *ShellSurface::transientParent() const
139 {
140     return m_transientParent;
141 }
142
143 void ShellSurface::setOffset(const QPointF &offset)
144 {
145     m_xOffset = offset.x();
146     m_yOffset = offset.y();
147 }
148
149 void ShellSurface::move(struct wl_client *client,
150                 struct wl_resource *shell_surface_resource,
151                 struct wl_resource *input_device_super,
152                 uint32_t time)
153 {
154     Q_UNUSED(client);
155     Q_UNUSED(time);
156     ShellSurface *self = static_cast<ShellSurface *>(shell_surface_resource->data);
157     InputDevice *input_device = static_cast<InputDevice *>(input_device_super->data);
158     if (self->m_resizeGrabber || self->m_moveGrabber) {
159         qDebug() << "invalid state";
160         return;
161     }
162
163     self->m_moveGrabber = new ShellSurfaceMoveGrabber(self);
164     wl_pointer *pointer = input_device->pointerDevice();
165     self->m_moveGrabber->base()->x = pointer->x;
166     self->m_moveGrabber->base()->y = pointer->y;
167     self->m_moveGrabber->offset_x = wl_fixed_to_int(pointer->x) - self->surface()->pos().x();
168     self->m_moveGrabber->offset_y = wl_fixed_to_int(pointer->y) - self->surface()->pos().y();
169
170     wl_pointer_start_grab(pointer, self->m_moveGrabber->base());
171 }
172
173 void ShellSurface::resize(struct wl_client *client,
174                   struct wl_resource *shell_surface_resource,
175                   struct wl_resource *input_device_super,
176                   uint32_t time,
177                   uint32_t edges)
178 {
179     Q_UNUSED(shell_surface_resource);
180     Q_UNUSED(client);
181     Q_UNUSED(time);
182     Q_UNUSED(edges);
183     ShellSurface *self = static_cast<ShellSurface *>(shell_surface_resource->data);
184     InputDevice *input_device = static_cast<InputDevice *>(input_device_super->data);
185     if (self->m_moveGrabber || self->m_resizeGrabber) {
186         qDebug() << "invalid state2";
187         return;
188     }
189     self->m_resizeGrabber = new ShellSurfaceResizeGrabber(self);
190     wl_pointer *pointer = input_device->pointerDevice();
191     self->m_resizeGrabber->base()->x = pointer->x;
192     self->m_resizeGrabber->base()->y = pointer->y;
193     self->m_resizeGrabber->resize_edges = wl_shell_surface_resize(edges);
194     self->m_resizeGrabber->width = self->surface()->size().width();
195     self->m_resizeGrabber->height = self->surface()->size().height();
196
197     wl_pointer_start_grab(pointer, self->m_resizeGrabber->base());
198 }
199
200 void ShellSurface::set_toplevel(struct wl_client *client,
201                      struct wl_resource *shell_surface_resource)
202 {
203     Q_UNUSED(client);
204     ShellSurface *self = static_cast<ShellSurface *>(shell_surface_resource->data);
205     self->m_transientParent = 0;
206     self->m_xOffset = 0;
207     self->m_yOffset = 0;
208
209 }
210
211 void ShellSurface::set_transient(struct wl_client *client,
212                       struct wl_resource *shell_surface_resource,
213                       struct wl_resource *parent_surface_resource,
214                       int x,
215                       int y,
216                       uint32_t flags)
217 {
218
219     Q_UNUSED(client);
220     Q_UNUSED(flags);
221     ShellSurface *shell_surface = static_cast<ShellSurface *>(shell_surface_resource->data);
222     Surface *parent_surface = static_cast<Surface *>(parent_surface_resource->data);
223     shell_surface->m_transientParent = parent_surface->shellSurface();
224     shell_surface->m_xOffset = x;
225     shell_surface->m_yOffset = y;
226     if (flags & WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
227         shell_surface->surface()->setTransientInactive(true);
228 }
229
230 void ShellSurface::set_fullscreen(struct wl_client *client,
231                        struct wl_resource *shell_surface_resource,
232                        uint32_t method,
233                        uint32_t framerate,
234                        struct wl_resource *output)
235 {
236     Q_UNUSED(client);
237     Q_UNUSED(shell_surface_resource);
238     Q_UNUSED(method);
239     Q_UNUSED(framerate);
240     Q_UNUSED(output);
241 }
242
243 void ShellSurface::set_popup(wl_client *client, wl_resource *resource, wl_resource *input_device, uint32_t time, wl_resource *parent, int32_t x, int32_t y, uint32_t flags)
244 {
245     Q_UNUSED(client);
246     Q_UNUSED(resource);
247     Q_UNUSED(input_device);
248     Q_UNUSED(time);
249     Q_UNUSED(parent);
250     Q_UNUSED(x);
251     Q_UNUSED(y);
252     Q_UNUSED(flags);
253 }
254
255 void ShellSurface::set_maximized(struct wl_client *client,
256                        struct wl_resource *shell_surface_resource,
257                        struct wl_resource *output)
258 {
259     Q_UNUSED(client);
260     Q_UNUSED(shell_surface_resource);
261     Q_UNUSED(output);
262 }
263
264 void ShellSurface::pong(struct wl_client *client,
265                         struct wl_resource *resource,
266                         uint32_t serial)
267 {
268     Q_UNUSED(client);
269     Q_UNUSED(resource);
270     Q_UNUSED(serial);
271 }
272
273 void ShellSurface::set_title(struct wl_client *client,
274                              struct wl_resource *resource,
275                              const char *title)
276 {
277     Q_UNUSED(client);
278     ShellSurface *self = static_cast<ShellSurface *>(resource->data);
279     self->surface()->setTitle(QString::fromUtf8(title));
280 }
281
282 void ShellSurface::set_class(struct wl_client *client,
283                              struct wl_resource *resource,
284                              const char *class_)
285 {
286     Q_UNUSED(client);
287     Q_UNUSED(resource);
288     Q_UNUSED(class_);
289 }
290
291 const struct wl_shell_surface_interface ShellSurface::shell_surface_interface = {
292     ShellSurface::pong,
293     ShellSurface::move,
294     ShellSurface::resize,
295     ShellSurface::set_toplevel,
296     ShellSurface::set_transient,
297     ShellSurface::set_fullscreen,
298     ShellSurface::set_popup,
299     ShellSurface::set_maximized,
300     ShellSurface::set_title,
301     ShellSurface::set_class
302 };
303
304 Qt::MouseButton toQtButton(uint32_t button)
305 {
306 #ifndef BTN_LEFT
307     static const uint32_t BTN_LEFT = 0x110;
308     static const uint32_t BTN_RIGHT = 0x111;
309     static const uint32_t BTN_MIDDLE = 0x112;
310 #endif
311     switch (button) {
312     case BTN_LEFT:
313         return Qt::LeftButton;
314     case BTN_RIGHT:
315         return Qt::RightButton;
316     case BTN_MIDDLE:
317         return Qt::MiddleButton;
318     default:
319         return Qt::NoButton;
320     }
321 }
322
323 ShellSurfaceGrabber::ShellSurfaceGrabber(ShellSurface *shellSurface, const struct wl_pointer_grab_interface *interface)
324     : shell_surface(shellSurface)
325 {
326     base()->interface = interface;
327     base()->focus = shell_surface->surface()->base();
328 }
329
330 ShellSurfaceGrabber::~ShellSurfaceGrabber()
331 {
332 }
333
334
335 void ShellSurfaceGrabber::destroy(wl_listener *listener, wl_resource *resource, uint32_t time)
336 {
337     Q_UNUSED(resource);
338     Q_UNUSED(time);
339     Q_UNUSED(listener);
340     //ShellSurfaceGrabber *shell_surface_grabber = container_of(listener, ShellSurfaceGrabber,surface_destroy_listener);
341     Q_ASSERT(false); //hasn't been enabled yet
342     //wl_input_device_end_grab(shell_surface_grabber->base()->input_device,Compositor::currentTimeMsecs());
343 }
344
345
346 ShellSurfaceResizeGrabber::ShellSurfaceResizeGrabber(ShellSurface *shellSurface)
347     : ShellSurfaceGrabber(shellSurface,&resize_grabber_interface)
348 {
349 }
350
351 void ShellSurfaceResizeGrabber::focus(wl_pointer_grab *grab, wl_surface *surface, int32_t x, int32_t y)
352 {
353     Q_UNUSED(grab);
354     Q_UNUSED(surface);
355     Q_UNUSED(x);
356     Q_UNUSED(y);
357 }
358
359 void ShellSurfaceResizeGrabber::motion(wl_pointer_grab *grab, uint32_t time, int32_t x, int32_t y)
360 {
361     Q_UNUSED(time);
362     Q_UNUSED(x);
363     Q_UNUSED(y);
364     //Should be more structured
365     ShellSurfaceResizeGrabber *resize_grabber = reinterpret_cast<ShellSurfaceResizeGrabber *>(grab);
366     ShellSurface *shell_surface = resize_grabber->shell_surface;
367     wl_pointer *pointer = grab->pointer;
368     int width_delta = wl_fixed_to_int(grab->x) - wl_fixed_to_int(pointer->x);
369     int height_delta = wl_fixed_to_int(grab->y) - wl_fixed_to_int(pointer->y);
370     int new_width = resize_grabber->width;
371     int new_height = resize_grabber->height;
372     if (resize_grabber->resize_edges & WL_SHELL_SURFACE_RESIZE_TOP_LEFT) {
373         if (resize_grabber->resize_edges & WL_SHELL_SURFACE_RESIZE_TOP) {
374             if (new_height + height_delta > 0) {
375                 new_height += height_delta;
376             } else {
377                 new_height = 1;
378             }
379         }
380         if (resize_grabber->resize_edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
381             if (new_width + width_delta > 0) {
382                 new_width += width_delta;
383             } else {
384                 new_width = 1;
385             }
386         }
387     }
388
389     if (resize_grabber->resize_edges & WL_SHELL_SURFACE_RESIZE_BOTTOM) {
390         if (new_height - height_delta > 0) {
391             new_height -= height_delta;
392         } else {
393             new_height = 1;
394         }
395     }
396     if (resize_grabber->resize_edges & WL_SHELL_SURFACE_RESIZE_RIGHT) {
397         if (new_width - width_delta > 0) {
398             new_width -= width_delta;
399         } else {
400             new_width =1;
401         }
402     }
403
404     shell_surface->sendConfigure(resize_grabber->resize_edges,new_width,new_height);
405 }
406
407 void ShellSurfaceResizeGrabber::button(wl_pointer_grab *grab, uint32_t time, uint32_t button, uint32_t state)
408 {
409     Q_UNUSED(time)
410     ShellSurfaceResizeGrabber *self = reinterpret_cast<ShellSurfaceResizeGrabber *>(grab);
411     ShellSurface *shell_surface = self->shell_surface;
412     if (toQtButton(button) == Qt::LeftButton && !state) {
413         wl_pointer_end_grab(grab->pointer);
414         shell_surface->resetResizeGrabber();
415         delete self;
416     }
417 }
418
419 const struct wl_pointer_grab_interface ShellSurfaceResizeGrabber::resize_grabber_interface = {
420     ShellSurfaceResizeGrabber::focus,
421     ShellSurfaceResizeGrabber::motion,
422     ShellSurfaceResizeGrabber::button
423 };
424
425 ShellSurfaceMoveGrabber::ShellSurfaceMoveGrabber(ShellSurface *shellSurface)
426     : ShellSurfaceGrabber(shellSurface,&move_grabber_interface)
427 {
428 }
429
430 void ShellSurfaceMoveGrabber::focus(wl_pointer_grab *grab, wl_surface *surface, int32_t x, int32_t y)
431 {
432     Q_UNUSED(grab);
433     Q_UNUSED(surface);
434     Q_UNUSED(x);
435     Q_UNUSED(y);
436 }
437
438 void ShellSurfaceMoveGrabber::motion(wl_pointer_grab *grab, uint32_t time, int32_t x, int32_t y)
439 {
440     Q_UNUSED(time);
441     Q_UNUSED(x);
442     Q_UNUSED(y);
443     ShellSurfaceMoveGrabber *shell_surface_grabber = reinterpret_cast<ShellSurfaceMoveGrabber *>(grab);
444     ShellSurface *shell_surface = shell_surface_grabber->shell_surface;
445     wl_pointer *pointer = grab->pointer;
446     QPointF pos(wl_fixed_to_int(pointer->x) - shell_surface_grabber->offset_x,
447                 wl_fixed_to_int(pointer->y) - shell_surface_grabber->offset_y);
448     shell_surface->surface()->setPos(pos);
449     if (shell_surface->transientParent())
450         shell_surface->setOffset(pos - shell_surface->transientParent()->surface()->pos());
451     shell_surface->surface()->damage(QRect(QPoint(0,0),shell_surface->surface()->size()));
452 }
453
454 void ShellSurfaceMoveGrabber::button(wl_pointer_grab *grab, uint32_t time, uint32_t button, uint32_t state)
455 {
456     Q_UNUSED(time)
457     ShellSurfaceResizeGrabber *self = reinterpret_cast<ShellSurfaceResizeGrabber *>(grab);
458     ShellSurface *shell_surface = self->shell_surface;
459     if (toQtButton(button) == Qt::LeftButton && !state) {
460         wl_pointer_set_focus(grab->pointer, 0, 0, 0);
461         wl_pointer_end_grab(grab->pointer);
462         shell_surface->resetMoveGrabber();
463         delete self;
464     }
465 }
466
467 const struct wl_pointer_grab_interface ShellSurfaceMoveGrabber::move_grabber_interface = {
468     ShellSurfaceMoveGrabber::focus,
469     ShellSurfaceMoveGrabber::motion,
470     ShellSurfaceMoveGrabber::button
471 };
472
473 }