xwm: don't let X windows steal the focus
[platform/upstream/weston.git] / xwayland / window-manager.c
1 /*
2  * Copyright © 2011 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25
26 #include "config.h"
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <sys/socket.h>
32 #include <sys/un.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #include <signal.h>
37 #include <X11/Xcursor/Xcursor.h>
38 #include <linux/input.h>
39
40 #include "xwayland.h"
41
42 #include "cairo-util.h"
43 #include "compositor.h"
44 #include "hash.h"
45 #include "shared/helpers.h"
46
47 struct wm_size_hints {
48         uint32_t flags;
49         int32_t x, y;
50         int32_t width, height;  /* should set so old wm's don't mess up */
51         int32_t min_width, min_height;
52         int32_t max_width, max_height;
53         int32_t width_inc, height_inc;
54         struct {
55                 int32_t x;
56                 int32_t y;
57         } min_aspect, max_aspect;
58         int32_t base_width, base_height;
59         int32_t win_gravity;
60 };
61
62 #define USPosition      (1L << 0)
63 #define USSize          (1L << 1)
64 #define PPosition       (1L << 2)
65 #define PSize           (1L << 3)
66 #define PMinSize        (1L << 4)
67 #define PMaxSize        (1L << 5)
68 #define PResizeInc      (1L << 6)
69 #define PAspect         (1L << 7)
70 #define PBaseSize       (1L << 8)
71 #define PWinGravity     (1L << 9)
72
73 struct motif_wm_hints {
74         uint32_t flags;
75         uint32_t functions;
76         uint32_t decorations;
77         int32_t input_mode;
78         uint32_t status;
79 };
80
81 #define MWM_HINTS_FUNCTIONS     (1L << 0)
82 #define MWM_HINTS_DECORATIONS   (1L << 1)
83 #define MWM_HINTS_INPUT_MODE    (1L << 2)
84 #define MWM_HINTS_STATUS        (1L << 3)
85
86 #define MWM_FUNC_ALL            (1L << 0)
87 #define MWM_FUNC_RESIZE         (1L << 1)
88 #define MWM_FUNC_MOVE           (1L << 2)
89 #define MWM_FUNC_MINIMIZE       (1L << 3)
90 #define MWM_FUNC_MAXIMIZE       (1L << 4)
91 #define MWM_FUNC_CLOSE          (1L << 5)
92
93 #define MWM_DECOR_ALL           (1L << 0)
94 #define MWM_DECOR_BORDER        (1L << 1)
95 #define MWM_DECOR_RESIZEH       (1L << 2)
96 #define MWM_DECOR_TITLE         (1L << 3)
97 #define MWM_DECOR_MENU          (1L << 4)
98 #define MWM_DECOR_MINIMIZE      (1L << 5)
99 #define MWM_DECOR_MAXIMIZE      (1L << 6)
100
101 #define MWM_DECOR_EVERYTHING \
102         (MWM_DECOR_BORDER | MWM_DECOR_RESIZEH | MWM_DECOR_TITLE | \
103          MWM_DECOR_MENU | MWM_DECOR_MINIMIZE | MWM_DECOR_MAXIMIZE)
104
105 #define MWM_INPUT_MODELESS 0
106 #define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1
107 #define MWM_INPUT_SYSTEM_MODAL 2
108 #define MWM_INPUT_FULL_APPLICATION_MODAL 3
109 #define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL
110
111 #define MWM_TEAROFF_WINDOW      (1L<<0)
112
113 #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
114 #define _NET_WM_MOVERESIZE_SIZE_TOP          1
115 #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
116 #define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
117 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
118 #define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
119 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
120 #define _NET_WM_MOVERESIZE_SIZE_LEFT         7
121 #define _NET_WM_MOVERESIZE_MOVE              8   /* movement only */
122 #define _NET_WM_MOVERESIZE_SIZE_KEYBOARD     9   /* size via keyboard */
123 #define _NET_WM_MOVERESIZE_MOVE_KEYBOARD    10   /* move via keyboard */
124 #define _NET_WM_MOVERESIZE_CANCEL           11   /* cancel operation */
125
126 struct weston_wm_window {
127         struct weston_wm *wm;
128         xcb_window_t id;
129         xcb_window_t frame_id;
130         struct frame *frame;
131         cairo_surface_t *cairo_surface;
132         uint32_t surface_id;
133         struct weston_surface *surface;
134         struct shell_surface *shsurf;
135         struct weston_view *view;
136         struct wl_listener surface_destroy_listener;
137         struct wl_event_source *repaint_source;
138         struct wl_event_source *configure_source;
139         int properties_dirty;
140         int pid;
141         char *machine;
142         char *class;
143         char *name;
144         struct weston_wm_window *transient_for;
145         uint32_t protocols;
146         xcb_atom_t type;
147         int width, height;
148         int x, y;
149         int saved_width, saved_height;
150         int decorate;
151         int override_redirect;
152         int fullscreen;
153         int has_alpha;
154         int delete_window;
155         int maximized_vert;
156         int maximized_horz;
157         struct wm_size_hints size_hints;
158         struct motif_wm_hints motif_hints;
159         struct wl_list link;
160 };
161
162 static struct weston_wm_window *
163 get_wm_window(struct weston_surface *surface);
164
165 static void
166 weston_wm_window_schedule_repaint(struct weston_wm_window *window);
167
168 static void
169 xserver_map_shell_surface(struct weston_wm_window *window,
170                           struct weston_surface *surface);
171
172 static int __attribute__ ((format (printf, 1, 2)))
173 wm_log(const char *fmt, ...)
174 {
175 #ifdef WM_DEBUG
176         int l;
177         va_list argp;
178
179         va_start(argp, fmt);
180         l = weston_vlog(fmt, argp);
181         va_end(argp);
182
183         return l;
184 #else
185         return 0;
186 #endif
187 }
188
189 static int __attribute__ ((format (printf, 1, 2)))
190 wm_log_continue(const char *fmt, ...)
191 {
192 #ifdef WM_DEBUG
193         int l;
194         va_list argp;
195
196         va_start(argp, fmt);
197         l = weston_vlog_continue(fmt, argp);
198         va_end(argp);
199
200         return l;
201 #else
202         return 0;
203 #endif
204 }
205
206 static bool __attribute__ ((warn_unused_result))
207 wm_lookup_window(struct weston_wm *wm, xcb_window_t hash,
208                  struct weston_wm_window **window)
209 {
210         *window = hash_table_lookup(wm->window_hash, hash);
211         if (*window)
212                 return true;
213         return false;
214 }
215
216 const char *
217 get_atom_name(xcb_connection_t *c, xcb_atom_t atom)
218 {
219         xcb_get_atom_name_cookie_t cookie;
220         xcb_get_atom_name_reply_t *reply;
221         xcb_generic_error_t *e;
222         static char buffer[64];
223
224         if (atom == XCB_ATOM_NONE)
225                 return "None";
226
227         cookie = xcb_get_atom_name (c, atom);
228         reply = xcb_get_atom_name_reply (c, cookie, &e);
229
230         if(reply) {
231                 snprintf(buffer, sizeof buffer, "%.*s",
232                          xcb_get_atom_name_name_length (reply),
233                          xcb_get_atom_name_name (reply));
234         } else {
235                 snprintf(buffer, sizeof buffer, "(atom %u)", atom);
236         }
237
238         free(reply);
239
240         return buffer;
241 }
242
243 static xcb_cursor_t
244 xcb_cursor_image_load_cursor(struct weston_wm *wm, const XcursorImage *img)
245 {
246         xcb_connection_t *c = wm->conn;
247         xcb_screen_iterator_t s = xcb_setup_roots_iterator(xcb_get_setup(c));
248         xcb_screen_t *screen = s.data;
249         xcb_gcontext_t gc;
250         xcb_pixmap_t pix;
251         xcb_render_picture_t pic;
252         xcb_cursor_t cursor;
253         int stride = img->width * 4;
254
255         pix = xcb_generate_id(c);
256         xcb_create_pixmap(c, 32, pix, screen->root, img->width, img->height);
257
258         pic = xcb_generate_id(c);
259         xcb_render_create_picture(c, pic, pix, wm->format_rgba.id, 0, 0);
260
261         gc = xcb_generate_id(c);
262         xcb_create_gc(c, gc, pix, 0, 0);
263
264         xcb_put_image(c, XCB_IMAGE_FORMAT_Z_PIXMAP, pix, gc,
265                       img->width, img->height, 0, 0, 0, 32,
266                       stride * img->height, (uint8_t *) img->pixels);
267         xcb_free_gc(c, gc);
268
269         cursor = xcb_generate_id(c);
270         xcb_render_create_cursor(c, cursor, pic, img->xhot, img->yhot);
271
272         xcb_render_free_picture(c, pic);
273         xcb_free_pixmap(c, pix);
274
275         return cursor;
276 }
277
278 static xcb_cursor_t
279 xcb_cursor_images_load_cursor(struct weston_wm *wm, const XcursorImages *images)
280 {
281         /* TODO: treat animated cursors as well */
282         if (images->nimage != 1)
283                 return -1;
284
285         return xcb_cursor_image_load_cursor(wm, images->images[0]);
286 }
287
288 static xcb_cursor_t
289 xcb_cursor_library_load_cursor(struct weston_wm *wm, const char *file)
290 {
291         xcb_cursor_t cursor;
292         XcursorImages *images;
293         char *v = NULL;
294         int size = 0;
295
296         if (!file)
297                 return 0;
298
299         v = getenv ("XCURSOR_SIZE");
300         if (v)
301                 size = atoi(v);
302
303         if (!size)
304                 size = 32;
305
306         images = XcursorLibraryLoadImages (file, NULL, size);
307         if (!images)
308                 return -1;
309
310         cursor = xcb_cursor_images_load_cursor (wm, images);
311         XcursorImagesDestroy (images);
312
313         return cursor;
314 }
315
316 void
317 dump_property(struct weston_wm *wm,
318               xcb_atom_t property, xcb_get_property_reply_t *reply)
319 {
320         int32_t *incr_value;
321         const char *text_value, *name;
322         xcb_atom_t *atom_value;
323         int width, len;
324         uint32_t i;
325
326         width = wm_log_continue("%s: ", get_atom_name(wm->conn, property));
327         if (reply == NULL) {
328                 wm_log_continue("(no reply)\n");
329                 return;
330         }
331
332         width += wm_log_continue("%s/%d, length %d (value_len %d): ",
333                                  get_atom_name(wm->conn, reply->type),
334                                  reply->format,
335                                  xcb_get_property_value_length(reply),
336                                  reply->value_len);
337
338         if (reply->type == wm->atom.incr) {
339                 incr_value = xcb_get_property_value(reply);
340                 wm_log_continue("%d\n", *incr_value);
341         } else if (reply->type == wm->atom.utf8_string ||
342               reply->type == wm->atom.string) {
343                 text_value = xcb_get_property_value(reply);
344                 if (reply->value_len > 40)
345                         len = 40;
346                 else
347                         len = reply->value_len;
348                 wm_log_continue("\"%.*s\"\n", len, text_value);
349         } else if (reply->type == XCB_ATOM_ATOM) {
350                 atom_value = xcb_get_property_value(reply);
351                 for (i = 0; i < reply->value_len; i++) {
352                         name = get_atom_name(wm->conn, atom_value[i]);
353                         if (width + strlen(name) + 2 > 78) {
354                                 wm_log_continue("\n    ");
355                                 width = 4;
356                         } else if (i > 0) {
357                                 width +=  wm_log_continue(", ");
358                         }
359
360                         width +=  wm_log_continue("%s", name);
361                 }
362                 wm_log_continue("\n");
363         } else {
364                 wm_log_continue("huh?\n");
365         }
366 }
367
368 static void
369 read_and_dump_property(struct weston_wm *wm,
370                        xcb_window_t window, xcb_atom_t property)
371 {
372         xcb_get_property_reply_t *reply;
373         xcb_get_property_cookie_t cookie;
374
375         cookie = xcb_get_property(wm->conn, 0, window,
376                                   property, XCB_ATOM_ANY, 0, 2048);
377         reply = xcb_get_property_reply(wm->conn, cookie, NULL);
378
379         dump_property(wm, property, reply);
380
381         free(reply);
382 }
383
384 /* We reuse some predefined, but otherwise useles atoms */
385 #define TYPE_WM_PROTOCOLS       XCB_ATOM_CUT_BUFFER0
386 #define TYPE_MOTIF_WM_HINTS     XCB_ATOM_CUT_BUFFER1
387 #define TYPE_NET_WM_STATE       XCB_ATOM_CUT_BUFFER2
388 #define TYPE_WM_NORMAL_HINTS    XCB_ATOM_CUT_BUFFER3
389
390 static void
391 weston_wm_window_read_properties(struct weston_wm_window *window)
392 {
393         struct weston_wm *wm = window->wm;
394         struct weston_shell_interface *shell_interface =
395                 &wm->server->compositor->shell_interface;
396
397 #define F(field) offsetof(struct weston_wm_window, field)
398         const struct {
399                 xcb_atom_t atom;
400                 xcb_atom_t type;
401                 int offset;
402         } props[] = {
403                 { XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, F(class) },
404                 { XCB_ATOM_WM_NAME, XCB_ATOM_STRING, F(name) },
405                 { XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, F(transient_for) },
406                 { wm->atom.wm_protocols, TYPE_WM_PROTOCOLS, F(protocols) },
407                 { wm->atom.wm_normal_hints, TYPE_WM_NORMAL_HINTS, F(protocols) },
408                 { wm->atom.net_wm_state, TYPE_NET_WM_STATE },
409                 { wm->atom.net_wm_window_type, XCB_ATOM_ATOM, F(type) },
410                 { wm->atom.net_wm_name, XCB_ATOM_STRING, F(name) },
411                 { wm->atom.net_wm_pid, XCB_ATOM_CARDINAL, F(pid) },
412                 { wm->atom.motif_wm_hints, TYPE_MOTIF_WM_HINTS, 0 },
413                 { wm->atom.wm_client_machine, XCB_ATOM_WM_CLIENT_MACHINE, F(machine) },
414         };
415 #undef F
416
417         xcb_get_property_cookie_t cookie[ARRAY_LENGTH(props)];
418         xcb_get_property_reply_t *reply;
419         void *p;
420         uint32_t *xid;
421         xcb_atom_t *atom;
422         uint32_t i;
423         char name[1024];
424
425         if (!window->properties_dirty)
426                 return;
427         window->properties_dirty = 0;
428
429         for (i = 0; i < ARRAY_LENGTH(props); i++)
430                 cookie[i] = xcb_get_property(wm->conn,
431                                              0, /* delete */
432                                              window->id,
433                                              props[i].atom,
434                                              XCB_ATOM_ANY, 0, 2048);
435
436         window->decorate = window->override_redirect ? 0 : MWM_DECOR_EVERYTHING;
437         window->size_hints.flags = 0;
438         window->motif_hints.flags = 0;
439         window->delete_window = 0;
440
441         for (i = 0; i < ARRAY_LENGTH(props); i++)  {
442                 reply = xcb_get_property_reply(wm->conn, cookie[i], NULL);
443                 if (!reply)
444                         /* Bad window, typically */
445                         continue;
446                 if (reply->type == XCB_ATOM_NONE) {
447                         /* No such property */
448                         free(reply);
449                         continue;
450                 }
451
452                 p = ((char *) window + props[i].offset);
453
454                 switch (props[i].type) {
455                 case XCB_ATOM_WM_CLIENT_MACHINE:
456                 case XCB_ATOM_STRING:
457                         /* FIXME: We're using this for both string and
458                            utf8_string */
459                         if (*(char **) p)
460                                 free(*(char **) p);
461
462                         *(char **) p =
463                                 strndup(xcb_get_property_value(reply),
464                                         xcb_get_property_value_length(reply));
465                         break;
466                 case XCB_ATOM_WINDOW:
467                         xid = xcb_get_property_value(reply);
468                         if (!wm_lookup_window(wm, *xid, p))
469                                 weston_log("XCB_ATOM_WINDOW contains window"
470                                            " id not found in hash table.\n");
471                         break;
472                 case XCB_ATOM_CARDINAL:
473                 case XCB_ATOM_ATOM:
474                         atom = xcb_get_property_value(reply);
475                         *(xcb_atom_t *) p = *atom;
476                         break;
477                 case TYPE_WM_PROTOCOLS:
478                         atom = xcb_get_property_value(reply);
479                         for (i = 0; i < reply->value_len; i++)
480                                 if (atom[i] == wm->atom.wm_delete_window) {
481                                         window->delete_window = 1;
482                                         break;
483                                 }
484                         break;
485                 case TYPE_WM_NORMAL_HINTS:
486                         memcpy(&window->size_hints,
487                                xcb_get_property_value(reply),
488                                sizeof window->size_hints);
489                         break;
490                 case TYPE_NET_WM_STATE:
491                         window->fullscreen = 0;
492                         atom = xcb_get_property_value(reply);
493                         for (i = 0; i < reply->value_len; i++) {
494                                 if (atom[i] == wm->atom.net_wm_state_fullscreen)
495                                         window->fullscreen = 1;
496                                 if (atom[i] == wm->atom.net_wm_state_maximized_vert)
497                                         window->maximized_vert = 1;
498                                 if (atom[i] == wm->atom.net_wm_state_maximized_horz)
499                                         window->maximized_horz = 1;
500                         }
501                         break;
502                 case TYPE_MOTIF_WM_HINTS:
503                         memcpy(&window->motif_hints,
504                                xcb_get_property_value(reply),
505                                sizeof window->motif_hints);
506                         if (window->motif_hints.flags & MWM_HINTS_DECORATIONS) {
507                                 if (window->motif_hints.decorations & MWM_DECOR_ALL)
508                                         /* MWM_DECOR_ALL means all except the other values listed. */
509                                         window->decorate =
510                                                 MWM_DECOR_EVERYTHING & (~window->motif_hints.decorations);
511                                 else
512                                         window->decorate =
513                                                 window->motif_hints.decorations;
514                         }
515                         break;
516                 default:
517                         break;
518                 }
519                 free(reply);
520         }
521
522         if (window->pid > 0) {
523                 gethostname(name, sizeof(name));
524                 for (i = 0; i < sizeof(name); i++) {
525                         if (name[i] == '\0')
526                                 break;
527                 }
528                 if (i == sizeof(name))
529                         name[0] = '\0'; /* ignore stupid hostnames */
530
531                 /* this is only one heuristic to guess the PID of a client is
532                 * valid, assuming it's compliant with icccm and ewmh.
533                 * Non-compliants and remote applications of course fail. */
534                 if (!window->machine || strcmp(window->machine, name))
535                         window->pid = 0;
536         }
537
538         if (window->shsurf && window->name)
539                 shell_interface->set_title(window->shsurf, window->name);
540         if (window->frame && window->name)
541                 frame_set_title(window->frame, window->name);
542         if (window->shsurf && window->pid > 0)
543                 shell_interface->set_pid(window->shsurf, window->pid);
544 }
545
546 static void
547 weston_wm_window_get_frame_size(struct weston_wm_window *window,
548                                 int *width, int *height)
549 {
550         struct theme *t = window->wm->theme;
551
552         if (window->fullscreen) {
553                 *width = window->width;
554                 *height = window->height;
555         } else if (window->decorate && window->frame) {
556                 *width = frame_width(window->frame);
557                 *height = frame_height(window->frame);
558         } else {
559                 *width = window->width + t->margin * 2;
560                 *height = window->height + t->margin * 2;
561         }
562 }
563
564 static void
565 weston_wm_window_get_child_position(struct weston_wm_window *window,
566                                     int *x, int *y)
567 {
568         struct theme *t = window->wm->theme;
569
570         if (window->fullscreen) {
571                 *x = 0;
572                 *y = 0;
573         } else if (window->decorate && window->frame) {
574                 frame_interior(window->frame, x, y, NULL, NULL);
575         } else {
576                 *x = t->margin;
577                 *y = t->margin;
578         }
579 }
580
581 static void
582 weston_wm_window_send_configure_notify(struct weston_wm_window *window)
583 {
584         xcb_configure_notify_event_t configure_notify;
585         struct weston_wm *wm = window->wm;
586         int x, y;
587
588         weston_wm_window_get_child_position(window, &x, &y);
589         configure_notify.response_type = XCB_CONFIGURE_NOTIFY;
590         configure_notify.pad0 = 0;
591         configure_notify.event = window->id;
592         configure_notify.window = window->id;
593         configure_notify.above_sibling = XCB_WINDOW_NONE;
594         configure_notify.x = x;
595         configure_notify.y = y;
596         configure_notify.width = window->width;
597         configure_notify.height = window->height;
598         configure_notify.border_width = 0;
599         configure_notify.override_redirect = 0;
600         configure_notify.pad1 = 0;
601
602         xcb_send_event(wm->conn, 0, window->id,
603                        XCB_EVENT_MASK_STRUCTURE_NOTIFY,
604                        (char *) &configure_notify);
605 }
606
607 static void
608 weston_wm_handle_configure_request(struct weston_wm *wm, xcb_generic_event_t *event)
609 {
610         xcb_configure_request_event_t *configure_request =
611                 (xcb_configure_request_event_t *) event;
612         struct weston_wm_window *window;
613         uint32_t mask, values[16];
614         int x, y, width, height, i = 0;
615
616         wm_log("XCB_CONFIGURE_REQUEST (window %d) %d,%d @ %dx%d\n",
617                configure_request->window,
618                configure_request->x, configure_request->y,
619                configure_request->width, configure_request->height);
620
621         if (!wm_lookup_window(wm, configure_request->window, &window))
622                 return;
623
624         if (window->fullscreen) {
625                 weston_wm_window_send_configure_notify(window);
626                 return;
627         }
628
629         if (configure_request->value_mask & XCB_CONFIG_WINDOW_WIDTH)
630                 window->width = configure_request->width;
631         if (configure_request->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
632                 window->height = configure_request->height;
633
634         if (window->frame)
635                 frame_resize_inside(window->frame, window->width, window->height);
636
637         weston_wm_window_get_child_position(window, &x, &y);
638         values[i++] = x;
639         values[i++] = y;
640         values[i++] = window->width;
641         values[i++] = window->height;
642         values[i++] = 0;
643         mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
644                 XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT |
645                 XCB_CONFIG_WINDOW_BORDER_WIDTH;
646         if (configure_request->value_mask & XCB_CONFIG_WINDOW_SIBLING) {
647                 values[i++] = configure_request->sibling;
648                 mask |= XCB_CONFIG_WINDOW_SIBLING;
649         }
650         if (configure_request->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) {
651                 values[i++] = configure_request->stack_mode;
652                 mask |= XCB_CONFIG_WINDOW_STACK_MODE;
653         }
654
655         xcb_configure_window(wm->conn, window->id, mask, values);
656
657         weston_wm_window_get_frame_size(window, &width, &height);
658         values[0] = width;
659         values[1] = height;
660         mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
661         xcb_configure_window(wm->conn, window->frame_id, mask, values);
662
663         weston_wm_window_schedule_repaint(window);
664 }
665
666 static int
667 our_resource(struct weston_wm *wm, uint32_t id)
668 {
669         const xcb_setup_t *setup;
670
671         setup = xcb_get_setup(wm->conn);
672
673         return (id & ~setup->resource_id_mask) == setup->resource_id_base;
674 }
675
676 static void
677 weston_wm_handle_configure_notify(struct weston_wm *wm, xcb_generic_event_t *event)
678 {
679         xcb_configure_notify_event_t *configure_notify =
680                 (xcb_configure_notify_event_t *) event;
681         struct weston_wm_window *window;
682
683         wm_log("XCB_CONFIGURE_NOTIFY (window %d) %d,%d @ %dx%d\n",
684                configure_notify->window,
685                configure_notify->x, configure_notify->y,
686                configure_notify->width, configure_notify->height);
687
688         if (!wm_lookup_window(wm, configure_notify->window, &window))
689                 return;
690
691         window->x = configure_notify->x;
692         window->y = configure_notify->y;
693         if (window->override_redirect) {
694                 window->width = configure_notify->width;
695                 window->height = configure_notify->height;
696                 if (window->frame)
697                         frame_resize_inside(window->frame,
698                                             window->width, window->height);
699         }
700 }
701
702 static void
703 weston_wm_kill_client(struct wl_listener *listener, void *data)
704 {
705         struct weston_surface *surface = data;
706         struct weston_wm_window *window = get_wm_window(surface);
707         if (!window)
708                 return;
709
710         if (window->pid > 0)
711                 kill(window->pid, SIGKILL);
712 }
713
714 static void
715 weston_wm_create_surface(struct wl_listener *listener, void *data)
716 {
717         struct weston_surface *surface = data;
718         struct weston_wm *wm =
719                 container_of(listener,
720                              struct weston_wm, create_surface_listener);
721         struct weston_wm_window *window;
722
723         if (wl_resource_get_client(surface->resource) != wm->server->client)
724                 return;
725
726         wl_list_for_each(window, &wm->unpaired_window_list, link)
727                 if (window->surface_id ==
728                     wl_resource_get_id(surface->resource)) {
729                         xserver_map_shell_surface(window, surface);
730                         window->surface_id = 0;
731                         wl_list_remove(&window->link);
732                         break;
733                 }
734 }
735
736 static void
737 weston_wm_send_focus_window(struct weston_wm *wm,
738                             struct weston_wm_window *window)
739 {
740         xcb_client_message_event_t client_message;
741
742         if (window) {
743                 uint32_t values[1];
744
745                 if (window->override_redirect)
746                         return;
747
748                 client_message.response_type = XCB_CLIENT_MESSAGE;
749                 client_message.format = 32;
750                 client_message.window = window->id;
751                 client_message.type = wm->atom.wm_protocols;
752                 client_message.data.data32[0] = wm->atom.wm_take_focus;
753                 client_message.data.data32[1] = XCB_TIME_CURRENT_TIME;
754
755                 xcb_send_event(wm->conn, 0, window->id,
756                                XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
757                                (char *) &client_message);
758
759                 xcb_set_input_focus (wm->conn, XCB_INPUT_FOCUS_POINTER_ROOT,
760                                      window->id, XCB_TIME_CURRENT_TIME);
761
762                 values[0] = XCB_STACK_MODE_ABOVE;
763                 xcb_configure_window (wm->conn, window->frame_id,
764                                       XCB_CONFIG_WINDOW_STACK_MODE, values);
765         } else {
766                 xcb_set_input_focus (wm->conn,
767                                      XCB_INPUT_FOCUS_POINTER_ROOT,
768                                      XCB_NONE,
769                                      XCB_TIME_CURRENT_TIME);
770         }
771 }
772
773 static void
774 weston_wm_window_activate(struct wl_listener *listener, void *data)
775 {
776         struct weston_surface *surface = data;
777         struct weston_wm_window *window = NULL;
778         struct weston_wm *wm =
779                 container_of(listener, struct weston_wm, activate_listener);
780
781         if (surface) {
782                 window = get_wm_window(surface);
783         }
784
785         weston_wm_send_focus_window(wm, window);
786
787         if (wm->focus_window) {
788                 if (wm->focus_window->frame)
789                         frame_unset_flag(wm->focus_window->frame, FRAME_FLAG_ACTIVE);
790                 weston_wm_window_schedule_repaint(wm->focus_window);
791         }
792         wm->focus_window = window;
793         if (wm->focus_window) {
794                 if (wm->focus_window->frame)
795                         frame_set_flag(wm->focus_window->frame, FRAME_FLAG_ACTIVE);
796                 weston_wm_window_schedule_repaint(wm->focus_window);
797         }
798 }
799
800 static void
801 weston_wm_window_transform(struct wl_listener *listener, void *data)
802 {
803         struct weston_surface *surface = data;
804         struct weston_wm_window *window = get_wm_window(surface);
805         struct weston_wm *wm =
806                 container_of(listener, struct weston_wm, transform_listener);
807         uint32_t mask, values[2];
808
809         if (!window || !wm)
810                 return;
811
812         if (!window->view || !weston_view_is_mapped(window->view))
813                 return;
814
815         if (window->x != window->view->geometry.x ||
816             window->y != window->view->geometry.y) {
817                 values[0] = window->view->geometry.x;
818                 values[1] = window->view->geometry.y;
819                 mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y;
820
821                 xcb_configure_window(wm->conn, window->frame_id, mask, values);
822                 xcb_flush(wm->conn);
823         }
824 }
825
826 #define ICCCM_WITHDRAWN_STATE   0
827 #define ICCCM_NORMAL_STATE      1
828 #define ICCCM_ICONIC_STATE      3
829
830 static void
831 weston_wm_window_set_wm_state(struct weston_wm_window *window, int32_t state)
832 {
833         struct weston_wm *wm = window->wm;
834         uint32_t property[2];
835
836         property[0] = state;
837         property[1] = XCB_WINDOW_NONE;
838
839         xcb_change_property(wm->conn,
840                             XCB_PROP_MODE_REPLACE,
841                             window->id,
842                             wm->atom.wm_state,
843                             wm->atom.wm_state,
844                             32, /* format */
845                             2, property);
846 }
847
848 static void
849 weston_wm_window_set_net_wm_state(struct weston_wm_window *window)
850 {
851         struct weston_wm *wm = window->wm;
852         uint32_t property[3];
853         int i;
854
855         i = 0;
856         if (window->fullscreen)
857                 property[i++] = wm->atom.net_wm_state_fullscreen;
858         if (window->maximized_vert)
859                 property[i++] = wm->atom.net_wm_state_maximized_vert;
860         if (window->maximized_horz)
861                 property[i++] = wm->atom.net_wm_state_maximized_horz;
862
863         xcb_change_property(wm->conn,
864                             XCB_PROP_MODE_REPLACE,
865                             window->id,
866                             wm->atom.net_wm_state,
867                             XCB_ATOM_ATOM,
868                             32, /* format */
869                             i, property);
870 }
871
872 static void
873 weston_wm_window_create_frame(struct weston_wm_window *window)
874 {
875         struct weston_wm *wm = window->wm;
876         uint32_t values[3];
877         int x, y, width, height;
878         int buttons = FRAME_BUTTON_CLOSE;
879
880         if (window->decorate & MWM_DECOR_MAXIMIZE)
881                 buttons |= FRAME_BUTTON_MAXIMIZE;
882
883         window->frame = frame_create(window->wm->theme,
884                                      window->width, window->height,
885                                      buttons, window->name);
886         frame_resize_inside(window->frame, window->width, window->height);
887
888         weston_wm_window_get_frame_size(window, &width, &height);
889         weston_wm_window_get_child_position(window, &x, &y);
890
891         values[0] = wm->screen->black_pixel;
892         values[1] =
893                 XCB_EVENT_MASK_KEY_PRESS |
894                 XCB_EVENT_MASK_KEY_RELEASE |
895                 XCB_EVENT_MASK_BUTTON_PRESS |
896                 XCB_EVENT_MASK_BUTTON_RELEASE |
897                 XCB_EVENT_MASK_POINTER_MOTION |
898                 XCB_EVENT_MASK_ENTER_WINDOW |
899                 XCB_EVENT_MASK_LEAVE_WINDOW |
900                 XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
901                 XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT;
902         values[2] = wm->colormap;
903
904         window->frame_id = xcb_generate_id(wm->conn);
905         xcb_create_window(wm->conn,
906                           32,
907                           window->frame_id,
908                           wm->screen->root,
909                           0, 0,
910                           width, height,
911                           0,
912                           XCB_WINDOW_CLASS_INPUT_OUTPUT,
913                           wm->visual_id,
914                           XCB_CW_BORDER_PIXEL |
915                           XCB_CW_EVENT_MASK |
916                           XCB_CW_COLORMAP, values);
917
918         xcb_reparent_window(wm->conn, window->id, window->frame_id, x, y);
919
920         values[0] = 0;
921         xcb_configure_window(wm->conn, window->id,
922                              XCB_CONFIG_WINDOW_BORDER_WIDTH, values);
923
924         window->cairo_surface =
925                 cairo_xcb_surface_create_with_xrender_format(wm->conn,
926                                                              wm->screen,
927                                                              window->frame_id,
928                                                              &wm->format_rgba,
929                                                              width, height);
930
931         hash_table_insert(wm->window_hash, window->frame_id, window);
932 }
933
934 /*
935  * Sets the _NET_WM_DESKTOP property for the window to 'desktop'.
936  * Passing a <0 desktop value deletes the property.
937  */
938 static void
939 weston_wm_window_set_virtual_desktop(struct weston_wm_window *window,
940                                      int desktop)
941 {
942         if (desktop >= 0) {
943                 xcb_change_property(window->wm->conn,
944                                     XCB_PROP_MODE_REPLACE,
945                                     window->id,
946                                     window->wm->atom.net_wm_desktop,
947                                     XCB_ATOM_CARDINAL,
948                                     32, /* format */
949                                     1, &desktop);
950         } else {
951                 xcb_delete_property(window->wm->conn,
952                                     window->id,
953                                     window->wm->atom.net_wm_desktop);
954         }
955 }
956
957 static void
958 weston_wm_handle_map_request(struct weston_wm *wm, xcb_generic_event_t *event)
959 {
960         xcb_map_request_event_t *map_request =
961                 (xcb_map_request_event_t *) event;
962         struct weston_wm_window *window;
963
964         if (our_resource(wm, map_request->window)) {
965                 wm_log("XCB_MAP_REQUEST (window %d, ours)\n",
966                        map_request->window);
967                 return;
968         }
969
970         if (!wm_lookup_window(wm, map_request->window, &window))
971                 return;
972
973         weston_wm_window_read_properties(window);
974
975         if (window->frame_id == XCB_WINDOW_NONE)
976                 weston_wm_window_create_frame(window);
977
978         wm_log("XCB_MAP_REQUEST (window %d, %p, frame %d)\n",
979                window->id, window, window->frame_id);
980
981         weston_wm_window_set_wm_state(window, ICCCM_NORMAL_STATE);
982         weston_wm_window_set_net_wm_state(window);
983         weston_wm_window_set_virtual_desktop(window, 0);
984
985         xcb_map_window(wm->conn, map_request->window);
986         xcb_map_window(wm->conn, window->frame_id);
987 }
988
989 static void
990 weston_wm_handle_map_notify(struct weston_wm *wm, xcb_generic_event_t *event)
991 {
992         xcb_map_notify_event_t *map_notify = (xcb_map_notify_event_t *) event;
993
994         if (our_resource(wm, map_notify->window)) {
995                 wm_log("XCB_MAP_NOTIFY (window %d, ours)\n",
996                        map_notify->window);
997                         return;
998         }
999
1000         wm_log("XCB_MAP_NOTIFY (window %d)\n", map_notify->window);
1001 }
1002
1003 static void
1004 weston_wm_handle_unmap_notify(struct weston_wm *wm, xcb_generic_event_t *event)
1005 {
1006         xcb_unmap_notify_event_t *unmap_notify =
1007                 (xcb_unmap_notify_event_t *) event;
1008         struct weston_wm_window *window;
1009
1010         wm_log("XCB_UNMAP_NOTIFY (window %d, event %d%s)\n",
1011                unmap_notify->window,
1012                unmap_notify->event,
1013                our_resource(wm, unmap_notify->window) ? ", ours" : "");
1014
1015         if (our_resource(wm, unmap_notify->window))
1016                 return;
1017
1018         if (unmap_notify->response_type & SEND_EVENT_MASK)
1019                 /* We just ignore the ICCCM 4.1.4 synthetic unmap notify
1020                  * as it may come in after we've destroyed the window. */
1021                 return;
1022
1023         if (!wm_lookup_window(wm, unmap_notify->window, &window))
1024                 return;
1025
1026         if (window->surface_id) {
1027                 /* Make sure we're not on the unpaired surface list or we
1028                  * could be assigned a surface during surface creation that
1029                  * was mapped before this unmap request.
1030                  */
1031                 wl_list_remove(&window->link);
1032                 window->surface_id = 0;
1033         }
1034         if (wm->focus_window == window)
1035                 wm->focus_window = NULL;
1036         if (window->surface)
1037                 wl_list_remove(&window->surface_destroy_listener.link);
1038         window->surface = NULL;
1039         window->shsurf = NULL;
1040         window->view = NULL;
1041
1042         weston_wm_window_set_wm_state(window, ICCCM_WITHDRAWN_STATE);
1043         weston_wm_window_set_virtual_desktop(window, -1);
1044
1045         xcb_unmap_window(wm->conn, window->frame_id);
1046 }
1047
1048 static void
1049 weston_wm_window_draw_decoration(void *data)
1050 {
1051         struct weston_wm_window *window = data;
1052         struct weston_wm *wm = window->wm;
1053         struct theme *t = wm->theme;
1054         cairo_t *cr;
1055         int x, y, width, height;
1056         int32_t input_x, input_y, input_w, input_h;
1057         struct weston_shell_interface *shell_interface =
1058                 &wm->server->compositor->shell_interface;
1059         uint32_t flags = 0;
1060
1061         weston_wm_window_read_properties(window);
1062
1063         window->repaint_source = NULL;
1064
1065         weston_wm_window_get_frame_size(window, &width, &height);
1066         weston_wm_window_get_child_position(window, &x, &y);
1067
1068         cairo_xcb_surface_set_size(window->cairo_surface, width, height);
1069         cr = cairo_create(window->cairo_surface);
1070
1071         if (window->fullscreen) {
1072                 /* nothing */
1073         } else if (window->decorate) {
1074                 if (wm->focus_window == window)
1075                         flags |= THEME_FRAME_ACTIVE;
1076
1077                 frame_repaint(window->frame, cr);
1078         } else {
1079                 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1080                 cairo_set_source_rgba(cr, 0, 0, 0, 0);
1081                 cairo_paint(cr);
1082
1083                 render_shadow(cr, t->shadow, 2, 2, width + 8, height + 8, 64, 64);
1084         }
1085
1086         cairo_destroy(cr);
1087
1088         if (window->surface) {
1089                 pixman_region32_fini(&window->surface->pending.opaque);
1090                 if(window->has_alpha) {
1091                         pixman_region32_init(&window->surface->pending.opaque);
1092                 } else {
1093                         /* We leave an extra pixel around the X window area to
1094                          * make sure we don't sample from the undefined alpha
1095                          * channel when filtering. */
1096                         pixman_region32_init_rect(&window->surface->pending.opaque,
1097                                                   x - 1, y - 1,
1098                                                   window->width + 2,
1099                                                   window->height + 2);
1100                 }
1101                 if (window->view)
1102                         weston_view_geometry_dirty(window->view);
1103
1104                 pixman_region32_fini(&window->surface->pending.input);
1105
1106                 if (window->decorate && !window->fullscreen) {
1107                         frame_input_rect(window->frame, &input_x, &input_y,
1108                                          &input_w, &input_h);
1109                 } else {
1110                         input_x = x;
1111                         input_y = y;
1112                         input_w = width;
1113                         input_h = height;
1114                 }
1115
1116                 pixman_region32_init_rect(&window->surface->pending.input,
1117                                           input_x, input_y, input_w, input_h);
1118
1119                 shell_interface->set_window_geometry(window->shsurf,
1120                                                      input_x, input_y, input_w, input_h);
1121         }
1122 }
1123
1124 static void
1125 weston_wm_window_schedule_repaint(struct weston_wm_window *window)
1126 {
1127         struct weston_wm *wm = window->wm;
1128         int width, height;
1129
1130         if (window->frame_id == XCB_WINDOW_NONE) {
1131                 if (window->surface != NULL) {
1132                         weston_wm_window_get_frame_size(window, &width, &height);
1133                         pixman_region32_fini(&window->surface->pending.opaque);
1134                         if(window->has_alpha) {
1135                                 pixman_region32_init(&window->surface->pending.opaque);
1136                         } else {
1137                                 pixman_region32_init_rect(&window->surface->pending.opaque, 0, 0,
1138                                                           width, height);
1139                         }
1140                         if (window->view)
1141                                 weston_view_geometry_dirty(window->view);
1142                 }
1143                 return;
1144         }
1145
1146         if (window->repaint_source)
1147                 return;
1148
1149         window->repaint_source =
1150                 wl_event_loop_add_idle(wm->server->loop,
1151                                        weston_wm_window_draw_decoration,
1152                                        window);
1153 }
1154
1155 static void
1156 weston_wm_handle_property_notify(struct weston_wm *wm, xcb_generic_event_t *event)
1157 {
1158         xcb_property_notify_event_t *property_notify =
1159                 (xcb_property_notify_event_t *) event;
1160         struct weston_wm_window *window;
1161
1162         if (!wm_lookup_window(wm, property_notify->window, &window))
1163                 return;
1164
1165         window->properties_dirty = 1;
1166
1167         wm_log("XCB_PROPERTY_NOTIFY: window %d, ", property_notify->window);
1168         if (property_notify->state == XCB_PROPERTY_DELETE)
1169                 wm_log("deleted\n");
1170         else
1171                 read_and_dump_property(wm, property_notify->window,
1172                                        property_notify->atom);
1173
1174         if (property_notify->atom == wm->atom.net_wm_name ||
1175             property_notify->atom == XCB_ATOM_WM_NAME)
1176                 weston_wm_window_schedule_repaint(window);
1177 }
1178
1179 static void
1180 weston_wm_window_create(struct weston_wm *wm,
1181                         xcb_window_t id, int width, int height, int x, int y, int override)
1182 {
1183         struct weston_wm_window *window;
1184         uint32_t values[1];
1185         xcb_get_geometry_cookie_t geometry_cookie;
1186         xcb_get_geometry_reply_t *geometry_reply;
1187
1188         window = zalloc(sizeof *window);
1189         if (window == NULL) {
1190                 wm_log("failed to allocate window\n");
1191                 return;
1192         }
1193
1194         geometry_cookie = xcb_get_geometry(wm->conn, id);
1195
1196         values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE |
1197                     XCB_EVENT_MASK_FOCUS_CHANGE;
1198         xcb_change_window_attributes(wm->conn, id, XCB_CW_EVENT_MASK, values);
1199
1200         window->wm = wm;
1201         window->id = id;
1202         window->properties_dirty = 1;
1203         window->override_redirect = override;
1204         window->width = width;
1205         window->height = height;
1206         window->x = x;
1207         window->y = y;
1208
1209         geometry_reply = xcb_get_geometry_reply(wm->conn, geometry_cookie, NULL);
1210         /* technically we should use XRender and check the visual format's
1211         alpha_mask, but checking depth is simpler and works in all known cases */
1212         if(geometry_reply != NULL)
1213                 window->has_alpha = geometry_reply->depth == 32;
1214         free(geometry_reply);
1215
1216         hash_table_insert(wm->window_hash, id, window);
1217 }
1218
1219 static void
1220 weston_wm_window_destroy(struct weston_wm_window *window)
1221 {
1222         struct weston_wm *wm = window->wm;
1223
1224         if (window->repaint_source)
1225                 wl_event_source_remove(window->repaint_source);
1226         if (window->cairo_surface)
1227                 cairo_surface_destroy(window->cairo_surface);
1228
1229         if (window->frame_id) {
1230                 xcb_reparent_window(wm->conn, window->id, wm->wm_window, 0, 0);
1231                 xcb_destroy_window(wm->conn, window->frame_id);
1232                 weston_wm_window_set_wm_state(window, ICCCM_WITHDRAWN_STATE);
1233                 weston_wm_window_set_virtual_desktop(window, -1);
1234                 hash_table_remove(wm->window_hash, window->frame_id);
1235                 window->frame_id = XCB_WINDOW_NONE;
1236         }
1237
1238         if (window->surface_id)
1239                 wl_list_remove(&window->link);
1240
1241         if (window->surface)
1242                 wl_list_remove(&window->surface_destroy_listener.link);
1243
1244         hash_table_remove(window->wm->window_hash, window->id);
1245         free(window);
1246 }
1247
1248 static void
1249 weston_wm_handle_create_notify(struct weston_wm *wm, xcb_generic_event_t *event)
1250 {
1251         xcb_create_notify_event_t *create_notify =
1252                 (xcb_create_notify_event_t *) event;
1253
1254         wm_log("XCB_CREATE_NOTIFY (window %d, width %d, height %d%s%s)\n",
1255                create_notify->window,
1256                create_notify->width, create_notify->height,
1257                create_notify->override_redirect ? ", override" : "",
1258                our_resource(wm, create_notify->window) ? ", ours" : "");
1259
1260         if (our_resource(wm, create_notify->window))
1261                 return;
1262
1263         weston_wm_window_create(wm, create_notify->window,
1264                                 create_notify->width, create_notify->height,
1265                                 create_notify->x, create_notify->y,
1266                                 create_notify->override_redirect);
1267 }
1268
1269 static void
1270 weston_wm_handle_destroy_notify(struct weston_wm *wm, xcb_generic_event_t *event)
1271 {
1272         xcb_destroy_notify_event_t *destroy_notify =
1273                 (xcb_destroy_notify_event_t *) event;
1274         struct weston_wm_window *window;
1275
1276         wm_log("XCB_DESTROY_NOTIFY, win %d, event %d%s\n",
1277                destroy_notify->window,
1278                destroy_notify->event,
1279                our_resource(wm, destroy_notify->window) ? ", ours" : "");
1280
1281         if (our_resource(wm, destroy_notify->window))
1282                 return;
1283
1284         if (!wm_lookup_window(wm, destroy_notify->window, &window))
1285                 return;
1286
1287         weston_wm_window_destroy(window);
1288 }
1289
1290 static void
1291 weston_wm_handle_reparent_notify(struct weston_wm *wm, xcb_generic_event_t *event)
1292 {
1293         xcb_reparent_notify_event_t *reparent_notify =
1294                 (xcb_reparent_notify_event_t *) event;
1295         struct weston_wm_window *window;
1296
1297         wm_log("XCB_REPARENT_NOTIFY (window %d, parent %d, event %d)\n",
1298                reparent_notify->window,
1299                reparent_notify->parent,
1300                reparent_notify->event);
1301
1302         if (reparent_notify->parent == wm->screen->root) {
1303                 weston_wm_window_create(wm, reparent_notify->window, 10, 10,
1304                                         reparent_notify->x, reparent_notify->y,
1305                                         reparent_notify->override_redirect);
1306         } else if (!our_resource(wm, reparent_notify->parent)) {
1307                 if (!wm_lookup_window(wm, reparent_notify->window, &window))
1308                         return;
1309                 weston_wm_window_destroy(window);
1310         }
1311 }
1312
1313 struct weston_seat *
1314 weston_wm_pick_seat(struct weston_wm *wm)
1315 {
1316         return container_of(wm->server->compositor->seat_list.next,
1317                             struct weston_seat, link);
1318 }
1319
1320 static struct weston_seat *
1321 weston_wm_pick_seat_for_window(struct weston_wm_window *window)
1322 {
1323         struct weston_wm *wm = window->wm;
1324         struct weston_seat *seat, *s;
1325
1326         seat = NULL;
1327         wl_list_for_each(s, &wm->server->compositor->seat_list, link) {
1328                 struct weston_pointer *pointer = weston_seat_get_pointer(s);
1329                 struct weston_pointer *old_pointer =
1330                         weston_seat_get_pointer(seat);
1331
1332                 if (pointer && pointer->focus &&
1333                     pointer->focus->surface == window->surface &&
1334                     pointer->button_count > 0 &&
1335                     (!seat ||
1336                      pointer->grab_serial -
1337                      old_pointer->grab_serial < (1 << 30)))
1338                         seat = s;
1339         }
1340
1341         return seat;
1342 }
1343
1344 static void
1345 weston_wm_window_handle_moveresize(struct weston_wm_window *window,
1346                                    xcb_client_message_event_t *client_message)
1347 {
1348         static const int map[] = {
1349                 THEME_LOCATION_RESIZING_TOP_LEFT,
1350                 THEME_LOCATION_RESIZING_TOP,
1351                 THEME_LOCATION_RESIZING_TOP_RIGHT,
1352                 THEME_LOCATION_RESIZING_RIGHT,
1353                 THEME_LOCATION_RESIZING_BOTTOM_RIGHT,
1354                 THEME_LOCATION_RESIZING_BOTTOM,
1355                 THEME_LOCATION_RESIZING_BOTTOM_LEFT,
1356                 THEME_LOCATION_RESIZING_LEFT
1357         };
1358
1359         struct weston_wm *wm = window->wm;
1360         struct weston_seat *seat = weston_wm_pick_seat_for_window(window);
1361         struct weston_pointer *pointer = weston_seat_get_pointer(seat);
1362         int detail;
1363         struct weston_shell_interface *shell_interface =
1364                 &wm->server->compositor->shell_interface;
1365
1366         if (!pointer || pointer->button_count != 1
1367             || !pointer->focus
1368             || pointer->focus->surface != window->surface)
1369                 return;
1370
1371         detail = client_message->data.data32[2];
1372         switch (detail) {
1373         case _NET_WM_MOVERESIZE_MOVE:
1374                 shell_interface->move(window->shsurf, pointer);
1375                 break;
1376         case _NET_WM_MOVERESIZE_SIZE_TOPLEFT:
1377         case _NET_WM_MOVERESIZE_SIZE_TOP:
1378         case _NET_WM_MOVERESIZE_SIZE_TOPRIGHT:
1379         case _NET_WM_MOVERESIZE_SIZE_RIGHT:
1380         case _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT:
1381         case _NET_WM_MOVERESIZE_SIZE_BOTTOM:
1382         case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT:
1383         case _NET_WM_MOVERESIZE_SIZE_LEFT:
1384                 shell_interface->resize(window->shsurf, pointer, map[detail]);
1385                 break;
1386         case _NET_WM_MOVERESIZE_CANCEL:
1387                 break;
1388         }
1389 }
1390
1391 #define _NET_WM_STATE_REMOVE    0
1392 #define _NET_WM_STATE_ADD       1
1393 #define _NET_WM_STATE_TOGGLE    2
1394
1395 static int
1396 update_state(int action, int *state)
1397 {
1398         int new_state, changed;
1399
1400         switch (action) {
1401         case _NET_WM_STATE_REMOVE:
1402                 new_state = 0;
1403                 break;
1404         case _NET_WM_STATE_ADD:
1405                 new_state = 1;
1406                 break;
1407         case _NET_WM_STATE_TOGGLE:
1408                 new_state = !*state;
1409                 break;
1410         default:
1411                 return 0;
1412         }
1413
1414         changed = (*state != new_state);
1415         *state = new_state;
1416
1417         return changed;
1418 }
1419
1420 static void
1421 weston_wm_window_configure(void *data);
1422
1423 static void
1424 weston_wm_window_set_toplevel(struct weston_wm_window *window)
1425 {
1426         struct weston_shell_interface *shell_interface =
1427                 &window->wm->server->compositor->shell_interface;
1428
1429         shell_interface->set_toplevel(window->shsurf);
1430         window->width = window->saved_width;
1431         window->height = window->saved_height;
1432         if (window->frame)
1433                 frame_resize_inside(window->frame,
1434                                         window->width,
1435                                         window->height);
1436         weston_wm_window_configure(window);
1437 }
1438
1439 static inline bool
1440 weston_wm_window_is_maximized(struct weston_wm_window *window)
1441 {
1442         return window->maximized_horz && window->maximized_vert;
1443 }
1444
1445 static void
1446 weston_wm_window_handle_state(struct weston_wm_window *window,
1447                               xcb_client_message_event_t *client_message)
1448 {
1449         struct weston_wm *wm = window->wm;
1450         struct weston_shell_interface *shell_interface =
1451                 &wm->server->compositor->shell_interface;
1452         uint32_t action, property;
1453         int maximized = weston_wm_window_is_maximized(window);
1454
1455         action = client_message->data.data32[0];
1456         property = client_message->data.data32[1];
1457
1458         if (property == wm->atom.net_wm_state_fullscreen &&
1459             update_state(action, &window->fullscreen)) {
1460                 weston_wm_window_set_net_wm_state(window);
1461                 if (window->fullscreen) {
1462                         window->saved_width = window->width;
1463                         window->saved_height = window->height;
1464
1465                         if (window->shsurf)
1466                                 shell_interface->set_fullscreen(window->shsurf,
1467                                                                 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
1468                                                                 0, NULL);
1469                 } else {
1470                         if (window->shsurf)
1471                                 weston_wm_window_set_toplevel(window);
1472                 }
1473         } else {
1474                 if (property == wm->atom.net_wm_state_maximized_vert &&
1475                     update_state(action, &window->maximized_vert))
1476                         weston_wm_window_set_net_wm_state(window);
1477                 if (property == wm->atom.net_wm_state_maximized_horz &&
1478                     update_state(action, &window->maximized_horz))
1479                         weston_wm_window_set_net_wm_state(window);
1480
1481                 if (maximized != weston_wm_window_is_maximized(window)) {
1482                         if (weston_wm_window_is_maximized(window)) {
1483                                 window->saved_width = window->width;
1484                                 window->saved_height = window->height;
1485
1486                                 if (window->shsurf)
1487                                         shell_interface->set_maximized(window->shsurf);
1488                         } else if (window->shsurf) {
1489                                 weston_wm_window_set_toplevel(window);
1490                         }
1491                 }
1492         }
1493 }
1494
1495 static void
1496 surface_destroy(struct wl_listener *listener, void *data)
1497 {
1498         struct weston_wm_window *window =
1499                 container_of(listener,
1500                              struct weston_wm_window, surface_destroy_listener);
1501
1502         wm_log("surface for xid %d destroyed\n", window->id);
1503
1504         /* This should have been freed by the shell.
1505          * Don't try to use it later. */
1506         window->shsurf = NULL;
1507         window->surface = NULL;
1508         window->view = NULL;
1509 }
1510
1511 static void
1512 weston_wm_window_handle_surface_id(struct weston_wm_window *window,
1513                                    xcb_client_message_event_t *client_message)
1514 {
1515         struct weston_wm *wm = window->wm;
1516         struct wl_resource *resource;
1517
1518         if (window->surface_id != 0) {
1519                 wm_log("already have surface id for window %d\n", window->id);
1520                 return;
1521         }
1522
1523         /* Xwayland will send the wayland requests to create the
1524          * wl_surface before sending this client message.  Even so, we
1525          * can end up handling the X event before the wayland requests
1526          * and thus when we try to look up the surface ID, the surface
1527          * hasn't been created yet.  In that case put the window on
1528          * the unpaired window list and continue when the surface gets
1529          * created. */
1530         uint32_t id = client_message->data.data32[0];
1531         resource = wl_client_get_object(wm->server->client, id);
1532         if (resource) {
1533                 window->surface_id = 0;
1534                 xserver_map_shell_surface(window,
1535                                           wl_resource_get_user_data(resource));
1536         }
1537         else {
1538                 window->surface_id = id;
1539                 wl_list_insert(&wm->unpaired_window_list, &window->link);
1540         }
1541 }
1542
1543 static void
1544 weston_wm_handle_client_message(struct weston_wm *wm,
1545                                 xcb_generic_event_t *event)
1546 {
1547         xcb_client_message_event_t *client_message =
1548                 (xcb_client_message_event_t *) event;
1549         struct weston_wm_window *window;
1550
1551         wm_log("XCB_CLIENT_MESSAGE (%s %d %d %d %d %d win %d)\n",
1552                get_atom_name(wm->conn, client_message->type),
1553                client_message->data.data32[0],
1554                client_message->data.data32[1],
1555                client_message->data.data32[2],
1556                client_message->data.data32[3],
1557                client_message->data.data32[4],
1558                client_message->window);
1559
1560         /* The window may get created and destroyed before we actually
1561          * handle the message.  If it doesn't exist, bail.
1562          */
1563         if (!wm_lookup_window(wm, client_message->window, &window))
1564                 return;
1565
1566         if (client_message->type == wm->atom.net_wm_moveresize)
1567                 weston_wm_window_handle_moveresize(window, client_message);
1568         else if (client_message->type == wm->atom.net_wm_state)
1569                 weston_wm_window_handle_state(window, client_message);
1570         else if (client_message->type == wm->atom.wl_surface_id)
1571                 weston_wm_window_handle_surface_id(window, client_message);
1572 }
1573
1574 enum cursor_type {
1575         XWM_CURSOR_TOP,
1576         XWM_CURSOR_BOTTOM,
1577         XWM_CURSOR_LEFT,
1578         XWM_CURSOR_RIGHT,
1579         XWM_CURSOR_TOP_LEFT,
1580         XWM_CURSOR_TOP_RIGHT,
1581         XWM_CURSOR_BOTTOM_LEFT,
1582         XWM_CURSOR_BOTTOM_RIGHT,
1583         XWM_CURSOR_LEFT_PTR,
1584 };
1585
1586 /*
1587  * The following correspondences between file names and cursors was copied
1588  * from: https://bugs.kde.org/attachment.cgi?id=67313
1589  */
1590
1591 static const char *bottom_left_corners[] = {
1592         "bottom_left_corner",
1593         "sw-resize",
1594         "size_bdiag"
1595 };
1596
1597 static const char *bottom_right_corners[] = {
1598         "bottom_right_corner",
1599         "se-resize",
1600         "size_fdiag"
1601 };
1602
1603 static const char *bottom_sides[] = {
1604         "bottom_side",
1605         "s-resize",
1606         "size_ver"
1607 };
1608
1609 static const char *left_ptrs[] = {
1610         "left_ptr",
1611         "default",
1612         "top_left_arrow",
1613         "left-arrow"
1614 };
1615
1616 static const char *left_sides[] = {
1617         "left_side",
1618         "w-resize",
1619         "size_hor"
1620 };
1621
1622 static const char *right_sides[] = {
1623         "right_side",
1624         "e-resize",
1625         "size_hor"
1626 };
1627
1628 static const char *top_left_corners[] = {
1629         "top_left_corner",
1630         "nw-resize",
1631         "size_fdiag"
1632 };
1633
1634 static const char *top_right_corners[] = {
1635         "top_right_corner",
1636         "ne-resize",
1637         "size_bdiag"
1638 };
1639
1640 static const char *top_sides[] = {
1641         "top_side",
1642         "n-resize",
1643         "size_ver"
1644 };
1645
1646 struct cursor_alternatives {
1647         const char **names;
1648         size_t count;
1649 };
1650
1651 static const struct cursor_alternatives cursors[] = {
1652         {top_sides, ARRAY_LENGTH(top_sides)},
1653         {bottom_sides, ARRAY_LENGTH(bottom_sides)},
1654         {left_sides, ARRAY_LENGTH(left_sides)},
1655         {right_sides, ARRAY_LENGTH(right_sides)},
1656         {top_left_corners, ARRAY_LENGTH(top_left_corners)},
1657         {top_right_corners, ARRAY_LENGTH(top_right_corners)},
1658         {bottom_left_corners, ARRAY_LENGTH(bottom_left_corners)},
1659         {bottom_right_corners, ARRAY_LENGTH(bottom_right_corners)},
1660         {left_ptrs, ARRAY_LENGTH(left_ptrs)},
1661 };
1662
1663 static void
1664 weston_wm_create_cursors(struct weston_wm *wm)
1665 {
1666         const char *name;
1667         int i, count = ARRAY_LENGTH(cursors);
1668         size_t j;
1669
1670         wm->cursors = malloc(count * sizeof(xcb_cursor_t));
1671         for (i = 0; i < count; i++) {
1672                 for (j = 0; j < cursors[i].count; j++) {
1673                         name = cursors[i].names[j];
1674                         wm->cursors[i] =
1675                                 xcb_cursor_library_load_cursor(wm, name);
1676                         if (wm->cursors[i] != (xcb_cursor_t)-1)
1677                                 break;
1678                 }
1679         }
1680
1681         wm->last_cursor = -1;
1682 }
1683
1684 static void
1685 weston_wm_destroy_cursors(struct weston_wm *wm)
1686 {
1687         uint8_t i;
1688
1689         for (i = 0; i < ARRAY_LENGTH(cursors); i++)
1690                 xcb_free_cursor(wm->conn, wm->cursors[i]);
1691
1692         free(wm->cursors);
1693 }
1694
1695 static int
1696 get_cursor_for_location(enum theme_location location)
1697 {
1698         // int location = theme_get_location(t, x, y, width, height, 0);
1699
1700         switch (location) {
1701                 case THEME_LOCATION_RESIZING_TOP:
1702                         return XWM_CURSOR_TOP;
1703                 case THEME_LOCATION_RESIZING_BOTTOM:
1704                         return XWM_CURSOR_BOTTOM;
1705                 case THEME_LOCATION_RESIZING_LEFT:
1706                         return XWM_CURSOR_LEFT;
1707                 case THEME_LOCATION_RESIZING_RIGHT:
1708                         return XWM_CURSOR_RIGHT;
1709                 case THEME_LOCATION_RESIZING_TOP_LEFT:
1710                         return XWM_CURSOR_TOP_LEFT;
1711                 case THEME_LOCATION_RESIZING_TOP_RIGHT:
1712                         return XWM_CURSOR_TOP_RIGHT;
1713                 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
1714                         return XWM_CURSOR_BOTTOM_LEFT;
1715                 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
1716                         return XWM_CURSOR_BOTTOM_RIGHT;
1717                 case THEME_LOCATION_EXTERIOR:
1718                 case THEME_LOCATION_TITLEBAR:
1719                 default:
1720                         return XWM_CURSOR_LEFT_PTR;
1721         }
1722 }
1723
1724 static void
1725 weston_wm_window_set_cursor(struct weston_wm *wm, xcb_window_t window_id,
1726                             int cursor)
1727 {
1728         uint32_t cursor_value_list;
1729
1730         if (wm->last_cursor == cursor)
1731                 return;
1732
1733         wm->last_cursor = cursor;
1734
1735         cursor_value_list = wm->cursors[cursor];
1736         xcb_change_window_attributes (wm->conn, window_id,
1737                                       XCB_CW_CURSOR, &cursor_value_list);
1738         xcb_flush(wm->conn);
1739 }
1740
1741 static void
1742 weston_wm_window_close(struct weston_wm_window *window, xcb_timestamp_t time)
1743 {
1744         xcb_client_message_event_t client_message;
1745
1746         if (window->delete_window) {
1747                 client_message.response_type = XCB_CLIENT_MESSAGE;
1748                 client_message.format = 32;
1749                 client_message.window = window->id;
1750                 client_message.type = window->wm->atom.wm_protocols;
1751                 client_message.data.data32[0] =
1752                         window->wm->atom.wm_delete_window;
1753                 client_message.data.data32[1] = time;
1754
1755                 xcb_send_event(window->wm->conn, 0, window->id,
1756                                XCB_EVENT_MASK_NO_EVENT,
1757                                (char *) &client_message);
1758         } else {
1759                 xcb_kill_client(window->wm->conn, window->id);
1760         }
1761 }
1762
1763 static void
1764 weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event)
1765 {
1766         xcb_button_press_event_t *button = (xcb_button_press_event_t *) event;
1767         struct weston_shell_interface *shell_interface =
1768                 &wm->server->compositor->shell_interface;
1769         struct weston_seat *seat;
1770         struct weston_pointer *pointer;
1771         struct weston_wm_window *window;
1772         enum theme_location location;
1773         enum frame_button_state button_state;
1774         uint32_t button_id;
1775
1776         wm_log("XCB_BUTTON_%s (detail %d)\n",
1777                button->response_type == XCB_BUTTON_PRESS ?
1778                "PRESS" : "RELEASE", button->detail);
1779
1780         if (!wm_lookup_window(wm, button->event, &window) ||
1781             !window->decorate)
1782                 return;
1783
1784         if (button->detail != 1 && button->detail != 2)
1785                 return;
1786
1787         seat = weston_wm_pick_seat_for_window(window);
1788         pointer = weston_seat_get_pointer(seat);
1789
1790         button_state = button->response_type == XCB_BUTTON_PRESS ?
1791                 FRAME_BUTTON_PRESSED : FRAME_BUTTON_RELEASED;
1792         button_id = button->detail == 1 ? BTN_LEFT : BTN_RIGHT;
1793
1794         /* Make sure we're looking at the right location.  The frame
1795          * could have received a motion event from a pointer from a
1796          * different wl_seat, but under X it looks like our core
1797          * pointer moved.  Move the frame pointer to the button press
1798          * location before deciding what to do. */
1799         location = frame_pointer_motion(window->frame, NULL,
1800                                         button->event_x, button->event_y);
1801         location = frame_pointer_button(window->frame, NULL,
1802                                         button_id, button_state);
1803         if (frame_status(window->frame) & FRAME_STATUS_REPAINT)
1804                 weston_wm_window_schedule_repaint(window);
1805
1806         if (frame_status(window->frame) & FRAME_STATUS_MOVE) {
1807                 if (pointer)
1808                         shell_interface->move(window->shsurf, pointer);
1809                 frame_status_clear(window->frame, FRAME_STATUS_MOVE);
1810         }
1811
1812         if (frame_status(window->frame) & FRAME_STATUS_RESIZE) {
1813                 if (pointer)
1814                         shell_interface->resize(window->shsurf, pointer, location);
1815                 frame_status_clear(window->frame, FRAME_STATUS_RESIZE);
1816         }
1817
1818         if (frame_status(window->frame) & FRAME_STATUS_CLOSE) {
1819                 weston_wm_window_close(window, button->time);
1820                 frame_status_clear(window->frame, FRAME_STATUS_CLOSE);
1821         }
1822
1823         if (frame_status(window->frame) & FRAME_STATUS_MAXIMIZE) {
1824                 window->maximized_horz = !window->maximized_horz;
1825                 window->maximized_vert = !window->maximized_vert;
1826                 if (weston_wm_window_is_maximized(window)) {
1827                         window->saved_width = window->width;
1828                         window->saved_height = window->height;
1829                         shell_interface->set_maximized(window->shsurf);
1830                 } else {
1831                         weston_wm_window_set_toplevel(window);
1832                 }
1833                 frame_status_clear(window->frame, FRAME_STATUS_MAXIMIZE);
1834         }
1835 }
1836
1837 static void
1838 weston_wm_handle_motion(struct weston_wm *wm, xcb_generic_event_t *event)
1839 {
1840         xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *) event;
1841         struct weston_wm_window *window;
1842         enum theme_location location;
1843         int cursor;
1844
1845         if (!wm_lookup_window(wm, motion->event, &window) ||
1846             !window->decorate)
1847                 return;
1848
1849         location = frame_pointer_motion(window->frame, NULL,
1850                                         motion->event_x, motion->event_y);
1851         if (frame_status(window->frame) & FRAME_STATUS_REPAINT)
1852                 weston_wm_window_schedule_repaint(window);
1853
1854         cursor = get_cursor_for_location(location);
1855         weston_wm_window_set_cursor(wm, window->frame_id, cursor);
1856 }
1857
1858 static void
1859 weston_wm_handle_enter(struct weston_wm *wm, xcb_generic_event_t *event)
1860 {
1861         xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *) event;
1862         struct weston_wm_window *window;
1863         enum theme_location location;
1864         int cursor;
1865
1866         if (!wm_lookup_window(wm, enter->event, &window) ||
1867             !window->decorate)
1868                 return;
1869
1870         location = frame_pointer_enter(window->frame, NULL,
1871                                        enter->event_x, enter->event_y);
1872         if (frame_status(window->frame) & FRAME_STATUS_REPAINT)
1873                 weston_wm_window_schedule_repaint(window);
1874
1875         cursor = get_cursor_for_location(location);
1876         weston_wm_window_set_cursor(wm, window->frame_id, cursor);
1877 }
1878
1879 static void
1880 weston_wm_handle_leave(struct weston_wm *wm, xcb_generic_event_t *event)
1881 {
1882         xcb_leave_notify_event_t *leave = (xcb_leave_notify_event_t *) event;
1883         struct weston_wm_window *window;
1884
1885         if (!wm_lookup_window(wm, leave->event, &window) ||
1886             !window->decorate)
1887                 return;
1888
1889         frame_pointer_leave(window->frame, NULL);
1890         if (frame_status(window->frame) & FRAME_STATUS_REPAINT)
1891                 weston_wm_window_schedule_repaint(window);
1892
1893         weston_wm_window_set_cursor(wm, window->frame_id, XWM_CURSOR_LEFT_PTR);
1894 }
1895
1896 static void
1897 weston_wm_handle_focus_in(struct weston_wm *wm, xcb_generic_event_t *event)
1898 {
1899         xcb_focus_in_event_t *focus = (xcb_focus_in_event_t *) event;
1900         /* Do not let X clients change the focus behind the compositor's
1901          * back. Reset the focus to the old one if it changed. */
1902         if (!wm->focus_window || focus->event != wm->focus_window->id)
1903                 weston_wm_send_focus_window(wm, wm->focus_window);
1904 }
1905
1906 static int
1907 weston_wm_handle_event(int fd, uint32_t mask, void *data)
1908 {
1909         struct weston_wm *wm = data;
1910         xcb_generic_event_t *event;
1911         int count = 0;
1912
1913         while (event = xcb_poll_for_event(wm->conn), event != NULL) {
1914                 if (weston_wm_handle_selection_event(wm, event)) {
1915                         free(event);
1916                         count++;
1917                         continue;
1918                 }
1919
1920                 if (weston_wm_handle_dnd_event(wm, event)) {
1921                         free(event);
1922                         count++;
1923                         continue;
1924                 }
1925
1926                 switch (EVENT_TYPE(event)) {
1927                 case XCB_BUTTON_PRESS:
1928                 case XCB_BUTTON_RELEASE:
1929                         weston_wm_handle_button(wm, event);
1930                         break;
1931                 case XCB_ENTER_NOTIFY:
1932                         weston_wm_handle_enter(wm, event);
1933                         break;
1934                 case XCB_LEAVE_NOTIFY:
1935                         weston_wm_handle_leave(wm, event);
1936                         break;
1937                 case XCB_MOTION_NOTIFY:
1938                         weston_wm_handle_motion(wm, event);
1939                         break;
1940                 case XCB_CREATE_NOTIFY:
1941                         weston_wm_handle_create_notify(wm, event);
1942                         break;
1943                 case XCB_MAP_REQUEST:
1944                         weston_wm_handle_map_request(wm, event);
1945                         break;
1946                 case XCB_MAP_NOTIFY:
1947                         weston_wm_handle_map_notify(wm, event);
1948                         break;
1949                 case XCB_UNMAP_NOTIFY:
1950                         weston_wm_handle_unmap_notify(wm, event);
1951                         break;
1952                 case XCB_REPARENT_NOTIFY:
1953                         weston_wm_handle_reparent_notify(wm, event);
1954                         break;
1955                 case XCB_CONFIGURE_REQUEST:
1956                         weston_wm_handle_configure_request(wm, event);
1957                         break;
1958                 case XCB_CONFIGURE_NOTIFY:
1959                         weston_wm_handle_configure_notify(wm, event);
1960                         break;
1961                 case XCB_DESTROY_NOTIFY:
1962                         weston_wm_handle_destroy_notify(wm, event);
1963                         break;
1964                 case XCB_MAPPING_NOTIFY:
1965                         wm_log("XCB_MAPPING_NOTIFY\n");
1966                         break;
1967                 case XCB_PROPERTY_NOTIFY:
1968                         weston_wm_handle_property_notify(wm, event);
1969                         break;
1970                 case XCB_CLIENT_MESSAGE:
1971                         weston_wm_handle_client_message(wm, event);
1972                         break;
1973                 case XCB_FOCUS_IN:
1974                         weston_wm_handle_focus_in(wm, event);
1975                         break;
1976                 }
1977
1978                 free(event);
1979                 count++;
1980         }
1981
1982         xcb_flush(wm->conn);
1983
1984         return count;
1985 }
1986
1987 static void
1988 weston_wm_get_visual_and_colormap(struct weston_wm *wm)
1989 {
1990         xcb_depth_iterator_t d_iter;
1991         xcb_visualtype_iterator_t vt_iter;
1992         xcb_visualtype_t *visualtype;
1993
1994         d_iter = xcb_screen_allowed_depths_iterator(wm->screen);
1995         visualtype = NULL;
1996         while (d_iter.rem > 0) {
1997                 if (d_iter.data->depth == 32) {
1998                         vt_iter = xcb_depth_visuals_iterator(d_iter.data);
1999                         visualtype = vt_iter.data;
2000                         break;
2001                 }
2002
2003                 xcb_depth_next(&d_iter);
2004         }
2005
2006         if (visualtype == NULL) {
2007                 weston_log("no 32 bit visualtype\n");
2008                 return;
2009         }
2010
2011         wm->visual_id = visualtype->visual_id;
2012         wm->colormap = xcb_generate_id(wm->conn);
2013         xcb_create_colormap(wm->conn, XCB_COLORMAP_ALLOC_NONE,
2014                             wm->colormap, wm->screen->root, wm->visual_id);
2015 }
2016
2017 static void
2018 weston_wm_get_resources(struct weston_wm *wm)
2019 {
2020
2021 #define F(field) offsetof(struct weston_wm, field)
2022
2023         static const struct { const char *name; int offset; } atoms[] = {
2024                 { "WM_PROTOCOLS",       F(atom.wm_protocols) },
2025                 { "WM_NORMAL_HINTS",    F(atom.wm_normal_hints) },
2026                 { "WM_TAKE_FOCUS",      F(atom.wm_take_focus) },
2027                 { "WM_DELETE_WINDOW",   F(atom.wm_delete_window) },
2028                 { "WM_STATE",           F(atom.wm_state) },
2029                 { "WM_S0",              F(atom.wm_s0) },
2030                 { "WM_CLIENT_MACHINE",  F(atom.wm_client_machine) },
2031                 { "_NET_WM_CM_S0",      F(atom.net_wm_cm_s0) },
2032                 { "_NET_WM_NAME",       F(atom.net_wm_name) },
2033                 { "_NET_WM_PID",        F(atom.net_wm_pid) },
2034                 { "_NET_WM_ICON",       F(atom.net_wm_icon) },
2035                 { "_NET_WM_STATE",      F(atom.net_wm_state) },
2036                 { "_NET_WM_STATE_MAXIMIZED_VERT", F(atom.net_wm_state_maximized_vert) },
2037                 { "_NET_WM_STATE_MAXIMIZED_HORZ", F(atom.net_wm_state_maximized_horz) },
2038                 { "_NET_WM_STATE_FULLSCREEN", F(atom.net_wm_state_fullscreen) },
2039                 { "_NET_WM_USER_TIME", F(atom.net_wm_user_time) },
2040                 { "_NET_WM_ICON_NAME", F(atom.net_wm_icon_name) },
2041                 { "_NET_WM_DESKTOP", F(atom.net_wm_desktop) },
2042                 { "_NET_WM_WINDOW_TYPE", F(atom.net_wm_window_type) },
2043
2044                 { "_NET_WM_WINDOW_TYPE_DESKTOP", F(atom.net_wm_window_type_desktop) },
2045                 { "_NET_WM_WINDOW_TYPE_DOCK", F(atom.net_wm_window_type_dock) },
2046                 { "_NET_WM_WINDOW_TYPE_TOOLBAR", F(atom.net_wm_window_type_toolbar) },
2047                 { "_NET_WM_WINDOW_TYPE_MENU", F(atom.net_wm_window_type_menu) },
2048                 { "_NET_WM_WINDOW_TYPE_UTILITY", F(atom.net_wm_window_type_utility) },
2049                 { "_NET_WM_WINDOW_TYPE_SPLASH", F(atom.net_wm_window_type_splash) },
2050                 { "_NET_WM_WINDOW_TYPE_DIALOG", F(atom.net_wm_window_type_dialog) },
2051                 { "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", F(atom.net_wm_window_type_dropdown) },
2052                 { "_NET_WM_WINDOW_TYPE_POPUP_MENU", F(atom.net_wm_window_type_popup) },
2053                 { "_NET_WM_WINDOW_TYPE_TOOLTIP", F(atom.net_wm_window_type_tooltip) },
2054                 { "_NET_WM_WINDOW_TYPE_NOTIFICATION", F(atom.net_wm_window_type_notification) },
2055                 { "_NET_WM_WINDOW_TYPE_COMBO", F(atom.net_wm_window_type_combo) },
2056                 { "_NET_WM_WINDOW_TYPE_DND", F(atom.net_wm_window_type_dnd) },
2057                 { "_NET_WM_WINDOW_TYPE_NORMAL", F(atom.net_wm_window_type_normal) },
2058
2059                 { "_NET_WM_MOVERESIZE", F(atom.net_wm_moveresize) },
2060                 { "_NET_SUPPORTING_WM_CHECK",
2061                                         F(atom.net_supporting_wm_check) },
2062                 { "_NET_SUPPORTED",     F(atom.net_supported) },
2063                 { "_MOTIF_WM_HINTS",    F(atom.motif_wm_hints) },
2064                 { "CLIPBOARD",          F(atom.clipboard) },
2065                 { "CLIPBOARD_MANAGER",  F(atom.clipboard_manager) },
2066                 { "TARGETS",            F(atom.targets) },
2067                 { "UTF8_STRING",        F(atom.utf8_string) },
2068                 { "_WL_SELECTION",      F(atom.wl_selection) },
2069                 { "INCR",               F(atom.incr) },
2070                 { "TIMESTAMP",          F(atom.timestamp) },
2071                 { "MULTIPLE",           F(atom.multiple) },
2072                 { "UTF8_STRING" ,       F(atom.utf8_string) },
2073                 { "COMPOUND_TEXT",      F(atom.compound_text) },
2074                 { "TEXT",               F(atom.text) },
2075                 { "STRING",             F(atom.string) },
2076                 { "text/plain;charset=utf-8",   F(atom.text_plain_utf8) },
2077                 { "text/plain",         F(atom.text_plain) },
2078                 { "XdndSelection",      F(atom.xdnd_selection) },
2079                 { "XdndAware",          F(atom.xdnd_aware) },
2080                 { "XdndEnter",          F(atom.xdnd_enter) },
2081                 { "XdndLeave",          F(atom.xdnd_leave) },
2082                 { "XdndDrop",           F(atom.xdnd_drop) },
2083                 { "XdndStatus",         F(atom.xdnd_status) },
2084                 { "XdndFinished",       F(atom.xdnd_finished) },
2085                 { "XdndTypeList",       F(atom.xdnd_type_list) },
2086                 { "XdndActionCopy",     F(atom.xdnd_action_copy) },
2087                 { "WL_SURFACE_ID",      F(atom.wl_surface_id) }
2088         };
2089 #undef F
2090
2091         xcb_xfixes_query_version_cookie_t xfixes_cookie;
2092         xcb_xfixes_query_version_reply_t *xfixes_reply;
2093         xcb_intern_atom_cookie_t cookies[ARRAY_LENGTH(atoms)];
2094         xcb_intern_atom_reply_t *reply;
2095         xcb_render_query_pict_formats_reply_t *formats_reply;
2096         xcb_render_query_pict_formats_cookie_t formats_cookie;
2097         xcb_render_pictforminfo_t *formats;
2098         uint32_t i;
2099
2100         xcb_prefetch_extension_data (wm->conn, &xcb_xfixes_id);
2101         xcb_prefetch_extension_data (wm->conn, &xcb_composite_id);
2102
2103         formats_cookie = xcb_render_query_pict_formats(wm->conn);
2104
2105         for (i = 0; i < ARRAY_LENGTH(atoms); i++)
2106                 cookies[i] = xcb_intern_atom (wm->conn, 0,
2107                                               strlen(atoms[i].name),
2108                                               atoms[i].name);
2109
2110         for (i = 0; i < ARRAY_LENGTH(atoms); i++) {
2111                 reply = xcb_intern_atom_reply (wm->conn, cookies[i], NULL);
2112                 *(xcb_atom_t *) ((char *) wm + atoms[i].offset) = reply->atom;
2113                 free(reply);
2114         }
2115
2116         wm->xfixes = xcb_get_extension_data(wm->conn, &xcb_xfixes_id);
2117         if (!wm->xfixes || !wm->xfixes->present)
2118                 weston_log("xfixes not available\n");
2119
2120         xfixes_cookie = xcb_xfixes_query_version(wm->conn,
2121                                                  XCB_XFIXES_MAJOR_VERSION,
2122                                                  XCB_XFIXES_MINOR_VERSION);
2123         xfixes_reply = xcb_xfixes_query_version_reply(wm->conn,
2124                                                       xfixes_cookie, NULL);
2125
2126         weston_log("xfixes version: %d.%d\n",
2127                xfixes_reply->major_version, xfixes_reply->minor_version);
2128
2129         free(xfixes_reply);
2130
2131         formats_reply = xcb_render_query_pict_formats_reply(wm->conn,
2132                                                             formats_cookie, 0);
2133         if (formats_reply == NULL)
2134                 return;
2135
2136         formats = xcb_render_query_pict_formats_formats(formats_reply);
2137         for (i = 0; i < formats_reply->num_formats; i++) {
2138                 if (formats[i].direct.red_mask != 0xff &&
2139                     formats[i].direct.red_shift != 16)
2140                         continue;
2141                 if (formats[i].type == XCB_RENDER_PICT_TYPE_DIRECT &&
2142                     formats[i].depth == 24)
2143                         wm->format_rgb = formats[i];
2144                 if (formats[i].type == XCB_RENDER_PICT_TYPE_DIRECT &&
2145                     formats[i].depth == 32 &&
2146                     formats[i].direct.alpha_mask == 0xff &&
2147                     formats[i].direct.alpha_shift == 24)
2148                         wm->format_rgba = formats[i];
2149         }
2150
2151         free(formats_reply);
2152 }
2153
2154 static void
2155 weston_wm_create_wm_window(struct weston_wm *wm)
2156 {
2157         static const char name[] = "Weston WM";
2158
2159         wm->wm_window = xcb_generate_id(wm->conn);
2160         xcb_create_window(wm->conn,
2161                           XCB_COPY_FROM_PARENT,
2162                           wm->wm_window,
2163                           wm->screen->root,
2164                           0, 0,
2165                           10, 10,
2166                           0,
2167                           XCB_WINDOW_CLASS_INPUT_OUTPUT,
2168                           wm->screen->root_visual,
2169                           0, NULL);
2170
2171         xcb_change_property(wm->conn,
2172                             XCB_PROP_MODE_REPLACE,
2173                             wm->wm_window,
2174                             wm->atom.net_supporting_wm_check,
2175                             XCB_ATOM_WINDOW,
2176                             32, /* format */
2177                             1, &wm->wm_window);
2178
2179         xcb_change_property(wm->conn,
2180                             XCB_PROP_MODE_REPLACE,
2181                             wm->wm_window,
2182                             wm->atom.net_wm_name,
2183                             wm->atom.utf8_string,
2184                             8, /* format */
2185                             strlen(name), name);
2186
2187         xcb_change_property(wm->conn,
2188                             XCB_PROP_MODE_REPLACE,
2189                             wm->screen->root,
2190                             wm->atom.net_supporting_wm_check,
2191                             XCB_ATOM_WINDOW,
2192                             32, /* format */
2193                             1, &wm->wm_window);
2194
2195         /* Claim the WM_S0 selection even though we don't suport
2196          * the --replace functionality. */
2197         xcb_set_selection_owner(wm->conn,
2198                                 wm->wm_window,
2199                                 wm->atom.wm_s0,
2200                                 XCB_TIME_CURRENT_TIME);
2201
2202         xcb_set_selection_owner(wm->conn,
2203                                 wm->wm_window,
2204                                 wm->atom.net_wm_cm_s0,
2205                                 XCB_TIME_CURRENT_TIME);
2206 }
2207
2208 struct weston_wm *
2209 weston_wm_create(struct weston_xserver *wxs, int fd)
2210 {
2211         struct weston_wm *wm;
2212         struct wl_event_loop *loop;
2213         xcb_screen_iterator_t s;
2214         uint32_t values[1];
2215         xcb_atom_t supported[5];
2216
2217         wm = zalloc(sizeof *wm);
2218         if (wm == NULL)
2219                 return NULL;
2220
2221         wm->server = wxs;
2222         wm->window_hash = hash_table_create();
2223         if (wm->window_hash == NULL) {
2224                 free(wm);
2225                 return NULL;
2226         }
2227
2228         /* xcb_connect_to_fd takes ownership of the fd. */
2229         wm->conn = xcb_connect_to_fd(fd, NULL);
2230         if (xcb_connection_has_error(wm->conn)) {
2231                 weston_log("xcb_connect_to_fd failed\n");
2232                 close(fd);
2233                 hash_table_destroy(wm->window_hash);
2234                 free(wm);
2235                 return NULL;
2236         }
2237
2238         s = xcb_setup_roots_iterator(xcb_get_setup(wm->conn));
2239         wm->screen = s.data;
2240
2241         loop = wl_display_get_event_loop(wxs->wl_display);
2242         wm->source =
2243                 wl_event_loop_add_fd(loop, fd,
2244                                      WL_EVENT_READABLE,
2245                                      weston_wm_handle_event, wm);
2246         wl_event_source_check(wm->source);
2247
2248         weston_wm_get_resources(wm);
2249         weston_wm_get_visual_and_colormap(wm);
2250
2251         values[0] =
2252                 XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
2253                 XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
2254                 XCB_EVENT_MASK_PROPERTY_CHANGE;
2255         xcb_change_window_attributes(wm->conn, wm->screen->root,
2256                                      XCB_CW_EVENT_MASK, values);
2257
2258         xcb_composite_redirect_subwindows(wm->conn, wm->screen->root,
2259                                           XCB_COMPOSITE_REDIRECT_MANUAL);
2260
2261         wm->theme = theme_create();
2262
2263         supported[0] = wm->atom.net_wm_moveresize;
2264         supported[1] = wm->atom.net_wm_state;
2265         supported[2] = wm->atom.net_wm_state_fullscreen;
2266         supported[3] = wm->atom.net_wm_state_maximized_vert;
2267         supported[4] = wm->atom.net_wm_state_maximized_horz;
2268         xcb_change_property(wm->conn,
2269                             XCB_PROP_MODE_REPLACE,
2270                             wm->screen->root,
2271                             wm->atom.net_supported,
2272                             XCB_ATOM_ATOM,
2273                             32, /* format */
2274                             ARRAY_LENGTH(supported), supported);
2275
2276         weston_wm_selection_init(wm);
2277
2278         weston_wm_dnd_init(wm);
2279
2280         xcb_flush(wm->conn);
2281
2282         wm->create_surface_listener.notify = weston_wm_create_surface;
2283         wl_signal_add(&wxs->compositor->create_surface_signal,
2284                       &wm->create_surface_listener);
2285         wm->activate_listener.notify = weston_wm_window_activate;
2286         wl_signal_add(&wxs->compositor->activate_signal,
2287                       &wm->activate_listener);
2288         wm->transform_listener.notify = weston_wm_window_transform;
2289         wl_signal_add(&wxs->compositor->transform_signal,
2290                       &wm->transform_listener);
2291         wm->kill_listener.notify = weston_wm_kill_client;
2292         wl_signal_add(&wxs->compositor->kill_signal,
2293                       &wm->kill_listener);
2294         wl_list_init(&wm->unpaired_window_list);
2295
2296         weston_wm_create_cursors(wm);
2297         weston_wm_window_set_cursor(wm, wm->screen->root, XWM_CURSOR_LEFT_PTR);
2298
2299         /* Create wm window and take WM_S0 selection last, which
2300          * signals to Xwayland that we're done with setup. */
2301         weston_wm_create_wm_window(wm);
2302
2303         weston_log("created wm, root %d\n", wm->screen->root);
2304
2305         return wm;
2306 }
2307
2308 void
2309 weston_wm_destroy(struct weston_wm *wm)
2310 {
2311         /* FIXME: Free windows in hash. */
2312         hash_table_destroy(wm->window_hash);
2313         weston_wm_destroy_cursors(wm);
2314         xcb_disconnect(wm->conn);
2315         wl_event_source_remove(wm->source);
2316         wl_list_remove(&wm->selection_listener.link);
2317         wl_list_remove(&wm->activate_listener.link);
2318         wl_list_remove(&wm->kill_listener.link);
2319         wl_list_remove(&wm->transform_listener.link);
2320         wl_list_remove(&wm->create_surface_listener.link);
2321
2322         free(wm);
2323 }
2324
2325 static struct weston_wm_window *
2326 get_wm_window(struct weston_surface *surface)
2327 {
2328         struct wl_listener *listener;
2329
2330         listener = wl_signal_get(&surface->destroy_signal, surface_destroy);
2331         if (listener)
2332                 return container_of(listener, struct weston_wm_window,
2333                                     surface_destroy_listener);
2334
2335         return NULL;
2336 }
2337
2338 static void
2339 weston_wm_window_configure(void *data)
2340 {
2341         struct weston_wm_window *window = data;
2342         struct weston_wm *wm = window->wm;
2343         uint32_t values[4];
2344         int x, y, width, height;
2345
2346         weston_wm_window_get_child_position(window, &x, &y);
2347         values[0] = x;
2348         values[1] = y;
2349         values[2] = window->width;
2350         values[3] = window->height;
2351         xcb_configure_window(wm->conn,
2352                              window->id,
2353                              XCB_CONFIG_WINDOW_X |
2354                              XCB_CONFIG_WINDOW_Y |
2355                              XCB_CONFIG_WINDOW_WIDTH |
2356                              XCB_CONFIG_WINDOW_HEIGHT,
2357                              values);
2358
2359         weston_wm_window_get_frame_size(window, &width, &height);
2360         values[0] = width;
2361         values[1] = height;
2362         xcb_configure_window(wm->conn,
2363                              window->frame_id,
2364                              XCB_CONFIG_WINDOW_WIDTH |
2365                              XCB_CONFIG_WINDOW_HEIGHT,
2366                              values);
2367
2368         window->configure_source = NULL;
2369
2370         weston_wm_window_schedule_repaint(window);
2371 }
2372
2373 static void
2374 send_configure(struct weston_surface *surface, int32_t width, int32_t height)
2375 {
2376         struct weston_wm_window *window = get_wm_window(surface);
2377         struct weston_wm *wm = window->wm;
2378         struct theme *t = window->wm->theme;
2379         int vborder, hborder;
2380
2381         if (window->decorate && !window->fullscreen) {
2382                 hborder = 2 * t->width;
2383                 vborder = t->titlebar_height + t->width;
2384         } else {
2385                 hborder = 0;
2386                 vborder = 0;
2387         }
2388
2389         if (width > hborder)
2390                 window->width = width - hborder;
2391         else
2392                 window->width = 1;
2393
2394         if (height > vborder)
2395                 window->height = height - vborder;
2396         else
2397                 window->height = 1;
2398
2399         if (window->frame)
2400                 frame_resize_inside(window->frame, window->width, window->height);
2401
2402         if (window->configure_source)
2403                 return;
2404
2405         window->configure_source =
2406                 wl_event_loop_add_idle(wm->server->loop,
2407                                        weston_wm_window_configure, window);
2408 }
2409
2410 static const struct weston_shell_client shell_client = {
2411         send_configure
2412 };
2413
2414 static int
2415 legacy_fullscreen(struct weston_wm *wm,
2416                   struct weston_wm_window *window,
2417                   struct weston_output **output_ret)
2418 {
2419         struct weston_compositor *compositor = wm->server->compositor;
2420         struct weston_output *output;
2421         uint32_t minmax = PMinSize | PMaxSize;
2422         int matching_size;
2423
2424         /* Heuristics for detecting legacy fullscreen windows... */
2425
2426         wl_list_for_each(output, &compositor->output_list, link) {
2427                 if (output->x == window->x &&
2428                     output->y == window->y &&
2429                     output->width == window->width &&
2430                     output->height == window->height &&
2431                     window->override_redirect) {
2432                         *output_ret = output;
2433                         return 1;
2434                 }
2435
2436                 matching_size = 0;
2437                 if ((window->size_hints.flags & (USSize |PSize)) &&
2438                     window->size_hints.width == output->width &&
2439                     window->size_hints.height == output->height)
2440                         matching_size = 1;
2441                 if ((window->size_hints.flags & minmax) == minmax &&
2442                     window->size_hints.min_width == output->width &&
2443                     window->size_hints.min_height == output->height &&
2444                     window->size_hints.max_width == output->width &&
2445                     window->size_hints.max_height == output->height)
2446                         matching_size = 1;
2447
2448                 if (matching_size && !window->decorate &&
2449                     (window->size_hints.flags & (USPosition | PPosition)) &&
2450                     window->size_hints.x == output->x &&
2451                     window->size_hints.y == output->y) {
2452                         *output_ret = output;
2453                         return 1;
2454                 }
2455         }
2456
2457         return 0;
2458 }
2459
2460 static bool
2461 weston_wm_window_type_inactive(struct weston_wm_window *window)
2462 {
2463         struct weston_wm *wm = window->wm;
2464
2465         return window->type == wm->atom.net_wm_window_type_tooltip ||
2466                window->type == wm->atom.net_wm_window_type_dropdown ||
2467                window->type == wm->atom.net_wm_window_type_dnd ||
2468                window->type == wm->atom.net_wm_window_type_combo ||
2469                window->type == wm->atom.net_wm_window_type_popup ||
2470                window->type == wm->atom.net_wm_window_type_utility;
2471 }
2472
2473 static void
2474 xserver_map_shell_surface(struct weston_wm_window *window,
2475                           struct weston_surface *surface)
2476 {
2477         struct weston_wm *wm = window->wm;
2478         struct weston_shell_interface *shell_interface =
2479                 &wm->server->compositor->shell_interface;
2480         struct weston_output *output;
2481         struct weston_wm_window *parent;
2482         int flags = 0;
2483
2484         weston_wm_window_read_properties(window);
2485
2486         /* A weston_wm_window may have many different surfaces assigned
2487          * throughout its life, so we must make sure to remove the listener
2488          * from the old surface signal list. */
2489         if (window->surface)
2490                 wl_list_remove(&window->surface_destroy_listener.link);
2491
2492         window->surface = surface;
2493         window->surface_destroy_listener.notify = surface_destroy;
2494         wl_signal_add(&window->surface->destroy_signal,
2495                       &window->surface_destroy_listener);
2496
2497         weston_wm_window_schedule_repaint(window);
2498
2499         if (!shell_interface->create_shell_surface)
2500                 return;
2501
2502         if (!shell_interface->get_primary_view)
2503                 return;
2504
2505         if (window->surface->configure) {
2506                 weston_log("warning, unexpected in %s: "
2507                            "surface's configure hook is already set.\n",
2508                            __func__);
2509                 return;
2510         }
2511
2512         window->shsurf =
2513                 shell_interface->create_shell_surface(shell_interface->shell,
2514                                                       window->surface,
2515                                                       &shell_client);
2516         window->view = shell_interface->get_primary_view(shell_interface->shell,
2517                                                          window->shsurf);
2518
2519         if (window->name)
2520                 shell_interface->set_title(window->shsurf, window->name);
2521         if (window->pid > 0)
2522                 shell_interface->set_pid(window->shsurf, window->pid);
2523
2524         if (window->fullscreen) {
2525                 window->saved_width = window->width;
2526                 window->saved_height = window->height;
2527                 shell_interface->set_fullscreen(window->shsurf,
2528                                                 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
2529                                                 0, NULL);
2530                 return;
2531         } else if (legacy_fullscreen(wm, window, &output)) {
2532                 window->fullscreen = 1;
2533                 shell_interface->set_fullscreen(window->shsurf,
2534                                                 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
2535                                                 0, output);
2536         } else if (window->override_redirect) {
2537                 shell_interface->set_xwayland(window->shsurf,
2538                                               window->x,
2539                                               window->y,
2540                                               WL_SHELL_SURFACE_TRANSIENT_INACTIVE);
2541         } else if (window->transient_for && window->transient_for->surface) {
2542                 parent = window->transient_for;
2543                 if (weston_wm_window_type_inactive(window))
2544                         flags = WL_SHELL_SURFACE_TRANSIENT_INACTIVE;
2545                 shell_interface->set_transient(window->shsurf,
2546                                                parent->surface,
2547                                                window->x - parent->x,
2548                                                window->y - parent->y, flags);
2549         } else if (weston_wm_window_is_maximized(window)) {
2550                 shell_interface->set_maximized(window->shsurf);
2551         } else {
2552                 if (weston_wm_window_type_inactive(window)) {
2553                         shell_interface->set_xwayland(window->shsurf,
2554                                                         window->x,
2555                                                         window->y,
2556                                                         WL_SHELL_SURFACE_TRANSIENT_INACTIVE);
2557                 } else {
2558                         shell_interface->set_toplevel(window->shsurf);
2559                 }
2560         }
2561 }