1/* swc: libswc/shell_surface.c
2 *
3 * Copyright (c) 2013, 2014 Michael Forney
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#include "shell_surface.h"
25#include "compositor.h"
26#include "internal.h"
27#include "output.h"
28#include "screen.h"
29#include "seat.h"
30#include "surface.h"
31#include "swc.h"
32#include "util.h"
33#include "view.h"
34#include "window.h"
35
36#include <signal.h>
37#include <stdlib.h>
38
39struct shell_surface {
40 struct window window;
41
42 struct wl_resource *resource;
43 struct wl_listener surface_destroy_listener;
44};
45
46static void
47configure(struct window *window, uint32_t width, uint32_t height)
48{
49 struct shell_surface *shell_surface =
50 wl_container_of(window, shell_surface, window);
51
52 wl_shell_surface_send_configure(
53 shell_surface->resource, WL_SHELL_SURFACE_RESIZE_NONE, width, height);
54
55 /* wl_shell does not support acknowledging configures. */
56 window->configure.acknowledged = true;
57}
58
59static void
60close_(struct window *window)
61{
62 struct shell_surface *shell_surface =
63 wl_container_of(window, shell_surface, window);
64 struct wl_client *client;
65 pid_t pid;
66
67 client = wl_resource_get_client(shell_surface->resource);
68 wl_client_get_credentials(client, &pid, NULL, NULL);
69 kill(pid, SIGTERM);
70}
71
72static const struct window_impl window_impl = {
73 .configure = configure,
74 .close = close_,
75};
76
77static void
78pong(struct wl_client *client, struct wl_resource *resource, uint32_t serial)
79{
80}
81
82static void
83move(struct wl_client *client, struct wl_resource *resource,
84 struct wl_resource *seat_resource, uint32_t serial)
85{
86 struct shell_surface *shell_surface = wl_resource_get_user_data(resource);
87 struct button *button;
88
89 if (!(button = pointer_get_button(swc.seat->pointer, serial))) {
90 return;
91 }
92
93 window_begin_move(&shell_surface->window, button);
94}
95
96static void
97resize(struct wl_client *client, struct wl_resource *resource,
98 struct wl_resource *seat_resource, uint32_t serial, uint32_t edges)
99{
100 struct shell_surface *shell_surface = wl_resource_get_user_data(resource);
101 struct button *button;
102
103 if (!(button = pointer_get_button(swc.seat->pointer, serial))) {
104 return;
105 }
106
107 window_begin_resize(&shell_surface->window, edges, button);
108}
109
110static void
111set_toplevel(struct wl_client *client, struct wl_resource *resource)
112{
113 struct shell_surface *shell_surface = wl_resource_get_user_data(resource);
114
115 window_manage(&shell_surface->window);
116 window_set_parent(&shell_surface->window, NULL);
117}
118
119static void
120set_transient(struct wl_client *client, struct wl_resource *resource,
121 struct wl_resource *parent_resource, int32_t x, int32_t y,
122 uint32_t flags)
123{
124 struct shell_surface *shell_surface = wl_resource_get_user_data(resource);
125 struct surface *parent_surface = wl_resource_get_user_data(parent_resource);
126 struct compositor_view *parent_view = compositor_view(parent_surface->view);
127
128 if (!parent_view || !parent_view->window) {
129 return;
130 }
131
132 window_manage(&shell_surface->window);
133 window_set_parent(&shell_surface->window, parent_view->window);
134}
135
136static void
137set_fullscreen(struct wl_client *client, struct wl_resource *resource,
138 uint32_t method, uint32_t framerate,
139 struct wl_resource *output_resource)
140{
141 struct shell_surface *shell_surface = wl_resource_get_user_data(resource);
142 struct output *output =
143 output_resource ? wl_resource_get_user_data(output_resource) : NULL;
144 struct screen *screen;
145
146 screen = output ? output->screen
147 : wl_container_of(swc.screens.next, screen, link);
148
149 /* TODO: Handle fullscreen windows. */
150
151 window_manage(&shell_surface->window);
152 window_set_parent(&shell_surface->window, NULL);
153}
154
155static void
156set_popup(struct wl_client *client, struct wl_resource *resource,
157 struct wl_resource *seat_resource, uint32_t serial,
158 struct wl_resource *parent_resource, int32_t x, int32_t y,
159 uint32_t flags)
160{
161 struct shell_surface *shell_surface = wl_resource_get_user_data(resource);
162 struct surface *parent_surface = wl_resource_get_user_data(parent_resource);
163 struct compositor_view *parent_view = compositor_view(parent_surface->view);
164
165 if (!parent_view || !parent_view->window) {
166 return;
167 }
168
169 window_unmanage(&shell_surface->window);
170 window_set_parent(&shell_surface->window, parent_view->window);
171 view_move(&shell_surface->window.view->base,
172 parent_view->base.geometry.x + x,
173 parent_view->base.geometry.y + y);
174}
175
176static void
177set_maximized(struct wl_client *client, struct wl_resource *resource,
178 struct wl_resource *output_resource)
179{
180 struct shell_surface *shell_surface = wl_resource_get_user_data(resource);
181
182 /* TODO: Handle maximized windows. */
183
184 window_manage(&shell_surface->window);
185 window_set_parent(&shell_surface->window, NULL);
186}
187
188static void
189set_title(struct wl_client *client, struct wl_resource *resource,
190 const char *title)
191{
192 struct shell_surface *shell_surface = wl_resource_get_user_data(resource);
193 window_set_title(&shell_surface->window, title, -1);
194}
195
196static void
197set_class(struct wl_client *client, struct wl_resource *resource,
198 const char *class)
199{
200 struct shell_surface *shell_surface = wl_resource_get_user_data(resource);
201 window_set_app_id(&shell_surface->window, class);
202}
203
204static const struct wl_shell_surface_interface shell_surface_implementation = {
205 .pong = pong,
206 .move = move,
207 .resize = resize,
208 .set_toplevel = set_toplevel,
209 .set_transient = set_transient,
210 .set_fullscreen = set_fullscreen,
211 .set_popup = set_popup,
212 .set_maximized = set_maximized,
213 .set_title = set_title,
214 .set_class = set_class,
215};
216
217static void
218handle_surface_destroy(struct wl_listener *listener, void *data)
219{
220 struct shell_surface *shell_surface =
221 wl_container_of(listener, shell_surface, surface_destroy_listener);
222 wl_resource_destroy(shell_surface->resource);
223}
224
225static void
226destroy_shell_surface(struct wl_resource *resource)
227{
228 struct shell_surface *shell_surface = wl_resource_get_user_data(resource);
229
230 window_finalize(&shell_surface->window);
231 free(shell_surface);
232}
233
234struct shell_surface *
235shell_surface_new(struct wl_client *client, uint32_t version, uint32_t id,
236 struct surface *surface)
237{
238 struct shell_surface *shell_surface;
239
240 shell_surface = malloc(sizeof(*shell_surface));
241
242 if (!shell_surface) {
243 goto error0;
244 }
245
246 shell_surface->resource =
247 wl_resource_create(client, &wl_shell_surface_interface, version, id);
248
249 if (!shell_surface->resource) {
250 goto error1;
251 }
252 if (!surface_set_role(surface, shell_surface->resource)) {
253 goto error2;
254 }
255
256 if (!window_initialize(&shell_surface->window, &window_impl, surface)) {
257 goto error2;
258 }
259 wl_resource_set_implementation(shell_surface->resource,
260 &shell_surface_implementation, shell_surface,
261 &destroy_shell_surface);
262 shell_surface->surface_destroy_listener.notify = &handle_surface_destroy;
263 wl_resource_add_destroy_listener(surface->resource,
264 &shell_surface->surface_destroy_listener);
265
266 return shell_surface;
267
268error2:
269 wl_resource_destroy(shell_surface->resource);
270 free(shell_surface);
271error1:
272error0:
273 return NULL;
274}