main neuswc / libswc / shell_surface.c
  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}