blob: c8810a9186dbff8a3ad7aa94c30a53fcc769f302 [file] [log] [blame]
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001/*
2 * Copyright © 2011 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
Daniel Stonec228e232013-05-22 18:03:19 +030023#include "config.h"
Kristian Høgsberg380deee2012-05-21 17:12:41 -040024
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <sys/socket.h>
29#include <sys/un.h>
30#include <fcntl.h>
31#include <errno.h>
32#include <unistd.h>
33#include <signal.h>
Tiago Vignatti90fada42012-07-16 12:02:08 -040034#include <X11/Xcursor/Xcursor.h>
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -050035#include <linux/input.h>
Kristian Høgsberg380deee2012-05-21 17:12:41 -040036
37#include "xwayland.h"
38
Kristian Høgsberg2ba10df2013-12-03 16:38:15 -080039#include "cairo-util.h"
40#include "compositor.h"
Kristian Høgsberg380deee2012-05-21 17:12:41 -040041#include "xserver-server-protocol.h"
42#include "hash.h"
43
Kristian Høgsberg1a7a57f2013-08-31 00:12:25 -070044struct wm_size_hints {
45 uint32_t flags;
46 int32_t x, y;
47 int32_t width, height; /* should set so old wm's don't mess up */
48 int32_t min_width, min_height;
49 int32_t max_width, max_height;
50 int32_t width_inc, height_inc;
51 struct {
52 int32_t x;
53 int32_t y;
54 } min_aspect, max_aspect;
55 int32_t base_width, base_height;
56 int32_t win_gravity;
57};
58
59#define USPosition (1L << 0)
60#define USSize (1L << 1)
61#define PPosition (1L << 2)
62#define PSize (1L << 3)
63#define PMinSize (1L << 4)
64#define PMaxSize (1L << 5)
65#define PResizeInc (1L << 6)
66#define PAspect (1L << 7)
67#define PBaseSize (1L << 8)
68#define PWinGravity (1L << 9)
69
Kristian Høgsberg380deee2012-05-21 17:12:41 -040070struct motif_wm_hints {
71 uint32_t flags;
72 uint32_t functions;
73 uint32_t decorations;
74 int32_t input_mode;
75 uint32_t status;
76};
77
78#define MWM_HINTS_FUNCTIONS (1L << 0)
79#define MWM_HINTS_DECORATIONS (1L << 1)
80#define MWM_HINTS_INPUT_MODE (1L << 2)
81#define MWM_HINTS_STATUS (1L << 3)
82
83#define MWM_FUNC_ALL (1L << 0)
84#define MWM_FUNC_RESIZE (1L << 1)
85#define MWM_FUNC_MOVE (1L << 2)
86#define MWM_FUNC_MINIMIZE (1L << 3)
87#define MWM_FUNC_MAXIMIZE (1L << 4)
88#define MWM_FUNC_CLOSE (1L << 5)
89
90#define MWM_DECOR_ALL (1L << 0)
91#define MWM_DECOR_BORDER (1L << 1)
92#define MWM_DECOR_RESIZEH (1L << 2)
93#define MWM_DECOR_TITLE (1L << 3)
94#define MWM_DECOR_MENU (1L << 4)
95#define MWM_DECOR_MINIMIZE (1L << 5)
96#define MWM_DECOR_MAXIMIZE (1L << 6)
97
98#define MWM_INPUT_MODELESS 0
99#define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1
100#define MWM_INPUT_SYSTEM_MODAL 2
101#define MWM_INPUT_FULL_APPLICATION_MODAL 3
102#define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL
103
104#define MWM_TEAROFF_WINDOW (1L<<0)
105
106#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
107#define _NET_WM_MOVERESIZE_SIZE_TOP 1
108#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
109#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3
110#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
111#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5
112#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
113#define _NET_WM_MOVERESIZE_SIZE_LEFT 7
114#define _NET_WM_MOVERESIZE_MOVE 8 /* movement only */
115#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 /* size via keyboard */
116#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */
117#define _NET_WM_MOVERESIZE_CANCEL 11 /* cancel operation */
118
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400119struct weston_wm_window {
120 struct weston_wm *wm;
121 xcb_window_t id;
122 xcb_window_t frame_id;
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -0500123 struct frame *frame;
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400124 cairo_surface_t *cairo_surface;
Kristian Høgsberg757d8af2014-03-17 22:33:29 -0700125 uint32_t surface_id;
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400126 struct weston_surface *surface;
127 struct shell_surface *shsurf;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500128 struct weston_view *view;
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400129 struct wl_listener surface_destroy_listener;
130 struct wl_event_source *repaint_source;
Kristian Høgsberga61ca062012-05-22 16:05:52 -0400131 struct wl_event_source *configure_source;
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400132 int properties_dirty;
Tiago Vignatti0d20d7c2012-09-27 17:48:37 +0300133 int pid;
134 char *machine;
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400135 char *class;
136 char *name;
137 struct weston_wm_window *transient_for;
138 uint32_t protocols;
139 xcb_atom_t type;
140 int width, height;
141 int x, y;
Kristian Høgsbergb810eb52013-02-12 20:07:05 -0500142 int saved_width, saved_height;
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400143 int decorate;
Tiago Vignatti771241e2012-06-04 20:01:45 +0300144 int override_redirect;
Kristian Høgsbergb810eb52013-02-12 20:07:05 -0500145 int fullscreen;
MoD384a11a2013-06-22 11:04:21 -0500146 int has_alpha;
Kristian Høgsberg2cd6da12013-10-13 22:11:07 -0700147 int delete_window;
Kristian Høgsberg1a7a57f2013-08-31 00:12:25 -0700148 struct wm_size_hints size_hints;
149 struct motif_wm_hints motif_hints;
Kristian Høgsberg757d8af2014-03-17 22:33:29 -0700150 struct wl_list link;
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400151};
152
153static struct weston_wm_window *
154get_wm_window(struct weston_surface *surface);
155
Kristian Høgsbergeaee7842012-05-22 10:04:20 -0400156static void
157weston_wm_window_schedule_repaint(struct weston_wm_window *window);
158
Kristian Høgsberg757d8af2014-03-17 22:33:29 -0700159static void
160xserver_map_shell_surface(struct weston_wm_window *window,
161 struct weston_surface *surface);
162
Kristian Høgsberg082d58c2013-06-18 01:00:27 -0400163static int __attribute__ ((format (printf, 1, 2)))
164wm_log(const char *fmt, ...)
165{
166#ifdef WM_DEBUG
167 int l;
168 va_list argp;
169
170 va_start(argp, fmt);
171 l = weston_vlog(fmt, argp);
172 va_end(argp);
173
174 return l;
175#else
176 return 0;
177#endif
178}
179
180static int __attribute__ ((format (printf, 1, 2)))
181wm_log_continue(const char *fmt, ...)
182{
183#ifdef WM_DEBUG
184 int l;
185 va_list argp;
186
187 va_start(argp, fmt);
188 l = weston_vlog_continue(fmt, argp);
189 va_end(argp);
190
191 return l;
192#else
193 return 0;
194#endif
195}
196
197
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400198const char *
199get_atom_name(xcb_connection_t *c, xcb_atom_t atom)
200{
201 xcb_get_atom_name_cookie_t cookie;
202 xcb_get_atom_name_reply_t *reply;
203 xcb_generic_error_t *e;
204 static char buffer[64];
205
206 if (atom == XCB_ATOM_NONE)
207 return "None";
208
209 cookie = xcb_get_atom_name (c, atom);
210 reply = xcb_get_atom_name_reply (c, cookie, &e);
MoD55375b92013-06-11 19:59:42 -0500211
212 if(reply) {
213 snprintf(buffer, sizeof buffer, "%.*s",
214 xcb_get_atom_name_name_length (reply),
215 xcb_get_atom_name_name (reply));
216 } else {
217 snprintf(buffer, sizeof buffer, "(atom %u)", atom);
218 }
219
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400220 free(reply);
221
222 return buffer;
223}
224
Tiago Vignatti90fada42012-07-16 12:02:08 -0400225static xcb_cursor_t
226xcb_cursor_image_load_cursor(struct weston_wm *wm, const XcursorImage *img)
227{
228 xcb_connection_t *c = wm->conn;
229 xcb_screen_iterator_t s = xcb_setup_roots_iterator(xcb_get_setup(c));
230 xcb_screen_t *screen = s.data;
231 xcb_gcontext_t gc;
232 xcb_pixmap_t pix;
233 xcb_render_picture_t pic;
234 xcb_cursor_t cursor;
235 int stride = img->width * 4;
236
237 pix = xcb_generate_id(c);
238 xcb_create_pixmap(c, 32, pix, screen->root, img->width, img->height);
239
240 pic = xcb_generate_id(c);
241 xcb_render_create_picture(c, pic, pix, wm->format_rgba.id, 0, 0);
242
243 gc = xcb_generate_id(c);
244 xcb_create_gc(c, gc, pix, 0, 0);
245
246 xcb_put_image(c, XCB_IMAGE_FORMAT_Z_PIXMAP, pix, gc,
247 img->width, img->height, 0, 0, 0, 32,
248 stride * img->height, (uint8_t *) img->pixels);
249 xcb_free_gc(c, gc);
250
251 cursor = xcb_generate_id(c);
252 xcb_render_create_cursor(c, cursor, pic, img->xhot, img->yhot);
253
254 xcb_render_free_picture(c, pic);
255 xcb_free_pixmap(c, pix);
256
257 return cursor;
258}
259
260static xcb_cursor_t
261xcb_cursor_images_load_cursor(struct weston_wm *wm, const XcursorImages *images)
262{
263 /* TODO: treat animated cursors as well */
264 if (images->nimage != 1)
265 return -1;
266
267 return xcb_cursor_image_load_cursor(wm, images->images[0]);
268}
269
270static xcb_cursor_t
271xcb_cursor_library_load_cursor(struct weston_wm *wm, const char *file)
272{
273 xcb_cursor_t cursor;
274 XcursorImages *images;
275 char *v = NULL;
276 int size = 0;
277
278 if (!file)
279 return 0;
280
281 v = getenv ("XCURSOR_SIZE");
282 if (v)
283 size = atoi(v);
284
285 if (!size)
286 size = 32;
287
288 images = XcursorLibraryLoadImages (file, NULL, size);
Tiago Vignattiac78bb12012-09-28 16:29:46 +0300289 if (!images)
290 return -1;
291
Tiago Vignatti90fada42012-07-16 12:02:08 -0400292 cursor = xcb_cursor_images_load_cursor (wm, images);
293 XcursorImagesDestroy (images);
294
295 return cursor;
296}
297
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400298void
Kristian Høgsberg0273b572012-05-30 09:58:02 -0400299dump_property(struct weston_wm *wm,
300 xcb_atom_t property, xcb_get_property_reply_t *reply)
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400301{
302 int32_t *incr_value;
303 const char *text_value, *name;
304 xcb_atom_t *atom_value;
305 int width, len;
306 uint32_t i;
307
Kristian Høgsberg082d58c2013-06-18 01:00:27 -0400308 width = wm_log_continue("%s: ", get_atom_name(wm->conn, property));
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400309 if (reply == NULL) {
Kristian Høgsberg082d58c2013-06-18 01:00:27 -0400310 wm_log_continue("(no reply)\n");
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400311 return;
312 }
313
Kristian Høgsberg082d58c2013-06-18 01:00:27 -0400314 width += wm_log_continue("%s/%d, length %d (value_len %d): ",
315 get_atom_name(wm->conn, reply->type),
316 reply->format,
317 xcb_get_property_value_length(reply),
318 reply->value_len);
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400319
320 if (reply->type == wm->atom.incr) {
321 incr_value = xcb_get_property_value(reply);
Kristian Høgsberg082d58c2013-06-18 01:00:27 -0400322 wm_log_continue("%d\n", *incr_value);
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400323 } else if (reply->type == wm->atom.utf8_string ||
324 reply->type == wm->atom.string) {
325 text_value = xcb_get_property_value(reply);
326 if (reply->value_len > 40)
327 len = 40;
328 else
329 len = reply->value_len;
Kristian Høgsberg082d58c2013-06-18 01:00:27 -0400330 wm_log_continue("\"%.*s\"\n", len, text_value);
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400331 } else if (reply->type == XCB_ATOM_ATOM) {
332 atom_value = xcb_get_property_value(reply);
333 for (i = 0; i < reply->value_len; i++) {
334 name = get_atom_name(wm->conn, atom_value[i]);
335 if (width + strlen(name) + 2 > 78) {
Kristian Høgsberg082d58c2013-06-18 01:00:27 -0400336 wm_log_continue("\n ");
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400337 width = 4;
338 } else if (i > 0) {
Kristian Høgsberg082d58c2013-06-18 01:00:27 -0400339 width += wm_log_continue(", ");
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400340 }
341
Kristian Høgsberg082d58c2013-06-18 01:00:27 -0400342 width += wm_log_continue("%s", name);
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400343 }
Kristian Høgsberg082d58c2013-06-18 01:00:27 -0400344 wm_log_continue("\n");
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400345 } else {
Kristian Høgsberg082d58c2013-06-18 01:00:27 -0400346 wm_log_continue("huh?\n");
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400347 }
348}
349
Tiago Vignatti2d129f12012-11-30 17:19:59 -0200350static void
Kristian Høgsberg0273b572012-05-30 09:58:02 -0400351read_and_dump_property(struct weston_wm *wm,
352 xcb_window_t window, xcb_atom_t property)
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400353{
Kristian Høgsberg0273b572012-05-30 09:58:02 -0400354 xcb_get_property_reply_t *reply;
355 xcb_get_property_cookie_t cookie;
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400356
Kristian Høgsberg0273b572012-05-30 09:58:02 -0400357 cookie = xcb_get_property(wm->conn, 0, window,
358 property, XCB_ATOM_ANY, 0, 2048);
359 reply = xcb_get_property_reply(wm->conn, cookie, NULL);
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400360
Kristian Høgsberg0273b572012-05-30 09:58:02 -0400361 dump_property(wm, property, reply);
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400362
Kristian Høgsberg0273b572012-05-30 09:58:02 -0400363 free(reply);
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400364}
365
366/* We reuse some predefined, but otherwise useles atoms */
367#define TYPE_WM_PROTOCOLS XCB_ATOM_CUT_BUFFER0
368#define TYPE_MOTIF_WM_HINTS XCB_ATOM_CUT_BUFFER1
Kristian Høgsbergb810eb52013-02-12 20:07:05 -0500369#define TYPE_NET_WM_STATE XCB_ATOM_CUT_BUFFER2
Kristian Høgsberg1a7a57f2013-08-31 00:12:25 -0700370#define TYPE_WM_NORMAL_HINTS XCB_ATOM_CUT_BUFFER3
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400371
372static void
373weston_wm_window_read_properties(struct weston_wm_window *window)
374{
375 struct weston_wm *wm = window->wm;
Giulio Camuffo62942ad2013-09-11 18:20:47 +0200376 struct weston_shell_interface *shell_interface =
377 &wm->server->compositor->shell_interface;
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400378
379#define F(field) offsetof(struct weston_wm_window, field)
380 const struct {
381 xcb_atom_t atom;
382 xcb_atom_t type;
383 int offset;
384 } props[] = {
385 { XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, F(class) },
386 { XCB_ATOM_WM_NAME, XCB_ATOM_STRING, F(name) },
387 { XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, F(transient_for) },
388 { wm->atom.wm_protocols, TYPE_WM_PROTOCOLS, F(protocols) },
Kristian Høgsberg1a7a57f2013-08-31 00:12:25 -0700389 { wm->atom.wm_normal_hints, TYPE_WM_NORMAL_HINTS, F(protocols) },
Kristian Høgsbergb810eb52013-02-12 20:07:05 -0500390 { wm->atom.net_wm_state, TYPE_NET_WM_STATE },
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400391 { wm->atom.net_wm_window_type, XCB_ATOM_ATOM, F(type) },
392 { wm->atom.net_wm_name, XCB_ATOM_STRING, F(name) },
Tiago Vignatti0d20d7c2012-09-27 17:48:37 +0300393 { wm->atom.net_wm_pid, XCB_ATOM_CARDINAL, F(pid) },
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400394 { wm->atom.motif_wm_hints, TYPE_MOTIF_WM_HINTS, 0 },
Tiago Vignatti0d20d7c2012-09-27 17:48:37 +0300395 { wm->atom.wm_client_machine, XCB_ATOM_WM_CLIENT_MACHINE, F(machine) },
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400396 };
397#undef F
398
399 xcb_get_property_cookie_t cookie[ARRAY_LENGTH(props)];
400 xcb_get_property_reply_t *reply;
401 void *p;
402 uint32_t *xid;
403 xcb_atom_t *atom;
404 uint32_t i;
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400405
406 if (!window->properties_dirty)
407 return;
408 window->properties_dirty = 0;
409
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400410 for (i = 0; i < ARRAY_LENGTH(props); i++)
411 cookie[i] = xcb_get_property(wm->conn,
412 0, /* delete */
413 window->id,
414 props[i].atom,
415 XCB_ATOM_ANY, 0, 2048);
416
Tiago Vignatti2ea74d92012-07-20 23:09:53 +0300417 window->decorate = !window->override_redirect;
Kristian Høgsberg1a7a57f2013-08-31 00:12:25 -0700418 window->size_hints.flags = 0;
419 window->motif_hints.flags = 0;
Kristian Høgsberg2cd6da12013-10-13 22:11:07 -0700420 window->delete_window = 0;
Kristian Høgsberg1a7a57f2013-08-31 00:12:25 -0700421
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400422 for (i = 0; i < ARRAY_LENGTH(props); i++) {
423 reply = xcb_get_property_reply(wm->conn, cookie[i], NULL);
424 if (!reply)
425 /* Bad window, typically */
426 continue;
427 if (reply->type == XCB_ATOM_NONE) {
428 /* No such property */
429 free(reply);
430 continue;
431 }
432
433 p = ((char *) window + props[i].offset);
434
435 switch (props[i].type) {
Tiago Vignatti0d20d7c2012-09-27 17:48:37 +0300436 case XCB_ATOM_WM_CLIENT_MACHINE:
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400437 case XCB_ATOM_STRING:
438 /* FIXME: We're using this for both string and
439 utf8_string */
440 if (*(char **) p)
441 free(*(char **) p);
442
443 *(char **) p =
444 strndup(xcb_get_property_value(reply),
445 xcb_get_property_value_length(reply));
446 break;
447 case XCB_ATOM_WINDOW:
448 xid = xcb_get_property_value(reply);
449 *(struct weston_wm_window **) p =
450 hash_table_lookup(wm->window_hash, *xid);
451 break;
Tiago Vignatti0d20d7c2012-09-27 17:48:37 +0300452 case XCB_ATOM_CARDINAL:
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400453 case XCB_ATOM_ATOM:
454 atom = xcb_get_property_value(reply);
455 *(xcb_atom_t *) p = *atom;
456 break;
457 case TYPE_WM_PROTOCOLS:
Kristian Høgsberg2cd6da12013-10-13 22:11:07 -0700458 atom = xcb_get_property_value(reply);
459 for (i = 0; i < reply->value_len; i++)
460 if (atom[i] == wm->atom.wm_delete_window)
461 window->delete_window = 1;
462 break;
463
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400464 break;
Kristian Høgsberg1a7a57f2013-08-31 00:12:25 -0700465 case TYPE_WM_NORMAL_HINTS:
466 memcpy(&window->size_hints,
467 xcb_get_property_value(reply),
468 sizeof window->size_hints);
469 break;
Kristian Høgsbergb810eb52013-02-12 20:07:05 -0500470 case TYPE_NET_WM_STATE:
471 window->fullscreen = 0;
472 atom = xcb_get_property_value(reply);
473 for (i = 0; i < reply->value_len; i++)
474 if (atom[i] == wm->atom.net_wm_state_fullscreen)
475 window->fullscreen = 1;
476 break;
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400477 case TYPE_MOTIF_WM_HINTS:
Kristian Høgsberg1a7a57f2013-08-31 00:12:25 -0700478 memcpy(&window->motif_hints,
479 xcb_get_property_value(reply),
480 sizeof window->motif_hints);
481 if (window->motif_hints.flags & MWM_HINTS_DECORATIONS)
482 window->decorate =
483 window->motif_hints.decorations > 0;
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400484 break;
485 default:
486 break;
487 }
488 free(reply);
489 }
Giulio Camuffo62942ad2013-09-11 18:20:47 +0200490
491 if (window->shsurf && window->name)
492 shell_interface->set_title(window->shsurf, window->name);
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -0500493 if (window->frame && window->name)
494 frame_set_title(window->frame, window->name);
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400495}
496
497static void
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400498weston_wm_window_get_frame_size(struct weston_wm_window *window,
499 int *width, int *height)
500{
501 struct theme *t = window->wm->theme;
502
Kristian Høgsbergb810eb52013-02-12 20:07:05 -0500503 if (window->fullscreen) {
504 *width = window->width;
505 *height = window->height;
Dima Ryazanovcae1f0f2013-11-15 02:02:23 -0800506 } else if (window->decorate && window->frame) {
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -0500507 *width = frame_width(window->frame);
508 *height = frame_height(window->frame);
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400509 } else {
510 *width = window->width + t->margin * 2;
511 *height = window->height + t->margin * 2;
512 }
513}
514
515static void
516weston_wm_window_get_child_position(struct weston_wm_window *window,
517 int *x, int *y)
518{
519 struct theme *t = window->wm->theme;
520
Kristian Høgsbergb810eb52013-02-12 20:07:05 -0500521 if (window->fullscreen) {
522 *x = 0;
523 *y = 0;
Dima Ryazanovcae1f0f2013-11-15 02:02:23 -0800524 } else if (window->decorate && window->frame) {
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -0500525 frame_interior(window->frame, x, y, NULL, NULL);
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400526 } else {
527 *x = t->margin;
528 *y = t->margin;
529 }
530}
Kristian Høgsbergeaee7842012-05-22 10:04:20 -0400531
532static void
Kristian Høgsbergb810eb52013-02-12 20:07:05 -0500533weston_wm_window_send_configure_notify(struct weston_wm_window *window)
534{
535 xcb_configure_notify_event_t configure_notify;
536 struct weston_wm *wm = window->wm;
537 int x, y;
538
539 weston_wm_window_get_child_position(window, &x, &y);
540 configure_notify.response_type = XCB_CONFIGURE_NOTIFY;
541 configure_notify.pad0 = 0;
542 configure_notify.event = window->id;
543 configure_notify.window = window->id;
544 configure_notify.above_sibling = XCB_WINDOW_NONE;
545 configure_notify.x = x;
546 configure_notify.y = y;
547 configure_notify.width = window->width;
548 configure_notify.height = window->height;
549 configure_notify.border_width = 0;
550 configure_notify.override_redirect = 0;
551 configure_notify.pad1 = 0;
552
553 xcb_send_event(wm->conn, 0, window->id,
554 XCB_EVENT_MASK_STRUCTURE_NOTIFY,
555 (char *) &configure_notify);
556}
557
558static void
Kristian Høgsbergeaee7842012-05-22 10:04:20 -0400559weston_wm_handle_configure_request(struct weston_wm *wm, xcb_generic_event_t *event)
560{
561 xcb_configure_request_event_t *configure_request =
562 (xcb_configure_request_event_t *) event;
563 struct weston_wm_window *window;
564 uint32_t mask, values[16];
565 int x, y, width, height, i = 0;
566
Kristian Høgsberg082d58c2013-06-18 01:00:27 -0400567 wm_log("XCB_CONFIGURE_REQUEST (window %d) %d,%d @ %dx%d\n",
568 configure_request->window,
569 configure_request->x, configure_request->y,
570 configure_request->width, configure_request->height);
Kristian Høgsbergeaee7842012-05-22 10:04:20 -0400571
572 window = hash_table_lookup(wm->window_hash, configure_request->window);
573
Kristian Høgsbergb810eb52013-02-12 20:07:05 -0500574 if (window->fullscreen) {
575 weston_wm_window_send_configure_notify(window);
576 return;
577 }
578
Kristian Høgsbergeaee7842012-05-22 10:04:20 -0400579 if (configure_request->value_mask & XCB_CONFIG_WINDOW_WIDTH)
580 window->width = configure_request->width;
581 if (configure_request->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
582 window->height = configure_request->height;
583
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -0500584 if (window->frame)
585 frame_resize_inside(window->frame, window->width, window->height);
586
Kristian Høgsbergeaee7842012-05-22 10:04:20 -0400587 weston_wm_window_get_child_position(window, &x, &y);
588 values[i++] = x;
589 values[i++] = y;
590 values[i++] = window->width;
591 values[i++] = window->height;
592 values[i++] = 0;
593 mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
594 XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT |
595 XCB_CONFIG_WINDOW_BORDER_WIDTH;
596 if (configure_request->value_mask & XCB_CONFIG_WINDOW_SIBLING) {
597 values[i++] = configure_request->sibling;
598 mask |= XCB_CONFIG_WINDOW_SIBLING;
599 }
600 if (configure_request->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) {
601 values[i++] = configure_request->stack_mode;
602 mask |= XCB_CONFIG_WINDOW_STACK_MODE;
603 }
604
605 xcb_configure_window(wm->conn, window->id, mask, values);
606
607 weston_wm_window_get_frame_size(window, &width, &height);
608 values[0] = width;
609 values[1] = height;
610 mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
611 xcb_configure_window(wm->conn, window->frame_id, mask, values);
612
613 weston_wm_window_schedule_repaint(window);
614}
615
Kristian Høgsberg00db2ee2013-07-04 02:29:32 -0400616static int
617our_resource(struct weston_wm *wm, uint32_t id)
618{
619 const xcb_setup_t *setup;
620
621 setup = xcb_get_setup(wm->conn);
622
623 return (id & ~setup->resource_id_mask) == setup->resource_id_base;
624}
625
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400626static void
627weston_wm_handle_configure_notify(struct weston_wm *wm, xcb_generic_event_t *event)
628{
629 xcb_configure_notify_event_t *configure_notify =
630 (xcb_configure_notify_event_t *) event;
631 struct weston_wm_window *window;
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400632
Kristian Høgsberg00db2ee2013-07-04 02:29:32 -0400633 wm_log("XCB_CONFIGURE_NOTIFY (window %d) %d,%d @ %dx%d\n",
Kristian Høgsberg082d58c2013-06-18 01:00:27 -0400634 configure_notify->window,
635 configure_notify->x, configure_notify->y,
636 configure_notify->width, configure_notify->height);
Tiago Vignattie66fcee2012-07-20 23:09:54 +0300637
Kristian Høgsberg00db2ee2013-07-04 02:29:32 -0400638 window = hash_table_lookup(wm->window_hash, configure_notify->window);
Kristian Høgsberg122877d2013-08-22 16:18:17 -0700639 window->x = configure_notify->x;
640 window->y = configure_notify->y;
Kristian Høgsberg1b6fed42013-08-31 00:00:57 -0700641 if (window->override_redirect) {
642 window->width = configure_notify->width;
643 window->height = configure_notify->height;
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -0500644 if (window->frame)
645 frame_resize_inside(window->frame,
646 window->width, window->height);
Kristian Høgsberg1b6fed42013-08-31 00:00:57 -0700647 }
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400648}
649
650static void
Tiago Vignatti0d20d7c2012-09-27 17:48:37 +0300651weston_wm_kill_client(struct wl_listener *listener, void *data)
652{
653 struct weston_surface *surface = data;
654 struct weston_wm_window *window = get_wm_window(surface);
655 char name[1024];
656
657 if (!window)
658 return;
659
660 gethostname(name, 1024);
661
662 /* this is only one heuristic to guess the PID of a client is valid,
663 * assuming it's compliant with icccm and ewmh. Non-compliants and
664 * remote applications of course fail. */
665 if (!strcmp(window->machine, name) && window->pid != 0)
666 kill(window->pid, SIGKILL);
667}
668
669static void
Kristian Høgsberg757d8af2014-03-17 22:33:29 -0700670weston_wm_create_surface(struct wl_listener *listener, void *data)
671{
672 struct weston_surface *surface = data;
673 struct weston_wm *wm =
674 container_of(listener,
675 struct weston_wm, create_surface_listener);
676 struct weston_wm_window *window;
677
678 if (wl_resource_get_client(surface->resource) != wm->server->client)
679 return;
680
681 wl_list_for_each(window, &wm->unpaired_window_list, link)
682 if (window->surface_id ==
683 wl_resource_get_id(surface->resource)) {
684 xserver_map_shell_surface(window, surface);
685 break;
686 }
687}
688
689static void
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400690weston_wm_window_activate(struct wl_listener *listener, void *data)
691{
692 struct weston_surface *surface = data;
Giulio Camuffo9f42e502013-08-13 11:42:02 +0200693 struct weston_wm_window *window = NULL;
Scott Moreau85ecac02012-05-21 15:49:14 -0600694 struct weston_wm *wm =
695 container_of(listener, struct weston_wm, activate_listener);
696 xcb_client_message_event_t client_message;
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400697
Giulio Camuffo9f42e502013-08-13 11:42:02 +0200698 if (surface) {
699 window = get_wm_window(surface);
700 }
701
Scott Moreau85ecac02012-05-21 15:49:14 -0600702 if (window) {
703 client_message.response_type = XCB_CLIENT_MESSAGE;
704 client_message.format = 32;
705 client_message.window = window->id;
706 client_message.type = wm->atom.wm_protocols;
707 client_message.data.data32[0] = wm->atom.wm_take_focus;
708 client_message.data.data32[1] = XCB_TIME_CURRENT_TIME;
709
710 xcb_send_event(wm->conn, 0, window->id,
711 XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
712 (char *) &client_message);
713
714 xcb_set_input_focus (wm->conn, XCB_INPUT_FOCUS_POINTER_ROOT,
715 window->id, XCB_TIME_CURRENT_TIME);
716 } else {
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400717 xcb_set_input_focus (wm->conn,
718 XCB_INPUT_FOCUS_POINTER_ROOT,
719 XCB_NONE,
720 XCB_TIME_CURRENT_TIME);
Scott Moreau85ecac02012-05-21 15:49:14 -0600721 }
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400722
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -0500723 if (wm->focus_window) {
Dima Ryazanovb03b87f2013-11-15 02:01:19 -0800724 if (wm->focus_window->frame)
725 frame_unset_flag(wm->focus_window->frame, FRAME_FLAG_ACTIVE);
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400726 weston_wm_window_schedule_repaint(wm->focus_window);
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -0500727 }
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400728 wm->focus_window = window;
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -0500729 if (wm->focus_window) {
Dima Ryazanovb03b87f2013-11-15 02:01:19 -0800730 if (wm->focus_window->frame)
731 frame_set_flag(wm->focus_window->frame, FRAME_FLAG_ACTIVE);
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400732 weston_wm_window_schedule_repaint(wm->focus_window);
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -0500733 }
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400734}
735
Tiago Vignattifb2adba2013-06-12 15:43:21 -0300736static void
737weston_wm_window_transform(struct wl_listener *listener, void *data)
738{
739 struct weston_surface *surface = data;
740 struct weston_wm_window *window = get_wm_window(surface);
741 struct weston_wm *wm =
742 container_of(listener, struct weston_wm, transform_listener);
Tiago Vignattifb2adba2013-06-12 15:43:21 -0300743 uint32_t mask, values[2];
Tiago Vignattifb2adba2013-06-12 15:43:21 -0300744
745 if (!window || !wm)
746 return;
747
Jason Ekstranda7af7042013-10-12 22:38:11 -0500748 if (!window->view || !weston_view_is_mapped(window->view))
Tiago Vignattifb2adba2013-06-12 15:43:21 -0300749 return;
750
Jason Ekstranda7af7042013-10-12 22:38:11 -0500751 if (window->x != window->view->geometry.x ||
752 window->y != window->view->geometry.y) {
753 values[0] = window->view->geometry.x;
754 values[1] = window->view->geometry.y;
Kristian Høgsberge89a8b62013-08-22 16:20:44 -0700755 mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y;
Tiago Vignattifb2adba2013-06-12 15:43:21 -0300756
Kristian Høgsberge89a8b62013-08-22 16:20:44 -0700757 xcb_configure_window(wm->conn, window->frame_id, mask, values);
758 xcb_flush(wm->conn);
759 }
Tiago Vignattifb2adba2013-06-12 15:43:21 -0300760}
761
Kristian Høgsberga6d9a5e2012-05-30 12:15:44 -0400762#define ICCCM_WITHDRAWN_STATE 0
763#define ICCCM_NORMAL_STATE 1
764#define ICCCM_ICONIC_STATE 3
765
766static void
Kristian Høgsbergb810eb52013-02-12 20:07:05 -0500767weston_wm_window_set_wm_state(struct weston_wm_window *window, int32_t state)
Kristian Høgsberga6d9a5e2012-05-30 12:15:44 -0400768{
769 struct weston_wm *wm = window->wm;
770 uint32_t property[2];
771
772 property[0] = state;
773 property[1] = XCB_WINDOW_NONE;
774
775 xcb_change_property(wm->conn,
776 XCB_PROP_MODE_REPLACE,
777 window->id,
778 wm->atom.wm_state,
779 wm->atom.wm_state,
780 32, /* format */
781 2, property);
782}
783
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400784static void
Kristian Høgsbergb810eb52013-02-12 20:07:05 -0500785weston_wm_window_set_net_wm_state(struct weston_wm_window *window)
786{
787 struct weston_wm *wm = window->wm;
788 uint32_t property[1];
789 int i;
790
791 i = 0;
792 if (window->fullscreen)
793 property[i++] = wm->atom.net_wm_state_fullscreen;
794
795 xcb_change_property(wm->conn,
796 XCB_PROP_MODE_REPLACE,
797 window->id,
798 wm->atom.net_wm_state,
799 XCB_ATOM_ATOM,
800 32, /* format */
801 i, property);
802}
803
804static void
Kristian Høgsberg318ea372013-09-03 16:19:18 -0700805weston_wm_window_create_frame(struct weston_wm_window *window)
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400806{
Kristian Høgsberg318ea372013-09-03 16:19:18 -0700807 struct weston_wm *wm = window->wm;
Kristian Høgsbergf9187192013-05-02 13:43:24 -0400808 uint32_t values[3];
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400809 int x, y, width, height;
810
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -0500811 window->frame = frame_create(window->wm->theme,
812 window->width, window->height,
813 FRAME_BUTTON_CLOSE, window->name);
814 frame_resize_inside(window->frame, window->width, window->height);
815
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400816 weston_wm_window_get_frame_size(window, &width, &height);
817 weston_wm_window_get_child_position(window, &x, &y);
818
Kristian Høgsbergf9187192013-05-02 13:43:24 -0400819 values[0] = wm->screen->black_pixel;
820 values[1] =
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400821 XCB_EVENT_MASK_KEY_PRESS |
822 XCB_EVENT_MASK_KEY_RELEASE |
823 XCB_EVENT_MASK_BUTTON_PRESS |
824 XCB_EVENT_MASK_BUTTON_RELEASE |
Tiago Vignatti236b48d2012-07-16 12:09:19 -0400825 XCB_EVENT_MASK_POINTER_MOTION |
826 XCB_EVENT_MASK_ENTER_WINDOW |
827 XCB_EVENT_MASK_LEAVE_WINDOW |
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400828 XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
Kristian Høgsberg44c20132012-05-30 10:09:21 -0400829 XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT;
Kristian Høgsbergf9187192013-05-02 13:43:24 -0400830 values[2] = wm->colormap;
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400831
832 window->frame_id = xcb_generate_id(wm->conn);
833 xcb_create_window(wm->conn,
Kristian Høgsbergf9187192013-05-02 13:43:24 -0400834 32,
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400835 window->frame_id,
836 wm->screen->root,
837 0, 0,
838 width, height,
839 0,
840 XCB_WINDOW_CLASS_INPUT_OUTPUT,
Kristian Høgsbergf9187192013-05-02 13:43:24 -0400841 wm->visual_id,
842 XCB_CW_BORDER_PIXEL |
843 XCB_CW_EVENT_MASK |
844 XCB_CW_COLORMAP, values);
845
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400846 xcb_reparent_window(wm->conn, window->id, window->frame_id, x, y);
847
848 values[0] = 0;
849 xcb_configure_window(wm->conn, window->id,
850 XCB_CONFIG_WINDOW_BORDER_WIDTH, values);
851
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400852 window->cairo_surface =
853 cairo_xcb_surface_create_with_xrender_format(wm->conn,
854 wm->screen,
855 window->frame_id,
Kristian Høgsbergf9187192013-05-02 13:43:24 -0400856 &wm->format_rgba,
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400857 width, height);
858
859 hash_table_insert(wm->window_hash, window->frame_id, window);
860}
861
862static void
Kristian Høgsberg318ea372013-09-03 16:19:18 -0700863weston_wm_handle_map_request(struct weston_wm *wm, xcb_generic_event_t *event)
864{
865 xcb_map_request_event_t *map_request =
866 (xcb_map_request_event_t *) event;
867 struct weston_wm_window *window;
868
869 if (our_resource(wm, map_request->window)) {
870 wm_log("XCB_MAP_REQUEST (window %d, ours)\n",
871 map_request->window);
872 return;
873 }
874
875 window = hash_table_lookup(wm->window_hash, map_request->window);
876
877 weston_wm_window_read_properties(window);
878
879 if (window->frame_id == XCB_WINDOW_NONE)
880 weston_wm_window_create_frame(window);
881
882 wm_log("XCB_MAP_REQUEST (window %d, %p, frame %d)\n",
883 window->id, window, window->frame_id);
884
885 weston_wm_window_set_wm_state(window, ICCCM_NORMAL_STATE);
886 weston_wm_window_set_net_wm_state(window);
887
888 xcb_map_window(wm->conn, map_request->window);
889 xcb_map_window(wm->conn, window->frame_id);
890}
891
892static void
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400893weston_wm_handle_map_notify(struct weston_wm *wm, xcb_generic_event_t *event)
894{
895 xcb_map_notify_event_t *map_notify = (xcb_map_notify_event_t *) event;
896
897 if (our_resource(wm, map_notify->window)) {
Kristian Høgsberg082d58c2013-06-18 01:00:27 -0400898 wm_log("XCB_MAP_NOTIFY (window %d, ours)\n",
899 map_notify->window);
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400900 return;
901 }
902
Kristian Høgsberg082d58c2013-06-18 01:00:27 -0400903 wm_log("XCB_MAP_NOTIFY (window %d)\n", map_notify->window);
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400904}
905
906static void
Kristian Høgsberg194ea542012-05-30 10:05:41 -0400907weston_wm_handle_unmap_notify(struct weston_wm *wm, xcb_generic_event_t *event)
908{
909 xcb_unmap_notify_event_t *unmap_notify =
910 (xcb_unmap_notify_event_t *) event;
911 struct weston_wm_window *window;
912
Kristian Høgsberg082d58c2013-06-18 01:00:27 -0400913 wm_log("XCB_UNMAP_NOTIFY (window %d, event %d%s)\n",
914 unmap_notify->window,
915 unmap_notify->event,
916 our_resource(wm, unmap_notify->window) ? ", ours" : "");
Kristian Høgsberg194ea542012-05-30 10:05:41 -0400917
918 if (our_resource(wm, unmap_notify->window))
919 return;
920
MoD31700122013-06-11 19:58:55 -0500921 if (unmap_notify->response_type & SEND_EVENT_MASK)
Kristian Høgsbergd64bdf42012-05-31 10:33:43 -0400922 /* We just ignore the ICCCM 4.1.4 synthetic unmap notify
923 * as it may come in after we've destroyed the window. */
Kristian Høgsbergf197e9f2012-05-30 11:46:29 -0400924 return;
Kristian Høgsbergf197e9f2012-05-30 11:46:29 -0400925
Kristian Høgsbergd64bdf42012-05-31 10:33:43 -0400926 window = hash_table_lookup(wm->window_hash, unmap_notify->window);
Kristian Høgsberg194ea542012-05-30 10:05:41 -0400927 if (wm->focus_window == window)
928 wm->focus_window = NULL;
Kristian Høgsberg194ea542012-05-30 10:05:41 -0400929 if (window->surface)
930 wl_list_remove(&window->surface_destroy_listener.link);
931 window->surface = NULL;
Giulio Camuffo85739ea2013-09-17 16:43:45 +0200932 window->shsurf = NULL;
Dima Ryazanove5a32082013-11-15 02:01:18 -0800933 window->view = NULL;
Kristian Høgsbergab6d6672013-09-03 16:38:51 -0700934 xcb_unmap_window(wm->conn, window->frame_id);
Kristian Høgsberg194ea542012-05-30 10:05:41 -0400935}
936
937static void
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400938weston_wm_window_draw_decoration(void *data)
939{
940 struct weston_wm_window *window = data;
941 struct weston_wm *wm = window->wm;
942 struct theme *t = wm->theme;
943 cairo_t *cr;
944 int x, y, width, height;
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -0500945 int32_t input_x, input_y, input_w, input_h;
946
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400947 uint32_t flags = 0;
948
949 weston_wm_window_read_properties(window);
950
951 window->repaint_source = NULL;
952
953 weston_wm_window_get_frame_size(window, &width, &height);
954 weston_wm_window_get_child_position(window, &x, &y);
955
956 cairo_xcb_surface_set_size(window->cairo_surface, width, height);
957 cr = cairo_create(window->cairo_surface);
958
Kristian Høgsbergb810eb52013-02-12 20:07:05 -0500959 if (window->fullscreen) {
960 /* nothing */
961 } else if (window->decorate) {
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400962 if (wm->focus_window == window)
963 flags |= THEME_FRAME_ACTIVE;
964
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -0500965 frame_repaint(window->frame, cr);
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400966 } else {
967 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
968 cairo_set_source_rgba(cr, 0, 0, 0, 0);
969 cairo_paint(cr);
970
971 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
972 cairo_set_source_rgba(cr, 0, 0, 0, 0.45);
973 tile_mask(cr, t->shadow, 2, 2, width + 8, height + 8, 64, 64);
974 }
975
976 cairo_destroy(cr);
977
978 if (window->surface) {
Scott Moreau76d8fc82012-11-22 15:35:13 -0700979 pixman_region32_fini(&window->surface->pending.opaque);
MoD384a11a2013-06-22 11:04:21 -0500980 if(window->has_alpha) {
981 pixman_region32_init(&window->surface->pending.opaque);
982 } else {
983 /* We leave an extra pixel around the X window area to
984 * make sure we don't sample from the undefined alpha
985 * channel when filtering. */
986 pixman_region32_init_rect(&window->surface->pending.opaque,
987 x - 1, y - 1,
988 window->width + 2,
989 window->height + 2);
990 }
Jason Ekstranda7af7042013-10-12 22:38:11 -0500991 if (window->view)
992 weston_view_geometry_dirty(window->view);
Kristian Høgsberg380deee2012-05-21 17:12:41 -0400993
Kristian Høgsberg81585e92013-02-14 22:01:58 -0500994 pixman_region32_fini(&window->surface->pending.input);
Kristian Høgsberg1d75c7d2013-10-30 23:46:08 -0700995
996 if (window->fullscreen) {
997 input_x = 0;
998 input_y = 0;
999 input_w = window->width;
1000 input_h = window->height;
1001 } else if (window->decorate) {
1002 frame_input_rect(window->frame, &input_x, &input_y,
1003 &input_w, &input_h);
1004 }
1005
Kristian Høgsbergd8b617d2013-02-14 21:56:32 -05001006 pixman_region32_init_rect(&window->surface->pending.input,
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001007 input_x, input_y, input_w, input_h);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001008 }
1009}
1010
1011static void
1012weston_wm_window_schedule_repaint(struct weston_wm_window *window)
1013{
1014 struct weston_wm *wm = window->wm;
Pekka Paalanen4f9c07b2012-09-03 16:48:41 +03001015 int width, height;
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001016
Kristian Høgsbergc4063f32012-07-22 15:32:45 -04001017 if (window->frame_id == XCB_WINDOW_NONE) {
1018 if (window->surface != NULL) {
Pekka Paalanen4f9c07b2012-09-03 16:48:41 +03001019 weston_wm_window_get_frame_size(window, &width, &height);
Scott Moreau76d8fc82012-11-22 15:35:13 -07001020 pixman_region32_fini(&window->surface->pending.opaque);
MoD384a11a2013-06-22 11:04:21 -05001021 if(window->has_alpha) {
1022 pixman_region32_init(&window->surface->pending.opaque);
1023 } else {
1024 pixman_region32_init_rect(&window->surface->pending.opaque, 0, 0,
1025 width, height);
1026 }
Jason Ekstranda7af7042013-10-12 22:38:11 -05001027 if (window->view)
1028 weston_view_geometry_dirty(window->view);
Kristian Høgsbergc4063f32012-07-22 15:32:45 -04001029 }
1030 return;
1031 }
1032
1033 if (window->repaint_source)
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001034 return;
1035
1036 window->repaint_source =
1037 wl_event_loop_add_idle(wm->server->loop,
1038 weston_wm_window_draw_decoration,
1039 window);
1040}
1041
1042static void
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001043weston_wm_handle_property_notify(struct weston_wm *wm, xcb_generic_event_t *event)
1044{
1045 xcb_property_notify_event_t *property_notify =
1046 (xcb_property_notify_event_t *) event;
1047 struct weston_wm_window *window;
1048
1049 window = hash_table_lookup(wm->window_hash, property_notify->window);
Rob Bradfordaa521bd2013-01-10 19:48:57 +00001050 if (!window)
1051 return;
1052
1053 window->properties_dirty = 1;
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001054
Kristian Høgsberg082d58c2013-06-18 01:00:27 -04001055 wm_log("XCB_PROPERTY_NOTIFY: window %d, ", property_notify->window);
Kristian Høgsberge244cb02012-05-30 11:34:35 -04001056 if (property_notify->state == XCB_PROPERTY_DELETE)
Kristian Høgsberg082d58c2013-06-18 01:00:27 -04001057 wm_log("deleted\n");
Kristian Høgsberge244cb02012-05-30 11:34:35 -04001058 else
1059 read_and_dump_property(wm, property_notify->window,
1060 property_notify->atom);
Kristian Høgsberg0273b572012-05-30 09:58:02 -04001061
1062 if (property_notify->atom == wm->atom.net_wm_name ||
1063 property_notify->atom == XCB_ATOM_WM_NAME)
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001064 weston_wm_window_schedule_repaint(window);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001065}
1066
1067static void
Kristian Høgsberg029539b2012-05-30 11:28:24 -04001068weston_wm_window_create(struct weston_wm *wm,
Giulio Camuffoca43f092013-09-11 17:49:13 +02001069 xcb_window_t id, int width, int height, int x, int y, int override)
Kristian Høgsberg029539b2012-05-30 11:28:24 -04001070{
1071 struct weston_wm_window *window;
1072 uint32_t values[1];
MoD384a11a2013-06-22 11:04:21 -05001073 xcb_get_geometry_cookie_t geometry_cookie;
1074 xcb_get_geometry_reply_t *geometry_reply;
Kristian Høgsberg029539b2012-05-30 11:28:24 -04001075
Peter Huttererf3d62272013-08-08 11:57:05 +10001076 window = zalloc(sizeof *window);
Kristian Høgsberg029539b2012-05-30 11:28:24 -04001077 if (window == NULL) {
Kristian Høgsberg082d58c2013-06-18 01:00:27 -04001078 wm_log("failed to allocate window\n");
Kristian Høgsberg029539b2012-05-30 11:28:24 -04001079 return;
1080 }
1081
MoD384a11a2013-06-22 11:04:21 -05001082 geometry_cookie = xcb_get_geometry(wm->conn, id);
1083
Kristian Høgsberg029539b2012-05-30 11:28:24 -04001084 values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE;
1085 xcb_change_window_attributes(wm->conn, id, XCB_CW_EVENT_MASK, values);
1086
Kristian Høgsberg029539b2012-05-30 11:28:24 -04001087 window->wm = wm;
1088 window->id = id;
1089 window->properties_dirty = 1;
Tiago Vignatti771241e2012-06-04 20:01:45 +03001090 window->override_redirect = override;
Kristian Høgsberg029539b2012-05-30 11:28:24 -04001091 window->width = width;
1092 window->height = height;
Giulio Camuffoca43f092013-09-11 17:49:13 +02001093 window->x = x;
1094 window->y = y;
Kristian Høgsberg029539b2012-05-30 11:28:24 -04001095
MoD384a11a2013-06-22 11:04:21 -05001096 geometry_reply = xcb_get_geometry_reply(wm->conn, geometry_cookie, NULL);
1097 /* technically we should use XRender and check the visual format's
1098 alpha_mask, but checking depth is simpler and works in all known cases */
1099 if(geometry_reply != NULL)
1100 window->has_alpha = geometry_reply->depth == 32;
1101 free(geometry_reply);
1102
Kristian Høgsberg029539b2012-05-30 11:28:24 -04001103 hash_table_insert(wm->window_hash, id, window);
1104}
1105
1106static void
1107weston_wm_window_destroy(struct weston_wm_window *window)
1108{
Kristian Høgsbergab6d6672013-09-03 16:38:51 -07001109 struct weston_wm *wm = window->wm;
1110
1111 if (window->repaint_source)
1112 wl_event_source_remove(window->repaint_source);
1113 if (window->cairo_surface)
1114 cairo_surface_destroy(window->cairo_surface);
1115
1116 if (window->frame_id) {
1117 xcb_reparent_window(wm->conn, window->id, wm->wm_window, 0, 0);
1118 xcb_destroy_window(wm->conn, window->frame_id);
1119 weston_wm_window_set_wm_state(window, ICCCM_WITHDRAWN_STATE);
1120 hash_table_remove(wm->window_hash, window->frame_id);
1121 window->frame_id = XCB_WINDOW_NONE;
1122 }
1123
Kristian Høgsberg029539b2012-05-30 11:28:24 -04001124 hash_table_remove(window->wm->window_hash, window->id);
1125 free(window);
1126}
1127
1128static void
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001129weston_wm_handle_create_notify(struct weston_wm *wm, xcb_generic_event_t *event)
1130{
1131 xcb_create_notify_event_t *create_notify =
1132 (xcb_create_notify_event_t *) event;
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001133
Kristian Høgsberg082d58c2013-06-18 01:00:27 -04001134 wm_log("XCB_CREATE_NOTIFY (window %d, width %d, height %d%s%s)\n",
1135 create_notify->window,
1136 create_notify->width, create_notify->height,
1137 create_notify->override_redirect ? ", override" : "",
1138 our_resource(wm, create_notify->window) ? ", ours" : "");
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001139
1140 if (our_resource(wm, create_notify->window))
1141 return;
1142
Kristian Høgsberg029539b2012-05-30 11:28:24 -04001143 weston_wm_window_create(wm, create_notify->window,
Tiago Vignatti771241e2012-06-04 20:01:45 +03001144 create_notify->width, create_notify->height,
Giulio Camuffoca43f092013-09-11 17:49:13 +02001145 create_notify->x, create_notify->y,
Tiago Vignatti771241e2012-06-04 20:01:45 +03001146 create_notify->override_redirect);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001147}
1148
1149static void
1150weston_wm_handle_destroy_notify(struct weston_wm *wm, xcb_generic_event_t *event)
1151{
1152 xcb_destroy_notify_event_t *destroy_notify =
1153 (xcb_destroy_notify_event_t *) event;
1154 struct weston_wm_window *window;
1155
Kristian Høgsberg082d58c2013-06-18 01:00:27 -04001156 wm_log("XCB_DESTROY_NOTIFY, win %d, event %d%s\n",
1157 destroy_notify->window,
1158 destroy_notify->event,
1159 our_resource(wm, destroy_notify->window) ? ", ours" : "");
Kristian Høgsberg194ea542012-05-30 10:05:41 -04001160
1161 if (our_resource(wm, destroy_notify->window))
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001162 return;
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001163
1164 window = hash_table_lookup(wm->window_hash, destroy_notify->window);
Kristian Høgsberg029539b2012-05-30 11:28:24 -04001165 weston_wm_window_destroy(window);
1166}
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001167
Kristian Høgsberg029539b2012-05-30 11:28:24 -04001168static void
1169weston_wm_handle_reparent_notify(struct weston_wm *wm, xcb_generic_event_t *event)
1170{
1171 xcb_reparent_notify_event_t *reparent_notify =
1172 (xcb_reparent_notify_event_t *) event;
1173 struct weston_wm_window *window;
Kristian Høgsbergc9571fb2012-05-29 15:35:29 -04001174
Kristian Høgsberg082d58c2013-06-18 01:00:27 -04001175 wm_log("XCB_REPARENT_NOTIFY (window %d, parent %d, event %d)\n",
1176 reparent_notify->window,
1177 reparent_notify->parent,
1178 reparent_notify->event);
Kristian Høgsberg029539b2012-05-30 11:28:24 -04001179
1180 if (reparent_notify->parent == wm->screen->root) {
Tiago Vignatti771241e2012-06-04 20:01:45 +03001181 weston_wm_window_create(wm, reparent_notify->window, 10, 10,
Giulio Camuffoca43f092013-09-11 17:49:13 +02001182 reparent_notify->x, reparent_notify->y,
Tiago Vignatti771241e2012-06-04 20:01:45 +03001183 reparent_notify->override_redirect);
Kristian Høgsberg029539b2012-05-30 11:28:24 -04001184 } else if (!our_resource(wm, reparent_notify->parent)) {
1185 window = hash_table_lookup(wm->window_hash,
1186 reparent_notify->window);
1187 weston_wm_window_destroy(window);
1188 }
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001189}
1190
Kristian Høgsberg5ba31892012-08-10 10:06:59 -04001191struct weston_seat *
1192weston_wm_pick_seat(struct weston_wm *wm)
1193{
1194 return container_of(wm->server->compositor->seat_list.next,
1195 struct weston_seat, link);
1196}
1197
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001198static void
Kristian Høgsberge68fd102012-05-22 17:09:40 -04001199weston_wm_window_handle_moveresize(struct weston_wm_window *window,
1200 xcb_client_message_event_t *client_message)
1201{
1202 static const int map[] = {
1203 THEME_LOCATION_RESIZING_TOP_LEFT,
1204 THEME_LOCATION_RESIZING_TOP,
1205 THEME_LOCATION_RESIZING_TOP_RIGHT,
1206 THEME_LOCATION_RESIZING_RIGHT,
1207 THEME_LOCATION_RESIZING_BOTTOM_RIGHT,
1208 THEME_LOCATION_RESIZING_BOTTOM,
1209 THEME_LOCATION_RESIZING_BOTTOM_LEFT,
1210 THEME_LOCATION_RESIZING_LEFT
1211 };
1212
1213 struct weston_wm *wm = window->wm;
Kristian Høgsberg5ba31892012-08-10 10:06:59 -04001214 struct weston_seat *seat = weston_wm_pick_seat(wm);
Kristian Høgsberge68fd102012-05-22 17:09:40 -04001215 int detail;
1216 struct weston_shell_interface *shell_interface =
1217 &wm->server->compositor->shell_interface;
1218
Jason Ekstranda7af7042013-10-12 22:38:11 -05001219 if (seat->pointer->button_count != 1 || !window->view
1220 || seat->pointer->focus != window->view)
Kristian Høgsberge68fd102012-05-22 17:09:40 -04001221 return;
1222
1223 detail = client_message->data.data32[2];
1224 switch (detail) {
1225 case _NET_WM_MOVERESIZE_MOVE:
1226 shell_interface->move(window->shsurf, seat);
1227 break;
1228 case _NET_WM_MOVERESIZE_SIZE_TOPLEFT:
1229 case _NET_WM_MOVERESIZE_SIZE_TOP:
1230 case _NET_WM_MOVERESIZE_SIZE_TOPRIGHT:
1231 case _NET_WM_MOVERESIZE_SIZE_RIGHT:
1232 case _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT:
1233 case _NET_WM_MOVERESIZE_SIZE_BOTTOM:
1234 case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT:
1235 case _NET_WM_MOVERESIZE_SIZE_LEFT:
1236 shell_interface->resize(window->shsurf, seat, map[detail]);
1237 break;
1238 case _NET_WM_MOVERESIZE_CANCEL:
1239 break;
1240 }
1241}
1242
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05001243#define _NET_WM_STATE_REMOVE 0
1244#define _NET_WM_STATE_ADD 1
1245#define _NET_WM_STATE_TOGGLE 2
1246
1247static int
1248update_state(int action, int *state)
1249{
1250 int new_state, changed;
1251
1252 switch (action) {
1253 case _NET_WM_STATE_REMOVE:
1254 new_state = 0;
1255 break;
1256 case _NET_WM_STATE_ADD:
1257 new_state = 1;
1258 break;
1259 case _NET_WM_STATE_TOGGLE:
1260 new_state = !*state;
1261 break;
1262 default:
1263 return 0;
1264 }
1265
1266 changed = (*state != new_state);
1267 *state = new_state;
1268
1269 return changed;
1270}
1271
1272static void
1273weston_wm_window_configure(void *data);
1274
1275static void
1276weston_wm_window_handle_state(struct weston_wm_window *window,
1277 xcb_client_message_event_t *client_message)
1278{
1279 struct weston_wm *wm = window->wm;
1280 struct weston_shell_interface *shell_interface =
1281 &wm->server->compositor->shell_interface;
1282 uint32_t action, property;
1283
1284 action = client_message->data.data32[0];
1285 property = client_message->data.data32[1];
1286
1287 if (property == wm->atom.net_wm_state_fullscreen &&
1288 update_state(action, &window->fullscreen)) {
1289 weston_wm_window_set_net_wm_state(window);
1290 if (window->fullscreen) {
1291 window->saved_width = window->width;
1292 window->saved_height = window->height;
Kristian Høgsberg762b1662013-02-21 20:18:37 -05001293
1294 if (window->shsurf)
1295 shell_interface->set_fullscreen(window->shsurf,
1296 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
1297 0, NULL);
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05001298 } else {
1299 shell_interface->set_toplevel(window->shsurf);
1300 window->width = window->saved_width;
1301 window->height = window->saved_height;
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001302 if (window->frame)
1303 frame_resize_inside(window->frame,
1304 window->width,
1305 window->height);
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05001306 weston_wm_window_configure(window);
1307 }
1308 }
1309}
1310
Kristian Høgsberge68fd102012-05-22 17:09:40 -04001311static void
Kristian Høgsberg757d8af2014-03-17 22:33:29 -07001312surface_destroy(struct wl_listener *listener, void *data)
1313{
1314 struct weston_wm_window *window =
1315 container_of(listener,
1316 struct weston_wm_window, surface_destroy_listener);
1317
1318 wm_log("surface for xid %d destroyed\n", window->id);
1319
1320 /* This should have been freed by the shell.
1321 * Don't try to use it later. */
1322 window->shsurf = NULL;
1323 window->surface = NULL;
1324 window->view = NULL;
1325}
1326
1327static void
1328weston_wm_window_handle_surface_id(struct weston_wm_window *window,
1329 xcb_client_message_event_t *client_message)
1330{
1331 struct weston_wm *wm = window->wm;
1332 struct wl_resource *resource;
1333
1334 if (window->surface_id != 0) {
1335 wm_log("already have surface id for window %d\n", window->id);
1336 return;
1337 }
1338
1339 /* Xwayland will send the wayland requests to create the
1340 * wl_surface before sending this client message. Even so, we
1341 * can end up handling the X event before the wayland requests
1342 * and thus when we try to look up the surface ID, the surface
1343 * hasn't been created yet. In that case put the window on
1344 * the unpaired window list and continue when the surface gets
1345 * created. */
1346 window->surface_id = client_message->data.data32[0];
1347 resource = wl_client_get_object(wm->server->client,
1348 window->surface_id);
1349 if (resource)
1350 xserver_map_shell_surface(window,
1351 wl_resource_get_user_data(resource));
1352 else
1353 wl_list_insert(&wm->unpaired_window_list, &window->link);
1354}
1355
1356static void
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001357weston_wm_handle_client_message(struct weston_wm *wm,
1358 xcb_generic_event_t *event)
1359{
1360 xcb_client_message_event_t *client_message =
1361 (xcb_client_message_event_t *) event;
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001362 struct weston_wm_window *window;
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001363
1364 window = hash_table_lookup(wm->window_hash, client_message->window);
1365
Kristian Høgsberg082d58c2013-06-18 01:00:27 -04001366 wm_log("XCB_CLIENT_MESSAGE (%s %d %d %d %d %d win %d)\n",
1367 get_atom_name(wm->conn, client_message->type),
1368 client_message->data.data32[0],
1369 client_message->data.data32[1],
1370 client_message->data.data32[2],
1371 client_message->data.data32[3],
1372 client_message->data.data32[4],
1373 client_message->window);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001374
Kristian Høgsberge68fd102012-05-22 17:09:40 -04001375 if (client_message->type == wm->atom.net_wm_moveresize)
1376 weston_wm_window_handle_moveresize(window, client_message);
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05001377 else if (client_message->type == wm->atom.net_wm_state)
1378 weston_wm_window_handle_state(window, client_message);
Kristian Høgsberg757d8af2014-03-17 22:33:29 -07001379 else if (client_message->type == wm->atom.wl_surface_id)
1380 weston_wm_window_handle_surface_id(window, client_message);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001381}
1382
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001383enum cursor_type {
1384 XWM_CURSOR_TOP,
1385 XWM_CURSOR_BOTTOM,
1386 XWM_CURSOR_LEFT,
1387 XWM_CURSOR_RIGHT,
1388 XWM_CURSOR_TOP_LEFT,
1389 XWM_CURSOR_TOP_RIGHT,
1390 XWM_CURSOR_BOTTOM_LEFT,
1391 XWM_CURSOR_BOTTOM_RIGHT,
1392 XWM_CURSOR_LEFT_PTR,
1393};
1394
Giulio Camuffoa2df51c2013-09-18 15:20:04 +02001395/*
1396 * The following correspondences between file names and cursors was copied
1397 * from: https://bugs.kde.org/attachment.cgi?id=67313
1398 */
1399
1400static const char *bottom_left_corners[] = {
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001401 "bottom_left_corner",
Giulio Camuffoa2df51c2013-09-18 15:20:04 +02001402 "sw-resize",
1403 "size_bdiag"
1404};
1405
1406static const char *bottom_right_corners[] = {
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001407 "bottom_right_corner",
Giulio Camuffoa2df51c2013-09-18 15:20:04 +02001408 "se-resize",
1409 "size_fdiag"
1410};
1411
1412static const char *bottom_sides[] = {
1413 "bottom_side",
1414 "s-resize",
1415 "size_ver"
1416};
1417
1418static const char *left_ptrs[] = {
1419 "left_ptr",
1420 "default",
1421 "top_left_arrow",
1422 "left-arrow"
1423};
1424
1425static const char *left_sides[] = {
1426 "left_side",
1427 "w-resize",
1428 "size_hor"
1429};
1430
1431static const char *right_sides[] = {
1432 "right_side",
1433 "e-resize",
1434 "size_hor"
1435};
1436
1437static const char *top_left_corners[] = {
1438 "top_left_corner",
1439 "nw-resize",
1440 "size_fdiag"
1441};
1442
1443static const char *top_right_corners[] = {
1444 "top_right_corner",
1445 "ne-resize",
1446 "size_bdiag"
1447};
1448
1449static const char *top_sides[] = {
1450 "top_side",
1451 "n-resize",
1452 "size_ver"
1453};
1454
1455struct cursor_alternatives {
1456 const char **names;
1457 size_t count;
1458};
1459
1460static const struct cursor_alternatives cursors[] = {
1461 {top_sides, ARRAY_LENGTH(top_sides)},
1462 {bottom_sides, ARRAY_LENGTH(bottom_sides)},
1463 {left_sides, ARRAY_LENGTH(left_sides)},
1464 {right_sides, ARRAY_LENGTH(right_sides)},
1465 {top_left_corners, ARRAY_LENGTH(top_left_corners)},
1466 {top_right_corners, ARRAY_LENGTH(top_right_corners)},
1467 {bottom_left_corners, ARRAY_LENGTH(bottom_left_corners)},
1468 {bottom_right_corners, ARRAY_LENGTH(bottom_right_corners)},
1469 {left_ptrs, ARRAY_LENGTH(left_ptrs)},
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001470};
1471
1472static void
1473weston_wm_create_cursors(struct weston_wm *wm)
1474{
Giulio Camuffoa2df51c2013-09-18 15:20:04 +02001475 const char *name;
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001476 int i, count = ARRAY_LENGTH(cursors);
Giulio Camuffoa2df51c2013-09-18 15:20:04 +02001477 size_t j;
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001478
1479 wm->cursors = malloc(count * sizeof(xcb_cursor_t));
1480 for (i = 0; i < count; i++) {
Giulio Camuffoa2df51c2013-09-18 15:20:04 +02001481 for (j = 0; j < cursors[i].count; j++) {
1482 name = cursors[i].names[j];
1483 wm->cursors[i] =
1484 xcb_cursor_library_load_cursor(wm, name);
1485 if (wm->cursors[i] != (xcb_cursor_t)-1)
1486 break;
1487 }
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001488 }
1489
1490 wm->last_cursor = -1;
1491}
1492
1493static void
1494weston_wm_destroy_cursors(struct weston_wm *wm)
1495{
1496 uint8_t i;
1497
1498 for (i = 0; i < ARRAY_LENGTH(cursors); i++)
1499 xcb_free_cursor(wm->conn, wm->cursors[i]);
1500
1501 free(wm->cursors);
1502}
1503
1504static int
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001505get_cursor_for_location(enum theme_location location)
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001506{
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001507 // int location = theme_get_location(t, x, y, width, height, 0);
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001508
1509 switch (location) {
1510 case THEME_LOCATION_RESIZING_TOP:
1511 return XWM_CURSOR_TOP;
1512 case THEME_LOCATION_RESIZING_BOTTOM:
1513 return XWM_CURSOR_BOTTOM;
1514 case THEME_LOCATION_RESIZING_LEFT:
1515 return XWM_CURSOR_LEFT;
1516 case THEME_LOCATION_RESIZING_RIGHT:
1517 return XWM_CURSOR_RIGHT;
1518 case THEME_LOCATION_RESIZING_TOP_LEFT:
1519 return XWM_CURSOR_TOP_LEFT;
1520 case THEME_LOCATION_RESIZING_TOP_RIGHT:
1521 return XWM_CURSOR_TOP_RIGHT;
1522 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
1523 return XWM_CURSOR_BOTTOM_LEFT;
1524 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
1525 return XWM_CURSOR_BOTTOM_RIGHT;
1526 case THEME_LOCATION_EXTERIOR:
1527 case THEME_LOCATION_TITLEBAR:
1528 default:
1529 return XWM_CURSOR_LEFT_PTR;
1530 }
1531}
1532
1533static void
Tiago Vignattic1903232012-07-16 12:15:37 -04001534weston_wm_window_set_cursor(struct weston_wm *wm, xcb_window_t window_id,
1535 int cursor)
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001536{
1537 uint32_t cursor_value_list;
1538
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001539 if (wm->last_cursor == cursor)
1540 return;
1541
1542 wm->last_cursor = cursor;
1543
1544 cursor_value_list = wm->cursors[cursor];
Tiago Vignattic1903232012-07-16 12:15:37 -04001545 xcb_change_window_attributes (wm->conn, window_id,
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001546 XCB_CW_CURSOR, &cursor_value_list);
1547 xcb_flush(wm->conn);
1548}
1549
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001550static void
Kristian Høgsberg2cd6da12013-10-13 22:11:07 -07001551weston_wm_window_close(struct weston_wm_window *window, xcb_timestamp_t time)
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001552{
1553 xcb_client_message_event_t client_message;
1554
Kristian Høgsberg2cd6da12013-10-13 22:11:07 -07001555 if (window->delete_window) {
1556 client_message.response_type = XCB_CLIENT_MESSAGE;
1557 client_message.format = 32;
1558 client_message.window = window->id;
1559 client_message.type = window->wm->atom.wm_protocols;
1560 client_message.data.data32[0] =
1561 window->wm->atom.wm_delete_window;
1562 client_message.data.data32[1] = time;
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001563
Kristian Høgsberg2cd6da12013-10-13 22:11:07 -07001564 xcb_send_event(window->wm->conn, 0, window->id,
1565 XCB_EVENT_MASK_NO_EVENT,
1566 (char *) &client_message);
1567 } else {
1568 xcb_kill_client(window->wm->conn, window->id);
1569 }
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001570}
1571
1572static void
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001573weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event)
1574{
1575 xcb_button_press_event_t *button = (xcb_button_press_event_t *) event;
1576 struct weston_shell_interface *shell_interface =
1577 &wm->server->compositor->shell_interface;
Kristian Høgsberg5ba31892012-08-10 10:06:59 -04001578 struct weston_seat *seat = weston_wm_pick_seat(wm);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001579 struct weston_wm_window *window;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04001580 enum theme_location location;
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001581 enum frame_button_state button_state;
1582 uint32_t button_id;
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001583
Kristian Høgsberg082d58c2013-06-18 01:00:27 -04001584 wm_log("XCB_BUTTON_%s (detail %d)\n",
1585 button->response_type == XCB_BUTTON_PRESS ?
1586 "PRESS" : "RELEASE", button->detail);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001587
1588 window = hash_table_lookup(wm->window_hash, button->event);
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001589 if (!window || !window->decorate)
1590 return;
Kristian Høgsbergc1693f22012-05-22 16:56:23 -04001591
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001592 if (button->detail != 1 && button->detail != 2)
1593 return;
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04001594
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001595 button_state = button->response_type == XCB_BUTTON_PRESS ?
1596 FRAME_BUTTON_PRESSED : FRAME_BUTTON_RELEASED;
1597 button_id = button->detail == 1 ? BTN_LEFT : BTN_RIGHT;
1598
1599 location = frame_pointer_button(window->frame, NULL,
1600 button_id, button_state);
1601 if (frame_status(window->frame) & FRAME_STATUS_REPAINT)
1602 weston_wm_window_schedule_repaint(window);
1603
1604 if (frame_status(window->frame) & FRAME_STATUS_MOVE) {
1605 shell_interface->move(window->shsurf, seat);
1606 frame_status_clear(window->frame, FRAME_STATUS_MOVE);
1607 }
1608
1609 if (frame_status(window->frame) & FRAME_STATUS_RESIZE) {
1610 shell_interface->resize(window->shsurf, seat, location);
1611 frame_status_clear(window->frame, FRAME_STATUS_RESIZE);
1612 }
1613
1614 if (frame_status(window->frame) & FRAME_STATUS_CLOSE) {
Kristian Høgsberg2cd6da12013-10-13 22:11:07 -07001615 weston_wm_window_close(window, button->time);
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001616 frame_status_clear(window->frame, FRAME_STATUS_CLOSE);
Kristian Høgsbergf96e6c02012-05-22 16:38:53 -04001617 }
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001618}
1619
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001620static void
1621weston_wm_handle_motion(struct weston_wm *wm, xcb_generic_event_t *event)
1622{
1623 xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *) event;
1624 struct weston_wm_window *window;
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001625 enum theme_location location;
1626 int cursor;
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001627
1628 window = hash_table_lookup(wm->window_hash, motion->event);
Tiago Vignatti9134b772012-07-20 19:41:12 +03001629 if (!window || !window->decorate)
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001630 return;
1631
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001632 location = frame_pointer_motion(window->frame, NULL,
1633 motion->event_x, motion->event_y);
1634 if (frame_status(window->frame) & FRAME_STATUS_REPAINT)
1635 weston_wm_window_schedule_repaint(window);
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001636
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001637 cursor = get_cursor_for_location(location);
Tiago Vignattic1903232012-07-16 12:15:37 -04001638 weston_wm_window_set_cursor(wm, window->frame_id, cursor);
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001639}
1640
1641static void
1642weston_wm_handle_enter(struct weston_wm *wm, xcb_generic_event_t *event)
1643{
1644 xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *) event;
1645 struct weston_wm_window *window;
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001646 enum theme_location location;
1647 int cursor;
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001648
1649 window = hash_table_lookup(wm->window_hash, enter->event);
Tiago Vignatti9134b772012-07-20 19:41:12 +03001650 if (!window || !window->decorate)
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001651 return;
1652
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001653 location = frame_pointer_enter(window->frame, NULL,
1654 enter->event_x, enter->event_y);
1655 if (frame_status(window->frame) & FRAME_STATUS_REPAINT)
1656 weston_wm_window_schedule_repaint(window);
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001657
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001658 cursor = get_cursor_for_location(location);
Tiago Vignattic1903232012-07-16 12:15:37 -04001659 weston_wm_window_set_cursor(wm, window->frame_id, cursor);
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001660}
1661
1662static void
1663weston_wm_handle_leave(struct weston_wm *wm, xcb_generic_event_t *event)
1664{
1665 xcb_leave_notify_event_t *leave = (xcb_leave_notify_event_t *) event;
1666 struct weston_wm_window *window;
1667
1668 window = hash_table_lookup(wm->window_hash, leave->event);
Tiago Vignatti9134b772012-07-20 19:41:12 +03001669 if (!window || !window->decorate)
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001670 return;
1671
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05001672 frame_pointer_leave(window->frame, NULL);
1673 if (frame_status(window->frame) & FRAME_STATUS_REPAINT)
1674 weston_wm_window_schedule_repaint(window);
1675
Tiago Vignattic1903232012-07-16 12:15:37 -04001676 weston_wm_window_set_cursor(wm, window->frame_id, XWM_CURSOR_LEFT_PTR);
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001677}
1678
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001679static int
1680weston_wm_handle_event(int fd, uint32_t mask, void *data)
1681{
1682 struct weston_wm *wm = data;
1683 xcb_generic_event_t *event;
1684 int count = 0;
1685
1686 while (event = xcb_poll_for_event(wm->conn), event != NULL) {
1687 if (weston_wm_handle_selection_event(wm, event)) {
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001688 free(event);
1689 count++;
1690 continue;
1691 }
1692
Kristian Høgsbergf9cb3b12013-09-04 21:12:26 -07001693 if (weston_wm_handle_dnd_event(wm, event)) {
1694 free(event);
1695 count++;
1696 continue;
1697 }
1698
MoD31700122013-06-11 19:58:55 -05001699 switch (EVENT_TYPE(event)) {
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001700 case XCB_BUTTON_PRESS:
1701 case XCB_BUTTON_RELEASE:
1702 weston_wm_handle_button(wm, event);
1703 break;
Tiago Vignatti236b48d2012-07-16 12:09:19 -04001704 case XCB_ENTER_NOTIFY:
1705 weston_wm_handle_enter(wm, event);
1706 break;
1707 case XCB_LEAVE_NOTIFY:
1708 weston_wm_handle_leave(wm, event);
1709 break;
1710 case XCB_MOTION_NOTIFY:
1711 weston_wm_handle_motion(wm, event);
1712 break;
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001713 case XCB_CREATE_NOTIFY:
1714 weston_wm_handle_create_notify(wm, event);
1715 break;
1716 case XCB_MAP_REQUEST:
1717 weston_wm_handle_map_request(wm, event);
1718 break;
1719 case XCB_MAP_NOTIFY:
1720 weston_wm_handle_map_notify(wm, event);
1721 break;
1722 case XCB_UNMAP_NOTIFY:
Kristian Høgsberg194ea542012-05-30 10:05:41 -04001723 weston_wm_handle_unmap_notify(wm, event);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001724 break;
Kristian Høgsberg029539b2012-05-30 11:28:24 -04001725 case XCB_REPARENT_NOTIFY:
1726 weston_wm_handle_reparent_notify(wm, event);
1727 break;
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001728 case XCB_CONFIGURE_REQUEST:
1729 weston_wm_handle_configure_request(wm, event);
1730 break;
1731 case XCB_CONFIGURE_NOTIFY:
1732 weston_wm_handle_configure_notify(wm, event);
1733 break;
1734 case XCB_DESTROY_NOTIFY:
1735 weston_wm_handle_destroy_notify(wm, event);
1736 break;
1737 case XCB_MAPPING_NOTIFY:
Kristian Høgsberg082d58c2013-06-18 01:00:27 -04001738 wm_log("XCB_MAPPING_NOTIFY\n");
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001739 break;
1740 case XCB_PROPERTY_NOTIFY:
1741 weston_wm_handle_property_notify(wm, event);
1742 break;
1743 case XCB_CLIENT_MESSAGE:
1744 weston_wm_handle_client_message(wm, event);
1745 break;
1746 }
1747
1748 free(event);
1749 count++;
1750 }
1751
1752 xcb_flush(wm->conn);
1753
1754 return count;
1755}
1756
1757static void
Kristian Høgsbergf9187192013-05-02 13:43:24 -04001758weston_wm_get_visual_and_colormap(struct weston_wm *wm)
1759{
1760 xcb_depth_iterator_t d_iter;
1761 xcb_visualtype_iterator_t vt_iter;
1762 xcb_visualtype_t *visualtype;
1763
1764 d_iter = xcb_screen_allowed_depths_iterator(wm->screen);
1765 visualtype = NULL;
1766 while (d_iter.rem > 0) {
1767 if (d_iter.data->depth == 32) {
1768 vt_iter = xcb_depth_visuals_iterator(d_iter.data);
1769 visualtype = vt_iter.data;
1770 break;
1771 }
1772
1773 xcb_depth_next(&d_iter);
1774 }
1775
1776 if (visualtype == NULL) {
1777 weston_log("no 32 bit visualtype\n");
1778 return;
1779 }
1780
1781 wm->visual_id = visualtype->visual_id;
1782 wm->colormap = xcb_generate_id(wm->conn);
1783 xcb_create_colormap(wm->conn, XCB_COLORMAP_ALLOC_NONE,
1784 wm->colormap, wm->screen->root, wm->visual_id);
1785}
1786
1787static void
Tiago Vignatti9c4ff832012-11-30 17:19:57 -02001788weston_wm_get_resources(struct weston_wm *wm)
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001789{
1790
1791#define F(field) offsetof(struct weston_wm, field)
1792
1793 static const struct { const char *name; int offset; } atoms[] = {
1794 { "WM_PROTOCOLS", F(atom.wm_protocols) },
Kristian Høgsberg1a7a57f2013-08-31 00:12:25 -07001795 { "WM_NORMAL_HINTS", F(atom.wm_normal_hints) },
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001796 { "WM_TAKE_FOCUS", F(atom.wm_take_focus) },
1797 { "WM_DELETE_WINDOW", F(atom.wm_delete_window) },
Kristian Høgsberga6d9a5e2012-05-30 12:15:44 -04001798 { "WM_STATE", F(atom.wm_state) },
Kristian Høgsberg670b5d32012-06-04 11:00:40 -04001799 { "WM_S0", F(atom.wm_s0) },
Tiago Vignatti0d20d7c2012-09-27 17:48:37 +03001800 { "WM_CLIENT_MACHINE", F(atom.wm_client_machine) },
Kristian Høgsberg69981d92013-08-21 22:14:58 -07001801 { "_NET_WM_CM_S0", F(atom.net_wm_cm_s0) },
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001802 { "_NET_WM_NAME", F(atom.net_wm_name) },
Tiago Vignatti0d20d7c2012-09-27 17:48:37 +03001803 { "_NET_WM_PID", F(atom.net_wm_pid) },
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001804 { "_NET_WM_ICON", F(atom.net_wm_icon) },
1805 { "_NET_WM_STATE", F(atom.net_wm_state) },
1806 { "_NET_WM_STATE_FULLSCREEN", F(atom.net_wm_state_fullscreen) },
1807 { "_NET_WM_USER_TIME", F(atom.net_wm_user_time) },
1808 { "_NET_WM_ICON_NAME", F(atom.net_wm_icon_name) },
1809 { "_NET_WM_WINDOW_TYPE", F(atom.net_wm_window_type) },
1810
1811 { "_NET_WM_WINDOW_TYPE_DESKTOP", F(atom.net_wm_window_type_desktop) },
1812 { "_NET_WM_WINDOW_TYPE_DOCK", F(atom.net_wm_window_type_dock) },
1813 { "_NET_WM_WINDOW_TYPE_TOOLBAR", F(atom.net_wm_window_type_toolbar) },
1814 { "_NET_WM_WINDOW_TYPE_MENU", F(atom.net_wm_window_type_menu) },
1815 { "_NET_WM_WINDOW_TYPE_UTILITY", F(atom.net_wm_window_type_utility) },
1816 { "_NET_WM_WINDOW_TYPE_SPLASH", F(atom.net_wm_window_type_splash) },
1817 { "_NET_WM_WINDOW_TYPE_DIALOG", F(atom.net_wm_window_type_dialog) },
Tiago Vignattibf1e8662012-06-12 14:07:49 +03001818 { "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", F(atom.net_wm_window_type_dropdown) },
1819 { "_NET_WM_WINDOW_TYPE_POPUP_MENU", F(atom.net_wm_window_type_popup) },
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001820 { "_NET_WM_WINDOW_TYPE_TOOLTIP", F(atom.net_wm_window_type_tooltip) },
1821 { "_NET_WM_WINDOW_TYPE_NOTIFICATION", F(atom.net_wm_window_type_notification) },
1822 { "_NET_WM_WINDOW_TYPE_COMBO", F(atom.net_wm_window_type_combo) },
1823 { "_NET_WM_WINDOW_TYPE_DND", F(atom.net_wm_window_type_dnd) },
1824 { "_NET_WM_WINDOW_TYPE_NORMAL", F(atom.net_wm_window_type_normal) },
1825
1826 { "_NET_WM_MOVERESIZE", F(atom.net_wm_moveresize) },
1827 { "_NET_SUPPORTING_WM_CHECK",
1828 F(atom.net_supporting_wm_check) },
1829 { "_NET_SUPPORTED", F(atom.net_supported) },
1830 { "_MOTIF_WM_HINTS", F(atom.motif_wm_hints) },
1831 { "CLIPBOARD", F(atom.clipboard) },
Kristian Høgsbergcba022a2012-06-04 10:11:45 -04001832 { "CLIPBOARD_MANAGER", F(atom.clipboard_manager) },
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001833 { "TARGETS", F(atom.targets) },
1834 { "UTF8_STRING", F(atom.utf8_string) },
1835 { "_WL_SELECTION", F(atom.wl_selection) },
1836 { "INCR", F(atom.incr) },
1837 { "TIMESTAMP", F(atom.timestamp) },
1838 { "MULTIPLE", F(atom.multiple) },
1839 { "UTF8_STRING" , F(atom.utf8_string) },
1840 { "COMPOUND_TEXT", F(atom.compound_text) },
1841 { "TEXT", F(atom.text) },
1842 { "STRING", F(atom.string) },
1843 { "text/plain;charset=utf-8", F(atom.text_plain_utf8) },
1844 { "text/plain", F(atom.text_plain) },
Kristian Høgsbergf9cb3b12013-09-04 21:12:26 -07001845 { "XdndSelection", F(atom.xdnd_selection) },
1846 { "XdndAware", F(atom.xdnd_aware) },
1847 { "XdndEnter", F(atom.xdnd_enter) },
1848 { "XdndLeave", F(atom.xdnd_leave) },
1849 { "XdndDrop", F(atom.xdnd_drop) },
1850 { "XdndStatus", F(atom.xdnd_status) },
1851 { "XdndFinished", F(atom.xdnd_finished) },
1852 { "XdndTypeList", F(atom.xdnd_type_list) },
Kristian Høgsberg757d8af2014-03-17 22:33:29 -07001853 { "XdndActionCopy", F(atom.xdnd_action_copy) },
1854 { "WL_SURFACE_ID", F(atom.wl_surface_id) }
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001855 };
1856#undef F
1857
1858 xcb_xfixes_query_version_cookie_t xfixes_cookie;
1859 xcb_xfixes_query_version_reply_t *xfixes_reply;
1860 xcb_intern_atom_cookie_t cookies[ARRAY_LENGTH(atoms)];
1861 xcb_intern_atom_reply_t *reply;
1862 xcb_render_query_pict_formats_reply_t *formats_reply;
1863 xcb_render_query_pict_formats_cookie_t formats_cookie;
1864 xcb_render_pictforminfo_t *formats;
1865 uint32_t i;
1866
1867 xcb_prefetch_extension_data (wm->conn, &xcb_xfixes_id);
Kristian Høgsbergbcfd07b2013-10-11 16:48:19 -07001868 xcb_prefetch_extension_data (wm->conn, &xcb_composite_id);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001869
1870 formats_cookie = xcb_render_query_pict_formats(wm->conn);
1871
1872 for (i = 0; i < ARRAY_LENGTH(atoms); i++)
1873 cookies[i] = xcb_intern_atom (wm->conn, 0,
1874 strlen(atoms[i].name),
1875 atoms[i].name);
1876
1877 for (i = 0; i < ARRAY_LENGTH(atoms); i++) {
1878 reply = xcb_intern_atom_reply (wm->conn, cookies[i], NULL);
1879 *(xcb_atom_t *) ((char *) wm + atoms[i].offset) = reply->atom;
1880 free(reply);
1881 }
1882
1883 wm->xfixes = xcb_get_extension_data(wm->conn, &xcb_xfixes_id);
1884 if (!wm->xfixes || !wm->xfixes->present)
Martin Minarik6d118362012-06-07 18:01:59 +02001885 weston_log("xfixes not available\n");
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001886
1887 xfixes_cookie = xcb_xfixes_query_version(wm->conn,
1888 XCB_XFIXES_MAJOR_VERSION,
1889 XCB_XFIXES_MINOR_VERSION);
1890 xfixes_reply = xcb_xfixes_query_version_reply(wm->conn,
1891 xfixes_cookie, NULL);
1892
Martin Minarik6d118362012-06-07 18:01:59 +02001893 weston_log("xfixes version: %d.%d\n",
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001894 xfixes_reply->major_version, xfixes_reply->minor_version);
1895
1896 free(xfixes_reply);
1897
1898 formats_reply = xcb_render_query_pict_formats_reply(wm->conn,
1899 formats_cookie, 0);
1900 if (formats_reply == NULL)
1901 return;
1902
1903 formats = xcb_render_query_pict_formats_formats(formats_reply);
Kristian Høgsberge89cef32012-07-16 11:57:08 -04001904 for (i = 0; i < formats_reply->num_formats; i++) {
1905 if (formats[i].direct.red_mask != 0xff &&
1906 formats[i].direct.red_shift != 16)
1907 continue;
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001908 if (formats[i].type == XCB_RENDER_PICT_TYPE_DIRECT &&
1909 formats[i].depth == 24)
Kristian Høgsberge89cef32012-07-16 11:57:08 -04001910 wm->format_rgb = formats[i];
1911 if (formats[i].type == XCB_RENDER_PICT_TYPE_DIRECT &&
1912 formats[i].depth == 32 &&
1913 formats[i].direct.alpha_mask == 0xff &&
1914 formats[i].direct.alpha_shift == 24)
1915 wm->format_rgba = formats[i];
1916 }
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001917
1918 free(formats_reply);
1919}
1920
1921static void
1922weston_wm_create_wm_window(struct weston_wm *wm)
1923{
1924 static const char name[] = "Weston WM";
1925
1926 wm->wm_window = xcb_generate_id(wm->conn);
1927 xcb_create_window(wm->conn,
1928 XCB_COPY_FROM_PARENT,
1929 wm->wm_window,
1930 wm->screen->root,
1931 0, 0,
1932 10, 10,
1933 0,
1934 XCB_WINDOW_CLASS_INPUT_OUTPUT,
1935 wm->screen->root_visual,
1936 0, NULL);
1937
1938 xcb_change_property(wm->conn,
1939 XCB_PROP_MODE_REPLACE,
1940 wm->wm_window,
1941 wm->atom.net_supporting_wm_check,
1942 XCB_ATOM_WINDOW,
1943 32, /* format */
1944 1, &wm->wm_window);
1945
1946 xcb_change_property(wm->conn,
1947 XCB_PROP_MODE_REPLACE,
1948 wm->wm_window,
1949 wm->atom.net_wm_name,
1950 wm->atom.utf8_string,
1951 8, /* format */
1952 strlen(name), name);
1953
1954 xcb_change_property(wm->conn,
1955 XCB_PROP_MODE_REPLACE,
1956 wm->screen->root,
1957 wm->atom.net_supporting_wm_check,
1958 XCB_ATOM_WINDOW,
1959 32, /* format */
1960 1, &wm->wm_window);
1961
Kristian Høgsberg670b5d32012-06-04 11:00:40 -04001962 /* Claim the WM_S0 selection even though we don't suport
1963 * the --replace functionality. */
1964 xcb_set_selection_owner(wm->conn,
1965 wm->wm_window,
1966 wm->atom.wm_s0,
1967 XCB_TIME_CURRENT_TIME);
Kristian Høgsberg69981d92013-08-21 22:14:58 -07001968
1969 xcb_set_selection_owner(wm->conn,
1970 wm->wm_window,
1971 wm->atom.net_wm_cm_s0,
1972 XCB_TIME_CURRENT_TIME);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001973}
1974
1975struct weston_wm *
Kristian Høgsberg757d8af2014-03-17 22:33:29 -07001976weston_wm_create(struct weston_xserver *wxs, int fd)
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001977{
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001978 struct weston_wm *wm;
1979 struct wl_event_loop *loop;
1980 xcb_screen_iterator_t s;
Kristian Høgsberg4dec0112012-06-03 09:18:06 -04001981 uint32_t values[1];
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05001982 xcb_atom_t supported[3];
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001983
Peter Huttererf3d62272013-08-08 11:57:05 +10001984 wm = zalloc(sizeof *wm);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001985 if (wm == NULL)
1986 return NULL;
1987
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001988 wm->server = wxs;
1989 wm->window_hash = hash_table_create();
1990 if (wm->window_hash == NULL) {
1991 free(wm);
1992 return NULL;
1993 }
1994
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001995 /* xcb_connect_to_fd takes ownership of the fd. */
Kristian Høgsberg757d8af2014-03-17 22:33:29 -07001996 wm->conn = xcb_connect_to_fd(fd, NULL);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04001997 if (xcb_connection_has_error(wm->conn)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001998 weston_log("xcb_connect_to_fd failed\n");
Kristian Høgsberg757d8af2014-03-17 22:33:29 -07001999 close(fd);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002000 hash_table_destroy(wm->window_hash);
2001 free(wm);
2002 return NULL;
2003 }
2004
2005 s = xcb_setup_roots_iterator(xcb_get_setup(wm->conn));
2006 wm->screen = s.data;
2007
2008 loop = wl_display_get_event_loop(wxs->wl_display);
2009 wm->source =
Kristian Høgsberg757d8af2014-03-17 22:33:29 -07002010 wl_event_loop_add_fd(loop, fd,
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002011 WL_EVENT_READABLE,
2012 weston_wm_handle_event, wm);
2013 wl_event_source_check(wm->source);
2014
Tiago Vignatti9c4ff832012-11-30 17:19:57 -02002015 weston_wm_get_resources(wm);
Kristian Høgsbergf9187192013-05-02 13:43:24 -04002016 weston_wm_get_visual_and_colormap(wm);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002017
2018 values[0] =
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002019 XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
2020 XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
2021 XCB_EVENT_MASK_PROPERTY_CHANGE;
2022 xcb_change_window_attributes(wm->conn, wm->screen->root,
2023 XCB_CW_EVENT_MASK, values);
Kristian Høgsbergbcfd07b2013-10-11 16:48:19 -07002024
2025 xcb_composite_redirect_subwindows(wm->conn, wm->screen->root,
2026 XCB_COMPOSITE_REDIRECT_MANUAL);
2027
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002028 wm->theme = theme_create();
2029
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002030 supported[0] = wm->atom.net_wm_moveresize;
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05002031 supported[1] = wm->atom.net_wm_state;
2032 supported[2] = wm->atom.net_wm_state_fullscreen;
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002033 xcb_change_property(wm->conn,
2034 XCB_PROP_MODE_REPLACE,
2035 wm->screen->root,
2036 wm->atom.net_supported,
2037 XCB_ATOM_ATOM,
2038 32, /* format */
2039 ARRAY_LENGTH(supported), supported);
2040
Kristian Høgsberg4dec0112012-06-03 09:18:06 -04002041 weston_wm_selection_init(wm);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002042
Kristian Høgsbergf9cb3b12013-09-04 21:12:26 -07002043 weston_wm_dnd_init(wm);
2044
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002045 xcb_flush(wm->conn);
2046
Kristian Høgsberg757d8af2014-03-17 22:33:29 -07002047 wm->create_surface_listener.notify = weston_wm_create_surface;
2048 wl_signal_add(&wxs->compositor->create_surface_signal,
2049 &wm->create_surface_listener);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002050 wm->activate_listener.notify = weston_wm_window_activate;
2051 wl_signal_add(&wxs->compositor->activate_signal,
2052 &wm->activate_listener);
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002053 wm->transform_listener.notify = weston_wm_window_transform;
2054 wl_signal_add(&wxs->compositor->transform_signal,
2055 &wm->transform_listener);
Tiago Vignatti0d20d7c2012-09-27 17:48:37 +03002056 wm->kill_listener.notify = weston_wm_kill_client;
2057 wl_signal_add(&wxs->compositor->kill_signal,
2058 &wm->kill_listener);
Kristian Høgsberg757d8af2014-03-17 22:33:29 -07002059 wl_list_init(&wm->unpaired_window_list);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002060
Tiago Vignatti236b48d2012-07-16 12:09:19 -04002061 weston_wm_create_cursors(wm);
Tiago Vignattic1903232012-07-16 12:15:37 -04002062 weston_wm_window_set_cursor(wm, wm->screen->root, XWM_CURSOR_LEFT_PTR);
Tiago Vignatti236b48d2012-07-16 12:09:19 -04002063
Kristian Høgsberg757d8af2014-03-17 22:33:29 -07002064 /* Create wm window and take WM_S0 selection last, which
2065 * signals to Xwayland that we're done with setup. */
2066 weston_wm_create_wm_window(wm);
2067
2068 weston_log("created wm, root %d\n", wm->screen->root);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002069
2070 return wm;
2071}
2072
2073void
2074weston_wm_destroy(struct weston_wm *wm)
2075{
2076 /* FIXME: Free windows in hash. */
2077 hash_table_destroy(wm->window_hash);
Tiago Vignatti236b48d2012-07-16 12:09:19 -04002078 weston_wm_destroy_cursors(wm);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002079 xcb_disconnect(wm->conn);
2080 wl_event_source_remove(wm->source);
2081 wl_list_remove(&wm->selection_listener.link);
2082 wl_list_remove(&wm->activate_listener.link);
Tiago Vignatti0d20d7c2012-09-27 17:48:37 +03002083 wl_list_remove(&wm->kill_listener.link);
Louis-Francis Ratté-Bouliannedce3dac2013-07-20 05:16:45 +01002084 wl_list_remove(&wm->transform_listener.link);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002085
2086 free(wm);
2087}
2088
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002089static struct weston_wm_window *
2090get_wm_window(struct weston_surface *surface)
2091{
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002092 struct wl_listener *listener;
2093
Jason Ekstrand26ed73c2013-06-06 22:34:41 -05002094 listener = wl_signal_get(&surface->destroy_signal, surface_destroy);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002095 if (listener)
2096 return container_of(listener, struct weston_wm_window,
2097 surface_destroy_listener);
2098
2099 return NULL;
2100}
2101
2102static void
Kristian Høgsberga61ca062012-05-22 16:05:52 -04002103weston_wm_window_configure(void *data)
2104{
2105 struct weston_wm_window *window = data;
2106 struct weston_wm *wm = window->wm;
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05002107 uint32_t values[4];
2108 int x, y, width, height;
Kristian Høgsberga61ca062012-05-22 16:05:52 -04002109
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05002110 weston_wm_window_get_child_position(window, &x, &y);
2111 values[0] = x;
2112 values[1] = y;
2113 values[2] = window->width;
2114 values[3] = window->height;
Kristian Høgsberga61ca062012-05-22 16:05:52 -04002115 xcb_configure_window(wm->conn,
2116 window->id,
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05002117 XCB_CONFIG_WINDOW_X |
2118 XCB_CONFIG_WINDOW_Y |
Kristian Høgsberga61ca062012-05-22 16:05:52 -04002119 XCB_CONFIG_WINDOW_WIDTH |
2120 XCB_CONFIG_WINDOW_HEIGHT,
2121 values);
2122
2123 weston_wm_window_get_frame_size(window, &width, &height);
2124 values[0] = width;
2125 values[1] = height;
2126 xcb_configure_window(wm->conn,
2127 window->frame_id,
2128 XCB_CONFIG_WINDOW_WIDTH |
2129 XCB_CONFIG_WINDOW_HEIGHT,
2130 values);
2131
2132 window->configure_source = NULL;
2133
2134 weston_wm_window_schedule_repaint(window);
2135}
2136
2137static void
2138send_configure(struct weston_surface *surface,
2139 uint32_t edges, int32_t width, int32_t height)
2140{
2141 struct weston_wm_window *window = get_wm_window(surface);
2142 struct weston_wm *wm = window->wm;
2143 struct theme *t = window->wm->theme;
Kristian Høgsbergfa514b42013-07-08 15:00:25 -04002144 int vborder, hborder;
Kristian Høgsberga61ca062012-05-22 16:05:52 -04002145
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05002146 if (window->fullscreen) {
Kristian Høgsbergfa514b42013-07-08 15:00:25 -04002147 hborder = 0;
2148 vborder = 0;
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05002149 } else if (window->decorate) {
Kristian Høgsbergfa514b42013-07-08 15:00:25 -04002150 hborder = 2 * (t->margin + t->width);
2151 vborder = 2 * t->margin + t->titlebar_height + t->width;
Kristian Høgsberga61ca062012-05-22 16:05:52 -04002152 } else {
Kristian Høgsbergfa514b42013-07-08 15:00:25 -04002153 hborder = 2 * t->margin;
2154 vborder = 2 * t->margin;
Kristian Høgsberga61ca062012-05-22 16:05:52 -04002155 }
2156
Kristian Høgsbergfa514b42013-07-08 15:00:25 -04002157 if (width > hborder)
2158 window->width = width - hborder;
2159 else
2160 window->width = 1;
2161
2162 if (height > vborder)
2163 window->height = height - vborder;
2164 else
2165 window->height = 1;
2166
Jason Ekstrandd14c4ca2013-10-13 19:08:41 -05002167 if (window->frame)
2168 frame_resize_inside(window->frame, window->width, window->height);
2169
Kristian Høgsberga61ca062012-05-22 16:05:52 -04002170 if (window->configure_source)
2171 return;
2172
2173 window->configure_source =
2174 wl_event_loop_add_idle(wm->server->loop,
2175 weston_wm_window_configure, window);
2176}
2177
2178static const struct weston_shell_client shell_client = {
2179 send_configure
2180};
2181
Kristian Høgsberg59f44c12013-08-31 00:08:27 -07002182static int
2183legacy_fullscreen(struct weston_wm *wm,
2184 struct weston_wm_window *window,
2185 struct weston_output **output_ret)
2186{
2187 struct weston_compositor *compositor = wm->server->compositor;
2188 struct weston_output *output;
Kristian Høgsberg1a7a57f2013-08-31 00:12:25 -07002189 uint32_t minmax = PMinSize | PMaxSize;
2190 int matching_size;
Kristian Høgsberg59f44c12013-08-31 00:08:27 -07002191
2192 /* Heuristics for detecting legacy fullscreen windows... */
2193
2194 wl_list_for_each(output, &compositor->output_list, link) {
2195 if (output->x == window->x &&
2196 output->y == window->y &&
2197 output->width == window->width &&
2198 output->height == window->height &&
2199 window->override_redirect) {
2200 *output_ret = output;
2201 return 1;
2202 }
Kristian Høgsberg1a7a57f2013-08-31 00:12:25 -07002203
2204 matching_size = 0;
2205 if ((window->size_hints.flags & (USSize |PSize)) &&
2206 window->size_hints.width == output->width &&
2207 window->size_hints.height == output->height)
2208 matching_size = 1;
2209 if ((window->size_hints.flags & minmax) == minmax &&
2210 window->size_hints.min_width == output->width &&
2211 window->size_hints.min_height == output->height &&
2212 window->size_hints.max_width == output->width &&
2213 window->size_hints.max_height == output->height)
2214 matching_size = 1;
2215
2216 if (matching_size && !window->decorate &&
2217 (window->size_hints.flags & (USPosition | PPosition)) &&
2218 window->size_hints.x == output->x &&
2219 window->size_hints.y == output->y) {
2220 *output_ret = output;
2221 return 1;
2222 }
Kristian Høgsberg59f44c12013-08-31 00:08:27 -07002223 }
2224
2225 return 0;
2226}
Kristian Høgsberg757d8af2014-03-17 22:33:29 -07002227
Kristian Høgsberga61ca062012-05-22 16:05:52 -04002228static void
Kristian Høgsberg757d8af2014-03-17 22:33:29 -07002229xserver_map_shell_surface(struct weston_wm_window *window,
2230 struct weston_surface *surface)
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002231{
Kristian Høgsberg757d8af2014-03-17 22:33:29 -07002232 struct weston_wm *wm = window->wm;
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002233 struct weston_shell_interface *shell_interface =
2234 &wm->server->compositor->shell_interface;
Kristian Høgsberg59f44c12013-08-31 00:08:27 -07002235 struct weston_output *output;
Kristian Høgsberg9f7e3312014-01-02 22:40:37 -08002236 struct weston_wm_window *parent;
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002237
Kristian Høgsberg757d8af2014-03-17 22:33:29 -07002238 weston_wm_window_read_properties(window);
2239
2240 /* A weston_wm_window may have many different surfaces assigned
2241 * throughout its life, so we must make sure to remove the listener
2242 * from the old surface signal list. */
2243 if (window->surface)
2244 wl_list_remove(&window->surface_destroy_listener.link);
2245
2246 window->surface = surface;
2247 window->surface_destroy_listener.notify = surface_destroy;
2248 wl_signal_add(&window->surface->destroy_signal,
2249 &window->surface_destroy_listener);
2250
2251 weston_wm_window_schedule_repaint(window);
2252
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002253 if (!shell_interface->create_shell_surface)
2254 return;
2255
Jason Ekstranda7af7042013-10-12 22:38:11 -05002256 if (!shell_interface->get_primary_view)
2257 return;
2258
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002259 window->shsurf =
2260 shell_interface->create_shell_surface(shell_interface->shell,
Kristian Høgsberga61ca062012-05-22 16:05:52 -04002261 window->surface,
2262 &shell_client);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002263 window->view = shell_interface->get_primary_view(shell_interface->shell,
2264 window->shsurf);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002265
Giulio Camuffo62942ad2013-09-11 18:20:47 +02002266 if (window->name)
2267 shell_interface->set_title(window->shsurf, window->name);
2268
Kristian Høgsbergb810eb52013-02-12 20:07:05 -05002269 if (window->fullscreen) {
2270 window->saved_width = window->width;
2271 window->saved_height = window->height;
2272 shell_interface->set_fullscreen(window->shsurf,
2273 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
2274 0, NULL);
2275 return;
Kristian Høgsberg59f44c12013-08-31 00:08:27 -07002276 } else if (legacy_fullscreen(wm, window, &output)) {
2277 window->fullscreen = 1;
2278 shell_interface->set_fullscreen(window->shsurf,
2279 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
2280 0, output);
Kristian Høgsberg9f7e3312014-01-02 22:40:37 -08002281 } else if (window->override_redirect) {
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002282 shell_interface->set_xwayland(window->shsurf,
Kristian Høgsberg146f5ba2013-08-22 16:24:15 -07002283 window->x,
2284 window->y,
Tiago Vignattifb2adba2013-06-12 15:43:21 -03002285 WL_SHELL_SURFACE_TRANSIENT_INACTIVE);
Axel Davye4450f92014-01-12 15:06:05 +01002286 } else if (window->transient_for && window->transient_for->surface) {
Kristian Høgsberg9f7e3312014-01-02 22:40:37 -08002287 parent = window->transient_for;
2288 shell_interface->set_transient(window->shsurf,
2289 parent->surface,
Axel Davyfa506b62014-01-12 15:06:04 +01002290 window->x - parent->x,
2291 window->y - parent->y, 0);
Kristian Høgsberg9f7e3312014-01-02 22:40:37 -08002292 } else {
2293 shell_interface->set_toplevel(window->shsurf);
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002294 }
Kristian Høgsberg380deee2012-05-21 17:12:41 -04002295}