compositor-x11: Improve fullscreen support

The old implementation didn't work because we set the minimum and maximum
sizes so that the WM can't resize us.  That makes the fullscreen protocol
not work.  Additionally we were requesting fullscreen after mapping, which
requires the more complicated (and potentially flickery) client message
approach.

Now we just set the _NET_WM_STATE before mapping and avoid setting
the size hints in case of fullscreen.  That's all good, but the problem
is that we now have to wait for configure notify before we know
what size our output will be.  For now we just block and pull events from
X until we get the size.

Ideally we would treat the map as an output hotplug event and just add the
output at that point, but we can't start up with no outputs present.
That may be worth fixing, but for now, the block-on-map is fine.
Kristian Høgsberg 12 years ago
parent 7fb46fbe95
commit d6f09a75a7
  1. 135
      src/compositor-x11.c

@ -401,11 +401,10 @@ x11_output_destroy(struct weston_output *output_base)
}
static void
x11_output_set_wm_protocols(struct x11_output *output)
x11_output_set_wm_protocols(struct x11_compositor *c,
struct x11_output *output)
{
xcb_atom_t list[1];
struct x11_compositor *c =
(struct x11_compositor *) output->base.compositor;
list[0] = c->atom.wm_delete_window;
xcb_change_property (c->conn,
@ -418,38 +417,6 @@ x11_output_set_wm_protocols(struct x11_output *output)
list);
}
static void
x11_output_change_state(struct x11_output *output, int add, xcb_atom_t state)
{
xcb_client_message_event_t event;
struct x11_compositor *c =
(struct x11_compositor *) output->base.compositor;
xcb_screen_iterator_t iter;
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
#define _NET_WM_STATE_ADD 1 /* add/set property */
#define _NET_WM_STATE_TOGGLE 2 /* toggle property */
memset(&event, 0, sizeof event);
event.response_type = XCB_CLIENT_MESSAGE;
event.format = 32;
event.window = output->window;
event.type = c->atom.net_wm_state;
event.data.data32[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
event.data.data32[1] = state;
event.data.data32[2] = 0;
event.data.data32[3] = 0;
event.data.data32[4] = 0;
iter = xcb_setup_roots_iterator(xcb_get_setup(c->conn));
xcb_send_event(c->conn, 0, iter.data->root,
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
(void *) &event);
}
struct wm_normal_hints {
uint32_t flags;
uint32_t pad[4];
@ -494,6 +461,47 @@ x11_output_set_icon(struct x11_compositor *c,
pixman_image_unref(image);
}
static void
x11_output_wait_for_map(struct x11_compositor *c, struct x11_output *output)
{
xcb_map_notify_event_t *map_notify;
xcb_configure_notify_event_t *configure_notify;
xcb_generic_event_t *event;
int mapped = 0;
uint8_t response_type;
/* This isn't the nicest way to do this. Ideally, we could
* just go back to the main loop and once we get the map
* notify, we add the output to the compositor. While we do
* support output hotplug, we can't start up with no outputs.
* We could add the output and then resize once we get the map
* notify, but we don't want to start up and immediately
* resize the output. */
xcb_flush(c->conn);
while (!mapped) {
event = xcb_wait_for_event(c->conn);
response_type = event->response_type & ~0x80;
switch (response_type) {
case XCB_MAP_NOTIFY:
map_notify = (xcb_map_notify_event_t *) event;
if (map_notify->window == output->window)
mapped = 1;
break;
case XCB_CONFIGURE_NOTIFY:
configure_notify =
(xcb_configure_notify_event_t *) event;
output->mode.width = configure_notify->width;
output->mode.height = configure_notify->height;
break;
}
}
}
static struct x11_output *
x11_compositor_create_output(struct x11_compositor *c, int x, int y,
int width, int height, int fullscreen,
@ -508,6 +516,7 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
struct wm_normal_hints normal_hints;
struct wl_event_loop *loop;
uint32_t mask = XCB_CW_EVENT_MASK | XCB_CW_CURSOR;
xcb_atom_t atom_list[1];
uint32_t values[2] = {
XCB_EVENT_MASK_EXPOSURE |
XCB_EVENT_MASK_STRUCTURE_NOTIFY,
@ -545,12 +554,6 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
wl_list_init(&output->base.mode_list);
wl_list_insert(&output->base.mode_list, &output->mode.link);
output->base.current = &output->mode;
output->base.make = "xwayland";
output->base.model = "none";
weston_output_init(&output->base, &c->base,
x, y, width, height, transform);
values[1] = c->null_cursor;
output->window = xcb_generate_id(c->conn);
iter = xcb_setup_roots_iterator(xcb_get_setup(c->conn));
@ -565,19 +568,28 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
iter.data->root_visual,
mask, values);
/* Don't resize me. */
memset(&normal_hints, 0, sizeof normal_hints);
normal_hints.flags =
WM_NORMAL_HINTS_MAX_SIZE | WM_NORMAL_HINTS_MIN_SIZE;
normal_hints.min_width = width;
normal_hints.min_height = height;
normal_hints.max_width = width;
normal_hints.max_height = height;
xcb_change_property (c->conn, XCB_PROP_MODE_REPLACE, output->window,
c->atom.wm_normal_hints,
c->atom.wm_size_hints, 32,
sizeof normal_hints / 4,
(uint8_t *) &normal_hints);
if (fullscreen) {
atom_list[0] = c->atom.net_wm_state_fullscreen;
xcb_change_property(c->conn, XCB_PROP_MODE_REPLACE,
output->window,
c->atom.net_wm_state,
XCB_ATOM_ATOM, 32,
ARRAY_LENGTH(atom_list), atom_list);
} else {
/* Don't resize me. */
memset(&normal_hints, 0, sizeof normal_hints);
normal_hints.flags =
WM_NORMAL_HINTS_MAX_SIZE | WM_NORMAL_HINTS_MIN_SIZE;
normal_hints.min_width = width;
normal_hints.min_height = height;
normal_hints.max_width = width;
normal_hints.max_height = height;
xcb_change_property(c->conn, XCB_PROP_MODE_REPLACE, output->window,
c->atom.wm_normal_hints,
c->atom.wm_size_hints, 32,
sizeof normal_hints / 4,
(uint8_t *) &normal_hints);
}
/* Set window name. Don't bother with non-EWMH WMs. */
xcb_change_property(c->conn, XCB_PROP_MODE_REPLACE, output->window,
@ -589,13 +601,11 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
x11_output_set_icon(c, output, DATADIR "/weston/wayland.png");
xcb_map_window(c->conn, output->window);
x11_output_set_wm_protocols(c, output);
x11_output_set_wm_protocols(output);
xcb_map_window(c->conn, output->window);
if (fullscreen)
x11_output_change_state(output, 1,
c->atom.net_wm_state_fullscreen);
x11_output_wait_for_map(c, output);
output->base.egl_surface =
eglCreateWindowSurface(c->base.egl_display, c->base.egl_config,
@ -616,6 +626,11 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
output->base.set_backlight = NULL;
output->base.set_dpms = NULL;
output->base.switch_mode = NULL;
output->base.current = &output->mode;
output->base.make = "xwayland";
output->base.model = "none";
weston_output_init(&output->base, &c->base,
x, y, width, height, transform);
wl_list_insert(c->base.output_list.prev, &output->base.link);
@ -1340,7 +1355,7 @@ backend_init(struct wl_display *display, int argc, char *argv[],
const struct weston_option x11_options[] = {
{ WESTON_OPTION_INTEGER, "width", 0, &option_width },
{ WESTON_OPTION_INTEGER, "height", 0, &option_height },
{ WESTON_OPTION_BOOLEAN, "fullscreen", 0, &fullscreen },
{ WESTON_OPTION_BOOLEAN, "fullscreen", 'f', &fullscreen },
{ WESTON_OPTION_INTEGER, "output-count", 0, &option_count },
{ WESTON_OPTION_BOOLEAN, "no-input", 0, &no_input },
};

Loading…
Cancel
Save