summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuhiko Tanibata <NOBUHIKO_TANIBATA@denso.co.jp>2014-01-20 10:27:29 +0900
committerNobuhiko Tanibata <NOBUHIKO_TANIBATA@denso.co.jp>2014-01-20 10:27:29 +0900
commitb5db437f0d89404936c654e43f0fce8c4d1e7715 (patch)
treeee29dfec6f00cf3a6323083f568ca019b4aa9d6d
parent16d36d6da92eff18cea390acdcdc910c7fa41a3f (diff)
downloadweston-b5db437f0d89404936c654e43f0fce8c4d1e7715.tar.gz
Weston 1.3.92
-rw-r--r--.gitignore2
-rw-r--r--Makefile.am29
-rw-r--r--clients/.gitignore6
-rw-r--r--clients/Makefile.am56
-rw-r--r--clients/clickdot.c2
-rw-r--r--clients/cliptest.c2
-rw-r--r--clients/desktop-shell.c24
-rw-r--r--clients/dnd.c94
-rw-r--r--clients/editor.c55
-rw-r--r--clients/eventdemo.c2
-rw-r--r--clients/flower.c3
-rw-r--r--clients/fullscreen.c3
-rw-r--r--clients/gears.c2
-rw-r--r--clients/image.c4
-rw-r--r--clients/keyboard.c86
-rw-r--r--clients/nested.c678
-rw-r--r--clients/resizor.c5
-rw-r--r--clients/scaler.c215
-rw-r--r--clients/simple-egl.c107
-rw-r--r--clients/stacking.c312
-rw-r--r--clients/subsurfaces.c3
-rw-r--r--clients/tablet-shell.c478
-rw-r--r--clients/terminal.c383
-rw-r--r--clients/transformed.c3
-rw-r--r--clients/view.c4
-rw-r--r--clients/weston-info.c16
-rw-r--r--clients/window.c1025
-rw-r--r--clients/window.h39
-rw-r--r--clients/wscreensaver.c2
-rw-r--r--configure.ac111
-rw-r--r--desktop-shell/.gitignore4
-rw-r--r--desktop-shell/Makefile.am39
-rw-r--r--desktop-shell/exposay.c609
-rw-r--r--desktop-shell/input-panel.c354
-rw-r--r--desktop-shell/shell.c (renamed from src/shell.c)3022
-rw-r--r--desktop-shell/shell.h220
-rw-r--r--man/Makefile.am1
-rw-r--r--man/weston.ini.man39
-rw-r--r--man/weston.man20
-rw-r--r--protocol/Makefile.am23
-rw-r--r--protocol/scaler.xml156
-rw-r--r--protocol/subsurface.xml244
-rw-r--r--protocol/tablet-shell.xml40
-rw-r--r--protocol/wayland-test.xml7
-rw-r--r--protocol/xdg-shell.xml438
-rw-r--r--shared/Makefile.am2
-rw-r--r--shared/cairo-util.c106
-rw-r--r--shared/cairo-util.h126
-rw-r--r--shared/frame.c848
-rw-r--r--shared/os-compatibility.c19
-rw-r--r--src/.gitignore11
-rw-r--r--src/Makefile.am133
-rw-r--r--src/animation.c253
-rw-r--r--src/bindings.c63
-rw-r--r--src/compositor-drm.c373
-rw-r--r--src/compositor-fbdev.c25
-rw-r--r--src/compositor-headless.c4
-rw-r--r--src/compositor-rdp.c8
-rw-r--r--src/compositor-rpi.c271
-rw-r--r--src/compositor-wayland.c1335
-rw-r--r--src/compositor-x11.c214
-rw-r--r--src/compositor.c1512
-rw-r--r--src/compositor.h363
-rw-r--r--src/data-device.c408
-rw-r--r--src/dbus.c404
-rw-r--r--src/dbus.h107
-rw-r--r--src/evdev.c145
-rw-r--r--src/evdev.h12
-rw-r--r--src/filter.c1
-rw-r--r--src/filter.h1
-rw-r--r--src/gl-renderer.c535
-rw-r--r--src/gl-renderer.h130
-rw-r--r--src/input.c724
-rw-r--r--src/launcher-util.c128
-rw-r--r--src/launcher-util.h6
-rw-r--r--src/logind-util.c940
-rw-r--r--src/logind-util.h120
-rw-r--r--src/noop-renderer.c13
-rw-r--r--src/pixman-renderer.c346
-rw-r--r--src/rpi-bcm-stubs.h13
-rw-r--r--src/rpi-renderer.c700
-rw-r--r--src/rpi-renderer.h1
-rw-r--r--src/screenshooter.c110
-rw-r--r--src/spring-tool.c4
-rw-r--r--src/tablet-shell.c575
-rw-r--r--src/text-backend.c4
-rw-r--r--src/udev-seat.c37
-rw-r--r--src/udev-seat.h2
-rw-r--r--src/vertex-clipping.c70
-rw-r--r--src/vertex-clipping.h30
-rw-r--r--src/weston-launch.c22
-rw-r--r--src/zoom.c192
-rw-r--r--tests/.gitignore3
-rw-r--r--tests/Makefile.am90
-rw-r--r--tests/bad-buffer-test.c77
-rw-r--r--tests/buffer-count-test.c141
-rw-r--r--tests/subsurface-test.c1
-rw-r--r--tests/surface-global-test.c27
-rw-r--r--tests/surface-test.c17
-rw-r--r--tests/text-test.c2
-rw-r--r--tests/vertex-clip-test.c12
-rw-r--r--tests/weston-test-client-helper.c36
-rw-r--r--tests/weston-test-client-helper.h7
-rw-r--r--tests/weston-test.c97
-rw-r--r--weston.ini.in (renamed from weston.ini)9
-rw-r--r--xwayland/.gitignore2
-rw-r--r--xwayland/Makefile.am (renamed from src/xwayland/Makefile.am)2
-rw-r--r--xwayland/dnd.c (renamed from src/xwayland/dnd.c)6
-rw-r--r--xwayland/hash.c (renamed from src/xwayland/hash.c)0
-rw-r--r--xwayland/hash.h (renamed from src/xwayland/hash.h)0
-rw-r--r--xwayland/launcher.c (renamed from src/xwayland/launcher.c)0
-rw-r--r--xwayland/selection.c (renamed from src/xwayland/selection.c)0
-rw-r--r--xwayland/window-manager.c (renamed from src/xwayland/window-manager.c)230
-rw-r--r--xwayland/xwayland.h (renamed from src/xwayland/xwayland.h)2
114 files changed, 14802 insertions, 6372 deletions
diff --git a/.gitignore b/.gitignore
index f96bbd19..111c56c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,6 +28,8 @@ cscope.out
/missing
/stamp-h1
/test-driver
+/weston.ini
Makefile
Makefile.in
TAGS
+protocol/.*.valid
diff --git a/Makefile.am b/Makefile.am
index e9ecc380..f22c5429 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,8 +2,33 @@ if BUILD_WCAP_TOOLS
wcap_subdir = wcap
endif
-SUBDIRS = shared src clients data protocol tests $(wcap_subdir) man
+if ENABLE_XWAYLAND
+xwayland_subdir = xwayland
+endif
+
+SUBDIRS = \
+ shared \
+ src \
+ $(xwayland_subdir) \
+ desktop-shell \
+ clients \
+ data \
+ protocol \
+ tests \
+ $(wcap_subdir) \
+ man
DISTCHECK_CONFIGURE_FLAGS = --disable-setuid-install
-EXTRA_DIST = weston.ini wayland-scanner.mk
+EXTRA_DIST = weston.ini.in wayland-scanner.mk
+
+weston.ini : $(srcdir)/weston.ini.in
+ $(AM_V_GEN)$(SED) \
+ -e 's|@bindir[@]|$(bindir)|g' \
+ -e 's|@abs_top_builddir[@]|$(abs_top_builddir)|g' \
+ -e 's|@libexecdir[@]|$(libexecdir)|g' \
+ $< > $@
+
+all-local : weston.ini
+
+CLEANFILES = weston.ini
diff --git a/clients/.gitignore b/clients/.gitignore
index 23959cce..d23027ce 100644
--- a/clients/.gitignore
+++ b/clients/.gitignore
@@ -11,10 +11,12 @@ weston-image
weston-nested
weston-nested-client
weston-resizor
+weston-scaler
weston-simple-egl
weston-simple-shm
weston-simple-touch
weston-smoke
+weston-stacking
weston-subsurfaces
weston-transformed
weston-view
@@ -27,8 +29,8 @@ weston-keyboard
libtoytoolkit.a
screenshooter-client-protocol.h
screenshooter-protocol.c
-subsurface-client-protocol.h
-subsurface-protocol.c
+scaler-client-protocol.h
+scaler-protocol.c
tablet-shell-client-protocol.h
tablet-shell-protocol.c
text-client-protocol.h
diff --git a/clients/Makefile.am b/clients/Makefile.am
index 4f9dc481..4f8d4a6f 100644
--- a/clients/Makefile.am
+++ b/clients/Makefile.am
@@ -1,6 +1,4 @@
-bin_PROGRAMS = \
- weston-info \
- $(terminal)
+bin_PROGRAMS = $(install_clients)
demo_clients = \
$(clients_programs) \
@@ -9,20 +7,12 @@ demo_clients = \
$(simple_clients_programs) \
$(simple_egl_clients_programs)
-if ENABLE_DEMO_CLIENTS
+if INSTALL_DEMO_CLIENTS
bin_PROGRAMS += $(demo_clients)
else
noinst_PROGRAMS = $(demo_clients)
endif
-libexec_PROGRAMS = \
- $(desktop_shell) \
- $(tablet_shell) \
- $(screenshooter) \
- $(screensaver) \
- $(keyboard) \
- weston-simple-im
-
AM_CFLAGS = $(GCC_CFLAGS)
AM_CPPFLAGS = \
-DDATADIR='"$(datadir)"' \
@@ -64,7 +54,14 @@ weston_simple_egl_LDADD = $(SIMPLE_EGL_CLIENT_LIBS) -lm
endif
if BUILD_CLIENTS
-terminal = weston-terminal
+install_clients = weston-terminal weston-info
+
+libexec_PROGRAMS = \
+ weston-desktop-shell \
+ weston-screenshooter \
+ $(screensaver) \
+ weston-keyboard \
+ weston-simple-im
clients_programs = \
weston-flower \
@@ -77,19 +74,13 @@ clients_programs = \
weston-clickdot \
weston-transformed \
weston-fullscreen \
+ weston-stacking \
weston-calibrator \
+ weston-scaler \
$(subsurfaces) \
$(full_gl_client_programs) \
$(cairo_glesv2_programs)
-desktop_shell = weston-desktop-shell
-
-if ENABLE_TABLET_SHELL
-tablet_shell = weston-tablet-shell
-endif
-
-screenshooter = weston-screenshooter
-
noinst_LTLIBRARIES = libtoytoolkit.la
libtoytoolkit_la_SOURCES = \
@@ -97,8 +88,8 @@ libtoytoolkit_la_SOURCES = \
window.h \
text-cursor-position-protocol.c \
text-cursor-position-client-protocol.h \
- subsurface-protocol.c \
- subsurface-client-protocol.h \
+ scaler-protocol.c \
+ scaler-client-protocol.h \
workspaces-protocol.c \
workspaces-client-protocol.h
@@ -137,6 +128,9 @@ weston_smoke_LDADD = libtoytoolkit.la
weston_resizor_SOURCES = resizor.c
weston_resizor_LDADD = libtoytoolkit.la
+weston_scaler_SOURCES = scaler.c
+weston_scaler_LDADD = libtoytoolkit.la
+
if HAVE_CAIRO_GLESV2
cairo_glesv2_programs = weston-nested weston-nested-client
@@ -159,6 +153,9 @@ weston_transformed_LDADD = libtoytoolkit.la
weston_fullscreen_SOURCES = fullscreen.c
weston_fullscreen_LDADD = libtoytoolkit.la
+weston_stacking_SOURCES = stacking.c
+weston_stacking_LDADD = libtoytoolkit.la
+
weston_calibrator_SOURCES = calibrator.c \
../shared/matrix.c \
../shared/matrix.h
@@ -181,7 +178,6 @@ weston_editor_LDADD = libtoytoolkit.la $(PANGO_LIBS)
weston_editor_CPPFLAGS = $(AM_CPPFLAGS) $(PANGO_CFLAGS)
endif
-keyboard = weston-keyboard
weston_keyboard_SOURCES = \
keyboard.c \
desktop-shell-client-protocol.h \
@@ -208,12 +204,6 @@ weston_desktop_shell_SOURCES = \
desktop-shell-protocol.c
weston_desktop_shell_LDADD = libtoytoolkit.la
-weston_tablet_shell_SOURCES = \
- tablet-shell.c \
- tablet-shell-client-protocol.h \
- tablet-shell-protocol.c
-weston_tablet_shell_LDADD = libtoytoolkit.la
-
BUILT_SOURCES = \
screenshooter-client-protocol.h \
screenshooter-protocol.c \
@@ -225,10 +215,8 @@ BUILT_SOURCES = \
input-method-client-protocol.h \
desktop-shell-client-protocol.h \
desktop-shell-protocol.c \
- tablet-shell-client-protocol.h \
- tablet-shell-protocol.c \
- subsurface-client-protocol.h \
- subsurface-protocol.c \
+ scaler-client-protocol.h \
+ scaler-protocol.c \
workspaces-client-protocol.h \
workspaces-protocol.c
diff --git a/clients/clickdot.c b/clients/clickdot.c
index aebe4db1..c300fa54 100644
--- a/clients/clickdot.c
+++ b/clients/clickdot.c
@@ -249,7 +249,7 @@ clickdot_create(struct display *display)
clickdot = xzalloc(sizeof *clickdot);
clickdot->window = window_create(display);
- clickdot->widget = frame_create(clickdot->window, clickdot);
+ clickdot->widget = window_frame_create(clickdot->window, clickdot);
window_set_title(clickdot->window, "Wayland ClickDot");
clickdot->display = display;
clickdot->buffer = NULL;
diff --git a/clients/cliptest.c b/clients/cliptest.c
index 4b778087..89c3ca73 100644
--- a/clients/cliptest.c
+++ b/clients/cliptest.c
@@ -798,7 +798,7 @@ cliptest_create(struct display *display)
geometry_init(&cliptest->ui.geometry);
cliptest->window = window_create(display);
- cliptest->widget = frame_create(cliptest->window, cliptest);
+ cliptest->widget = window_frame_create(cliptest->window, cliptest);
window_set_title(cliptest->window, "cliptest");
cliptest->display = display;
diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c
index 599c0a5b..4e7a815e 100644
--- a/clients/desktop-shell.c
+++ b/clients/desktop-shell.c
@@ -95,6 +95,7 @@ struct background {
struct output {
struct wl_output *output;
+ uint32_t server_output_id;
struct wl_list link;
struct panel *panel;
@@ -142,7 +143,7 @@ sigchild_handler(int s)
}
static void
-menu_func(struct window *window, int index, void *data)
+menu_func(struct window *window, struct input *input, int index, void *data)
{
printf("Selected index %d from a panel menu.\n", index);
}
@@ -896,7 +897,7 @@ unlock_dialog_create(struct desktop *desktop)
dialog = xzalloc(sizeof *dialog);
dialog->window = window_create_custom(display);
- dialog->widget = frame_create(dialog->window, dialog);
+ dialog->widget = window_frame_create(dialog->window, dialog);
window_set_title(dialog->window, "Unlock your desktop");
window_set_user_data(dialog->window, dialog);
@@ -1213,6 +1214,7 @@ create_output(struct desktop *desktop, uint32_t id)
output->output =
display_bind(desktop->display, id, &wl_output_interface, 2);
+ output->server_output_id = id;
wl_output_add_listener(output->output, &output_listener, output);
@@ -1242,6 +1244,23 @@ global_handler(struct display *display, uint32_t id,
}
static void
+global_handler_remove(struct display *display, uint32_t id,
+ const char *interface, uint32_t version, void *data)
+{
+ struct desktop *desktop = data;
+ struct output *output;
+
+ if (!strcmp(interface, "wl_output")) {
+ wl_list_for_each(output, &desktop->outputs, link) {
+ if (output->server_output_id == id) {
+ output_destroy(output);
+ break;
+ }
+ }
+ }
+}
+
+static void
panel_add_launchers(struct panel *panel, struct desktop *desktop)
{
struct weston_config_section *s;
@@ -1298,6 +1317,7 @@ int main(int argc, char *argv[])
display_set_user_data(desktop.display, &desktop);
display_set_global_handler(desktop.display, global_handler);
+ display_set_global_handler_remove(desktop.display, global_handler_remove);
/* Create panel and background for outputs processed before the shell
* global interface was processed */
diff --git a/clients/dnd.c b/clients/dnd.c
index 19cc243c..00739c31 100644
--- a/clients/dnd.c
+++ b/clients/dnd.c
@@ -334,62 +334,42 @@ static const struct wl_data_source_listener data_source_listener = {
};
static cairo_surface_t *
-create_drag_cursor(struct dnd_drag *dnd_drag,
- struct item *item, int32_t x, int32_t y, double opacity)
+create_drag_icon(struct dnd_drag *dnd_drag,
+ struct item *item, int32_t x, int32_t y, double opacity)
{
struct dnd *dnd = dnd_drag->dnd;
cairo_surface_t *surface;
- struct wl_cursor_image *pointer;
struct rectangle rectangle;
cairo_pattern_t *pattern;
cairo_t *cr;
- pointer = display_get_pointer_image(dnd->display, CURSOR_DRAGGING);
- if (!pointer) {
- fprintf(stderr, "WARNING: grabbing cursor image not found\n");
- pointer = display_get_pointer_image(dnd->display,
- CURSOR_LEFT_PTR);
- assert(pointer && "no cursor image found");
- }
-
- rectangle.width = item_width + 2 * pointer->width;
- rectangle.height = item_height + 2 * pointer->height;
+ rectangle.width = item_width;
+ rectangle.height = item_height;
surface = display_create_surface(dnd->display, NULL, &rectangle,
SURFACE_SHM);
cr = cairo_create(surface);
- cairo_translate(cr, pointer->width, pointer->height);
-
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
- cairo_set_source_rgba(cr, 0, 0, 0, 0);
- cairo_paint(cr);
-
- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_set_source_surface(cr, item->surface, 0, 0);
pattern = cairo_pattern_create_rgba(0, 0, 0, opacity);
cairo_mask(cr, pattern);
cairo_pattern_destroy(pattern);
- /* FIXME: more cairo-gl brokeness */
- surface_flush_device(surface);
cairo_destroy(cr);
- dnd_drag->hotspot_x = pointer->width + x - item->x;
- dnd_drag->hotspot_y = pointer->height + y - item->y;
+ dnd_drag->hotspot_x = x - item->x;
+ dnd_drag->hotspot_y = y - item->y;
dnd_drag->width = rectangle.width;
dnd_drag->height = rectangle.height;
return surface;
}
-static void
-dnd_button_handler(struct widget *widget,
- struct input *input, uint32_t time,
- uint32_t button, enum wl_pointer_button_state state,
- void *data)
+static int
+create_drag_source(struct dnd *dnd,
+ struct input *input, uint32_t time,
+ int32_t x, int32_t y)
{
- struct dnd *dnd = data;
- int32_t x, y;
struct item *item;
struct rectangle allocation;
struct dnd_drag *dnd_drag;
@@ -401,12 +381,11 @@ dnd_button_handler(struct widget *widget,
cairo_surface_t *icon;
widget_get_allocation(dnd->widget, &allocation);
- input_get_position(input, &x, &y);
item = dnd_get_item(dnd, x, y);
x -= allocation.x;
y -= allocation.y;
- if (item && state == WL_POINTER_BUTTON_STATE_PRESSED) {
+ if (item) {
dnd_drag = xmalloc(sizeof *dnd_drag);
dnd_drag->dnd = dnd;
dnd_drag->input = input;
@@ -428,8 +407,6 @@ dnd_button_handler(struct widget *widget,
dnd_drag->drag_surface =
wl_compositor_create_surface(compositor);
- input_ungrab(input);
-
if (dnd->self_only) {
dnd_drag->data_source = NULL;
} else {
@@ -450,12 +427,10 @@ dnd_button_handler(struct widget *widget,
dnd_drag->drag_surface,
serial);
- input_set_pointer_image(input, CURSOR_DRAGGING);
-
dnd_drag->opaque =
- create_drag_cursor(dnd_drag, item, x, y, 1);
+ create_drag_icon(dnd_drag, item, x, y, 1);
dnd_drag->translucent =
- create_drag_cursor(dnd_drag, item, x, y, 0.2);
+ create_drag_icon(dnd_drag, item, x, y, 0.2);
if (dnd->self_only)
icon = dnd_drag->opaque;
@@ -471,9 +446,47 @@ dnd_button_handler(struct widget *widget,
dnd->current_drag = dnd_drag;
window_schedule_redraw(dnd->window);
+
+ return 0;
+ } else
+ return -1;
+}
+
+static void
+dnd_button_handler(struct widget *widget,
+ struct input *input, uint32_t time,
+ uint32_t button, enum wl_pointer_button_state state,
+ void *data)
+{
+ struct dnd *dnd = data;
+ int32_t x, y;
+
+ input_get_position(input, &x, &y);
+ if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
+ input_ungrab(input);
+ if (create_drag_source(dnd, input, time, x, y) == 0)
+ input_set_pointer_image(input, CURSOR_DRAGGING);
}
}
+static void
+dnd_touch_down_handler(struct widget *widget,
+ struct input *input, uint32_t serial,
+ uint32_t time, int32_t id,
+ float x, float y, void *data)
+{
+ struct dnd *dnd = data;
+ int32_t int_x, int_y;
+
+ if (id > 0)
+ return;
+
+ int_x = (int32_t)x;
+ int_y = (int32_t)y;
+ if (create_drag_source(dnd, input, time, int_x, int_y) == 0)
+ touch_grab(input, 0);
+}
+
static int
lookup_cursor(struct dnd *dnd, int x, int y)
{
@@ -589,7 +602,7 @@ dnd_create(struct display *display)
dnd = xzalloc(sizeof *dnd);
dnd->window = window_create(display);
- dnd->widget = frame_create(dnd->window, dnd);
+ dnd->widget = window_frame_create(dnd->window, dnd);
window_set_title(dnd->window, "Wayland Drag and Drop Demo");
dnd->display = display;
@@ -614,11 +627,12 @@ dnd_create(struct display *display)
widget_set_enter_handler(dnd->widget, dnd_enter_handler);
widget_set_motion_handler(dnd->widget, dnd_motion_handler);
widget_set_button_handler(dnd->widget, dnd_button_handler);
+ widget_set_touch_down_handler(dnd->widget, dnd_touch_down_handler);
width = 4 * (item_width + item_padding) + item_padding;
height = 4 * (item_height + item_padding) + item_padding;
- frame_set_child_size(dnd->widget, width, height);
+ window_frame_set_child_size(dnd->widget, width, height);
return dnd;
}
diff --git a/clients/editor.c b/clients/editor.c
index 12650f32..76e2346a 100644
--- a/clients/editor.c
+++ b/clients/editor.c
@@ -115,6 +115,9 @@ static void text_entry_button_handler(struct widget *widget,
struct input *input, uint32_t time,
uint32_t button,
enum wl_pointer_button_state state, void *data);
+static void text_entry_touch_handler(struct widget *widget, struct input *input,
+ uint32_t serial, uint32_t time, int32_t id,
+ float tx, float ty, void *data);
static int text_entry_motion_handler(struct widget *widget,
struct input *input, uint32_t time,
float x, float y, void *data);
@@ -516,6 +519,7 @@ text_entry_create(struct editor *editor, const char *text)
widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
widget_set_button_handler(entry->widget, text_entry_button_handler);
widget_set_motion_handler(entry->widget, text_entry_motion_handler);
+ widget_set_touch_down_handler(entry->widget, text_entry_touch_handler);
return entry;
}
@@ -1078,6 +1082,29 @@ text_entry_button_handler(struct widget *widget,
}
static void
+text_entry_touch_handler(struct widget *widget, struct input *input,
+ uint32_t serial, uint32_t time, int32_t id,
+ float tx, float ty, void *data)
+{
+ struct text_entry *entry = data;
+ struct wl_seat *seat = input_get_seat(input);
+ struct rectangle allocation;
+ struct editor *editor;
+ int32_t x, y;
+
+ widget_get_allocation(entry->widget, &allocation);
+
+ x = tx - (allocation.x + text_offset_left);
+ y = ty - (allocation.y + text_offset_left);
+
+ editor = window_get_user_data(entry->window);
+ text_entry_activate(entry, seat);
+ editor->active_entry = entry;
+
+ text_entry_set_cursor_position(entry, x, y, true);
+}
+
+static void
editor_button_handler(struct widget *widget,
struct input *input, uint32_t time,
uint32_t button,
@@ -1099,6 +1126,29 @@ editor_button_handler(struct widget *widget,
}
static void
+editor_touch_handler(struct widget *widget, struct input *input,
+ uint32_t serial, uint32_t time, int32_t id,
+ float tx, float ty, void *data)
+{
+ struct editor *editor = data;
+
+ struct wl_seat *seat = input_get_seat(input);
+
+ text_entry_deactivate(editor->entry, seat);
+ text_entry_deactivate(editor->editor, seat);
+ editor->active_entry = NULL;
+}
+
+static void
+keyboard_focus_handler(struct window *window,
+ struct input *device, void *data)
+{
+ struct editor *editor = data;
+
+ window_schedule_redraw(editor->window);
+}
+
+static void
key_handler(struct window *window,
struct input *input, uint32_t time,
uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
@@ -1221,7 +1271,7 @@ main(int argc, char *argv[])
display_set_global_handler(editor.display, global_handler);
editor.window = window_create(editor.display);
- editor.widget = frame_create(editor.window, &editor);
+ editor.widget = window_frame_create(editor.window, &editor);
editor.entry = text_entry_create(&editor, "Entry");
editor.entry->click_to_show = click_to_show;
@@ -1233,11 +1283,14 @@ main(int argc, char *argv[])
window_set_title(editor.window, "Text Editor");
window_set_key_handler(editor.window, key_handler);
+ window_set_keyboard_focus_handler(editor.window,
+ keyboard_focus_handler);
window_set_user_data(editor.window, &editor);
widget_set_redraw_handler(editor.widget, redraw_handler);
widget_set_resize_handler(editor.widget, resize_handler);
widget_set_button_handler(editor.widget, editor_button_handler);
+ widget_set_touch_down_handler(editor.widget, editor_touch_handler);
window_schedule_resize(editor.window, 500, 400);
diff --git a/clients/eventdemo.c b/clients/eventdemo.c
index 05ad5dcb..029b1d8b 100644
--- a/clients/eventdemo.c
+++ b/clients/eventdemo.c
@@ -307,7 +307,7 @@ eventdemo_create(struct display *d)
*/
e->widget = window_add_widget(e->window, e);
} else {
- e->widget = frame_create(e->window, e);
+ e->widget = window_frame_create(e->window, e);
window_set_title(e->window, title);
}
e->display = d;
diff --git a/clients/flower.c b/clients/flower.c
index 825c833e..389f8bee 100644
--- a/clients/flower.c
+++ b/clients/flower.c
@@ -158,8 +158,7 @@ touch_down_handler(struct widget *widget, struct input *input,
float x, float y, void *data)
{
struct flower *flower = data;
- window_touch_move(flower->window, input,
- display_get_serial(flower->display));
+ window_move(flower->window, input, display_get_serial(flower->display));
}
int main(int argc, char *argv[])
diff --git a/clients/fullscreen.c b/clients/fullscreen.c
index 72e2c81f..034a3528 100644
--- a/clients/fullscreen.c
+++ b/clients/fullscreen.c
@@ -283,8 +283,7 @@ touch_handler(struct widget *widget, struct input *input,
float x, float y, void *data)
{
struct fullscreen *fullscreen = data;
- window_touch_move(fullscreen->window, input,
- display_get_serial(fullscreen->display));
+ window_move(fullscreen->window, input, display_get_serial(fullscreen->display));
}
static void
diff --git a/clients/gears.c b/clients/gears.c
index 30f4e688..93a86b4f 100644
--- a/clients/gears.c
+++ b/clients/gears.c
@@ -404,7 +404,7 @@ gears_create(struct display *display)
gears = zalloc(sizeof *gears);
gears->d = display;
gears->window = window_create(display);
- gears->widget = frame_create(gears->window, gears);
+ gears->widget = window_frame_create(gears->window, gears);
window_set_title(gears->window, "Wayland Gears");
gears->display = display_get_egl_display(gears->d);
diff --git a/clients/image.c b/clients/image.c
index 4d3f3b87..3a52c220 100644
--- a/clients/image.c
+++ b/clients/image.c
@@ -336,7 +336,7 @@ fullscreen_handler(struct window *window, void *data)
}
static void
-close_handler(struct window *window, void *data)
+close_handler(void *data)
{
struct image *image = data;
@@ -378,7 +378,7 @@ image_create(struct display *display, const char *filename,
}
image->window = window_create(display);
- image->widget = frame_create(image->window, image);
+ image->widget = window_frame_create(image->window, image);
window_set_title(image->window, title);
image->display = display;
image->image_counter = image_counter;
diff --git a/clients/keyboard.c b/clients/keyboard.c
index 9ee4a848..6876cdec 100644
--- a/clients/keyboard.c
+++ b/clients/keyboard.c
@@ -261,6 +261,19 @@ struct keyboard {
enum keyboard_state state;
};
+static void __attribute__ ((format (printf, 1, 2)))
+dbg(const char *fmt, ...)
+{
+#ifdef DEBUG
+ int l;
+ va_list argp;
+
+ va_start(argp, fmt);
+ l = vfprintf(stderr, fmt, argp);
+ va_end(argp);
+#endif
+}
+
static const char *
label_from_key(struct keyboard *keyboard,
const struct key *key)
@@ -384,12 +397,13 @@ resize_handler(struct widget *widget,
static char *
insert_text(const char *text, uint32_t offset, const char *insert)
{
- char *new_text = xmalloc(strlen(text) + strlen(insert) + 1);
+ int tlen = strlen(text), ilen = strlen(insert);
+ char *new_text = xmalloc(tlen + ilen + 1);
- strncat(new_text, text, offset);
- new_text[offset] = '\0';
- strcat(new_text, insert);
- strcat(new_text, text + offset);
+ memcpy(new_text, text, offset);
+ memcpy(new_text + offset, insert, ilen);
+ memcpy(new_text + offset + ilen, text + offset, tlen - offset);
+ new_text[tlen + ilen] = '\0';
return new_text;
}
@@ -462,14 +476,14 @@ delete_before_cursor(struct virtual_keyboard *keyboard)
const char *start, *end;
if (!keyboard->surrounding_text) {
- fprintf(stderr, "delete_before_cursor: No surrounding text available\n");
+ dbg("delete_before_cursor: No surrounding text available\n");
return;
}
start = prev_utf8_char(keyboard->surrounding_text,
keyboard->surrounding_text + keyboard->surrounding_cursor);
if (!start) {
- fprintf(stderr, "delete_before_cursor: No previous character to delete\n");
+ dbg("delete_before_cursor: No previous character to delete\n");
return;
}
@@ -489,6 +503,21 @@ delete_before_cursor(struct virtual_keyboard *keyboard)
memmove(keyboard->surrounding_text + keyboard->surrounding_cursor, end, strlen(end));
}
+static char *
+append(char *s1, const char *s2)
+{
+ int len1, len2;
+ char *s;
+
+ len1 = strlen(s1);
+ len2 = strlen(s2);
+ s = xrealloc(s1, len1 + len2 + 1);
+ memcpy(s + len1, s2, len2);
+ s[len1 + len2] = '\0';
+
+ return s;
+}
+
static void
keyboard_handle_key(struct keyboard *keyboard, uint32_t time, const struct key *key, struct input *input, enum wl_pointer_button_state state)
{
@@ -501,8 +530,9 @@ keyboard_handle_key(struct keyboard *keyboard, uint32_t time, const struct key *
if (state != WL_POINTER_BUTTON_STATE_PRESSED)
break;
- keyboard->keyboard->preedit_string = strcat(keyboard->keyboard->preedit_string,
- label);
+ keyboard->keyboard->preedit_string =
+ append(keyboard->keyboard->preedit_string,
+ label);
virtual_keyboard_send_preedit(keyboard->keyboard, -1);
break;
case keytype_backspace:
@@ -526,8 +556,8 @@ keyboard_handle_key(struct keyboard *keyboard, uint32_t time, const struct key *
case keytype_space:
if (state != WL_POINTER_BUTTON_STATE_PRESSED)
break;
- keyboard->keyboard->preedit_string = strcat(keyboard->keyboard->preedit_string,
- " ");
+ keyboard->keyboard->preedit_string =
+ append(keyboard->keyboard->preedit_string, " ");
virtual_keyboard_commit_preedit(keyboard->keyboard);
break;
case keytype_switch:
@@ -625,11 +655,9 @@ button_handler(struct widget *widget,
}
static void
-touch_down_handler(struct widget *widget, struct input *input,
- uint32_t serial, uint32_t time, int32_t id,
- float x, float y, void *data)
+touch_handler(struct input *input, uint32_t time,
+ float x, float y, uint32_t state, void *data)
{
-
struct keyboard *keyboard = data;
struct rectangle allocation;
int row, col;
@@ -648,20 +676,35 @@ touch_down_handler(struct widget *widget, struct input *input,
for (i = 0; i < layout->count; ++i) {
col -= layout->keys[i].width;
if (col < 0) {
- keyboard_handle_key(keyboard, time, &layout->keys[i], input, WL_POINTER_BUTTON_STATE_PRESSED);
+ keyboard_handle_key(keyboard, time,
+ &layout->keys[i], input, state);
break;
}
}
- widget_schedule_redraw(widget);
+ widget_schedule_redraw(keyboard->widget);
+}
+
+static void
+touch_down_handler(struct widget *widget, struct input *input,
+ uint32_t serial, uint32_t time, int32_t id,
+ float x, float y, void *data)
+{
+ touch_handler(input, time, x, y,
+ WL_POINTER_BUTTON_STATE_PRESSED, data);
}
static void
touch_up_handler(struct widget *widget, struct input *input,
- uint32_t serial, uint32_t time, int32_t id,
- void *data)
+ uint32_t serial, uint32_t time, int32_t id,
+ void *data)
{
+ float x, y;
+ input_get_touch(input, id, &x, &y);
+
+ touch_handler(input, time, x, y,
+ WL_POINTER_BUTTON_STATE_RELEASED, data);
}
static void
@@ -685,7 +728,7 @@ handle_reset(void *data,
{
struct virtual_keyboard *keyboard = data;
- fprintf(stderr, "Reset pre-edit buffer\n");
+ dbg("Reset pre-edit buffer\n");
if (strlen(keyboard->preedit_string)) {
free(keyboard->preedit_string);
@@ -732,7 +775,7 @@ handle_commit_state(void *data,
layout = get_current_layout(keyboard);
if (keyboard->surrounding_text)
- fprintf(stderr, "Surrounding text updated: %s\n", keyboard->surrounding_text);
+ dbg("Surrounding text updated: %s\n", keyboard->surrounding_text);
window_schedule_resize(keyboard->keyboard->window,
layout->columns * key_width,
@@ -882,7 +925,6 @@ keyboard_create(struct output *output, struct virtual_keyboard *virtual_keyboard
widget_set_touch_down_handler(keyboard->widget, touch_down_handler);
widget_set_touch_up_handler(keyboard->widget, touch_up_handler);
-
window_schedule_resize(keyboard->window,
layout->columns * key_width,
layout->rows * key_height);
diff --git a/clients/nested.c b/clients/nested.c
index 50852340..74767795 100644
--- a/clients/nested.c
+++ b/clients/nested.c
@@ -47,6 +47,18 @@
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#ifndef EGL_WL_create_wayland_buffer_from_image
+#define EGL_WL_create_wayland_buffer_from_image 1
+
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI struct wl_buffer * EGLAPIENTRY eglCreateWaylandBufferFromImageWL(EGLDisplay dpy, EGLImageKHR image);
+#endif
+typedef struct wl_buffer * (EGLAPIENTRYP PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL) (EGLDisplay dpy, EGLImageKHR image);
+
+#endif
+
+static int option_blit;
+
struct nested {
struct display *display;
struct window *window;
@@ -58,7 +70,8 @@ struct nested {
struct program *texture_program;
struct wl_list surface_list;
- struct wl_list frame_callback_list;
+
+ const struct nested_renderer *renderer;
};
struct nested_region {
@@ -66,52 +79,194 @@ struct nested_region {
pixman_region32_t region;
};
+struct nested_buffer_reference {
+ struct nested_buffer *buffer;
+ struct wl_listener destroy_listener;
+};
+
+struct nested_buffer {
+ struct wl_resource *resource;
+ struct wl_signal destroy_signal;
+ struct wl_listener destroy_listener;
+ uint32_t busy_count;
+
+ /* A buffer in the parent compositor representing the same
+ * data. This is created on-demand when the subsurface
+ * renderer is used */
+ struct wl_buffer *parent_buffer;
+ /* This reference is used to mark when the parent buffer has
+ * been attached to the subsurface. It will be unrefenced when
+ * we receive a buffer release event. That way we won't inform
+ * the client that the buffer is free until the parent
+ * compositor is also finished with it */
+ struct nested_buffer_reference parent_ref;
+};
+
struct nested_surface {
struct wl_resource *resource;
- struct wl_resource *buffer_resource;
struct nested *nested;
EGLImageKHR *image;
- GLuint texture;
struct wl_list link;
+
+ struct wl_list frame_callback_list;
+
+ struct {
+ /* wl_surface.attach */
+ int newly_attached;
+ struct nested_buffer *buffer;
+ struct wl_listener buffer_destroy_listener;
+
+ /* wl_surface.frame */
+ struct wl_list frame_callback_list;
+
+ /* wl_surface.damage */
+ pixman_region32_t damage;
+ } pending;
+
+ void *renderer_data;
+};
+
+/* Data used for the blit renderer */
+struct nested_blit_surface {
+ struct nested_buffer_reference buffer_ref;
+ GLuint texture;
cairo_surface_t *cairo_surface;
};
+/* Data used for the subsurface renderer */
+struct nested_ss_surface {
+ struct widget *widget;
+ struct wl_surface *surface;
+ struct wl_subsurface *subsurface;
+ struct wl_callback *frame_callback;
+};
+
struct nested_frame_callback {
struct wl_resource *resource;
struct wl_list link;
};
+struct nested_renderer {
+ void (* surface_init)(struct nested_surface *surface);
+ void (* surface_fini)(struct nested_surface *surface);
+ void (* render_clients)(struct nested *nested, cairo_t *cr);
+ void (* surface_attach)(struct nested_surface *surface,
+ struct nested_buffer *buffer);
+};
+
+static const struct weston_option nested_options[] = {
+ { WESTON_OPTION_BOOLEAN, "blit", 'b', &option_blit },
+};
+
+static const struct nested_renderer nested_blit_renderer;
+static const struct nested_renderer nested_ss_renderer;
+
static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
static PFNEGLCREATEIMAGEKHRPROC create_image;
static PFNEGLDESTROYIMAGEKHRPROC destroy_image;
static PFNEGLBINDWAYLANDDISPLAYWL bind_display;
static PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
static PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
+static PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL create_wayland_buffer_from_image;
static void
-frame_callback(void *data, struct wl_callback *callback, uint32_t time)
+nested_buffer_destroy_handler(struct wl_listener *listener, void *data)
{
- struct nested *nested = data;
- struct nested_frame_callback *nc, *next;
+ struct nested_buffer *buffer =
+ container_of(listener, struct nested_buffer, destroy_listener);
- if (callback)
- wl_callback_destroy(callback);
+ wl_signal_emit(&buffer->destroy_signal, buffer);
+
+ if (buffer->parent_buffer)
+ wl_buffer_destroy(buffer->parent_buffer);
+
+ free(buffer);
+}
+
+static struct nested_buffer *
+nested_buffer_from_resource(struct wl_resource *resource)
+{
+ struct nested_buffer *buffer;
+ struct wl_listener *listener;
+
+ listener =
+ wl_resource_get_destroy_listener(resource,
+ nested_buffer_destroy_handler);
+
+ if (listener)
+ return container_of(listener, struct nested_buffer,
+ destroy_listener);
+
+ buffer = zalloc(sizeof *buffer);
+ if (buffer == NULL)
+ return NULL;
- wl_list_for_each_safe(nc, next, &nested->frame_callback_list, link) {
+ buffer->resource = resource;
+ wl_signal_init(&buffer->destroy_signal);
+ buffer->destroy_listener.notify = nested_buffer_destroy_handler;
+ wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
+
+ return buffer;
+}
+
+static void
+nested_buffer_reference_handle_destroy(struct wl_listener *listener,
+ void *data)
+{
+ struct nested_buffer_reference *ref =
+ container_of(listener, struct nested_buffer_reference,
+ destroy_listener);
+
+ assert((struct nested_buffer *)data == ref->buffer);
+ ref->buffer = NULL;
+}
+
+static void
+nested_buffer_reference(struct nested_buffer_reference *ref,
+ struct nested_buffer *buffer)
+{
+ if (buffer == ref->buffer)
+ return;
+
+ if (ref->buffer) {
+ ref->buffer->busy_count--;
+ if (ref->buffer->busy_count == 0) {
+ assert(wl_resource_get_client(ref->buffer->resource));
+ wl_resource_queue_event(ref->buffer->resource,
+ WL_BUFFER_RELEASE);
+ }
+ wl_list_remove(&ref->destroy_listener.link);
+ }
+
+ if (buffer) {
+ buffer->busy_count++;
+ wl_signal_add(&buffer->destroy_signal,
+ &ref->destroy_listener);
+
+ ref->destroy_listener.notify =
+ nested_buffer_reference_handle_destroy;
+ }
+
+ ref->buffer = buffer;
+}
+
+static void
+flush_surface_frame_callback_list(struct nested_surface *surface,
+ uint32_t time)
+{
+ struct nested_frame_callback *nc, *next;
+
+ wl_list_for_each_safe(nc, next, &surface->frame_callback_list, link) {
wl_callback_send_done(nc->resource, time);
wl_resource_destroy(nc->resource);
}
- wl_list_init(&nested->frame_callback_list);
+ wl_list_init(&surface->frame_callback_list);
/* FIXME: toytoolkit need a pre-block handler where we can
* call this. */
- wl_display_flush_clients(nested->child_display);
+ wl_display_flush_clients(surface->nested->child_display);
}
-static const struct wl_callback_listener frame_listener = {
- frame_callback
-};
-
static void
redraw_handler(struct widget *widget, void *data)
{
@@ -119,8 +274,6 @@ redraw_handler(struct widget *widget, void *data)
cairo_surface_t *surface;
cairo_t *cr;
struct rectangle allocation;
- struct wl_callback *callback;
- struct nested_surface *s;
widget_get_allocation(nested->widget, &allocation);
@@ -136,34 +289,11 @@ redraw_handler(struct widget *widget, void *data)
cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
cairo_fill(cr);
- wl_list_for_each(s, &nested->surface_list, link) {
- display_acquire_window_surface(nested->display,
- nested->window, NULL);
-
- glBindTexture(GL_TEXTURE_2D, s->texture);
- image_target_texture_2d(GL_TEXTURE_2D, s->image);
-
- display_release_window_surface(nested->display,
- nested->window);
-
- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
- cairo_set_source_surface(cr, s->cairo_surface,
- allocation.x + 10,
- allocation.y + 10);
- cairo_rectangle(cr, allocation.x + 10,
- allocation.y + 10,
- allocation.width - 10,
- allocation.height - 10);
-
- cairo_fill(cr);
- }
+ nested->renderer->render_clients(nested, cr);
cairo_destroy(cr);
cairo_surface_destroy(surface);
-
- callback = wl_surface_frame(window_get_wl_surface(nested->window));
- wl_callback_add_listener(callback, &frame_listener, nested);
}
static void
@@ -264,6 +394,22 @@ static void
destroy_surface(struct wl_resource *resource)
{
struct nested_surface *surface = wl_resource_get_user_data(resource);
+ struct nested *nested = surface->nested;
+ struct nested_frame_callback *cb, *next;
+
+ wl_list_for_each_safe(cb, next,
+ &surface->frame_callback_list, link)
+ wl_resource_destroy(cb->resource);
+
+ wl_list_for_each_safe(cb, next,
+ &surface->pending.frame_callback_list, link)
+ wl_resource_destroy(cb->resource);
+
+ pixman_region32_fini(&surface->pending.damage);
+
+ nested->renderer->surface_fini(surface);
+
+ wl_list_remove(&surface->link);
free(surface);
}
@@ -281,54 +427,66 @@ surface_attach(struct wl_client *client,
{
struct nested_surface *surface = wl_resource_get_user_data(resource);
struct nested *nested = surface->nested;
- EGLint format, width, height;
- cairo_device_t *device;
+ struct nested_buffer *buffer = NULL;
- if (surface->buffer_resource)
- wl_buffer_send_release(surface->buffer_resource);
+ if (buffer_resource) {
+ int format;
- surface->buffer_resource = buffer_resource;
- if (!query_buffer(nested->egl_display, (void *) buffer_resource,
- EGL_TEXTURE_FORMAT, &format)) {
- fprintf(stderr, "attaching non-egl wl_buffer\n");
- return;
+ if (!query_buffer(nested->egl_display, (void *) buffer_resource,
+ EGL_TEXTURE_FORMAT, &format)) {
+ wl_resource_post_error(buffer_resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "attaching non-egl wl_buffer");
+ return;
+ }
+
+ switch (format) {
+ case EGL_TEXTURE_RGB:
+ case EGL_TEXTURE_RGBA:
+ break;
+ default:
+ wl_resource_post_error(buffer_resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "invalid format");
+ return;
+ }
+
+ buffer = nested_buffer_from_resource(buffer_resource);
+ if (buffer == NULL) {
+ wl_client_post_no_memory(client);
+ return;
+ }
}
+ if (surface->pending.buffer)
+ wl_list_remove(&surface->pending.buffer_destroy_listener.link);
+
+ surface->pending.buffer = buffer;
+ surface->pending.newly_attached = 1;
+ if (buffer) {
+ wl_signal_add(&buffer->destroy_signal,
+ &surface->pending.buffer_destroy_listener);
+ }
+}
+
+static void
+nested_surface_attach(struct nested_surface *surface,
+ struct nested_buffer *buffer)
+{
+ struct nested *nested = surface->nested;
+
if (surface->image != EGL_NO_IMAGE_KHR)
destroy_image(nested->egl_display, surface->image);
- if (surface->cairo_surface)
- cairo_surface_destroy(surface->cairo_surface);
-
- switch (format) {
- case EGL_TEXTURE_RGB:
- case EGL_TEXTURE_RGBA:
- break;
- default:
- fprintf(stderr, "unhandled format: %x\n", format);
- return;
- }
surface->image = create_image(nested->egl_display, NULL,
- EGL_WAYLAND_BUFFER_WL, buffer_resource,
+ EGL_WAYLAND_BUFFER_WL, buffer->resource,
NULL);
if (surface->image == EGL_NO_IMAGE_KHR) {
fprintf(stderr, "failed to create img\n");
return;
}
- query_buffer(nested->egl_display,
- (void *) buffer_resource, EGL_WIDTH, &width);
- query_buffer(nested->egl_display,
- (void *) buffer_resource, EGL_HEIGHT, &height);
-
- device = display_get_cairo_device(nested->display);
- surface->cairo_surface =
- cairo_gl_surface_create_for_texture(device,
- CAIRO_CONTENT_COLOR_ALPHA,
- surface->texture,
- width, height);
-
- window_schedule_redraw(nested->window);
+ nested->renderer->surface_attach(surface, buffer);
}
static void
@@ -336,6 +494,11 @@ surface_damage(struct wl_client *client,
struct wl_resource *resource,
int32_t x, int32_t y, int32_t width, int32_t height)
{
+ struct nested_surface *surface = wl_resource_get_user_data(resource);
+
+ pixman_region32_union_rect(&surface->pending.damage,
+ &surface->pending.damage,
+ x, y, width, height);
}
static void
@@ -353,7 +516,6 @@ surface_frame(struct wl_client *client,
{
struct nested_frame_callback *callback;
struct nested_surface *surface = wl_resource_get_user_data(resource);
- struct nested *nested = surface->nested;
callback = malloc(sizeof *callback);
if (callback == NULL) {
@@ -366,7 +528,8 @@ surface_frame(struct wl_client *client,
wl_resource_set_implementation(callback->resource, NULL, callback,
destroy_frame_callback);
- wl_list_insert(nested->frame_callback_list.prev, &callback->link);
+ wl_list_insert(surface->pending.frame_callback_list.prev,
+ &callback->link);
}
static void
@@ -386,8 +549,41 @@ surface_set_input_region(struct wl_client *client,
}
static void
+empty_region(pixman_region32_t *region)
+{
+ pixman_region32_fini(region);
+ pixman_region32_init(region);
+}
+
+static void
surface_commit(struct wl_client *client, struct wl_resource *resource)
{
+ struct nested_surface *surface = wl_resource_get_user_data(resource);
+ struct nested *nested = surface->nested;
+
+ /* wl_surface.attach */
+ if (surface->pending.newly_attached)
+ nested_surface_attach(surface, surface->pending.buffer);
+
+ if (surface->pending.buffer) {
+ wl_list_remove(&surface->pending.buffer_destroy_listener.link);
+ surface->pending.buffer = NULL;
+ }
+ surface->pending.newly_attached = 0;
+
+ /* wl_surface.damage */
+ empty_region(&surface->pending.damage);
+
+ /* wl_surface.frame */
+ wl_list_insert_list(&surface->frame_callback_list,
+ &surface->pending.frame_callback_list);
+ wl_list_init(&surface->pending.frame_callback_list);
+
+ /* FIXME: For the subsurface renderer we don't need to
+ * actually redraw the window. However we do want to cause a
+ * commit because the subsurface is synchronized. Ideally we
+ * would just queue the commit */
+ window_schedule_redraw(nested->window);
}
static void
@@ -409,6 +605,16 @@ static const struct wl_surface_interface surface_interface = {
};
static void
+surface_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
+{
+ struct nested_surface *surface =
+ container_of(listener, struct nested_surface,
+ pending.buffer_destroy_listener);
+
+ surface->pending.buffer = NULL;
+}
+
+static void
compositor_create_surface(struct wl_client *client,
struct wl_resource *resource, uint32_t id)
{
@@ -423,15 +629,17 @@ compositor_create_surface(struct wl_client *client,
surface->nested = nested;
+ wl_list_init(&surface->frame_callback_list);
+
+ wl_list_init(&surface->pending.frame_callback_list);
+ surface->pending.buffer_destroy_listener.notify =
+ surface_handle_pending_buffer_destroy;
+ pixman_region32_init(&surface->pending.damage);
+
display_acquire_window_surface(nested->display,
nested->window, NULL);
- glGenTextures(1, &surface->texture);
- glBindTexture(GL_TEXTURE_2D, surface->texture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ nested->renderer->surface_init(surface);
display_release_window_surface(nested->display, nested->window);
@@ -531,10 +739,10 @@ nested_init_compositor(struct nested *nested)
{
const char *extensions;
struct wl_event_loop *loop;
+ int use_ss_renderer = 0;
int fd, ret;
wl_list_init(&nested->surface_list);
- wl_list_init(&nested->frame_callback_list);
nested->child_display = wl_display_create();
loop = wl_display_get_event_loop(nested->child_display);
fd = wl_event_loop_get_fd(loop);
@@ -570,6 +778,29 @@ nested_init_compositor(struct nested *nested)
return -1;
}
+ if (display_has_subcompositor(nested->display)) {
+ const char *func = "eglCreateWaylandBufferFromImageWL";
+ const char *ext = "EGL_WL_create_wayland_buffer_from_image";
+
+ if (strstr(extensions, ext)) {
+ create_wayland_buffer_from_image =
+ (void *) eglGetProcAddress(func);
+ use_ss_renderer = 1;
+ }
+ }
+
+ if (option_blit)
+ use_ss_renderer = 0;
+
+ if (use_ss_renderer) {
+ printf("Using subsurfaces to render client surfaces\n");
+ nested->renderer = &nested_ss_renderer;
+ } else {
+ printf("Using local compositing with blits to "
+ "render client surfaces\n");
+ nested->renderer = &nested_blit_renderer;
+ }
+
return 0;
}
@@ -583,7 +814,7 @@ nested_create(struct display *display)
return nested;
nested->window = window_create(display);
- nested->widget = frame_create(nested->window, nested);
+ nested->widget = window_frame_create(nested->window, nested);
window_set_title(nested->window, "Wayland Nested");
nested->display = display;
@@ -607,12 +838,289 @@ nested_destroy(struct nested *nested)
free(nested);
}
+/*** blit renderer ***/
+
+static void
+blit_surface_init(struct nested_surface *surface)
+{
+ struct nested_blit_surface *blit_surface =
+ zalloc(sizeof *blit_surface);
+
+ glGenTextures(1, &blit_surface->texture);
+ glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ surface->renderer_data = blit_surface;
+}
+
+static void
+blit_surface_fini(struct nested_surface *surface)
+{
+ struct nested_blit_surface *blit_surface = surface->renderer_data;
+
+ nested_buffer_reference(&blit_surface->buffer_ref, NULL);
+
+ glDeleteTextures(1, &blit_surface->texture);
+
+ free(blit_surface);
+}
+
+static void
+blit_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
+{
+ struct nested *nested = data;
+ struct nested_surface *surface;
+
+ wl_list_for_each(surface, &nested->surface_list, link)
+ flush_surface_frame_callback_list(surface, time);
+
+ if (callback)
+ wl_callback_destroy(callback);
+}
+
+static const struct wl_callback_listener blit_frame_listener = {
+ blit_frame_callback
+};
+
+static void
+blit_render_clients(struct nested *nested,
+ cairo_t *cr)
+{
+ struct nested_surface *s;
+ struct rectangle allocation;
+ struct wl_callback *callback;
+
+ widget_get_allocation(nested->widget, &allocation);
+
+ wl_list_for_each(s, &nested->surface_list, link) {
+ struct nested_blit_surface *blit_surface = s->renderer_data;
+
+ display_acquire_window_surface(nested->display,
+ nested->window, NULL);
+
+ glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
+ image_target_texture_2d(GL_TEXTURE_2D, s->image);
+
+ display_release_window_surface(nested->display,
+ nested->window);
+
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ cairo_set_source_surface(cr, blit_surface->cairo_surface,
+ allocation.x + 10,
+ allocation.y + 10);
+ cairo_rectangle(cr, allocation.x + 10,
+ allocation.y + 10,
+ allocation.width - 10,
+ allocation.height - 10);
+
+ cairo_fill(cr);
+ }
+
+ callback = wl_surface_frame(window_get_wl_surface(nested->window));
+ wl_callback_add_listener(callback, &blit_frame_listener, nested);
+}
+
+static void
+blit_surface_attach(struct nested_surface *surface,
+ struct nested_buffer *buffer)
+{
+ struct nested *nested = surface->nested;
+ struct nested_blit_surface *blit_surface = surface->renderer_data;
+ EGLint width, height;
+ cairo_device_t *device;
+
+ nested_buffer_reference(&blit_surface->buffer_ref, buffer);
+
+ if (blit_surface->cairo_surface)
+ cairo_surface_destroy(blit_surface->cairo_surface);
+
+ query_buffer(nested->egl_display, (void *) buffer->resource,
+ EGL_WIDTH, &width);
+ query_buffer(nested->egl_display, (void *) buffer->resource,
+ EGL_HEIGHT, &height);
+
+ device = display_get_cairo_device(nested->display);
+ blit_surface->cairo_surface =
+ cairo_gl_surface_create_for_texture(device,
+ CAIRO_CONTENT_COLOR_ALPHA,
+ blit_surface->texture,
+ width, height);
+}
+
+static const struct nested_renderer
+nested_blit_renderer = {
+ .surface_init = blit_surface_init,
+ .surface_fini = blit_surface_fini,
+ .render_clients = blit_render_clients,
+ .surface_attach = blit_surface_attach
+};
+
+/*** subsurface renderer ***/
+
+static void
+ss_surface_init(struct nested_surface *surface)
+{
+ struct nested *nested = surface->nested;
+ struct wl_compositor *compositor =
+ display_get_compositor(nested->display);
+ struct nested_ss_surface *ss_surface =
+ zalloc(sizeof *ss_surface);
+ struct rectangle allocation;
+ struct wl_region *region;
+
+ ss_surface->widget =
+ window_add_subsurface(nested->window,
+ nested,
+ SUBSURFACE_SYNCHRONIZED);
+
+ ss_surface->surface = widget_get_wl_surface(ss_surface->widget);
+ ss_surface->subsurface = widget_get_wl_subsurface(ss_surface->widget);
+
+ /* The toy toolkit gets confused about the pointer position
+ * when it gets motion events for a subsurface so we'll just
+ * disable input on it */
+ region = wl_compositor_create_region(compositor);
+ wl_surface_set_input_region(ss_surface->surface, region);
+ wl_region_destroy(region);
+
+ widget_get_allocation(nested->widget, &allocation);
+ wl_subsurface_set_position(ss_surface->subsurface,
+ allocation.x + 10,
+ allocation.y + 10);
+
+ surface->renderer_data = ss_surface;
+}
+
+static void
+ss_surface_fini(struct nested_surface *surface)
+{
+ struct nested_ss_surface *ss_surface = surface->renderer_data;
+
+ widget_destroy(ss_surface->widget);
+
+ if (ss_surface->frame_callback)
+ wl_callback_destroy(ss_surface->frame_callback);
+
+ free(ss_surface);
+}
+
+static void
+ss_render_clients(struct nested *nested,
+ cairo_t *cr)
+{
+ /* The clients are composited by the parent compositor so we
+ * don't need to do anything here */
+}
+
+static void
+ss_buffer_release(void *data, struct wl_buffer *wl_buffer)
+{
+ struct nested_buffer *buffer = data;
+
+ nested_buffer_reference(&buffer->parent_ref, NULL);
+}
+
+static struct wl_buffer_listener ss_buffer_listener = {
+ ss_buffer_release
+};
+
+static void
+ss_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
+{
+ struct nested_surface *surface = data;
+ struct nested_ss_surface *ss_surface = surface->renderer_data;
+
+ flush_surface_frame_callback_list(surface, time);
+
+ if (callback)
+ wl_callback_destroy(callback);
+
+ ss_surface->frame_callback = NULL;
+}
+
+static const struct wl_callback_listener ss_frame_listener = {
+ ss_frame_callback
+};
+
+static void
+ss_surface_attach(struct nested_surface *surface,
+ struct nested_buffer *buffer)
+{
+ struct nested *nested = surface->nested;
+ struct nested_ss_surface *ss_surface = surface->renderer_data;
+ struct wl_buffer *parent_buffer;
+ const pixman_box32_t *rects;
+ int n_rects, i;
+
+ if (buffer) {
+ /* Create a representation of the buffer in the parent
+ * compositor if we haven't already */
+ if (buffer->parent_buffer == NULL) {
+ EGLDisplay *edpy = nested->egl_display;
+ EGLImageKHR image = surface->image;
+
+ buffer->parent_buffer =
+ create_wayland_buffer_from_image(edpy, image);
+
+ wl_buffer_add_listener(buffer->parent_buffer,
+ &ss_buffer_listener,
+ buffer);
+ }
+
+ parent_buffer = buffer->parent_buffer;
+
+ /* We'll take a reference to the buffer while the parent
+ * compositor is using it so that we won't report the release
+ * event until the parent has also finished with it */
+ nested_buffer_reference(&buffer->parent_ref, buffer);
+ } else {
+ parent_buffer = NULL;
+ }
+
+ wl_surface_attach(ss_surface->surface, parent_buffer, 0, 0);
+
+ rects = pixman_region32_rectangles(&surface->pending.damage, &n_rects);
+
+ for (i = 0; i < n_rects; i++) {
+ const pixman_box32_t *rect = rects + i;
+ wl_surface_damage(ss_surface->surface,
+ rect->x1,
+ rect->y1,
+ rect->x2 - rect->x1,
+ rect->y2 - rect->y1);
+ }
+
+ if (ss_surface->frame_callback)
+ wl_callback_destroy(ss_surface->frame_callback);
+
+ ss_surface->frame_callback = wl_surface_frame(ss_surface->surface);
+ wl_callback_add_listener(ss_surface->frame_callback,
+ &ss_frame_listener,
+ surface);
+
+ wl_surface_commit(ss_surface->surface);
+}
+
+static const struct nested_renderer
+nested_ss_renderer = {
+ .surface_init = ss_surface_init,
+ .surface_fini = ss_surface_fini,
+ .render_clients = ss_render_clients,
+ .surface_attach = ss_surface_attach
+};
+
int
main(int argc, char *argv[])
{
struct display *display;
struct nested *nested;
+ parse_options(nested_options,
+ ARRAY_LENGTH(nested_options), &argc, argv);
+
display = display_create(&argc, argv);
if (display == NULL) {
fprintf(stderr, "failed to create display: %m\n");
diff --git a/clients/resizor.c b/clients/resizor.c
index 68e4bf9a..9cf1a3c6 100644
--- a/clients/resizor.c
+++ b/clients/resizor.c
@@ -195,7 +195,8 @@ key_handler(struct window *window, struct input *input, uint32_t time,
}
static void
-menu_func(struct window *window, int index, void *user_data)
+menu_func(struct window *window,
+ struct input *input, int index, void *user_data)
{
fprintf(stderr, "picked entry %d\n", index);
}
@@ -235,7 +236,7 @@ resizor_create(struct display *display)
resizor = xzalloc(sizeof *resizor);
resizor->window = window_create(display);
- resizor->widget = frame_create(resizor->window, resizor);
+ resizor->widget = window_frame_create(resizor->window, resizor);
window_set_title(resizor->window, "Wayland Resizor");
resizor->display = display;
diff --git a/clients/scaler.c b/clients/scaler.c
new file mode 100644
index 00000000..97530961
--- /dev/null
+++ b/clients/scaler.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ * Copyright © 2013 Collabora, Ltd.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <cairo.h>
+
+#include <linux/input.h>
+
+#include "window.h"
+#include "scaler-client-protocol.h"
+
+#define BUFFER_SCALE 2
+static const int BUFFER_WIDTH = 421 * BUFFER_SCALE;
+static const int BUFFER_HEIGHT = 337 * BUFFER_SCALE;
+static const int SURFACE_WIDTH = 55 * 4;
+static const int SURFACE_HEIGHT = 77 * 4;
+static const double RECT_X = 21 * BUFFER_SCALE; /* buffer coords */
+static const double RECT_Y = 25 * BUFFER_SCALE;
+static const double RECT_W = 55 * BUFFER_SCALE;
+static const double RECT_H = 77 * BUFFER_SCALE;
+
+struct box {
+ struct display *display;
+ struct window *window;
+ struct widget *widget;
+ int width, height;
+
+ struct wl_scaler *scaler;
+ struct wl_viewport *viewport;
+};
+
+static void
+resize_handler(struct widget *widget,
+ int32_t width, int32_t height, void *data)
+{
+ struct box *box = data;
+
+ /* Dont resize me */
+ widget_set_size(box->widget, box->width, box->height);
+}
+
+static void
+redraw_handler(struct widget *widget, void *data)
+{
+ struct box *box = data;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+
+ surface = window_get_surface(box->window);
+ if (surface == NULL ||
+ cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
+ fprintf(stderr, "failed to create cairo egl surface\n");
+ return;
+ }
+
+ cr = cairo_create(surface);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_line_width(cr, 1.0);
+ cairo_translate(cr, RECT_X, RECT_Y);
+
+ /* red background */
+ cairo_set_source_rgba(cr, 255, 0, 0, 255);
+ cairo_paint(cr);
+
+ /* blue box */
+ cairo_set_source_rgba(cr, 0, 0, 255, 255);
+ cairo_rectangle(cr, 0, 0, RECT_W, RECT_H);
+ cairo_fill(cr);
+
+ /* black border outside the box */
+ cairo_set_source_rgb(cr, 0, 0, 0);
+ cairo_move_to(cr, 0, RECT_H + 0.5);
+ cairo_line_to(cr, RECT_W, RECT_H + 0.5);
+ cairo_stroke(cr);
+
+ /* white border inside the box */
+ cairo_set_source_rgb(cr, 1, 1, 1);
+ cairo_move_to(cr, RECT_W - 0.5, 0);
+ cairo_line_to(cr, RECT_W - 0.5, RECT_H);
+ cairo_stroke(cr);
+
+ /* the green border on inside the box, to be split half by crop */
+ cairo_set_source_rgb(cr, 0, 1, 0);
+ cairo_move_to(cr, 0.5, RECT_H);
+ cairo_line_to(cr, 0.5, 0);
+ cairo_move_to(cr, 0, 0.5);
+ cairo_line_to(cr, RECT_W, 0.5);
+ cairo_stroke(cr);
+
+ cairo_destroy(cr);
+
+ /* TODO: buffer_transform */
+
+ cairo_surface_destroy(surface);
+}
+
+static void
+global_handler(struct display *display, uint32_t name,
+ const char *interface, uint32_t version, void *data)
+{
+ struct box *box = data;
+ wl_fixed_t src_x, src_y, src_width, src_height;
+
+ /* Cut the green border in half, take white border fully in,
+ * and black border fully out. The borders are 1px wide in buffer.
+ *
+ * The gl-renderer uses linear texture sampling, this means the
+ * top and left edges go to 100% green, bottom goes to 50% blue/black,
+ * right edge has thick white sliding to 50% red.
+ */
+ src_x = wl_fixed_from_double((RECT_X + 0.5) / BUFFER_SCALE);
+ src_y = wl_fixed_from_double((RECT_Y + 0.5) / BUFFER_SCALE);
+ src_width = wl_fixed_from_double((RECT_W - 0.5) / BUFFER_SCALE);
+ src_height = wl_fixed_from_double((RECT_H - 0.5) / BUFFER_SCALE);
+
+ if (strcmp(interface, "wl_scaler") == 0) {
+ box->scaler = display_bind(display, name,
+ &wl_scaler_interface, 1);
+
+ box->viewport = wl_scaler_get_viewport(box->scaler,
+ widget_get_wl_surface(box->widget));
+
+ wl_viewport_set(box->viewport,
+ src_x, src_y, src_width, src_height,
+ SURFACE_WIDTH, SURFACE_HEIGHT); /* dst */
+ }
+}
+
+static void
+button_handler(struct widget *widget,
+ struct input *input, uint32_t time,
+ uint32_t button, enum wl_pointer_button_state state, void *data)
+{
+ struct box *box = data;
+
+ if (button != BTN_LEFT)
+ return;
+
+ if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
+ window_move(box->window, input,
+ display_get_serial(box->display));
+ }
+}
+
+static void
+touch_down_handler(struct widget *widget, struct input *input,
+ uint32_t serial, uint32_t time, int32_t id,
+ float x, float y, void *data)
+{
+ struct box *box = data;
+ window_move(box->window, input,
+ display_get_serial(box->display));
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct box box;
+ struct display *d;
+ struct timeval tv;
+
+ d = display_create(&argc, argv);
+ if (d == NULL) {
+ fprintf(stderr, "failed to create display: %m\n");
+ return -1;
+ }
+
+ gettimeofday(&tv, NULL);
+ srandom(tv.tv_usec);
+
+ box.width = BUFFER_WIDTH / BUFFER_SCALE;
+ box.height = BUFFER_HEIGHT / BUFFER_SCALE;
+ box.display = d;
+ box.window = window_create(d);
+ box.widget = window_add_widget(box.window, &box);
+ window_set_title(box.window, "Scaler Test Box");
+ window_set_buffer_scale(box.window, BUFFER_SCALE);
+
+ widget_set_resize_handler(box.widget, resize_handler);
+ widget_set_redraw_handler(box.widget, redraw_handler);
+ widget_set_button_handler(box.widget, button_handler);
+ widget_set_default_cursor(box.widget, CURSOR_HAND1);
+ widget_set_touch_down_handler(box.widget, touch_down_handler);
+
+ window_schedule_resize(box.window, box.width, box.height);
+
+ display_set_user_data(box.display, &box);
+ display_set_global_handler(box.display, global_handler);
+
+ display_run(d);
+
+ window_destroy(box.window);
+ return 0;
+}
diff --git a/clients/simple-egl.c b/clients/simple-egl.c
index 1fd41379..2c009ee2 100644
--- a/clients/simple-egl.c
+++ b/clients/simple-egl.c
@@ -87,12 +87,13 @@ struct window {
GLuint col;
} gl;
+ uint32_t benchmark_time, frames;
struct wl_egl_window *native;
struct wl_surface *surface;
struct wl_shell_surface *shell_surface;
EGLSurface egl_surface;
struct wl_callback *callback;
- int fullscreen, configured, opaque;
+ int fullscreen, configured, opaque, buffer_size, frame_sync;
};
static const char *vert_shader_text =
@@ -115,7 +116,7 @@ static const char *frag_shader_text =
static int running = 1;
static void
-init_egl(struct display *display, int opaque)
+init_egl(struct display *display, struct window *window)
{
static const EGLint context_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
@@ -128,15 +129,15 @@ init_egl(struct display *display, int opaque)
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
- EGL_ALPHA_SIZE, 1,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};
- EGLint major, minor, n;
+ EGLint major, minor, n, count, i, size;
+ EGLConfig *configs;
EGLBoolean ret;
- if (opaque)
+ if (window->opaque || window->buffer_size == 16)
config_attribs[9] = 0;
display->egl.dpy = eglGetDisplay(display->display);
@@ -147,9 +148,30 @@ init_egl(struct display *display, int opaque)
ret = eglBindAPI(EGL_OPENGL_ES_API);
assert(ret == EGL_TRUE);
+ if (!eglGetConfigs(display->egl.dpy, NULL, 0, &count) || count < 1)
+ assert(0);
+
+ configs = calloc(count, sizeof *configs);
+ assert(configs);
+
ret = eglChooseConfig(display->egl.dpy, config_attribs,
- &display->egl.conf, 1, &n);
- assert(ret && n == 1);
+ configs, count, &n);
+ assert(ret && n >= 1);
+
+ for (i = 0; i < n; i++) {
+ eglGetConfigAttrib(display->egl.dpy,
+ configs[i], EGL_BUFFER_SIZE, &size);
+ if (window->buffer_size == size) {
+ display->egl.conf = configs[i];
+ break;
+ }
+ }
+ free(configs);
+ if (display->egl.conf == NULL) {
+ fprintf(stderr, "did not find config with buffer size %d\n",
+ window->buffer_size);
+ exit(EXIT_FAILURE);
+ }
display->egl.ctx = eglCreateContext(display->egl.dpy,
display->egl.conf,
@@ -275,9 +297,6 @@ static const struct wl_shell_surface_listener shell_surface_listener = {
};
static void
-redraw(void *data, struct wl_callback *callback, uint32_t time);
-
-static void
configure_callback(void *data, struct wl_callback *callback, uint32_t time)
{
struct window *window = data;
@@ -285,9 +304,6 @@ configure_callback(void *data, struct wl_callback *callback, uint32_t time)
wl_callback_destroy(callback);
window->configured = 1;
-
- if (window->callback == NULL)
- redraw(data, NULL, time);
}
static struct wl_callback_listener configure_callback_listener = {
@@ -295,7 +311,7 @@ static struct wl_callback_listener configure_callback_listener = {
};
static void
-toggle_fullscreen(struct window *window, int fullscreen)
+set_fullscreen(struct window *window, int fullscreen)
{
struct wl_callback *callback;
@@ -306,16 +322,18 @@ toggle_fullscreen(struct window *window, int fullscreen)
wl_shell_surface_set_fullscreen(window->shell_surface,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
0, NULL);
+ callback = wl_display_sync(window->display->display);
+ wl_callback_add_listener(callback,
+ &configure_callback_listener,
+ window);
+
} else {
wl_shell_surface_set_toplevel(window->shell_surface);
handle_configure(window, window->shell_surface, 0,
window->window_size.width,
window->window_size.height);
+ window->configured = 1;
}
-
- callback = wl_display_sync(window->display->display);
- wl_callback_add_listener(callback, &configure_callback_listener,
- window);
}
static void
@@ -346,7 +364,10 @@ create_surface(struct window *window)
window->egl_surface, window->display->egl.ctx);
assert(ret == EGL_TRUE);
- toggle_fullscreen(window, window->fullscreen);
+ if (!window->frame_sync)
+ eglSwapInterval(display->egl.dpy, 0);
+
+ set_fullscreen(window, window->fullscreen);
}
static void
@@ -391,11 +412,11 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
{ 0, 0, 1, 0 },
{ 0, 0, 0, 1 }
};
- static const int32_t speed_div = 5;
- static uint32_t start_time = 0;
+ static const int32_t speed_div = 5, benchmark_interval = 5;
struct wl_region *region;
EGLint rect[4];
EGLint buffer_age = 0;
+ struct timeval tv;
assert(window->callback == callback);
window->callback = NULL;
@@ -406,10 +427,20 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
if (!window->configured)
return;
- if (start_time == 0)
- start_time = time;
+ gettimeofday(&tv, NULL);
+ time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+ if (window->frames == 0)
+ window->benchmark_time = time;
+ if (time - window->benchmark_time > (benchmark_interval * 1000)) {
+ printf("%d frames in %d seconds: %f fps\n",
+ window->frames,
+ benchmark_interval,
+ (float) window->frames / benchmark_interval);
+ window->benchmark_time = time;
+ window->frames = 0;
+ }
- angle = ((time-start_time) / speed_div) % 360 * M_PI / 180.0;
+ angle = (time / speed_div) % 360 * M_PI / 180.0;
rotation[0][0] = cos(angle);
rotation[0][2] = sin(angle);
rotation[2][0] = -sin(angle);
@@ -448,9 +479,6 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
wl_surface_set_opaque_region(window->surface, NULL);
}
- window->callback = wl_surface_frame(window->surface);
- wl_callback_add_listener(window->callback, &frame_listener, window);
-
if (display->swap_buffers_with_damage && buffer_age > 0) {
rect[0] = window->geometry.width / 4 - 1;
rect[1] = window->geometry.height / 4 - 1;
@@ -462,6 +490,7 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
} else {
eglSwapBuffers(display->egl.dpy, window->egl_surface);
}
+ window->frames++;
}
static const struct wl_callback_listener frame_listener = {
@@ -599,7 +628,7 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
struct display *d = data;
if (key == KEY_F11 && state)
- toggle_fullscreen(d->window, d->window->fullscreen ^ 1);
+ set_fullscreen(d->window, d->window->fullscreen ^ 1);
else if (key == KEY_ESC && state)
running = 0;
}
@@ -705,6 +734,8 @@ usage(int error_code)
fprintf(stderr, "Usage: simple-egl [OPTIONS]\n\n"
" -f\tRun in fullscreen mode\n"
" -o\tCreate an opaque surface\n"
+ " -s\tUse a 16 bpp EGL config\n"
+ " -b\tDon't sync to compositor redraw (eglSwapInterval 0)\n"
" -h\tThis help text\n\n");
exit(error_code);
@@ -722,12 +753,18 @@ main(int argc, char **argv)
display.window = &window;
window.window_size.width = 250;
window.window_size.height = 250;
+ window.buffer_size = 32;
+ window.frame_sync = 1;
for (i = 1; i < argc; i++) {
if (strcmp("-f", argv[i]) == 0)
window.fullscreen = 1;
else if (strcmp("-o", argv[i]) == 0)
window.opaque = 1;
+ else if (strcmp("-s", argv[i]) == 0)
+ window.buffer_size = 16;
+ else if (strcmp("-b", argv[i]) == 0)
+ window.frame_sync = 0;
else if (strcmp("-h", argv[i]) == 0)
usage(EXIT_SUCCESS);
else
@@ -743,7 +780,7 @@ main(int argc, char **argv)
wl_display_dispatch(display.display);
- init_egl(&display, window.opaque);
+ init_egl(&display, &window);
create_surface(&window);
init_gl(&window);
@@ -755,8 +792,16 @@ main(int argc, char **argv)
sigint.sa_flags = SA_RESETHAND;
sigaction(SIGINT, &sigint, NULL);
- while (running && ret != -1)
- ret = wl_display_dispatch(display.display);
+ /* The mainloop here is a little subtle. Redrawing will cause
+ * EGL to read events so we can just call
+ * wl_display_dispatch_pending() to handle any events that got
+ * queued up as a side effect. */
+ while (running && ret != -1) {
+ wl_display_dispatch_pending(display.display);
+ while (!window.configured)
+ wl_display_dispatch(display.display);
+ redraw(&window, NULL, 0);
+ }
fprintf(stderr, "simple-egl exiting\n");
diff --git a/clients/stacking.c b/clients/stacking.c
new file mode 100644
index 00000000..544094c6
--- /dev/null
+++ b/clients/stacking.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright © 2013 Collabora Ltd.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <linux/input.h>
+#include <cairo.h>
+
+#include "window.h"
+
+struct stacking {
+ struct display *display;
+ struct window *root_window;
+};
+
+static void
+button_handler(struct widget *widget,
+ struct input *input, uint32_t time,
+ uint32_t button,
+ enum wl_pointer_button_state state, void *data);
+static void
+key_handler(struct window *window,
+ struct input *input, uint32_t time,
+ uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
+ void *data);
+static void
+keyboard_focus_handler(struct window *window,
+ struct input *device, void *data);
+static void
+fullscreen_handler(struct window *window, void *data);
+static void
+redraw_handler(struct widget *widget, void *data);
+
+/* Iff parent_window is set, the new window will be transient. */
+static struct window *
+new_window(struct stacking *stacking, struct window *parent_window)
+{
+ struct window *new_window;
+ struct widget *new_widget;
+
+ if (parent_window == NULL) {
+ new_window = window_create(stacking->display);
+ } else {
+ new_window = window_create_transient(stacking->display,
+ parent_window, 50, 50, 0);
+ }
+
+ new_widget = window_frame_create(new_window, new_window);
+
+ window_set_title(new_window, "Stacking Test");
+ window_set_key_handler(new_window, key_handler);
+ window_set_keyboard_focus_handler(new_window, keyboard_focus_handler);
+ window_set_fullscreen_handler(new_window, fullscreen_handler);
+ widget_set_button_handler(new_widget, button_handler);
+ widget_set_redraw_handler(new_widget, redraw_handler);
+ window_set_user_data(new_window, stacking);
+
+ window_schedule_resize(new_window, 300, 300);
+
+ return new_window;
+}
+
+static void
+show_popup_cb(struct window *window, struct input *input, int index, void *data)
+{
+ /* Ignore the selected menu item. */
+}
+
+static void
+show_popup(struct stacking *stacking, struct input *input, uint32_t time,
+ struct window *window)
+{
+ int32_t x, y;
+ static const char *entries[] = {
+ "Test Entry",
+ "Another Test Entry",
+ };
+
+ input_get_position(input, &x, &y);
+ window_show_menu(stacking->display, input, time, window, x, y,
+ show_popup_cb, entries, ARRAY_LENGTH(entries));
+}
+
+static void
+button_handler(struct widget *widget,
+ struct input *input, uint32_t time,
+ uint32_t button,
+ enum wl_pointer_button_state state, void *data)
+{
+ struct stacking *stacking = data;
+
+ switch (button) {
+ case BTN_RIGHT:
+ if (state == WL_POINTER_BUTTON_STATE_PRESSED)
+ show_popup(stacking, input, time,
+ widget_get_user_data(widget));
+ break;
+
+ case BTN_LEFT:
+ default:
+ break;
+ }
+}
+
+static void
+key_handler(struct window *window,
+ struct input *input, uint32_t time,
+ uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
+ void *data)
+{
+ struct stacking *stacking = data;
+
+ if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
+ return;
+
+ switch (sym) {
+ case XKB_KEY_f:
+ fullscreen_handler(window, data);
+ break;
+
+ case XKB_KEY_m:
+ window_set_maximized(window, !window_is_maximized(window));
+ break;
+
+ case XKB_KEY_n:
+ /* New top-level window. */
+ new_window(stacking, NULL);
+ break;
+
+ case XKB_KEY_p:
+ show_popup(stacking, input, time, window);
+ break;
+
+ case XKB_KEY_q:
+ exit (0);
+ break;
+
+ case XKB_KEY_t:
+ /* New transient window. */
+ new_window(stacking, window);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+keyboard_focus_handler(struct window *window,
+ struct input *device, void *data)
+{
+ window_schedule_redraw(window);
+}
+
+static void
+fullscreen_handler(struct window *window, void *data)
+{
+ window_set_fullscreen(window, !window_is_fullscreen(window));
+}
+
+static void
+draw_string(cairo_t *cr,
+ const char *fmt, ...) __attribute__((format (gnu_printf, 2, 3)));
+
+static void
+draw_string(cairo_t *cr,
+ const char *fmt, ...)
+{
+ char buffer[4096];
+ char *p, *end;
+ va_list argp;
+ cairo_text_extents_t text_extents;
+ cairo_font_extents_t font_extents;
+
+ cairo_save(cr);
+
+ cairo_select_font_face(cr, "sans",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size(cr, 14);
+
+ cairo_font_extents(cr, &font_extents);
+
+ va_start(argp, fmt);
+
+ vsnprintf(buffer, sizeof(buffer), fmt, argp);
+
+ p = buffer;
+ while (*p) {
+ end = strchr(p, '\n');
+ if (end)
+ *end = 0;
+
+ cairo_show_text(cr, p);
+ cairo_text_extents(cr, p, &text_extents);
+ cairo_rel_move_to(cr, -text_extents.x_advance, font_extents.height);
+
+ if (end)
+ p = end + 1;
+ else
+ break;
+ }
+
+ va_end(argp);
+
+ cairo_restore(cr);
+}
+
+static void
+set_window_background_colour(cairo_t *cr, struct window *window)
+{
+ if (window_is_transient(window))
+ cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 0.4);
+ else if (window_is_maximized(window))
+ cairo_set_source_rgba(cr, 1.0, 1.0, 0.0, 0.6);
+ else if (window_is_fullscreen(window))
+ cairo_set_source_rgba(cr, 0.0, 1.0, 1.0, 0.6);
+ else
+ cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
+}
+
+static void
+redraw_handler(struct widget *widget, void *data)
+{
+ struct window *window;
+ struct rectangle allocation;
+ cairo_t *cr;
+
+ widget_get_allocation(widget, &allocation);
+ window = widget_get_user_data(widget);
+
+ cr = widget_cairo_create(widget);
+ cairo_translate(cr, allocation.x, allocation.y);
+
+ /* Draw background. */
+ cairo_push_group(cr);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ set_window_background_colour(cr, window);
+ cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
+ cairo_fill(cr);
+
+ cairo_pop_group_to_source(cr);
+ cairo_paint(cr);
+
+ /* Print the instructions. */
+ cairo_move_to(cr, 5, 15);
+ cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+
+ draw_string(cr,
+ "Window: %p\n"
+ "Fullscreen? %u\n"
+ "Maximized? %u\n"
+ "Transient? %u\n"
+ "Keys: (f)ullscreen, (m)aximize,\n"
+ " (n)ew window, (p)opup,\n"
+ " (q)uit, (t)ransient window\n",
+ window, window_is_fullscreen(window),
+ window_is_maximized(window), window_is_transient(window));
+
+ cairo_destroy(cr);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct stacking stacking;
+
+ memset(&stacking, 0, sizeof stacking);
+
+#ifdef HAVE_PANGO
+ g_type_init();
+#endif
+
+ stacking.display = display_create(&argc, argv);
+ if (stacking.display == NULL) {
+ fprintf(stderr, "Failed to create display: %m\n");
+ return -1;
+ }
+
+ display_set_user_data(stacking.display, &stacking);
+
+ stacking.root_window = new_window(&stacking, NULL);
+
+ display_run(stacking.display);
+
+ return 0;
+}
diff --git a/clients/subsurfaces.c b/clients/subsurfaces.c
index 101ff17e..45cc44b4 100644
--- a/clients/subsurfaces.c
+++ b/clients/subsurfaces.c
@@ -498,6 +498,7 @@ triangle_create(struct window *window, struct egl_state *egl)
tri->egl = egl;
tri->widget = window_add_subsurface(window, tri,
int_to_mode(option_triangle_mode));
+ widget_set_use_cairo(tri->widget, 0);
widget_set_resize_handler(tri->widget, triangle_resize_handler);
widget_set_redraw_handler(tri->widget, triangle_redraw_handler);
@@ -722,7 +723,7 @@ demoapp_create(struct display *display)
display_set_user_data(app->display, app);
app->window = window_create(app->display);
- app->widget = frame_create(app->window, app);
+ app->widget = window_frame_create(app->window, app);
window_set_title(app->window, "Wayland Sub-surface Demo");
window_set_key_handler(app->window, key_handler);
diff --git a/clients/tablet-shell.c b/clients/tablet-shell.c
deleted file mode 100644
index 45733b11..00000000
--- a/clients/tablet-shell.c
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- * Copyright © 2011, 2012 Intel Corporation
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that copyright
- * notice and this permission notice appear in supporting documentation, and
- * that the name of the copyright holders not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission. The copyright holders make no representations
- * about the suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
- * OF THIS SOFTWARE.
- */
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/wait.h>
-
-#include "window.h"
-#include "../shared/cairo-util.h"
-#include "../shared/config-parser.h"
-
-#include "tablet-shell-client-protocol.h"
-
-struct tablet {
- struct display *display;
- struct tablet_shell *tablet_shell;
- struct rectangle allocation;
- struct window *switcher;
-
- struct homescreen *homescreen;
- struct lockscreen *lockscreen;
-};
-
-struct homescreen {
- struct window *window;
- struct widget *widget;
- struct wl_list launcher_list;
-};
-
-struct lockscreen {
- struct window *window;
- struct widget *widget;
-};
-
-struct launcher {
- struct widget *widget;
- struct homescreen *homescreen;
- cairo_surface_t *icon;
- int focused, pressed;
- char *path;
- struct wl_list link;
-};
-
-static char *key_lockscreen_icon;
-static char *key_lockscreen_background;
-static char *key_homescreen_background;
-
-static void
-sigchild_handler(int s)
-{
- int status;
- pid_t pid;
-
- while (pid = waitpid(-1, &status, WNOHANG), pid > 0)
- fprintf(stderr, "child %d exited\n", pid);
-}
-
-static void
-paint_background(cairo_t *cr, const char *path, struct rectangle *allocation)
-{
- cairo_surface_t *image = NULL;
- cairo_pattern_t *pattern;
- cairo_matrix_t matrix;
- double sx, sy;
-
- cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
- if (path)
- image = load_cairo_surface(path);
- if (image) {
- pattern = cairo_pattern_create_for_surface(image);
- sx = (double) cairo_image_surface_get_width(image) /
- allocation->width;
- sy = (double) cairo_image_surface_get_height(image) /
- allocation->height;
- cairo_matrix_init_scale(&matrix, sx, sy);
- cairo_pattern_set_matrix(pattern, &matrix);
- cairo_set_source(cr, pattern);
- cairo_pattern_destroy (pattern);
- cairo_surface_destroy(image);
- cairo_paint(cr);
- } else {
- fprintf(stderr, "couldn't load background image: %s\n", path);
- cairo_set_source_rgb(cr, 0.2, 0, 0);
- cairo_paint(cr);
- }
-}
-
-static void
-homescreen_draw(struct widget *widget, void *data)
-{
- struct homescreen *homescreen = data;
- cairo_surface_t *surface;
- struct rectangle allocation;
- cairo_t *cr;
- struct launcher *launcher;
- const int rows = 4, columns = 5, icon_width = 128, icon_height = 128;
- int x, y, i, width, height, vmargin, hmargin, vpadding, hpadding;
-
- surface = window_get_surface(homescreen->window);
- cr = cairo_create(surface);
-
- widget_get_allocation(widget, &allocation);
- paint_background(cr, key_homescreen_background, &allocation);
-
- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
-
- width = allocation.width - columns * icon_width;
- hpadding = width / (columns + 1);
- hmargin = (width - hpadding * (columns - 1)) / 2;
-
- height = allocation.height - rows * icon_height;
- vpadding = height / (rows + 1);
- vmargin = (height - vpadding * (rows - 1)) / 2;
-
- x = hmargin;
- y = vmargin;
- i = 0;
-
- wl_list_for_each(launcher, &homescreen->launcher_list, link) {
- widget_set_allocation(launcher->widget,
- x, y, icon_width, icon_height);
- x += icon_width + hpadding;
- i++;
- if (i == columns) {
- x = hmargin;
- y += icon_height + vpadding;
- i = 0;
- }
- }
-
- cairo_destroy(cr);
- cairo_surface_destroy(surface);
-}
-
-static void
-lockscreen_draw(struct widget *widget, void *data)
-{
- struct lockscreen *lockscreen = data;
- cairo_surface_t *surface;
- cairo_surface_t *icon;
- struct rectangle allocation;
- cairo_t *cr;
- int width, height;
-
- surface = window_get_surface(lockscreen->window);
- cr = cairo_create(surface);
-
- widget_get_allocation(widget, &allocation);
- paint_background(cr, key_lockscreen_background, &allocation);
-
- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
- icon = load_cairo_surface(key_lockscreen_icon);
- if (icon) {
- width = cairo_image_surface_get_width(icon);
- height = cairo_image_surface_get_height(icon);
- cairo_set_source_surface(cr, icon,
- allocation.x + (allocation.width - width) / 2,
- allocation.y + (allocation.height - height) / 2);
- } else {
- fprintf(stderr, "couldn't load lockscreen icon: %s\n",
- key_lockscreen_icon);
- cairo_set_source_rgb(cr, 0.2, 0, 0);
- }
- cairo_paint(cr);
- cairo_destroy(cr);
- cairo_surface_destroy(icon);
- cairo_surface_destroy(surface);
-}
-
-static void
-lockscreen_button_handler(struct widget *widget,
- struct input *input, uint32_t time,
- uint32_t button,
- enum wl_pointer_button_state state, void *data)
-{
- struct lockscreen *lockscreen = data;
-
- if (state == WL_POINTER_BUTTON_STATE_PRESSED && lockscreen->window) {
- window_destroy(lockscreen->window);
- lockscreen->window = NULL;
- }
-}
-
-static struct homescreen *
-homescreen_create(struct tablet *tablet)
-{
- struct homescreen *homescreen;
-
- homescreen = zalloc (sizeof *homescreen);
- homescreen->window = window_create_custom(tablet->display);
- homescreen->widget =
- window_add_widget(homescreen->window, homescreen);
- window_set_user_data(homescreen->window, homescreen);
- window_set_title(homescreen->window, "homescreen");
- widget_set_redraw_handler(homescreen->widget, homescreen_draw);
-
- return homescreen;
-}
-
-static struct lockscreen *
-lockscreen_create(struct tablet *tablet)
-{
- struct lockscreen *lockscreen;
-
- lockscreen = zalloc (sizeof *lockscreen);
- lockscreen->window = window_create_custom(tablet->display);
- lockscreen->widget =
- window_add_widget(lockscreen->window, lockscreen);
- window_set_user_data(lockscreen->window, lockscreen);
- window_set_title(lockscreen->window, "lockscreen");
- widget_set_redraw_handler(lockscreen->widget, lockscreen_draw);
- widget_set_button_handler(lockscreen->widget,
- lockscreen_button_handler);
-
- return lockscreen;
-}
-
-static void
-show_lockscreen(void *data, struct tablet_shell *tablet_shell)
-{
- struct tablet *tablet = data;
-
- tablet->lockscreen = lockscreen_create(tablet);
- tablet_shell_set_lockscreen(tablet->tablet_shell,
- window_get_wl_surface(tablet->lockscreen->window));
-
- widget_schedule_resize(tablet->lockscreen->widget,
- tablet->allocation.width,
- tablet->allocation.height);
-}
-
-static void
-show_switcher(void *data, struct tablet_shell *tablet_shell)
-{
- struct tablet *tablet = data;
-
- tablet->switcher = window_create_custom(tablet->display);
- window_set_user_data(tablet->switcher, tablet);
- tablet_shell_set_switcher(tablet->tablet_shell,
- window_get_wl_surface(tablet->switcher));
-}
-
-static void
-hide_switcher(void *data, struct tablet_shell *tablet_shell)
-{
-}
-
-static const struct tablet_shell_listener tablet_shell_listener = {
- show_lockscreen,
- show_switcher,
- hide_switcher
-};
-
-static int
-launcher_enter_handler(struct widget *widget, struct input *input,
- float x, float y, void *data)
-{
- struct launcher *launcher = data;
-
- launcher->focused = 1;
- widget_schedule_redraw(widget);
-
- return CURSOR_LEFT_PTR;
-}
-
-static void
-launcher_leave_handler(struct widget *widget,
- struct input *input, void *data)
-{
- struct launcher *launcher = data;
-
- launcher->focused = 0;
- widget_schedule_redraw(widget);
-}
-
-static void
-launcher_activate(struct launcher *widget)
-{
- pid_t pid;
-
- pid = fork();
- if (pid < 0) {
- fprintf(stderr, "fork failed: %m\n");
- return;
- }
-
- if (pid)
- return;
-
- if (execl(widget->path, widget->path, NULL) < 0) {
- fprintf(stderr, "execl '%s' failed: %m\n", widget->path);
- exit(1);
- }
-}
-
-static void
-launcher_button_handler(struct widget *widget,
- struct input *input, uint32_t time,
- uint32_t button,
- enum wl_pointer_button_state state, void *data)
-{
- struct launcher *launcher;
-
- launcher = widget_get_user_data(widget);
- widget_schedule_redraw(widget);
- if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
- launcher_activate(launcher);
- launcher->pressed = 0;
- } else if (state == WL_POINTER_BUTTON_STATE_PRESSED)
- launcher->pressed = 1;
-}
-
-static void
-launcher_redraw_handler(struct widget *widget, void *data)
-{
- struct launcher *launcher = data;
- cairo_surface_t *surface;
- struct rectangle allocation;
- cairo_t *cr;
-
- surface = window_get_surface(launcher->homescreen->window);
- cr = cairo_create(surface);
-
- widget_get_allocation(widget, &allocation);
- if (launcher->pressed) {
- allocation.x++;
- allocation.y++;
- }
-
- cairo_set_source_surface(cr, launcher->icon,
- allocation.x, allocation.y);
- cairo_paint(cr);
-
- if (launcher->focused) {
- cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.4);
- cairo_mask_surface(cr, launcher->icon,
- allocation.x, allocation.y);
- }
-
- cairo_destroy(cr);
-}
-
-static void
-tablet_shell_add_launcher(struct tablet *tablet,
- const char *icon, const char *path)
-{
- struct launcher *launcher;
- struct homescreen *homescreen = tablet->homescreen;
-
- launcher = xmalloc(sizeof *launcher);
- launcher->icon = load_cairo_surface(icon);
- if ( !launcher->icon ||
- cairo_surface_status (launcher->icon) != CAIRO_STATUS_SUCCESS) {
- fprintf(stderr, "couldn't load %s\n", icon);
- free(launcher);
- return;
- }
- launcher->path = strdup(path);
-
- launcher->homescreen = homescreen;
- launcher->widget = widget_add_widget(homescreen->widget, launcher);
- widget_set_enter_handler(launcher->widget,
- launcher_enter_handler);
- widget_set_leave_handler(launcher->widget,
- launcher_leave_handler);
- widget_set_button_handler(launcher->widget,
- launcher_button_handler);
- widget_set_redraw_handler(launcher->widget,
- launcher_redraw_handler);
-
- wl_list_insert(&homescreen->launcher_list, &launcher->link);
-}
-
-static void
-global_handler(struct display *display, uint32_t name,
- const char *interface, uint32_t version, void *data)
-{
- struct tablet *tablet = data;
-
- if (!strcmp(interface, "tablet_shell")) {
- tablet->tablet_shell =
- display_bind(display, name,
- &tablet_shell_interface, 1);
- tablet_shell_add_listener(tablet->tablet_shell,
- &tablet_shell_listener, tablet);
- }
-}
-
-int main(int argc, char *argv[])
-{
- struct tablet tablet = { 0 };
- struct display *display;
- struct output *output;
- struct weston_config *config;
- struct weston_config_section *s;
- char *icon, *path;
- const char *name;
-
- display = display_create(&argc, argv);
- if (display == NULL) {
- fprintf(stderr, "failed to create display: %m\n");
- return -1;
- }
-
- tablet.display = display;
-
- display_set_user_data(tablet.display, &tablet);
- display_set_global_handler(tablet.display, global_handler);
-
- tablet.homescreen = homescreen_create(&tablet);
- tablet_shell_set_homescreen(tablet.tablet_shell,
- window_get_wl_surface(tablet.homescreen->window));
-
- wl_display_roundtrip (display_get_display(tablet.display));
-
- wl_list_init(&tablet.homescreen->launcher_list);
-
- config = weston_config_parse("weston.ini");
- s = weston_config_get_section(config, "shell", NULL, NULL);
- weston_config_section_get_string(s, "lockscreen-icon",
- &key_lockscreen_icon, NULL);
- weston_config_section_get_string(s, "lockscreen",
- &key_lockscreen_background, NULL);
- weston_config_section_get_string(s, "homescreen",
- &key_homescreen_background, NULL);
-
- s = NULL;
- while (weston_config_next_section(config, &s, &name)) {
- if (strcmp(name, "launcher") != 0)
- continue;
-
- weston_config_section_get_string(s, "icon", &icon, NULL);
- weston_config_section_get_string(s, "path", &path, NULL);
-
- if (icon != NULL && path != NULL)
- tablet_shell_add_launcher(&tablet, icon, path);
- else
- fprintf(stderr, "invalid launcher section\n");
-
- free(icon);
- free(path);
- }
-
- weston_config_destroy(config);
-
- signal(SIGCHLD, sigchild_handler);
-
- output = display_get_output(tablet.display);
- output_get_allocation(output, &tablet.allocation);
- widget_schedule_resize(tablet.homescreen->widget,
- tablet.allocation.width,
- tablet.allocation.height);
- display_run(display);
-
- return 0;
-}
diff --git a/clients/terminal.c b/clients/terminal.c
index cec1d67e..e2a6236c 100644
--- a/clients/terminal.c
+++ b/clients/terminal.c
@@ -38,6 +38,8 @@
#include <wchar.h>
#include <locale.h>
+#include <linux/input.h>
+
#include <wayland-client.h>
#include "../shared/config-parser.h"
@@ -426,6 +428,7 @@ struct terminal {
struct window *window;
struct widget *widget;
struct display *display;
+ char *title;
union utf8_char *data;
struct task io_task;
char *tab_ruler;
@@ -441,8 +444,11 @@ struct terminal {
character_set saved_cs, saved_g0, saved_g1;
keyboard_mode key_mode;
int data_pitch, attr_pitch; /* The width in bytes of a line */
- int width, height, start, row, column;
+ int width, height, row, column, max_width;
+ uint32_t buffer_height;
+ uint32_t start, end, saved_start, log_size;
int saved_row, saved_column;
+ int scrolling;
int send_cursor_position;
int fd, master;
uint32_t modifiers;
@@ -461,7 +467,7 @@ struct terminal {
uint32_t hide_cursor_serial;
struct wl_data_source *selection;
- uint32_t button_time;
+ uint32_t click_time;
int dragging, click_count;
int selection_start_x, selection_start_y;
int selection_end_x, selection_end_y;
@@ -545,9 +551,9 @@ terminal_get_row(struct terminal *terminal, int row)
{
int index;
- index = (row + terminal->start) % terminal->height;
+ index = (row + terminal->start) & (terminal->buffer_height - 1);
- return &terminal->data[index * terminal->width];
+ return (void *) terminal->data + index * terminal->data_pitch;
}
static struct attr*
@@ -555,9 +561,9 @@ terminal_get_attr_row(struct terminal *terminal, int row)
{
int index;
- index = (row + terminal->start) % terminal->height;
+ index = (row + terminal->start) & (terminal->buffer_height - 1);
- return &terminal->data_attr[index * terminal->width];
+ return (void *) terminal->data_attr + index * terminal->attr_pitch;
}
union decoded_attr {
@@ -620,18 +626,16 @@ terminal_scroll_buffer(struct terminal *terminal, int d)
{
int i;
- d = d % (terminal->height + 1);
- terminal->start = (terminal->start + d) % terminal->height;
- if (terminal->start < 0) terminal->start = terminal->height + terminal->start;
- if(d < 0) {
+ terminal->start += d;
+ if (d < 0) {
d = 0 - d;
- for(i = 0; i < d; i++) {
+ for (i = 0; i < d; i++) {
memset(terminal_get_row(terminal, i), 0, terminal->data_pitch);
attr_init(terminal_get_attr_row(terminal, i),
terminal->curr_attr, terminal->width);
}
} else {
- for(i = terminal->height - d; i < terminal->height; i++) {
+ for (i = terminal->height - d; i < terminal->height; i++) {
memset(terminal_get_row(terminal, i), 0, terminal->data_pitch);
attr_init(terminal_get_attr_row(terminal, i),
terminal->curr_attr, terminal->width);
@@ -733,68 +737,90 @@ terminal_shift_line(struct terminal *terminal, int d)
}
static void
-terminal_resize_cells(struct terminal *terminal, int width, int height)
+terminal_resize_cells(struct terminal *terminal,
+ int width, int height)
{
- size_t size;
union utf8_char *data;
struct attr *data_attr;
char *tab_ruler;
int data_pitch, attr_pitch;
int i, l, total_rows;
+ uint32_t d, uheight = height;
struct rectangle allocation;
struct winsize ws;
+ if (uheight > terminal->buffer_height)
+ height = terminal->buffer_height;
+
if (terminal->width == width && terminal->height == height)
return;
- data_pitch = width * sizeof(union utf8_char);
- size = data_pitch * height;
- data = zalloc(size);
- attr_pitch = width * sizeof(struct attr);
- data_attr = malloc(attr_pitch * height);
- tab_ruler = zalloc(width);
- attr_init(data_attr, terminal->curr_attr, width * height);
- if (terminal->data && terminal->data_attr) {
- if (width > terminal->width)
- l = terminal->width;
- else
- l = width;
-
- if (terminal->height > height) {
- total_rows = height;
- i = 1 + terminal->row - height;
- if (i > 0) {
- terminal->start = (terminal->start + i) % terminal->height;
- terminal->row = terminal->row - i;
- }
- } else {
- total_rows = terminal->height;
+ if (terminal->data && width <= terminal->max_width) {
+ d = 0;
+ if (height < terminal->height && height <= terminal->row)
+ d = terminal->height - height;
+ else if (height > terminal->height &&
+ terminal->height - 1 == terminal->row) {
+ d = terminal->height - height;
+ if (terminal->log_size < uheight)
+ d = -terminal->start;
}
- for (i = 0; i < total_rows; i++) {
- memcpy(&data[width * i],
- terminal_get_row(terminal, i),
- l * sizeof(union utf8_char));
- memcpy(&data_attr[width * i],
- terminal_get_attr_row(terminal, i),
- l * sizeof(struct attr));
+ terminal->start += d;
+ terminal->row -= d;
+ } else {
+ terminal->max_width = width;
+ data_pitch = width * sizeof(union utf8_char);
+ data = zalloc(data_pitch * terminal->buffer_height);
+ attr_pitch = width * sizeof(struct attr);
+ data_attr = malloc(attr_pitch * terminal->buffer_height);
+ tab_ruler = zalloc(width);
+ attr_init(data_attr, terminal->curr_attr,
+ width * terminal->buffer_height);
+
+ if (terminal->data && terminal->data_attr) {
+ if (width > terminal->width)
+ l = terminal->width;
+ else
+ l = width;
+
+ if (terminal->height > height) {
+ total_rows = height;
+ i = 1 + terminal->row - height;
+ if (i > 0) {
+ terminal->start += i;
+ terminal->row = terminal->row - i;
+ }
+ } else {
+ total_rows = terminal->height;
+ }
+
+ for (i = 0; i < total_rows; i++) {
+ memcpy(&data[width * i],
+ terminal_get_row(terminal, i),
+ l * sizeof(union utf8_char));
+ memcpy(&data_attr[width * i],
+ terminal_get_attr_row(terminal, i),
+ l * sizeof(struct attr));
+ }
+
+ free(terminal->data);
+ free(terminal->data_attr);
+ free(terminal->tab_ruler);
}
- free(terminal->data);
- free(terminal->data_attr);
- free(terminal->tab_ruler);
+ terminal->data_pitch = data_pitch;
+ terminal->attr_pitch = attr_pitch;
+ terminal->data = data;
+ terminal->data_attr = data_attr;
+ terminal->tab_ruler = tab_ruler;
+ terminal->start = 0;
}
- terminal->data_pitch = data_pitch;
- terminal->attr_pitch = attr_pitch;
terminal->margin_bottom =
height - (terminal->height - terminal->margin_bottom);
terminal->width = width;
terminal->height = height;
- terminal->data = data;
- terminal->data_attr = data_attr;
- terminal->tab_ruler = tab_ruler;
- terminal->start = 0;
terminal_init_tabs(terminal);
/* Update the window size */
@@ -812,7 +838,7 @@ resize_handler(struct widget *widget,
{
struct terminal *terminal = data;
int32_t columns, rows, m;
-
+ char *p;
m = 2 * terminal->margin;
columns = (width - m) / (int32_t) terminal->average_width;
rows = (height - m) / (int32_t) terminal->extents.height;
@@ -822,6 +848,9 @@ resize_handler(struct widget *widget,
width = columns * terminal->average_width + m;
height = rows * terminal->extents.height + m;
widget_set_size(terminal->widget, width, height);
+ asprintf(&p, "%s — [%dx%d]", terminal->title, columns, rows);
+ window_set_title(terminal->window, p);
+ free(p);
}
terminal_resize_cells(terminal, columns, rows);
@@ -840,7 +869,7 @@ terminal_resize(struct terminal *terminal, int columns, int rows)
width = columns * terminal->average_width + m;
height = rows * terminal->extents.height + m;
- frame_set_child_size(terminal->widget, width, height);
+ window_frame_set_child_size(terminal->widget, width, height);
}
struct color_scheme DEFAULT_COLORS = {
@@ -1232,6 +1261,8 @@ handle_osc(struct terminal *terminal)
case 0: /* Icon name and window title */
case 1: /* Icon label */
case 2: /* Window title*/
+ free(terminal->title);
+ terminal->title = strdup(p);
window_set_title(terminal->window, p);
break;
case 7: /* shell cwd as uri */
@@ -1383,12 +1414,9 @@ handle_escape(struct terminal *terminal)
terminal->curr_attr, terminal->width);
}
} else if (args[0] == 2) {
- for (i = 0; i < terminal->height; i++) {
- memset(terminal_get_row(terminal, i),
- 0, terminal->data_pitch);
- attr_init(terminal_get_attr_row(terminal, i),
- terminal->curr_attr, terminal->width);
- }
+ /* Clear screen by scrolling contents out */
+ terminal_scroll_buffer(terminal,
+ terminal->end - terminal->start);
}
break;
case 'K': /* EL */
@@ -1827,7 +1855,7 @@ handle_special_char(struct terminal *terminal, char c)
case '\v':
case '\f':
terminal->row++;
- if(terminal->row > terminal->margin_bottom) {
+ if (terminal->row > terminal->margin_bottom) {
terminal->row = terminal->margin_bottom;
terminal_scroll(terminal, +1);
}
@@ -1930,6 +1958,13 @@ handle_char(struct terminal *terminal, union utf8_char utf8)
row[terminal->column] = utf8;
attr_row[terminal->column++] = terminal->curr_attr;
+ if (terminal->row + terminal->start + 1 > terminal->end)
+ terminal->end = terminal->row + terminal->start + 1;
+ if (terminal->end == terminal->buffer_height)
+ terminal->log_size = terminal->buffer_height;
+ else if (terminal->log_size < terminal->buffer_height)
+ terminal->log_size = terminal->end;
+
/* cursor jump for wide character. */
if (is_wide(utf8))
row[terminal->column++].ch = 0x200B; /* space glyph */
@@ -2177,45 +2212,90 @@ fullscreen_handler(struct window *window, void *data)
}
static void
-close_handler(struct window *window, void *data)
+close_handler(void *data)
{
struct terminal *terminal = data;
terminal_destroy(terminal);
}
+static void
+terminal_copy(struct terminal *terminal, struct input *input)
+{
+ terminal->selection =
+ display_create_data_source(terminal->display);
+ wl_data_source_offer(terminal->selection,
+ "text/plain;charset=utf-8");
+ wl_data_source_add_listener(terminal->selection,
+ &data_source_listener, terminal);
+ input_set_selection(input, terminal->selection,
+ display_get_serial(terminal->display));
+}
+
+static void
+terminal_paste(struct terminal *terminal, struct input *input)
+{
+ input_receive_selection_data_to_fd(input,
+ "text/plain;charset=utf-8",
+ terminal->master);
+
+}
+
+static void
+terminal_new_instance(struct terminal *terminal)
+{
+ struct terminal *new_terminal;
+
+ new_terminal = terminal_create(terminal->display);
+ if (terminal_run(new_terminal, option_shell))
+ terminal_destroy(new_terminal);
+}
+
static int
handle_bound_key(struct terminal *terminal,
struct input *input, uint32_t sym, uint32_t time)
{
- struct terminal *new_terminal;
-
switch (sym) {
case XKB_KEY_X:
/* Cut selection; terminal doesn't do cut, fall
* through to copy. */
case XKB_KEY_C:
- terminal->selection =
- display_create_data_source(terminal->display);
- wl_data_source_offer(terminal->selection,
- "text/plain;charset=utf-8");
- wl_data_source_add_listener(terminal->selection,
- &data_source_listener, terminal);
- input_set_selection(input, terminal->selection,
- display_get_serial(terminal->display));
+ terminal_copy(terminal, input);
return 1;
case XKB_KEY_V:
- input_receive_selection_data_to_fd(input,
- "text/plain;charset=utf-8",
- terminal->master);
+ terminal_paste(terminal, input);
+ return 1;
+ case XKB_KEY_N:
+ terminal_new_instance(terminal);
+ return 1;
+
+ case XKB_KEY_Up:
+ if (!terminal->scrolling)
+ terminal->saved_start = terminal->start;
+ if (terminal->start == terminal->end - terminal->log_size)
+ return 1;
+ terminal->scrolling = 1;
+ terminal->start--;
+ terminal->row++;
+ terminal->selection_start_row++;
+ terminal->selection_end_row++;
+ widget_schedule_redraw(terminal->widget);
return 1;
- case XKB_KEY_N:
- new_terminal = terminal_create(terminal->display);
- if (terminal_run(new_terminal, option_shell))
- terminal_destroy(new_terminal);
+ case XKB_KEY_Down:
+ if (!terminal->scrolling)
+ terminal->saved_start = terminal->start;
+
+ if (terminal->start == terminal->saved_start)
+ return 1;
+ terminal->scrolling = 1;
+ terminal->start++;
+ terminal->row--;
+ terminal->selection_start_row--;
+ terminal->selection_end_row--;
+ widget_schedule_redraw(terminal->widget);
return 1;
default:
@@ -2231,7 +2311,7 @@ key_handler(struct window *window, struct input *input, uint32_t time,
struct terminal *terminal = data;
char ch[MAX_RESPONSE];
uint32_t modifiers, serial;
- int ret, len = 0;
+ int ret, len = 0, d;
bool convert_utf8 = true;
modifiers = input_get_modifiers(input);
@@ -2435,6 +2515,16 @@ key_handler(struct window *window, struct input *input, uint32_t time,
}
if (state == WL_KEYBOARD_KEY_STATE_PRESSED && len > 0) {
+ if (terminal->scrolling) {
+ d = terminal->saved_start - terminal->start;
+ terminal->row -= d;
+ terminal->selection_start_row -= d;
+ terminal->selection_end_row -= d;
+ terminal->start = terminal->saved_start;
+ terminal->scrolling = 0;
+ widget_schedule_redraw(terminal->widget);
+ }
+
terminal_write(terminal, ch, len);
/* Hide cursor, except if this was coming from a
@@ -2564,37 +2654,81 @@ recompute_selection(struct terminal *terminal)
}
static void
+menu_func(struct window *window, struct input *input, int index, void *data)
+{
+ struct terminal *terminal = data;
+
+ fprintf(stderr, "picked entry %d\n", index);
+
+ switch (index) {
+ case 0:
+ terminal_new_instance(terminal);
+ break;
+ case 1:
+ terminal_copy(terminal, input);
+ break;
+ case 2:
+ terminal_paste(terminal, input);
+ break;
+ }
+}
+
+static void
+show_menu(struct terminal *terminal, struct input *input, uint32_t time)
+{
+ int32_t x, y;
+ static const char *entries[] = {
+ "Open Terminal", "Copy", "Paste"
+ };
+
+ input_get_position(input, &x, &y);
+ window_show_menu(terminal->display, input, time, terminal->window,
+ x - 10, y - 10, menu_func,
+ entries, ARRAY_LENGTH(entries));
+}
+
+static void
+click_handler(struct widget *widget, struct terminal *terminal,
+ struct input *input, int32_t x, int32_t y,
+ uint32_t time)
+{
+ if (time - terminal->click_time < 500)
+ terminal->click_count++;
+ else
+ terminal->click_count = 1;
+
+ terminal->click_time = time;
+ terminal->dragging = (terminal->click_count - 1) % 3 + SELECT_CHAR;
+
+ terminal->selection_end_x = terminal->selection_start_x = x;
+ terminal->selection_end_y = terminal->selection_start_y = y;
+ if (recompute_selection(terminal))
+ widget_schedule_redraw(widget);
+}
+
+static void
button_handler(struct widget *widget,
struct input *input, uint32_t time,
uint32_t button,
enum wl_pointer_button_state state, void *data)
{
struct terminal *terminal = data;
+ int32_t x, y;
switch (button) {
- case 272:
+ case BTN_LEFT:
if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
-
- if (time - terminal->button_time < 500)
- terminal->click_count++;
- else
- terminal->click_count = 1;
-
- terminal->button_time = time;
- terminal->dragging =
- (terminal->click_count - 1) % 3 + SELECT_CHAR;
-
- input_get_position(input,
- &terminal->selection_start_x,
- &terminal->selection_start_y);
- terminal->selection_end_x = terminal->selection_start_x;
- terminal->selection_end_y = terminal->selection_start_y;
- if (recompute_selection(terminal))
- widget_schedule_redraw(widget);
+ input_get_position(input, &x, &y);
+ click_handler(widget, terminal, input, x, y, time);
} else {
terminal->dragging = SELECT_NONE;
}
break;
+
+ case BTN_RIGHT:
+ if (state == WL_POINTER_BUTTON_STATE_PRESSED)
+ show_menu(terminal, input, time);
+ break;
}
}
@@ -2602,6 +2736,11 @@ static int
enter_handler(struct widget *widget,
struct input *input, float x, float y, void *data)
{
+ struct terminal *terminal = data;
+
+ /* Reset title to get rid of resizing '[WxH]' in titlebar */
+ window_set_title(terminal->window, terminal->title);
+
return CURSOR_IBEAM;
}
@@ -2634,6 +2773,43 @@ output_handler(struct window *window, struct output *output, int enter,
window_schedule_redraw(window);
}
+static void
+touch_down_handler(struct widget *widget, struct input *input,
+ uint32_t serial, uint32_t time, int32_t id,
+ float x, float y, void *data)
+{
+ struct terminal *terminal = data;
+
+ if (id == 0)
+ click_handler(widget, terminal, input, x, y, time);
+}
+
+static void
+touch_up_handler(struct widget *widget, struct input *input,
+ uint32_t serial, uint32_t time, int32_t id, void *data)
+{
+ struct terminal *terminal = data;
+
+ if (id == 0)
+ terminal->dragging = SELECT_NONE;
+}
+
+static void
+touch_motion_handler(struct widget *widget, struct input *input,
+ uint32_t time, int32_t id, float x, float y, void *data)
+{
+ struct terminal *terminal = data;
+
+ if (terminal->dragging &&
+ id == 0) {
+ terminal->selection_end_x = (int)x;
+ terminal->selection_end_y = (int)y;
+
+ if (recompute_selection(terminal))
+ widget_schedule_redraw(widget);
+ }
+}
+
#ifndef howmany
#define howmany(x, y) (((x) + ((y) - 1)) / (y))
#endif
@@ -2652,8 +2828,9 @@ terminal_create(struct display *display)
terminal->margin_top = 0;
terminal->margin_bottom = -1;
terminal->window = window_create(display);
- terminal->widget = frame_create(terminal->window, terminal);
- window_set_title(terminal->window, "Wayland Terminal");
+ terminal->widget = window_frame_create(terminal->window, terminal);
+ terminal->title = strdup("Wayland Terminal");
+ window_set_title(terminal->window, terminal->title);
widget_set_transparent(terminal->widget, 0);
init_state_machine(&terminal->state_machine);
@@ -2661,6 +2838,8 @@ terminal_create(struct display *display)
terminal->display = display;
terminal->margin = 5;
+ terminal->buffer_height = 1024;
+ terminal->end = 1;
window_set_user_data(terminal->window, terminal);
window_set_key_handler(terminal->window, key_handler);
@@ -2678,6 +2857,9 @@ terminal_create(struct display *display)
widget_set_button_handler(terminal->widget, button_handler);
widget_set_enter_handler(terminal->widget, enter_handler);
widget_set_motion_handler(terminal->widget, motion_handler);
+ widget_set_touch_up_handler(terminal->widget, touch_up_handler);
+ widget_set_touch_down_handler(terminal->widget, touch_down_handler);
+ widget_set_touch_motion_handler(terminal->widget, touch_motion_handler);
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
cr = cairo_create(surface);
@@ -2726,6 +2908,7 @@ terminal_destroy(struct terminal *terminal)
if (wl_list_empty(&terminal_list))
display_exit(terminal->display);
+ free(terminal->title);
free(terminal);
}
diff --git a/clients/transformed.c b/clients/transformed.c
index 54212dd4..bbc1dc02 100644
--- a/clients/transformed.c
+++ b/clients/transformed.c
@@ -227,8 +227,7 @@ touch_handler(struct widget *widget, struct input *input,
float x, float y, void *data)
{
struct transformed *transformed = data;
- window_touch_move(transformed->window, input,
- display_get_serial(transformed->display));
+ window_move(transformed->window, input, display_get_serial(transformed->display));
}
static void
diff --git a/clients/view.c b/clients/view.c
index f5b1843f..4ac9ca50 100644
--- a/clients/view.c
+++ b/clients/view.c
@@ -168,7 +168,7 @@ fullscreen_handler(struct window *window, void *data)
}
static void
-close_handler(struct window *window, void *data)
+close_handler(void *data)
{
struct view *view = data;
@@ -251,7 +251,7 @@ view_create(struct display *display,
}
view->window = window_create(display);
- view->widget = frame_create(view->window, view);
+ view->widget = window_frame_create(view->window, view);
window_set_title(view->window, title);
g_free(title);
view->display = display;
diff --git a/clients/weston-info.c b/clients/weston-info.c
index 5d928f54..4cc05723 100644
--- a/clients/weston-info.c
+++ b/clients/weston-info.c
@@ -234,8 +234,20 @@ print_shm_info(void *data)
printf("\tformats:");
wl_list_for_each(format, &shm->formats, link)
- printf(" %s", (format->format == WL_SHM_FORMAT_ARGB8888) ?
- "ARGB8888" : "XRGB8888");
+ switch (format->format) {
+ case WL_SHM_FORMAT_ARGB8888:
+ printf(" ARGB8888");
+ break;
+ case WL_SHM_FORMAT_XRGB8888:
+ printf(" XRGB8888");
+ break;
+ case WL_SHM_FORMAT_RGB565:
+ printf(" RGB565");
+ break;
+ default:
+ printf(" unknown(%08x)", format->format);
+ break;
+ }
printf("\n");
}
diff --git a/clients/window.c b/clients/window.c
index 56de5d78..d59b9c7f 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -117,6 +117,7 @@ struct display {
display_output_handler_t output_configure_handler;
display_global_handler_t global_handler;
+ display_global_handler_t global_handler_remove;
void *user_data;
@@ -220,7 +221,6 @@ struct surface {
struct window {
struct display *display;
- struct window *parent;
struct wl_list window_output_list;
char *title;
struct rectangle saved_allocation;
@@ -253,7 +253,7 @@ struct window {
struct surface *main_surface;
struct wl_shell_surface *shell_surface;
- struct frame *frame;
+ struct window_frame *frame;
/* struct surface::link, contains also main_surface */
struct wl_list subsurface_list;
@@ -285,10 +285,16 @@ struct widget {
int opaque;
int tooltip_count;
int default_cursor;
+ /* If this is set to false then no cairo surface will be
+ * created before redrawing the surface. This is useful if the
+ * redraw handler is going to do completely custom rendering
+ * such as using EGL directly */
+ int use_cairo;
};
struct touch_point {
int32_t id;
+ float x, y;
struct widget *widget;
struct wl_list link;
};
@@ -320,6 +326,11 @@ struct input {
struct wl_data_device *data_device;
struct data_offer *drag_offer;
struct data_offer *selection_offer;
+ uint32_t touch_grab;
+ int32_t touch_grab_id;
+ float drag_x, drag_y;
+ struct window *drag_focus;
+ uint32_t drag_enter_serial;
struct {
struct xkb_keymap *keymap;
@@ -339,6 +350,7 @@ struct input {
struct output {
struct display *display;
struct wl_output *output;
+ uint32_t server_output_id;
struct rectangle allocation;
struct wl_list link;
int transform;
@@ -348,51 +360,18 @@ struct output {
void *user_data;
};
-enum frame_button_action {
- FRAME_BUTTON_NULL = 0,
- FRAME_BUTTON_ICON = 1,
- FRAME_BUTTON_CLOSE = 2,
- FRAME_BUTTON_MINIMIZE = 3,
- FRAME_BUTTON_MAXIMIZE = 4,
-};
-
-enum frame_button_pointer {
- FRAME_BUTTON_DEFAULT = 0,
- FRAME_BUTTON_OVER = 1,
- FRAME_BUTTON_ACTIVE = 2,
-};
-
-enum frame_button_align {
- FRAME_BUTTON_RIGHT = 0,
- FRAME_BUTTON_LEFT = 1,
-};
-
-enum frame_button_decoration {
- FRAME_BUTTON_NONE = 0,
- FRAME_BUTTON_FANCY = 1,
-};
-
-struct frame_button {
- struct widget *widget;
- struct frame *frame;
- cairo_surface_t *icon;
- enum frame_button_action type;
- enum frame_button_pointer state;
- struct wl_list link; /* buttons_list */
- enum frame_button_align align;
- enum frame_button_decoration decoration;
-};
-
-struct frame {
+struct window_frame {
struct widget *widget;
struct widget *child;
- struct wl_list buttons_list;
+ struct frame *frame;
};
struct menu {
struct window *window;
+ struct window *parent;
struct widget *widget;
struct input *input;
+ struct frame *frame;
const char **entries;
uint32_t time;
int current;
@@ -1110,6 +1089,9 @@ shm_surface_prepare(struct toysurface *base, int dx, int dy,
surface->flags,
leaf->resize_pool,
&leaf->data);
+ if (!leaf->cairo_surface)
+ return NULL;
+
wl_buffer_add_listener(leaf->data->buffer,
&shm_surface_buffer_listener, surface);
@@ -1514,7 +1496,7 @@ window_get_output_scale(struct window *window)
return scale;
}
-static void frame_destroy(struct frame *frame);
+static void window_frame_destroy(struct window_frame *frame);
static void
surface_destroy(struct surface *surface)
@@ -1568,7 +1550,7 @@ window_destroy(struct window *window)
}
if (window->frame)
- frame_destroy(window->frame);
+ window_frame_destroy(window->frame);
if (window->shell_surface)
wl_shell_surface_destroy(window->shell_surface);
@@ -1632,6 +1614,7 @@ widget_create(struct window *window, struct surface *surface, void *data)
widget->tooltip = NULL;
widget->tooltip_count = 0;
widget->default_cursor = CURSOR_LEFT_PTR;
+ widget->use_cairo = 1;
return widget;
}
@@ -1670,10 +1653,8 @@ widget_destroy(struct widget *widget)
if (surface->widget == widget && surface->subsurface)
surface_destroy(widget->surface);
- if (widget->tooltip) {
- free(widget->tooltip);
- widget->tooltip = NULL;
- }
+ if (widget->tooltip)
+ widget_destroy_tooltip(widget);
wl_list_for_each(input, &display->input_list, link) {
if (input->focus_widget == widget)
@@ -1730,6 +1711,8 @@ widget_get_cairo_surface(struct widget *widget)
struct surface *surface = widget->surface;
struct window *window = widget->window;
+ assert(widget->use_cairo);
+
if (!surface->cairo_surface) {
if (surface == window->main_surface)
window_create_main_surface(window);
@@ -1842,6 +1825,12 @@ widget_get_wl_surface(struct widget *widget)
return widget->surface->surface;
}
+struct wl_subsurface *
+widget_get_wl_subsurface(struct widget *widget)
+{
+ return widget->surface->subsurface;
+}
+
uint32_t
widget_get_last_time(struct widget *widget)
{
@@ -1956,6 +1945,13 @@ widget_schedule_redraw(struct widget *widget)
window_schedule_redraw_task(widget->window);
}
+void
+widget_set_use_cairo(struct widget *widget,
+ int use_cairo)
+{
+ widget->use_cairo = use_cairo;
+}
+
cairo_surface_t *
window_get_surface(struct window *window)
{
@@ -1972,12 +1968,6 @@ window_get_wl_surface(struct window *window)
return window->main_surface->surface;
}
-struct wl_shell_surface *
-window_get_wl_shell_surface(struct window *window)
-{
- return window->shell_surface;
-}
-
static void
tooltip_redraw_handler(struct widget *widget, void *data)
{
@@ -2166,376 +2156,113 @@ static void
frame_resize_handler(struct widget *widget,
int32_t width, int32_t height, void *data)
{
- struct frame *frame = data;
+ struct window_frame *frame = data;
struct widget *child = frame->child;
- struct rectangle allocation;
- struct display *display = widget->window->display;
- struct surface *surface = widget->surface;
- struct frame_button * button;
- struct theme *t = display->theme;
- int x_l, x_r, y, w, h;
- int decoration_width, decoration_height;
- int opaque_margin, shadow_margin;
-
- switch (widget->window->type) {
- case TYPE_FULLSCREEN:
- decoration_width = 0;
- decoration_height = 0;
-
- allocation.x = 0;
- allocation.y = 0;
- allocation.width = width;
- allocation.height = height;
- opaque_margin = 0;
-
- wl_list_for_each(button, &frame->buttons_list, link)
- button->widget->opaque = 1;
- break;
- case TYPE_MAXIMIZED:
- decoration_width = t->width * 2;
- decoration_height = t->width + t->titlebar_height;
-
- allocation.x = t->width;
- allocation.y = t->titlebar_height;
- allocation.width = width - decoration_width;
- allocation.height = height - decoration_height;
-
- opaque_margin = 0;
-
- wl_list_for_each(button, &frame->buttons_list, link)
- button->widget->opaque = 0;
- break;
- default:
- decoration_width = (t->width + t->margin) * 2;
- decoration_height = t->width +
- t->titlebar_height + t->margin * 2;
-
- allocation.x = t->width + t->margin;
- allocation.y = t->titlebar_height + t->margin;
- allocation.width = width - decoration_width;
- allocation.height = height - decoration_height;
-
- opaque_margin = t->margin + t->frame_radius;
-
- wl_list_for_each(button, &frame->buttons_list, link)
- button->widget->opaque = 0;
- break;
- }
-
- widget_set_allocation(child, allocation.x, allocation.y,
- allocation.width, allocation.height);
-
- if (child->resize_handler)
- child->resize_handler(child,
- allocation.width,
- allocation.height,
- child->user_data);
-
- width = child->allocation.width + decoration_width;
- height = child->allocation.height + decoration_height;
-
- shadow_margin = widget->window->type == TYPE_MAXIMIZED ? 0 : t->margin;
-
- surface->input_region =
- wl_compositor_create_region(display->compositor);
- if (widget->window->type != TYPE_FULLSCREEN) {
- wl_region_add(surface->input_region,
- shadow_margin, shadow_margin,
- width - 2 * shadow_margin,
- height - 2 * shadow_margin);
+ struct rectangle interior;
+ struct rectangle input;
+ struct rectangle opaque;
+
+ if (widget->window->type == TYPE_FULLSCREEN) {
+ interior.x = 0;
+ interior.y = 0;
+ interior.width = width;
+ interior.height = height;
} else {
- wl_region_add(surface->input_region, 0, 0, width, height);
- }
-
- widget_set_allocation(widget, 0, 0, width, height);
-
- if (child->opaque)
- wl_region_add(surface->opaque_region,
- opaque_margin, opaque_margin,
- widget->allocation.width - 2 * opaque_margin,
- widget->allocation.height - 2 * opaque_margin);
-
- /* frame internal buttons */
- x_r = frame->widget->allocation.width - t->width - shadow_margin;
- x_l = t->width + shadow_margin;
- y = t->width + shadow_margin;
- wl_list_for_each(button, &frame->buttons_list, link) {
- const int button_padding = 4;
- w = cairo_image_surface_get_width(button->icon);
- h = cairo_image_surface_get_height(button->icon);
-
- if (button->decoration == FRAME_BUTTON_FANCY)
- w += 10;
-
- if (button->align == FRAME_BUTTON_LEFT) {
- widget_set_allocation(button->widget,
- x_l, y , w + 1, h + 1);
- x_l += w;
- x_l += button_padding;
+ if (widget->window->type == TYPE_MAXIMIZED) {
+ frame_set_flag(frame->frame, FRAME_FLAG_MAXIMIZED);
} else {
- x_r -= w;
- widget_set_allocation(button->widget,
- x_r, y , w + 1, h + 1);
- x_r -= button_padding;
+ frame_unset_flag(frame->frame, FRAME_FLAG_MAXIMIZED);
}
- }
-}
-
-static int
-frame_button_enter_handler(struct widget *widget,
- struct input *input, float x, float y, void *data)
-{
- struct frame_button *frame_button = data;
-
- widget_schedule_redraw(frame_button->widget);
- frame_button->state = FRAME_BUTTON_OVER;
-
- return CURSOR_LEFT_PTR;
-}
-static void
-frame_button_leave_handler(struct widget *widget, struct input *input, void *data)
-{
- struct frame_button *frame_button = data;
-
- widget_schedule_redraw(frame_button->widget);
- frame_button->state = FRAME_BUTTON_DEFAULT;
-}
-
-static void
-frame_button_button_handler(struct widget *widget,
- struct input *input, uint32_t time,
- uint32_t button,
- enum wl_pointer_button_state state, void *data)
-{
- struct frame_button *frame_button = data;
- struct window *window = widget->window;
- int was_pressed = (frame_button->state == FRAME_BUTTON_ACTIVE);
-
- if (button != BTN_LEFT)
- return;
-
- switch (state) {
- case WL_POINTER_BUTTON_STATE_PRESSED:
- frame_button->state = FRAME_BUTTON_ACTIVE;
- widget_schedule_redraw(frame_button->widget);
-
- if (frame_button->type == FRAME_BUTTON_ICON)
- window_show_frame_menu(window, input, time);
- return;
- case WL_POINTER_BUTTON_STATE_RELEASED:
- frame_button->state = FRAME_BUTTON_DEFAULT;
- widget_schedule_redraw(frame_button->widget);
- break;
+ frame_resize(frame->frame, width, height);
+ frame_interior(frame->frame, &interior.x, &interior.y,
+ &interior.width, &interior.height);
}
- if (!was_pressed)
- return;
-
- switch (frame_button->type) {
- case FRAME_BUTTON_CLOSE:
- if (window->close_handler)
- window->close_handler(window->parent,
- window->user_data);
- else
- display_exit(window->display);
- break;
- case FRAME_BUTTON_MINIMIZE:
- fprintf(stderr,"Minimize stub\n");
- break;
- case FRAME_BUTTON_MAXIMIZE:
- window_set_maximized(window, window->type != TYPE_MAXIMIZED);
- break;
- default:
- /* Unknown operation */
- break;
- }
-}
+ widget_set_allocation(child, interior.x, interior.y,
+ interior.width, interior.height);
-static void
-frame_button_touch_down_handler(struct widget *widget, struct input *input,
- uint32_t serial, uint32_t time, int32_t id,
- float x, float y, void *data)
-{
- struct frame_button *frame_button = data;
- struct window *window = widget->window;
+ if (child->resize_handler) {
+ child->resize_handler(child, interior.width, interior.height,
+ child->user_data);
- switch (frame_button->type) {
- case FRAME_BUTTON_CLOSE:
- if (window->close_handler)
- window->close_handler(window->parent,
- window->user_data);
- else
- display_exit(window->display);
- break;
- case FRAME_BUTTON_MINIMIZE:
- fprintf(stderr,"Minimize stub\n");
- break;
- case FRAME_BUTTON_MAXIMIZE:
- window_set_maximized(window, window->type != TYPE_MAXIMIZED);
- break;
- default:
- /* Unknown operation */
- break;
+ if (widget->window->type == TYPE_FULLSCREEN) {
+ width = child->allocation.width;
+ height = child->allocation.height;
+ } else {
+ frame_resize_inside(frame->frame,
+ child->allocation.width,
+ child->allocation.height);
+ width = frame_width(frame->frame);
+ height = frame_height(frame->frame);
+ }
}
-}
-
-
-static int
-frame_button_motion_handler(struct widget *widget,
- struct input *input, uint32_t time,
- float x, float y, void *data)
-{
- struct frame_button *frame_button = data;
- enum frame_button_pointer previous_button_state = frame_button->state;
- /* only track state for a pressed button */
- if (input->grab != widget)
- return CURSOR_LEFT_PTR;
+ widget_set_allocation(widget, 0, 0, width, height);
- if (x > widget->allocation.x &&
- x < (widget->allocation.x + widget->allocation.width) &&
- y > widget->allocation.y &&
- y < (widget->allocation.y + widget->allocation.height)) {
- frame_button->state = FRAME_BUTTON_ACTIVE;
+ widget->surface->input_region =
+ wl_compositor_create_region(widget->window->display->compositor);
+ if (widget->window->type != TYPE_FULLSCREEN) {
+ frame_input_rect(frame->frame, &input.x, &input.y,
+ &input.width, &input.height);
+ wl_region_add(widget->surface->input_region,
+ input.x, input.y, input.width, input.height);
} else {
- frame_button->state = FRAME_BUTTON_DEFAULT;
+ wl_region_add(widget->surface->input_region, 0, 0, width, height);
}
- if (frame_button->state != previous_button_state)
- widget_schedule_redraw(frame_button->widget);
-
- return CURSOR_LEFT_PTR;
-}
-
-static void
-frame_button_redraw_handler(struct widget *widget, void *data)
-{
- struct frame_button *frame_button = data;
- cairo_t *cr;
- int width, height, x, y;
-
- x = widget->allocation.x;
- y = widget->allocation.y;
- width = widget->allocation.width;
- height = widget->allocation.height;
-
- if (!width)
- return;
- if (!height)
- return;
- if (widget->opaque)
- return;
-
- cr = widget_cairo_create(widget);
-
- if (frame_button->decoration == FRAME_BUTTON_FANCY) {
- cairo_set_line_width(cr, 1);
-
- cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
- cairo_rectangle (cr, x, y, 25, 16);
+ widget_set_allocation(widget, 0, 0, width, height);
- cairo_stroke_preserve(cr);
+ if (child->opaque) {
+ if (widget->window->type != TYPE_FULLSCREEN) {
+ frame_opaque_rect(frame->frame, &opaque.x, &opaque.y,
+ &opaque.width, &opaque.height);
- switch (frame_button->state) {
- case FRAME_BUTTON_DEFAULT:
- cairo_set_source_rgb(cr, 0.88, 0.88, 0.88);
- break;
- case FRAME_BUTTON_OVER:
- cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
- break;
- case FRAME_BUTTON_ACTIVE:
- cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
- break;
+ wl_region_add(widget->surface->opaque_region,
+ opaque.x, opaque.y,
+ opaque.width, opaque.height);
+ } else {
+ wl_region_add(widget->surface->opaque_region,
+ 0, 0, width, height);
}
-
- cairo_fill (cr);
-
- x += 4;
}
- cairo_set_source_surface(cr, frame_button->icon, x, y);
- cairo_paint(cr);
-
- cairo_destroy(cr);
-}
-
-static struct widget *
-frame_button_create(struct frame *frame, void *data, enum frame_button_action type,
- enum frame_button_align align, enum frame_button_decoration style)
-{
- struct frame_button *frame_button;
- const char *icon = data;
-
- frame_button = xzalloc (sizeof *frame_button);
- frame_button->icon = cairo_image_surface_create_from_png(icon);
- frame_button->widget = widget_add_widget(frame->widget, frame_button);
- frame_button->frame = frame;
- frame_button->type = type;
- frame_button->align = align;
- frame_button->decoration = style;
-
- wl_list_insert(frame->buttons_list.prev, &frame_button->link);
-
- widget_set_redraw_handler(frame_button->widget, frame_button_redraw_handler);
- widget_set_enter_handler(frame_button->widget, frame_button_enter_handler);
- widget_set_leave_handler(frame_button->widget, frame_button_leave_handler);
- widget_set_touch_down_handler(frame_button->widget, frame_button_touch_down_handler);
- widget_set_button_handler(frame_button->widget, frame_button_button_handler);
- widget_set_motion_handler(frame_button->widget, frame_button_motion_handler);
- return frame_button->widget;
-}
-
-static void
-frame_button_destroy(struct frame_button *frame_button)
-{
- widget_destroy(frame_button->widget);
- wl_list_remove(&frame_button->link);
- cairo_surface_destroy(frame_button->icon);
- free(frame_button);
- return;
+ widget_schedule_redraw(widget);
}
static void
frame_redraw_handler(struct widget *widget, void *data)
{
cairo_t *cr;
+ struct window_frame *frame = data;
struct window *window = widget->window;
- struct theme *t = window->display->theme;
- uint32_t flags = 0;
if (window->type == TYPE_FULLSCREEN)
return;
+ if (window->focus_count) {
+ frame_set_flag(frame->frame, FRAME_FLAG_ACTIVE);
+ } else {
+ frame_unset_flag(frame->frame, FRAME_FLAG_ACTIVE);
+ }
+
cr = widget_cairo_create(widget);
- if (window->focus_count)
- flags |= THEME_FRAME_ACTIVE;
- if (window->type == TYPE_MAXIMIZED)
- flags |= THEME_FRAME_MAXIMIZED;
- theme_render_frame(t, cr, widget->allocation.width,
- widget->allocation.height, window->title, flags);
+ frame_repaint(frame->frame, cr);
cairo_destroy(cr);
}
static int
-frame_get_pointer_image_for_location(struct frame *frame, struct input *input)
+frame_get_pointer_image_for_location(struct window_frame *frame,
+ enum theme_location location)
{
- struct theme *t = frame->widget->window->display->theme;
struct window *window = frame->widget->window;
- int location;
if (window->type != TYPE_TOPLEVEL)
return CURSOR_LEFT_PTR;
- location = theme_get_location(t, input->sx, input->sy,
- frame->widget->allocation.width,
- frame->widget->allocation.height,
- window->type == TYPE_MAXIMIZED ?
- THEME_FRAME_MAXIMIZED : 0);
-
switch (location) {
case THEME_LOCATION_RESIZING_TOP:
return CURSOR_TOP;
@@ -2561,15 +2288,15 @@ frame_get_pointer_image_for_location(struct frame *frame, struct input *input)
}
static void
-frame_menu_func(struct window *window, int index, void *data)
+frame_menu_func(struct window *window,
+ struct input *input, int index, void *data)
{
struct display *display;
switch (index) {
case 0: /* close */
if (window->close_handler)
- window->close_handler(window->parent,
- window->user_data);
+ window->close_handler(window->user_data);
else
display_exit(window->display);
break;
@@ -2624,7 +2351,14 @@ static int
frame_enter_handler(struct widget *widget,
struct input *input, float x, float y, void *data)
{
- return frame_get_pointer_image_for_location(data, input);
+ struct window_frame *frame = data;
+ enum theme_location location;
+
+ location = frame_pointer_enter(frame->frame, input, x, y);
+ if (frame_status(frame->frame) & FRAME_STATUS_REPAINT)
+ widget_schedule_redraw(frame->widget);
+
+ return frame_get_pointer_image_for_location(data, location);
}
static int
@@ -2632,7 +2366,79 @@ frame_motion_handler(struct widget *widget,
struct input *input, uint32_t time,
float x, float y, void *data)
{
- return frame_get_pointer_image_for_location(data, input);
+ struct window_frame *frame = data;
+ enum theme_location location;
+
+ location = frame_pointer_motion(frame->frame, input, x, y);
+ if (frame_status(frame->frame) & FRAME_STATUS_REPAINT)
+ widget_schedule_redraw(frame->widget);
+
+ return frame_get_pointer_image_for_location(data, location);
+}
+
+static void
+frame_leave_handler(struct widget *widget,
+ struct input *input, void *data)
+{
+ struct window_frame *frame = data;
+
+ frame_pointer_leave(frame->frame, input);
+ if (frame_status(frame->frame) & FRAME_STATUS_REPAINT)
+ widget_schedule_redraw(frame->widget);
+}
+
+static void
+frame_handle_status(struct window_frame *frame, struct input *input,
+ uint32_t time, enum theme_location location)
+{
+ struct window *window = frame->widget->window;
+ uint32_t status;
+
+ status = frame_status(frame->frame);
+ if (status & FRAME_STATUS_REPAINT)
+ widget_schedule_redraw(frame->widget);
+
+ if (status & FRAME_STATUS_MINIMIZE)
+ fprintf(stderr,"Minimize stub\n");
+
+ if (status & FRAME_STATUS_MENU) {
+ window_show_frame_menu(window, input, time);
+ frame_status_clear(frame->frame, FRAME_STATUS_MENU);
+ }
+
+ if (status & FRAME_STATUS_MAXIMIZE) {
+ window_set_maximized(window, window->type != TYPE_MAXIMIZED);
+ frame_status_clear(frame->frame, FRAME_STATUS_MAXIMIZE);
+ }
+
+ if (status & FRAME_STATUS_CLOSE) {
+ if (window->close_handler)
+ window->close_handler(window->user_data);
+ else
+ display_exit(window->display);
+ return;
+ }
+
+ if ((status & FRAME_STATUS_MOVE) && window->shell_surface) {
+ input_ungrab(input);
+ wl_shell_surface_move(window->shell_surface,
+ input_get_seat(input),
+ window->display->serial);
+
+ frame_status_clear(frame->frame, FRAME_STATUS_MOVE);
+ }
+
+ if ((status & FRAME_STATUS_RESIZE) && window->shell_surface) {
+ input_ungrab(input);
+
+ window->resizing = 1;
+ wl_shell_surface_resize(window->shell_surface,
+ input_get_seat(input),
+ window->display->serial,
+ location);
+
+ frame_status_clear(frame->frame, FRAME_STATUS_RESIZE);
+ }
}
static void
@@ -2642,99 +2448,62 @@ frame_button_handler(struct widget *widget,
void *data)
{
- struct frame *frame = data;
- struct window *window = widget->window;
- struct display *display = window->display;
- int location;
-
- if (state != WL_POINTER_BUTTON_STATE_PRESSED)
- return;
+ struct window_frame *frame = data;
+ enum theme_location location;
- location = theme_get_location(display->theme, input->sx, input->sy,
- frame->widget->allocation.width,
- frame->widget->allocation.height,
- window->type == TYPE_MAXIMIZED ?
- THEME_FRAME_MAXIMIZED : 0);
-
- if (window->display->shell && button == BTN_LEFT &&
- window->type == TYPE_TOPLEVEL) {
- switch (location) {
- case THEME_LOCATION_TITLEBAR:
- if (!window->shell_surface)
- break;
- input_ungrab(input);
- wl_shell_surface_move(window->shell_surface,
- input_get_seat(input),
- display->serial);
- break;
- case THEME_LOCATION_RESIZING_TOP:
- case THEME_LOCATION_RESIZING_BOTTOM:
- case THEME_LOCATION_RESIZING_LEFT:
- case THEME_LOCATION_RESIZING_RIGHT:
- case THEME_LOCATION_RESIZING_TOP_LEFT:
- case THEME_LOCATION_RESIZING_TOP_RIGHT:
- case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
- case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
- if (!window->shell_surface)
- break;
- input_ungrab(input);
-
- window->resizing = 1;
- wl_shell_surface_resize(window->shell_surface,
- input_get_seat(input),
- display->serial, location);
- break;
- }
- } else if (button == BTN_RIGHT &&
- (window->type == TYPE_TOPLEVEL ||
- window->type == TYPE_MAXIMIZED)) {
- window_show_frame_menu(window, input, time);
- }
+ location = frame_pointer_button(frame->frame, input, button, state);
+ frame_handle_status(frame, input, time, location);
}
-static void
+static void
frame_touch_down_handler(struct widget *widget, struct input *input,
uint32_t serial, uint32_t time, int32_t id,
float x, float y, void *data)
{
- struct window *window = widget->window;
- struct display *display = window->display;
-
- wl_shell_surface_move(window->shell_surface,
- input_get_seat(input),
- display->serial);
+ struct window_frame *frame = data;
+
+ frame_touch_down(frame->frame, input, id, x, y);
+ frame_handle_status(frame, input, time, THEME_LOCATION_CLIENT_AREA);
+}
+
+static void
+frame_touch_up_handler(struct widget *widget,
+ struct input *input, uint32_t serial, uint32_t time,
+ int32_t id, void *data)
+{
+ struct window_frame *frame = data;
+
+ frame_touch_up(frame->frame, input, id);
+ frame_handle_status(frame, input, time, THEME_LOCATION_CLIENT_AREA);
}
struct widget *
-frame_create(struct window *window, void *data)
+window_frame_create(struct window *window, void *data)
{
- struct frame *frame;
+ struct window_frame *frame;
+ uint32_t buttons;
+
+ if (window->type == TYPE_CUSTOM) {
+ buttons = FRAME_BUTTON_NONE;
+ } else {
+ buttons = FRAME_BUTTON_ALL;
+ }
frame = xzalloc(sizeof *frame);
+ frame->frame = frame_create(window->display->theme, 0, 0,
+ buttons, window->title);
+
frame->widget = window_add_widget(window, frame);
frame->child = widget_add_widget(frame->widget, data);
widget_set_redraw_handler(frame->widget, frame_redraw_handler);
widget_set_resize_handler(frame->widget, frame_resize_handler);
widget_set_enter_handler(frame->widget, frame_enter_handler);
+ widget_set_leave_handler(frame->widget, frame_leave_handler);
widget_set_motion_handler(frame->widget, frame_motion_handler);
widget_set_button_handler(frame->widget, frame_button_handler);
widget_set_touch_down_handler(frame->widget, frame_touch_down_handler);
-
- /* Create empty list for frame buttons */
- wl_list_init(&frame->buttons_list);
-
- frame_button_create(frame, DATADIR "/weston/icon_window.png",
- FRAME_BUTTON_ICON, FRAME_BUTTON_LEFT, FRAME_BUTTON_NONE);
-
- frame_button_create(frame, DATADIR "/weston/sign_close.png",
- FRAME_BUTTON_CLOSE, FRAME_BUTTON_RIGHT, FRAME_BUTTON_FANCY);
-
- frame_button_create(frame, DATADIR "/weston/sign_maximize.png",
- FRAME_BUTTON_MAXIMIZE, FRAME_BUTTON_RIGHT, FRAME_BUTTON_FANCY);
-
- frame_button_create(frame, DATADIR "/weston/sign_minimize.png",
- FRAME_BUTTON_MINIMIZE, FRAME_BUTTON_RIGHT, FRAME_BUTTON_FANCY);
+ widget_set_touch_up_handler(frame->widget, frame_touch_up_handler);
window->frame = frame;
@@ -2742,7 +2511,8 @@ frame_create(struct window *window, void *data)
}
void
-frame_set_child_size(struct widget *widget, int child_width, int child_height)
+window_frame_set_child_size(struct widget *widget, int child_width,
+ int child_height)
{
struct display *display = widget->window->display;
struct theme *t = display->theme;
@@ -2766,12 +2536,9 @@ frame_set_child_size(struct widget *widget, int child_width, int child_height)
}
static void
-frame_destroy(struct frame *frame)
+window_frame_destroy(struct window_frame *frame)
{
- struct frame_button *button, *tmp;
-
- wl_list_for_each_safe(button, tmp, &frame->buttons_list, link)
- frame_button_destroy(button);
+ frame_destroy(frame->frame);
/* frame->child must be destroyed by the application */
widget_destroy(frame->widget);
@@ -2814,6 +2581,31 @@ input_set_focus_widget(struct input *input, struct widget *focus,
}
void
+touch_grab(struct input *input, int32_t touch_id)
+{
+ input->touch_grab = 1;
+ input->touch_grab_id = touch_id;
+}
+
+void
+touch_ungrab(struct input *input)
+{
+ struct touch_point *tp, *tmp;
+
+ input->touch_grab = 0;
+
+ wl_list_for_each_safe(tp, tmp,
+ &input->touch_point_list, link) {
+ if (tp->id != input->touch_grab_id)
+ continue;
+ wl_list_remove(&tp->link);
+ free(tp);
+
+ return;
+ }
+}
+
+void
input_grab(struct input *input, struct widget *widget, uint32_t button)
{
input->grab = widget;
@@ -3038,6 +2830,8 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
uint32_t format, int fd, uint32_t size)
{
struct input *input = data;
+ struct xkb_keymap *keymap;
+ struct xkb_state *state;
char *map_str;
if (!data) {
@@ -3056,26 +2850,30 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
return;
}
- input->xkb.keymap = xkb_map_new_from_string(input->display->xkb_context,
- map_str,
- XKB_KEYMAP_FORMAT_TEXT_V1,
- 0);
+ keymap = xkb_map_new_from_string(input->display->xkb_context,
+ map_str,
+ XKB_KEYMAP_FORMAT_TEXT_V1,
+ 0);
munmap(map_str, size);
close(fd);
- if (!input->xkb.keymap) {
+ if (!keymap) {
fprintf(stderr, "failed to compile keymap\n");
return;
}
- input->xkb.state = xkb_state_new(input->xkb.keymap);
- if (!input->xkb.state) {
+ state = xkb_state_new(keymap);
+ if (!state) {
fprintf(stderr, "failed to create XKB state\n");
- xkb_map_unref(input->xkb.keymap);
- input->xkb.keymap = NULL;
+ xkb_map_unref(keymap);
return;
}
+ xkb_keymap_unref(input->xkb.keymap);
+ xkb_state_unref(input->xkb.state);
+ input->xkb.keymap = keymap;
+ input->xkb.state = state;
+
input->xkb.control_mask =
1 << xkb_map_mod_get_index(input->xkb.keymap, "Control");
input->xkb.alt_mask =
@@ -3148,8 +2946,7 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
input->modifiers == MOD_ALT_MASK &&
state == WL_KEYBOARD_KEY_STATE_PRESSED) {
if (window->close_handler)
- window->close_handler(window->parent,
- window->user_data);
+ window->close_handler(window->user_data);
else
display_exit(window->display);
} else if (window->key_handler) {
@@ -3236,6 +3033,8 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
if (tp) {
tp->id = id;
tp->widget = widget;
+ tp->x = sx;
+ tp->y = sy;
wl_list_insert(&input->touch_point_list, &tp->link);
if (widget->touch_down_handler)
@@ -3295,6 +3094,8 @@ touch_handle_motion(void *data, struct wl_touch *wl_touch,
if (tp->id != id)
continue;
+ tp->x = sx;
+ tp->y = sy;
if (tp->widget->touch_motion_handler)
(*tp->widget->touch_motion_handler)(tp->widget, input, time,
id, sx, sy,
@@ -3412,6 +3213,23 @@ input_get_position(struct input *input, int32_t *x, int32_t *y)
*y = input->sy;
}
+int
+input_get_touch(struct input *input, int32_t id, float *x, float *y)
+{
+ struct touch_point *tp;
+
+ wl_list_for_each(tp, &input->touch_point_list, link) {
+ if (tp->id != id)
+ continue;
+
+ *x = tp->x;
+ *y = tp->y;
+ return 0;
+ }
+
+ return -1;
+}
+
struct display *
input_get_display(struct input *input)
{
@@ -3508,9 +3326,14 @@ data_device_enter(void *data, struct wl_data_device *data_device,
float y = wl_fixed_to_double(y_w);
char **p;
- input->pointer_enter_serial = serial;
window = wl_surface_get_user_data(surface);
- input->pointer_focus = window;
+ input->drag_enter_serial = serial;
+ input->drag_focus = window,
+ input->drag_x = x;
+ input->drag_y = y;
+
+ if (!input->touch_grab)
+ input->pointer_enter_serial = serial;
if (offer) {
input->drag_offer = wl_data_offer_get_user_data(offer);
@@ -3524,7 +3347,6 @@ data_device_enter(void *data, struct wl_data_device *data_device,
types_data = NULL;
}
- window = input->pointer_focus;
if (window->data_handler)
window->data_handler(window, input, x, y, types_data,
window->user_data);
@@ -3546,13 +3368,13 @@ data_device_motion(void *data, struct wl_data_device *data_device,
uint32_t time, wl_fixed_t x_w, wl_fixed_t y_w)
{
struct input *input = data;
- struct window *window = input->pointer_focus;
+ struct window *window = input->drag_focus;
float x = wl_fixed_to_double(x_w);
float y = wl_fixed_to_double(y_w);
void *types_data;
- input->sx = x;
- input->sy = y;
+ input->drag_x = x;
+ input->drag_y = y;
if (input->drag_offer)
types_data = input->drag_offer->types.data;
@@ -3568,11 +3390,18 @@ static void
data_device_drop(void *data, struct wl_data_device *data_device)
{
struct input *input = data;
- struct window *window = input->pointer_focus;
+ struct window *window = input->drag_focus;
+ float x, y;
+
+ x = input->drag_x;
+ y = input->drag_y;
if (window->drop_handler)
window->drop_handler(window, input,
- input->sx, input->sy, window->user_data);
+ x, y, window->user_data);
+
+ if (input->touch_grab)
+ touch_ungrab(input);
}
static void
@@ -3741,7 +3570,7 @@ void
input_accept(struct input *input, const char *type)
{
wl_data_offer_accept(input->drag_offer->offer,
- input->pointer_enter_serial, type);
+ input->drag_enter_serial, type);
}
static void
@@ -3789,8 +3618,8 @@ input_receive_drag_data(struct input *input, const char *mime_type,
data_func_t func, void *data)
{
data_offer_receive_data(input->drag_offer, mime_type, func, data);
- input->drag_offer->x = input->sx;
- input->drag_offer->y = input->sy;
+ input->drag_offer->x = input->drag_x;
+ input->drag_offer->y = input->drag_y;
}
int
@@ -3844,16 +3673,6 @@ window_move(struct window *window, struct input *input, uint32_t serial)
wl_shell_surface_move(window->shell_surface, input->seat, serial);
}
-void
-window_touch_move(struct window *window, struct input *input, uint32_t serial)
-{
- if (!window->shell_surface)
- return;
-
- wl_shell_surface_move(window->shell_surface, input->seat,
- window->display->serial);
-}
-
static void
surface_set_synchronized(struct surface *surface)
{
@@ -3956,21 +3775,10 @@ hack_prevent_EGL_sub_surface_deadlock(struct window *window)
}
static void
-idle_resize(struct window *window)
+window_do_resize(struct window *window)
{
struct surface *surface;
- window->resize_needed = 0;
- window->redraw_needed = 1;
-
- DBG("from %dx%d to %dx%d\n",
- window->main_surface->server_allocation.width,
- window->main_surface->server_allocation.height,
- window->pending_allocation.width,
- window->pending_allocation.height);
-
- hack_prevent_EGL_sub_surface_deadlock(window);
-
widget_set_allocation(window->main_surface->widget,
window->pending_allocation.x,
window->pending_allocation.y,
@@ -3993,6 +3801,46 @@ idle_resize(struct window *window)
}
}
+static void
+idle_resize(struct window *window)
+{
+ window->resize_needed = 0;
+ window->redraw_needed = 1;
+
+ DBG("from %dx%d to %dx%d\n",
+ window->main_surface->server_allocation.width,
+ window->main_surface->server_allocation.height,
+ window->pending_allocation.width,
+ window->pending_allocation.height);
+
+ hack_prevent_EGL_sub_surface_deadlock(window);
+
+ window_do_resize(window);
+}
+
+static void
+undo_resize(struct window *window)
+{
+ window->pending_allocation.width =
+ window->main_surface->server_allocation.width;
+ window->pending_allocation.height =
+ window->main_surface->server_allocation.height;
+
+ DBG("back to %dx%d\n",
+ window->main_surface->server_allocation.width,
+ window->main_surface->server_allocation.height);
+
+ window_do_resize(window);
+
+ if (window->pending_allocation.width == 0 &&
+ window->pending_allocation.height == 0) {
+ fprintf(stderr, "Error: Could not draw a surface, "
+ "most likely due to insufficient disk space in "
+ "%s (XDG_RUNTIME_DIR).\n", getenv("XDG_RUNTIME_DIR"));
+ exit(EXIT_FAILURE);
+ }
+}
+
void
window_schedule_resize(struct window *window, int width, int height)
{
@@ -4052,6 +3900,7 @@ menu_destroy(struct menu *menu)
{
widget_destroy(menu->widget);
window_destroy(menu->window);
+ frame_destroy(menu->frame);
free(menu);
}
@@ -4116,25 +3965,31 @@ static const struct wl_callback_listener listener = {
frame_callback
};
-static void
+static int
surface_redraw(struct surface *surface)
{
DBG_OBJ(surface->surface, "begin\n");
if (!surface->window->redraw_needed && !surface->redraw_needed)
- return;
+ return 0;
/* Whole-window redraw forces a redraw even if the previous has
* not yet hit the screen.
*/
if (surface->frame_cb) {
if (!surface->window->redraw_needed)
- return;
+ return 0;
DBG_OBJ(surface->frame_cb, "cancelled\n");
wl_callback_destroy(surface->frame_cb);
}
+ if (surface->widget->use_cairo &&
+ !widget_get_cairo_surface(surface->widget)) {
+ DBG_OBJ(surface->surface, "cancelled due buffer failure\n");
+ return -1;
+ }
+
surface->frame_cb = wl_surface_frame(surface->surface);
wl_callback_add_listener(surface->frame_cb, &listener, surface);
DBG_OBJ(surface->frame_cb, "new\n");
@@ -4143,6 +3998,7 @@ surface_redraw(struct surface *surface)
DBG_OBJ(surface->surface, "-> widget_redraw\n");
widget_redraw(surface->widget);
DBG_OBJ(surface->surface, "done\n");
+ return 0;
}
static void
@@ -4150,6 +4006,8 @@ idle_redraw(struct task *task, uint32_t events)
{
struct window *window = container_of(task, struct window, redraw_task);
struct surface *surface;
+ int failed = 0;
+ int resized = 0;
DBG(" --------- \n");
@@ -4164,16 +4022,35 @@ idle_redraw(struct task *task, uint32_t events)
}
idle_resize(window);
+ resized = 1;
}
- wl_list_for_each(surface, &window->subsurface_list, link)
- surface_redraw(surface);
+ if (surface_redraw(window->main_surface) < 0) {
+ /*
+ * Only main_surface failure will cause us to undo the resize.
+ * If sub-surfaces fail, they will just be broken with old
+ * content.
+ */
+ failed = 1;
+ } else {
+ wl_list_for_each(surface, &window->subsurface_list, link) {
+ if (surface == window->main_surface)
+ continue;
+
+ surface_redraw(surface);
+ }
+ }
window->redraw_needed = 0;
window_flush(window);
wl_list_for_each(surface, &window->subsurface_list, link)
surface_set_synchronized_default(surface);
+
+ if (resized && failed) {
+ /* Restore widget tree to correspond to what is on screen. */
+ undo_resize(window);
+ }
}
static void
@@ -4207,6 +4084,12 @@ window_is_fullscreen(struct window *window)
return window->type == TYPE_FULLSCREEN;
}
+int
+window_is_transient(struct window *window)
+{
+ return window->type == TYPE_TRANSIENT;
+}
+
static void
configure_request_completed(void *data, struct wl_callback *callback, uint32_t time)
{
@@ -4375,6 +4258,10 @@ window_set_title(struct window *window, const char *title)
{
free(window->title);
window->title = strdup(title);
+ if (window->frame) {
+ frame_set_title(window->frame->frame, title);
+ widget_schedule_redraw(window->frame->widget);
+ }
if (window->shell_surface)
wl_shell_surface_set_title(window->shell_surface, title);
}
@@ -4489,8 +4376,7 @@ surface_create(struct window *window)
}
static struct window *
-window_create_internal(struct display *display,
- struct window *parent, int type)
+window_create_internal(struct display *display, int type)
{
struct window *window;
struct surface *surface;
@@ -4498,7 +4384,6 @@ window_create_internal(struct display *display,
window = xzalloc(sizeof *window);
wl_list_init(&window->subsurface_list);
window->display = display;
- window->parent = parent;
surface = surface_create(window);
window->main_surface = surface;
@@ -4542,13 +4427,13 @@ window_create_internal(struct display *display,
struct window *
window_create(struct display *display)
{
- return window_create_internal(display, NULL, TYPE_NONE);
+ return window_create_internal(display, TYPE_NONE);
}
struct window *
window_create_custom(struct display *display)
{
- return window_create_internal(display, NULL, TYPE_CUSTOM);
+ return window_create_internal(display, TYPE_CUSTOM);
}
struct window *
@@ -4557,8 +4442,7 @@ window_create_transient(struct display *display, struct window *parent,
{
struct window *window;
- window = window_create_internal(parent->display,
- parent, TYPE_TRANSIENT);
+ window = window_create_internal(parent->display, TYPE_TRANSIENT);
window->x = x;
window->y = y;
@@ -4566,7 +4450,7 @@ window_create_transient(struct display *display, struct window *parent,
if (display->shell)
wl_shell_surface_set_transient(
window->shell_surface,
- window->parent->main_surface->surface,
+ parent->main_surface->surface,
window->x, window->y, flags);
return window;
@@ -4575,9 +4459,11 @@ window_create_transient(struct display *display, struct window *parent,
static void
menu_set_item(struct menu *menu, int sy)
{
+ int32_t x, y, width, height;
int next;
- next = (sy - 8) / 20;
+ frame_interior(menu->frame, &x, &y, &width, &height);
+ next = (sy - y) / 20;
if (menu->current != next) {
menu->current = next;
widget_schedule_redraw(menu->widget);
@@ -4631,8 +4517,8 @@ menu_button_handler(struct widget *widget,
(menu->release_count > 0 || time - menu->time > 500)) {
/* Either relase after press-drag-release or
* click-motion-click. */
- menu->func(menu->window->parent,
- menu->current, menu->window->parent->user_data);
+ menu->func(menu->parent, input,
+ menu->current, menu->parent->user_data);
input_ungrab(input);
menu_destroy(menu);
} else if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
@@ -4644,35 +4530,35 @@ static void
menu_redraw_handler(struct widget *widget, void *data)
{
cairo_t *cr;
- const int32_t r = 3, margin = 3;
struct menu *menu = data;
- int32_t width, height, i;
+ int32_t x, y, width, height, i;
cr = widget_cairo_create(widget);
- cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
- cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
- cairo_paint(cr);
- width = widget->allocation.width;
- height = widget->allocation.height;
- rounded_rect(cr, 0, 0, width, height, r);
+ frame_repaint(menu->frame, cr);
+ frame_interior(menu->frame, &x, &y, &width, &height);
- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
- cairo_set_source_rgba(cr, 0.0, 0.0, 0.4, 0.8);
+ theme_set_background_source(menu->window->display->theme,
+ cr, THEME_FRAME_ACTIVE);
+ cairo_rectangle(cr, x, y, width, height);
cairo_fill(cr);
+ cairo_select_font_face(cr, "sans",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size(cr, 12);
+
for (i = 0; i < menu->count; i++) {
if (i == menu->current) {
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
- cairo_rectangle(cr, margin, i * 20 + margin,
- width - 2 * margin, 20);
+ cairo_rectangle(cr, x, y + i * 20, width, 20);
cairo_fill(cr);
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
- cairo_move_to(cr, 10, i * 20 + 16);
+ cairo_move_to(cr, x + 10, y + i * 20 + 16);
cairo_show_text(cr, menu->entries[i]);
} else {
- cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
- cairo_move_to(cr, 10, i * 20 + 16);
+ cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
+ cairo_move_to(cr, x + 10, y + i * 20 + 16);
cairo_show_text(cr, menu->entries[i]);
}
}
@@ -4688,22 +4574,25 @@ window_show_menu(struct display *display,
{
struct window *window;
struct menu *menu;
- const int32_t margin = 3;
+ int32_t ix, iy;
menu = malloc(sizeof *menu);
if (!menu)
return;
- window = window_create_internal(parent->display, parent, TYPE_MENU);
+ window = window_create_internal(parent->display, TYPE_MENU);
if (!window) {
free(menu);
return;
}
menu->window = window;
+ menu->parent = parent;
menu->widget = window_add_widget(menu->window, menu);
window_set_buffer_scale (menu->window, window_get_buffer_scale (parent));
window_set_buffer_transform (menu->window, window_get_buffer_transform (parent));
+ menu->frame = frame_create(window->display->theme, 0, 0,
+ FRAME_BUTTON_NONE, NULL);
menu->entries = entries;
menu->count = count;
menu->release_count = 0;
@@ -4716,10 +4605,6 @@ window_show_menu(struct display *display,
window->y = y;
input_ungrab(input);
- wl_shell_surface_set_popup(window->shell_surface, input->seat,
- display_get_serial(window->display),
- window->parent->main_surface->surface,
- window->x, window->y, 0);
widget_set_redraw_handler(menu->widget, menu_redraw_handler);
widget_set_enter_handler(menu->widget, menu_enter_handler);
@@ -4728,7 +4613,16 @@ window_show_menu(struct display *display,
widget_set_button_handler(menu->widget, menu_button_handler);
input_grab(input, menu->widget, 0);
- window_schedule_resize(window, 200, count * 20 + margin * 2);
+ frame_resize_inside(menu->frame, 200, count * 20);
+ frame_set_flag(menu->frame, FRAME_FLAG_ACTIVE);
+ window_schedule_resize(window, frame_width(menu->frame),
+ frame_height(menu->frame));
+
+ frame_interior(menu->frame, &ix, &iy, NULL, NULL);
+ wl_shell_surface_set_popup(window->shell_surface, input->seat,
+ display_get_serial(window->display),
+ parent->main_surface->surface,
+ window->x - ix, window->y - iy, 0);
}
void
@@ -4849,6 +4743,7 @@ display_add_output(struct display *d, uint32_t id)
output->scale = 1;
output->output =
wl_registry_bind(d->registry, id, &wl_output_interface, 2);
+ output->server_output_id = id;
wl_list_insert(d->output_list.prev, &output->link);
wl_output_add_listener(output->output, &output_listener, output);
@@ -4865,6 +4760,19 @@ output_destroy(struct output *output)
free(output);
}
+static void
+display_destroy_output(struct display *d, uint32_t id)
+{
+ struct output *output;
+
+ wl_list_for_each(output, &d->output_list, link) {
+ if (output->server_output_id == id) {
+ output_destroy(output);
+ break;
+ }
+ }
+}
+
void
display_set_global_handler(struct display *display,
display_global_handler_t handler)
@@ -4882,6 +4790,15 @@ display_set_global_handler(struct display *display,
}
void
+display_set_global_handler_remove(struct display *display,
+ display_global_handler_t remove_handler)
+{
+ display->global_handler_remove = remove_handler;
+ if (!remove_handler)
+ return;
+}
+
+void
display_set_output_configure_handler(struct display *display,
display_output_handler_t handler)
{
@@ -4965,7 +4882,7 @@ fini_xkb(struct input *input)
xkb_map_unref(input->xkb.keymap);
}
-#define MAX(a,b) ((a) > (b) ? a : b)
+#define MIN(a,b) ((a) < (b) ? a : b)
static void
display_add_input(struct display *d, uint32_t id)
@@ -4975,7 +4892,7 @@ display_add_input(struct display *d, uint32_t id)
input = xzalloc(sizeof *input);
input->display = d;
input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface,
- MAX(d->seat_version, 3));
+ MIN(d->seat_version, 3));
input->touch_focus = NULL;
input->pointer_focus = NULL;
input->keyboard_focus = NULL;
@@ -5115,9 +5032,15 @@ registry_handle_global_remove(void *data, struct wl_registry *registry,
if (global->name != name)
continue;
- /* XXX: Should destroy bound globals, and call
- * the counterpart of display::global_handler
- */
+ if (strcmp(global->interface, "wl_output") == 0)
+ display_destroy_output(d, name);
+
+ /* XXX: Should destroy remaining bound globals */
+
+ if (d->global_handler_remove)
+ d->global_handler_remove(d, name, global->interface,
+ global->version, d->user_data);
+
wl_list_remove(&global->link);
free(global->interface);
free(global);
@@ -5480,12 +5403,6 @@ display_get_argb_egl_config(struct display *d)
return d->argb_config;
}
-struct wl_shell *
-display_get_shell(struct display *display)
-{
- return display->shell;
-}
-
int
display_acquire_window_surface(struct display *display,
struct window *window,
@@ -5656,3 +5573,9 @@ xstrdup(const char *s)
{
return fail_on_null(strdup(s));
}
+
+void *
+xrealloc(char *p, size_t s)
+{
+ return fail_on_null(realloc(p, s));
+}
diff --git a/clients/window.h b/clients/window.h
index 4427ab5a..dec133fc 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -28,7 +28,6 @@
#include <cairo.h>
#include "../shared/config-parser.h"
#include "../shared/zalloc.h"
-#include "subsurface-client-protocol.h"
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
@@ -62,6 +61,8 @@ void *
xzalloc(size_t s);
char *
xstrdup(const char *s);
+void *
+xrealloc(char *p, size_t s);
struct display *
display_create(int *argc, char *argv[]);
@@ -87,9 +88,6 @@ display_get_cairo_device(struct display *display);
struct wl_compositor *
display_get_compositor(struct display *display);
-struct wl_shell *
-display_get_shell(struct display *display);
-
struct output *
display_get_output(struct display *display);
@@ -104,6 +102,9 @@ typedef void (*display_global_handler_t)(struct display *display,
void
display_set_global_handler(struct display *display,
display_global_handler_t handler);
+void
+display_set_global_handler_remove(struct display *display,
+ display_global_handler_t remove_handler);
void *
display_bind(struct display *display, uint32_t name,
const struct wl_interface *interface, uint32_t version);
@@ -211,7 +212,7 @@ typedef void (*window_drop_handler_t)(struct window *window,
struct input *input,
int32_t x, int32_t y, void *data);
-typedef void (*window_close_handler_t)(struct window *window, void *data);
+typedef void (*window_close_handler_t)(void *data);
typedef void (*window_fullscreen_handler_t)(struct window *window, void *data);
typedef void (*window_output_handler_t)(struct window *window, struct output *output,
@@ -277,7 +278,8 @@ window_create_custom(struct display *display);
int
window_has_focus(struct window *window);
-typedef void (*menu_func_t)(struct window *window, int index, void *data);
+typedef void (*menu_func_t)(struct window *window,
+ struct input *input, int index, void *data);
void
window_show_menu(struct display *display,
@@ -329,8 +331,6 @@ window_get_display(struct window *window);
void
window_move(struct window *window, struct input *input, uint32_t time);
void
-window_touch_move(struct window *window, struct input *input, uint32_t time);
-void
window_get_allocation(struct window *window, struct rectangle *allocation);
void
window_schedule_redraw(struct window *window);
@@ -347,8 +347,8 @@ window_get_surface(struct window *window);
struct wl_surface *
window_get_wl_surface(struct window *window);
-struct wl_shell_surface *
-window_get_wl_shell_surface(struct window *window);
+struct wl_subsurface *
+widget_get_wl_subsurface(struct widget *widget);
enum window_buffer_type {
WINDOW_BUFFER_TYPE_EGL_WINDOW,
@@ -363,6 +363,9 @@ void
window_set_buffer_type(struct window *window, enum window_buffer_type type);
int
+window_is_transient(struct window *window);
+
+int
window_is_fullscreen(struct window *window);
void
@@ -506,12 +509,15 @@ widget_set_axis_handler(struct widget *widget,
widget_axis_handler_t handler);
void
widget_schedule_redraw(struct widget *widget);
+void
+widget_set_use_cairo(struct widget *widget, int use_cairo);
struct widget *
-frame_create(struct window *window, void *data);
+window_frame_create(struct window *window, void *data);
void
-frame_set_child_size(struct widget *widget, int child_width, int child_height);
+window_frame_set_child_size(struct widget *widget, int child_width,
+ int child_height);
void
input_set_pointer_image(struct input *input, int pointer);
@@ -519,6 +525,9 @@ input_set_pointer_image(struct input *input, int pointer);
void
input_get_position(struct input *input, int32_t *x, int32_t *y);
+int
+input_get_touch(struct input *input, int32_t id, float *x, float *y);
+
#define MOD_SHIFT_MASK 0x01
#define MOD_ALT_MASK 0x02
#define MOD_CONTROL_MASK 0x04
@@ -527,6 +536,12 @@ uint32_t
input_get_modifiers(struct input *input);
void
+touch_grab(struct input *input, int32_t touch_id);
+
+void
+touch_ungrab(struct input *input);
+
+void
input_grab(struct input *input, struct widget *widget, uint32_t button);
void
diff --git a/clients/wscreensaver.c b/clients/wscreensaver.c
index 9a2c47ad..47f6c8a3 100644
--- a/clients/wscreensaver.c
+++ b/clients/wscreensaver.c
@@ -200,7 +200,7 @@ create_wscreensaver_instance(struct wscreensaver *screensaver,
window_get_wl_surface(mi->window),
output);
} else {
- mi->widget = frame_create(mi->window, mi);
+ mi->widget = window_frame_create(mi->window, mi);
}
widget_set_redraw_handler(mi->widget, redraw_handler);
diff --git a/configure.ac b/configure.ac
index 50bce23a..571bf601 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
m4_define([weston_major_version], [1])
m4_define([weston_minor_version], [3])
-m4_define([weston_micro_version], [1])
+m4_define([weston_micro_version], [91])
m4_define([weston_version],
[weston_major_version.weston_minor_version.weston_micro_version])
@@ -35,6 +35,8 @@ LT_INIT([disable-static])
AC_ARG_VAR([WESTON_NATIVE_BACKEND],
[Set the native backend to use, if Weston is not running under Wayland nor X11. @<:@default=drm-backend.so@:>@])
+AC_ARG_VAR([WESTON_SHELL_CLIENT],
+ [Set the default desktop shell client to load if none is specified in weston.ini. @<:@default=weston-desktop-shell@:>@])
PKG_PROG_PKG_CONFIG()
@@ -53,16 +55,17 @@ AC_CHECK_DECL(CLOCK_MONOTONIC,[],
[[#include <time.h>]])
AC_CHECK_HEADERS([execinfo.h])
-AC_CHECK_FUNCS([mkostemp strchrnul initgroups])
+AC_CHECK_FUNCS([mkostemp strchrnul initgroups posix_fallocate])
-COMPOSITOR_MODULES="wayland-server >= 1.2.91 pixman-1"
+COMPOSITOR_MODULES="wayland-server >= 1.3.90 pixman-1"
AC_ARG_ENABLE(egl, [ --disable-egl],,
enable_egl=yes)
AM_CONDITIONAL(ENABLE_EGL, test x$enable_egl = xyes)
if test x$enable_egl = xyes; then
AC_DEFINE([ENABLE_EGL], [1], [Build Weston with EGL support])
- COMPOSITOR_MODULES="$COMPOSITOR_MODULES egl >= 7.10 glesv2"
+ PKG_CHECK_MODULES(EGL, [egl >= 7.10 glesv2])
+ PKG_CHECK_MODULES([EGL_TESTS], [egl >= 7.10 glesv2 wayland-client wayland-egl])
fi
AC_ARG_ENABLE(xkbcommon,
@@ -78,8 +81,6 @@ if test x$enable_xkbcommon = xyes; then
COMPOSITOR_MODULES="$COMPOSITOR_MODULES xkbcommon >= 0.3.0"
fi
-PKG_CHECK_MODULES(COMPOSITOR, [$COMPOSITOR_MODULES])
-
AC_ARG_ENABLE(setuid-install, [ --enable-setuid-install],,
enable_setuid_install=yes)
AM_CONDITIONAL(ENABLE_SETUID_INSTALL, test x$enable_setuid_install = xyes)
@@ -104,6 +105,8 @@ if test x$enable_xwayland = xyes; then
fi
fi
+PKG_CHECK_MODULES(LIBDRM, [libdrm],
+ [AC_DEFINE(HAVE_LIBDRM, 1, [Define if libdrm is available]) have_libdrm=yes], have_libdrm=no)
AC_ARG_ENABLE(x11-compositor, [ --enable-x11-compositor],,
enable_x11_compositor=yes)
@@ -143,12 +146,13 @@ fi
AC_ARG_ENABLE(drm-compositor, [ --enable-drm-compositor],,
enable_drm_compositor=yes)
-AM_CONDITIONAL(ENABLE_DRM_COMPOSITOR, test x$enable_drm_compositor = xyes -a x$enable_egl = xyes)
-if test x$enable_drm_compositor = xyes -a x$enable_egl = xyes; then
+AM_CONDITIONAL(ENABLE_DRM_COMPOSITOR, test x$enable_drm_compositor = xyes)
+if test x$enable_drm_compositor = xyes; then
AC_DEFINE([BUILD_DRM_COMPOSITOR], [1], [Build the DRM compositor])
PKG_CHECK_MODULES(DRM_COMPOSITOR, [libudev >= 136 libdrm >= 2.4.30 gbm mtdev >= 1.1.0])
fi
+PKG_CHECK_MODULES(COMPOSITOR, [$COMPOSITOR_MODULES])
AC_ARG_ENABLE(wayland-compositor, [ --enable-wayland-compositor],,
enable_wayland_compositor=yes)
@@ -157,7 +161,7 @@ AM_CONDITIONAL(ENABLE_WAYLAND_COMPOSITOR,
if test x$enable_wayland_compositor = xyes -a x$enable_egl = xyes; then
AC_DEFINE([BUILD_WAYLAND_COMPOSITOR], [1],
[Build the Wayland (nested) compositor])
- PKG_CHECK_MODULES(WAYLAND_COMPOSITOR, [wayland-client wayland-egl])
+ PKG_CHECK_MODULES(WAYLAND_COMPOSITOR, [wayland-client wayland-egl wayland-cursor])
fi
@@ -264,6 +268,8 @@ AC_SUBST(JPEG_LIBS)
PKG_CHECK_MODULES(CAIRO, [cairo])
+PKG_CHECK_MODULES(TEST_CLIENT, [wayland-client])
+
AC_ARG_ENABLE(simple-clients,
AS_HELP_STRING([--disable-simple-clients],
[do not build the simple wl_shm clients]),,
@@ -314,20 +320,26 @@ AC_ARG_ENABLE(resize-optimization,
AS_IF([test "x$enable_resize_optimization" = "xyes"],
[AC_DEFINE([USE_RESIZE_POOL], [1], [Use resize memory pool as a performance optimization])])
+PKG_CHECK_MODULES(SYSTEMD_LOGIN, [libsystemd-login],
+ [have_systemd_login=yes], [have_systemd_login=no])
+AS_IF([test "x$have_systemd_login" = "xyes"],
+ [AC_DEFINE([HAVE_SYSTEMD_LOGIN], [1], [Have systemd-login])])
+AM_CONDITIONAL(HAVE_SYSTEMD_LOGIN, test "x$have_systemd_login" = "xyes")
+
+PKG_CHECK_MODULES(SYSTEMD_LOGIN_209, [libsystemd-login >= 209],
+ [have_systemd_login_209=yes], [have_systemd_login_209=no])
+AS_IF([test "x$have_systemd_login_209" = "xyes"],
+ [AC_DEFINE([HAVE_SYSTEMD_LOGIN_209], [1], [Have systemd-login >= 209])])
+
AC_ARG_ENABLE(weston-launch, [ --enable-weston-launch],, enable_weston_launch=yes)
AM_CONDITIONAL(BUILD_WESTON_LAUNCH, test x$enable_weston_launch == xyes)
if test x$enable_weston_launch == xyes; then
- PKG_CHECK_MODULES(WESTON_LAUNCH, [libdrm])
- PKG_CHECK_MODULES(SYSTEMD_LOGIN, [libsystemd-login],
- [have_systemd_login=yes], [have_systemd_login=no])
- AS_IF([test "x$have_systemd_login" = "xyes"],
- [AC_DEFINE([HAVE_SYSTEMD_LOGIN], [1], [Have systemd-login])])
-
AC_CHECK_LIB([pam], [pam_open_session], [have_pam=yes], [have_pam=no])
if test x$have_pam == xno; then
AC_ERROR([weston-launch requires pam])
fi
- WESTON_LAUNCH_LIBS="$WESTON_LAUNCH_LIBS -lpam"
+ PAM_LIBS=-lpam
+ AC_SUBST(PAM_LIBS)
fi
if test x$enable_egl = xyes; then
@@ -351,13 +363,6 @@ AM_CONDITIONAL(BUILD_SUBSURFACES_CLIENT,
AM_CONDITIONAL(ENABLE_DESKTOP_SHELL, true)
-AC_ARG_ENABLE(tablet-shell,
- AS_HELP_STRING([--disable-tablet-shell],
- [do not build tablet-shell server plugin and client]),,
- enable_tablet_shell=yes)
-AM_CONDITIONAL(ENABLE_TABLET_SHELL,
- test "x$enable_tablet_shell" = "xyes")
-
# CMS modules
AC_ARG_ENABLE(colord,
AS_HELP_STRING([--disable-colord],
@@ -377,6 +382,28 @@ if test "x$enable_colord" != "xno"; then
fi
AM_CONDITIONAL(ENABLE_COLORD, test "x$enable_colord" = "xyes")
+# dbus support
+AC_ARG_ENABLE(dbus,
+ AS_HELP_STRING([--disable-dbus],
+ [do not build with dbus support]),,
+ enable_dbus=auto)
+if test "x$enable_dbus" != "xno"; then
+ PKG_CHECK_MODULES(DBUS,
+ dbus-1 >= 1.6,
+ have_dbus=yes,
+ have_dbus=no)
+ if test "x$have_dbus" = "xno" -a "x$enable_dbus" = "xyes"; then
+ AC_MSG_ERROR([dbus support explicitly requested, but libdbus couldn't be found])
+ fi
+ if test "x$have_dbus" = "xyes"; then
+ enable_dbus=yes
+ AC_DEFINE([HAVE_DBUS], [1], [Build with dbus support])
+ else
+ enable_dbus=no
+ fi
+fi
+AM_CONDITIONAL(ENABLE_DBUS, test "x$enable_dbus" = "xyes")
+
AC_ARG_ENABLE(wcap-tools, [ --disable-wcap-tools],, enable_wcap_tools=yes)
AM_CONDITIONAL(BUILD_WCAP_TOOLS, test x$enable_wcap_tools = xyes)
if test x$enable_wcap_tools = xyes; then
@@ -425,11 +452,18 @@ AC_MSG_NOTICE([Weston's native backend: $WESTON_NATIVE_BACKEND])
AC_DEFINE_UNQUOTED([WESTON_NATIVE_BACKEND], ["$WESTON_NATIVE_BACKEND"],
[The default backend to load, if not wayland nor x11.])
-AC_ARG_ENABLE(demo-clients,
- AS_HELP_STRING([--enable-demo-clients],
- [install demo clients built with weston]),,
- enable_demo_clients=no)
-AM_CONDITIONAL(ENABLE_DEMO_CLIENTS, [test "x$enable_demo_clients" = "xyes"])
+if test "x$WESTON_SHELL_CLIENT" = "x"; then
+ WESTON_SHELL_CLIENT="weston-desktop-shell"
+fi
+AC_MSG_NOTICE([Weston's default desktop shell client: $WESTON_SHELL_CLIENT])
+AC_DEFINE_UNQUOTED([WESTON_SHELL_CLIENT], ["$WESTON_SHELL_CLIENT"],
+ [The default desktop shell client to load.])
+
+AC_ARG_ENABLE(demo-clients-install,
+ AS_HELP_STRING([--enable-demo-clients-install],
+ [Install demo clients built with weston]),,
+ enable_demo_clients_install=no)
+AM_CONDITIONAL(INSTALL_DEMO_CLIENTS, [test "x$enable_demo_clients_install" = "xyes"])
PKG_CHECK_MODULES(LCMS, lcms2,
[have_lcms=yes], [have_lcms=no])
@@ -443,10 +477,22 @@ if test x$wayland_scanner = x; then
AC_MSG_ERROR([wayland-scanner is needed to compile weston])
fi
+PKG_CHECK_MODULES(WAYLAND_SCANNER, wayland-scanner)
+AC_PATH_PROG(XMLLINT, xmllint)
+AC_ARG_WITH([dtddir],
+ AS_HELP_STRING([--with-dtddir],
+ [Directory containing the Wayland
+ protocol DTD @<:@default=from pkgconfig@:>@]),
+ [dtddir="$withval"],
+ [dtddir=$($PKG_CONFIG --variable=pkgdatadir wayland-scanner)])
+AC_SUBST([dtddir])
+AM_CONDITIONAL([HAVE_XMLLINT], [test "x$XMLLINT" != "x" -a "x$dtddir" != "x"])
+
AC_CONFIG_FILES([Makefile
shared/Makefile
src/Makefile
- src/xwayland/Makefile
+ xwayland/Makefile
+ desktop-shell/Makefile
src/version.h
src/weston.pc
clients/Makefile
@@ -464,13 +510,14 @@ AC_MSG_RESULT([
Cairo Renderer ${with_cairo}
EGL ${enable_egl}
libxkbcommon ${enable_xkbcommon}
+ xcb_xkb ${have_xcb_xkb}
XWayland ${enable_xwayland}
+ dbus ${enable_dbus}
Build wcap utility ${enable_wcap_tools}
- Build Tablet Shell ${enable_tablet_shell}
weston-launch utility ${enable_weston_launch}
- weston-launch systemd support ${have_systemd_login}
+ systemd-login support ${have_systemd_login}
DRM Compositor ${enable_drm_compositor}
X11 Compositor ${enable_x11_compositor}
@@ -487,7 +534,7 @@ AC_MSG_RESULT([
Build Simple Clients ${enable_simple_clients}
Build Simple EGL Clients ${enable_simple_egl_clients}
- Install Demo Clients ${enable_demo_clients}
+ Install Demo Clients ${enable_demo_clients_install}
Colord Support ${have_colord}
GLU Support ${have_glu}
diff --git a/desktop-shell/.gitignore b/desktop-shell/.gitignore
new file mode 100644
index 00000000..ff42e5fe
--- /dev/null
+++ b/desktop-shell/.gitignore
@@ -0,0 +1,4 @@
+desktop-shell-protocol.c
+desktop-shell-server-protocol.h
+xdg-shell-protocol.c
+xdg-shell-server-protocol.h
diff --git a/desktop-shell/Makefile.am b/desktop-shell/Makefile.am
new file mode 100644
index 00000000..fef85f2e
--- /dev/null
+++ b/desktop-shell/Makefile.am
@@ -0,0 +1,39 @@
+moduledir = $(libdir)/weston
+module_LTLIBRARIES = $(desktop_shell)
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/shared \
+ -I$(top_srcdir)/src \
+ -I$(top_builddir)/src \
+ -DDATADIR='"$(datadir)"' \
+ -DMODULEDIR='"$(moduledir)"' \
+ -DLIBEXECDIR='"$(libexecdir)"' \
+ -DIN_WESTON
+
+if ENABLE_DESKTOP_SHELL
+desktop_shell = desktop-shell.la
+desktop_shell_la_LDFLAGS = -module -avoid-version
+desktop_shell_la_LIBADD = $(COMPOSITOR_LIBS) \
+ ../shared/libshared.la
+desktop_shell_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
+desktop_shell_la_SOURCES = \
+ shell.h \
+ shell.c \
+ exposay.c \
+ input-panel.c \
+ desktop-shell-protocol.c \
+ desktop-shell-server-protocol.h \
+ xdg-shell-protocol.c \
+ xdg-shell-server-protocol.h
+endif
+
+BUILT_SOURCES = \
+ desktop-shell-protocol.c \
+ desktop-shell-server-protocol.h \
+ xdg-shell-protocol.c \
+ xdg-shell-server-protocol.h
+
+CLEANFILES = $(BUILT_SOURCES)
+
+wayland_protocoldir = $(top_srcdir)/protocol
+include $(top_srcdir)/wayland-scanner.mk
diff --git a/desktop-shell/exposay.c b/desktop-shell/exposay.c
new file mode 100644
index 00000000..01bf0b13
--- /dev/null
+++ b/desktop-shell/exposay.c
@@ -0,0 +1,609 @@
+/*
+ * Copyright © 2010-2012 Intel Corporation
+ * Copyright © 2011-2012 Collabora, Ltd.
+ * Copyright © 2013 Raspberry Pi Foundation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <linux/input.h>
+
+#include "shell.h"
+
+struct exposay_surface {
+ struct desktop_shell *shell;
+ struct weston_surface *surface;
+ struct weston_view *view;
+ struct wl_list link;
+
+ int x;
+ int y;
+ int width;
+ int height;
+ double scale;
+
+ int row;
+ int column;
+
+ /* The animations only apply a transformation for their own lifetime,
+ * and don't have an option to indefinitely maintain the
+ * transformation in a steady state - so, we apply our own once the
+ * animation has finished. */
+ struct weston_transform transform;
+};
+
+static void exposay_set_state(struct desktop_shell *shell,
+ enum exposay_target_state state,
+ struct weston_seat *seat);
+static void exposay_check_state(struct desktop_shell *shell);
+
+static void
+exposay_in_flight_inc(struct desktop_shell *shell)
+{
+ shell->exposay.in_flight++;
+}
+
+static void
+exposay_in_flight_dec(struct desktop_shell *shell)
+{
+ if (--shell->exposay.in_flight > 0)
+ return;
+
+ exposay_check_state(shell);
+}
+
+static void
+exposay_animate_in_done(struct weston_view_animation *animation, void *data)
+{
+ struct exposay_surface *esurface = data;
+
+ wl_list_insert(&esurface->view->geometry.transformation_list,
+ &esurface->transform.link);
+ weston_matrix_init(&esurface->transform.matrix);
+ weston_matrix_scale(&esurface->transform.matrix,
+ esurface->scale, esurface->scale, 1.0f);
+ weston_matrix_translate(&esurface->transform.matrix,
+ esurface->x - esurface->view->geometry.x,
+ esurface->y - esurface->view->geometry.y,
+ 0);
+
+ weston_view_geometry_dirty(esurface->view);
+ weston_compositor_schedule_repaint(esurface->view->surface->compositor);
+
+ exposay_in_flight_dec(esurface->shell);
+}
+
+static void
+exposay_animate_in(struct exposay_surface *esurface)
+{
+ exposay_in_flight_inc(esurface->shell);
+
+ weston_move_scale_run(esurface->view,
+ esurface->x - esurface->view->geometry.x,
+ esurface->y - esurface->view->geometry.y,
+ 1.0, esurface->scale, 0,
+ exposay_animate_in_done, esurface);
+}
+
+static void
+exposay_animate_out_done(struct weston_view_animation *animation, void *data)
+{
+ struct exposay_surface *esurface = data;
+ struct desktop_shell *shell = esurface->shell;
+
+ wl_list_remove(&esurface->link);
+ free(esurface);
+
+ exposay_in_flight_dec(shell);
+}
+
+static void
+exposay_animate_out(struct exposay_surface *esurface)
+{
+ exposay_in_flight_inc(esurface->shell);
+
+ /* Remove the static transformation set up by
+ * exposay_transform_in_done(). */
+ wl_list_remove(&esurface->transform.link);
+ weston_view_geometry_dirty(esurface->view);
+
+ weston_move_scale_run(esurface->view,
+ esurface->x - esurface->view->geometry.x,
+ esurface->y - esurface->view->geometry.y,
+ 1.0, esurface->scale, 1,
+ exposay_animate_out_done, esurface);
+}
+
+static void
+exposay_highlight_surface(struct desktop_shell *shell,
+ struct exposay_surface *esurface)
+{
+ struct weston_view *view = NULL;
+
+ if (esurface) {
+ shell->exposay.row_current = esurface->row;
+ shell->exposay.column_current = esurface->column;
+ view = esurface->view;
+ }
+
+ activate(shell, view->surface, shell->exposay.seat);
+ shell->exposay.focus_current = view;
+}
+
+static int
+exposay_is_animating(struct desktop_shell *shell)
+{
+ if (shell->exposay.state_cur == EXPOSAY_LAYOUT_INACTIVE ||
+ shell->exposay.state_cur == EXPOSAY_LAYOUT_OVERVIEW)
+ return 0;
+
+ return (shell->exposay.in_flight > 0);
+}
+
+static void
+exposay_pick(struct desktop_shell *shell, int x, int y)
+{
+ struct exposay_surface *esurface;
+
+ if (exposay_is_animating(shell))
+ return;
+
+ wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
+ if (x < esurface->x || x > esurface->x + esurface->width)
+ continue;
+ if (y < esurface->y || y > esurface->y + esurface->height)
+ continue;
+
+ exposay_highlight_surface(shell, esurface);
+ return;
+ }
+}
+
+/* Pretty lame layout for now; just tries to make a square. Should take
+ * aspect ratio into account really. Also needs to be notified of surface
+ * addition and removal and adjust layout/animate accordingly. */
+static enum exposay_layout_state
+exposay_layout(struct desktop_shell *shell)
+{
+ struct workspace *workspace = shell->exposay.workspace;
+ struct weston_compositor *compositor = shell->compositor;
+ struct weston_output *output = get_default_output(compositor);
+ struct weston_view *view;
+ struct exposay_surface *esurface, *highlight = NULL;
+ int w, h;
+ int i;
+ int last_row_removed = 0;
+
+ wl_list_init(&shell->exposay.surface_list);
+
+ shell->exposay.num_surfaces = 0;
+ wl_list_for_each(view, &workspace->layer.view_list, layer_link) {
+ if (!get_shell_surface(view->surface))
+ continue;
+ shell->exposay.num_surfaces++;
+ }
+
+ if (shell->exposay.num_surfaces == 0) {
+ shell->exposay.grid_size = 0;
+ shell->exposay.hpadding_outer = 0;
+ shell->exposay.vpadding_outer = 0;
+ shell->exposay.padding_inner = 0;
+ shell->exposay.surface_size = 0;
+ return EXPOSAY_LAYOUT_OVERVIEW;
+ }
+
+ /* Lay the grid out as square as possible, losing surfaces from the
+ * bottom row if required. Start with fixed padding of a 10% margin
+ * around the outside and 80px internal padding between surfaces, and
+ * maximise the area made available to surfaces after this, but only
+ * to a maximum of 1/3rd the total output size.
+ *
+ * If we can't make a square grid, add one extra row at the bottom
+ * which will have a smaller number of columns.
+ *
+ * XXX: Surely there has to be a better way to express this maths,
+ * right?!
+ */
+ shell->exposay.grid_size = floor(sqrtf(shell->exposay.num_surfaces));
+ if (pow(shell->exposay.grid_size, 2) != shell->exposay.num_surfaces)
+ shell->exposay.grid_size++;
+ last_row_removed = pow(shell->exposay.grid_size, 2) - shell->exposay.num_surfaces;
+
+ shell->exposay.hpadding_outer = (output->width / 10);
+ shell->exposay.vpadding_outer = (output->height / 10);
+ shell->exposay.padding_inner = 80;
+
+ w = output->width - (shell->exposay.hpadding_outer * 2);
+ w -= shell->exposay.padding_inner * (shell->exposay.grid_size - 1);
+ w /= shell->exposay.grid_size;
+
+ h = output->height - (shell->exposay.vpadding_outer * 2);
+ h -= shell->exposay.padding_inner * (shell->exposay.grid_size - 1);
+ h /= shell->exposay.grid_size;
+
+ shell->exposay.surface_size = (w < h) ? w : h;
+ if (shell->exposay.surface_size > (output->width / 2))
+ shell->exposay.surface_size = output->width / 2;
+ if (shell->exposay.surface_size > (output->height / 2))
+ shell->exposay.surface_size = output->height / 2;
+
+ i = 0;
+ wl_list_for_each(view, &workspace->layer.view_list, layer_link) {
+ int pad;
+
+ pad = shell->exposay.surface_size + shell->exposay.padding_inner;
+
+ if (!get_shell_surface(view->surface))
+ continue;
+
+ esurface = malloc(sizeof(*esurface));
+ if (!esurface) {
+ exposay_set_state(shell, EXPOSAY_TARGET_CANCEL,
+ shell->exposay.seat);
+ break;
+ }
+
+ wl_list_insert(&shell->exposay.surface_list, &esurface->link);
+ esurface->shell = shell;
+ esurface->view = view;
+
+ esurface->row = i / shell->exposay.grid_size;
+ esurface->column = i % shell->exposay.grid_size;
+
+ esurface->x = shell->exposay.hpadding_outer;
+ esurface->x += pad * esurface->column;
+ esurface->y = shell->exposay.vpadding_outer;
+ esurface->y += pad * esurface->row;
+
+ if (esurface->row == shell->exposay.grid_size - 1)
+ esurface->x += (shell->exposay.surface_size + shell->exposay.padding_inner) * last_row_removed / 2;
+
+ if (view->surface->width > view->surface->height)
+ esurface->scale = shell->exposay.surface_size / (float) view->surface->width;
+ else
+ esurface->scale = shell->exposay.surface_size / (float) view->surface->height;
+ esurface->width = view->surface->width * esurface->scale;
+ esurface->height = view->surface->height * esurface->scale;
+
+ if (shell->exposay.focus_current == esurface->view)
+ highlight = esurface;
+
+ set_alpha_if_fullscreen(get_shell_surface(view->surface));
+
+ exposay_animate_in(esurface);
+
+ i++;
+ }
+
+ if (highlight)
+ exposay_highlight_surface(shell, highlight);
+
+ weston_compositor_schedule_repaint(shell->compositor);
+
+ return EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW;
+}
+
+static void
+exposay_focus(struct weston_pointer_grab *grab)
+{
+}
+
+static void
+exposay_motion(struct weston_pointer_grab *grab, uint32_t time,
+ wl_fixed_t x, wl_fixed_t y)
+{
+ struct desktop_shell *shell =
+ container_of(grab, struct desktop_shell, exposay.grab_ptr);
+
+ weston_pointer_move(grab->pointer, x, y);
+
+ exposay_pick(shell,
+ wl_fixed_to_int(grab->pointer->x),
+ wl_fixed_to_int(grab->pointer->y));
+}
+
+static void
+exposay_button(struct weston_pointer_grab *grab, uint32_t time, uint32_t button,
+ uint32_t state_w)
+{
+ struct desktop_shell *shell =
+ container_of(grab, struct desktop_shell, exposay.grab_ptr);
+ struct weston_seat *seat = grab->pointer->seat;
+ enum wl_pointer_button_state state = state_w;
+
+ if (button != BTN_LEFT)
+ return;
+
+ /* Store the surface we clicked on, and don't do anything if we end up
+ * releasing on a different surface. */
+ if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
+ shell->exposay.clicked = shell->exposay.focus_current;
+ return;
+ }
+
+ if (shell->exposay.focus_current == shell->exposay.clicked)
+ exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);
+ else
+ shell->exposay.clicked = NULL;
+}
+
+static void
+exposay_pointer_grab_cancel(struct weston_pointer_grab *grab)
+{
+ struct desktop_shell *shell =
+ container_of(grab, struct desktop_shell, exposay.grab_ptr);
+
+ exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, shell->exposay.seat);
+}
+
+static const struct weston_pointer_grab_interface exposay_ptr_grab = {
+ exposay_focus,
+ exposay_motion,
+ exposay_button,
+ exposay_pointer_grab_cancel,
+};
+
+static int
+exposay_maybe_move(struct desktop_shell *shell, int row, int column)
+{
+ struct exposay_surface *esurface;
+
+ wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
+ if (esurface->row != row || esurface->column != column)
+ continue;
+
+ exposay_highlight_surface(shell, esurface);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void
+exposay_key(struct weston_keyboard_grab *grab, uint32_t time, uint32_t key,
+ uint32_t state_w)
+{
+ struct weston_seat *seat = grab->keyboard->seat;
+ struct desktop_shell *shell =
+ container_of(grab, struct desktop_shell, exposay.grab_kbd);
+ enum wl_keyboard_key_state state = state_w;
+
+ if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
+ return;
+
+ switch (key) {
+ case KEY_ESC:
+ exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);
+ break;
+ case KEY_ENTER:
+ exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);
+ break;
+ case KEY_UP:
+ exposay_maybe_move(shell, shell->exposay.row_current - 1,
+ shell->exposay.column_current);
+ break;
+ case KEY_DOWN:
+ /* Special case for trying to move to the bottom row when it
+ * has fewer items than all the others. */
+ if (!exposay_maybe_move(shell, shell->exposay.row_current + 1,
+ shell->exposay.column_current) &&
+ shell->exposay.row_current < (shell->exposay.grid_size - 1)) {
+ exposay_maybe_move(shell, shell->exposay.row_current + 1,
+ (shell->exposay.num_surfaces %
+ shell->exposay.grid_size) - 1);
+ }
+ break;
+ case KEY_LEFT:
+ exposay_maybe_move(shell, shell->exposay.row_current,
+ shell->exposay.column_current - 1);
+ break;
+ case KEY_RIGHT:
+ exposay_maybe_move(shell, shell->exposay.row_current,
+ shell->exposay.column_current + 1);
+ break;
+ case KEY_TAB:
+ /* Try to move right, then down (and to the leftmost column),
+ * then if all else fails, to the top left. */
+ if (!exposay_maybe_move(shell, shell->exposay.row_current,
+ shell->exposay.column_current + 1) &&
+ !exposay_maybe_move(shell, shell->exposay.row_current + 1, 0))
+ exposay_maybe_move(shell, 0, 0);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+exposay_modifier(struct weston_keyboard_grab *grab, uint32_t serial,
+ uint32_t mods_depressed, uint32_t mods_latched,
+ uint32_t mods_locked, uint32_t group)
+{
+ struct desktop_shell *shell =
+ container_of(grab, struct desktop_shell, exposay.grab_kbd);
+ struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
+
+ /* We want to know when mod has been pressed and released.
+ * FIXME: There is a problem here: if mod is pressed, then a key
+ * is pressed and released, then mod is released, we will treat that
+ * as if only mod had been pressed and released. */
+ if (seat->modifier_state) {
+ if (seat->modifier_state == shell->binding_modifier) {
+ shell->exposay.mod_pressed = true;
+ } else {
+ shell->exposay.mod_invalid = true;
+ }
+ } else {
+ if (shell->exposay.mod_pressed && !shell->exposay.mod_invalid)
+ exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);
+
+ shell->exposay.mod_invalid = false;
+ shell->exposay.mod_pressed = false;
+ }
+
+ return;
+}
+
+static void
+exposay_cancel(struct weston_keyboard_grab *grab)
+{
+ struct desktop_shell *shell =
+ container_of(grab, struct desktop_shell, exposay.grab_kbd);
+
+ exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, shell->exposay.seat);
+}
+
+static const struct weston_keyboard_grab_interface exposay_kbd_grab = {
+ exposay_key,
+ exposay_modifier,
+ exposay_cancel,
+};
+
+/**
+ * Called when the transition from overview -> inactive has completed.
+ */
+static enum exposay_layout_state
+exposay_set_inactive(struct desktop_shell *shell)
+{
+ struct weston_seat *seat = shell->exposay.seat;
+
+ weston_keyboard_end_grab(seat->keyboard);
+ weston_pointer_end_grab(seat->pointer);
+ if (seat->keyboard->input_method_resource)
+ seat->keyboard->grab = &seat->keyboard->input_method_grab;
+
+ return EXPOSAY_LAYOUT_INACTIVE;
+}
+
+/**
+ * Begins the transition from overview to inactive. */
+static enum exposay_layout_state
+exposay_transition_inactive(struct desktop_shell *shell, int switch_focus)
+{
+ struct exposay_surface *esurface;
+
+ /* Call activate() before we start the animations to avoid
+ * animating back the old state and then immediately transitioning
+ * to the new. */
+ if (switch_focus && shell->exposay.focus_current)
+ activate(shell, shell->exposay.focus_current->surface,
+ shell->exposay.seat);
+ else if (shell->exposay.focus_prev)
+ activate(shell, shell->exposay.focus_prev->surface,
+ shell->exposay.seat);
+
+ wl_list_for_each(esurface, &shell->exposay.surface_list, link)
+ exposay_animate_out(esurface);
+ weston_compositor_schedule_repaint(shell->compositor);
+
+ return EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE;
+}
+
+static enum exposay_layout_state
+exposay_transition_active(struct desktop_shell *shell)
+{
+ struct weston_seat *seat = shell->exposay.seat;
+
+ shell->exposay.workspace = get_current_workspace(shell);
+ shell->exposay.focus_prev = get_default_view (seat->keyboard->focus);
+ shell->exposay.focus_current = get_default_view (seat->keyboard->focus);
+ shell->exposay.clicked = NULL;
+ wl_list_init(&shell->exposay.surface_list);
+
+ lower_fullscreen_layer(shell);
+ shell->exposay.grab_kbd.interface = &exposay_kbd_grab;
+ weston_keyboard_start_grab(seat->keyboard,
+ &shell->exposay.grab_kbd);
+ weston_keyboard_set_focus(seat->keyboard, NULL);
+
+ shell->exposay.grab_ptr.interface = &exposay_ptr_grab;
+ weston_pointer_start_grab(seat->pointer,
+ &shell->exposay.grab_ptr);
+ weston_pointer_set_focus(seat->pointer, NULL,
+ seat->pointer->x, seat->pointer->y);
+
+ return exposay_layout(shell);
+}
+
+static void
+exposay_check_state(struct desktop_shell *shell)
+{
+ enum exposay_layout_state state_new = shell->exposay.state_cur;
+ int do_switch = 0;
+
+ /* Don't do anything whilst animations are running, just store up
+ * target state changes and only act on them when the animations have
+ * completed. */
+ if (exposay_is_animating(shell))
+ return;
+
+ switch (shell->exposay.state_target) {
+ case EXPOSAY_TARGET_OVERVIEW:
+ switch (shell->exposay.state_cur) {
+ case EXPOSAY_LAYOUT_OVERVIEW:
+ goto out;
+ case EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW:
+ state_new = EXPOSAY_LAYOUT_OVERVIEW;
+ break;
+ default:
+ state_new = exposay_transition_active(shell);
+ break;
+ }
+ break;
+
+ case EXPOSAY_TARGET_SWITCH:
+ do_switch = 1; /* fallthrough */
+ case EXPOSAY_TARGET_CANCEL:
+ switch (shell->exposay.state_cur) {
+ case EXPOSAY_LAYOUT_INACTIVE:
+ goto out;
+ case EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE:
+ state_new = exposay_set_inactive(shell);
+ break;
+ default:
+ state_new = exposay_transition_inactive(shell, do_switch);
+ break;
+ }
+
+ break;
+ }
+
+out:
+ shell->exposay.state_cur = state_new;
+}
+
+static void
+exposay_set_state(struct desktop_shell *shell, enum exposay_target_state state,
+ struct weston_seat *seat)
+{
+ shell->exposay.state_target = state;
+ shell->exposay.seat = seat;
+ exposay_check_state(shell);
+}
+
+void
+exposay_binding(struct weston_seat *seat, enum weston_keyboard_modifier modifier,
+ void *data)
+{
+ struct desktop_shell *shell = data;
+
+ exposay_set_state(shell, EXPOSAY_TARGET_OVERVIEW, seat);
+}
diff --git a/desktop-shell/input-panel.c b/desktop-shell/input-panel.c
new file mode 100644
index 00000000..267b3ef0
--- /dev/null
+++ b/desktop-shell/input-panel.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright © 2010-2012 Intel Corporation
+ * Copyright © 2011-2012 Collabora, Ltd.
+ * Copyright © 2013 Raspberry Pi Foundation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "shell.h"
+#include "desktop-shell-server-protocol.h"
+#include "input-method-server-protocol.h"
+
+struct input_panel_surface {
+ struct wl_resource *resource;
+ struct wl_signal destroy_signal;
+
+ struct desktop_shell *shell;
+
+ struct wl_list link;
+ struct weston_surface *surface;
+ struct weston_view *view;
+ struct wl_listener surface_destroy_listener;
+
+ struct weston_output *output;
+ uint32_t panel;
+};
+
+static void
+show_input_panels(struct wl_listener *listener, void *data)
+{
+ struct desktop_shell *shell =
+ container_of(listener, struct desktop_shell,
+ show_input_panel_listener);
+ struct input_panel_surface *ipsurf, *next;
+
+ shell->text_input.surface = (struct weston_surface*)data;
+
+ if (shell->showing_input_panels)
+ return;
+
+ shell->showing_input_panels = true;
+
+ if (!shell->locked)
+ wl_list_insert(&shell->panel_layer.link,
+ &shell->input_panel_layer.link);
+
+ wl_list_for_each_safe(ipsurf, next,
+ &shell->input_panel.surfaces, link) {
+ if (ipsurf->surface->width == 0)
+ continue;
+ wl_list_insert(&shell->input_panel_layer.view_list,
+ &ipsurf->view->layer_link);
+ weston_view_geometry_dirty(ipsurf->view);
+ weston_view_update_transform(ipsurf->view);
+ weston_surface_damage(ipsurf->surface);
+ weston_slide_run(ipsurf->view, ipsurf->surface->height * 0.9,
+ 0, NULL, NULL);
+ }
+}
+
+static void
+hide_input_panels(struct wl_listener *listener, void *data)
+{
+ struct desktop_shell *shell =
+ container_of(listener, struct desktop_shell,
+ hide_input_panel_listener);
+ struct weston_view *view, *next;
+
+ if (!shell->showing_input_panels)
+ return;
+
+ shell->showing_input_panels = false;
+
+ if (!shell->locked)
+ wl_list_remove(&shell->input_panel_layer.link);
+
+ wl_list_for_each_safe(view, next,
+ &shell->input_panel_layer.view_list, layer_link)
+ weston_view_unmap(view);
+}
+
+static void
+update_input_panels(struct wl_listener *listener, void *data)
+{
+ struct desktop_shell *shell =
+ container_of(listener, struct desktop_shell,
+ update_input_panel_listener);
+
+ memcpy(&shell->text_input.cursor_rectangle, data, sizeof(pixman_box32_t));
+}
+
+static void
+input_panel_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
+{
+ struct input_panel_surface *ip_surface = surface->configure_private;
+ struct desktop_shell *shell = ip_surface->shell;
+ float x, y;
+
+ if (surface->width == 0)
+ return;
+
+ if (ip_surface->panel) {
+ x = get_default_view(shell->text_input.surface)->geometry.x + shell->text_input.cursor_rectangle.x2;
+ y = get_default_view(shell->text_input.surface)->geometry.y + shell->text_input.cursor_rectangle.y2;
+ } else {
+ x = ip_surface->output->x + (ip_surface->output->width - surface->width) / 2;
+ y = ip_surface->output->y + ip_surface->output->height - surface->height;
+ }
+
+ weston_view_set_position(ip_surface->view, x, y);
+
+ if (!weston_surface_is_mapped(surface) && shell->showing_input_panels) {
+ wl_list_insert(&shell->input_panel_layer.view_list,
+ &ip_surface->view->layer_link);
+ weston_view_update_transform(ip_surface->view);
+ weston_surface_damage(surface);
+ weston_slide_run(ip_surface->view, ip_surface->view->surface->height * 0.9, 0, NULL, NULL);
+ }
+}
+
+static void
+destroy_input_panel_surface(struct input_panel_surface *input_panel_surface)
+{
+ wl_signal_emit(&input_panel_surface->destroy_signal, input_panel_surface);
+
+ wl_list_remove(&input_panel_surface->surface_destroy_listener.link);
+ wl_list_remove(&input_panel_surface->link);
+
+ input_panel_surface->surface->configure = NULL;
+ weston_view_destroy(input_panel_surface->view);
+
+ free(input_panel_surface);
+}
+
+static struct input_panel_surface *
+get_input_panel_surface(struct weston_surface *surface)
+{
+ if (surface->configure == input_panel_configure) {
+ return surface->configure_private;
+ } else {
+ return NULL;
+ }
+}
+
+static void
+input_panel_handle_surface_destroy(struct wl_listener *listener, void *data)
+{
+ struct input_panel_surface *ipsurface = container_of(listener,
+ struct input_panel_surface,
+ surface_destroy_listener);
+
+ if (ipsurface->resource) {
+ wl_resource_destroy(ipsurface->resource);
+ } else {
+ destroy_input_panel_surface(ipsurface);
+ }
+}
+
+static struct input_panel_surface *
+create_input_panel_surface(struct desktop_shell *shell,
+ struct weston_surface *surface)
+{
+ struct input_panel_surface *input_panel_surface;
+
+ input_panel_surface = calloc(1, sizeof *input_panel_surface);
+ if (!input_panel_surface)
+ return NULL;
+
+ surface->configure = input_panel_configure;
+ surface->configure_private = input_panel_surface;
+
+ input_panel_surface->shell = shell;
+
+ input_panel_surface->surface = surface;
+ input_panel_surface->view = weston_view_create(surface);
+
+ wl_signal_init(&input_panel_surface->destroy_signal);
+ input_panel_surface->surface_destroy_listener.notify = input_panel_handle_surface_destroy;
+ wl_signal_add(&surface->destroy_signal,
+ &input_panel_surface->surface_destroy_listener);
+
+ wl_list_init(&input_panel_surface->link);
+
+ return input_panel_surface;
+}
+
+static void
+input_panel_surface_set_toplevel(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *output_resource,
+ uint32_t position)
+{
+ struct input_panel_surface *input_panel_surface =
+ wl_resource_get_user_data(resource);
+ struct desktop_shell *shell = input_panel_surface->shell;
+
+ wl_list_insert(&shell->input_panel.surfaces,
+ &input_panel_surface->link);
+
+ input_panel_surface->output = wl_resource_get_user_data(output_resource);
+ input_panel_surface->panel = 0;
+}
+
+static void
+input_panel_surface_set_overlay_panel(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct input_panel_surface *input_panel_surface =
+ wl_resource_get_user_data(resource);
+ struct desktop_shell *shell = input_panel_surface->shell;
+
+ wl_list_insert(&shell->input_panel.surfaces,
+ &input_panel_surface->link);
+
+ input_panel_surface->panel = 1;
+}
+
+static const struct wl_input_panel_surface_interface input_panel_surface_implementation = {
+ input_panel_surface_set_toplevel,
+ input_panel_surface_set_overlay_panel
+};
+
+static void
+destroy_input_panel_surface_resource(struct wl_resource *resource)
+{
+ struct input_panel_surface *ipsurf =
+ wl_resource_get_user_data(resource);
+
+ destroy_input_panel_surface(ipsurf);
+}
+
+static void
+input_panel_get_input_panel_surface(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *surface_resource)
+{
+ struct weston_surface *surface =
+ wl_resource_get_user_data(surface_resource);
+ struct desktop_shell *shell = wl_resource_get_user_data(resource);
+ struct input_panel_surface *ipsurf;
+
+ if (get_input_panel_surface(surface)) {
+ wl_resource_post_error(surface_resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "wl_input_panel::get_input_panel_surface already requested");
+ return;
+ }
+
+ ipsurf = create_input_panel_surface(shell, surface);
+ if (!ipsurf) {
+ wl_resource_post_error(surface_resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "surface->configure already set");
+ return;
+ }
+
+ ipsurf->resource =
+ wl_resource_create(client,
+ &wl_input_panel_surface_interface, 1, id);
+ wl_resource_set_implementation(ipsurf->resource,
+ &input_panel_surface_implementation,
+ ipsurf,
+ destroy_input_panel_surface_resource);
+}
+
+static const struct wl_input_panel_interface input_panel_implementation = {
+ input_panel_get_input_panel_surface
+};
+
+static void
+unbind_input_panel(struct wl_resource *resource)
+{
+ struct desktop_shell *shell = wl_resource_get_user_data(resource);
+
+ shell->input_panel.binding = NULL;
+}
+
+static void
+bind_input_panel(struct wl_client *client,
+ void *data, uint32_t version, uint32_t id)
+{
+ struct desktop_shell *shell = data;
+ struct wl_resource *resource;
+
+ resource = wl_resource_create(client,
+ &wl_input_panel_interface, 1, id);
+
+ if (shell->input_panel.binding == NULL) {
+ wl_resource_set_implementation(resource,
+ &input_panel_implementation,
+ shell, unbind_input_panel);
+ shell->input_panel.binding = resource;
+ return;
+ }
+
+ wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "interface object already bound");
+ wl_resource_destroy(resource);
+}
+
+void
+input_panel_destroy(struct desktop_shell *shell)
+{
+ wl_list_remove(&shell->show_input_panel_listener.link);
+ wl_list_remove(&shell->hide_input_panel_listener.link);
+}
+
+int
+input_panel_setup(struct desktop_shell *shell)
+{
+ struct weston_compositor *ec = shell->compositor;
+
+ shell->show_input_panel_listener.notify = show_input_panels;
+ wl_signal_add(&ec->show_input_panel_signal,
+ &shell->show_input_panel_listener);
+ shell->hide_input_panel_listener.notify = hide_input_panels;
+ wl_signal_add(&ec->hide_input_panel_signal,
+ &shell->hide_input_panel_listener);
+ shell->update_input_panel_listener.notify = update_input_panels;
+ wl_signal_add(&ec->update_input_panel_signal,
+ &shell->update_input_panel_listener);
+
+ wl_list_init(&shell->input_panel.surfaces);
+
+ if (wl_global_create(shell->compositor->wl_display,
+ &wl_input_panel_interface, 1,
+ shell, bind_input_panel) == NULL)
+ return -1;
+
+ return 0;
+}
diff --git a/src/shell.c b/desktop-shell/shell.c
index fa9ff544..a8c4b3ea 100644
--- a/src/shell.c
+++ b/desktop-shell/shell.c
@@ -1,6 +1,7 @@
/*
* Copyright © 2010-2012 Intel Corporation
* Copyright © 2011-2012 Collabora, Ltd.
+ * Copyright © 2013 Raspberry Pi Foundation
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
@@ -25,7 +26,6 @@
#include <stdlib.h>
#include <stdio.h>
-#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <linux/input.h>
@@ -34,26 +34,18 @@
#include <math.h>
#include <sys/types.h>
-#include "compositor.h"
+#include "shell.h"
#include "desktop-shell-server-protocol.h"
-#include "input-method-server-protocol.h"
#include "workspaces-server-protocol.h"
#include "../shared/config-parser.h"
+#include "xdg-shell-server-protocol.h"
#define DEFAULT_NUM_WORKSPACES 1
#define DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH 200
-enum animation_type {
- ANIMATION_NONE,
-
- ANIMATION_ZOOM,
- ANIMATION_FADE
-};
-
-enum fade_type {
- FADE_IN,
- FADE_OUT
-};
+#ifndef static_assert
+#define static_assert(cond, msg)
+#endif
struct focus_state {
struct weston_seat *seat;
@@ -64,114 +56,16 @@ struct focus_state {
struct wl_listener surface_destroy_listener;
};
-struct workspace {
- struct weston_layer layer;
-
- struct wl_list focus_list;
- struct wl_listener seat_destroyed_listener;
-};
-
-struct input_panel_surface {
- struct wl_resource *resource;
- struct wl_signal destroy_signal;
-
- struct desktop_shell *shell;
-
- struct wl_list link;
- struct weston_surface *surface;
- struct wl_listener surface_destroy_listener;
-
- struct weston_output *output;
- uint32_t panel;
-};
-
-struct desktop_shell {
- struct weston_compositor *compositor;
-
- struct wl_listener idle_listener;
- struct wl_listener wake_listener;
- struct wl_listener destroy_listener;
- struct wl_listener show_input_panel_listener;
- struct wl_listener hide_input_panel_listener;
- struct wl_listener update_input_panel_listener;
-
- struct weston_layer fullscreen_layer;
- struct weston_layer panel_layer;
- struct weston_layer background_layer;
- struct weston_layer lock_layer;
- struct weston_layer input_panel_layer;
-
- struct wl_listener pointer_focus_listener;
- struct weston_surface *grab_surface;
-
- struct {
- struct weston_process process;
- struct wl_client *client;
- struct wl_resource *desktop_shell;
-
- unsigned deathcount;
- uint32_t deathstamp;
- } child;
-
- bool locked;
- bool showing_input_panels;
- bool prepare_event_sent;
-
- struct {
- struct weston_surface *surface;
- pixman_box32_t cursor_rectangle;
- } text_input;
-
- struct weston_surface *lock_surface;
- struct wl_listener lock_surface_listener;
-
- struct {
- struct wl_array array;
- unsigned int current;
- unsigned int num;
-
- struct wl_list client_list;
-
- struct weston_animation animation;
- struct wl_list anim_sticky_list;
- int anim_dir;
- uint32_t anim_timestamp;
- double anim_current;
- struct workspace *anim_from;
- struct workspace *anim_to;
- } workspaces;
-
- struct {
- char *path;
- int duration;
- struct wl_resource *binding;
- struct weston_process process;
- struct wl_event_source *timer;
- } screensaver;
-
- struct {
- struct wl_resource *binding;
- struct wl_list surfaces;
- } input_panel;
-
- struct {
- struct weston_surface *surface;
- struct weston_surface_animation *animation;
- enum fade_type type;
- struct wl_event_source *startup_timer;
- } fade;
-
- uint32_t binding_modifier;
- enum animation_type win_animation_type;
- enum animation_type startup_animation_type;
+struct shell_output {
+ struct desktop_shell *shell;
+ struct weston_output *output;
+ struct wl_listener destroy_listener;
+ struct wl_list link;
};
enum shell_surface_type {
SHELL_SURFACE_NONE,
SHELL_SURFACE_TOPLEVEL,
- SHELL_SURFACE_TRANSIENT,
- SHELL_SURFACE_FULLSCREEN,
- SHELL_SURFACE_MAXIMIZED,
SHELL_SURFACE_POPUP,
SHELL_SURFACE_XWAYLAND
};
@@ -181,21 +75,65 @@ struct ping_timer {
uint32_t serial;
};
+/*
+ * Surface stacking and ordering.
+ *
+ * This is handled using several linked lists of surfaces, organised into
+ * ‘layers’. The layers are ordered, and each of the surfaces in one layer are
+ * above all of the surfaces in the layer below. The set of layers is static and
+ * in the following order (top-most first):
+ * • Lock layer (only ever displayed on its own)
+ * • Cursor layer
+ * • Fullscreen layer
+ * • Panel layer
+ * • Input panel layer
+ * • Workspace layers
+ * • Background layer
+ *
+ * The list of layers may be manipulated to remove whole layers of surfaces from
+ * display. For example, when locking the screen, all layers except the lock
+ * layer are removed.
+ *
+ * A surface’s layer is modified on configuring the surface, in
+ * set_surface_type() (which is only called when the surface’s type change is
+ * _committed_). If a surface’s type changes (e.g. when making a window
+ * fullscreen) its layer changes too.
+ *
+ * In order to allow popup and transient surfaces to be correctly stacked above
+ * their parent surfaces, each surface tracks both its parent surface, and a
+ * linked list of its children. When a surface’s layer is updated, so are the
+ * layers of its children. Note that child surfaces are *not* the same as
+ * subsurfaces — child/parent surfaces are purely for maintaining stacking
+ * order.
+ *
+ * The children_link list of siblings of a surface (i.e. those surfaces which
+ * have the same parent) only contains weston_surfaces which have a
+ * shell_surface. Stacking is not implemented for non-shell_surface
+ * weston_surfaces. This means that the following implication does *not* hold:
+ * (shsurf->parent != NULL) ⇒ !wl_list_is_empty(shsurf->children_link)
+ */
+
struct shell_surface {
struct wl_resource *resource;
struct wl_signal destroy_signal;
struct weston_surface *surface;
+ struct weston_view *view;
+ int32_t last_width, last_height;
struct wl_listener surface_destroy_listener;
struct weston_surface *parent;
+ struct wl_list children_list; /* child surfaces of this one */
+ struct wl_list children_link; /* sibling surfaces of this one */
struct desktop_shell *shell;
- enum shell_surface_type type, next_type;
+ enum shell_surface_type type;
char *title, *class;
int32_t saved_x, saved_y;
+ int32_t saved_width, saved_height;
bool saved_position_valid;
+ bool saved_size_valid;
bool saved_rotation_valid;
- int unresponsive;
+ int unresponsive, grabbed;
struct {
struct weston_transform transform;
@@ -218,7 +156,7 @@ struct shell_surface {
enum wl_shell_surface_fullscreen_method type;
struct weston_transform transform; /* matrix from x, y */
uint32_t framerate;
- struct weston_surface *black_surface;
+ struct weston_view *black_view;
} fullscreen;
struct ping_timer *ping_timer;
@@ -227,9 +165,17 @@ struct shell_surface {
struct weston_output *fullscreen_output;
struct weston_output *output;
+ struct weston_output *recommended_output;
struct wl_list link;
const struct weston_shell_client *client;
+
+ struct {
+ bool maximized;
+ bool fullscreen;
+ bool relative;
+ } state, next_state; /* surface states */
+ bool state_changed;
};
struct shell_grab {
@@ -276,15 +222,12 @@ struct shell_seat {
} popup_grab;
};
-static void
-activate(struct desktop_shell *shell, struct weston_surface *es,
- struct weston_seat *seat);
-
-static struct workspace *
-get_current_workspace(struct desktop_shell *shell);
-
-static struct shell_surface *
-get_shell_surface(struct weston_surface *surface);
+void
+set_alpha_if_fullscreen(struct shell_surface *shsurf)
+{
+ if (shsurf && shsurf->state.fullscreen)
+ shsurf->fullscreen.black_view->alpha = 0.25;
+}
static struct desktop_shell *
shell_surface_get_shell(struct shell_surface *shsurf);
@@ -295,21 +238,40 @@ surface_rotate(struct shell_surface *surface, struct weston_seat *seat);
static void
shell_fade_startup(struct desktop_shell *shell);
+static struct shell_seat *
+get_shell_seat(struct weston_seat *seat);
+
+static void
+shell_surface_update_child_surface_layers(struct shell_surface *shsurf);
+
+static bool
+shell_surface_is_wl_shell_surface(struct shell_surface *shsurf);
+
+static bool
+shell_surface_is_xdg_surface(struct shell_surface *shsurf);
+
+static bool
+shell_surface_is_xdg_popup(struct shell_surface *shsurf);
+
+static void
+shell_surface_set_parent(struct shell_surface *shsurf,
+ struct weston_surface *parent);
+
static bool
shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
{
struct desktop_shell *shell;
- struct weston_surface *top_fs_es;
+ struct weston_view *top_fs_ev;
shell = shell_surface_get_shell(shsurf);
- if (wl_list_empty(&shell->fullscreen_layer.surface_list))
+ if (wl_list_empty(&shell->fullscreen_layer.view_list))
return false;
- top_fs_es = container_of(shell->fullscreen_layer.surface_list.next,
- struct weston_surface,
+ top_fs_ev = container_of(shell->fullscreen_layer.view_list.next,
+ struct weston_view,
layer_link);
- return (shsurf == get_shell_surface(top_fs_es));
+ return (shsurf == get_shell_surface(top_fs_ev->surface));
}
static void
@@ -323,6 +285,26 @@ destroy_shell_grab_shsurf(struct wl_listener *listener, void *data)
grab->shsurf = NULL;
}
+struct weston_view *
+get_default_view(struct weston_surface *surface)
+{
+ struct shell_surface *shsurf;
+ struct weston_view *view;
+
+ if (!surface || wl_list_empty(&surface->views))
+ return NULL;
+
+ shsurf = get_shell_surface(surface);
+ if (shsurf)
+ return shsurf->view;
+
+ wl_list_for_each(view, &surface->views, surface_link)
+ if (weston_view_is_mapped(view))
+ return view;
+
+ return container_of(surface->views.next, struct weston_view, surface_link);
+}
+
static void
popup_grab_end(struct weston_pointer *pointer);
@@ -343,11 +325,13 @@ shell_grab_start(struct shell_grab *grab,
wl_signal_add(&shsurf->destroy_signal,
&grab->shsurf_destroy_listener);
+ shsurf->grabbed = 1;
weston_pointer_start_grab(pointer, &grab->grab);
if (shell->child.desktop_shell) {
desktop_shell_send_grab_cursor(shell->child.desktop_shell,
cursor);
- weston_pointer_set_focus(pointer, shell->grab_surface,
+ weston_pointer_set_focus(pointer,
+ get_default_view(shell->grab_surface),
wl_fixed_from_int(0),
wl_fixed_from_int(0));
}
@@ -356,8 +340,10 @@ shell_grab_start(struct shell_grab *grab,
static void
shell_grab_end(struct shell_grab *grab)
{
- if (grab->shsurf)
+ if (grab->shsurf) {
wl_list_remove(&grab->shsurf_destroy_listener.link);
+ grab->shsurf->grabbed = 0;
+ }
weston_pointer_end_grab(grab->grab.pointer);
}
@@ -377,23 +363,27 @@ shell_touch_grab_start(struct shell_touch_grab *grab,
&grab->shsurf_destroy_listener);
grab->touch = touch;
+ shsurf->grabbed = 1;
weston_touch_start_grab(touch, &grab->grab);
if (shell->child.desktop_shell)
- weston_touch_set_focus(touch->seat, shell->grab_surface);
+ weston_touch_set_focus(touch->seat,
+ get_default_view(shell->grab_surface));
}
static void
shell_touch_grab_end(struct shell_touch_grab *grab)
{
- if (grab->shsurf)
+ if (grab->shsurf) {
wl_list_remove(&grab->shsurf_destroy_listener.link);
+ grab->shsurf->grabbed = 0;
+ }
weston_touch_end_grab(grab->touch);
}
static void
-center_on_output(struct weston_surface *surface,
+center_on_output(struct weston_view *view,
struct weston_output *output);
static enum weston_keyboard_modifier
@@ -419,6 +409,8 @@ get_animation_type(char *animation)
return ANIMATION_ZOOM;
else if (!strcmp("fade", animation))
return ANIMATION_FADE;
+ else if (!strcmp("dim-layer", animation))
+ return ANIMATION_DIM_LAYER;
else
return ANIMATION_NONE;
}
@@ -440,6 +432,9 @@ shell_configuration(struct desktop_shell *shell)
section = weston_config_get_section(shell->compositor->config,
"shell", NULL, NULL);
weston_config_section_get_string(section,
+ "client", &s, LIBEXECDIR "/" WESTON_SHELL_CLIENT);
+ shell->client = s;
+ weston_config_section_get_string(section,
"binding-modifier", &s, "super");
shell->binding_modifier = get_modifier(s);
free(s);
@@ -452,12 +447,103 @@ shell_configuration(struct desktop_shell *shell)
free(s);
if (shell->startup_animation_type == ANIMATION_ZOOM)
shell->startup_animation_type = ANIMATION_NONE;
-
+ weston_config_section_get_string(section, "focus-animation", &s, "none");
+ shell->focus_animation_type = get_animation_type(s);
+ free(s);
weston_config_section_get_uint(section, "num-workspaces",
&shell->workspaces.num,
DEFAULT_NUM_WORKSPACES);
}
+struct weston_output *
+get_default_output(struct weston_compositor *compositor)
+{
+ return container_of(compositor->output_list.next,
+ struct weston_output, link);
+}
+
+
+/* no-op func for checking focus surface */
+static void
+focus_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
+{
+}
+
+static struct focus_surface *
+get_focus_surface(struct weston_surface *surface)
+{
+ if (surface->configure == focus_surface_configure)
+ return surface->configure_private;
+ else
+ return NULL;
+}
+
+static bool
+is_focus_surface (struct weston_surface *es)
+{
+ return (es->configure == focus_surface_configure);
+}
+
+static bool
+is_focus_view (struct weston_view *view)
+{
+ return is_focus_surface (view->surface);
+}
+
+static struct focus_surface *
+create_focus_surface(struct weston_compositor *ec,
+ struct weston_output *output)
+{
+ struct focus_surface *fsurf = NULL;
+ struct weston_surface *surface = NULL;
+
+ fsurf = malloc(sizeof *fsurf);
+ if (!fsurf)
+ return NULL;
+
+ fsurf->surface = weston_surface_create(ec);
+ surface = fsurf->surface;
+ if (surface == NULL) {
+ free(fsurf);
+ return NULL;
+ }
+
+ surface->configure = focus_surface_configure;
+ surface->output = output;
+ surface->configure_private = fsurf;
+
+ fsurf->view = weston_view_create (surface);
+ fsurf->view->output = output;
+
+ weston_surface_set_size(surface, output->width, output->height);
+ weston_view_set_position(fsurf->view, output->x, output->y);
+ weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
+ pixman_region32_fini(&surface->opaque);
+ pixman_region32_init_rect(&surface->opaque, output->x, output->y,
+ output->width, output->height);
+ pixman_region32_fini(&surface->input);
+ pixman_region32_init(&surface->input);
+
+ wl_list_init(&fsurf->workspace_transform.link);
+
+ return fsurf;
+}
+
+static void
+focus_surface_destroy(struct focus_surface *fsurf)
+{
+ weston_surface_destroy(fsurf->surface);
+ free(fsurf);
+}
+
+static void
+focus_animation_done(struct weston_view_animation *animation, void *data)
+{
+ struct workspace *ws = data;
+
+ ws->focus_animation = NULL;
+}
+
static void
focus_state_destroy(struct focus_state *state)
{
@@ -484,17 +570,19 @@ focus_state_surface_destroy(struct wl_listener *listener, void *data)
struct focus_state,
surface_destroy_listener);
struct desktop_shell *shell;
- struct weston_surface *main_surface;
- struct weston_surface *surface, *next;
+ struct weston_surface *main_surface, *next;
+ struct weston_view *view;
main_surface = weston_surface_get_main_surface(state->keyboard_focus);
next = NULL;
- wl_list_for_each(surface, &state->ws->layer.surface_list, layer_link) {
- if (surface == main_surface)
+ wl_list_for_each(view, &state->ws->layer.view_list, layer_link) {
+ if (view->surface == main_surface)
+ continue;
+ if (is_focus_view(view))
continue;
- next = surface;
+ next = view->surface;
break;
}
@@ -502,10 +590,21 @@ focus_state_surface_destroy(struct wl_listener *listener, void *data)
if (main_surface != state->keyboard_focus)
next = main_surface;
+ shell = state->seat->compositor->shell_interface.shell;
if (next) {
- shell = state->seat->compositor->shell_interface.shell;
+ state->keyboard_focus = NULL;
activate(shell, next, state->seat);
} else {
+ if (shell->focus_animation_type == ANIMATION_DIM_LAYER) {
+ if (state->ws->focus_animation)
+ weston_view_animation_destroy(state->ws->focus_animation);
+
+ state->ws->focus_animation = weston_fade_run(
+ state->ws->fsurf_front->view,
+ state->ws->fsurf_front->view->alpha, 0.0, 300,
+ focus_animation_done, state->ws);
+ }
+
wl_list_remove(&state->link);
focus_state_destroy(state);
}
@@ -520,6 +619,7 @@ focus_state_create(struct weston_seat *seat, struct workspace *ws)
if (state == NULL)
return NULL;
+ state->keyboard_focus = NULL;
state->ws = ws;
state->seat = seat;
wl_list_insert(&ws->focus_list, &state->link);
@@ -590,6 +690,63 @@ drop_focus_state(struct desktop_shell *shell, struct workspace *ws,
}
static void
+animate_focus_change(struct desktop_shell *shell, struct workspace *ws,
+ struct weston_view *from, struct weston_view *to)
+{
+ struct weston_output *output;
+ bool focus_surface_created = false;
+
+ /* FIXME: Only support dim animation using two layers */
+ if (from == to || shell->focus_animation_type != ANIMATION_DIM_LAYER)
+ return;
+
+ output = get_default_output(shell->compositor);
+ if (ws->fsurf_front == NULL && (from || to)) {
+ ws->fsurf_front = create_focus_surface(shell->compositor, output);
+ ws->fsurf_back = create_focus_surface(shell->compositor, output);
+ ws->fsurf_front->view->alpha = 0.0;
+ ws->fsurf_back->view->alpha = 0.0;
+ focus_surface_created = true;
+ } else {
+ wl_list_remove(&ws->fsurf_front->view->layer_link);
+ wl_list_remove(&ws->fsurf_back->view->layer_link);
+ }
+
+ if (ws->focus_animation) {
+ weston_view_animation_destroy(ws->focus_animation);
+ ws->focus_animation = NULL;
+ }
+
+ if (to)
+ wl_list_insert(&to->layer_link,
+ &ws->fsurf_front->view->layer_link);
+ else if (from)
+ wl_list_insert(&ws->layer.view_list,
+ &ws->fsurf_front->view->layer_link);
+
+ if (focus_surface_created) {
+ ws->focus_animation = weston_fade_run(
+ ws->fsurf_front->view,
+ ws->fsurf_front->view->alpha, 0.6, 300,
+ focus_animation_done, ws);
+ } else if (from) {
+ wl_list_insert(&from->layer_link,
+ &ws->fsurf_back->view->layer_link);
+ ws->focus_animation = weston_stable_fade_run(
+ ws->fsurf_front->view, 0.0,
+ ws->fsurf_back->view, 0.6,
+ focus_animation_done, ws);
+ } else if (to) {
+ wl_list_insert(&ws->layer.view_list,
+ &ws->fsurf_back->view->layer_link);
+ ws->focus_animation = weston_stable_fade_run(
+ ws->fsurf_front->view, 0.0,
+ ws->fsurf_back->view, 0.6,
+ focus_animation_done, ws);
+ }
+}
+
+static void
workspace_destroy(struct workspace *ws)
{
struct focus_state *state, *next;
@@ -597,6 +754,11 @@ workspace_destroy(struct workspace *ws)
wl_list_for_each_safe(state, next, &ws->focus_list, link)
focus_state_destroy(state);
+ if (ws->fsurf_front)
+ focus_surface_destroy(ws->fsurf_front);
+ if (ws->fsurf_back)
+ focus_surface_destroy(ws->fsurf_back);
+
free(ws);
}
@@ -626,6 +788,9 @@ workspace_create(void)
wl_list_init(&ws->focus_list);
wl_list_init(&ws->seat_destroyed_listener.link);
ws->seat_destroyed_listener.notify = seat_destroyed;
+ ws->fsurf_front = NULL;
+ ws->fsurf_back = NULL;
+ ws->focus_animation = NULL;
return ws;
}
@@ -633,7 +798,7 @@ workspace_create(void)
static int
workspace_is_empty(struct workspace *ws)
{
- return wl_list_empty(&ws->layer.surface_list);
+ return wl_list_empty(&ws->layer.view_list);
}
static struct workspace *
@@ -645,7 +810,7 @@ get_workspace(struct desktop_shell *shell, unsigned int index)
return *pws;
}
-static struct workspace *
+struct workspace *
get_current_workspace(struct desktop_shell *shell)
{
return get_workspace(shell, shell->workspaces.current);
@@ -669,53 +834,59 @@ get_output_height(struct weston_output *output)
}
static void
-surface_translate(struct weston_surface *surface, double d)
+view_translate(struct workspace *ws, struct weston_view *view, double d)
{
- struct shell_surface *shsurf = get_shell_surface(surface);
struct weston_transform *transform;
- transform = &shsurf->workspace_transform;
+ if (is_focus_view(view)) {
+ struct focus_surface *fsurf = get_focus_surface(view->surface);
+ transform = &fsurf->workspace_transform;
+ } else {
+ struct shell_surface *shsurf = get_shell_surface(view->surface);
+ transform = &shsurf->workspace_transform;
+ }
+
if (wl_list_empty(&transform->link))
- wl_list_insert(surface->geometry.transformation_list.prev,
- &shsurf->workspace_transform.link);
+ wl_list_insert(view->geometry.transformation_list.prev,
+ &transform->link);
- weston_matrix_init(&shsurf->workspace_transform.matrix);
- weston_matrix_translate(&shsurf->workspace_transform.matrix,
+ weston_matrix_init(&transform->matrix);
+ weston_matrix_translate(&transform->matrix,
0.0, d, 0.0);
- weston_surface_geometry_dirty(surface);
+ weston_view_geometry_dirty(view);
}
static void
workspace_translate_out(struct workspace *ws, double fraction)
{
- struct weston_surface *surface;
+ struct weston_view *view;
unsigned int height;
double d;
- wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
- height = get_output_height(surface->output);
+ wl_list_for_each(view, &ws->layer.view_list, layer_link) {
+ height = get_output_height(view->surface->output);
d = height * fraction;
- surface_translate(surface, d);
+ view_translate(ws, view, d);
}
}
static void
workspace_translate_in(struct workspace *ws, double fraction)
{
- struct weston_surface *surface;
+ struct weston_view *view;
unsigned int height;
double d;
- wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
- height = get_output_height(surface->output);
+ wl_list_for_each(view, &ws->layer.view_list, layer_link) {
+ height = get_output_height(view->surface->output);
if (fraction > 0)
d = -(height - height * fraction);
else
d = height + height * fraction;
- surface_translate(surface, d);
+ view_translate(ws, view, d);
}
}
@@ -749,16 +920,23 @@ reverse_workspace_change_animation(struct desktop_shell *shell,
static void
workspace_deactivate_transforms(struct workspace *ws)
{
- struct weston_surface *surface;
- struct shell_surface *shsurf;
+ struct weston_view *view;
+ struct weston_transform *transform;
- wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
- shsurf = get_shell_surface(surface);
- if (!wl_list_empty(&shsurf->workspace_transform.link)) {
- wl_list_remove(&shsurf->workspace_transform.link);
- wl_list_init(&shsurf->workspace_transform.link);
+ wl_list_for_each(view, &ws->layer.view_list, layer_link) {
+ if (is_focus_view(view)) {
+ struct focus_surface *fsurf = get_focus_surface(view->surface);
+ transform = &fsurf->workspace_transform;
+ } else {
+ struct shell_surface *shsurf = get_shell_surface(view->surface);
+ transform = &shsurf->workspace_transform;
+ }
+
+ if (!wl_list_empty(&transform->link)) {
+ wl_list_remove(&transform->link);
+ wl_list_init(&transform->link);
}
- weston_surface_geometry_dirty(surface);
+ weston_view_geometry_dirty(view);
}
}
@@ -879,12 +1057,13 @@ change_workspace(struct desktop_shell *shell, unsigned int index)
{
struct workspace *from;
struct workspace *to;
+ struct focus_state *state;
if (index == shell->workspaces.current)
return;
/* Don't change workspace when there is any fullscreen surfaces. */
- if (!wl_list_empty(&shell->fullscreen_layer.surface_list))
+ if (!wl_list_empty(&shell->fullscreen_layer.view_list))
return;
from = get_current_workspace(shell);
@@ -905,6 +1084,18 @@ change_workspace(struct desktop_shell *shell, unsigned int index)
restore_focus_state(shell, to);
+ if (shell->focus_animation_type != ANIMATION_NONE) {
+ wl_list_for_each(state, &from->focus_list, link)
+ if (state->keyboard_focus)
+ animate_focus_change(shell, from,
+ get_default_view(state->keyboard_focus), NULL);
+
+ wl_list_for_each(state, &to->focus_list, link)
+ if (state->keyboard_focus)
+ animate_focus_change(shell, to,
+ NULL, get_default_view(state->keyboard_focus));
+ }
+
if (workspace_is_empty(to) && workspace_is_empty(from))
update_workspace(shell, index, from, to);
else
@@ -916,7 +1107,7 @@ change_workspace(struct desktop_shell *shell, unsigned int index)
static bool
workspace_has_only(struct workspace *ws, struct weston_surface *surface)
{
- struct wl_list *list = &ws->layer.surface_list;
+ struct wl_list *list = &ws->layer.view_list;
struct wl_list *e;
if (wl_list_empty(list))
@@ -927,44 +1118,51 @@ workspace_has_only(struct workspace *ws, struct weston_surface *surface)
if (e->next != list)
return false;
- return container_of(e, struct weston_surface, layer_link) == surface;
+ return container_of(e, struct weston_view, layer_link)->surface == surface;
}
static void
move_surface_to_workspace(struct desktop_shell *shell,
- struct weston_surface *surface,
- uint32_t workspace)
+ struct shell_surface *shsurf,
+ uint32_t workspace)
{
struct workspace *from;
struct workspace *to;
struct weston_seat *seat;
struct weston_surface *focus;
-
- assert(weston_surface_get_main_surface(surface) == surface);
+ struct weston_view *view;
if (workspace == shell->workspaces.current)
return;
+ view = get_default_view(shsurf->surface);
+ if (!view)
+ return;
+
+ assert(weston_surface_get_main_surface(view->surface) == view->surface);
+
if (workspace >= shell->workspaces.num)
workspace = shell->workspaces.num - 1;
from = get_current_workspace(shell);
to = get_workspace(shell, workspace);
- wl_list_remove(&surface->layer_link);
- wl_list_insert(&to->layer.surface_list, &surface->layer_link);
+ wl_list_remove(&view->layer_link);
+ wl_list_insert(&to->layer.view_list, &view->layer_link);
- drop_focus_state(shell, from, surface);
+ shell_surface_update_child_surface_layers(shsurf);
+
+ drop_focus_state(shell, from, view->surface);
wl_list_for_each(seat, &shell->compositor->seat_list, link) {
if (!seat->keyboard)
continue;
focus = weston_surface_get_main_surface(seat->keyboard->focus);
- if (focus == surface)
+ if (focus == view->surface)
weston_keyboard_set_focus(seat->keyboard, NULL);
}
- weston_surface_damage_below(surface);
+ weston_view_damage_below(view);
}
static void
@@ -973,21 +1171,28 @@ take_surface_to_workspace_by_seat(struct desktop_shell *shell,
unsigned int index)
{
struct weston_surface *surface;
+ struct weston_view *view;
struct shell_surface *shsurf;
struct workspace *from;
struct workspace *to;
struct focus_state *state;
surface = weston_surface_get_main_surface(seat->keyboard->focus);
- if (surface == NULL ||
- index == shell->workspaces.current)
+ view = get_default_view(surface);
+ if (view == NULL ||
+ index == shell->workspaces.current ||
+ is_focus_view(view))
return;
from = get_current_workspace(shell);
to = get_workspace(shell, index);
- wl_list_remove(&surface->layer_link);
- wl_list_insert(&to->layer.surface_list, &surface->layer_link);
+ wl_list_remove(&view->layer_link);
+ wl_list_insert(&to->layer.view_list, &view->layer_link);
+
+ shsurf = get_shell_surface(surface);
+ if (shsurf != NULL)
+ shell_surface_update_child_surface_layers(shsurf);
replace_focus_state(shell, to, seat);
drop_focus_state(shell, from, surface);
@@ -1012,8 +1217,8 @@ take_surface_to_workspace_by_seat(struct desktop_shell *shell,
workspace_has_only(to, surface))
update_workspace(shell, index, from, to);
else {
- shsurf = get_shell_surface(surface);
- if (wl_list_empty(&shsurf->workspace_transform.link))
+ if (shsurf != NULL &&
+ wl_list_empty(&shsurf->workspace_transform.link))
wl_list_insert(&shell->workspaces.anim_sticky_list,
&shsurf->workspace_transform.link);
@@ -1037,9 +1242,14 @@ workspace_manager_move_surface(struct wl_client *client,
struct weston_surface *surface =
wl_resource_get_user_data(surface_resource);
struct weston_surface *main_surface;
+ struct shell_surface *shell_surface;
main_surface = weston_surface_get_main_surface(surface);
- move_surface_to_workspace(shell, main_surface, workspace);
+ shell_surface = get_shell_surface(main_surface);
+ if (shell_surface == NULL)
+ return;
+
+ move_surface_to_workspace(shell, shell_surface, workspace);
}
static const struct workspace_manager_interface workspace_manager_implementation = {
@@ -1091,7 +1301,7 @@ touch_move_grab_up(struct weston_touch_grab *grab, uint32_t time, int touch_id)
(struct weston_touch_move_grab *) container_of(
grab, struct shell_touch_grab, grab);
- if (grab->touch->seat->num_tp == 0) {
+ if (grab->touch->num_tp == 0) {
shell_touch_grab_end(&move->base);
free(move);
}
@@ -1112,8 +1322,7 @@ touch_move_grab_motion(struct weston_touch_grab *grab, uint32_t time,
es = shsurf->surface;
- weston_surface_configure(es, dx, dy,
- es->geometry.width, es->geometry.height);
+ weston_view_set_position(shsurf->view, dx, dy);
weston_compositor_schedule_repaint(es->compositor);
}
@@ -1144,16 +1353,18 @@ surface_touch_move(struct shell_surface *shsurf, struct weston_seat *seat)
if (!shsurf)
return -1;
- if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
+ if (shsurf->state.fullscreen)
+ return 0;
+ if (shsurf->grabbed)
return 0;
move = malloc(sizeof *move);
if (!move)
return -1;
- move->dx = wl_fixed_from_double(shsurf->surface->geometry.x) -
+ move->dx = wl_fixed_from_double(shsurf->view->geometry.x) -
seat->touch->grab_x;
- move->dy = wl_fixed_from_double(shsurf->surface->geometry.y) -
+ move->dy = wl_fixed_from_double(shsurf->view->geometry.y) -
seat->touch->grab_y;
shell_touch_grab_start(&move->base, &touch_move_grab_interface, shsurf,
@@ -1168,24 +1379,24 @@ noop_grab_focus(struct weston_pointer_grab *grab)
}
static void
-move_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
+move_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
+ wl_fixed_t x, wl_fixed_t y)
{
struct weston_move_grab *move = (struct weston_move_grab *) grab;
struct weston_pointer *pointer = grab->pointer;
struct shell_surface *shsurf = move->base.shsurf;
- struct weston_surface *es;
- int dx = wl_fixed_to_int(pointer->x + move->dx);
- int dy = wl_fixed_to_int(pointer->y + move->dy);
+ int dx, dy;
+
+ weston_pointer_move(pointer, x, y);
+ dx = wl_fixed_to_int(pointer->x + move->dx);
+ dy = wl_fixed_to_int(pointer->y + move->dy);
if (!shsurf)
return;
- es = shsurf->surface;
-
- weston_surface_configure(es, dx, dy,
- es->geometry.width, es->geometry.height);
+ weston_view_set_position(shsurf->view, dx, dy);
- weston_compositor_schedule_repaint(es->compositor);
+ weston_compositor_schedule_repaint(shsurf->surface->compositor);
}
static void
@@ -1229,16 +1440,18 @@ surface_move(struct shell_surface *shsurf, struct weston_seat *seat)
if (!shsurf)
return -1;
- if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
+ if (shsurf->grabbed)
+ return 0;
+ if (shsurf->state.fullscreen)
return 0;
move = malloc(sizeof *move);
if (!move)
return -1;
- move->dx = wl_fixed_from_double(shsurf->surface->geometry.x) -
+ move->dx = wl_fixed_from_double(shsurf->view->geometry.x) -
seat->pointer->grab_x;
- move->dy = wl_fixed_from_double(shsurf->surface->geometry.y) -
+ move->dy = wl_fixed_from_double(shsurf->view->geometry.y) -
seat->pointer->grab_y;
shell_grab_start(&move->base, &move_grab_interface, shsurf,
@@ -1248,29 +1461,38 @@ surface_move(struct shell_surface *shsurf, struct weston_seat *seat)
}
static void
-shell_surface_move(struct wl_client *client, struct wl_resource *resource,
- struct wl_resource *seat_resource, uint32_t serial)
+common_surface_move(struct wl_resource *resource,
+ struct wl_resource *seat_resource, uint32_t serial)
{
struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
struct weston_surface *surface;
if (seat->pointer &&
+ seat->pointer->focus &&
seat->pointer->button_count > 0 &&
seat->pointer->grab_serial == serial) {
- surface = weston_surface_get_main_surface(seat->pointer->focus);
+ surface = weston_surface_get_main_surface(seat->pointer->focus->surface);
if ((surface == shsurf->surface) &&
(surface_move(shsurf, seat) < 0))
wl_resource_post_no_memory(resource);
} else if (seat->touch &&
+ seat->touch->focus &&
seat->touch->grab_serial == serial) {
- surface = weston_surface_get_main_surface(seat->touch->focus);
+ surface = weston_surface_get_main_surface(seat->touch->focus->surface);
if ((surface == shsurf->surface) &&
(surface_touch_move(shsurf, seat) < 0))
wl_resource_post_no_memory(resource);
}
}
+static void
+shell_surface_move(struct wl_client *client, struct wl_resource *resource,
+ struct wl_resource *seat_resource, uint32_t serial)
+{
+ common_surface_move(resource, seat_resource, serial);
+}
+
struct weston_resize_grab {
struct shell_grab base;
uint32_t edges;
@@ -1278,7 +1500,8 @@ struct weston_resize_grab {
};
static void
-resize_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
+resize_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
+ wl_fixed_t x, wl_fixed_t y)
{
struct weston_resize_grab *resize = (struct weston_resize_grab *) grab;
struct weston_pointer *pointer = grab->pointer;
@@ -1287,14 +1510,16 @@ resize_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
wl_fixed_t from_x, from_y;
wl_fixed_t to_x, to_y;
+ weston_pointer_move(pointer, x, y);
+
if (!shsurf)
return;
- weston_surface_from_global_fixed(shsurf->surface,
- pointer->grab_x, pointer->grab_y,
- &from_x, &from_y);
- weston_surface_from_global_fixed(shsurf->surface,
- pointer->x, pointer->y, &to_x, &to_y);
+ weston_view_from_global_fixed(shsurf->view,
+ pointer->grab_x, pointer->grab_y,
+ &from_x, &from_y);
+ weston_view_from_global_fixed(shsurf->view,
+ pointer->x, pointer->y, &to_x, &to_y);
width = resize->width;
if (resize->edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
@@ -1370,15 +1595,15 @@ surface_subsurfaces_boundingbox(struct weston_surface *surface, int32_t *x,
struct weston_subsurface *subsurface;
pixman_region32_init_rect(&region, 0, 0,
- surface->geometry.width,
- surface->geometry.height);
+ surface->width,
+ surface->height);
wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) {
pixman_region32_union_rect(&region, &region,
subsurface->position.x,
subsurface->position.y,
- subsurface->surface->geometry.width,
- subsurface->surface->geometry.height);
+ subsurface->surface->width,
+ subsurface->surface->height);
}
box = pixman_region32_extents(&region);
@@ -1400,8 +1625,7 @@ surface_resize(struct shell_surface *shsurf,
{
struct weston_resize_grab *resize;
- if (shsurf->type == SHELL_SURFACE_FULLSCREEN ||
- shsurf->type == SHELL_SURFACE_MAXIMIZED)
+ if (shsurf->state.fullscreen || shsurf->state.maximized)
return 0;
if (edges == 0 || edges > 15 ||
@@ -1423,21 +1647,24 @@ surface_resize(struct shell_surface *shsurf,
}
static void
-shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
- struct wl_resource *seat_resource, uint32_t serial,
- uint32_t edges)
+common_surface_resize(struct wl_resource *resource,
+ struct wl_resource *seat_resource, uint32_t serial,
+ uint32_t edges)
{
struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
struct weston_surface *surface;
- if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
+ if (shsurf->state.fullscreen)
return;
- surface = weston_surface_get_main_surface(seat->pointer->focus);
if (seat->pointer->button_count == 0 ||
seat->pointer->grab_serial != serial ||
- surface != shsurf->surface)
+ seat->pointer->focus == NULL)
+ return;
+
+ surface = weston_surface_get_main_surface(seat->pointer->focus->surface);
+ if (surface != shsurf->surface)
return;
if (surface_resize(shsurf, seat, edges) < 0)
@@ -1445,6 +1672,14 @@ shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
}
static void
+shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
+ struct wl_resource *seat_resource, uint32_t serial,
+ uint32_t edges)
+{
+ common_surface_resize(resource, seat_resource, serial, edges);
+}
+
+static void
end_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer);
static void
@@ -1452,20 +1687,22 @@ busy_cursor_grab_focus(struct weston_pointer_grab *base)
{
struct shell_grab *grab = (struct shell_grab *) base;
struct weston_pointer *pointer = base->pointer;
- struct weston_surface *surface;
+ struct weston_view *view;
wl_fixed_t sx, sy;
- surface = weston_compositor_pick_surface(pointer->seat->compositor,
- pointer->x, pointer->y,
- &sx, &sy);
+ view = weston_compositor_pick_view(pointer->seat->compositor,
+ pointer->x, pointer->y,
+ &sx, &sy);
- if (!grab->shsurf || grab->shsurf->surface != surface)
+ if (!grab->shsurf || grab->shsurf->surface != view->surface)
end_busy_cursor(grab->shsurf, pointer);
}
static void
-busy_cursor_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
+busy_cursor_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
+ wl_fixed_t x, wl_fixed_t y)
{
+ weston_pointer_move(grab->pointer, x, y);
}
static void
@@ -1549,7 +1786,8 @@ ping_timeout_handler(void *data)
shsurf->unresponsive = 1;
wl_list_for_each(seat, &shsurf->surface->compositor->seat_list, link)
- if (seat->pointer->focus == shsurf->surface)
+ if (seat->pointer->focus &&
+ seat->pointer->focus->surface == shsurf->surface)
set_busy_cursor(shsurf, seat->pointer);
return 1;
@@ -1581,7 +1819,12 @@ ping_handler(struct weston_surface *surface, uint32_t serial)
wl_event_loop_add_timer(loop, ping_timeout_handler, shsurf);
wl_event_source_timer_update(shsurf->ping_timer->source, ping_timeout);
- wl_shell_surface_send_ping(shsurf->resource, serial);
+ if (shell_surface_is_wl_shell_surface(shsurf))
+ wl_shell_surface_send_ping(shsurf->resource, serial);
+ else if (shell_surface_is_xdg_surface(shsurf))
+ xdg_surface_send_ping(shsurf->resource, serial);
+ else if (shell_surface_is_xdg_popup(shsurf))
+ xdg_popup_send_ping(shsurf->resource, serial);
}
}
@@ -1589,22 +1832,22 @@ static void
handle_pointer_focus(struct wl_listener *listener, void *data)
{
struct weston_pointer *pointer = data;
- struct weston_surface *surface = pointer->focus;
+ struct weston_view *view = pointer->focus;
struct weston_compositor *compositor;
struct shell_surface *shsurf;
uint32_t serial;
- if (!surface)
+ if (!view)
return;
- compositor = surface->compositor;
- shsurf = get_shell_surface(surface);
+ compositor = view->surface->compositor;
+ shsurf = get_shell_surface(view->surface);
if (shsurf && shsurf->unresponsive) {
set_busy_cursor(shsurf, pointer);
} else {
serial = wl_display_next_serial(compositor->wl_display);
- ping_handler(surface, serial);
+ ping_handler(view->surface, serial);
}
}
@@ -1622,12 +1865,26 @@ create_pointer_focus_listener(struct weston_seat *seat)
}
static void
-shell_surface_pong(struct wl_client *client, struct wl_resource *resource,
- uint32_t serial)
+xdg_surface_set_transient_for(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *parent_resource)
{
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
- struct weston_seat *seat;
+ struct weston_surface *parent;
+
+ if (parent_resource)
+ parent = wl_resource_get_user_data(parent_resource);
+ else
+ parent = NULL;
+
+ shell_surface_set_parent(shsurf, parent);
+}
+
+static void
+surface_pong(struct shell_surface *shsurf, uint32_t serial)
+{
struct weston_compositor *ec = shsurf->surface->compositor;
+ struct weston_seat *seat;
if (shsurf->ping_timer == NULL)
/* Just ignore unsolicited pong. */
@@ -1644,6 +1901,16 @@ shell_surface_pong(struct wl_client *client, struct wl_resource *resource,
}
static void
+shell_surface_pong(struct wl_client *client, struct wl_resource *resource,
+ uint32_t serial)
+{
+ struct shell_surface *shsurf = wl_resource_get_user_data(resource);
+
+ surface_pong(shsurf, serial);
+
+}
+
+static void
set_title(struct shell_surface *shsurf, const char *title)
{
free(shsurf->title);
@@ -1669,13 +1936,6 @@ shell_surface_set_class(struct wl_client *client,
shsurf->class = strdup(class);
}
-static struct weston_output *
-get_default_output(struct weston_compositor *compositor)
-{
- return container_of(compositor->output_list.next,
- struct weston_output, link);
-}
-
static void
restore_output_mode(struct weston_output *output)
{
@@ -1696,127 +1956,172 @@ restore_all_output_modes(struct weston_compositor *compositor)
restore_output_mode(output);
}
-static void
-shell_unset_fullscreen(struct shell_surface *shsurf)
+static int
+get_output_panel_height(struct desktop_shell *shell,
+ struct weston_output *output)
{
- struct workspace *ws;
- /* undo all fullscreen things here */
- if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
- shell_surface_is_top_fullscreen(shsurf)) {
- restore_output_mode(shsurf->fullscreen_output);
- }
- shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
- shsurf->fullscreen.framerate = 0;
- wl_list_remove(&shsurf->fullscreen.transform.link);
- wl_list_init(&shsurf->fullscreen.transform.link);
- if (shsurf->fullscreen.black_surface)
- weston_surface_destroy(shsurf->fullscreen.black_surface);
- shsurf->fullscreen.black_surface = NULL;
- shsurf->fullscreen_output = NULL;
- weston_surface_set_position(shsurf->surface,
- shsurf->saved_x, shsurf->saved_y);
- if (shsurf->saved_rotation_valid) {
- wl_list_insert(&shsurf->surface->geometry.transformation_list,
- &shsurf->rotation.transform.link);
- shsurf->saved_rotation_valid = false;
+ struct weston_view *view;
+ int panel_height = 0;
+
+ if (!output)
+ return 0;
+
+ wl_list_for_each(view, &shell->panel_layer.view_list, layer_link) {
+ if (view->surface->output == output) {
+ panel_height = view->surface->height;
+ break;
+ }
}
- ws = get_current_workspace(shsurf->shell);
- wl_list_remove(&shsurf->surface->layer_link);
- wl_list_insert(&ws->layer.surface_list, &shsurf->surface->layer_link);
+ return panel_height;
}
-static void
-shell_unset_maximized(struct shell_surface *shsurf)
+/* The surface will be inserted into the list immediately after the link
+ * returned by this function (i.e. will be stacked immediately above the
+ * returned link). */
+static struct wl_list *
+shell_surface_calculate_layer_link (struct shell_surface *shsurf)
{
struct workspace *ws;
- /* undo all maximized things here */
- shsurf->output = get_default_output(shsurf->surface->compositor);
- weston_surface_set_position(shsurf->surface,
- shsurf->saved_x,
- shsurf->saved_y);
+ struct weston_view *parent;
- if (shsurf->saved_rotation_valid) {
- wl_list_insert(&shsurf->surface->geometry.transformation_list,
- &shsurf->rotation.transform.link);
- shsurf->saved_rotation_valid = false;
+ switch (shsurf->type) {
+ case SHELL_SURFACE_POPUP:
+ case SHELL_SURFACE_TOPLEVEL:
+ if (shsurf->state.fullscreen) {
+ return &shsurf->shell->fullscreen_layer.view_list;
+ } else if (shsurf->parent) {
+ /* Move the surface to its parent layer so
+ * that surfaces which are transient for
+ * fullscreen surfaces don't get hidden by the
+ * fullscreen surfaces. */
+
+ /* TODO: Handle a parent with multiple views */
+ parent = get_default_view(shsurf->parent);
+ if (parent)
+ return parent->layer_link.prev;
+ }
+ break;
+
+ case SHELL_SURFACE_XWAYLAND:
+ return &shsurf->shell->fullscreen_layer.view_list;
+
+ case SHELL_SURFACE_NONE:
+ default:
+ /* Go to the fallback, below. */
+ break;
}
+ /* Move the surface to a normal workspace layer so that surfaces
+ * which were previously fullscreen or transient are no longer
+ * rendered on top. */
ws = get_current_workspace(shsurf->shell);
- wl_list_remove(&shsurf->surface->layer_link);
- wl_list_insert(&ws->layer.surface_list, &shsurf->surface->layer_link);
+ return &ws->layer.view_list;
}
-static int
-reset_shell_surface_type(struct shell_surface *surface)
+static void
+shell_surface_update_child_surface_layers (struct shell_surface *shsurf)
{
- switch (surface->type) {
- case SHELL_SURFACE_FULLSCREEN:
- shell_unset_fullscreen(surface);
- break;
- case SHELL_SURFACE_MAXIMIZED:
- shell_unset_maximized(surface);
- break;
- case SHELL_SURFACE_NONE:
- case SHELL_SURFACE_TOPLEVEL:
- case SHELL_SURFACE_TRANSIENT:
- case SHELL_SURFACE_POPUP:
- case SHELL_SURFACE_XWAYLAND:
- break;
- }
+ struct shell_surface *child;
- surface->type = SHELL_SURFACE_NONE;
- return 0;
+ /* Move the child layers to the same workspace as shsurf. They will be
+ * stacked above shsurf. */
+ wl_list_for_each_reverse(child, &shsurf->children_list, children_link) {
+ if (shsurf->view->layer_link.prev != &child->view->layer_link) {
+ weston_view_geometry_dirty(child->view);
+ wl_list_remove(&child->view->layer_link);
+ wl_list_insert(shsurf->view->layer_link.prev,
+ &child->view->layer_link);
+ weston_view_geometry_dirty(child->view);
+ weston_surface_damage(child->surface);
+
+ /* Recurse. We don’t expect this to recurse very far (if
+ * at all) because that would imply we have transient
+ * (or popup) children of transient surfaces, which
+ * would be unusual. */
+ shell_surface_update_child_surface_layers(child);
+ }
+ }
}
+/* Update the surface’s layer. Mark both the old and new views as having dirty
+ * geometry to ensure the changes are redrawn.
+ *
+ * If any child surfaces exist and are mapped, ensure they’re in the same layer
+ * as this surface. */
static void
-set_surface_type(struct shell_surface *shsurf)
+shell_surface_update_layer(struct shell_surface *shsurf)
{
- struct weston_surface *surface = shsurf->surface;
- struct weston_surface *pes = shsurf->parent;
+ struct wl_list *new_layer_link;
- reset_shell_surface_type(shsurf);
+ new_layer_link = shell_surface_calculate_layer_link(shsurf);
- shsurf->type = shsurf->next_type;
- shsurf->next_type = SHELL_SURFACE_NONE;
+ if (new_layer_link == &shsurf->view->layer_link)
+ return;
- switch (shsurf->type) {
- case SHELL_SURFACE_TOPLEVEL:
- break;
- case SHELL_SURFACE_TRANSIENT:
- weston_surface_set_position(surface,
- pes->geometry.x + shsurf->transient.x,
- pes->geometry.y + shsurf->transient.y);
- break;
+ weston_view_geometry_dirty(shsurf->view);
+ wl_list_remove(&shsurf->view->layer_link);
+ wl_list_insert(new_layer_link, &shsurf->view->layer_link);
+ weston_view_geometry_dirty(shsurf->view);
+ weston_surface_damage(shsurf->surface);
- case SHELL_SURFACE_MAXIMIZED:
- case SHELL_SURFACE_FULLSCREEN:
- shsurf->saved_x = surface->geometry.x;
- shsurf->saved_y = surface->geometry.y;
- shsurf->saved_position_valid = true;
-
- if (!wl_list_empty(&shsurf->rotation.transform.link)) {
- wl_list_remove(&shsurf->rotation.transform.link);
- wl_list_init(&shsurf->rotation.transform.link);
- weston_surface_geometry_dirty(shsurf->surface);
- shsurf->saved_rotation_valid = true;
- }
- break;
+ shell_surface_update_child_surface_layers(shsurf);
+}
- case SHELL_SURFACE_XWAYLAND:
- weston_surface_set_position(surface, shsurf->transient.x,
- shsurf->transient.y);
- break;
+static void
+shell_surface_set_parent(struct shell_surface *shsurf,
+ struct weston_surface *parent)
+{
+ shsurf->parent = parent;
- default:
- break;
+ wl_list_remove(&shsurf->children_link);
+ wl_list_init(&shsurf->children_link);
+
+ /* Insert into the parent surface’s child list. */
+ if (parent != NULL) {
+ struct shell_surface *parent_shsurf = get_shell_surface(parent);
+ if (parent_shsurf != NULL)
+ wl_list_insert(&parent_shsurf->children_list,
+ &shsurf->children_link);
}
}
static void
+shell_surface_set_output(struct shell_surface *shsurf,
+ struct weston_output *output)
+{
+ struct weston_surface *es = shsurf->surface;
+
+ /* get the default output, if the client set it as NULL
+ check whether the ouput is available */
+ if (output)
+ shsurf->output = output;
+ else if (es->output)
+ shsurf->output = es->output;
+ else
+ shsurf->output = get_default_output(es->compositor);
+}
+
+static void
+surface_clear_next_states(struct shell_surface *shsurf)
+{
+ shsurf->next_state.maximized = false;
+ shsurf->next_state.fullscreen = false;
+
+ if ((shsurf->next_state.maximized != shsurf->state.maximized) ||
+ (shsurf->next_state.fullscreen != shsurf->state.fullscreen))
+ shsurf->state_changed = true;
+}
+
+static void
set_toplevel(struct shell_surface *shsurf)
{
- shsurf->next_type = SHELL_SURFACE_TOPLEVEL;
+ shell_surface_set_parent(shsurf, NULL);
+ surface_clear_next_states(shsurf);
+ shsurf->type = SHELL_SURFACE_TOPLEVEL;
+
+ /* The layer_link is updated in set_surface_type(),
+ * called from configure. */
}
static void
@@ -1832,12 +2137,22 @@ static void
set_transient(struct shell_surface *shsurf,
struct weston_surface *parent, int x, int y, uint32_t flags)
{
- /* assign to parents output */
- shsurf->parent = parent;
+ assert(parent != NULL);
+
+ shell_surface_set_parent(shsurf, parent);
+
+ surface_clear_next_states(shsurf);
+
shsurf->transient.x = x;
shsurf->transient.y = y;
shsurf->transient.flags = flags;
- shsurf->next_type = SHELL_SURFACE_TRANSIENT;
+
+ shsurf->next_state.relative = true;
+ shsurf->state_changed = true;
+ shsurf->type = SHELL_SURFACE_TOPLEVEL;
+
+ /* The layer_link is updated in set_surface_type(),
+ * called from configure. */
}
static void
@@ -1853,88 +2168,323 @@ shell_surface_set_transient(struct wl_client *client,
set_transient(shsurf, parent, x, y, flags);
}
-static struct desktop_shell *
-shell_surface_get_shell(struct shell_surface *shsurf)
+static void
+set_fullscreen(struct shell_surface *shsurf,
+ uint32_t method,
+ uint32_t framerate,
+ struct weston_output *output)
{
- return shsurf->shell;
+ shell_surface_set_output(shsurf, output);
+
+ shsurf->fullscreen_output = shsurf->output;
+ shsurf->fullscreen.type = method;
+ shsurf->fullscreen.framerate = framerate;
+
+ shsurf->next_state.fullscreen = true;
+ shsurf->state_changed = true;
+ shsurf->type = SHELL_SURFACE_TOPLEVEL;
+
+ shsurf->client->send_configure(shsurf->surface, 0,
+ shsurf->output->width,
+ shsurf->output->height);
+
+ /* The layer_link is updated in set_surface_type(),
+ * called from configure. */
}
-static int
-get_output_panel_height(struct desktop_shell *shell,
- struct weston_output *output)
+static void
+weston_view_set_initial_position(struct weston_view *view,
+ struct desktop_shell *shell);
+
+static void
+unset_fullscreen(struct shell_surface *shsurf)
{
- struct weston_surface *surface;
- int panel_height = 0;
+ /* Unset the fullscreen output, driver configuration and transforms. */
+ if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
+ shell_surface_is_top_fullscreen(shsurf)) {
+ restore_output_mode(shsurf->fullscreen_output);
+ }
+ shsurf->fullscreen_output = NULL;
- if (!output)
- return 0;
+ shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
+ shsurf->fullscreen.framerate = 0;
- wl_list_for_each(surface, &shell->panel_layer.surface_list, layer_link) {
- if (surface->output == output) {
- panel_height = surface->geometry.height;
- break;
- }
+ wl_list_remove(&shsurf->fullscreen.transform.link);
+ wl_list_init(&shsurf->fullscreen.transform.link);
+
+ if (shsurf->fullscreen.black_view)
+ weston_surface_destroy(shsurf->fullscreen.black_view->surface);
+ shsurf->fullscreen.black_view = NULL;
+
+ if (shsurf->saved_position_valid)
+ weston_view_set_position(shsurf->view,
+ shsurf->saved_x, shsurf->saved_y);
+ else
+ weston_view_set_initial_position(shsurf->view, shsurf->shell);
+
+ if (shsurf->saved_rotation_valid) {
+ wl_list_insert(&shsurf->view->geometry.transformation_list,
+ &shsurf->rotation.transform.link);
+ shsurf->saved_rotation_valid = false;
}
- return panel_height;
+ /* Layer is updated in set_surface_type(). */
}
static void
-shell_surface_set_maximized(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *output_resource )
+shell_surface_set_fullscreen(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t method,
+ uint32_t framerate,
+ struct wl_resource *output_resource)
{
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
- struct weston_surface *es = shsurf->surface;
- struct desktop_shell *shell = NULL;
- uint32_t edges = 0, panel_height = 0;
+ struct weston_output *output;
- /* get the default output, if the client set it as NULL
- check whether the ouput is available */
if (output_resource)
- shsurf->output = wl_resource_get_user_data(output_resource);
- else if (es->output)
- shsurf->output = es->output;
+ output = wl_resource_get_user_data(output_resource);
else
- shsurf->output = get_default_output(es->compositor);
+ output = NULL;
+
+ shell_surface_set_parent(shsurf, NULL);
+
+ surface_clear_next_states(shsurf);
+ set_fullscreen(shsurf, method, framerate, output);
+}
+
+static void
+set_popup(struct shell_surface *shsurf,
+ struct weston_surface *parent,
+ struct weston_seat *seat,
+ uint32_t serial,
+ int32_t x,
+ int32_t y)
+{
+ assert(parent != NULL);
+
+ shsurf->popup.shseat = get_shell_seat(seat);
+ shsurf->popup.serial = serial;
+ shsurf->popup.x = x;
+ shsurf->popup.y = y;
+
+ shsurf->type = SHELL_SURFACE_POPUP;
+}
+
+static void
+shell_surface_set_popup(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *seat_resource,
+ uint32_t serial,
+ struct wl_resource *parent_resource,
+ int32_t x, int32_t y, uint32_t flags)
+{
+ struct shell_surface *shsurf = wl_resource_get_user_data(resource);
+ struct weston_surface *parent =
+ wl_resource_get_user_data(parent_resource);
+
+ shell_surface_set_parent(shsurf, parent);
+
+ surface_clear_next_states(shsurf);
+ set_popup(shsurf,
+ parent,
+ wl_resource_get_user_data(seat_resource),
+ serial, x, y);
+}
+
+static void
+set_maximized(struct shell_surface *shsurf,
+ struct weston_output *output)
+{
+ struct desktop_shell *shell;
+ uint32_t edges = 0, panel_height = 0;
+
+ shell_surface_set_output(shsurf, output);
shell = shell_surface_get_shell(shsurf);
panel_height = get_output_panel_height(shell, shsurf->output);
- edges = WL_SHELL_SURFACE_RESIZE_TOP|WL_SHELL_SURFACE_RESIZE_LEFT;
+ edges = WL_SHELL_SURFACE_RESIZE_TOP | WL_SHELL_SURFACE_RESIZE_LEFT;
shsurf->client->send_configure(shsurf->surface, edges,
- shsurf->output->width,
- shsurf->output->height - panel_height);
+ shsurf->output->width,
+ shsurf->output->height - panel_height);
+
+ shsurf->next_state.maximized = true;
+ shsurf->state_changed = true;
+ shsurf->type = SHELL_SURFACE_TOPLEVEL;
+}
+
+static void
+unset_maximized(struct shell_surface *shsurf)
+{
+ /* undo all maximized things here */
+ shsurf->output = get_default_output(shsurf->surface->compositor);
- shsurf->next_type = SHELL_SURFACE_MAXIMIZED;
+ if (shsurf->saved_position_valid)
+ weston_view_set_position(shsurf->view,
+ shsurf->saved_x, shsurf->saved_y);
+ else
+ weston_view_set_initial_position(shsurf->view, shsurf->shell);
+
+ if (shsurf->saved_rotation_valid) {
+ wl_list_insert(&shsurf->view->geometry.transformation_list,
+ &shsurf->rotation.transform.link);
+ shsurf->saved_rotation_valid = false;
+ }
+
+ /* Layer is updated in set_surface_type(). */
+}
+
+static void
+shell_surface_set_maximized(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *output_resource)
+{
+ struct shell_surface *shsurf = wl_resource_get_user_data(resource);
+ struct weston_output *output;
+
+ if (output_resource)
+ output = wl_resource_get_user_data(output_resource);
+ else
+ output = NULL;
+
+ shell_surface_set_parent(shsurf, NULL);
+
+ surface_clear_next_states(shsurf);
+ set_maximized(shsurf, output);
+}
+
+/* This is only ever called from set_surface_type(), so there’s no need to
+ * update layer_links here, since they’ll be updated when we return. */
+static int
+reset_surface_type(struct shell_surface *surface)
+{
+ if (surface->state.fullscreen)
+ unset_fullscreen(surface);
+ if (surface->state.maximized)
+ unset_maximized(surface);
+
+ return 0;
+}
+
+static void
+set_full_output(struct shell_surface *shsurf)
+{
+ shsurf->saved_x = shsurf->view->geometry.x;
+ shsurf->saved_y = shsurf->view->geometry.y;
+ shsurf->saved_width = shsurf->surface->width;
+ shsurf->saved_height = shsurf->surface->height;
+ shsurf->saved_size_valid = true;
+ shsurf->saved_position_valid = true;
+
+ if (!wl_list_empty(&shsurf->rotation.transform.link)) {
+ wl_list_remove(&shsurf->rotation.transform.link);
+ wl_list_init(&shsurf->rotation.transform.link);
+ weston_view_geometry_dirty(shsurf->view);
+ shsurf->saved_rotation_valid = true;
+ }
+}
+
+static void
+set_surface_type(struct shell_surface *shsurf)
+{
+ struct weston_surface *pes = shsurf->parent;
+ struct weston_view *pev = get_default_view(pes);
+
+ reset_surface_type(shsurf);
+
+ shsurf->state = shsurf->next_state;
+ shsurf->state_changed = false;
+
+ switch (shsurf->type) {
+ case SHELL_SURFACE_TOPLEVEL:
+ if (shsurf->state.maximized || shsurf->state.fullscreen) {
+ set_full_output(shsurf);
+ } else if (shsurf->state.relative && pev) {
+ weston_view_set_position(shsurf->view,
+ pev->geometry.x + shsurf->transient.x,
+ pev->geometry.y + shsurf->transient.y);
+ }
+ break;
+
+ case SHELL_SURFACE_XWAYLAND:
+ weston_view_set_position(shsurf->view, shsurf->transient.x,
+ shsurf->transient.y);
+ break;
+
+ case SHELL_SURFACE_POPUP:
+ case SHELL_SURFACE_NONE:
+ default:
+ break;
+ }
+
+ /* Update the surface’s layer. */
+ shell_surface_update_layer(shsurf);
+}
+
+static struct desktop_shell *
+shell_surface_get_shell(struct shell_surface *shsurf)
+{
+ return shsurf->shell;
}
static void
-black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy, int32_t width, int32_t height);
+black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy);
-static struct weston_surface *
+static struct weston_view *
create_black_surface(struct weston_compositor *ec,
struct weston_surface *fs_surface,
float x, float y, int w, int h)
{
struct weston_surface *surface = NULL;
+ struct weston_view *view;
surface = weston_surface_create(ec);
if (surface == NULL) {
weston_log("no memory\n");
return NULL;
}
+ view = weston_view_create(surface);
+ if (surface == NULL) {
+ weston_log("no memory\n");
+ weston_surface_destroy(surface);
+ return NULL;
+ }
surface->configure = black_surface_configure;
surface->configure_private = fs_surface;
- weston_surface_configure(surface, x, y, w, h);
weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
pixman_region32_fini(&surface->opaque);
pixman_region32_init_rect(&surface->opaque, 0, 0, w, h);
pixman_region32_fini(&surface->input);
pixman_region32_init_rect(&surface->input, 0, 0, w, h);
- return surface;
+ weston_surface_set_size(surface, w, h);
+ weston_view_set_position(view, x, y);
+
+ return view;
+}
+
+static void
+shell_ensure_fullscreen_black_view(struct shell_surface *shsurf)
+{
+ struct weston_output *output = shsurf->fullscreen_output;
+
+ assert(shsurf->state.fullscreen);
+
+ if (!shsurf->fullscreen.black_view)
+ shsurf->fullscreen.black_view =
+ create_black_surface(shsurf->surface->compositor,
+ shsurf->surface,
+ output->x, output->y,
+ output->width,
+ output->height);
+
+ weston_view_geometry_dirty(shsurf->fullscreen.black_view);
+ wl_list_remove(&shsurf->fullscreen.black_view->layer_link);
+ wl_list_insert(&shsurf->view->layer_link,
+ &shsurf->fullscreen.black_view->layer_link);
+ weston_view_geometry_dirty(shsurf->fullscreen.black_view);
+ weston_surface_damage(shsurf->surface);
}
/* Create black surface and append it to the associated fullscreen surface.
@@ -1951,33 +2501,23 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
if (shsurf->fullscreen.type != WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER)
restore_output_mode(output);
- if (!shsurf->fullscreen.black_surface)
- shsurf->fullscreen.black_surface =
- create_black_surface(surface->compositor,
- surface,
- output->x, output->y,
- output->width,
- output->height);
-
- wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
- wl_list_insert(&surface->layer_link,
- &shsurf->fullscreen.black_surface->layer_link);
- shsurf->fullscreen.black_surface->output = output;
+ shell_ensure_fullscreen_black_view(shsurf);
- surface_subsurfaces_boundingbox(surface, &surf_x, &surf_y,
+ surface_subsurfaces_boundingbox(shsurf->surface, &surf_x, &surf_y,
&surf_width, &surf_height);
switch (shsurf->fullscreen.type) {
case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
if (surface->buffer_ref.buffer)
- center_on_output(surface, shsurf->fullscreen_output);
+ center_on_output(shsurf->view, shsurf->fullscreen_output);
break;
case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
/* 1:1 mapping between surface and output dimensions */
if (output->width == surf_width &&
output->height == surf_height) {
- weston_surface_set_position(surface, output->x - surf_x,
- output->y - surf_y);
+ weston_view_set_position(shsurf->view,
+ output->x - surf_x,
+ output->y - surf_y);
break;
}
@@ -1986,8 +2526,9 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
output_aspect = (float) output->width /
(float) output->height;
- surface_aspect = (float) surface->geometry.width /
- (float) surface->geometry.height;
+ /* XXX: Use surf_width and surf_height here? */
+ surface_aspect = (float) surface->width /
+ (float) surface->height;
if (output_aspect < surface_aspect)
scale = (float) output->width /
(float) surf_width;
@@ -1997,130 +2538,64 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
weston_matrix_scale(matrix, scale, scale, 1);
wl_list_remove(&shsurf->fullscreen.transform.link);
- wl_list_insert(&surface->geometry.transformation_list,
+ wl_list_insert(&shsurf->view->geometry.transformation_list,
&shsurf->fullscreen.transform.link);
x = output->x + (output->width - surf_width * scale) / 2 - surf_x;
y = output->y + (output->height - surf_height * scale) / 2 - surf_y;
- weston_surface_set_position(surface, x, y);
+ weston_view_set_position(shsurf->view, x, y);
break;
case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
if (shell_surface_is_top_fullscreen(shsurf)) {
struct weston_mode mode = {0,
- surf_width * surface->buffer_scale,
- surf_height * surface->buffer_scale,
+ surf_width * surface->buffer_viewport.scale,
+ surf_height * surface->buffer_viewport.scale,
shsurf->fullscreen.framerate};
- if (weston_output_switch_mode(output, &mode, surface->buffer_scale,
+ if (weston_output_switch_mode(output, &mode, surface->buffer_viewport.scale,
WESTON_MODE_SWITCH_SET_TEMPORARY) == 0) {
- weston_surface_set_position(surface,
- output->x - surf_x,
- output->y - surf_y);
- weston_surface_configure(shsurf->fullscreen.black_surface,
- output->x - surf_x,
- output->y - surf_y,
- output->width,
- output->height);
+ weston_view_set_position(shsurf->view,
+ output->x - surf_x,
+ output->y - surf_y);
+ shsurf->fullscreen.black_view->surface->width = output->width;
+ shsurf->fullscreen.black_view->surface->height = output->height;
+ weston_view_set_position(shsurf->fullscreen.black_view,
+ output->x - surf_x,
+ output->y - surf_y);
break;
} else {
restore_output_mode(output);
- center_on_output(surface, output);
+ center_on_output(shsurf->view, output);
}
}
break;
case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
- center_on_output(surface, output);
+ center_on_output(shsurf->view, output);
break;
default:
break;
}
}
-/* make the fullscreen and black surface at the top */
-static void
-shell_stack_fullscreen(struct shell_surface *shsurf)
-{
- struct weston_output *output = shsurf->fullscreen_output;
- struct weston_surface *surface = shsurf->surface;
- struct desktop_shell *shell = shell_surface_get_shell(shsurf);
-
- wl_list_remove(&surface->layer_link);
- wl_list_insert(&shell->fullscreen_layer.surface_list,
- &surface->layer_link);
- weston_surface_damage(surface);
-
- if (!shsurf->fullscreen.black_surface)
- shsurf->fullscreen.black_surface =
- create_black_surface(surface->compositor,
- surface,
- output->x, output->y,
- output->width,
- output->height);
-
- wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
- wl_list_insert(&surface->layer_link,
- &shsurf->fullscreen.black_surface->layer_link);
- weston_surface_damage(shsurf->fullscreen.black_surface);
-}
-
static void
shell_map_fullscreen(struct shell_surface *shsurf)
{
- shell_stack_fullscreen(shsurf);
shell_configure_fullscreen(shsurf);
}
static void
-set_fullscreen(struct shell_surface *shsurf,
- uint32_t method,
- uint32_t framerate,
- struct weston_output *output)
-{
- struct weston_surface *es = shsurf->surface;
-
- if (output)
- shsurf->output = output;
- else if (es->output)
- shsurf->output = es->output;
- else
- shsurf->output = get_default_output(es->compositor);
-
- shsurf->fullscreen_output = shsurf->output;
- shsurf->fullscreen.type = method;
- shsurf->fullscreen.framerate = framerate;
- shsurf->next_type = SHELL_SURFACE_FULLSCREEN;
-
- shsurf->client->send_configure(shsurf->surface, 0,
- shsurf->output->width,
- shsurf->output->height);
-}
-
-static void
-shell_surface_set_fullscreen(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t method,
- uint32_t framerate,
- struct wl_resource *output_resource)
-{
- struct shell_surface *shsurf = wl_resource_get_user_data(resource);
- struct weston_output *output;
-
- if (output_resource)
- output = wl_resource_get_user_data(output_resource);
- else
- output = NULL;
-
- set_fullscreen(shsurf, method, framerate, output);
-}
-
-static void
set_xwayland(struct shell_surface *shsurf, int x, int y, uint32_t flags)
{
/* XXX: using the same fields for transient type */
+ surface_clear_next_states(shsurf);
shsurf->transient.x = x;
shsurf->transient.y = y;
shsurf->transient.flags = flags;
- shsurf->next_type = SHELL_SURFACE_XWAYLAND;
+
+ shell_surface_set_parent(shsurf, NULL);
+
+ shsurf->type = SHELL_SURFACE_XWAYLAND;
+ shsurf->state_changed = true;
}
static const struct weston_pointer_grab_interface popup_grab_interface;
@@ -2189,18 +2664,19 @@ static void
popup_grab_focus(struct weston_pointer_grab *grab)
{
struct weston_pointer *pointer = grab->pointer;
- struct weston_surface *surface;
+ struct weston_view *view;
struct shell_seat *shseat =
container_of(grab, struct shell_seat, popup_grab.grab);
struct wl_client *client = shseat->popup_grab.client;
wl_fixed_t sx, sy;
- surface = weston_compositor_pick_surface(pointer->seat->compositor,
- pointer->x, pointer->y,
- &sx, &sy);
+ view = weston_compositor_pick_view(pointer->seat->compositor,
+ pointer->x, pointer->y,
+ &sx, &sy);
- if (surface && wl_resource_get_client(surface->resource) == client) {
- weston_pointer_set_focus(pointer, surface, sx, sy);
+ if (view && view->surface->resource &&
+ wl_resource_get_client(view->surface->resource) == client) {
+ weston_pointer_set_focus(pointer, view, sx, sy);
} else {
weston_pointer_set_focus(pointer, NULL,
wl_fixed_from_int(0),
@@ -2209,16 +2685,19 @@ popup_grab_focus(struct weston_pointer_grab *grab)
}
static void
-popup_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
+popup_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
+ wl_fixed_t x, wl_fixed_t y)
{
struct weston_pointer *pointer = grab->pointer;
struct wl_resource *resource;
wl_fixed_t sx, sy;
+ weston_pointer_move(pointer, x, y);
+
wl_resource_for_each(resource, &pointer->focus_resource_list) {
- weston_surface_from_global_fixed(pointer->focus,
- pointer->x, pointer->y,
- &sx, &sy);
+ weston_view_from_global_fixed(pointer->focus,
+ pointer->x, pointer->y,
+ &sx, &sy);
wl_pointer_send_motion(resource, time, sx, sy);
}
}
@@ -2266,6 +2745,16 @@ static const struct weston_pointer_grab_interface popup_grab_interface = {
};
static void
+shell_surface_send_popup_done(struct shell_surface *shsurf)
+{
+ if (shell_surface_is_wl_shell_surface(shsurf))
+ wl_shell_surface_send_popup_done(shsurf->resource);
+ else if (shell_surface_is_xdg_popup(shsurf))
+ xdg_popup_send_popup_done(shsurf->resource,
+ shsurf->popup.serial);
+}
+
+static void
popup_grab_end(struct weston_pointer *pointer)
{
struct weston_pointer_grab *grab = pointer->grab;
@@ -2281,7 +2770,7 @@ popup_grab_end(struct weston_pointer *pointer)
assert(!wl_list_empty(&shseat->popup_grab.surfaces_list));
/* Send the popup_done event to all the popups open */
wl_list_for_each(shsurf, &shseat->popup_grab.surfaces_list, popup.grab_link) {
- wl_shell_surface_send_popup_done(shsurf->resource);
+ shell_surface_send_popup_done(shsurf);
shsurf->popup.shseat = NULL;
if (prev) {
wl_list_init(&prev->popup.grab_link);
@@ -2331,41 +2820,23 @@ static void
shell_map_popup(struct shell_surface *shsurf)
{
struct shell_seat *shseat = shsurf->popup.shseat;
- struct weston_surface *es = shsurf->surface;
- struct weston_surface *parent = shsurf->parent;
+ struct weston_view *parent_view = get_default_view(shsurf->parent);
- es->output = parent->output;
+ shsurf->surface->output = parent_view->output;
+ shsurf->view->output = parent_view->output;
- weston_surface_set_transform_parent(es, parent);
- weston_surface_set_position(es, shsurf->popup.x, shsurf->popup.y);
- weston_surface_update_transform(es);
+ weston_view_set_transform_parent(shsurf->view, parent_view);
+ weston_view_set_position(shsurf->view, shsurf->popup.x, shsurf->popup.y);
+ weston_view_update_transform(shsurf->view);
if (shseat->seat->pointer->grab_serial == shsurf->popup.serial) {
add_popup_grab(shsurf, shseat);
} else {
- wl_shell_surface_send_popup_done(shsurf->resource);
+ shell_surface_send_popup_done(shsurf);
shseat->popup_grab.client = NULL;
}
}
-static void
-shell_surface_set_popup(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *seat_resource,
- uint32_t serial,
- struct wl_resource *parent_resource,
- int32_t x, int32_t y, uint32_t flags)
-{
- struct shell_surface *shsurf = wl_resource_get_user_data(resource);
-
- shsurf->type = SHELL_SURFACE_POPUP;
- shsurf->parent = wl_resource_get_user_data(parent_resource);
- shsurf->popup.shseat = get_shell_seat(wl_resource_get_user_data(seat_resource));
- shsurf->popup.serial = serial;
- shsurf->popup.x = x;
- shsurf->popup.y = y;
-}
-
static const struct wl_shell_surface_interface shell_surface_implementation = {
shell_surface_pong,
shell_surface_move,
@@ -2382,6 +2853,8 @@ static const struct wl_shell_surface_interface shell_surface_implementation = {
static void
destroy_shell_surface(struct shell_surface *shsurf)
{
+ struct shell_surface *child, *next;
+
wl_signal_emit(&shsurf->destroy_signal, shsurf);
if (!wl_list_empty(&shsurf->popup.grab_link)) {
@@ -2392,8 +2865,8 @@ destroy_shell_surface(struct shell_surface *shsurf)
shell_surface_is_top_fullscreen(shsurf))
restore_output_mode (shsurf->fullscreen_output);
- if (shsurf->fullscreen.black_surface)
- weston_surface_destroy(shsurf->fullscreen.black_surface);
+ if (shsurf->fullscreen.black_view)
+ weston_surface_destroy(shsurf->fullscreen.black_view->surface);
/* As destroy_resource() use wl_list_for_each_safe(),
* we can always remove the listener.
@@ -2403,6 +2876,14 @@ destroy_shell_surface(struct shell_surface *shsurf)
ping_timer_destroy(shsurf);
free(shsurf->title);
+ weston_view_destroy(shsurf->view);
+
+ wl_list_remove(&shsurf->children_link);
+ wl_list_for_each_safe(child, next, &shsurf->children_list, children_link) {
+ wl_list_remove(&child->children_link);
+ child->parent = NULL;
+ }
+
wl_list_remove(&shsurf->link);
free(shsurf);
}
@@ -2429,9 +2910,11 @@ shell_handle_surface_destroy(struct wl_listener *listener, void *data)
}
static void
-shell_surface_configure(struct weston_surface *, int32_t, int32_t, int32_t, int32_t);
+shell_surface_configure(struct weston_surface *, int32_t, int32_t);
+static void
+shell_surface_output_destroyed(struct weston_surface *);
-static struct shell_surface *
+struct shell_surface *
get_shell_surface(struct weston_surface *surface)
{
if (surface->configure == shell_surface_configure)
@@ -2440,9 +2923,9 @@ get_shell_surface(struct weston_surface *surface)
return NULL;
}
-static struct shell_surface *
-create_shell_surface(void *shell, struct weston_surface *surface,
- const struct weston_shell_client *client)
+static struct shell_surface *
+create_common_surface(void *shell, struct weston_surface *surface,
+ const struct weston_shell_client *client)
{
struct shell_surface *shsurf;
@@ -2457,17 +2940,26 @@ create_shell_surface(void *shell, struct weston_surface *surface,
return NULL;
}
+ shsurf->view = weston_view_create(surface);
+ if (!shsurf->view) {
+ weston_log("no memory to allocate shell surface\n");
+ free(shsurf);
+ return NULL;
+ }
+
surface->configure = shell_surface_configure;
surface->configure_private = shsurf;
+ surface->output_destroyed = shell_surface_output_destroyed;
shsurf->shell = (struct desktop_shell *) shell;
shsurf->unresponsive = 0;
shsurf->saved_position_valid = false;
+ shsurf->saved_size_valid = false;
shsurf->saved_rotation_valid = false;
shsurf->surface = surface;
shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
shsurf->fullscreen.framerate = 0;
- shsurf->fullscreen.black_surface = NULL;
+ shsurf->fullscreen.black_view = NULL;
shsurf->ping_timer = NULL;
wl_list_init(&shsurf->fullscreen.transform.link);
@@ -2486,14 +2978,30 @@ create_shell_surface(void *shell, struct weston_surface *surface,
wl_list_init(&shsurf->workspace_transform.link);
+ wl_list_init(&shsurf->children_link);
+ wl_list_init(&shsurf->children_list);
+ shsurf->parent = NULL;
+
shsurf->type = SHELL_SURFACE_NONE;
- shsurf->next_type = SHELL_SURFACE_NONE;
shsurf->client = client;
return shsurf;
}
+static struct shell_surface *
+create_shell_surface(void *shell, struct weston_surface *surface,
+ const struct weston_shell_client *client)
+{
+ return create_common_surface(shell, surface, client);
+}
+
+static struct weston_view *
+get_primary_view(void *shell, struct shell_surface *shsurf)
+{
+ return shsurf->view;
+}
+
static void
shell_get_shell_surface(struct wl_client *client,
struct wl_resource *resource,
@@ -2528,10 +3036,427 @@ shell_get_shell_surface(struct wl_client *client,
shsurf, shell_destroy_shell_surface);
}
+static bool
+shell_surface_is_wl_shell_surface(struct shell_surface *shsurf)
+{
+ return wl_resource_instance_of(shsurf->resource,
+ &wl_shell_surface_interface,
+ &shell_surface_implementation);
+}
+
static const struct wl_shell_interface shell_implementation = {
shell_get_shell_surface
};
+/****************************
+ * xdg-shell implementation */
+
+static void
+xdg_surface_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+xdg_surface_pong(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t serial)
+{
+ struct shell_surface *shsurf = wl_resource_get_user_data(resource);
+
+ surface_pong(shsurf, serial);
+}
+
+static void
+xdg_surface_set_app_id(struct wl_client *client,
+ struct wl_resource *resource,
+ const char *app_id)
+{
+ struct shell_surface *shsurf = wl_resource_get_user_data(resource);
+
+ free(shsurf->class);
+ shsurf->class = strdup(app_id);
+}
+
+static void
+xdg_surface_set_title(struct wl_client *client,
+ struct wl_resource *resource, const char *title)
+{
+ struct shell_surface *shsurf = wl_resource_get_user_data(resource);
+
+ set_title(shsurf, title);
+}
+
+static void
+xdg_surface_move(struct wl_client *client, struct wl_resource *resource,
+ struct wl_resource *seat_resource, uint32_t serial)
+{
+ common_surface_move(resource, seat_resource, serial);
+}
+
+static void
+xdg_surface_resize(struct wl_client *client, struct wl_resource *resource,
+ struct wl_resource *seat_resource, uint32_t serial,
+ uint32_t edges)
+{
+ common_surface_resize(resource, seat_resource, serial, edges);
+}
+
+static void
+xdg_surface_set_output(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *output_resource)
+{
+ struct shell_surface *shsurf = wl_resource_get_user_data(resource);
+ struct weston_output *output;
+
+ if (output_resource)
+ output = wl_resource_get_user_data(output_resource);
+ else
+ output = NULL;
+
+ shsurf->recommended_output = output;
+}
+
+static void
+xdg_surface_set_fullscreen(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct shell_surface *shsurf = wl_resource_get_user_data(resource);
+
+ if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
+ return;
+
+ if (!shsurf->next_state.fullscreen)
+ set_fullscreen(shsurf,
+ WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
+ 0, shsurf->recommended_output);
+}
+
+static void
+xdg_surface_unset_fullscreen(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct shell_surface *shsurf = wl_resource_get_user_data(resource);
+ int32_t width, height;
+
+ if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
+ return;
+
+ if (!shsurf->next_state.fullscreen)
+ return;
+
+ shsurf->next_state.fullscreen = false;
+ shsurf->state_changed = true;
+
+ if (shsurf->saved_size_valid) {
+ width = shsurf->saved_width;
+ height = shsurf->saved_height;
+ shsurf->saved_size_valid = false;
+ } else {
+ width = shsurf->surface->width;
+ height = shsurf->surface->height;
+ }
+
+ shsurf->client->send_configure(shsurf->surface, 0, width, height);
+}
+
+static void
+xdg_surface_set_maximized(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct shell_surface *shsurf = wl_resource_get_user_data(resource);
+
+ if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
+ return;
+
+ if (!shsurf->next_state.maximized)
+ set_maximized(shsurf, NULL);
+}
+
+static void
+xdg_surface_unset_maximized(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct shell_surface *shsurf = wl_resource_get_user_data(resource);
+ int32_t width, height;
+
+ if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
+ return;
+
+ if (!shsurf->next_state.maximized)
+ return;
+
+ shsurf->next_state.maximized = false;
+ shsurf->state_changed = true;
+
+ if (shsurf->saved_size_valid) {
+ width = shsurf->saved_width;
+ height = shsurf->saved_height;
+ shsurf->saved_size_valid = false;
+ } else {
+ width = shsurf->surface->width;
+ height = shsurf->surface->height;
+ }
+
+ shsurf->client->send_configure(shsurf->surface, 0, width, height);
+}
+
+static const struct xdg_surface_interface xdg_surface_implementation = {
+ xdg_surface_destroy,
+ xdg_surface_set_transient_for,
+ xdg_surface_set_title,
+ xdg_surface_set_app_id,
+ xdg_surface_pong,
+ xdg_surface_move,
+ xdg_surface_resize,
+ xdg_surface_set_output,
+ xdg_surface_set_fullscreen,
+ xdg_surface_unset_fullscreen,
+ xdg_surface_set_maximized,
+ xdg_surface_unset_maximized,
+ NULL /* set_minimized */
+};
+
+static void
+xdg_send_configure(struct weston_surface *surface,
+ uint32_t edges, int32_t width, int32_t height)
+{
+ struct shell_surface *shsurf = get_shell_surface(surface);
+
+ xdg_surface_send_configure(shsurf->resource, edges, width, height);
+}
+
+static const struct weston_shell_client xdg_client = {
+ xdg_send_configure
+};
+
+static void
+xdg_use_unstable_version(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t version)
+{
+ if (version > 1) {
+ wl_resource_post_error(resource,
+ 1,
+ "xdg-shell:: version not implemented yet.");
+ return;
+ }
+}
+
+static struct shell_surface *
+create_xdg_surface(void *shell, struct weston_surface *surface,
+ const struct weston_shell_client *client)
+{
+ struct shell_surface *shsurf;
+
+ shsurf = create_common_surface(shell, surface, client);
+ shsurf->type = SHELL_SURFACE_TOPLEVEL;
+
+ return shsurf;
+}
+
+static void
+xdg_get_xdg_surface(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *surface_resource)
+{
+ struct weston_surface *surface =
+ wl_resource_get_user_data(surface_resource);
+ struct desktop_shell *shell = wl_resource_get_user_data(resource);
+ struct shell_surface *shsurf;
+
+ if (get_shell_surface(surface)) {
+ wl_resource_post_error(surface_resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "desktop_shell::get_shell_surface already requested");
+ return;
+ }
+
+ shsurf = create_xdg_surface(shell, surface, &xdg_client);
+ if (!shsurf) {
+ wl_resource_post_error(surface_resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "surface->configure already set");
+ return;
+ }
+
+ shsurf->resource =
+ wl_resource_create(client,
+ &xdg_surface_interface, 1, id);
+ wl_resource_set_implementation(shsurf->resource,
+ &xdg_surface_implementation,
+ shsurf, shell_destroy_shell_surface);
+}
+
+static bool
+shell_surface_is_xdg_surface(struct shell_surface *shsurf)
+{
+ return wl_resource_instance_of(shsurf->resource,
+ &xdg_surface_interface,
+ &xdg_surface_implementation);
+}
+
+/* xdg-popup implementation */
+
+static void
+xdg_popup_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+xdg_popup_pong(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t serial)
+{
+ struct shell_surface *shsurf = wl_resource_get_user_data(resource);
+
+ surface_pong(shsurf, serial);
+}
+
+static const struct xdg_popup_interface xdg_popup_implementation = {
+ xdg_popup_destroy,
+ xdg_popup_pong
+};
+
+static void
+xdg_popup_send_configure(struct weston_surface *surface,
+ uint32_t edges, int32_t width, int32_t height)
+{
+}
+
+static const struct weston_shell_client xdg_popup_client = {
+ xdg_popup_send_configure
+};
+
+static struct shell_surface *
+create_xdg_popup(void *shell, struct weston_surface *surface,
+ const struct weston_shell_client *client,
+ struct weston_surface *parent,
+ struct shell_seat *seat,
+ uint32_t serial,
+ int32_t x, int32_t y)
+{
+ struct shell_surface *shsurf;
+
+ shsurf = create_common_surface(shell, surface, client);
+ shsurf->type = SHELL_SURFACE_POPUP;
+ shsurf->popup.shseat = seat;
+ shsurf->popup.serial = serial;
+ shsurf->popup.x = x;
+ shsurf->popup.y = y;
+ shell_surface_set_parent(shsurf, parent);
+
+ return shsurf;
+}
+
+static void
+xdg_get_xdg_popup(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *surface_resource,
+ struct wl_resource *parent_resource,
+ struct wl_resource *seat_resource,
+ uint32_t serial,
+ int32_t x, int32_t y, uint32_t flags)
+{
+ struct weston_surface *surface =
+ wl_resource_get_user_data(surface_resource);
+ struct desktop_shell *shell = wl_resource_get_user_data(resource);
+ struct shell_surface *shsurf;
+ struct weston_surface *parent;
+ struct shell_seat *seat;
+
+ if (get_shell_surface(surface)) {
+ wl_resource_post_error(surface_resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "desktop_shell::get_shell_surface already requested");
+ return;
+ }
+
+ if (!parent_resource) {
+ wl_resource_post_error(surface_resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "xdg_shell::get_xdg_popup requires a parent shell surface");
+ }
+
+ parent = wl_resource_get_user_data(parent_resource);
+ seat = get_shell_seat(wl_resource_get_user_data(seat_resource));;
+
+ shsurf = create_xdg_popup(shell, surface, &xdg_popup_client,
+ parent, seat, serial, x, y);
+ if (!shsurf) {
+ wl_resource_post_error(surface_resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "surface->configure already set");
+ return;
+ }
+
+ shsurf->resource =
+ wl_resource_create(client,
+ &xdg_popup_interface, 1, id);
+ wl_resource_set_implementation(shsurf->resource,
+ &xdg_popup_implementation,
+ shsurf, shell_destroy_shell_surface);
+}
+
+static bool
+shell_surface_is_xdg_popup(struct shell_surface *shsurf)
+{
+ return wl_resource_instance_of(shsurf->resource,
+ &xdg_popup_interface,
+ &xdg_popup_implementation);
+}
+
+static const struct xdg_shell_interface xdg_implementation = {
+ xdg_use_unstable_version,
+ xdg_get_xdg_surface,
+ xdg_get_xdg_popup
+};
+
+static int
+xdg_shell_unversioned_dispatch(const void *implementation,
+ void *_target, uint32_t opcode,
+ const struct wl_message *message,
+ union wl_argument *args)
+{
+ struct wl_resource *resource = _target;
+ struct desktop_shell *shell = wl_resource_get_user_data(resource);
+
+ if (opcode != 0) {
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "must call use_unstable_version first");
+ return 0;
+ }
+
+#define XDG_SERVER_VERSION 1
+
+ static_assert(XDG_SERVER_VERSION == XDG_SHELL_VERSION_CURRENT,
+ "shell implementation doesn't match protocol version");
+
+ if (args[0].i != XDG_SERVER_VERSION) {
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "incompatible version, server is %d "
+ "client wants %d",
+ XDG_SERVER_VERSION, args[0].i);
+ return 0;
+ }
+
+ wl_resource_set_implementation(resource, &xdg_implementation,
+ shell, NULL);
+
+ return 1;
+}
+
+/* end of xdg-shell implementation */
+/***********************************/
+
static void
shell_fade(struct desktop_shell *shell, enum fade_type type);
@@ -2589,34 +3514,34 @@ terminate_screensaver(struct desktop_shell *shell)
}
static void
-configure_static_surface(struct weston_surface *es, struct weston_layer *layer, int32_t width, int32_t height)
+configure_static_view(struct weston_view *ev, struct weston_layer *layer)
{
- struct weston_surface *s, *next;
+ struct weston_view *v, *next;
- if (width == 0)
- return;
-
- wl_list_for_each_safe(s, next, &layer->surface_list, layer_link) {
- if (s->output == es->output && s != es) {
- weston_surface_unmap(s);
- s->configure = NULL;
+ wl_list_for_each_safe(v, next, &layer->view_list, layer_link) {
+ if (v->output == ev->output && v != ev) {
+ weston_view_unmap(v);
+ v->surface->configure = NULL;
}
}
- weston_surface_configure(es, es->output->x, es->output->y, width, height);
+ weston_view_set_position(ev, ev->output->x, ev->output->y);
- if (wl_list_empty(&es->layer_link)) {
- wl_list_insert(&layer->surface_list, &es->layer_link);
- weston_compositor_schedule_repaint(es->compositor);
+ if (wl_list_empty(&ev->layer_link)) {
+ wl_list_insert(&layer->view_list, &ev->layer_link);
+ weston_compositor_schedule_repaint(ev->surface->compositor);
}
}
static void
-background_configure(struct weston_surface *es, int32_t sx, int32_t sy, int32_t width, int32_t height)
+background_configure(struct weston_surface *es, int32_t sx, int32_t sy)
{
struct desktop_shell *shell = es->configure_private;
+ struct weston_view *view;
+
+ view = container_of(es->views.next, struct weston_view, surface_link);
- configure_static_surface(es, &shell->background_layer, width, height);
+ configure_static_view(view, &shell->background_layer);
}
static void
@@ -2628,6 +3553,7 @@ desktop_shell_set_background(struct wl_client *client,
struct desktop_shell *shell = wl_resource_get_user_data(resource);
struct weston_surface *surface =
wl_resource_get_user_data(surface_resource);
+ struct weston_view *view, *next;
if (surface->configure) {
wl_resource_post_error(surface_resource,
@@ -2636,9 +3562,14 @@ desktop_shell_set_background(struct wl_client *client,
return;
}
+ wl_list_for_each_safe(view, next, &surface->views, surface_link)
+ weston_view_destroy(view);
+ view = weston_view_create(surface);
+
surface->configure = background_configure;
surface->configure_private = shell;
surface->output = wl_resource_get_user_data(output_resource);
+ view->output = surface->output;
desktop_shell_send_configure(resource, 0,
surface_resource,
surface->output->width,
@@ -2646,11 +3577,14 @@ desktop_shell_set_background(struct wl_client *client,
}
static void
-panel_configure(struct weston_surface *es, int32_t sx, int32_t sy, int32_t width, int32_t height)
+panel_configure(struct weston_surface *es, int32_t sx, int32_t sy)
{
struct desktop_shell *shell = es->configure_private;
+ struct weston_view *view;
+
+ view = container_of(es->views.next, struct weston_view, surface_link);
- configure_static_surface(es, &shell->panel_layer, width, height);
+ configure_static_view(view, &shell->panel_layer);
}
static void
@@ -2662,6 +3596,7 @@ desktop_shell_set_panel(struct wl_client *client,
struct desktop_shell *shell = wl_resource_get_user_data(resource);
struct weston_surface *surface =
wl_resource_get_user_data(surface_resource);
+ struct weston_view *view, *next;
if (surface->configure) {
wl_resource_post_error(surface_resource,
@@ -2670,9 +3605,14 @@ desktop_shell_set_panel(struct wl_client *client,
return;
}
+ wl_list_for_each_safe(view, next, &surface->views, surface_link)
+ weston_view_destroy(view);
+ view = weston_view_create(surface);
+
surface->configure = panel_configure;
surface->configure_private = shell;
surface->output = wl_resource_get_user_data(output_resource);
+ view->output = surface->output;
desktop_shell_send_configure(resource, 0,
surface_resource,
surface->output->width,
@@ -2680,21 +3620,22 @@ desktop_shell_set_panel(struct wl_client *client,
}
static void
-lock_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy, int32_t width, int32_t height)
+lock_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
{
struct desktop_shell *shell = surface->configure_private;
+ struct weston_view *view;
+
+ view = container_of(surface->views.next, struct weston_view, surface_link);
- if (width == 0)
+ if (surface->width == 0)
return;
- surface->geometry.width = width;
- surface->geometry.height = height;
- center_on_output(surface, get_default_output(shell->compositor));
+ center_on_output(view, get_default_output(shell->compositor));
if (!weston_surface_is_mapped(surface)) {
- wl_list_insert(&shell->lock_layer.surface_list,
- &surface->layer_link);
- weston_surface_update_transform(surface);
+ wl_list_insert(&shell->lock_layer.view_list,
+ &view->layer_link);
+ weston_view_update_transform(view);
shell_fade(shell, FADE_IN);
}
}
@@ -2729,6 +3670,7 @@ desktop_shell_set_lock_surface(struct wl_client *client,
wl_signal_add(&surface->destroy_signal,
&shell->lock_surface_listener);
+ weston_view_create(surface);
surface->configure = lock_surface_configure;
surface->configure_private = shell;
}
@@ -2781,6 +3723,7 @@ desktop_shell_set_grab_surface(struct wl_client *client,
struct desktop_shell *shell = wl_resource_get_user_data(resource);
shell->grab_surface = wl_resource_get_user_data(surface_resource);
+ weston_view_create(shell->grab_surface);
}
static void
@@ -2815,28 +3758,79 @@ get_shell_surface_type(struct weston_surface *surface)
static void
move_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
{
- struct weston_surface *focus =
- (struct weston_surface *) seat->pointer->focus;
+ struct weston_surface *focus;
struct weston_surface *surface;
struct shell_surface *shsurf;
+ if (seat->pointer->focus == NULL)
+ return;
+
+ focus = seat->pointer->focus->surface;
+
surface = weston_surface_get_main_surface(focus);
if (surface == NULL)
return;
shsurf = get_shell_surface(surface);
- if (shsurf == NULL || shsurf->type == SHELL_SURFACE_FULLSCREEN ||
- shsurf->type == SHELL_SURFACE_MAXIMIZED)
+ if (shsurf == NULL || shsurf->state.fullscreen ||
+ shsurf->state.maximized)
return;
surface_move(shsurf, (struct weston_seat *) seat);
}
static void
+maximize_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
+{
+ struct weston_surface *focus = seat->pointer->focus->surface;
+ struct weston_surface *surface;
+ struct shell_surface *shsurf;
+
+ surface = weston_surface_get_main_surface(focus);
+ if (surface == NULL)
+ return;
+
+ shsurf = get_shell_surface(surface);
+ if (shsurf == NULL)
+ return;
+
+ if (!shell_surface_is_xdg_surface(shsurf))
+ return;
+
+ if (shsurf->state.maximized)
+ xdg_surface_send_request_unset_maximized(shsurf->resource);
+ else
+ xdg_surface_send_request_set_maximized(shsurf->resource);
+}
+
+static void
+fullscreen_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
+{
+ struct weston_surface *focus = seat->pointer->focus->surface;
+ struct weston_surface *surface;
+ struct shell_surface *shsurf;
+
+ surface = weston_surface_get_main_surface(focus);
+ if (surface == NULL)
+ return;
+
+ shsurf = get_shell_surface(surface);
+ if (shsurf == NULL)
+ return;
+
+ if (!shell_surface_is_xdg_surface(shsurf))
+ return;
+
+ if (shsurf->state.fullscreen)
+ xdg_surface_send_request_unset_fullscreen(shsurf->resource);
+ else
+ xdg_surface_send_request_set_fullscreen(shsurf->resource);
+}
+
+static void
touch_move_binding(struct weston_seat *seat, uint32_t time, void *data)
{
- struct weston_surface *focus =
- (struct weston_surface *) seat->touch->focus;
+ struct weston_surface *focus = seat->touch->focus->surface;
struct weston_surface *surface;
struct shell_surface *shsurf;
@@ -2845,8 +3839,8 @@ touch_move_binding(struct weston_seat *seat, uint32_t time, void *data)
return;
shsurf = get_shell_surface(surface);
- if (shsurf == NULL || shsurf->type == SHELL_SURFACE_FULLSCREEN ||
- shsurf->type == SHELL_SURFACE_MAXIMIZED)
+ if (shsurf == NULL || shsurf->state.fullscreen ||
+ shsurf->state.maximized)
return;
surface_touch_move(shsurf, (struct weston_seat *) seat);
@@ -2855,37 +3849,41 @@ touch_move_binding(struct weston_seat *seat, uint32_t time, void *data)
static void
resize_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
{
- struct weston_surface *focus =
- (struct weston_surface *) seat->pointer->focus;
+ struct weston_surface *focus;
struct weston_surface *surface;
uint32_t edges = 0;
int32_t x, y;
struct shell_surface *shsurf;
+ if (seat->pointer->focus == NULL)
+ return;
+
+ focus = seat->pointer->focus->surface;
+
surface = weston_surface_get_main_surface(focus);
if (surface == NULL)
return;
shsurf = get_shell_surface(surface);
- if (!shsurf || shsurf->type == SHELL_SURFACE_FULLSCREEN ||
- shsurf->type == SHELL_SURFACE_MAXIMIZED)
+ if (shsurf == NULL || shsurf->state.fullscreen ||
+ shsurf->state.maximized)
return;
- weston_surface_from_global(surface,
- wl_fixed_to_int(seat->pointer->grab_x),
- wl_fixed_to_int(seat->pointer->grab_y),
- &x, &y);
+ weston_view_from_global(shsurf->view,
+ wl_fixed_to_int(seat->pointer->grab_x),
+ wl_fixed_to_int(seat->pointer->grab_y),
+ &x, &y);
- if (x < surface->geometry.width / 3)
+ if (x < shsurf->surface->width / 3)
edges |= WL_SHELL_SURFACE_RESIZE_LEFT;
- else if (x < 2 * surface->geometry.width / 3)
+ else if (x < 2 * shsurf->surface->width / 3)
edges |= 0;
else
edges |= WL_SHELL_SURFACE_RESIZE_RIGHT;
- if (y < surface->geometry.height / 3)
+ if (y < shsurf->surface->height / 3)
edges |= WL_SHELL_SURFACE_RESIZE_TOP;
- else if (y < 2 * surface->geometry.height / 3)
+ else if (y < 2 * shsurf->surface->height / 3)
edges |= 0;
else
edges |= WL_SHELL_SURFACE_RESIZE_BOTTOM;
@@ -2899,8 +3897,7 @@ surface_opacity_binding(struct weston_seat *seat, uint32_t time, uint32_t axis,
{
float step = 0.005;
struct shell_surface *shsurf;
- struct weston_surface *focus =
- (struct weston_surface *) seat->pointer->focus;
+ struct weston_surface *focus = seat->pointer->focus->surface;
struct weston_surface *surface;
/* XXX: broken for windows containing sub-surfaces */
@@ -2912,14 +3909,14 @@ surface_opacity_binding(struct weston_seat *seat, uint32_t time, uint32_t axis,
if (!shsurf)
return;
- surface->alpha -= wl_fixed_to_double(value) * step;
+ shsurf->view->alpha -= wl_fixed_to_double(value) * step;
- if (surface->alpha > 1.0)
- surface->alpha = 1.0;
- if (surface->alpha < step)
- surface->alpha = step;
+ if (shsurf->view->alpha > 1.0)
+ shsurf->view->alpha = 1.0;
+ if (shsurf->view->alpha < step)
+ shsurf->view->alpha = step;
- weston_surface_geometry_dirty(surface);
+ weston_view_geometry_dirty(shsurf->view);
weston_surface_damage(surface);
}
@@ -2955,13 +3952,12 @@ do_zoom(struct weston_seat *seat, uint32_t time, uint32_t key, uint32_t axis,
else if (output->zoom.level > output->zoom.max_level)
output->zoom.level = output->zoom.max_level;
else if (!output->zoom.active) {
- output->zoom.active = 1;
- output->disable_planes++;
+ weston_output_activate_zoom(output);
}
output->zoom.spring_z.target = output->zoom.level;
- weston_output_update_zoom(output, output->zoom.type);
+ weston_output_update_zoom(output);
}
}
}
@@ -2990,29 +3986,29 @@ terminate_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
}
static void
-rotate_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
+rotate_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
+ wl_fixed_t x, wl_fixed_t y)
{
struct rotate_grab *rotate =
container_of(grab, struct rotate_grab, base.grab);
struct weston_pointer *pointer = grab->pointer;
struct shell_surface *shsurf = rotate->base.shsurf;
- struct weston_surface *surface;
float cx, cy, dx, dy, cposx, cposy, dposx, dposy, r;
+ weston_pointer_move(pointer, x, y);
+
if (!shsurf)
return;
- surface = shsurf->surface;
-
- cx = 0.5f * surface->geometry.width;
- cy = 0.5f * surface->geometry.height;
+ cx = 0.5f * shsurf->surface->width;
+ cy = 0.5f * shsurf->surface->height;
dx = wl_fixed_to_double(pointer->x) - rotate->center.x;
dy = wl_fixed_to_double(pointer->y) - rotate->center.y;
r = sqrtf(dx * dx + dy * dy);
wl_list_remove(&shsurf->rotation.transform.link);
- weston_surface_geometry_dirty(shsurf->surface);
+ weston_view_geometry_dirty(shsurf->view);
if (r > 20.0f) {
struct weston_matrix *matrix =
@@ -3028,7 +4024,7 @@ rotate_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
weston_matrix_translate(matrix, cx, cy, 0.0f);
wl_list_insert(
- &shsurf->surface->geometry.transformation_list,
+ &shsurf->view->geometry.transformation_list,
&shsurf->rotation.transform.link);
} else {
wl_list_init(&shsurf->rotation.transform.link);
@@ -3038,14 +4034,14 @@ rotate_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
/* We need to adjust the position of the surface
* in case it was resized in a rotated state before */
- cposx = surface->geometry.x + cx;
- cposy = surface->geometry.y + cy;
+ cposx = shsurf->view->geometry.x + cx;
+ cposy = shsurf->view->geometry.y + cy;
dposx = rotate->center.x - cposx;
dposy = rotate->center.y - cposy;
if (dposx != 0.0f || dposy != 0.0f) {
- weston_surface_set_position(surface,
- surface->geometry.x + dposx,
- surface->geometry.y + dposy);
+ weston_view_set_position(shsurf->view,
+ shsurf->view->geometry.x + dposx,
+ shsurf->view->geometry.y + dposy);
}
/* Repaint implies weston_surface_update_transform(), which
@@ -3102,10 +4098,10 @@ surface_rotate(struct shell_surface *surface, struct weston_seat *seat)
if (!rotate)
return;
- weston_surface_to_global_float(surface->surface,
- surface->surface->geometry.width * 0.5f,
- surface->surface->geometry.height * 0.5f,
- &rotate->center.x, &rotate->center.y);
+ weston_view_to_global_float(surface->view,
+ surface->surface->width * 0.5f,
+ surface->surface->height * 0.5f,
+ &rotate->center.x, &rotate->center.y);
dx = wl_fixed_to_double(seat->pointer->x) - rotate->center.x;
dy = wl_fixed_to_double(seat->pointer->y) - rotate->center.y;
@@ -3132,43 +4128,56 @@ static void
rotate_binding(struct weston_seat *seat, uint32_t time, uint32_t button,
void *data)
{
- struct weston_surface *focus =
- (struct weston_surface *) seat->pointer->focus;
+ struct weston_surface *focus;
struct weston_surface *base_surface;
struct shell_surface *surface;
+ if (seat->pointer->focus == NULL)
+ return;
+
+ focus = seat->pointer->focus->surface;
+
base_surface = weston_surface_get_main_surface(focus);
if (base_surface == NULL)
return;
surface = get_shell_surface(base_surface);
- if (!surface || surface->type == SHELL_SURFACE_FULLSCREEN ||
- surface->type == SHELL_SURFACE_MAXIMIZED)
+ if (surface == NULL || surface->state.fullscreen ||
+ surface->state.maximized)
return;
surface_rotate(surface, seat);
}
-static void
+/* Move all fullscreen layers down to the current workspace in a non-reversible
+ * manner. This should be used when implementing shell-wide overlays, such as
+ * the alt-tab switcher, which need to de-promote fullscreen layers. */
+void
lower_fullscreen_layer(struct desktop_shell *shell)
{
struct workspace *ws;
- struct weston_surface *surface, *prev;
+ struct weston_view *view, *prev;
ws = get_current_workspace(shell);
- wl_list_for_each_reverse_safe(surface, prev,
- &shell->fullscreen_layer.surface_list,
- layer_link)
- weston_surface_restack(surface, &ws->layer.surface_list);
+ wl_list_for_each_reverse_safe(view, prev,
+ &shell->fullscreen_layer.view_list,
+ layer_link) {
+ wl_list_remove(&view->layer_link);
+ wl_list_insert(&ws->layer.view_list, &view->layer_link);
+ weston_view_damage_below(view);
+ weston_surface_damage(view->surface);
+ }
}
-static void
+void
activate(struct desktop_shell *shell, struct weston_surface *es,
struct weston_seat *seat)
{
struct weston_surface *main_surface;
struct focus_state *state;
struct workspace *ws;
+ struct weston_surface *old_es;
+ struct shell_surface *shsurf;
main_surface = weston_surface_get_main_surface(es);
@@ -3178,27 +4187,30 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
if (state == NULL)
return;
+ old_es = state->keyboard_focus;
state->keyboard_focus = es;
wl_list_remove(&state->surface_destroy_listener.link);
wl_signal_add(&es->destroy_signal, &state->surface_destroy_listener);
- switch (get_shell_surface_type(main_surface)) {
- case SHELL_SURFACE_FULLSCREEN:
- /* should on top of panels */
- shell_stack_fullscreen(get_shell_surface(main_surface));
- shell_configure_fullscreen(get_shell_surface(main_surface));
- break;
- default:
+ shsurf = get_shell_surface(main_surface);
+ if (shsurf->state.fullscreen)
+ shell_configure_fullscreen(shsurf);
+ else
restore_all_output_modes(shell->compositor);
+
+ if (shell->focus_animation_type != ANIMATION_NONE) {
ws = get_current_workspace(shell);
- weston_surface_restack(main_surface, &ws->layer.surface_list);
- break;
+ animate_focus_change(shell, ws, get_default_view(old_es), get_default_view(es));
}
+
+ /* Update the surface’s layer. This brings it to the top of the stacking
+ * order as appropriate. */
+ shell_surface_update_layer(get_shell_surface(main_surface));
}
/* no-op func for checking black surface */
static void
-black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy, int32_t width, int32_t height)
+black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
{
}
@@ -3239,9 +4251,10 @@ click_to_activate_binding(struct weston_seat *seat, uint32_t time, uint32_t butt
{
if (seat->pointer->grab != &seat->pointer->default_grab)
return;
+ if (seat->pointer->focus == NULL)
+ return;
- activate_binding(seat, data,
- (struct weston_surface *) seat->pointer->focus);
+ activate_binding(seat, data, seat->pointer->focus->surface);
}
static void
@@ -3249,9 +4262,10 @@ touch_to_activate_binding(struct weston_seat *seat, uint32_t time, void *data)
{
if (seat->touch->grab != &seat->touch->default_grab)
return;
+ if (seat->touch->focus == NULL)
+ return;
- activate_binding(seat, data,
- (struct weston_surface *) seat->touch->focus);
+ activate_binding(seat, data, seat->touch->focus->surface);
}
static void
@@ -3307,7 +4321,7 @@ unlock(struct desktop_shell *shell)
}
static void
-shell_fade_done(struct weston_surface_animation *animation, void *data)
+shell_fade_done(struct weston_view_animation *animation, void *data)
{
struct desktop_shell *shell = data;
@@ -3315,32 +4329,42 @@ shell_fade_done(struct weston_surface_animation *animation, void *data)
switch (shell->fade.type) {
case FADE_IN:
- weston_surface_destroy(shell->fade.surface);
- shell->fade.surface = NULL;
+ weston_surface_destroy(shell->fade.view->surface);
+ shell->fade.view = NULL;
break;
case FADE_OUT:
lock(shell);
break;
+ default:
+ break;
}
}
-static struct weston_surface *
+static struct weston_view *
shell_fade_create_surface(struct desktop_shell *shell)
{
struct weston_compositor *compositor = shell->compositor;
struct weston_surface *surface;
+ struct weston_view *view;
surface = weston_surface_create(compositor);
if (!surface)
return NULL;
- weston_surface_configure(surface, 0, 0, 8192, 8192);
+ view = weston_view_create(surface);
+ if (!view) {
+ weston_surface_destroy(surface);
+ return NULL;
+ }
+
+ weston_surface_set_size(surface, 8192, 8192);
+ weston_view_set_position(view, 0, 0);
weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
- wl_list_insert(&compositor->fade_layer.surface_list,
- &surface->layer_link);
+ wl_list_insert(&compositor->fade_layer.view_list,
+ &view->layer_link);
pixman_region32_init(&surface->input);
- return surface;
+ return view;
}
static void
@@ -3362,20 +4386,20 @@ shell_fade(struct desktop_shell *shell, enum fade_type type)
shell->fade.type = type;
- if (shell->fade.surface == NULL) {
- shell->fade.surface = shell_fade_create_surface(shell);
- if (!shell->fade.surface)
+ if (shell->fade.view == NULL) {
+ shell->fade.view = shell_fade_create_surface(shell);
+ if (!shell->fade.view)
return;
- shell->fade.surface->alpha = 1.0 - tint;
- weston_surface_update_transform(shell->fade.surface);
+ shell->fade.view->alpha = 1.0 - tint;
+ weston_view_update_transform(shell->fade.view);
}
if (shell->fade.animation)
weston_fade_update(shell->fade.animation, tint);
else
shell->fade.animation =
- weston_fade_run(shell->fade.surface,
+ weston_fade_run(shell->fade.view,
1.0 - tint, tint, 300.0,
shell_fade_done, shell);
}
@@ -3388,8 +4412,8 @@ do_shell_fade_startup(void *data)
if (shell->startup_animation_type == ANIMATION_FADE)
shell_fade(shell, FADE_IN);
else if (shell->startup_animation_type == ANIMATION_NONE) {
- weston_surface_destroy(shell->fade.surface);
- shell->fade.surface = NULL;
+ weston_surface_destroy(shell->fade.view->surface);
+ shell->fade.view = NULL;
}
}
@@ -3427,18 +4451,18 @@ shell_fade_init(struct desktop_shell *shell)
struct wl_event_loop *loop;
- if (shell->fade.surface != NULL) {
+ if (shell->fade.view != NULL) {
weston_log("%s: warning: fade surface already exists\n",
__func__);
return;
}
- shell->fade.surface = shell_fade_create_surface(shell);
- if (!shell->fade.surface)
+ shell->fade.view = shell_fade_create_surface(shell);
+ if (!shell->fade.view)
return;
- weston_surface_update_transform(shell->fade.surface);
- weston_surface_damage(shell->fade.surface);
+ weston_view_update_transform(shell->fade.view);
+ weston_surface_damage(shell->fade.view->surface);
loop = wl_display_get_event_loop(shell->compositor->wl_display);
shell->fade.startup_timer =
@@ -3466,87 +4490,22 @@ wake_handler(struct wl_listener *listener, void *data)
}
static void
-show_input_panels(struct wl_listener *listener, void *data)
-{
- struct desktop_shell *shell =
- container_of(listener, struct desktop_shell,
- show_input_panel_listener);
- struct input_panel_surface *surface, *next;
- struct weston_surface *ws;
-
- shell->text_input.surface = (struct weston_surface*)data;
-
- if (shell->showing_input_panels)
- return;
-
- shell->showing_input_panels = true;
-
- if (!shell->locked)
- wl_list_insert(&shell->panel_layer.link,
- &shell->input_panel_layer.link);
-
- wl_list_for_each_safe(surface, next,
- &shell->input_panel.surfaces, link) {
- ws = surface->surface;
- if (!ws->buffer_ref.buffer)
- continue;
- wl_list_insert(&shell->input_panel_layer.surface_list,
- &ws->layer_link);
- weston_surface_geometry_dirty(ws);
- weston_surface_update_transform(ws);
- weston_surface_damage(ws);
- weston_slide_run(ws, ws->geometry.height, 0, NULL, NULL);
- }
-}
-
-static void
-hide_input_panels(struct wl_listener *listener, void *data)
-{
- struct desktop_shell *shell =
- container_of(listener, struct desktop_shell,
- hide_input_panel_listener);
- struct weston_surface *surface, *next;
-
- if (!shell->showing_input_panels)
- return;
-
- shell->showing_input_panels = false;
-
- if (!shell->locked)
- wl_list_remove(&shell->input_panel_layer.link);
-
- wl_list_for_each_safe(surface, next,
- &shell->input_panel_layer.surface_list, layer_link)
- weston_surface_unmap(surface);
-}
-
-static void
-update_input_panels(struct wl_listener *listener, void *data)
-{
- struct desktop_shell *shell =
- container_of(listener, struct desktop_shell,
- update_input_panel_listener);
-
- memcpy(&shell->text_input.cursor_rectangle, data, sizeof(pixman_box32_t));
-}
-
-static void
-center_on_output(struct weston_surface *surface, struct weston_output *output)
+center_on_output(struct weston_view *view, struct weston_output *output)
{
int32_t surf_x, surf_y, width, height;
float x, y;
- surface_subsurfaces_boundingbox(surface, &surf_x, &surf_y, &width, &height);
+ surface_subsurfaces_boundingbox(view->surface, &surf_x, &surf_y, &width, &height);
x = output->x + (output->width - width) / 2 - surf_x / 2;
y = output->y + (output->height - height) / 2 - surf_y / 2;
- weston_surface_configure(surface, x, y, width, height);
+ weston_view_set_position(view, x, y);
}
static void
-weston_surface_set_initial_position (struct weston_surface *surface,
- struct desktop_shell *shell)
+weston_view_set_initial_position(struct weston_view *view,
+ struct desktop_shell *shell)
{
struct weston_compositor *compositor = shell->compositor;
int ix = 0, iy = 0;
@@ -3576,8 +4535,8 @@ weston_surface_set_initial_position (struct weston_surface *surface,
}
if (!target_output) {
- weston_surface_set_position(surface, 10 + random() % 400,
- 10 + random() % 400);
+ weston_view_set_position(view, 10 + random() % 400,
+ 10 + random() % 400);
return;
}
@@ -3586,9 +4545,9 @@ weston_surface_set_initial_position (struct weston_surface *surface,
* output.
*/
panel_height = get_output_panel_height(shell, target_output);
- range_x = target_output->width - surface->geometry.width;
+ range_x = target_output->width - view->surface->width;
range_y = (target_output->height - panel_height) -
- surface->geometry.height;
+ view->surface->height;
if (range_x > 0)
dx = random() % range_x;
@@ -3603,106 +4562,97 @@ weston_surface_set_initial_position (struct weston_surface *surface,
x = target_output->x + dx;
y = target_output->y + dy;
- weston_surface_set_position (surface, x, y);
+ weston_view_set_position(view, x, y);
}
static void
-map(struct desktop_shell *shell, struct weston_surface *surface,
- int32_t width, int32_t height, int32_t sx, int32_t sy)
+map(struct desktop_shell *shell, struct shell_surface *shsurf,
+ int32_t sx, int32_t sy)
{
struct weston_compositor *compositor = shell->compositor;
- struct shell_surface *shsurf = get_shell_surface(surface);
- enum shell_surface_type surface_type = shsurf->type;
- struct weston_surface *parent;
struct weston_seat *seat;
- struct workspace *ws;
int panel_height = 0;
int32_t surf_x, surf_y;
- surface->geometry.width = width;
- surface->geometry.height = height;
- weston_surface_geometry_dirty(surface);
-
/* initial positioning, see also configure() */
- switch (surface_type) {
+ switch (shsurf->type) {
case SHELL_SURFACE_TOPLEVEL:
- weston_surface_set_initial_position(surface, shell);
- break;
- case SHELL_SURFACE_FULLSCREEN:
- center_on_output(surface, shsurf->fullscreen_output);
- shell_map_fullscreen(shsurf);
- break;
- case SHELL_SURFACE_MAXIMIZED:
- /* use surface configure to set the geometry */
- panel_height = get_output_panel_height(shell,surface->output);
- surface_subsurfaces_boundingbox(shsurf->surface, &surf_x, &surf_y,
- NULL, NULL);
- weston_surface_set_position(surface, shsurf->output->x - surf_x,
- shsurf->output->y + panel_height - surf_y);
+ if (shsurf->state.fullscreen) {
+ center_on_output(shsurf->view, shsurf->fullscreen_output);
+ shell_map_fullscreen(shsurf);
+ } else if (shsurf->state.maximized) {
+ /* use surface configure to set the geometry */
+ panel_height = get_output_panel_height(shell, shsurf->output);
+ surface_subsurfaces_boundingbox(shsurf->surface,
+ &surf_x, &surf_y, NULL, NULL);
+ weston_view_set_position(shsurf->view,
+ shsurf->output->x - surf_x,
+ shsurf->output->y +
+ panel_height - surf_y);
+ } else if (!shsurf->state.relative) {
+ weston_view_set_initial_position(shsurf->view, shell);
+ }
break;
case SHELL_SURFACE_POPUP:
shell_map_popup(shsurf);
break;
case SHELL_SURFACE_NONE:
- weston_surface_set_position(surface,
- surface->geometry.x + sx,
- surface->geometry.y + sy);
+ weston_view_set_position(shsurf->view,
+ shsurf->view->geometry.x + sx,
+ shsurf->view->geometry.y + sy);
break;
+ case SHELL_SURFACE_XWAYLAND:
default:
;
}
- /* surface stacking order, see also activate() */
- switch (surface_type) {
- case SHELL_SURFACE_POPUP:
- case SHELL_SURFACE_TRANSIENT:
- parent = shsurf->parent;
- wl_list_insert(parent->layer_link.prev, &surface->layer_link);
- break;
- case SHELL_SURFACE_FULLSCREEN:
- case SHELL_SURFACE_NONE:
- break;
- case SHELL_SURFACE_XWAYLAND:
- default:
- ws = get_current_workspace(shell);
- wl_list_insert(&ws->layer.surface_list, &surface->layer_link);
- break;
+ /* Surface stacking order, see also activate(). */
+ shell_surface_update_layer(shsurf);
+
+ if (shsurf->type != SHELL_SURFACE_NONE) {
+ weston_view_update_transform(shsurf->view);
+ if (shsurf->state.maximized) {
+ shsurf->surface->output = shsurf->output;
+ shsurf->view->output = shsurf->output;
+ }
}
- if (surface_type != SHELL_SURFACE_NONE) {
- weston_surface_update_transform(surface);
- if (surface_type == SHELL_SURFACE_MAXIMIZED)
- surface->output = shsurf->output;
+ if ((shsurf->type == SHELL_SURFACE_XWAYLAND || shsurf->state.relative) &&
+ shsurf->transient.flags == WL_SHELL_SURFACE_TRANSIENT_INACTIVE) {
}
- switch (surface_type) {
+ switch (shsurf->type) {
/* XXX: xwayland's using the same fields for transient type */
case SHELL_SURFACE_XWAYLAND:
- case SHELL_SURFACE_TRANSIENT:
if (shsurf->transient.flags ==
WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
break;
case SHELL_SURFACE_TOPLEVEL:
- case SHELL_SURFACE_FULLSCREEN:
- case SHELL_SURFACE_MAXIMIZED:
- if (!shell->locked) {
- wl_list_for_each(seat, &compositor->seat_list, link)
- activate(shell, surface, seat);
- }
+ if (shsurf->state.relative &&
+ shsurf->transient.flags == WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
+ break;
+ if (shell->locked)
+ break;
+ wl_list_for_each(seat, &compositor->seat_list, link)
+ activate(shell, shsurf->surface, seat);
break;
+ case SHELL_SURFACE_POPUP:
+ case SHELL_SURFACE_NONE:
default:
break;
}
- if (surface_type == SHELL_SURFACE_TOPLEVEL)
+ if (shsurf->type == SHELL_SURFACE_TOPLEVEL &&
+ !shsurf->state.maximized && !shsurf->state.fullscreen)
{
switch (shell->win_animation_type) {
case ANIMATION_FADE:
- weston_fade_run(surface, 0.0, 1.0, 300.0, NULL, NULL);
+ weston_fade_run(shsurf->view, 0.0, 1.0, 300.0, NULL, NULL);
break;
case ANIMATION_ZOOM:
- weston_zoom_run(surface, 0.5, 1.0, NULL, NULL);
+ weston_zoom_run(shsurf->view, 0.5, 1.0, NULL, NULL);
break;
+ case ANIMATION_NONE:
default:
break;
}
@@ -3711,48 +4661,40 @@ map(struct desktop_shell *shell, struct weston_surface *surface,
static void
configure(struct desktop_shell *shell, struct weston_surface *surface,
- float x, float y, int32_t width, int32_t height)
+ float x, float y)
{
- enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
struct shell_surface *shsurf;
- int32_t surf_x, surf_y;
+ struct weston_view *view;
+ int32_t mx, my, surf_x, surf_y;
shsurf = get_shell_surface(surface);
- if (shsurf)
- surface_type = shsurf->type;
-
- weston_surface_configure(surface, x, y, width, height);
- switch (surface_type) {
- case SHELL_SURFACE_FULLSCREEN:
- shell_stack_fullscreen(shsurf);
+ if (shsurf->state.fullscreen)
shell_configure_fullscreen(shsurf);
- break;
- case SHELL_SURFACE_MAXIMIZED:
+ else if (shsurf->state.maximized) {
/* setting x, y and using configure to change that geometry */
surface_subsurfaces_boundingbox(shsurf->surface, &surf_x, &surf_y,
NULL, NULL);
- surface->geometry.x = surface->output->x - surf_x;
- surface->geometry.y = surface->output->y +
- get_output_panel_height(shell,surface->output) - surf_y;
- break;
- case SHELL_SURFACE_TOPLEVEL:
- break;
- default:
- break;
+ mx = shsurf->output->x - surf_x;
+ my = shsurf->output->y +
+ get_output_panel_height(shell,shsurf->output) - surf_y;
+ weston_view_set_position(shsurf->view, mx, my);
+ } else {
+ weston_view_set_position(shsurf->view, x, y);
}
/* XXX: would a fullscreen surface need the same handling? */
if (surface->output) {
- weston_surface_update_transform(surface);
+ wl_list_for_each(view, &surface->views, surface_link)
+ weston_view_update_transform(view);
- if (surface_type == SHELL_SURFACE_MAXIMIZED)
+ if (shsurf->state.maximized)
surface->output = shsurf->output;
}
}
static void
-shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy, int32_t width, int32_t height)
+shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
{
struct shell_surface *shsurf = get_shell_surface(es);
struct desktop_shell *shell = shsurf->shell;
@@ -3764,32 +4706,43 @@ shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy, int32
remove_popup_grab(shsurf);
}
- if (width == 0)
+ if (es->width == 0)
return;
- if (shsurf->next_type != SHELL_SURFACE_NONE &&
- shsurf->type != shsurf->next_type) {
+ if (shsurf->state_changed) {
set_surface_type(shsurf);
type_changed = 1;
}
if (!weston_surface_is_mapped(es)) {
- map(shell, es, width, height, sx, sy);
+ map(shell, shsurf, sx, sy);
} else if (type_changed || sx != 0 || sy != 0 ||
- es->geometry.width != width ||
- es->geometry.height != height) {
+ shsurf->last_width != es->width ||
+ shsurf->last_height != es->height) {
+ shsurf->last_width = es->width;
+ shsurf->last_height = es->height;
float from_x, from_y;
float to_x, to_y;
- weston_surface_to_global_float(es, 0, 0, &from_x, &from_y);
- weston_surface_to_global_float(es, sx, sy, &to_x, &to_y);
+ weston_view_to_global_float(shsurf->view, 0, 0, &from_x, &from_y);
+ weston_view_to_global_float(shsurf->view, sx, sy, &to_x, &to_y);
configure(shell, es,
- es->geometry.x + to_x - from_x,
- es->geometry.y + to_y - from_y,
- width, height);
+ shsurf->view->geometry.x + to_x - from_x,
+ shsurf->view->geometry.y + to_y - from_y);
}
}
+static void
+shell_surface_output_destroyed(struct weston_surface *es)
+{
+ struct shell_surface *shsurf = get_shell_surface(es);
+
+ shsurf->saved_position_valid = false;
+ shsurf->next_state.maximized = false;
+ shsurf->next_state.fullscreen = false;
+ shsurf->state_changed = true;
+}
+
static void launch_desktop_shell_process(void *data);
static void
@@ -3811,28 +4764,43 @@ desktop_shell_sigchld(struct weston_process *process, int status)
shell->child.deathcount++;
if (shell->child.deathcount > 5) {
- weston_log("weston-desktop-shell died, giving up.\n");
+ weston_log("%s died, giving up.\n", shell->client);
return;
}
- weston_log("weston-desktop-shell died, respawning...\n");
+ weston_log("%s died, respawning...\n", shell->client);
launch_desktop_shell_process(shell);
shell_fade_startup(shell);
}
static void
+desktop_shell_client_destroy(struct wl_listener *listener, void *data)
+{
+ struct desktop_shell *shell;
+
+ shell = container_of(listener, struct desktop_shell,
+ child.client_destroy_listener);
+
+ shell->child.client = NULL;
+}
+
+static void
launch_desktop_shell_process(void *data)
{
struct desktop_shell *shell = data;
- const char *shell_exe = LIBEXECDIR "/weston-desktop-shell";
shell->child.client = weston_client_launch(shell->compositor,
&shell->child.process,
- shell_exe,
+ shell->client,
desktop_shell_sigchld);
if (!shell->child.client)
- weston_log("not able to start %s\n", shell_exe);
+ weston_log("not able to start %s\n", shell->client);
+
+ shell->child.client_destroy_listener.notify =
+ desktop_shell_client_destroy;
+ wl_client_add_destroy_listener(shell->child.client,
+ &shell->child.client_destroy_listener);
}
static void
@@ -3848,6 +4816,19 @@ bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
}
static void
+bind_xdg_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+ struct desktop_shell *shell = data;
+ struct wl_resource *resource;
+
+ resource = wl_resource_create(client, &xdg_shell_interface, 1, id);
+ if (resource)
+ wl_resource_set_dispatcher(resource,
+ xdg_shell_unversioned_dispatch,
+ NULL, shell, NULL);
+}
+
+static void
unbind_desktop_shell(struct wl_resource *resource)
{
struct desktop_shell *shell = wl_resource_get_user_data(resource);
@@ -3887,23 +4868,25 @@ bind_desktop_shell(struct wl_client *client,
}
static void
-screensaver_configure(struct weston_surface *surface, int32_t sx, int32_t sy, int32_t width, int32_t height)
+screensaver_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
{
struct desktop_shell *shell = surface->configure_private;
+ struct weston_view *view;
- if (width == 0)
+ if (surface->width == 0)
return;
/* XXX: starting weston-screensaver beforehand does not work */
if (!shell->locked)
return;
- center_on_output(surface, surface->output);
+ view = container_of(surface->views.next, struct weston_view, surface_link);
+ center_on_output(view, surface->output);
- if (wl_list_empty(&surface->layer_link)) {
- wl_list_insert(shell->lock_layer.surface_list.prev,
- &surface->layer_link);
- weston_surface_update_transform(surface);
+ if (wl_list_empty(&view->layer_link)) {
+ wl_list_insert(shell->lock_layer.view_list.prev,
+ &view->layer_link);
+ weston_view_update_transform(view);
wl_event_source_timer_update(shell->screensaver.timer,
shell->screensaver.duration);
shell_fade(shell, FADE_IN);
@@ -3920,6 +4903,12 @@ screensaver_set_surface(struct wl_client *client,
struct weston_surface *surface =
wl_resource_get_user_data(surface_resource);
struct weston_output *output = wl_resource_get_user_data(output_resource);
+ struct weston_view *view, *next;
+
+ /* Make sure we only have one view */
+ wl_list_for_each_safe(view, next, &surface->views, surface_link)
+ weston_view_destroy(view);
+ weston_view_create(surface);
surface->configure = screensaver_configure;
surface->configure_private = shell;
@@ -3960,226 +4949,6 @@ bind_screensaver(struct wl_client *client,
wl_resource_destroy(resource);
}
-static void
-input_panel_configure(struct weston_surface *surface, int32_t sx, int32_t sy, int32_t width, int32_t height)
-{
- struct input_panel_surface *ip_surface = surface->configure_private;
- struct desktop_shell *shell = ip_surface->shell;
- float x, y;
- uint32_t show_surface = 0;
-
- if (width == 0)
- return;
-
- if (!weston_surface_is_mapped(surface)) {
- if (!shell->showing_input_panels)
- return;
-
- show_surface = 1;
- }
-
- fprintf(stderr, "%s panel: %d, output: %p\n", __FUNCTION__, ip_surface->panel, ip_surface->output);
-
- if (ip_surface->panel) {
- x = shell->text_input.surface->geometry.x + shell->text_input.cursor_rectangle.x2;
- y = shell->text_input.surface->geometry.y + shell->text_input.cursor_rectangle.y2;
- } else {
- x = ip_surface->output->x + (ip_surface->output->width - width) / 2;
- y = ip_surface->output->y + ip_surface->output->height - height;
- }
-
- weston_surface_configure(surface,
- x, y,
- width, height);
-
- if (show_surface) {
- wl_list_insert(&shell->input_panel_layer.surface_list,
- &surface->layer_link);
- weston_surface_update_transform(surface);
- weston_surface_damage(surface);
- weston_slide_run(surface, surface->geometry.height, 0, NULL, NULL);
- }
-}
-
-static void
-destroy_input_panel_surface(struct input_panel_surface *input_panel_surface)
-{
- wl_signal_emit(&input_panel_surface->destroy_signal, input_panel_surface);
-
- wl_list_remove(&input_panel_surface->surface_destroy_listener.link);
- wl_list_remove(&input_panel_surface->link);
-
- input_panel_surface->surface->configure = NULL;
-
- free(input_panel_surface);
-}
-
-static struct input_panel_surface *
-get_input_panel_surface(struct weston_surface *surface)
-{
- if (surface->configure == input_panel_configure) {
- return surface->configure_private;
- } else {
- return NULL;
- }
-}
-
-static void
-input_panel_handle_surface_destroy(struct wl_listener *listener, void *data)
-{
- struct input_panel_surface *ipsurface = container_of(listener,
- struct input_panel_surface,
- surface_destroy_listener);
-
- if (ipsurface->resource) {
- wl_resource_destroy(ipsurface->resource);
- } else {
- destroy_input_panel_surface(ipsurface);
- }
-}
-
-static struct input_panel_surface *
-create_input_panel_surface(struct desktop_shell *shell,
- struct weston_surface *surface)
-{
- struct input_panel_surface *input_panel_surface;
-
- input_panel_surface = calloc(1, sizeof *input_panel_surface);
- if (!input_panel_surface)
- return NULL;
-
- surface->configure = input_panel_configure;
- surface->configure_private = input_panel_surface;
-
- input_panel_surface->shell = shell;
-
- input_panel_surface->surface = surface;
-
- wl_signal_init(&input_panel_surface->destroy_signal);
- input_panel_surface->surface_destroy_listener.notify = input_panel_handle_surface_destroy;
- wl_signal_add(&surface->destroy_signal,
- &input_panel_surface->surface_destroy_listener);
-
- wl_list_init(&input_panel_surface->link);
-
- return input_panel_surface;
-}
-
-static void
-input_panel_surface_set_toplevel(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *output_resource,
- uint32_t position)
-{
- struct input_panel_surface *input_panel_surface =
- wl_resource_get_user_data(resource);
- struct desktop_shell *shell = input_panel_surface->shell;
-
- wl_list_insert(&shell->input_panel.surfaces,
- &input_panel_surface->link);
-
- input_panel_surface->output = wl_resource_get_user_data(output_resource);
- input_panel_surface->panel = 0;
-}
-
-static void
-input_panel_surface_set_overlay_panel(struct wl_client *client,
- struct wl_resource *resource)
-{
- struct input_panel_surface *input_panel_surface =
- wl_resource_get_user_data(resource);
- struct desktop_shell *shell = input_panel_surface->shell;
-
- wl_list_insert(&shell->input_panel.surfaces,
- &input_panel_surface->link);
-
- input_panel_surface->panel = 1;
-}
-
-static const struct wl_input_panel_surface_interface input_panel_surface_implementation = {
- input_panel_surface_set_toplevel,
- input_panel_surface_set_overlay_panel
-};
-
-static void
-destroy_input_panel_surface_resource(struct wl_resource *resource)
-{
- struct input_panel_surface *ipsurf =
- wl_resource_get_user_data(resource);
-
- destroy_input_panel_surface(ipsurf);
-}
-
-static void
-input_panel_get_input_panel_surface(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t id,
- struct wl_resource *surface_resource)
-{
- struct weston_surface *surface =
- wl_resource_get_user_data(surface_resource);
- struct desktop_shell *shell = wl_resource_get_user_data(resource);
- struct input_panel_surface *ipsurf;
-
- if (get_input_panel_surface(surface)) {
- wl_resource_post_error(surface_resource,
- WL_DISPLAY_ERROR_INVALID_OBJECT,
- "wl_input_panel::get_input_panel_surface already requested");
- return;
- }
-
- ipsurf = create_input_panel_surface(shell, surface);
- if (!ipsurf) {
- wl_resource_post_error(surface_resource,
- WL_DISPLAY_ERROR_INVALID_OBJECT,
- "surface->configure already set");
- return;
- }
-
- ipsurf->resource =
- wl_resource_create(client,
- &wl_input_panel_surface_interface, 1, id);
- wl_resource_set_implementation(ipsurf->resource,
- &input_panel_surface_implementation,
- ipsurf,
- destroy_input_panel_surface_resource);
-}
-
-static const struct wl_input_panel_interface input_panel_implementation = {
- input_panel_get_input_panel_surface
-};
-
-static void
-unbind_input_panel(struct wl_resource *resource)
-{
- struct desktop_shell *shell = wl_resource_get_user_data(resource);
-
- shell->input_panel.binding = NULL;
-}
-
-static void
-bind_input_panel(struct wl_client *client,
- void *data, uint32_t version, uint32_t id)
-{
- struct desktop_shell *shell = data;
- struct wl_resource *resource;
-
- resource = wl_resource_create(client,
- &wl_input_panel_interface, 1, id);
-
- if (shell->input_panel.binding == NULL) {
- wl_resource_set_implementation(resource,
- &input_panel_implementation,
- shell, unbind_input_panel);
- shell->input_panel.binding = resource;
- return;
- }
-
- wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
- "interface object already bound");
- wl_resource_destroy(resource);
-}
-
struct switcher {
struct desktop_shell *shell;
struct weston_surface *current;
@@ -4190,33 +4959,30 @@ struct switcher {
static void
switcher_next(struct switcher *switcher)
{
- struct weston_surface *surface;
+ struct weston_view *view;
struct weston_surface *first = NULL, *prev = NULL, *next = NULL;
struct shell_surface *shsurf;
struct workspace *ws = get_current_workspace(switcher->shell);
- wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
- switch (get_shell_surface_type(surface)) {
- case SHELL_SURFACE_TOPLEVEL:
- case SHELL_SURFACE_FULLSCREEN:
- case SHELL_SURFACE_MAXIMIZED:
+ wl_list_for_each(view, &ws->layer.view_list, layer_link) {
+ shsurf = get_shell_surface(view->surface);
+ if (shsurf &&
+ shsurf->type == SHELL_SURFACE_TOPLEVEL &&
+ shsurf->parent == NULL) {
if (first == NULL)
- first = surface;
+ first = view->surface;
if (prev == switcher->current)
- next = surface;
- prev = surface;
- surface->alpha = 0.25;
- weston_surface_geometry_dirty(surface);
- weston_surface_damage(surface);
- break;
- default:
- break;
+ next = view->surface;
+ prev = view->surface;
+ view->alpha = 0.25;
+ weston_view_geometry_dirty(view);
+ weston_surface_damage(view->surface);
}
- if (is_black_surface(surface, NULL)) {
- surface->alpha = 0.25;
- weston_surface_geometry_dirty(surface);
- weston_surface_damage(surface);
+ if (is_black_surface(view->surface, NULL)) {
+ view->alpha = 0.25;
+ weston_view_geometry_dirty(view);
+ weston_surface_damage(view->surface);
}
}
@@ -4230,11 +4996,12 @@ switcher_next(struct switcher *switcher)
wl_signal_add(&next->destroy_signal, &switcher->listener);
switcher->current = next;
- next->alpha = 1.0;
+ wl_list_for_each(view, &next->views, surface_link)
+ view->alpha = 1.0;
shsurf = get_shell_surface(switcher->current);
- if (shsurf && shsurf->type ==SHELL_SURFACE_FULLSCREEN)
- shsurf->fullscreen.black_surface->alpha = 1.0;
+ if (shsurf && shsurf->state.fullscreen)
+ shsurf->fullscreen.black_view->alpha = 1.0;
}
static void
@@ -4249,13 +5016,16 @@ switcher_handle_surface_destroy(struct wl_listener *listener, void *data)
static void
switcher_destroy(struct switcher *switcher)
{
- struct weston_surface *surface;
+ struct weston_view *view;
struct weston_keyboard *keyboard = switcher->grab.keyboard;
struct workspace *ws = get_current_workspace(switcher->shell);
- wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
- surface->alpha = 1.0;
- weston_surface_damage(surface);
+ wl_list_for_each(view, &ws->layer.view_list, layer_link) {
+ if (is_focus_view(view))
+ continue;
+
+ view->alpha = 1.0;
+ weston_surface_damage(view->surface);
}
if (switcher->current)
@@ -4592,25 +5362,89 @@ workspace_move_surface_down_binding(struct weston_seat *seat, uint32_t time,
}
static void
+handle_output_destroy(struct wl_listener *listener, void *data)
+{
+ struct shell_output *output_listener =
+ container_of(listener, struct shell_output, destroy_listener);
+
+ wl_list_remove(&output_listener->destroy_listener.link);
+ wl_list_remove(&output_listener->link);
+ free(output_listener);
+}
+
+static void
+create_shell_output(struct desktop_shell *shell,
+ struct weston_output *output)
+{
+ struct shell_output *shell_output;
+
+ shell_output = zalloc(sizeof *shell_output);
+ if (shell_output == NULL)
+ return;
+
+ shell_output->output = output;
+ shell_output->shell = shell;
+ shell_output->destroy_listener.notify = handle_output_destroy;
+ wl_signal_add(&output->destroy_signal,
+ &shell_output->destroy_listener);
+ wl_list_insert(shell->output_list.prev, &shell_output->link);
+}
+
+static void
+handle_output_create(struct wl_listener *listener, void *data)
+{
+ struct desktop_shell *shell =
+ container_of(listener, struct desktop_shell, output_create_listener);
+ struct weston_output *output = (struct weston_output *)data;
+
+ create_shell_output(shell, output);
+}
+
+static void
+setup_output_destroy_handler(struct weston_compositor *ec,
+ struct desktop_shell *shell)
+{
+ struct weston_output *output;
+
+ wl_list_init(&shell->output_list);
+ wl_list_for_each(output, &ec->output_list, link)
+ create_shell_output(shell, output);
+
+ shell->output_create_listener.notify = handle_output_create;
+ wl_signal_add(&ec->output_created_signal,
+ &shell->output_create_listener);
+}
+
+static void
shell_destroy(struct wl_listener *listener, void *data)
{
struct desktop_shell *shell =
container_of(listener, struct desktop_shell, destroy_listener);
struct workspace **ws;
+ struct shell_output *shell_output, *tmp;
if (shell->child.client)
wl_client_destroy(shell->child.client);
wl_list_remove(&shell->idle_listener.link);
wl_list_remove(&shell->wake_listener.link);
- wl_list_remove(&shell->show_input_panel_listener.link);
- wl_list_remove(&shell->hide_input_panel_listener.link);
+
+ input_panel_destroy(shell);
+
+ wl_list_for_each_safe(shell_output, tmp, &shell->output_list, link) {
+ wl_list_remove(&shell_output->destroy_listener.link);
+ wl_list_remove(&shell_output->link);
+ free(shell_output);
+ }
+
+ wl_list_remove(&shell->output_create_listener.link);
wl_array_for_each(ws, &shell->workspaces.array)
workspace_destroy(*ws);
wl_array_release(&shell->workspaces.array);
free(shell->screensaver.path);
+ free(shell->client);
free(shell);
}
@@ -4643,6 +5477,10 @@ shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
zoom_key_binding, NULL);
weston_compositor_add_key_binding(ec, KEY_PAGEDOWN, mod,
zoom_key_binding, NULL);
+ weston_compositor_add_key_binding(ec, KEY_M, mod, maximize_binding,
+ NULL);
+ weston_compositor_add_key_binding(ec, KEY_F, mod, fullscreen_binding,
+ NULL);
weston_compositor_add_button_binding(ec, BTN_LEFT, mod, move_binding,
shell);
weston_compositor_add_touch_binding(ec, mod, touch_move_binding, shell);
@@ -4676,6 +5514,8 @@ shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
workspace_move_surface_down_binding,
shell);
+ weston_compositor_add_modifier_binding(ec, mod, exposay_binding, shell);
+
/* Add bindings for mod+F[1-6] for workspace 1 to 6. */
if (shell->workspaces.num > 1) {
num_workspace_bindings = shell->workspaces.num;
@@ -4714,15 +5554,11 @@ module_init(struct weston_compositor *ec,
wl_signal_add(&ec->idle_signal, &shell->idle_listener);
shell->wake_listener.notify = wake_handler;
wl_signal_add(&ec->wake_signal, &shell->wake_listener);
- shell->show_input_panel_listener.notify = show_input_panels;
- wl_signal_add(&ec->show_input_panel_signal, &shell->show_input_panel_listener);
- shell->hide_input_panel_listener.notify = hide_input_panels;
- wl_signal_add(&ec->hide_input_panel_signal, &shell->hide_input_panel_listener);
- shell->update_input_panel_listener.notify = update_input_panels;
- wl_signal_add(&ec->update_input_panel_signal, &shell->update_input_panel_listener);
+
ec->ping_handler = ping_handler;
ec->shell_interface.shell = shell;
ec->shell_interface.create_shell_surface = create_shell_surface;
+ ec->shell_interface.get_primary_view = get_primary_view;
ec->shell_interface.set_toplevel = set_toplevel;
ec->shell_interface.set_transient = set_transient;
ec->shell_interface.set_fullscreen = set_fullscreen;
@@ -4731,8 +5567,6 @@ module_init(struct weston_compositor *ec,
ec->shell_interface.resize = surface_resize;
ec->shell_interface.set_title = set_title;
- wl_list_init(&shell->input_panel.surfaces);
-
weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
weston_layer_init(&shell->background_layer, &shell->panel_layer.link);
@@ -4742,8 +5576,14 @@ module_init(struct weston_compositor *ec,
wl_array_init(&shell->workspaces.array);
wl_list_init(&shell->workspaces.client_list);
+ if (input_panel_setup(shell) < 0)
+ return -1;
+
shell_configuration(shell);
+ shell->exposay.state_cur = EXPOSAY_LAYOUT_INACTIVE;
+ shell->exposay.state_target = EXPOSAY_TARGET_CANCEL;
+
for (i = 0; i < shell->workspaces.num; i++) {
pws = wl_array_add(&shell->workspaces.array, sizeof *pws);
if (pws == NULL)
@@ -4763,6 +5603,10 @@ module_init(struct weston_compositor *ec,
shell, bind_shell) == NULL)
return -1;
+ if (wl_global_create(ec->wl_display, &xdg_shell_interface, 1,
+ shell, bind_xdg_shell) == NULL)
+ return -1;
+
if (wl_global_create(ec->wl_display,
&desktop_shell_interface, 2,
shell, bind_desktop_shell) == NULL)
@@ -4772,16 +5616,14 @@ module_init(struct weston_compositor *ec,
shell, bind_screensaver) == NULL)
return -1;
- if (wl_global_create(ec->wl_display, &wl_input_panel_interface, 1,
- shell, bind_input_panel) == NULL)
- return -1;
-
if (wl_global_create(ec->wl_display, &workspace_manager_interface, 1,
shell, bind_workspace_manager) == NULL)
return -1;
shell->child.deathstamp = weston_compositor_get_time();
+ setup_output_destroy_handler(ec, shell);
+
loop = wl_display_get_event_loop(ec->wl_display);
wl_event_loop_add_idle(loop, launch_desktop_shell_process, shell);
diff --git a/desktop-shell/shell.h b/desktop-shell/shell.h
new file mode 100644
index 00000000..8ef550f6
--- /dev/null
+++ b/desktop-shell/shell.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright © 2010-2012 Intel Corporation
+ * Copyright © 2011-2012 Collabora, Ltd.
+ * Copyright © 2013 Raspberry Pi Foundation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdbool.h>
+
+#include "compositor.h"
+
+enum animation_type {
+ ANIMATION_NONE,
+
+ ANIMATION_ZOOM,
+ ANIMATION_FADE,
+ ANIMATION_DIM_LAYER,
+};
+
+enum fade_type {
+ FADE_IN,
+ FADE_OUT
+};
+
+enum exposay_target_state {
+ EXPOSAY_TARGET_OVERVIEW, /* show all windows */
+ EXPOSAY_TARGET_CANCEL, /* return to normal, same focus */
+ EXPOSAY_TARGET_SWITCH, /* return to normal, switch focus */
+};
+
+enum exposay_layout_state {
+ EXPOSAY_LAYOUT_INACTIVE = 0, /* normal desktop */
+ EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE, /* in transition to normal */
+ EXPOSAY_LAYOUT_OVERVIEW, /* show all windows */
+ EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW, /* in transition to all windows */
+};
+
+struct focus_surface {
+ struct weston_surface *surface;
+ struct weston_view *view;
+ struct weston_transform workspace_transform;
+};
+
+struct workspace {
+ struct weston_layer layer;
+
+ struct wl_list focus_list;
+ struct wl_listener seat_destroyed_listener;
+
+ struct focus_surface *fsurf_front;
+ struct focus_surface *fsurf_back;
+ struct weston_view_animation *focus_animation;
+};
+
+struct desktop_shell {
+ struct weston_compositor *compositor;
+
+ struct wl_listener idle_listener;
+ struct wl_listener wake_listener;
+ struct wl_listener destroy_listener;
+ struct wl_listener show_input_panel_listener;
+ struct wl_listener hide_input_panel_listener;
+ struct wl_listener update_input_panel_listener;
+
+ struct weston_layer fullscreen_layer;
+ struct weston_layer panel_layer;
+ struct weston_layer background_layer;
+ struct weston_layer lock_layer;
+ struct weston_layer input_panel_layer;
+
+ struct wl_listener pointer_focus_listener;
+ struct weston_surface *grab_surface;
+
+ struct {
+ struct weston_process process;
+ struct wl_client *client;
+ struct wl_resource *desktop_shell;
+ struct wl_listener client_destroy_listener;
+
+ unsigned deathcount;
+ uint32_t deathstamp;
+ } child;
+
+ bool locked;
+ bool showing_input_panels;
+ bool prepare_event_sent;
+
+ struct {
+ struct weston_surface *surface;
+ pixman_box32_t cursor_rectangle;
+ } text_input;
+
+ struct weston_surface *lock_surface;
+ struct wl_listener lock_surface_listener;
+
+ struct {
+ struct wl_array array;
+ unsigned int current;
+ unsigned int num;
+
+ struct wl_list client_list;
+
+ struct weston_animation animation;
+ struct wl_list anim_sticky_list;
+ int anim_dir;
+ uint32_t anim_timestamp;
+ double anim_current;
+ struct workspace *anim_from;
+ struct workspace *anim_to;
+ } workspaces;
+
+ struct {
+ char *path;
+ int duration;
+ struct wl_resource *binding;
+ struct weston_process process;
+ struct wl_event_source *timer;
+ } screensaver;
+
+ struct {
+ struct wl_resource *binding;
+ struct wl_list surfaces;
+ } input_panel;
+
+ struct {
+ struct weston_view *view;
+ struct weston_view_animation *animation;
+ enum fade_type type;
+ struct wl_event_source *startup_timer;
+ } fade;
+
+ struct exposay {
+ /* XXX: Make these exposay_surfaces. */
+ struct weston_view *focus_prev;
+ struct weston_view *focus_current;
+ struct weston_view *clicked;
+ struct workspace *workspace;
+ struct weston_seat *seat;
+ struct wl_list surface_list;
+
+ struct weston_keyboard_grab grab_kbd;
+ struct weston_pointer_grab grab_ptr;
+
+ enum exposay_target_state state_target;
+ enum exposay_layout_state state_cur;
+ int in_flight; /* number of animations still running */
+
+ int num_surfaces;
+ int grid_size;
+ int surface_size;
+
+ int hpadding_outer;
+ int vpadding_outer;
+ int padding_inner;
+
+ int row_current;
+ int column_current;
+
+ bool mod_pressed;
+ bool mod_invalid;
+ } exposay;
+
+ uint32_t binding_modifier;
+ enum animation_type win_animation_type;
+ enum animation_type startup_animation_type;
+ enum animation_type focus_animation_type;
+
+ struct wl_listener output_create_listener;
+ struct wl_list output_list;
+
+ char *client;
+};
+
+void
+set_alpha_if_fullscreen(struct shell_surface *shsurf);
+
+struct weston_output *
+get_default_output(struct weston_compositor *compositor);
+
+struct weston_view *
+get_default_view(struct weston_surface *surface);
+
+struct shell_surface *
+get_shell_surface(struct weston_surface *surface);
+
+struct workspace *
+get_current_workspace(struct desktop_shell *shell);
+
+void
+lower_fullscreen_layer(struct desktop_shell *shell);
+
+void
+activate(struct desktop_shell *shell, struct weston_surface *es,
+ struct weston_seat *seat);
+
+void
+exposay_binding(struct weston_seat *seat,
+ enum weston_keyboard_modifier modifier,
+ void *data);
+int
+input_panel_setup(struct desktop_shell *shell);
+void
+input_panel_destroy(struct desktop_shell *shell);
diff --git a/man/Makefile.am b/man/Makefile.am
index e4abd8c4..5fb030a1 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -7,6 +7,7 @@ endif
MAN_SUBSTS = \
-e 's|__weston_native_backend__|$(WESTON_NATIVE_BACKEND)|g' \
-e 's|__weston_modules_dir__|$(pkglibdir)|g' \
+ -e 's|__weston_shell_client__|$(WESTON_SHELL_CLIENT)|g' \
-e 's|__version__|$(PACKAGE_VERSION)|g'
SUFFIXES = .1 .5 .7 .man
diff --git a/man/weston.ini.man b/man/weston.ini.man
index c5ec3218..6be90bf4 100644
--- a/man/weston.ini.man
+++ b/man/weston.ini.man
@@ -104,6 +104,30 @@ directory are:
.BR xwayland.so
.fi
.RE
+.TP 7
+.TP 7
+.BI "backend=" headless-backend.so
+overrides defaults backend. Available backend modules in the
+.IR "__weston_modules_dir__"
+directory are:
+.PP
+.RS 10
+.nf
+.BR drm-backend.so
+.BR fbdev-backend.so
+.BR headless-backend.so
+.BR rdp-backend.so
+.BR rpi-backend.so
+.BR wayland-backend.so
+.BR x11-backend.so
+.fi
+.RE
+.BI "gbm-format="format
+sets the GBM format used for the framebuffer for the GBM backend. Can be
+.B xrgb8888,
+.B xrgb2101010,
+.B rgb565.
+By default, xrgb8888 is used.
.RS
.PP
@@ -115,6 +139,11 @@ different shell plugins.
.PP
The entries that can appear in this section are:
.TP 7
+.BI "client=" file
+sets the path for the shell client to run. If not specified
+.I __weston_shell_client__
+is launched (string).
+.TP 7
.BI "background-image=" file
sets the path for the background image file (string).
.TP 7
@@ -160,6 +189,12 @@ sets the effect used for opening new windows (string). Can be
.B none.
By default, the fade animation is used.
.TP 7
+.BI "focus-animation=" dim-layer
+sets the effect used with the focused and unfocused windows. Can be
+.B dim-layer,
+.B none.
+By default, no animation is used.
+.TP 7
.BI "binding-modifier=" ctrl
sets the modifier key used for common bindings (string), such as moving
surfaces, resizing, rotating, switching, closing and setting the transparency
@@ -229,7 +264,8 @@ currently only recognized by the drm and x11 backends.
.TP 7
.BI "name=" name
sets a name for the output (string). The backend uses the name to
-identify the output. All X11 output names start with a letter X. The available
+identify the output. All X11 output names start with a letter X. All
+Wayland output names start with the letters WL. The available
output names for DRM backend are listed in the
.B "weston-launch(1)"
output.
@@ -240,6 +276,7 @@ Examples of usage:
.BR "LVDS1 " "DRM backend, Laptop internal panel no.1"
.BR "VGA1 " "DRM backend, VGA connector no.1"
.BR "X1 " "X11 backend, X window no.1"
+.BR "WL1 " "Wayland backend, Wayland window no.1"
.fi
.RE
.RS
diff --git a/man/weston.man b/man/weston.man
index 39d854be..f2d1b4c7 100644
--- a/man/weston.man
+++ b/man/weston.man
@@ -148,9 +148,27 @@ Name of the Wayland display to connect to, see also
.I WAYLAND_DISPLAY
of the environment.
.TP
+.B \-\-fullscreen
+Create a single fullscreen output
+.TP
+\fB\-\-output\-count\fR=\fIN\fR
+Create
+.I N
+Wayland windows to emulate the same number of outputs.
+.TP
\fB\-\-width\fR=\fIW\fR, \fB\-\-height\fR=\fIH\fR
-Make the desktop size
+Make all outputs have a size of
.IR W x H " pixels."
+.TP
+.B \-\-scale\fR=\fIN\fR
+Give all outputs a scale factor of
+.I N.
+.TP
+.B \-\-use\-pixman
+Use the pixman renderer. By default, weston will try to use EGL and
+GLES2 for rendering and will fall back to the pixman-based renderer for
+software compositing if EGL cannot be used. Passing this option will force
+weston to use the pixman renderer.
.
.SS X11 backend options:
.TP
diff --git a/protocol/Makefile.am b/protocol/Makefile.am
index 924e48f3..5e331a74 100644
--- a/protocol/Makefile.am
+++ b/protocol/Makefile.am
@@ -1,11 +1,26 @@
-EXTRA_DIST = \
+protocol_sources = \
desktop-shell.xml \
screenshooter.xml \
- tablet-shell.xml \
xserver.xml \
text.xml \
input-method.xml \
workspaces.xml \
- subsurface.xml \
text-cursor-position.xml \
- wayland-test.xml
+ wayland-test.xml \
+ xdg-shell.xml \
+ scaler.xml
+
+if HAVE_XMLLINT
+.PHONY: validate
+
+.%.xml.valid: %.xml
+ $(AM_V_GEN)$(XMLLINT) --noout --dtdvalid $(dtddir)/wayland.dtd $^ > $@
+
+validate: $(protocol_sources:%.xml=.%.xml.valid)
+
+all-local: validate
+
+CLEANFILES= $(protocol_sources:%.xml=.%.xml.valid)
+EXTRA_DIST=$(protocol_sources)
+
+endif
diff --git a/protocol/scaler.xml b/protocol/scaler.xml
new file mode 100644
index 00000000..dfe44b87
--- /dev/null
+++ b/protocol/scaler.xml
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="scaler">
+
+ <copyright>
+ Copyright © 2013 Collabora, Ltd.
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, provided that the above copyright notice appear in
+ all copies and that both that copyright notice and this permission
+ notice appear in supporting documentation, and that the name of
+ the copyright holders not be used in advertising or publicity
+ pertaining to distribution of the software without specific,
+ written prior permission. The copyright holders make no
+ representations about the suitability of this software for any
+ purpose. It is provided "as is" without express or implied
+ warranty.
+
+ THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ THIS SOFTWARE.
+ </copyright>
+
+ <interface name="wl_scaler" version="1">
+ <description summary="surface cropping and scaling">
+ The global interface exposing surface cropping and scaling
+ capabilities is used to instantiate an interface extension for a
+ wl_surface object. This extended interface will then allow
+ cropping and scaling the surface contents, effectively
+ disconnecting the direct relationship between the buffer and the
+ surface size.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="unbind from the cropping and scaling interface">
+ Informs the server that the client will not be using this
+ protocol object anymore. This does not affect any other objects,
+ wl_viewport objects included.
+ </description>
+ </request>
+
+ <enum name="error">
+ <entry name="viewport_exists" value="0"
+ summary="the surface already has a viewport object associated"/>
+ </enum>
+
+ <request name="get_viewport">
+ <description summary="extend surface interface for crop and scale">
+ Instantiate an interface extension for the given wl_surface to
+ crop and scale its content. If the given wl_surface already has
+ a wl_viewport object associated, the viewport_exists
+ protocol error is raised.
+ </description>
+
+ <arg name="id" type="new_id" interface="wl_viewport"
+ summary="the new viewport interface id"/>
+ <arg name="surface" type="object" interface="wl_surface"
+ summary="the surface"/>
+ </request>
+ </interface>
+
+ <interface name="wl_viewport" version="1">
+ <description summary="crop and scale interface to a wl_surface">
+ An additional interface to a wl_surface object, which allows the
+ client to specify the cropping and scaling of the surface
+ contents.
+
+ This interface allows to define the source rectangle (src_x,
+ src_y, src_width, src_height) from where to take the wl_buffer
+ contents, and scale that to destination size (dst_width,
+ dst_height). This state is double-buffered, and is applied on the
+ next wl_surface.commit.
+
+ Before the first set request, the wl_surface still behaves as if
+ there was no crop and scale state. That is, no scaling is applied,
+ and the surface size is as defined in wl_surface.attach.
+
+ The crop and scale state causes the surface size to become
+ dst_width, dst_height. This overrides whatever the attached
+ wl_buffer size is, unless the wl_buffer is NULL. If the wl_buffer is
+ NULL, the surface has no content and therefore no size.
+
+ The coordinate transformations from buffer pixel coordinates up to
+ the surface-local coordinates happen in the following order:
+ 1. buffer_transform (wl_surface.set_buffer_transform)
+ 2. buffer_scale (wl_surface.set_buffer_scale)
+ 3. crop and scale (wl_viewport.set)
+ This means, that the source rectangle coordinates of crop and scale
+ are given in the coordinates after the buffer transform and scale,
+ i.e. in the coordinates that would be the surface-local coordinates
+ if the crop and scale was not applied.
+
+ If the source rectangle is partially or completely outside of the
+ wl_buffer, then the surface contents are undefined (not void), and
+ the surface size is still dst_width, dst_height.
+
+ The x, y arguments of wl_surface.attach are applied as normal to
+ the surface. They indicate how many pixels to remove from the
+ surface size from the left and the top. In other words, they are
+ still in the surface-local coordinate system, just like dst_width
+ and dst_height are.
+
+ If the wl_surface associated with the wl_viewport is destroyed,
+ the wl_viewport object becomes inert.
+
+ If the wl_viewport object is destroyed, the crop and scale
+ state is removed from the wl_surface. The change will be applied
+ on the next wl_surface.commit.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="remove scaling and cropping from the surface">
+ The associated wl_surface's crop and scale state is removed.
+ The change is applied on the next wl_surface.commit.
+ </description>
+ </request>
+
+ <enum name="error">
+ <entry name="bad_value" value="0"
+ summary="negative values in width or height"/>
+ </enum>
+
+ <request name="set">
+ <description summary="set the crop and scale state">
+ Set the crop and scale state of the associated wl_surface. See
+ wl_viewport for the description, and relation to the wl_buffer
+ size.
+
+ The bad_value protocol error is raised if src_width or
+ src_height is negative, or if dst_width or dst_height is not
+ positive.
+
+ The crop and scale state is double-buffered state, and will be
+ applied on the next wl_surface.commit.
+
+ Arguments dst_x and dst_y do not exist here, use the x and y
+ arguments to wl_surface.attach. The x, y, dst_width, and dst_height
+ define the surface-local coordinate system irrespective of the
+ attached wl_buffer size.
+ </description>
+
+ <arg name="src_x" type="fixed" summary="source rectangle x"/>
+ <arg name="src_y" type="fixed" summary="source rectangle y"/>
+ <arg name="src_width" type="fixed" summary="source rectangle width"/>
+ <arg name="src_height" type="fixed" summary="source rectangle height"/>
+ <arg name="dst_width" type="int" summary="surface width"/>
+ <arg name="dst_height" type="int" summary="surface height"/>
+ </request>
+
+ </interface>
+</protocol>
diff --git a/protocol/subsurface.xml b/protocol/subsurface.xml
deleted file mode 100644
index 9e4a658d..00000000
--- a/protocol/subsurface.xml
+++ /dev/null
@@ -1,244 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<protocol name="subsurface">
-
- <copyright>
- Copyright © 2012-2013 Collabora, Ltd.
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, provided that the above copyright notice appear in
- all copies and that both that copyright notice and this permission
- notice appear in supporting documentation, and that the name of
- the copyright holders not be used in advertising or publicity
- pertaining to distribution of the software without specific,
- written prior permission. The copyright holders make no
- representations about the suitability of this software for any
- purpose. It is provided "as is" without express or implied
- warranty.
-
- THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
- SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
- SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
- AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
- ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
- THIS SOFTWARE.
- </copyright>
-
- <interface name="wl_subcompositor" version="1">
- <description summary="sub-surface compositing">
- The global interface exposing sub-surface compositing capabilities.
- A wl_surface, that has sub-surfaces associated, is called the
- parent surface. Sub-surfaces can be arbitrarily nested and create
- a tree of sub-surfaces.
-
- The root surface in a tree of sub-surfaces is the main
- surface. The main surface cannot be a sub-surface, because
- sub-surfaces must always have a parent.
-
- A main surface with its sub-surfaces forms a (compound) window.
- For window management purposes, this set of wl_surface objects is
- to be considered as a single window, and it should also behave as
- such.
-
- The aim of sub-surfaces is to offload some of the compositing work
- within a window from clients to the compositor. A prime example is
- a video player with decorations and video in separate wl_surface
- objects. This should allow the compositor to pass YUV video buffer
- processing to dedicated overlay hardware when possible.
- </description>
-
- <request name="destroy" type="destructor">
- <description summary="unbind from the subcompositor interface">
- Informs the server that the client will not be using this
- protocol object anymore. This does not affect any other
- objects, wl_subsurface objects included.
- </description>
- </request>
-
- <enum name="error">
- <entry name="bad_surface" value="0"
- summary="the to-be sub-surface is invalid"/>
- </enum>
-
- <request name="get_subsurface">
- <description summary="give a surface the role sub-surface">
- Create a sub-surface interface for the given surface, and
- associate it with the given parent surface. This turns a
- plain wl_surface into a sub-surface.
-
- The to-be sub-surface must not already have a dedicated
- purpose, like any shell surface type, cursor image, drag icon,
- or sub-surface. Otherwise a protocol error is raised.
- </description>
-
- <arg name="id" type="new_id" interface="wl_subsurface"
- summary="the new subsurface object id"/>
- <arg name="surface" type="object" interface="wl_surface"
- summary="the surface to be turned into a sub-surface"/>
- <arg name="parent" type="object" interface="wl_surface"
- summary="the parent surface"/>
- </request>
- </interface>
-
- <interface name="wl_subsurface" version="1">
- <description summary="sub-surface interface to a wl_surface">
- An additional interface to a wl_surface object, which has been
- made a sub-surface. A sub-surface has one parent surface. A
- sub-surface's size and position are not limited to that of the parent.
- Particularly, a sub-surface is not automatically clipped to its
- parent's area.
-
- A sub-surface becomes mapped, when a non-NULL wl_buffer is applied
- and the parent surface is mapped. The order of which one happens
- first is irrelevant. A sub-surface is hidden if the parent becomes
- hidden, or if a NULL wl_buffer is applied. These rules apply
- recursively through the tree of surfaces.
-
- The behaviour of wl_surface.commit request on a sub-surface
- depends on the sub-surface's mode. The possible modes are
- synchronized and desynchronized, see methods
- wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized
- mode caches the wl_surface state to be applied when the parent's
- state gets applied, and desynchronized mode applies the pending
- wl_surface state directly. A sub-surface is initially in the
- synchronized mode.
-
- Sub-surfaces have also other kind of state, which is managed by
- wl_subsurface requests, as opposed to wl_surface requests. This
- state includes the sub-surface position relative to the parent
- surface (wl_subsurface.set_position), and the stacking order of
- the parent and its sub-surfaces (wl_subsurface.place_above and
- .place_below). This state is applied when the parent surface's
- wl_surface state is applied, regardless of the sub-surface's mode.
- As the exception, set_sync and set_desync are effective immediately.
-
- The main surface can be thought to be always in desynchronized mode,
- since it does not have a parent in the sub-surfaces sense.
-
- Even if a sub-surface is in desynchronized mode, it will behave as
- in synchronized mode, if its parent surface behaves as in
- synchronized mode. This rule is applied recursively throughout the
- tree of surfaces. This means, that one can set a sub-surface into
- synchronized mode, and then assume that all its child and grand-child
- sub-surfaces are synchronized, too, without explicitly setting them.
-
- If the wl_surface associated with the wl_subsurface is destroyed, the
- wl_subsurface object becomes inert. Note, that destroying either object
- takes effect immediately. If you need to synchronize the removal
- of a sub-surface to the parent surface update, unmap the sub-surface
- first by attaching a NULL wl_buffer, update parent, and then destroy
- the sub-surface.
-
- If the parent wl_surface object is destroyed, the sub-surface is
- unmapped.
- </description>
-
- <request name="destroy" type="destructor">
- <description summary="remove sub-surface interface">
- The sub-surface interface is removed from the wl_surface object
- that was turned into a sub-surface with
- wl_subcompositor.get_subsurface request. The wl_surface's association
- to the parent is deleted, and the wl_surface loses its role as
- a sub-surface. The wl_surface is unmapped.
- </description>
- </request>
-
- <enum name="error">
- <entry name="bad_surface" value="0"
- summary="wl_surface is not a sibling or the parent"/>
- </enum>
-
- <request name="set_position">
- <description summary="reposition the sub-surface">
- This schedules a sub-surface position change.
- The sub-surface will be moved so, that its origin (top-left
- corner pixel) will be at the location x, y of the parent surface
- coordinate system. The coordinates are not restricted to the parent
- surface area. Negative values are allowed.
-
- The next wl_surface.commit on the parent surface will reset
- the sub-surface's position to the scheduled coordinates.
-
- The initial position is 0, 0.
- </description>
-
- <arg name="x" type="int" summary="coordinate in the parent surface"/>
- <arg name="y" type="int" summary="coordinate in the parent surface"/>
- </request>
-
- <request name="place_above">
- <description summary="restack the sub-surface">
- This sub-surface is taken from the stack, and put back just
- above the reference surface, changing the z-order of the sub-surfaces.
- The reference surface must be one of the sibling surfaces, or the
- parent surface. Using any other surface, including this sub-surface,
- will cause a protocol error.
-
- The z-order is double-buffered state, and will be applied on the
- next commit of the parent surface.
- See wl_surface.commit and wl_subcompositor.get_subsurface.
-
- A new sub-surface is initially added as the top-most in the stack
- of its siblings and parent.
- </description>
-
- <arg name="sibling" type="object" interface="wl_surface"
- summary="the reference surface"/>
- </request>
-
- <request name="place_below">
- <description summary="restack the sub-surface">
- The sub-surface is placed just below of the reference surface.
- See wl_subsurface.place_above.
- </description>
-
- <arg name="sibling" type="object" interface="wl_surface"
- summary="the reference surface"/>
- </request>
-
- <request name="set_sync">
- <description summary="set sub-surface to synchronized mode">
- Change the commit behaviour of the sub-surface to synchronized
- mode, also described as the parent dependant mode.
-
- In synchronized mode, wl_surface.commit on a sub-surface will
- accumulate the committed state in a cache, but the state will
- not be applied and hence will not change the compositor output.
- The cached state is applied to the sub-surface immediately after
- the parent surface's state is applied. This ensures atomic
- updates of the parent and all its synchronized sub-surfaces.
- Applying the cached state will invalidate the cache, so further
- parent surface commits do not (re-)apply old state.
-
- See wl_subsurface for the recursive effect of this mode.
- </description>
- </request>
-
- <request name="set_desync">
- <description summary="set sub-surface to desynchronized mode">
- Change the commit behaviour of the sub-surface to desynchronized
- mode, also described as independent or freely running mode.
-
- In desynchronized mode, wl_surface.commit on a sub-surface will
- apply the pending state directly, without caching, as happens
- normally with a wl_surface. Calling wl_surface.commit on the
- parent surface has no effect on the sub-surface's wl_surface
- state. This mode allows a sub-surface to be updated on its own.
-
- If cached state exists when wl_surface.commit is called in
- desynchronized mode, the pending state is added to the cached
- state, and applied as whole. This invalidates the cache.
-
- Note: even if a sub-surface is set to desynchronized, a parent
- sub-surface may override it to behave as synchronized. For details,
- see wl_subsurface.
-
- If a surface's parent surface behaves as desynchronized, then
- the cached state is applied on set_desync.
- </description>
- </request>
-
- </interface>
-</protocol>
diff --git a/protocol/tablet-shell.xml b/protocol/tablet-shell.xml
deleted file mode 100644
index 10f17568..00000000
--- a/protocol/tablet-shell.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<protocol name="tablet">
-
- <interface name="tablet_shell" version="1">
- <request name="set_lockscreen">
- <arg name="surface" type="object" interface="wl_surface"/>
- </request>
-
- <request name="set_switcher">
- <arg name="surface" type="object" interface="wl_surface"/>
- </request>
-
- <request name="set_homescreen">
- <arg name="surface" type="object" interface="wl_surface"/>
- </request>
-
- <request name="show_grid">
- <arg name="surface" type="object" interface="wl_surface"/>
- </request>
-
- <request name="show_panels">
- <arg name="surface" type="object" interface="wl_surface"/>
- </request>
-
- <request name="create_client">
- <arg name="id" type="new_id" interface="tablet_client"/>
- <arg name="name" type="string"/>
- <arg name="fd" type="fd"/>
- </request>
-
- <event name="show_lockscreen"/>
- <event name="show_switcher"/>
- <event name="hide_switcher"/>
- </interface>
-
- <interface name="tablet_client" version="1">
- <request name="destroy" type="destructor"/>
- <request name="activate"/>
- </interface>
-
-</protocol>
diff --git a/protocol/wayland-test.xml b/protocol/wayland-test.xml
index 2993f087..18b66253 100644
--- a/protocol/wayland-test.xml
+++ b/protocol/wayland-test.xml
@@ -51,5 +51,12 @@
<arg name="x" type="fixed"/>
<arg name="y" type="fixed"/>
</event>
+ <request name="get_n_egl_buffers">
+ <!-- causes a n_egl_buffers event to be sent which reports how many
+ buffer objects are live for the client -->
+ </request>
+ <event name="n_egl_buffers">
+ <arg name="n" type="uint"/>
+ </event>
</interface>
</protocol>
diff --git a/protocol/xdg-shell.xml b/protocol/xdg-shell.xml
new file mode 100644
index 00000000..4e5cff8d
--- /dev/null
+++ b/protocol/xdg-shell.xml
@@ -0,0 +1,438 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xdg_shell">
+
+ <copyright>
+ Copyright © 2008-2013 Kristian Høgsberg
+ Copyright © 2013 Rafael Antognolli
+ Copyright © 2013 Jasper St. Pierre
+ Copyright © 2010-2013 Intel Corporation
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, provided that the above copyright notice appear in
+ all copies and that both that copyright notice and this permission
+ notice appear in supporting documentation, and that the name of
+ the copyright holders not be used in advertising or publicity
+ pertaining to distribution of the software without specific,
+ written prior permission. The copyright holders make no
+ representations about the suitability of this software for any
+ purpose. It is provided "as is" without express or implied
+ warranty.
+
+ THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ THIS SOFTWARE.
+ </copyright>
+
+ <interface name="xdg_shell" version="1">
+ <description summary="create desktop-style surfaces">
+ This interface is implemented by servers that provide
+ desktop-style user interfaces.
+
+ It allows clients to associate a xdg_surface with
+ a basic surface.
+ </description>
+
+ <enum name="version">
+ <description summary="latest protocol version">
+ Use this enum to check the protocol version, and it will be updated
+ automatically.
+ </description>
+ <entry name="current" value="1" summary="Always the latest version"/>
+ </enum>
+
+
+ <request name="use_unstable_version">
+ <description summary="enable use of this unstable version">
+ Use this request in order to enable use of this interface.
+
+ Understand and agree that one is using an unstable interface,
+ that will likely change in the future, breaking the API.
+ </description>
+ <arg name="version" type="int"/>
+ </request>
+
+ <request name="get_xdg_surface">
+ <description summary="create a shell surface from a surface">
+ Create a shell surface for an existing surface.
+
+ Only one shell or popup surface can be associated with a given
+ surface.
+ </description>
+ <arg name="id" type="new_id" interface="xdg_surface"/>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ </request>
+
+ <request name="get_xdg_popup">
+ <description summary="create a shell surface from a surface">
+ Create a popup surface for an existing surface.
+
+ Only one shell or popup surface can be associated with a given
+ surface.
+ </description>
+ <arg name="id" type="new_id" interface="xdg_popup"/>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ <arg name="parent" type="object" interface="wl_surface"/>
+ <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/>
+ <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/>
+ <arg name="x" type="int"/>
+ <arg name="y" type="int"/>
+ <arg name="flags" type="uint"/>
+ </request>
+ </interface>
+
+ <interface name="xdg_surface" version="1">
+
+ <description summary="desktop-style metadata interface">
+ An interface that may be implemented by a wl_surface, for
+ implementations that provide a desktop-style user interface.
+
+ It provides requests to treat surfaces like windows, allowing to set
+ properties like maximized, fullscreen, minimized, and to move and resize
+ them, and associate metadata like title and app id.
+
+ On the server side the object is automatically destroyed when
+ the related wl_surface is destroyed. On client side,
+ xdg_surface.destroy() must be called before destroying
+ the wl_surface object.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="remove xdg_surface interface">
+ The xdg_surface interface is removed from the wl_surface object
+ that was turned into a xdg_surface with
+ xdg_shell.get_xdg_surface request. The xdg_surface properties,
+ like maximized and fullscreen, are lost. The wl_surface loses
+ its role as a xdg_surface. The wl_surface is unmapped.
+ </description>
+ </request>
+
+ <request name="set_transient_for">
+ <description summary="surface is a child of another surface">
+ Setting a surface as transient of another means that it is child
+ of another surface.
+
+ Child surfaces are stacked above their parents, and will be
+ unmapped if the parent is unmapped too. They should not appear
+ on task bars and alt+tab.
+ </description>
+ <arg name="parent" type="object" interface="wl_surface" allow-null="true"/>
+ </request>
+
+ <request name="set_title">
+ <description summary="set surface title">
+ Set a short title for the surface.
+
+ This string may be used to identify the surface in a task bar,
+ window list, or other user interface elements provided by the
+ compositor.
+
+ The string must be encoded in UTF-8.
+ </description>
+ <arg name="title" type="string"/>
+ </request>
+
+ <request name="set_app_id">
+ <description summary="set surface class">
+ Set an id for the surface.
+
+ The app id identifies the general class of applications to which
+ the surface belongs.
+
+ It should be the ID that appears in the new desktop entry
+ specification, the interface name.
+ </description>
+ <arg name="app_id" type="string"/>
+ </request>
+
+ <request name="pong">
+ <description summary="respond to a ping event">
+ A client must respond to a ping event with a pong request or
+ the client may be deemed unresponsive.
+ </description>
+ <arg name="serial" type="uint" summary="serial of the ping event"/>
+ </request>
+
+ <event name="ping">
+ <description summary="ping client">
+ Ping a client to check if it is receiving events and sending
+ requests. A client is expected to reply with a pong request.
+ </description>
+ <arg name="serial" type="uint"/>
+ </event>
+
+ <request name="move">
+ <description summary="start an interactive move">
+ Start a pointer-driven move of the surface.
+
+ This request must be used in response to a button press event.
+ The server may ignore move requests depending on the state of
+ the surface (e.g. fullscreen or maximized).
+ </description>
+ <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/>
+ <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/>
+ </request>
+
+ <enum name="resize_edge">
+ <description summary="edge values for resizing">
+ These values are used to indicate which edge of a surface
+ is being dragged in a resize operation. The server may
+ use this information to adapt its behavior, e.g. choose
+ an appropriate cursor image.
+ </description>
+ <entry name="none" value="0"/>
+ <entry name="top" value="1"/>
+ <entry name="bottom" value="2"/>
+ <entry name="left" value="4"/>
+ <entry name="top_left" value="5"/>
+ <entry name="bottom_left" value="6"/>
+ <entry name="right" value="8"/>
+ <entry name="top_right" value="9"/>
+ <entry name="bottom_right" value="10"/>
+ </enum>
+
+ <request name="resize">
+ <description summary="start an interactive resize">
+ Start a pointer-driven resizing of the surface.
+
+ This request must be used in response to a button press event.
+ The server may ignore resize requests depending on the state of
+ the surface (e.g. fullscreen or maximized).
+ </description>
+ <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/>
+ <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/>
+ <arg name="edges" type="uint" summary="which edge or corner is being dragged"/>
+ </request>
+
+ <event name="configure">
+ <description summary="suggest resize">
+ The configure event asks the client to resize its surface.
+
+ The size is a hint, in the sense that the client is free to
+ ignore it if it doesn't resize, pick a smaller size (to
+ satisfy aspect ratio or resize in steps of NxM pixels).
+
+ The edges parameter provides a hint about how the surface
+ was resized. The client may use this information to decide
+ how to adjust its content to the new size (e.g. a scrolling
+ area might adjust its content position to leave the viewable
+ content unmoved). Valid edge values are from resize_edge enum.
+
+ The client is free to dismiss all but the last configure
+ event it received.
+
+ The width and height arguments specify the size of the window
+ in surface local coordinates.
+ </description>
+
+ <arg name="edges" type="uint"/>
+ <arg name="width" type="int"/>
+ <arg name="height" type="int"/>
+ </event>
+
+ <request name="set_output">
+ <description summary="set the default output used by this surface">
+ Set the default output used by this surface when it is first mapped.
+
+ If this value is NULL (default), it's up to the compositor to choose
+ which display will be used to map this surface.
+
+ When fullscreen or maximized state are set on this surface, and it
+ wasn't mapped yet, the output set with this method will be used.
+ Otherwise, the output where the surface is currently mapped will be
+ used.
+ </description>
+ <arg name="output" type="object" interface="wl_output" allow-null="true"/>
+ </request>
+
+ <event name="request_set_fullscreen">
+ <description summary="server requests that the client set fullscreen">
+ Event sent from the compositor to the client requesting that the client
+ goes to a fullscreen state. It's the client job to call set_fullscreen
+ and really trigger the fullscreen state.
+ </description>
+ </event>
+
+ <event name="request_unset_fullscreen">
+ <description summary="server requests that the client unset fullscreen">
+ Event sent from the compositor to the client requesting that the client
+ leaves the fullscreen state. It's the client job to call
+ unset_fullscreen and really leave the fullscreen state.
+ </description>
+ </event>
+
+ <request name="set_fullscreen">
+ <description summary="set the surface state as fullscreen">
+ Set the surface as fullscreen.
+
+ After this request, the compositor should send a configure event
+ informing the output size.
+
+ This request informs the compositor that the next attached buffer
+ committed will be in a fullscreen state. The buffer size should be the
+ same size as the size informed in the configure event, if the client
+ doesn't want to leave any empty area.
+
+ In other words: the next attached buffer after set_maximized is the new
+ maximized buffer. And the surface will be positioned at the maximized
+ position on commit.
+
+ A simple way to synchronize and wait for the correct configure event is
+ to use a wl_display.sync request right after the set_fullscreen
+ request. When the sync callback returns, the last configure event
+ received just before it will be the correct one, and should contain the
+ right size for the surface to maximize.
+
+ Setting one state won't unset another state. Use
+ xdg_surface.unset_fullscreen for unsetting it.
+ </description>
+ </request>
+
+ <request name="unset_fullscreen">
+ <description summary="unset the surface state as fullscreen">
+ Unset the surface fullscreen state.
+
+ Same negotiation as set_fullscreen must be used.
+ </description>
+ </request>
+
+ <event name="request_set_maximized">
+ <description summary="server requests that the client set maximized">
+ Event sent from the compositor to the client requesting that the client
+ goes to a maximized state. It's the client job to call set_maximized
+ and really trigger the maximized state.
+ </description>
+ </event>
+
+ <event name="request_unset_maximized">
+ <description summary="server requests that the client unset maximized">
+ Event sent from the compositor to the client requesting that the client
+ leaves the maximized state. It's the client job to call unset_maximized
+ and really leave the maximized state.
+ </description>
+ </event>
+
+ <request name="set_maximized">
+ <description summary="set the surface state as maximized">
+ Set the surface as maximized.
+
+ After this request, the compositor will send a configure event
+ informing the output size minus panel and other MW decorations.
+
+ This request informs the compositor that the next attached buffer
+ committed will be in a maximized state. The buffer size should be the
+ same size as the size informed in the configure event, if the client
+ doesn't want to leave any empty area.
+
+ In other words: the next attached buffer after set_maximized is the new
+ maximized buffer. And the surface will be positioned at the maximized
+ position on commit.
+
+ A simple way to synchronize and wait for the correct configure event is
+ to use a wl_display.sync request right after the set_maximized request.
+ When the sync callback returns, the last configure event received just
+ before it will be the correct one, and should contain the right size
+ for the surface to maximize.
+
+ Setting one state won't unset another state. Use
+ xdg_surface.unset_maximized for unsetting it.
+ </description>
+ </request>
+
+ <request name="unset_maximized">
+ <description summary="unset the surface state as maximized">
+ Unset the surface maximized state.
+
+ Same negotiation as set_maximized must be used.
+ </description>
+ </request>
+
+ <request name="set_minimized">
+ <description summary="set the surface state as minimized">
+ Set the surface minimized state.
+
+ Setting one state won't unset another state.
+ </description>
+ </request>
+
+ <event name="focused_set">
+ <description summary="surface was focused">
+ The focused_set event is sent when this surface has been
+ activated. Window decorations should be updated accordingly.
+ </description>
+ </event>
+
+ <event name="focused_unset">
+ <description summary="surface was unfocused">
+ The focused_unset event is sent when this surface has been
+ deactivated, because another surface has been activated. Window
+ decorations should be updated accordingly.
+ </description>
+ </event>
+ </interface>
+
+ <interface name="xdg_popup" version="1">
+ <description summary="desktop-style metadata interface">
+ An interface that may be implemented by a wl_surface, for
+ implementations that provide a desktop-style popups/menus. A popup
+ surface is a transient surface with an added pointer grab.
+
+ An existing implicit grab will be changed to owner-events mode,
+ and the popup grab will continue after the implicit grab ends
+ (i.e. releasing the mouse button does not cause the popup to be
+ unmapped).
+
+ The popup grab continues until the window is destroyed or a mouse
+ button is pressed in any other clients window. A click in any of
+ the clients surfaces is reported as normal, however, clicks in
+ other clients surfaces will be discarded and trigger the callback.
+
+ The x and y arguments specify the locations of the upper left
+ corner of the surface relative to the upper left corner of the
+ parent surface, in surface local coordinates.
+
+ xdg_popup surfaces are always transient for another surface.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="remove xdg_surface interface">
+ The xdg_surface interface is removed from the wl_surface object
+ that was turned into a xdg_surface with
+ xdg_shell.get_xdg_surface request. The xdg_surface properties,
+ like maximized and fullscreen, are lost. The wl_surface loses
+ its role as a xdg_surface. The wl_surface is unmapped.
+ </description>
+ </request>
+
+ <request name="pong">
+ <description summary="respond to a ping event">
+ A client must respond to a ping event with a pong request or
+ the client may be deemed unresponsive.
+ </description>
+ <arg name="serial" type="uint" summary="serial of the ping event"/>
+ </request>
+
+ <event name="ping">
+ <description summary="ping client">
+ Ping a client to check if it is receiving events and sending
+ requests. A client is expected to reply with a pong request.
+ </description>
+ <arg name="serial" type="uint"/>
+ </event>
+
+ <event name="popup_done">
+ <description summary="popup interaction is done">
+ The popup_done event is sent out when a popup grab is broken,
+ that is, when the users clicks a surface that doesn't belong
+ to the client owning the popup surface.
+ </description>
+ <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/>
+ </event>
+
+ </interface>
+</protocol>
diff --git a/shared/Makefile.am b/shared/Makefile.am
index 2fcff7bb..31fab5f6 100644
--- a/shared/Makefile.am
+++ b/shared/Makefile.am
@@ -10,6 +10,7 @@ libshared_la_SOURCES = \
os-compatibility.h
libshared_cairo_la_CFLAGS = \
+ -DDATADIR='"$(datadir)"' \
$(GCC_CFLAGS) \
$(COMPOSITOR_CFLAGS) \
$(PIXMAN_CFLAGS) \
@@ -29,4 +30,5 @@ libshared_cairo_la_SOURCES = \
image-loader.c \
image-loader.h \
cairo-util.c \
+ frame.c \
cairo-util.h
diff --git a/shared/cairo-util.c b/shared/cairo-util.c
index 4305ba69..39485729 100644
--- a/shared/cairo-util.c
+++ b/shared/cairo-util.c
@@ -320,12 +320,27 @@ load_cairo_surface(const char *filename)
width, height, stride);
}
+void
+theme_set_background_source(struct theme *t, cairo_t *cr, uint32_t flags)
+{
+ cairo_pattern_t *pattern;
+
+ if (flags & THEME_FRAME_ACTIVE) {
+ pattern = cairo_pattern_create_linear(16, 16, 16, 112);
+ cairo_pattern_add_color_stop_rgb(pattern, 0.0, 1.0, 1.0, 1.0);
+ cairo_pattern_add_color_stop_rgb(pattern, 0.2, 0.8, 0.8, 0.8);
+ cairo_set_source(cr, pattern);
+ cairo_pattern_destroy(pattern);
+ } else {
+ cairo_set_source_rgba(cr, 0.75, 0.75, 0.75, 1);
+ }
+}
+
struct theme *
theme_create(void)
{
struct theme *t;
cairo_t *cr;
- cairo_pattern_t *pattern;
t = malloc(sizeof *t);
if (t == NULL)
@@ -352,12 +367,7 @@ theme_create(void)
cr = cairo_create(t->active_frame);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
- pattern = cairo_pattern_create_linear(16, 16, 16, 112);
- cairo_pattern_add_color_stop_rgb(pattern, 0.0, 1.0, 1.0, 1.0);
- cairo_pattern_add_color_stop_rgb(pattern, 0.2, 0.8, 0.8, 0.8);
- cairo_set_source(cr, pattern);
- cairo_pattern_destroy(pattern);
-
+ theme_set_background_source(t, cr, THEME_FRAME_ACTIVE);
rounded_rect(cr, 0, 0, 128, 128, t->frame_radius);
cairo_fill(cr);
@@ -370,7 +380,7 @@ theme_create(void)
cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 128, 128);
cr = cairo_create(t->inactive_frame);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
- cairo_set_source_rgba(cr, 0.75, 0.75, 0.75, 1);
+ theme_set_background_source(t, cr, 0);
rounded_rect(cr, 0, 0, 128, 128, t->frame_radius);
cairo_fill(cr);
@@ -408,7 +418,7 @@ theme_render_frame(struct theme *t,
cairo_text_extents_t extents;
cairo_font_extents_t font_extents;
cairo_surface_t *source;
- int x, y, margin;
+ int x, y, margin, top_margin;
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(cr, 0, 0, 0, 0);
@@ -429,40 +439,47 @@ theme_render_frame(struct theme *t,
else
source = t->inactive_frame;
+ if (title)
+ top_margin = t->titlebar_height;
+ else
+ top_margin = t->width;
+
tile_source(cr, source,
margin, margin,
width - margin * 2, height - margin * 2,
- t->width, t->titlebar_height);
-
- cairo_rectangle (cr, margin + t->width, margin,
- width - (margin + t->width) * 2,
- t->titlebar_height - t->width);
- cairo_clip(cr);
-
- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
- cairo_select_font_face(cr, "sans",
- CAIRO_FONT_SLANT_NORMAL,
- CAIRO_FONT_WEIGHT_BOLD);
- cairo_set_font_size(cr, 14);
- cairo_text_extents(cr, title, &extents);
- cairo_font_extents (cr, &font_extents);
- x = (width - extents.width) / 2;
- y = margin +
- (t->titlebar_height -
- font_extents.ascent - font_extents.descent) / 2 +
- font_extents.ascent;
-
- if (flags & THEME_FRAME_ACTIVE) {
- cairo_move_to(cr, x + 1, y + 1);
- cairo_set_source_rgb(cr, 1, 1, 1);
- cairo_show_text(cr, title);
- cairo_move_to(cr, x, y);
- cairo_set_source_rgb(cr, 0, 0, 0);
- cairo_show_text(cr, title);
- } else {
- cairo_move_to(cr, x, y);
- cairo_set_source_rgb(cr, 0.4, 0.4, 0.4);
- cairo_show_text(cr, title);
+ t->width, top_margin);
+
+ if (title) {
+ cairo_rectangle (cr, margin + t->width, margin,
+ width - (margin + t->width) * 2,
+ t->titlebar_height - t->width);
+ cairo_clip(cr);
+
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ cairo_select_font_face(cr, "sans",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_BOLD);
+ cairo_set_font_size(cr, 14);
+ cairo_text_extents(cr, title, &extents);
+ cairo_font_extents (cr, &font_extents);
+ x = (width - extents.width) / 2;
+ y = margin +
+ (t->titlebar_height -
+ font_extents.ascent - font_extents.descent) / 2 +
+ font_extents.ascent;
+
+ if (flags & THEME_FRAME_ACTIVE) {
+ cairo_move_to(cr, x + 1, y + 1);
+ cairo_set_source_rgb(cr, 1, 1, 1);
+ cairo_show_text(cr, title);
+ cairo_move_to(cr, x, y);
+ cairo_set_source_rgb(cr, 0, 0, 0);
+ cairo_show_text(cr, title);
+ } else {
+ cairo_move_to(cr, x, y);
+ cairo_set_source_rgb(cr, 0.4, 0.4, 0.4);
+ cairo_show_text(cr, title);
+ }
}
}
@@ -472,10 +489,15 @@ theme_get_location(struct theme *t, int x, int y,
{
int vlocation, hlocation, location;
const int grip_size = 8;
- int margin;
+ int margin, top_margin;
margin = (flags & THEME_FRAME_MAXIMIZED) ? 0 : t->margin;
+ if (flags & THEME_FRAME_NO_TITLE)
+ top_margin = t->width;
+ else
+ top_margin = t->titlebar_height;
+
if (x < margin)
hlocation = THEME_LOCATION_EXTERIOR;
else if (margin <= x && x < margin + grip_size)
@@ -502,7 +524,7 @@ theme_get_location(struct theme *t, int x, int y,
if (location & THEME_LOCATION_EXTERIOR)
location = THEME_LOCATION_EXTERIOR;
if (location == THEME_LOCATION_INTERIOR &&
- y < margin + t->titlebar_height)
+ y < margin + top_margin)
location = THEME_LOCATION_TITLEBAR;
else if (location == THEME_LOCATION_INTERIOR)
location = THEME_LOCATION_CLIENT_AREA;
diff --git a/shared/cairo-util.h b/shared/cairo-util.h
index 7b403944..7bcbc296 100644
--- a/shared/cairo-util.h
+++ b/shared/cairo-util.h
@@ -23,6 +23,7 @@
#ifndef _CAIRO_UTIL_H
#define _CAIRO_UTIL_H
+#include <stdint.h>
#include <cairo.h>
void
@@ -59,10 +60,13 @@ theme_destroy(struct theme *t);
enum {
THEME_FRAME_ACTIVE = 1,
- THEME_FRAME_MAXIMIZED,
+ THEME_FRAME_MAXIMIZED = 2,
+ THEME_FRAME_NO_TITLE = 4
};
void
+theme_set_background_source(struct theme *t, cairo_t *cr, uint32_t flags);
+void
theme_render_frame(struct theme *t,
cairo_t *cr, int width, int height,
const char *title, uint32_t flags);
@@ -86,4 +90,124 @@ enum theme_location {
enum theme_location
theme_get_location(struct theme *t, int x, int y, int width, int height, int flags);
+struct frame;
+
+enum frame_status {
+ FRAME_STATUS_NONE = 0,
+ FRAME_STATUS_REPAINT = 0x1,
+ FRAME_STATUS_MINIMIZE = 0x2,
+ FRAME_STATUS_MAXIMIZE = 0x4,
+ FRAME_STATUS_CLOSE = 0x8,
+ FRAME_STATUS_MENU = 0x10,
+ FRAME_STATUS_RESIZE = 0x20,
+ FRAME_STATUS_MOVE = 0x40,
+ FRAME_STATUS_ALL = 0x7f
+};
+
+enum frame_flag {
+ FRAME_FLAG_ACTIVE = 0x1,
+ FRAME_FLAG_MAXIMIZED = 0x2
+};
+
+enum {
+ FRAME_BUTTON_NONE = 0,
+ FRAME_BUTTON_CLOSE = 0x1,
+ FRAME_BUTTON_MAXIMIZE = 0x2,
+ FRAME_BUTTON_MINIMIZE = 0x4,
+ FRAME_BUTTON_ALL = 0x7
+};
+
+enum frame_button_state {
+ FRAME_BUTTON_RELEASED = 0,
+ FRAME_BUTTON_PRESSED = 1
+};
+
+struct frame *
+frame_create(struct theme *t, int32_t width, int32_t height, uint32_t buttons,
+ const char *title);
+
+void
+frame_destroy(struct frame *frame);
+
+/* May set FRAME_STATUS_REPAINT */
+int
+frame_set_title(struct frame *frame, const char *title);
+
+/* May set FRAME_STATUS_REPAINT */
+void
+frame_set_flag(struct frame *frame, enum frame_flag flag);
+
+/* May set FRAME_STATUS_REPAINT */
+void
+frame_unset_flag(struct frame *frame, enum frame_flag flag);
+
+/* May set FRAME_STATUS_REPAINT */
+void
+frame_resize(struct frame *frame, int32_t width, int32_t height);
+
+/* May set FRAME_STATUS_REPAINT */
+void
+frame_resize_inside(struct frame *frame, int32_t width, int32_t height);
+
+int32_t
+frame_width(struct frame *frame);
+
+int32_t
+frame_height(struct frame *frame);
+
+void
+frame_interior(struct frame *frame, int32_t *x, int32_t *y,
+ int32_t *width, int32_t *height);
+void
+frame_input_rect(struct frame *frame, int32_t *x, int32_t *y,
+ int32_t *width, int32_t *height);
+void
+frame_opaque_rect(struct frame *frame, int32_t *x, int32_t *y,
+ int32_t *width, int32_t *height);
+
+uint32_t
+frame_status(struct frame *frame);
+
+void
+frame_status_clear(struct frame *frame, enum frame_status status);
+
+/* May set FRAME_STATUS_REPAINT */
+enum theme_location
+frame_pointer_enter(struct frame *frame, void *pointer, int x, int y);
+
+/* May set FRAME_STATUS_REPAINT */
+enum theme_location
+frame_pointer_motion(struct frame *frame, void *pointer, int x, int y);
+
+/* May set FRAME_STATUS_REPAINT */
+void
+frame_pointer_leave(struct frame *frame, void *pointer);
+
+/* Call to indicate that a button has been pressed/released. The return
+ * value for a button release will be the same as for the corresponding
+ * press. This allows you to more easily track grabs. If you want the
+ * actual location, simply keep the location from the last
+ * frame_pointer_motion call.
+ *
+ * May set:
+ * FRAME_STATUS_MINIMIZE
+ * FRAME_STATUS_MAXIMIZE
+ * FRAME_STATUS_CLOSE
+ * FRAME_STATUS_MENU
+ * FRAME_STATUS_RESIZE
+ * FRAME_STATUS_MOVE
+ */
+enum theme_location
+frame_pointer_button(struct frame *frame, void *pointer,
+ uint32_t button, enum frame_button_state state);
+
+void
+frame_touch_down(struct frame *frame, void *data, int32_t id, int x, int y);
+
+void
+frame_touch_up(struct frame *frame, void *data, int32_t id);
+
+void
+frame_repaint(struct frame *frame, cairo_t *cr);
+
#endif
diff --git a/shared/frame.c b/shared/frame.c
new file mode 100644
index 00000000..a501649f
--- /dev/null
+++ b/shared/frame.c
@@ -0,0 +1,848 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ * Copyright © 2012-2013 Collabora, Ltd.
+ * Copyright © 2013 Jason Ekstrand
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <wayland-util.h>
+#include <linux/input.h>
+
+#include "cairo-util.h"
+
+enum frame_button_flags {
+ FRAME_BUTTON_ALIGN_RIGHT = 0x1,
+ FRAME_BUTTON_DECORATED = 0x2,
+ FRAME_BUTTON_CLICK_DOWN = 0x4,
+};
+
+struct frame_button {
+ struct frame *frame;
+ struct wl_list link; /* buttons_list */
+
+ cairo_surface_t *icon;
+ enum frame_button_flags flags;
+ int hover_count;
+ int press_count;
+
+ struct {
+ int x, y;
+ int width, height;
+ } allocation;
+
+ enum frame_status status_effect;
+};
+
+struct frame_pointer_button {
+ struct wl_list link;
+ uint32_t button;
+ enum theme_location press_location;
+ struct frame_button *frame_button;
+};
+
+struct frame_pointer {
+ struct wl_list link;
+ void *data;
+
+ int x, y;
+
+ struct frame_button *hover_button;
+ struct wl_list down_buttons;
+};
+
+struct frame_touch {
+ struct wl_list link;
+ void *data;
+
+ int x, y;
+
+ struct frame_button *button;
+};
+
+struct frame {
+ int32_t width, height;
+ char *title;
+ uint32_t flags;
+ struct theme *theme;
+
+ struct {
+ int32_t x, y;
+ int32_t width, height;
+ } interior;
+ int shadow_margin;
+ int opaque_margin;
+ int geometry_dirty;
+
+ uint32_t status;
+
+ struct wl_list buttons;
+ struct wl_list pointers;
+ struct wl_list touches;
+};
+
+static struct frame_button *
+frame_button_create(struct frame *frame, const char *icon,
+ enum frame_status status_effect,
+ enum frame_button_flags flags)
+{
+ struct frame_button *button;
+
+ button = calloc(1, sizeof *button);
+ if (!button)
+ return NULL;
+
+ button->icon = cairo_image_surface_create_from_png(icon);
+ if (!button->icon) {
+ free(button);
+ return NULL;
+ }
+
+ button->frame = frame;
+ button->flags = flags;
+ button->status_effect = status_effect;
+
+ wl_list_insert(frame->buttons.prev, &button->link);
+
+ return button;
+}
+
+static void
+frame_button_destroy(struct frame_button *button)
+{
+ cairo_surface_destroy(button->icon);
+ free(button);
+}
+
+static void
+frame_button_enter(struct frame_button *button)
+{
+ if (!button->hover_count)
+ button->frame->status |= FRAME_STATUS_REPAINT;
+ button->hover_count++;
+}
+
+static void
+frame_button_leave(struct frame_button *button, struct frame_pointer *pointer)
+{
+ button->hover_count--;
+ if (!button->hover_count)
+ button->frame->status |= FRAME_STATUS_REPAINT;
+}
+
+static void
+frame_button_press(struct frame_button *button)
+{
+ if (!button->press_count)
+ button->frame->status |= FRAME_STATUS_REPAINT;
+ button->press_count++;
+
+ if (button->flags & FRAME_BUTTON_CLICK_DOWN)
+ button->frame->status |= button->status_effect;
+}
+
+static void
+frame_button_release(struct frame_button *button)
+{
+ button->press_count--;
+ if (button->press_count)
+ return;
+
+ button->frame->status |= FRAME_STATUS_REPAINT;
+
+ if (!(button->flags & FRAME_BUTTON_CLICK_DOWN))
+ button->frame->status |= button->status_effect;
+}
+
+static void
+frame_button_cancel(struct frame_button *button)
+{
+ button->press_count--;
+ if (!button->press_count)
+ button->frame->status |= FRAME_STATUS_REPAINT;
+}
+
+static void
+frame_button_repaint(struct frame_button *button, cairo_t *cr)
+{
+ int x, y;
+
+ if (!button->allocation.width)
+ return;
+ if (!button->allocation.height)
+ return;
+
+ x = button->allocation.x;
+ y = button->allocation.y;
+
+ cairo_save(cr);
+
+ if (button->flags & FRAME_BUTTON_DECORATED) {
+ cairo_set_line_width(cr, 1);
+
+ cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
+ cairo_rectangle(cr, x, y, 25, 16);
+
+ cairo_stroke_preserve(cr);
+
+ if (button->press_count) {
+ cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
+ } else if (button->hover_count) {
+ cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+ } else {
+ cairo_set_source_rgb(cr, 0.88, 0.88, 0.88);
+ }
+
+ cairo_fill (cr);
+
+ x += 4;
+ }
+
+ cairo_set_source_surface(cr, button->icon, x, y);
+ cairo_paint(cr);
+
+ cairo_restore(cr);
+}
+
+static struct frame_pointer *
+frame_pointer_get(struct frame *frame, void *data)
+{
+ struct frame_pointer *pointer;
+
+ wl_list_for_each(pointer, &frame->pointers, link)
+ if (pointer->data == data)
+ return pointer;
+
+ pointer = calloc(1, sizeof *pointer);
+ if (!pointer)
+ return NULL;
+
+ pointer->data = data;
+ wl_list_init(&pointer->down_buttons);
+ wl_list_insert(&frame->pointers, &pointer->link);
+
+ return pointer;
+}
+
+static void
+frame_pointer_destroy(struct frame_pointer *pointer)
+{
+ wl_list_remove(&pointer->link);
+ free(pointer);
+}
+
+static struct frame_touch *
+frame_touch_get(struct frame *frame, void *data)
+{
+ struct frame_touch *touch;
+
+ wl_list_for_each(touch, &frame->touches, link)
+ if (touch->data == data)
+ return touch;
+
+ touch = calloc(1, sizeof *touch);
+ if (!touch)
+ return NULL;
+
+ touch->data = data;
+ wl_list_insert(&frame->touches, &touch->link);
+
+ return touch;
+}
+
+static void
+frame_touch_destroy(struct frame_touch *touch)
+{
+ wl_list_remove(&touch->link);
+ free(touch);
+}
+
+struct frame *
+frame_create(struct theme *t, int32_t width, int32_t height, uint32_t buttons,
+ const char *title)
+{
+ struct frame *frame;
+ struct frame_button *button;
+
+ frame = calloc(1, sizeof *frame);
+ if (!frame)
+ return NULL;
+
+ frame->width = width;
+ frame->height = height;
+ frame->flags = 0;
+ frame->theme = t;
+ frame->status = FRAME_STATUS_REPAINT;
+ frame->geometry_dirty = 1;
+
+ if (title) {
+ frame->title = strdup(title);
+ if (!frame->title)
+ goto free_frame;
+ }
+
+ wl_list_init(&frame->buttons);
+ wl_list_init(&frame->pointers);
+ wl_list_init(&frame->touches);
+
+ if (title) {
+ button = frame_button_create(frame,
+ DATADIR "/weston/icon_window.png",
+ FRAME_STATUS_MENU,
+ FRAME_BUTTON_CLICK_DOWN);
+ if (!button)
+ goto free_frame;
+ }
+
+ if (buttons & FRAME_BUTTON_CLOSE) {
+ button = frame_button_create(frame,
+ DATADIR "/weston/sign_close.png",
+ FRAME_STATUS_CLOSE,
+ FRAME_BUTTON_ALIGN_RIGHT |
+ FRAME_BUTTON_DECORATED);
+ if (!button)
+ goto free_frame;
+ }
+
+ if (buttons & FRAME_BUTTON_MAXIMIZE) {
+ button = frame_button_create(frame,
+ DATADIR "/weston/sign_maximize.png",
+ FRAME_STATUS_MAXIMIZE,
+ FRAME_BUTTON_ALIGN_RIGHT |
+ FRAME_BUTTON_DECORATED);
+ if (!button)
+ goto free_frame;
+ }
+
+ if (buttons & FRAME_BUTTON_MINIMIZE) {
+ button = frame_button_create(frame,
+ DATADIR "/weston/sign_minimize.png",
+ FRAME_STATUS_MINIMIZE,
+ FRAME_BUTTON_ALIGN_RIGHT |
+ FRAME_BUTTON_DECORATED);
+ if (!button)
+ goto free_frame;
+ }
+
+ return frame;
+
+free_frame:
+ free(frame->title);
+ free(frame);
+ return NULL;
+}
+
+void
+frame_destroy(struct frame *frame)
+{
+ struct frame_button *button, *next;
+
+ wl_list_for_each_safe(button, next, &frame->buttons, link)
+ frame_button_destroy(button);
+
+ free(frame->title);
+ free(frame);
+}
+
+int
+frame_set_title(struct frame *frame, const char *title)
+{
+ char *dup = NULL;
+
+ if (title) {
+ dup = strdup(title);
+ if (!dup)
+ return -1;
+ }
+
+ free(frame->title);
+ frame->title = dup;
+
+ frame->status |= FRAME_STATUS_REPAINT;
+
+ return 0;
+}
+
+void
+frame_set_flag(struct frame *frame, enum frame_flag flag)
+{
+ if (flag & FRAME_FLAG_MAXIMIZED && !(frame->flags & FRAME_FLAG_MAXIMIZED))
+ frame->geometry_dirty = 1;
+
+ frame->flags |= flag;
+ frame->status |= FRAME_STATUS_REPAINT;
+}
+
+void
+frame_unset_flag(struct frame *frame, enum frame_flag flag)
+{
+ if (flag & FRAME_FLAG_MAXIMIZED && frame->flags & FRAME_FLAG_MAXIMIZED)
+ frame->geometry_dirty = 1;
+
+ frame->flags &= ~flag;
+ frame->status |= FRAME_STATUS_REPAINT;
+}
+
+void
+frame_resize(struct frame *frame, int32_t width, int32_t height)
+{
+ frame->width = width;
+ frame->height = height;
+
+ frame->geometry_dirty = 1;
+ frame->status |= FRAME_STATUS_REPAINT;
+}
+
+void
+frame_resize_inside(struct frame *frame, int32_t width, int32_t height)
+{
+ struct theme *t = frame->theme;
+ int decoration_width, decoration_height, titlebar_height;
+
+ if (frame->title)
+ titlebar_height = t->titlebar_height;
+ else
+ titlebar_height = t->width;
+
+ if (frame->flags & FRAME_FLAG_MAXIMIZED) {
+ decoration_width = t->width * 2;
+ decoration_height = t->width + titlebar_height;
+ } else {
+ decoration_width = (t->width + t->margin) * 2;
+ decoration_height = t->width +
+ titlebar_height + t->margin * 2;
+ }
+
+ frame_resize(frame, width + decoration_width,
+ height + decoration_height);
+}
+
+int32_t
+frame_width(struct frame *frame)
+{
+ return frame->width;
+}
+
+int32_t
+frame_height(struct frame *frame)
+{
+ return frame->height;
+}
+
+static void
+frame_refresh_geometry(struct frame *frame)
+{
+ struct frame_button *button;
+ struct theme *t = frame->theme;
+ int x_l, x_r, y, w, h, titlebar_height;
+ int32_t decoration_width, decoration_height;
+
+ if (!frame->geometry_dirty)
+ return;
+
+ if (frame->title)
+ titlebar_height = t->titlebar_height;
+ else
+ titlebar_height = t->width;
+
+ if (frame->flags & FRAME_FLAG_MAXIMIZED) {
+ decoration_width = t->width * 2;
+ decoration_height = t->width + titlebar_height;
+
+ frame->interior.x = t->width;
+ frame->interior.y = titlebar_height;
+ frame->interior.width = frame->width - decoration_width;
+ frame->interior.height = frame->height - decoration_height;
+
+ frame->opaque_margin = 0;
+ frame->shadow_margin = 0;
+ } else {
+ decoration_width = (t->width + t->margin) * 2;
+ decoration_height = t->width + titlebar_height + t->margin * 2;
+
+ frame->interior.x = t->width + t->margin;
+ frame->interior.y = titlebar_height + t->margin;
+ frame->interior.width = frame->width - decoration_width;
+ frame->interior.height = frame->height - decoration_height;
+
+ frame->opaque_margin = t->margin + t->frame_radius;
+ frame->shadow_margin = t->margin;
+ }
+
+ x_r = frame->width - t->width - frame->shadow_margin;
+ x_l = t->width + frame->shadow_margin;
+ y = t->width + frame->shadow_margin;
+ wl_list_for_each(button, &frame->buttons, link) {
+ const int button_padding = 4;
+ w = cairo_image_surface_get_width(button->icon);
+ h = cairo_image_surface_get_height(button->icon);
+
+ if (button->flags & FRAME_BUTTON_DECORATED)
+ w += 10;
+
+ if (button->flags & FRAME_BUTTON_ALIGN_RIGHT) {
+ x_r -= w;
+
+ button->allocation.x = x_r;
+ button->allocation.y = y;
+ button->allocation.width = w + 1;
+ button->allocation.height = h + 1;
+
+ x_r -= button_padding;
+ } else {
+ button->allocation.x = x_l;
+ button->allocation.y = y;
+ button->allocation.width = w + 1;
+ button->allocation.height = h + 1;
+
+ x_l += w;
+ x_l += button_padding;
+ }
+ }
+
+ frame->geometry_dirty = 0;
+}
+
+void
+frame_interior(struct frame *frame, int32_t *x, int32_t *y,
+ int32_t *width, int32_t *height)
+{
+ frame_refresh_geometry(frame);
+
+ if (x)
+ *x = frame->interior.x;
+ if (y)
+ *y = frame->interior.y;
+ if (width)
+ *width = frame->interior.width;
+ if (height)
+ *height = frame->interior.height;
+}
+
+void
+frame_input_rect(struct frame *frame, int32_t *x, int32_t *y,
+ int32_t *width, int32_t *height)
+{
+ frame_refresh_geometry(frame);
+
+ if (x)
+ *x = frame->shadow_margin;
+ if (y)
+ *y = frame->shadow_margin;
+ if (width)
+ *width = frame->width - frame->shadow_margin * 2;
+ if (height)
+ *height = frame->height - frame->shadow_margin * 2;
+}
+
+void
+frame_opaque_rect(struct frame *frame, int32_t *x, int32_t *y,
+ int32_t *width, int32_t *height)
+{
+ frame_refresh_geometry(frame);
+
+ if (x)
+ *x = frame->opaque_margin;
+ if (y)
+ *y = frame->opaque_margin;
+ if (width)
+ *width = frame->width - frame->opaque_margin * 2;
+ if (height)
+ *height = frame->height - frame->opaque_margin * 2;
+}
+
+uint32_t
+frame_status(struct frame *frame)
+{
+ return frame->status;
+}
+
+void
+frame_status_clear(struct frame *frame, enum frame_status status)
+{
+ frame->status &= ~status;
+}
+
+static struct frame_button *
+frame_find_button(struct frame *frame, int x, int y)
+{
+ struct frame_button *button;
+ int rel_x, rel_y;
+
+ wl_list_for_each(button, &frame->buttons, link) {
+ rel_x = x - button->allocation.x;
+ rel_y = y - button->allocation.y;
+
+ if (0 <= rel_x && rel_x < button->allocation.width &&
+ 0 <= rel_y && rel_y < button->allocation.height)
+ return button;
+ }
+
+ return NULL;
+}
+
+enum theme_location
+frame_pointer_enter(struct frame *frame, void *data, int x, int y)
+{
+ return frame_pointer_motion(frame, data, x, y);
+}
+
+enum theme_location
+frame_pointer_motion(struct frame *frame, void *data, int x, int y)
+{
+ struct frame_pointer *pointer = frame_pointer_get(frame, data);
+ struct frame_button *button = frame_find_button(frame, x, y);
+ enum theme_location location;
+
+ location = theme_get_location(frame->theme, x, y,
+ frame->width, frame->height,
+ frame->flags & FRAME_FLAG_MAXIMIZED ?
+ THEME_FRAME_MAXIMIZED : 0);
+ if (!pointer)
+ return location;
+
+ pointer->x = x;
+ pointer->y = y;
+
+ if (pointer->hover_button == button)
+ return location;
+
+ if (pointer->hover_button)
+ frame_button_leave(pointer->hover_button, pointer);
+
+ pointer->hover_button = button;
+
+ if (pointer->hover_button)
+ frame_button_enter(pointer->hover_button);
+
+ return location;
+}
+
+static void
+frame_pointer_button_destroy(struct frame_pointer_button *button)
+{
+ wl_list_remove(&button->link);
+ free(button);
+}
+
+static void
+frame_pointer_button_press(struct frame *frame, struct frame_pointer *pointer,
+ struct frame_pointer_button *button)
+{
+ if (button->button == BTN_RIGHT) {
+ if (button->press_location == THEME_LOCATION_TITLEBAR)
+ frame->status |= FRAME_STATUS_MENU;
+
+ frame_pointer_button_destroy(button);
+
+ } else if (button->button == BTN_LEFT) {
+ if (pointer->hover_button) {
+ frame_button_press(pointer->hover_button);
+ } else {
+ switch (button->press_location) {
+ case THEME_LOCATION_TITLEBAR:
+ frame->status |= FRAME_STATUS_MOVE;
+
+ frame_pointer_button_destroy(button);
+ break;
+ case THEME_LOCATION_RESIZING_TOP:
+ case THEME_LOCATION_RESIZING_BOTTOM:
+ case THEME_LOCATION_RESIZING_LEFT:
+ case THEME_LOCATION_RESIZING_RIGHT:
+ case THEME_LOCATION_RESIZING_TOP_LEFT:
+ case THEME_LOCATION_RESIZING_TOP_RIGHT:
+ case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
+ case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
+ frame->status |= FRAME_STATUS_RESIZE;
+
+ frame_pointer_button_destroy(button);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+static void
+frame_pointer_button_release(struct frame *frame, struct frame_pointer *pointer,
+ struct frame_pointer_button *button)
+{
+ if (button->button == BTN_LEFT && button->frame_button) {
+ if (button->frame_button == pointer->hover_button)
+ frame_button_release(button->frame_button);
+ else
+ frame_button_cancel(button->frame_button);
+ }
+}
+
+static void
+frame_pointer_button_cancel(struct frame *frame, struct frame_pointer *pointer,
+ struct frame_pointer_button *button)
+{
+ if (button->frame_button)
+ frame_button_cancel(button->frame_button);
+}
+
+void
+frame_pointer_leave(struct frame *frame, void *data)
+{
+ struct frame_pointer *pointer = frame_pointer_get(frame, data);
+ struct frame_pointer_button *button, *next;
+ if (!pointer)
+ return;
+
+ if (pointer->hover_button)
+ frame_button_leave(pointer->hover_button, pointer);
+
+ wl_list_for_each_safe(button, next, &pointer->down_buttons, link) {
+ frame_pointer_button_cancel(frame, pointer, button);
+ frame_pointer_button_destroy(button);
+ }
+
+ frame_pointer_destroy(pointer);
+}
+
+enum theme_location
+frame_pointer_button(struct frame *frame, void *data,
+ uint32_t btn, enum frame_button_state state)
+{
+ struct frame_pointer *pointer = frame_pointer_get(frame, data);
+ struct frame_pointer_button *button;
+ enum theme_location location;
+
+ location = theme_get_location(frame->theme, pointer->x, pointer->y,
+ frame->width, frame->height,
+ frame->flags & FRAME_FLAG_MAXIMIZED ?
+ THEME_FRAME_MAXIMIZED : 0);
+
+ if (!pointer)
+ return location;
+
+ if (state == FRAME_BUTTON_PRESSED) {
+ button = malloc(sizeof *button);
+ if (!button)
+ return location;
+
+ button->button = btn;
+ button->press_location = location;
+ button->frame_button = pointer->hover_button;
+ wl_list_insert(&pointer->down_buttons, &button->link);
+
+ frame_pointer_button_press(frame, pointer, button);
+ } else if (state == FRAME_BUTTON_RELEASED) {
+ button = NULL;
+ wl_list_for_each(button, &pointer->down_buttons, link)
+ if (button->button == btn)
+ break;
+ /* Make sure we didn't hit the end */
+ if (&button->link == &pointer->down_buttons)
+ return location;
+
+ location = button->press_location;
+ frame_pointer_button_release(frame, pointer, button);
+ frame_pointer_button_destroy(button);
+ }
+
+ return location;
+}
+
+void
+frame_touch_down(struct frame *frame, void *data, int32_t id, int x, int y)
+{
+ struct frame_touch *touch = frame_touch_get(frame, data);
+ struct frame_button *button = frame_find_button(frame, x, y);
+ enum theme_location location;
+
+ if (id > 0)
+ return;
+
+ if (button) {
+ touch->button = button;
+ frame_button_press(touch->button);
+ return;
+ }
+
+ location = theme_get_location(frame->theme, x, y,
+ frame->width, frame->height,
+ frame->flags & FRAME_FLAG_MAXIMIZED ?
+ THEME_FRAME_MAXIMIZED : 0);
+
+ switch (location) {
+ case THEME_LOCATION_TITLEBAR:
+ frame->status |= FRAME_STATUS_MOVE;
+ break;
+ case THEME_LOCATION_RESIZING_TOP:
+ case THEME_LOCATION_RESIZING_BOTTOM:
+ case THEME_LOCATION_RESIZING_LEFT:
+ case THEME_LOCATION_RESIZING_RIGHT:
+ case THEME_LOCATION_RESIZING_TOP_LEFT:
+ case THEME_LOCATION_RESIZING_TOP_RIGHT:
+ case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
+ case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
+ frame->status |= FRAME_STATUS_RESIZE;
+ break;
+ default:
+ break;
+ }
+}
+
+void
+frame_touch_up(struct frame *frame, void *data, int32_t id)
+{
+ struct frame_touch *touch = frame_touch_get(frame, data);
+
+ if (id > 0)
+ return;
+
+ if (touch->button) {
+ frame_button_release(touch->button);
+ frame_touch_destroy(touch);
+ return;
+ }
+}
+
+void
+frame_repaint(struct frame *frame, cairo_t *cr)
+{
+ struct frame_button *button;
+ uint32_t flags = 0;
+
+ frame_refresh_geometry(frame);
+
+ if (frame->flags & FRAME_FLAG_MAXIMIZED)
+ flags |= THEME_FRAME_MAXIMIZED;
+
+ if (frame->flags & FRAME_FLAG_ACTIVE)
+ flags |= THEME_FRAME_ACTIVE;
+
+ cairo_save(cr);
+ theme_render_frame(frame->theme, cr, frame->width, frame->height,
+ frame->title, flags);
+ cairo_restore(cr);
+
+ wl_list_for_each(button, &frame->buttons, link)
+ frame_button_repaint(button, cr);
+
+ frame_status_clear(frame, FRAME_STATUS_REPAINT);
+}
diff --git a/shared/os-compatibility.c b/shared/os-compatibility.c
index 4f96dd4c..611e7c80 100644
--- a/shared/os-compatibility.c
+++ b/shared/os-compatibility.c
@@ -132,6 +132,12 @@ create_tmpfile_cloexec(char *tmpname)
* The file is suitable for buffer sharing between processes by
* transmitting the file descriptor over Unix sockets using the
* SCM_RIGHTS methods.
+ *
+ * If the C library implements posix_fallocate(), it is used to
+ * guarantee that disk space is available for the file at the
+ * given size. If disk space is insufficent, errno is set to ENOSPC.
+ * If posix_fallocate() is not supported, program may receive
+ * SIGBUS on accessing mmap()'ed file contents instead.
*/
int
os_create_anonymous_file(off_t size)
@@ -140,6 +146,7 @@ os_create_anonymous_file(off_t size)
const char *path;
char *name;
int fd;
+ int ret;
path = getenv("XDG_RUNTIME_DIR");
if (!path) {
@@ -161,10 +168,20 @@ os_create_anonymous_file(off_t size)
if (fd < 0)
return -1;
- if (ftruncate(fd, size) < 0) {
+#ifdef HAVE_POSIX_FALLOCATE
+ ret = posix_fallocate(fd, 0, size);
+ if (ret != 0) {
close(fd);
+ errno = ret;
return -1;
}
+#else
+ ret = ftruncate(fd, size);
+ if (ret < 0) {
+ close(fd);
+ return -1;
+ }
+#endif
return fd;
}
diff --git a/src/.gitignore b/src/.gitignore
index 539150d4..024594c8 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -7,18 +7,11 @@ screenshooter-server-protocol.h
spring-tool
text-cursor-position-protocol.c
text-cursor-position-server-protocol.h
-tablet-shell-protocol.c
-tablet-shell-server-protocol.h
-xserver-protocol.c
-xserver-server-protocol.h
-desktop-shell-protocol.c
-desktop-shell-server-protocol.h
text-protocol.c
text-server-protocol.h
workspaces-protocol.c
workspaces-server-protocol.h
input-method-protocol.c
input-method-server-protocol.h
-subsurface-server-protocol.h
-subsurface-protocol.c
-
+scaler-server-protocol.h
+scaler-protocol.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 749c074a..446639cc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -36,25 +36,38 @@ weston_SOURCES = \
input-method-server-protocol.h \
workspaces-protocol.c \
workspaces-server-protocol.h \
- subsurface-protocol.c \
- subsurface-server-protocol.h \
+ scaler-protocol.c \
+ scaler-server-protocol.h \
bindings.c \
animation.c \
- gl-renderer.h \
noop-renderer.c \
pixman-renderer.c \
pixman-renderer.h \
../shared/matrix.c \
../shared/matrix.h \
../shared/zalloc.h \
- weston-launch.h \
weston-egl-ext.h
-if ENABLE_EGL
-weston_SOURCES += \
- gl-renderer.c \
- vertex-clipping.c \
- vertex-clipping.h
+noinst_LTLIBRARIES = \
+ libsession-helper.la
+
+libsession_helper_la_SOURCES = \
+ weston-launch.h \
+ launcher-util.c \
+ launcher-util.h
+libsession_helper_la_CFLAGS = $(GCC_CFLAGS) $(LIBDRM_CFLAGS) $(PIXMAN_CFLAGS) $(COMPOSITOR_CFLAGS)
+libsession_helper_la_LIBADD = $(LIBDRM_LIBS)
+
+if ENABLE_DBUS
+if HAVE_SYSTEMD_LOGIN
+libsession_helper_la_SOURCES += \
+ dbus.h \
+ dbus.c \
+ logind-util.h \
+ logind-util.c
+libsession_helper_la_CFLAGS += $(SYSTEMD_LOGIN_CFLAGS) $(DBUS_CFLAGS)
+libsession_helper_la_LIBADD += $(SYSTEMD_LOGIN_LIBS) $(DBUS_LIBS)
+endif
endif
git-version.h : .FORCE
@@ -64,20 +77,16 @@ git-version.h : .FORCE
.FORCE :
-if ENABLE_XWAYLAND
-SUBDIRS = xwayland
-endif
-
-DIST_SUBDIRS = xwayland
-
-
if BUILD_WESTON_LAUNCH
weston_launch = weston-launch
weston_launch_SOURCES = weston-launch.c weston-launch.h
-weston_launch_CFLAGS= $(GCC_CFLAGS)
-weston_launch_CPPFLAGS = $(WESTON_LAUNCH_CFLAGS) $(SYSTEMD_LOGIN_CFLAGS) \
- -DBINDIR='"$(bindir)"'
-weston_launch_LDADD = $(WESTON_LAUNCH_LIBS) $(SYSTEMD_LOGIN_LIBS)
+weston_launch_CPPFLAGS = -DBINDIR='"$(bindir)"'
+weston_launch_CFLAGS= \
+ $(GCC_CFLAGS) \
+ $(PAM_CFLAGS) \
+ $(SYSTEMD_LOGIN_CFLAGS) \
+ $(LIBDRM_CFLAGS)
+weston_launch_LDADD = $(PAM_LIBS) $(SYSTEMD_LOGIN_LIBS) $(LIBDRM_LIBS)
if ENABLE_SETUID_INSTALL
install-exec-hook:
@@ -100,10 +109,9 @@ westoninclude_HEADERS = \
moduledir = $(libdir)/weston
module_LTLIBRARIES = \
- $(desktop_shell) \
- $(tablet_shell) \
$(cms_static) \
$(cms_colord) \
+ $(gl_renderer) \
$(x11_backend) \
$(drm_backend) \
$(wayland_backend) \
@@ -111,14 +119,27 @@ module_LTLIBRARIES = \
$(fbdev_backend) \
$(rdp_backend)
-noinst_LTLIBRARIES =
-
if INSTALL_RPI_COMPOSITOR
module_LTLIBRARIES += $(rpi_backend)
else
noinst_LTLIBRARIES += $(rpi_backend)
endif
+if ENABLE_EGL
+gl_renderer = gl-renderer.la
+gl_renderer_la_LDFLAGS = -module -avoid-version
+gl_renderer_la_LIBADD = $(COMPOSITOR_LIBS) $(EGL_LIBS)
+gl_renderer_la_CFLAGS = \
+ $(COMPOSITOR_CFLAGS) \
+ $(EGL_CFLAGS) \
+ $(GCC_CFLAGS)
+gl_renderer_la_SOURCES = \
+ gl-renderer.h \
+ gl-renderer.c \
+ vertex-clipping.c \
+ vertex-clipping.h
+endif
+
if ENABLE_X11_COMPOSITOR
x11_backend = x11-backend.la
x11_backend_la_LDFLAGS = -module -avoid-version
@@ -126,6 +147,7 @@ x11_backend_la_LIBADD = $(COMPOSITOR_LIBS) $(X11_COMPOSITOR_LIBS) \
../shared/libshared-cairo.la
x11_backend_la_CFLAGS = \
$(COMPOSITOR_CFLAGS) \
+ $(EGL_CFLAGS) \
$(PIXMAN_CFLAGS) \
$(CAIRO_CFLAGS) \
$(X11_COMPOSITOR_CFLAGS) \
@@ -136,10 +158,14 @@ endif
if ENABLE_DRM_COMPOSITOR
drm_backend = drm-backend.la
drm_backend_la_LDFLAGS = -module -avoid-version
-drm_backend_la_LIBADD = $(COMPOSITOR_LIBS) $(DRM_COMPOSITOR_LIBS) \
- ../shared/libshared.la -lrt
+drm_backend_la_LIBADD = \
+ $(COMPOSITOR_LIBS) \
+ $(DRM_COMPOSITOR_LIBS) \
+ ../shared/libshared.la -lrt \
+ libsession-helper.la
drm_backend_la_CFLAGS = \
$(COMPOSITOR_CFLAGS) \
+ $(EGL_CFLAGS) \
$(DRM_COMPOSITOR_CFLAGS) \
$(GCC_CFLAGS)
drm_backend_la_SOURCES = \
@@ -149,8 +175,6 @@ drm_backend_la_SOURCES = \
evdev.c \
evdev.h \
evdev-touchpad.c \
- launcher-util.c \
- launcher-util.h \
libbacklight.c \
libbacklight.h
@@ -164,10 +188,13 @@ endif
if ENABLE_WAYLAND_COMPOSITOR
wayland_backend = wayland-backend.la
wayland_backend_la_LDFLAGS = -module -avoid-version
-wayland_backend_la_LIBADD = $(COMPOSITOR_LIBS) $(WAYLAND_COMPOSITOR_LIBS) \
+wayland_backend_la_LIBADD = \
+ $(COMPOSITOR_LIBS) \
+ $(WAYLAND_COMPOSITOR_LIBS) \
../shared/libshared-cairo.la
wayland_backend_la_CFLAGS = \
$(COMPOSITOR_CFLAGS) \
+ $(EGL_CFLAGS) \
$(PIXMAN_CFLAGS) \
$(CAIRO_CFLAGS) \
$(WAYLAND_COMPOSITOR_CFLAGS) \
@@ -181,6 +208,7 @@ rpi_backend_la_LDFLAGS = -module -avoid-version
rpi_backend_la_LIBADD = $(COMPOSITOR_LIBS) \
$(RPI_COMPOSITOR_LIBS) \
$(RPI_BCM_HOST_LIBS) \
+ libsession-helper.la \
../shared/libshared.la
rpi_backend_la_CFLAGS = \
$(GCC_CFLAGS) \
@@ -192,11 +220,17 @@ rpi_backend_la_SOURCES = \
rpi-renderer.c \
rpi-renderer.h \
rpi-bcm-stubs.h \
- launcher-util.c \
- launcher-util.h \
+ udev-seat.c \
+ udev-seat.h \
evdev.c \
evdev.h \
evdev-touchpad.c
+
+if ENABLE_EGL
+rpi_backend_la_LIBADD += $(EGL_LIBS)
+rpi_backend_la_CFLAGS += $(EGL_CFLAGS)
+endif
+
endif
if ENABLE_HEADLESS_COMPOSITOR
@@ -216,9 +250,11 @@ fbdev_backend_la_LDFLAGS = -module -avoid-version
fbdev_backend_la_LIBADD = \
$(COMPOSITOR_LIBS) \
$(FBDEV_COMPOSITOR_LIBS) \
+ libsession-helper.la \
../shared/libshared.la
fbdev_backend_la_CFLAGS = \
$(COMPOSITOR_CFLAGS) \
+ $(EGL_CFLAGS) \
$(FBDEV_COMPOSITOR_CFLAGS) \
$(PIXMAN_CFLAGS) \
$(GCC_CFLAGS)
@@ -228,9 +264,7 @@ fbdev_backend_la_SOURCES = \
udev-seat.h \
evdev.c \
evdev.h \
- evdev-touchpad.c \
- launcher-util.c \
- launcher-util.h
+ evdev-touchpad.c
endif
if ENABLE_RDP_COMPOSITOR
@@ -246,29 +280,6 @@ rdp_backend_la_CFLAGS = \
rdp_backend_la_SOURCES = compositor-rdp.c
endif
-if ENABLE_DESKTOP_SHELL
-desktop_shell = desktop-shell.la
-desktop_shell_la_LDFLAGS = -module -avoid-version
-desktop_shell_la_LIBADD = $(COMPOSITOR_LIBS) \
- ../shared/libshared.la
-desktop_shell_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
-desktop_shell_la_SOURCES = \
- shell.c \
- desktop-shell-protocol.c \
- desktop-shell-server-protocol.h
-endif
-
-if ENABLE_TABLET_SHELL
-tablet_shell = tablet-shell.la
-tablet_shell_la_LDFLAGS = -module -avoid-version
-tablet_shell_la_LIBADD = $(COMPOSITOR_LIBS)
-tablet_shell_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
-tablet_shell_la_SOURCES = \
- tablet-shell.c \
- tablet-shell-protocol.c \
- tablet-shell-server-protocol.h
-endif
-
if HAVE_LCMS
cms_static = cms-static.la
cms_static_la_LDFLAGS = -module -avoid-version
@@ -306,18 +317,14 @@ BUILT_SOURCES = \
screenshooter-protocol.c \
text-cursor-position-server-protocol.h \
text-cursor-position-protocol.c \
- tablet-shell-protocol.c \
- tablet-shell-server-protocol.h \
- desktop-shell-protocol.c \
- desktop-shell-server-protocol.h \
text-protocol.c \
text-server-protocol.h \
input-method-protocol.c \
input-method-server-protocol.h \
workspaces-server-protocol.h \
workspaces-protocol.c \
- subsurface-server-protocol.h \
- subsurface-protocol.c \
+ scaler-server-protocol.h \
+ scaler-protocol.c \
git-version.h
CLEANFILES = $(BUILT_SOURCES)
diff --git a/src/animation.c b/src/animation.c
index 2c47ae7e..ee120367 100644
--- a/src/animation.c
+++ b/src/animation.c
@@ -34,7 +34,7 @@
WL_EXPORT void
weston_spring_init(struct weston_spring *spring,
- double k, double current, double target)
+ double k, double current, double target)
{
spring->k = k;
spring->friction = 400.0;
@@ -114,52 +114,53 @@ weston_spring_done(struct weston_spring *spring)
fabs(spring->current - spring->target) < 0.002;
}
-typedef void (*weston_surface_animation_frame_func_t)(struct weston_surface_animation *animation);
+typedef void (*weston_view_animation_frame_func_t)(struct weston_view_animation *animation);
-struct weston_surface_animation {
- struct weston_surface *surface;
+struct weston_view_animation {
+ struct weston_view *view;
struct weston_animation animation;
struct weston_spring spring;
struct weston_transform transform;
struct wl_listener listener;
float start, stop;
- weston_surface_animation_frame_func_t frame;
- weston_surface_animation_frame_func_t reset;
- weston_surface_animation_done_func_t done;
+ weston_view_animation_frame_func_t frame;
+ weston_view_animation_frame_func_t reset;
+ weston_view_animation_done_func_t done;
void *data;
+ void *private;
};
-static void
-weston_surface_animation_destroy(struct weston_surface_animation *animation)
+WL_EXPORT void
+weston_view_animation_destroy(struct weston_view_animation *animation)
{
wl_list_remove(&animation->animation.link);
wl_list_remove(&animation->listener.link);
wl_list_remove(&animation->transform.link);
if (animation->reset)
animation->reset(animation);
- weston_surface_geometry_dirty(animation->surface);
+ weston_view_geometry_dirty(animation->view);
if (animation->done)
animation->done(animation, animation->data);
free(animation);
}
static void
-handle_animation_surface_destroy(struct wl_listener *listener, void *data)
+handle_animation_view_destroy(struct wl_listener *listener, void *data)
{
- struct weston_surface_animation *animation =
+ struct weston_view_animation *animation =
container_of(listener,
- struct weston_surface_animation, listener);
+ struct weston_view_animation, listener);
- weston_surface_animation_destroy(animation);
+ weston_view_animation_destroy(animation);
}
static void
-weston_surface_animation_frame(struct weston_animation *base,
- struct weston_output *output, uint32_t msecs)
+weston_view_animation_frame(struct weston_animation *base,
+ struct weston_output *output, uint32_t msecs)
{
- struct weston_surface_animation *animation =
+ struct weston_view_animation *animation =
container_of(base,
- struct weston_surface_animation, animation);
+ struct weston_view_animation, animation);
if (base->frame_counter <= 1)
animation->spring.timestamp = msecs;
@@ -167,69 +168,71 @@ weston_surface_animation_frame(struct weston_animation *base,
weston_spring_update(&animation->spring, msecs);
if (weston_spring_done(&animation->spring)) {
- weston_compositor_schedule_repaint(animation->surface->compositor);
- weston_surface_animation_destroy(animation);
+ weston_view_schedule_repaint(animation->view);
+ weston_view_animation_destroy(animation);
return;
}
if (animation->frame)
animation->frame(animation);
- weston_surface_geometry_dirty(animation->surface);
- weston_compositor_schedule_repaint(animation->surface->compositor);
+ weston_view_geometry_dirty(animation->view);
+ weston_view_schedule_repaint(animation->view);
}
-static struct weston_surface_animation *
-weston_surface_animation_run(struct weston_surface *surface,
- float start, float stop,
- weston_surface_animation_frame_func_t frame,
- weston_surface_animation_frame_func_t reset,
- weston_surface_animation_done_func_t done,
- void *data)
+static struct weston_view_animation *
+weston_view_animation_run(struct weston_view *view,
+ float start, float stop,
+ weston_view_animation_frame_func_t frame,
+ weston_view_animation_frame_func_t reset,
+ weston_view_animation_done_func_t done,
+ void *data,
+ void *private)
{
- struct weston_surface_animation *animation;
+ struct weston_view_animation *animation;
animation = malloc(sizeof *animation);
if (!animation)
return NULL;
- animation->surface = surface;
+ animation->view = view;
animation->frame = frame;
animation->reset = reset;
animation->done = done;
animation->data = data;
animation->start = start;
animation->stop = stop;
+ animation->private = private;
weston_matrix_init(&animation->transform.matrix);
- wl_list_insert(&surface->geometry.transformation_list,
+ wl_list_insert(&view->geometry.transformation_list,
&animation->transform.link);
weston_spring_init(&animation->spring, 200.0, 0.0, 1.0);
animation->spring.friction = 700;
animation->animation.frame_counter = 0;
- animation->animation.frame = weston_surface_animation_frame;
- weston_surface_animation_frame(&animation->animation, NULL, 0);
+ animation->animation.frame = weston_view_animation_frame;
+ weston_view_animation_frame(&animation->animation, NULL, 0);
- animation->listener.notify = handle_animation_surface_destroy;
- wl_signal_add(&surface->destroy_signal, &animation->listener);
+ animation->listener.notify = handle_animation_view_destroy;
+ wl_signal_add(&view->destroy_signal, &animation->listener);
- wl_list_insert(&surface->output->animation_list,
+ wl_list_insert(&view->output->animation_list,
&animation->animation.link);
return animation;
}
static void
-reset_alpha(struct weston_surface_animation *animation)
+reset_alpha(struct weston_view_animation *animation)
{
- struct weston_surface *surface = animation->surface;
+ struct weston_view *view = animation->view;
- surface->alpha = animation->stop;
+ view->alpha = animation->stop;
}
static void
-zoom_frame(struct weston_surface_animation *animation)
+zoom_frame(struct weston_view_animation *animation)
{
- struct weston_surface *es = animation->surface;
+ struct weston_view *es = animation->view;
float scale;
scale = animation->start +
@@ -237,27 +240,27 @@ zoom_frame(struct weston_surface_animation *animation)
animation->spring.current;
weston_matrix_init(&animation->transform.matrix);
weston_matrix_translate(&animation->transform.matrix,
- -0.5f * es->geometry.width,
- -0.5f * es->geometry.height, 0);
+ -0.5f * es->surface->width,
+ -0.5f * es->surface->height, 0);
weston_matrix_scale(&animation->transform.matrix, scale, scale, scale);
weston_matrix_translate(&animation->transform.matrix,
- 0.5f * es->geometry.width,
- 0.5f * es->geometry.height, 0);
+ 0.5f * es->surface->width,
+ 0.5f * es->surface->height, 0);
es->alpha = animation->spring.current;
if (es->alpha > 1.0)
es->alpha = 1.0;
}
-WL_EXPORT struct weston_surface_animation *
-weston_zoom_run(struct weston_surface *surface, float start, float stop,
- weston_surface_animation_done_func_t done, void *data)
+WL_EXPORT struct weston_view_animation *
+weston_zoom_run(struct weston_view *view, float start, float stop,
+ weston_view_animation_done_func_t done, void *data)
{
- struct weston_surface_animation *zoom;
+ struct weston_view_animation *zoom;
- zoom = weston_surface_animation_run(surface, start, stop,
- zoom_frame, reset_alpha,
- done, data);
+ zoom = weston_view_animation_run(view, start, stop,
+ zoom_frame, reset_alpha,
+ done, data, NULL);
weston_spring_init(&zoom->spring, 300.0, start, stop);
zoom->spring.friction = 1400;
@@ -267,45 +270,85 @@ weston_zoom_run(struct weston_surface *surface, float start, float stop,
}
static void
-fade_frame(struct weston_surface_animation *animation)
+fade_frame(struct weston_view_animation *animation)
{
if (animation->spring.current > 0.999)
- animation->surface->alpha = 1;
+ animation->view->alpha = 1;
else if (animation->spring.current < 0.001 )
- animation->surface->alpha = 0;
+ animation->view->alpha = 0;
else
- animation->surface->alpha = animation->spring.current;
+ animation->view->alpha = animation->spring.current;
}
-WL_EXPORT struct weston_surface_animation *
-weston_fade_run(struct weston_surface *surface,
+WL_EXPORT struct weston_view_animation *
+weston_fade_run(struct weston_view *view,
float start, float end, float k,
- weston_surface_animation_done_func_t done, void *data)
+ weston_view_animation_done_func_t done, void *data)
{
- struct weston_surface_animation *fade;
+ struct weston_view_animation *fade;
- fade = weston_surface_animation_run(surface, 0, end,
- fade_frame, reset_alpha,
- done, data);
+ fade = weston_view_animation_run(view, 0, end,
+ fade_frame, reset_alpha,
+ done, data, NULL);
weston_spring_init(&fade->spring, k, start, end);
fade->spring.friction = 1400;
fade->spring.previous = -(end - start) * 0.03;
- surface->alpha = start;
+ view->alpha = start;
return fade;
}
WL_EXPORT void
-weston_fade_update(struct weston_surface_animation *fade, float target)
+weston_fade_update(struct weston_view_animation *fade, float target)
{
fade->spring.target = target;
}
static void
-slide_frame(struct weston_surface_animation *animation)
+stable_fade_frame(struct weston_view_animation *animation)
+{
+ struct weston_view *back_view;
+
+ if (animation->spring.current > 0.999)
+ animation->view->alpha = 1;
+ else if (animation->spring.current < 0.001 )
+ animation->view->alpha = 0;
+ else
+ animation->view->alpha = animation->spring.current;
+
+ back_view = (struct weston_view *) animation->private;
+ back_view->alpha =
+ (animation->spring.target - animation->view->alpha) /
+ (1.0 - animation->view->alpha);
+ weston_view_geometry_dirty(back_view);
+}
+
+WL_EXPORT struct weston_view_animation *
+weston_stable_fade_run(struct weston_view *front_view, float start,
+ struct weston_view *back_view, float end,
+ weston_view_animation_done_func_t done, void *data)
+{
+ struct weston_view_animation *fade;
+
+ fade = weston_view_animation_run(front_view, 0, 0,
+ stable_fade_frame, NULL,
+ done, data, back_view);
+
+
+ weston_spring_init(&fade->spring, 400, start, end);
+ fade->spring.friction = 1150;
+
+ front_view->alpha = start;
+ back_view->alpha = end;
+
+ return fade;
+}
+
+static void
+slide_frame(struct weston_view_animation *animation)
{
float scale;
@@ -316,15 +359,15 @@ slide_frame(struct weston_surface_animation *animation)
weston_matrix_translate(&animation->transform.matrix, 0, scale, 0);
}
-WL_EXPORT struct weston_surface_animation *
-weston_slide_run(struct weston_surface *surface, float start, float stop,
- weston_surface_animation_done_func_t done, void *data)
+WL_EXPORT struct weston_view_animation *
+weston_slide_run(struct weston_view *view, float start, float stop,
+ weston_view_animation_done_func_t done, void *data)
{
- struct weston_surface_animation *animation;
+ struct weston_view_animation *animation;
- animation = weston_surface_animation_run(surface, start, stop,
- slide_frame, NULL, done,
- data);
+ animation = weston_view_animation_run(view, start, stop,
+ slide_frame, NULL, done,
+ data, NULL);
if (!animation)
return NULL;
@@ -334,3 +377,65 @@ weston_slide_run(struct weston_surface *surface, float start, float stop,
return animation;
}
+
+struct weston_move_animation {
+ int dx;
+ int dy;
+ int reverse;
+ weston_view_animation_done_func_t done;
+};
+
+static void
+move_frame(struct weston_view_animation *animation)
+{
+ struct weston_move_animation *move = animation->private;
+ float scale;
+ float progress = animation->spring.current;
+
+ if (move->reverse)
+ progress = 1.0 - progress;
+
+ scale = animation->start +
+ (animation->stop - animation->start) *
+ progress;
+ weston_matrix_init(&animation->transform.matrix);
+ weston_matrix_scale(&animation->transform.matrix, scale, scale, 1.0f);
+ weston_matrix_translate(&animation->transform.matrix,
+ move->dx * progress, move->dy * progress,
+ 0);
+}
+
+static void
+move_done(struct weston_view_animation *animation, void *data)
+{
+ struct weston_move_animation *move = animation->private;
+
+ if (move->done)
+ move->done(animation, data);
+
+ free(move);
+}
+
+WL_EXPORT struct weston_view_animation *
+weston_move_scale_run(struct weston_view *view, int dx, int dy,
+ float start, float end, int reverse,
+ weston_view_animation_done_func_t done, void *data)
+{
+ struct weston_move_animation *move;
+ struct weston_view_animation *animation;
+
+ move = malloc(sizeof(*move));
+ if (!move)
+ return NULL;
+ move->dx = dx;
+ move->dy = dy;
+ move->reverse = reverse;
+ move->done = done;
+
+ animation = weston_view_animation_run(view, start, end, move_frame,
+ NULL, move_done, data, move);
+ animation->spring.k = 400;
+ animation->spring.friction = 1150;
+
+ return animation;
+}
diff --git a/src/bindings.c b/src/bindings.c
index 7cbded92..7d30024a 100644
--- a/src/bindings.c
+++ b/src/bindings.c
@@ -76,6 +76,24 @@ weston_compositor_add_key_binding(struct weston_compositor *compositor,
}
WL_EXPORT struct weston_binding *
+weston_compositor_add_modifier_binding(struct weston_compositor *compositor,
+ uint32_t modifier,
+ weston_modifier_binding_handler_t handler,
+ void *data)
+{
+ struct weston_binding *binding;
+
+ binding = weston_compositor_add_binding(compositor, 0, 0, 0,
+ modifier, handler, data);
+ if (binding == NULL)
+ return NULL;
+
+ wl_list_insert(compositor->modifier_binding_list.prev, &binding->link);
+
+ return binding;
+}
+
+WL_EXPORT struct weston_binding *
weston_compositor_add_button_binding(struct weston_compositor *compositor,
uint32_t button, uint32_t modifier,
weston_button_binding_handler_t handler,
@@ -248,6 +266,10 @@ weston_compositor_run_key_binding(struct weston_compositor *compositor,
if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
return;
+ /* Invalidate all active modifier bindings. */
+ wl_list_for_each(b, &compositor->modifier_binding_list, link)
+ b->key = key;
+
wl_list_for_each(b, &compositor->key_binding_list, link) {
if (b->key == key && b->modifier == seat->modifier_state) {
weston_key_binding_handler_t handler = b->handler;
@@ -264,6 +286,37 @@ weston_compositor_run_key_binding(struct weston_compositor *compositor,
}
WL_EXPORT void
+weston_compositor_run_modifier_binding(struct weston_compositor *compositor,
+ struct weston_seat *seat,
+ enum weston_keyboard_modifier modifier,
+ enum wl_keyboard_key_state state)
+{
+ struct weston_binding *b;
+
+ if (seat->keyboard->grab != &seat->keyboard->default_grab)
+ return;
+
+ wl_list_for_each(b, &compositor->modifier_binding_list, link) {
+ weston_modifier_binding_handler_t handler = b->handler;
+
+ if (b->modifier != modifier)
+ continue;
+
+ /* Prime the modifier binding. */
+ if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+ b->key = 0;
+ continue;
+ }
+ /* Ignore the binding if a key was pressed in between. */
+ else if (b->key != 0) {
+ return;
+ }
+
+ handler(seat, modifier, b->data);
+ }
+}
+
+WL_EXPORT void
weston_compositor_run_button_binding(struct weston_compositor *compositor,
struct weston_seat *seat,
uint32_t time, uint32_t button,
@@ -274,6 +327,10 @@ weston_compositor_run_button_binding(struct weston_compositor *compositor,
if (state == WL_POINTER_BUTTON_STATE_RELEASED)
return;
+ /* Invalidate all active modifier bindings. */
+ wl_list_for_each(b, &compositor->modifier_binding_list, link)
+ b->key = button;
+
wl_list_for_each(b, &compositor->button_binding_list, link) {
if (b->button == button && b->modifier == seat->modifier_state) {
weston_button_binding_handler_t handler = b->handler;
@@ -289,7 +346,7 @@ weston_compositor_run_touch_binding(struct weston_compositor *compositor,
{
struct weston_binding *b;
- if (seat->num_tp != 1 || touch_type != WL_TOUCH_DOWN)
+ if (seat->touch->num_tp != 1 || touch_type != WL_TOUCH_DOWN)
return;
wl_list_for_each(b, &compositor->touch_binding_list, link) {
@@ -308,6 +365,10 @@ weston_compositor_run_axis_binding(struct weston_compositor *compositor,
{
struct weston_binding *b;
+ /* Invalidate all active modifier bindings. */
+ wl_list_for_each(b, &compositor->modifier_binding_list, link)
+ b->key = axis;
+
wl_list_for_each(b, &compositor->axis_binding_list, link) {
if (b->axis == axis && b->modifier == seat->modifier_state) {
weston_axis_binding_handler_t handler = b->handler;
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 4f015d11..136d517e 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -33,6 +33,7 @@
#include <linux/vt.h>
#include <assert.h>
#include <sys/mman.h>
+#include <dlfcn.h>
#include <time.h>
#include <xf86drm.h>
@@ -155,7 +156,7 @@ struct drm_output {
struct gbm_bo *cursor_bo[2];
struct weston_plane cursor_plane;
struct weston_plane fb_plane;
- struct weston_surface *cursor_surface;
+ struct weston_view *cursor_view;
int current_cursor;
struct drm_fb *current, *next;
struct backlight *backlight;
@@ -194,6 +195,15 @@ struct drm_sprite {
uint32_t formats[];
};
+struct drm_parameters {
+ int connector;
+ int tty;
+ int use_pixman;
+ const char *seat_id;
+};
+
+static struct gl_renderer_interface *gl_renderer;
+
static const char default_seat[] = "seat0";
static void
@@ -402,7 +412,7 @@ drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
gbm_bo_destroy(fb->bo);
else
gbm_surface_release_buffer(output->surface,
- output->current->bo);
+ fb->bo);
}
}
@@ -410,52 +420,51 @@ static uint32_t
drm_output_check_scanout_format(struct drm_output *output,
struct weston_surface *es, struct gbm_bo *bo)
{
+ struct drm_compositor *c =
+ (struct drm_compositor *) output->base.compositor;
uint32_t format;
pixman_region32_t r;
format = gbm_bo_get_format(bo);
- switch (format) {
- case GBM_FORMAT_XRGB8888:
- return format;
- case GBM_FORMAT_ARGB8888:
- /* We can only scanout an ARGB buffer if the surface's
- * opaque region covers the whole output */
+ if (format == GBM_FORMAT_ARGB8888) {
+ /* We can scanout an ARGB buffer if the surface's
+ * opaque region covers the whole output, but we have
+ * to use XRGB as the KMS format code. */
pixman_region32_init(&r);
pixman_region32_subtract(&r, &output->base.region,
&es->opaque);
if (!pixman_region32_not_empty(&r))
format = GBM_FORMAT_XRGB8888;
- else
- format = 0;
pixman_region32_fini(&r);
+ }
+ if (c->format == format)
return format;
- default:
- return 0;
- }
+
+ return 0;
}
static struct weston_plane *
-drm_output_prepare_scanout_surface(struct weston_output *_output,
- struct weston_surface *es)
+drm_output_prepare_scanout_view(struct weston_output *_output,
+ struct weston_view *ev)
{
struct drm_output *output = (struct drm_output *) _output;
struct drm_compositor *c =
(struct drm_compositor *) output->base.compositor;
- struct weston_buffer *buffer = es->buffer_ref.buffer;
+ struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
struct gbm_bo *bo;
uint32_t format;
- if (es->geometry.x != output->base.x ||
- es->geometry.y != output->base.y ||
+ if (ev->geometry.x != output->base.x ||
+ ev->geometry.y != output->base.y ||
buffer == NULL || c->gbm == NULL ||
buffer->width != output->base.current_mode->width ||
buffer->height != output->base.current_mode->height ||
- output->base.transform != es->buffer_transform ||
- es->transform.enabled)
+ output->base.transform != ev->surface->buffer_viewport.transform ||
+ ev->transform.enabled)
return NULL;
bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
@@ -465,7 +474,7 @@ drm_output_prepare_scanout_surface(struct weston_output *_output,
if (!bo)
return NULL;
- format = drm_output_check_scanout_format(output, es, bo);
+ format = drm_output_check_scanout_format(output, ev->surface, bo);
if (format == 0) {
gbm_bo_destroy(bo);
return NULL;
@@ -587,7 +596,8 @@ drm_output_repaint(struct weston_output *output_base,
return -1;
mode = container_of(output->base.current_mode, struct drm_mode, base);
- if (!output->current) {
+ if (!output->current ||
+ output->current->stride != output->next->stride) {
ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
output->next->fb_id, 0, 0,
&output->connector_id, 1,
@@ -757,7 +767,7 @@ page_flip_handler(int fd, unsigned int frame,
static uint32_t
drm_output_check_sprite_format(struct drm_sprite *s,
- struct weston_surface *es, struct gbm_bo *bo)
+ struct weston_view *ev, struct gbm_bo *bo)
{
uint32_t i, format;
@@ -767,9 +777,9 @@ drm_output_check_sprite_format(struct drm_sprite *s,
pixman_region32_t r;
pixman_region32_init_rect(&r, 0, 0,
- es->geometry.width,
- es->geometry.height);
- pixman_region32_subtract(&r, &r, &es->opaque);
+ ev->surface->width,
+ ev->surface->height);
+ pixman_region32_subtract(&r, &r, &ev->surface->opaque);
if (!pixman_region32_not_empty(&r))
format = GBM_FORMAT_XRGB8888;
@@ -785,15 +795,15 @@ drm_output_check_sprite_format(struct drm_sprite *s,
}
static int
-drm_surface_transform_supported(struct weston_surface *es)
+drm_view_transform_supported(struct weston_view *ev)
{
- return !es->transform.enabled ||
- (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
+ return !ev->transform.enabled ||
+ (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
}
static struct weston_plane *
-drm_output_prepare_overlay_surface(struct weston_output *output_base,
- struct weston_surface *es)
+drm_output_prepare_overlay_view(struct weston_output *output_base,
+ struct weston_view *ev)
{
struct weston_compositor *ec = output_base->compositor;
struct drm_compositor *c =(struct drm_compositor *) ec;
@@ -808,28 +818,28 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base,
if (c->gbm == NULL)
return NULL;
- if (es->buffer_transform != output_base->transform)
+ if (ev->surface->buffer_viewport.transform != output_base->transform)
return NULL;
- if (es->buffer_scale != output_base->current_scale)
+ if (ev->surface->buffer_viewport.scale != output_base->current_scale)
return NULL;
if (c->sprites_are_broken)
return NULL;
- if (es->output_mask != (1u << output_base->id))
+ if (ev->output_mask != (1u << output_base->id))
return NULL;
- if (es->buffer_ref.buffer == NULL)
+ if (ev->surface->buffer_ref.buffer == NULL)
return NULL;
- if (es->alpha != 1.0f)
+ if (ev->alpha != 1.0f)
return NULL;
- if (wl_shm_buffer_get(es->buffer_ref.buffer->resource))
+ if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
return NULL;
- if (!drm_surface_transform_supported(es))
+ if (!drm_view_transform_supported(ev))
return NULL;
wl_list_for_each(s, &c->sprite_list, link) {
@@ -847,12 +857,12 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base,
return NULL;
bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
- es->buffer_ref.buffer->resource,
+ ev->surface->buffer_ref.buffer->resource,
GBM_BO_USE_SCANOUT);
if (!bo)
return NULL;
- format = drm_output_check_sprite_format(s, es, bo);
+ format = drm_output_check_sprite_format(s, ev, bo);
if (format == 0) {
gbm_bo_destroy(bo);
return NULL;
@@ -864,9 +874,9 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base,
return NULL;
}
- drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
+ drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
- box = pixman_region32_extents(&es->transform.boundingbox);
+ box = pixman_region32_extents(&ev->transform.boundingbox);
s->plane.x = box->x1;
s->plane.y = box->y1;
@@ -876,7 +886,7 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base,
* for us already).
*/
pixman_region32_init(&dest_rect);
- pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
+ pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
&output_base->region);
pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
box = pixman_region32_extents(&dest_rect);
@@ -892,36 +902,38 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base,
pixman_region32_fini(&dest_rect);
pixman_region32_init(&src_rect);
- pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
+ pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
&output_base->region);
box = pixman_region32_extents(&src_rect);
- weston_surface_from_global_fixed(es,
- wl_fixed_from_int(box->x1),
- wl_fixed_from_int(box->y1),
- &sx1, &sy1);
- weston_surface_from_global_fixed(es,
- wl_fixed_from_int(box->x2),
- wl_fixed_from_int(box->y2),
- &sx2, &sy2);
+ weston_view_from_global_fixed(ev,
+ wl_fixed_from_int(box->x1),
+ wl_fixed_from_int(box->y1),
+ &sx1, &sy1);
+ weston_view_from_global_fixed(ev,
+ wl_fixed_from_int(box->x2),
+ wl_fixed_from_int(box->y2),
+ &sx2, &sy2);
if (sx1 < 0)
sx1 = 0;
if (sy1 < 0)
sy1 = 0;
- if (sx2 > wl_fixed_from_int(es->geometry.width))
- sx2 = wl_fixed_from_int(es->geometry.width);
- if (sy2 > wl_fixed_from_int(es->geometry.height))
- sy2 = wl_fixed_from_int(es->geometry.height);
+ if (sx2 > wl_fixed_from_int(ev->surface->width))
+ sx2 = wl_fixed_from_int(ev->surface->width);
+ if (sy2 > wl_fixed_from_int(ev->surface->height))
+ sy2 = wl_fixed_from_int(ev->surface->height);
tbox.x1 = sx1;
tbox.y1 = sy1;
tbox.x2 = sx2;
tbox.y2 = sy2;
- tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
- wl_fixed_from_int(es->geometry.height),
- es->buffer_transform, es->buffer_scale, tbox);
+ tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
+ wl_fixed_from_int(ev->surface->height),
+ ev->surface->buffer_viewport.transform,
+ ev->surface->buffer_viewport.scale,
+ tbox);
s->src_x = tbox.x1 << 8;
s->src_y = tbox.y1 << 8;
@@ -933,8 +945,8 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base,
}
static struct weston_plane *
-drm_output_prepare_cursor_surface(struct weston_output *output_base,
- struct weston_surface *es)
+drm_output_prepare_cursor_view(struct weston_output *output_base,
+ struct weston_view *ev)
{
struct drm_compositor *c =
(struct drm_compositor *) output_base->compositor;
@@ -944,18 +956,18 @@ drm_output_prepare_cursor_surface(struct weston_output *output_base,
return NULL;
if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
return NULL;
- if (output->cursor_surface)
+ if (output->cursor_view)
return NULL;
- if (es->output_mask != (1u << output_base->id))
+ if (ev->output_mask != (1u << output_base->id))
return NULL;
if (c->cursors_are_broken)
return NULL;
- if (es->buffer_ref.buffer == NULL ||
- !wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
- es->geometry.width > 64 || es->geometry.height > 64)
+ if (ev->surface->buffer_ref.buffer == NULL ||
+ !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
+ ev->surface->width > 64 || ev->surface->height > 64)
return NULL;
- output->cursor_surface = es;
+ output->cursor_view = ev;
return &output->cursor_plane;
}
@@ -963,7 +975,8 @@ drm_output_prepare_cursor_surface(struct weston_output *output_base,
static void
drm_output_set_cursor(struct drm_output *output)
{
- struct weston_surface *es = output->cursor_surface;
+ struct weston_view *ev = output->cursor_view;
+ struct weston_buffer *buffer;
struct drm_compositor *c =
(struct drm_compositor *) output->base.compositor;
EGLint handle, stride;
@@ -972,24 +985,28 @@ drm_output_set_cursor(struct drm_output *output)
unsigned char *s;
int i, x, y;
- output->cursor_surface = NULL;
- if (es == NULL) {
+ output->cursor_view = NULL;
+ if (ev == NULL) {
drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
return;
}
- if (es->buffer_ref.buffer &&
+ buffer = ev->surface->buffer_ref.buffer;
+
+ if (buffer &&
pixman_region32_not_empty(&output->cursor_plane.damage)) {
pixman_region32_fini(&output->cursor_plane.damage);
pixman_region32_init(&output->cursor_plane.damage);
output->current_cursor ^= 1;
bo = output->cursor_bo[output->current_cursor];
memset(buf, 0, sizeof buf);
- stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer);
- s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer);
- for (i = 0; i < es->geometry.height; i++)
+ stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
+ s = wl_shm_buffer_get_data(buffer->shm_buffer);
+ wl_shm_buffer_begin_access(buffer->shm_buffer);
+ for (i = 0; i < ev->surface->height; i++)
memcpy(buf + i * 64, s + i * stride,
- es->geometry.width * 4);
+ ev->surface->width * 4);
+ wl_shm_buffer_end_access(buffer->shm_buffer);
if (gbm_bo_write(bo, buf, sizeof buf) < 0)
weston_log("failed update cursor: %m\n");
@@ -1002,8 +1019,8 @@ drm_output_set_cursor(struct drm_output *output)
}
}
- x = (es->geometry.x - output->base.x) * output->base.current_scale;
- y = (es->geometry.y - output->base.y) * output->base.current_scale;
+ x = (ev->geometry.x - output->base.x) * output->base.current_scale;
+ y = (ev->geometry.y - output->base.y) * output->base.current_scale;
if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
weston_log("failed to move cursor: %m\n");
@@ -1020,7 +1037,7 @@ drm_assign_planes(struct weston_output *output)
{
struct drm_compositor *c =
(struct drm_compositor *) output->compositor;
- struct weston_surface *es, *next;
+ struct weston_view *ev, *next;
pixman_region32_t overlap, surface_overlap;
struct weston_plane *primary, *next_plane;
@@ -1039,36 +1056,45 @@ drm_assign_planes(struct weston_output *output)
*/
pixman_region32_init(&overlap);
primary = &c->base.primary_plane;
- wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
- /* test whether this buffer can ever go into a plane:
- * non-shm, or small enough to be a cursor
+
+ wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
+ struct weston_surface *es = ev->surface;
+
+ /* Test whether this buffer can ever go into a plane:
+ * non-shm, or small enough to be a cursor.
+ *
+ * Also, keep a reference when using the pixman renderer.
+ * That makes it possible to do a seamless switch to the GL
+ * renderer and since the pixman renderer keeps a reference
+ * to the buffer anyway, there is no side effects.
*/
- if ((es->buffer_ref.buffer &&
- !wl_shm_buffer_get(es->buffer_ref.buffer->resource)) ||
- (es->geometry.width <= 64 && es->geometry.height <= 64))
+ if (c->use_pixman ||
+ (es->buffer_ref.buffer &&
+ (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
+ (ev->surface->width <= 64 && ev->surface->height <= 64))))
es->keep_buffer = 1;
else
es->keep_buffer = 0;
pixman_region32_init(&surface_overlap);
pixman_region32_intersect(&surface_overlap, &overlap,
- &es->transform.boundingbox);
+ &ev->transform.boundingbox);
next_plane = NULL;
if (pixman_region32_not_empty(&surface_overlap))
next_plane = primary;
if (next_plane == NULL)
- next_plane = drm_output_prepare_cursor_surface(output, es);
+ next_plane = drm_output_prepare_cursor_view(output, ev);
if (next_plane == NULL)
- next_plane = drm_output_prepare_scanout_surface(output, es);
+ next_plane = drm_output_prepare_scanout_view(output, ev);
if (next_plane == NULL)
- next_plane = drm_output_prepare_overlay_surface(output, es);
+ next_plane = drm_output_prepare_overlay_view(output, ev);
if (next_plane == NULL)
next_plane = primary;
- weston_surface_move_to_plane(es, next_plane);
+ weston_view_move_to_plane(ev, next_plane);
if (next_plane == primary)
pixman_region32_union(&overlap, &overlap,
- &es->transform.boundingbox);
+ &ev->transform.boundingbox);
pixman_region32_fini(&surface_overlap);
}
@@ -1112,7 +1138,7 @@ drm_output_destroy(struct weston_output *output_base)
if (c->use_pixman) {
drm_output_fini_pixman(output);
} else {
- gl_renderer_output_destroy(output_base);
+ gl_renderer->output_destroy(output_base);
gbm_surface_destroy(output->surface);
}
@@ -1120,7 +1146,6 @@ drm_output_destroy(struct weston_output *output_base)
weston_plane_release(&output->cursor_plane);
weston_output_destroy(&output->base);
- wl_list_remove(&output->base.link);
free(output);
}
@@ -1203,7 +1228,7 @@ drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mo
return -1;
}
} else {
- gl_renderer_output_destroy(&output->base);
+ gl_renderer->output_destroy(&output->base);
gbm_surface_destroy(output->surface);
if (drm_output_init_egl(output, ec) < 0) {
@@ -1268,19 +1293,51 @@ init_drm(struct drm_compositor *ec, struct udev_device *device)
return 0;
}
+static struct gbm_device *
+create_gbm_device(int fd)
+{
+ struct gbm_device *gbm;
+
+ gl_renderer = weston_load_module("gl-renderer.so",
+ "gl_renderer_interface");
+ if (!gl_renderer)
+ return NULL;
+
+ /* GBM will load a dri driver, but even though they need symbols from
+ * libglapi, in some version of Mesa they are not linked to it. Since
+ * only the gl-renderer module links to it, the call above won't make
+ * these symbols globally available, and loading the DRI driver fails.
+ * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
+ dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
+
+ gbm = gbm_create_device(fd);
+
+ return gbm;
+}
+
static int
-init_egl(struct drm_compositor *ec)
+drm_compositor_create_gl_renderer(struct drm_compositor *ec)
{
EGLint format;
- ec->gbm = gbm_create_device(ec->drm.fd);
+ format = ec->format;
+ if (gl_renderer->create(&ec->base, ec->gbm,
+ gl_renderer->opaque_attribs, &format) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+init_egl(struct drm_compositor *ec)
+{
+ ec->gbm = create_gbm_device(ec->drm.fd);
if (!ec->gbm)
return -1;
- format = ec->format;
- if (gl_renderer_create(&ec->base, ec->gbm,
- gl_renderer_opaque_attribs, &format) < 0) {
+ if (drm_compositor_create_gl_renderer(ec) < 0) {
gbm_device_destroy(ec->gbm);
return -1;
}
@@ -1482,7 +1539,7 @@ drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
return -1;
}
- if (gl_renderer_output_create(&output->base, output->surface) < 0) {
+ if (gl_renderer->output_create(&output->base, output->surface) < 0) {
weston_log("failed to create gl renderer output state\n");
gbm_surface_destroy(output->surface);
return -1;
@@ -1800,7 +1857,7 @@ create_output_for_connector(struct drm_compositor *ec,
int x, int y, struct udev_device *drm_device)
{
struct drm_output *output;
- struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
+ struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
struct weston_mode *m;
struct weston_config_section *section;
drmModeEncoder *encoder;
@@ -1903,6 +1960,7 @@ create_output_for_connector(struct drm_compositor *ec,
preferred = NULL;
current = NULL;
configured = NULL;
+ best = NULL;
wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
if (config == OUTPUT_CONFIG_MODE &&
@@ -1913,6 +1971,7 @@ create_output_for_connector(struct drm_compositor *ec,
current = drm_mode;
if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
preferred = drm_mode;
+ best = drm_mode;
}
if (config == OUTPUT_CONFIG_MODELINE) {
@@ -1938,6 +1997,8 @@ create_output_for_connector(struct drm_compositor *ec,
output->base.current_mode = &preferred->base;
else if (current)
output->base.current_mode = &current->base;
+ else if (best)
+ output->base.current_mode = &best->base;
if (output->base.current_mode == NULL) {
weston_log("no available modes for %s\n", output->base.name);
@@ -2050,7 +2111,7 @@ create_sprites(struct drm_compositor *ec)
if (!sprite) {
weston_log("%s: out of memory\n",
__func__);
- free(plane);
+ drmModeFreePlane(plane);
continue;
}
@@ -2165,7 +2226,6 @@ update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
drmModeRes *resources;
struct drm_output *output, *next;
int x = 0, y = 0;
- int x_offset = 0, y_offset = 0;
uint32_t connected = 0, disconnects = 0;
int i;
@@ -2215,17 +2275,10 @@ update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
if (disconnects) {
wl_list_for_each_safe(output, next, &ec->base.output_list,
base.link) {
- if (x_offset != 0 || y_offset != 0) {
- weston_output_move(&output->base,
- output->base.x - x_offset,
- output->base.y - y_offset);
- }
-
if (disconnects & (1 << output->connector_id)) {
disconnects &= ~(1 << output->connector_id);
weston_log("connector %d disconnected\n",
output->connector_id);
- x_offset += output->base.width;
drm_output_destroy(&output->base);
}
}
@@ -2289,8 +2342,6 @@ drm_destroy(struct weston_compositor *ec)
weston_compositor_shutdown(ec);
- ec->renderer->destroy(ec);
-
if (d->gbm)
gbm_device_destroy(d->gbm);
@@ -2343,7 +2394,6 @@ session_notify(struct wl_listener *listener, void *data)
if (ec->base.session_active) {
weston_log("activating session\n");
- compositor->focus = 1;
compositor->state = ec->prev_state;
drm_compositor_set_modes(ec);
weston_compositor_damage_all(compositor);
@@ -2352,7 +2402,6 @@ session_notify(struct wl_listener *listener, void *data)
weston_log("deactivating session\n");
udev_input_disable(&ec->input);
- compositor->focus = 0;
ec->prev_state = compositor->state;
weston_compositor_offscreen(compositor);
@@ -2557,16 +2606,62 @@ recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
}
#endif
+static void
+switch_to_gl_renderer(struct drm_compositor *c)
+{
+ struct drm_output *output;
+
+ if (!c->use_pixman)
+ return;
+
+ weston_log("Switching to GL renderer\n");
+
+ c->gbm = create_gbm_device(c->drm.fd);
+ if (!c->gbm) {
+ weston_log("Failed to create gbm device. "
+ "Aborting renderer switch\n");
+ return;
+ }
+
+ wl_list_for_each(output, &c->base.output_list, base.link)
+ pixman_renderer_output_destroy(&output->base);
+
+ c->base.renderer->destroy(&c->base);
+
+ if (drm_compositor_create_gl_renderer(c) < 0) {
+ gbm_device_destroy(c->gbm);
+ weston_log("Failed to create GL renderer. Quitting.\n");
+ /* FIXME: we need a function to shutdown cleanly */
+ assert(0);
+ }
+
+ wl_list_for_each(output, &c->base.output_list, base.link)
+ drm_output_init_egl(output, c);
+
+ c->use_pixman = 0;
+}
+
+static void
+renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
+ void *data)
+{
+ struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
+
+ switch_to_gl_renderer(c);
+}
+
static struct weston_compositor *
drm_compositor_create(struct wl_display *display,
- int connector, const char *seat_id, int tty, int pixman,
+ struct drm_parameters *param,
int *argc, char *argv[],
struct weston_config *config)
{
struct drm_compositor *ec;
+ struct weston_config_section *section;
struct udev_device *drm_device;
struct wl_event_loop *loop;
const char *path;
+ char *s;
uint32_t key;
weston_log("initializing drm backend\n");
@@ -2578,8 +2673,24 @@ drm_compositor_create(struct wl_display *display,
/* KMS support for sprites is not complete yet, so disable the
* functionality for now. */
ec->sprites_are_broken = 1;
- ec->format = GBM_FORMAT_XRGB8888;
- ec->use_pixman = pixman;
+
+ section = weston_config_get_section(config, "core", NULL, NULL);
+ weston_config_section_get_string(section,
+ "gbm-format", &s, "xrgb8888");
+ if (strcmp(s, "xrgb8888") == 0)
+ ec->format = GBM_FORMAT_XRGB8888;
+ else if (strcmp(s, "rgb565") == 0)
+ ec->format = GBM_FORMAT_RGB565;
+ else if (strcmp(s, "xrgb2101010") == 0)
+ ec->format = GBM_FORMAT_XRGB2101010;
+ else {
+ weston_log("fatal: unrecognized pixel format: %s\n", s);
+ free(s);
+ goto err_base;
+ }
+ free(s);
+
+ ec->use_pixman = param->use_pixman;
if (weston_compositor_init(&ec->base, display, argc, argv,
config) < 0) {
@@ -2588,7 +2699,8 @@ drm_compositor_create(struct wl_display *display,
}
/* Check if we run drm-backend using weston-launch */
- ec->base.launcher = weston_launcher_connect(&ec->base, tty);
+ ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
+ param->seat_id);
if (ec->base.launcher == NULL) {
weston_log("fatal: drm backend should be run "
"using weston-launch binary or as root\n");
@@ -2605,7 +2717,7 @@ drm_compositor_create(struct wl_display *display,
ec->session_listener.notify = session_notify;
wl_signal_add(&ec->base.session_signal, &ec->session_listener);
- drm_device = find_primary_gpu(ec, seat_id);
+ drm_device = find_primary_gpu(ec, param->seat_id);
if (drm_device == NULL) {
weston_log("no drm device found\n");
goto err_udev;
@@ -2632,8 +2744,6 @@ drm_compositor_create(struct wl_display *display,
ec->base.destroy = drm_destroy;
ec->base.restore = drm_restore;
- ec->base.focus = 1;
-
ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
for (key = KEY_F1; key < KEY_F9; key++)
@@ -2644,14 +2754,15 @@ drm_compositor_create(struct wl_display *display,
wl_list_init(&ec->sprite_list);
create_sprites(ec);
- if (create_outputs(ec, connector, drm_device) < 0) {
+ if (create_outputs(ec, param->connector, drm_device) < 0) {
weston_log("failed to create output for %s\n", path);
goto err_sprite;
}
path = NULL;
- if (udev_input_init(&ec->input, &ec->base, ec->udev, seat_id) < 0) {
+ if (udev_input_init(&ec->input,
+ &ec->base, ec->udev, param->seat_id) < 0) {
weston_log("failed to create input devices\n");
goto err_sprite;
}
@@ -2688,6 +2799,8 @@ drm_compositor_create(struct wl_display *display,
planes_binding, ec);
weston_compositor_add_debug_binding(&ec->base, KEY_Q,
recorder_binding, ec);
+ weston_compositor_add_debug_binding(&ec->base, KEY_W,
+ renderer_switch_binding, ec);
return &ec->base;
@@ -2718,19 +2831,19 @@ WL_EXPORT struct weston_compositor *
backend_init(struct wl_display *display, int *argc, char *argv[],
struct weston_config *config)
{
- int connector = 0, tty = 0, use_pixman = 0;
- const char *seat_id = default_seat;
+ struct drm_parameters param = { 0, };
const struct weston_option drm_options[] = {
- { WESTON_OPTION_INTEGER, "connector", 0, &connector },
- { WESTON_OPTION_STRING, "seat", 0, &seat_id },
- { WESTON_OPTION_INTEGER, "tty", 0, &tty },
+ { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
+ { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
+ { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
{ WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
- { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
+ { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
};
+ param.seat_id = default_seat;
+
parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
- return drm_compositor_create(display, connector, seat_id, tty, use_pixman,
- argc, argv, config);
+ return drm_compositor_create(display, &param, argc, argv, config);
}
diff --git a/src/compositor-fbdev.c b/src/compositor-fbdev.c
index 24140eff..0d962693 100644
--- a/src/compositor-fbdev.c
+++ b/src/compositor-fbdev.c
@@ -95,6 +95,8 @@ struct fbdev_parameters {
int use_gl;
};
+struct gl_renderer_interface *gl_renderer;
+
static const char default_seat[] = "seat0";
static inline struct fbdev_output *
@@ -625,7 +627,7 @@ fbdev_output_create(struct fbdev_compositor *compositor,
goto out_shadow_surface;
} else {
setenv("HYBRIS_EGLPLATFORM", "wayland", 1);
- if (gl_renderer_output_create(&output->base,
+ if (gl_renderer->output_create(&output->base,
(EGLNativeWindowType)NULL) < 0) {
weston_log("gl_renderer_output_create failed.\n");
goto out_shadow_surface;
@@ -686,11 +688,10 @@ fbdev_output_destroy(struct weston_output *base)
output->shadow_buf = NULL;
}
} else {
- gl_renderer_output_destroy(base);
+ gl_renderer->output_destroy(base);
}
/* Remove the output. */
- wl_list_remove(&output->base.link);
weston_output_destroy(&output->base);
free(output);
@@ -800,7 +801,6 @@ fbdev_compositor_destroy(struct weston_compositor *base)
weston_compositor_shutdown(&compositor->base);
/* Chain up. */
- compositor->base.renderer->destroy(&compositor->base);
weston_launcher_destroy(compositor->base.launcher);
free(compositor);
@@ -814,7 +814,6 @@ session_notify(struct wl_listener *listener, void *data)
if (compositor->base.session_active) {
weston_log("entering VT\n");
- compositor->base.focus = 1;
compositor->base.state = compositor->prev_state;
wl_list_for_each(output, &compositor->base.output_list, link) {
@@ -832,7 +831,6 @@ session_notify(struct wl_listener *listener, void *data)
fbdev_output_disable(output);
}
- compositor->base.focus = 0;
compositor->prev_state = compositor->base.state;
weston_compositor_offscreen(&compositor->base);
@@ -894,7 +892,7 @@ fbdev_compositor_create(struct wl_display *display, int *argc, char *argv[],
wl_signal_add(&compositor->base.session_signal,
&compositor->session_listener);
compositor->base.launcher =
- weston_launcher_connect(&compositor->base, param->tty);
+ weston_launcher_connect(&compositor->base, param->tty, "seat0");
if (!compositor->base.launcher) {
weston_log("fatal: fbdev backend should be run "
"using weston-launch binary or as root\n");
@@ -904,7 +902,6 @@ fbdev_compositor_create(struct wl_display *display, int *argc, char *argv[],
compositor->base.destroy = fbdev_compositor_destroy;
compositor->base.restore = fbdev_restore;
- compositor->base.focus = 1;
compositor->prev_state = WESTON_COMPOSITOR_ACTIVE;
compositor->use_pixman = !param->use_gl;
@@ -917,8 +914,16 @@ fbdev_compositor_create(struct wl_display *display, int *argc, char *argv[],
if (pixman_renderer_init(&compositor->base) < 0)
goto out_launcher;
} else {
- if (gl_renderer_create(&compositor->base, EGL_DEFAULT_DISPLAY,
- gl_renderer_opaque_attribs, NULL) < 0) {
+ gl_renderer = weston_load_module("gl-renderer.so",
+ "gl_renderer_interface");
+ if (!gl_renderer) {
+ weston_log("could not load gl renderer\n");
+ goto out_launcher;
+ }
+
+ if (gl_renderer->create(&compositor->base, EGL_DEFAULT_DISPLAY,
+ gl_renderer->opaque_attribs,
+ NULL) < 0) {
weston_log("gl_renderer_create failed.\n");
goto out_launcher;
}
diff --git a/src/compositor-headless.c b/src/compositor-headless.c
index 9d9f6dd3..5a5c1e68 100644
--- a/src/compositor-headless.c
+++ b/src/compositor-headless.c
@@ -114,8 +114,6 @@ headless_compositor_create_output(struct headless_compositor *c,
output->base.make = "weston";
output->base.model = "headless";
- weston_output_move(&output->base, 0, 0);
-
loop = wl_display_get_event_loop(c->base.wl_display);
output->finish_frame_timer =
wl_event_loop_add_timer(loop, finish_frame_handler, output);
@@ -143,8 +141,6 @@ headless_destroy(struct weston_compositor *ec)
{
struct headless_compositor *c = (struct headless_compositor *) ec;
- ec->renderer->destroy(ec);
-
weston_seat_release(&c->fake_seat);
weston_compositor_shutdown(ec);
diff --git a/src/compositor-rdp.c b/src/compositor-rdp.c
index 8a302f85..b9c36cfd 100644
--- a/src/compositor-rdp.c
+++ b/src/compositor-rdp.c
@@ -486,8 +486,6 @@ rdp_compositor_create_output(struct rdp_compositor *c, int width, int height,
if (pixman_renderer_output_create(&output->base) < 0)
goto out_shadow_surface;
- weston_output_move(&output->base, 0, 0);
-
loop = wl_display_get_event_loop(c->base.wl_display);
output->finish_frame_timer = wl_event_loop_add_timer(loop, finish_frame_handler, output);
@@ -523,7 +521,6 @@ rdp_restore(struct weston_compositor *ec)
static void
rdp_destroy(struct weston_compositor *ec)
{
- ec->renderer->destroy(ec);
weston_compositor_shutdown(ec);
free(ec);
@@ -599,8 +596,11 @@ rdp_peer_context_free(freerdp_peer* client, RdpPeerContext* context)
wl_event_source_remove(context->events[i]);
}
- if(context->item.flags & RDP_PEER_ACTIVATED)
+ if(context->item.flags & RDP_PEER_ACTIVATED) {
+ weston_seat_release_keyboard(&context->item.seat);
+ weston_seat_release_pointer(&context->item.seat);
weston_seat_release(&context->item.seat);
+ }
Stream_Free(context->encode_stream, TRUE);
nsc_context_free(context->nsc_context);
rfx_context_free(context->rfx_context);
diff --git a/src/compositor-rpi.c b/src/compositor-rpi.c
index 60926325..399090dd 100644
--- a/src/compositor-rpi.c
+++ b/src/compositor-rpi.c
@@ -45,6 +45,7 @@
#include "rpi-renderer.h"
#include "evdev.h"
#include "launcher-util.h"
+#include "udev-seat.h"
#if 0
#define DBG(...) \
@@ -87,6 +88,7 @@ struct rpi_compositor {
uint32_t prev_state;
struct udev *udev;
+ struct udev_input input;
struct wl_listener session_listener;
int single_buffer;
@@ -276,7 +278,6 @@ rpi_output_destroy(struct weston_output *base)
*/
rpi_flippipe_release(&output->flippipe);
- wl_list_remove(&output->base.link);
weston_output_destroy(&output->base);
vc_dispmanx_display_close(output->display);
@@ -415,247 +416,15 @@ out_free:
}
static void
-rpi_led_update(struct weston_seat *seat_base, enum weston_led leds)
-{
- struct rpi_seat *seat = to_rpi_seat(seat_base);
- struct evdev_device *device;
-
- wl_list_for_each(device, &seat->devices_list, link)
- evdev_led_update(device, leds);
-}
-
-static const char default_seat[] = "seat0";
-
-static void
-device_added(struct udev_device *udev_device, struct rpi_seat *master)
-{
- struct evdev_device *device;
- const char *devnode;
- const char *device_seat;
- int fd;
-
- device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
- if (!device_seat)
- device_seat = default_seat;
-
- if (strcmp(device_seat, master->seat_id))
- return;
-
- devnode = udev_device_get_devnode(udev_device);
-
- /* Use non-blocking mode so that we can loop on read on
- * evdev_device_data() until all events on the fd are
- * read. mtdev_get() also expects this. */
- fd = open(devnode, O_RDWR | O_NONBLOCK | O_CLOEXEC);
- if (fd < 0) {
- weston_log("opening input device '%s' failed.\n", devnode);
- return;
- }
-
- device = evdev_device_create(&master->base, devnode, fd);
- if (!device) {
- close(fd);
- weston_log("not using input device '%s'.\n", devnode);
- return;
- }
-
- wl_list_insert(master->devices_list.prev, &device->link);
-}
-
-static void
-evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
-{
- struct rpi_seat *seat = to_rpi_seat(seat_base);
- struct udev_enumerate *e;
- struct udev_list_entry *entry;
- struct udev_device *device;
- const char *path, *sysname;
-
- e = udev_enumerate_new(udev);
- udev_enumerate_add_match_subsystem(e, "input");
- udev_enumerate_scan_devices(e);
- udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
- path = udev_list_entry_get_name(entry);
- device = udev_device_new_from_syspath(udev, path);
-
- sysname = udev_device_get_sysname(device);
- if (strncmp("event", sysname, 5) != 0) {
- udev_device_unref(device);
- continue;
- }
-
- device_added(device, seat);
-
- udev_device_unref(device);
- }
- udev_enumerate_unref(e);
-
- evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
-
- if (wl_list_empty(&seat->devices_list)) {
- weston_log(
- "warning: no input devices on entering Weston. "
- "Possible causes:\n"
- "\t- no permissions to read /dev/input/event*\n"
- "\t- seats misconfigured "
- "(Weston backend option 'seat', "
- "udev device property ID_SEAT)\n");
- }
-}
-
-static int
-evdev_udev_handler(int fd, uint32_t mask, void *data)
-{
- struct rpi_seat *seat = data;
- struct udev_device *udev_device;
- struct evdev_device *device, *next;
- const char *action;
- const char *devnode;
-
- udev_device = udev_monitor_receive_device(seat->udev_monitor);
- if (!udev_device)
- return 1;
-
- action = udev_device_get_action(udev_device);
- if (!action)
- goto out;
-
- if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
- goto out;
-
- if (!strcmp(action, "add")) {
- device_added(udev_device, seat);
- }
- else if (!strcmp(action, "remove")) {
- devnode = udev_device_get_devnode(udev_device);
- wl_list_for_each_safe(device, next, &seat->devices_list, link)
- if (!strcmp(device->devnode, devnode)) {
- weston_log("input device %s, %s removed\n",
- device->devname, device->devnode);
- evdev_device_destroy(device);
- break;
- }
- }
-
-out:
- udev_device_unref(udev_device);
-
- return 0;
-}
-
-static int
-evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
-{
- struct rpi_seat *master = to_rpi_seat(seat_base);
- struct wl_event_loop *loop;
- struct weston_compositor *c = master->base.compositor;
- int fd;
-
- master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
- if (!master->udev_monitor) {
- weston_log("udev: failed to create the udev monitor\n");
- return 0;
- }
-
- udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
- "input", NULL);
-
- if (udev_monitor_enable_receiving(master->udev_monitor)) {
- weston_log("udev: failed to bind the udev monitor\n");
- udev_monitor_unref(master->udev_monitor);
- return 0;
- }
-
- loop = wl_display_get_event_loop(c->wl_display);
- fd = udev_monitor_get_fd(master->udev_monitor);
- master->udev_monitor_source =
- wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
- evdev_udev_handler, master);
- if (!master->udev_monitor_source) {
- udev_monitor_unref(master->udev_monitor);
- return 0;
- }
-
- return 1;
-}
-
-static void
-evdev_disable_udev_monitor(struct weston_seat *seat_base)
-{
- struct rpi_seat *seat = to_rpi_seat(seat_base);
-
- if (!seat->udev_monitor)
- return;
-
- udev_monitor_unref(seat->udev_monitor);
- seat->udev_monitor = NULL;
- wl_event_source_remove(seat->udev_monitor_source);
- seat->udev_monitor_source = NULL;
-}
-
-static void
-evdev_input_create(struct weston_compositor *c, struct udev *udev,
- const char *seat_id)
-{
- struct rpi_seat *seat;
-
- seat = zalloc(sizeof *seat);
- if (seat == NULL)
- return;
-
- weston_seat_init(&seat->base, c, "default");
- seat->base.led_update = rpi_led_update;
-
- wl_list_init(&seat->devices_list);
- seat->seat_id = strdup(seat_id);
- if (!evdev_enable_udev_monitor(udev, &seat->base)) {
- free(seat->seat_id);
- free(seat);
- return;
- }
-
- evdev_add_devices(udev, &seat->base);
-}
-
-static void
-evdev_remove_devices(struct weston_seat *seat_base)
-{
- struct rpi_seat *seat = to_rpi_seat(seat_base);
- struct evdev_device *device, *next;
-
- wl_list_for_each_safe(device, next, &seat->devices_list, link)
- evdev_device_destroy(device);
-
- if (seat->base.keyboard)
- notify_keyboard_focus_out(&seat->base);
-}
-
-static void
-evdev_input_destroy(struct weston_seat *seat_base)
-{
- struct rpi_seat *seat = to_rpi_seat(seat_base);
-
- evdev_remove_devices(seat_base);
- evdev_disable_udev_monitor(&seat->base);
-
- weston_seat_release(seat_base);
- free(seat->seat_id);
- free(seat);
-}
-
-static void
rpi_compositor_destroy(struct weston_compositor *base)
{
struct rpi_compositor *compositor = to_rpi_compositor(base);
- struct weston_seat *seat, *next;
- wl_list_for_each_safe(seat, next, &compositor->base.seat_list, link)
- evdev_input_destroy(seat);
+ udev_input_destroy(&compositor->input);
/* destroys outputs, too */
weston_compositor_shutdown(&compositor->base);
- compositor->base.renderer->destroy(&compositor->base);
weston_launcher_destroy(compositor->base.launcher);
bcm_host_deinit();
@@ -666,26 +435,17 @@ static void
session_notify(struct wl_listener *listener, void *data)
{
struct rpi_compositor *compositor = data;
- struct weston_seat *seat;
struct weston_output *output;
if (compositor->base.session_active) {
weston_log("activating session\n");
- compositor->base.focus = 1;
compositor->base.state = compositor->prev_state;
weston_compositor_damage_all(&compositor->base);
- wl_list_for_each(seat, &compositor->base.seat_list, link) {
- evdev_add_devices(compositor->udev, seat);
- evdev_enable_udev_monitor(compositor->udev, seat);
- }
+ udev_input_enable(&compositor->input, compositor->udev);
} else {
weston_log("deactivating session\n");
- wl_list_for_each(seat, &compositor->base.seat_list, link) {
- evdev_disable_udev_monitor(seat);
- evdev_remove_devices(seat);
- }
+ udev_input_disable(&compositor->input);
- compositor->base.focus = 0;
compositor->prev_state = compositor->base.state;
weston_compositor_offscreen(&compositor->base);
@@ -730,7 +490,6 @@ rpi_compositor_create(struct wl_display *display, int *argc, char *argv[],
struct rpi_parameters *param)
{
struct rpi_compositor *compositor;
- const char *seat = default_seat;
uint32_t key;
weston_log("initializing Raspberry Pi backend\n");
@@ -753,7 +512,7 @@ rpi_compositor_create(struct wl_display *display, int *argc, char *argv[],
wl_signal_add(&compositor->base.session_signal,
&compositor ->session_listener);
compositor->base.launcher =
- weston_launcher_connect(&compositor->base, param->tty);
+ weston_launcher_connect(&compositor->base, param->tty, "seat0");
if (!compositor->base.launcher) {
weston_log("Failed to initialize tty.\n");
goto out_udev;
@@ -762,13 +521,19 @@ rpi_compositor_create(struct wl_display *display, int *argc, char *argv[],
compositor->base.destroy = rpi_compositor_destroy;
compositor->base.restore = rpi_restore;
- compositor->base.focus = 1;
compositor->prev_state = WESTON_COMPOSITOR_ACTIVE;
compositor->single_buffer = param->renderer.single_buffer;
weston_log("Dispmanx planes are %s buffered.\n",
compositor->single_buffer ? "single" : "double");
+ if (udev_input_init(&compositor->input,
+ &compositor->base,
+ compositor->udev, "seat0") != 0) {
+ weston_log("Failed to initialize udev input.\n");
+ goto out_launcher;
+ }
+
for (key = KEY_F1; key < KEY_F9; key++)
weston_compositor_add_key_binding(&compositor->base, key,
MODIFIER_CTRL | MODIFIER_ALT,
@@ -784,18 +549,19 @@ rpi_compositor_create(struct wl_display *display, int *argc, char *argv[],
bcm_host_init();
if (rpi_renderer_create(&compositor->base, &param->renderer) < 0)
- goto out_launcher;
+ goto out_udev_input;
if (rpi_output_create(compositor, param->output_transform) < 0)
goto out_renderer;
- evdev_input_create(&compositor->base, compositor->udev, seat);
-
return &compositor->base;
out_renderer:
compositor->base.renderer->destroy(&compositor->base);
+out_udev_input:
+ udev_input_destroy(&compositor->input);
+
out_launcher:
weston_launcher_destroy(compositor->base.launcher);
@@ -823,6 +589,7 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
.tty = 0, /* default to current tty */
.renderer.single_buffer = 0,
.output_transform = WL_OUTPUT_TRANSFORM_NORMAL,
+ .renderer.opaque_regions = 0,
};
const struct weston_option rpi_options[] = {
@@ -830,6 +597,8 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
{ WESTON_OPTION_BOOLEAN, "single-buffer", 0,
&param.renderer.single_buffer },
{ WESTON_OPTION_STRING, "transform", 0, &transform },
+ { WESTON_OPTION_BOOLEAN, "opaque-regions", 0,
+ &param.renderer.opaque_regions },
};
parse_options(rpi_options, ARRAY_LENGTH(rpi_options), argc, argv);
diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index f3b03619..d2d89427 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -1,5 +1,6 @@
/*
* Copyright © 2010-2011 Benjamin Franzke
+ * Copyright © 2013 Jason Ekstrand
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
@@ -29,169 +30,347 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
+#include <linux/input.h>
#include <wayland-client.h>
#include <wayland-egl.h>
+#include <wayland-cursor.h>
#include "compositor.h"
#include "gl-renderer.h"
+#include "pixman-renderer.h"
#include "../shared/image-loader.h"
#include "../shared/os-compatibility.h"
+#include "../shared/cairo-util.h"
+
+#define WINDOW_TITLE "Weston Compositor"
struct wayland_compositor {
- struct weston_compositor base;
+ struct weston_compositor base;
struct {
struct wl_display *wl_display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_shell *shell;
- struct wl_output *output;
struct wl_shm *shm;
- struct {
- int32_t x, y, width, height;
- } screen_allocation;
-
struct wl_event_source *wl_source;
uint32_t event_mask;
} parent;
- struct {
- int32_t top, bottom, left, right;
- } border;
+ int use_pixman;
+
+ struct theme *theme;
+ cairo_device_t *frame_device;
+ struct wl_cursor_theme *cursor_theme;
+ struct wl_cursor *cursor;
struct wl_list input_list;
};
struct wayland_output {
- struct weston_output base;
+ struct weston_output base;
+
struct {
- int draw_initial_frame;
- struct wl_surface *surface;
- struct wl_shell_surface *shell_surface;
- struct wl_egl_window *egl_window;
+ int draw_initial_frame;
+ struct wl_surface *surface;
+ struct wl_shell_surface *shell_surface;
+ int configure_width, configure_height;
} parent;
- struct weston_mode mode;
+
+ int keyboard_count;
+
+ char *name;
+ struct frame *frame;
+
+ struct {
+ struct wl_egl_window *egl_window;
+ struct {
+ cairo_surface_t *top;
+ cairo_surface_t *left;
+ cairo_surface_t *right;
+ cairo_surface_t *bottom;
+ } border;
+ } gl;
+
+ struct {
+ struct wl_list buffers;
+ struct wl_list free_buffers;
+ } shm;
+
+ struct weston_mode mode;
+ uint32_t scale;
+};
+
+struct wayland_shm_buffer {
+ struct wayland_output *output;
+ struct wl_list link;
+ struct wl_list free_link;
+
+ struct wl_buffer *buffer;
+ void *data;
+ size_t size;
+ pixman_region32_t damage;
+ int frame_damaged;
+
+ pixman_image_t *pm_image;
+ cairo_surface_t *c_surface;
};
struct wayland_input {
struct weston_seat base;
struct wayland_compositor *compositor;
- struct wl_seat *seat;
- struct wl_pointer *pointer;
- struct wl_keyboard *keyboard;
- struct wl_touch *touch;
struct wl_list link;
+
+ struct {
+ struct wl_seat *seat;
+ struct wl_pointer *pointer;
+ struct wl_keyboard *keyboard;
+ struct wl_touch *touch;
+
+ struct {
+ struct wl_surface *surface;
+ int32_t hx, hy;
+ } cursor;
+ } parent;
+
uint32_t key_serial;
uint32_t enter_serial;
int focus;
struct wayland_output *output;
+ struct wayland_output *keyboard_focus;
};
+struct gl_renderer_interface *gl_renderer;
+
static void
-create_border(struct wayland_compositor *c)
+wayland_shm_buffer_destroy(struct wayland_shm_buffer *buffer)
{
- pixman_image_t *image;
- int32_t edges[4];
-
- image = load_image(DATADIR "/weston/border.png");
- if (!image) {
- weston_log("couldn't load border image\n");
- return;
- }
-
- edges[0] = c->border.left;
- edges[1] = c->border.right;
- edges[2] = c->border.top;
- edges[3] = c->border.bottom;
-
- gl_renderer_set_border(&c->base, pixman_image_get_width(image),
- pixman_image_get_height(image),
- pixman_image_get_data(image), edges);
+ cairo_surface_destroy(buffer->c_surface);
+ pixman_image_unref(buffer->pm_image);
- pixman_image_unref(image);
-}
+ wl_buffer_destroy(buffer->buffer);
+ munmap(buffer->data, buffer->size);
-static void
-frame_done(void *data, struct wl_callback *callback, uint32_t time)
-{
- struct weston_output *output = data;
+ pixman_region32_fini(&buffer->damage);
- wl_callback_destroy(callback);
- weston_output_finish_frame(output, time);
+ wl_list_remove(&buffer->link);
+ wl_list_remove(&buffer->free_link);
+ free(buffer);
}
-static const struct wl_callback_listener frame_listener = {
- frame_done
-};
-
static void
buffer_release(void *data, struct wl_buffer *buffer)
{
- wl_buffer_destroy(buffer);
+ struct wayland_shm_buffer *sb = data;
+
+ if (sb->output) {
+ wl_list_insert(&sb->output->shm.free_buffers, &sb->free_link);
+ } else {
+ wayland_shm_buffer_destroy(sb);
+ }
}
static const struct wl_buffer_listener buffer_listener = {
buffer_release
};
-static void
-draw_initial_frame(struct wayland_output *output)
+static struct wayland_shm_buffer *
+wayland_output_get_shm_buffer(struct wayland_output *output)
{
struct wayland_compositor *c =
(struct wayland_compositor *) output->base.compositor;
struct wl_shm *shm = c->parent.shm;
- struct wl_surface *surface = output->parent.surface;
- struct wl_shm_pool *pool;
- struct wl_buffer *buffer;
+ struct wayland_shm_buffer *sb;
+ struct wl_shm_pool *pool;
int width, height, stride;
- int size;
+ int32_t fx, fy;
int fd;
- void *data;
+ unsigned char *data;
+
+ if (!wl_list_empty(&output->shm.free_buffers)) {
+ sb = container_of(output->shm.free_buffers.next,
+ struct wayland_shm_buffer, free_link);
+ wl_list_remove(&sb->free_link);
+ wl_list_init(&sb->free_link);
+
+ return sb;
+ }
+
+ if (output->frame) {
+ width = frame_width(output->frame);
+ height = frame_height(output->frame);
+ } else {
+ width = output->base.current_mode->width;
+ height = output->base.current_mode->height;
+ }
- width = output->mode.width + c->border.left + c->border.right;
- height = output->mode.height + c->border.top + c->border.bottom;
- stride = width * 4;
- size = height * stride;
+ stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
- fd = os_create_anonymous_file(size);
+ fd = os_create_anonymous_file(height * stride);
if (fd < 0) {
perror("os_create_anonymous_file");
- return;
+ return NULL;
}
- data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ data = mmap(NULL, height * stride, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
perror("mmap");
close(fd);
- return;
+ return NULL;
}
- pool = wl_shm_create_pool(shm, fd, size);
+ sb = zalloc(sizeof *sb);
+
+ sb->output = output;
+ wl_list_init(&sb->free_link);
+ wl_list_insert(&output->shm.buffers, &sb->link);
+
+ pixman_region32_init_rect(&sb->damage, 0, 0,
+ output->base.width, output->base.height);
+ sb->frame_damaged = 1;
+
+ sb->data = data;
+ sb->size = height * stride;
+
+ pool = wl_shm_create_pool(shm, fd, sb->size);
- buffer = wl_shm_pool_create_buffer(pool, 0,
- width, height,
- stride,
- WL_SHM_FORMAT_ARGB8888);
- wl_buffer_add_listener(buffer, &buffer_listener, buffer);
+ sb->buffer = wl_shm_pool_create_buffer(pool, 0,
+ width, height,
+ stride,
+ WL_SHM_FORMAT_ARGB8888);
+ wl_buffer_add_listener(sb->buffer, &buffer_listener, sb);
wl_shm_pool_destroy(pool);
close(fd);
- memset(data, 0, size);
+ memset(data, 0, sb->size);
+
+ sb->c_surface =
+ cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32,
+ width, height, stride);
+
+ fx = 0;
+ fy = 0;
+ if (output->frame)
+ frame_interior(output->frame, &fx, &fy, 0, 0);
+ sb->pm_image =
+ pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height,
+ (uint32_t *)(data + fy * stride) + fx,
+ stride);
+
+ return sb;
+}
+
+static void
+frame_done(void *data, struct wl_callback *callback, uint32_t time)
+{
+ struct weston_output *output = data;
+
+ wl_callback_destroy(callback);
+ weston_output_finish_frame(output, time);
+}
+
+static const struct wl_callback_listener frame_listener = {
+ frame_done
+};
+
+static void
+draw_initial_frame(struct wayland_output *output)
+{
+ struct wayland_shm_buffer *sb;
+
+ sb = wayland_output_get_shm_buffer(output);
- wl_surface_attach(surface, buffer, 0, 0);
+ /* If we are rendering with GL, then orphan it so that it gets
+ * destroyed immediately */
+ if (output->gl.egl_window)
+ sb->output = NULL;
+
+ wl_surface_attach(output->parent.surface, sb->buffer, 0, 0);
/* We only need to damage some part, as its only transparant
* pixels anyway. */
- wl_surface_damage(surface, 0, 0, 1, 1);
+ wl_surface_damage(output->parent.surface, 0, 0, 1, 1);
+}
+
+static void
+wayland_output_update_gl_border(struct wayland_output *output)
+{
+ int32_t ix, iy, iwidth, iheight, fwidth, fheight;
+ cairo_t *cr;
+
+ if (!output->frame)
+ return;
+ if (!(frame_status(output->frame) & FRAME_STATUS_REPAINT))
+ return;
+
+ fwidth = frame_width(output->frame);
+ fheight = frame_height(output->frame);
+ frame_interior(output->frame, &ix, &iy, &iwidth, &iheight);
+
+ if (!output->gl.border.top)
+ output->gl.border.top =
+ cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ fwidth, iy);
+ cr = cairo_create(output->gl.border.top);
+ frame_repaint(output->frame, cr);
+ cairo_destroy(cr);
+ gl_renderer->output_set_border(&output->base, GL_RENDERER_BORDER_TOP,
+ fwidth, iy,
+ cairo_image_surface_get_stride(output->gl.border.top) / 4,
+ cairo_image_surface_get_data(output->gl.border.top));
+
+
+ if (!output->gl.border.left)
+ output->gl.border.left =
+ cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ ix, 1);
+ cr = cairo_create(output->gl.border.left);
+ cairo_translate(cr, 0, -iy);
+ frame_repaint(output->frame, cr);
+ cairo_destroy(cr);
+ gl_renderer->output_set_border(&output->base, GL_RENDERER_BORDER_LEFT,
+ ix, 1,
+ cairo_image_surface_get_stride(output->gl.border.left) / 4,
+ cairo_image_surface_get_data(output->gl.border.left));
+
+
+ if (!output->gl.border.right)
+ output->gl.border.right =
+ cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ fwidth - (ix + iwidth), 1);
+ cr = cairo_create(output->gl.border.right);
+ cairo_translate(cr, -(iwidth + ix), -iy);
+ frame_repaint(output->frame, cr);
+ cairo_destroy(cr);
+ gl_renderer->output_set_border(&output->base, GL_RENDERER_BORDER_RIGHT,
+ fwidth - (ix + iwidth), 1,
+ cairo_image_surface_get_stride(output->gl.border.right) / 4,
+ cairo_image_surface_get_data(output->gl.border.right));
+
+
+ if (!output->gl.border.bottom)
+ output->gl.border.bottom =
+ cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ fwidth, fheight - (iy + iheight));
+ cr = cairo_create(output->gl.border.bottom);
+ cairo_translate(cr, 0, -(iy + iheight));
+ frame_repaint(output->frame, cr);
+ cairo_destroy(cr);
+ gl_renderer->output_set_border(&output->base, GL_RENDERER_BORDER_BOTTOM,
+ fwidth, fheight - (iy + iheight),
+ cairo_image_surface_get_stride(output->gl.border.bottom) / 4,
+ cairo_image_surface_get_data(output->gl.border.bottom));
}
static void
wayland_output_start_repaint_loop(struct weston_output *output_base)
{
struct wayland_output *output = (struct wayland_output *) output_base;
+ struct wayland_compositor *wc =
+ (struct wayland_compositor *)output->base.compositor;
struct wl_callback *callback;
/* If this is the initial frame, we need to attach a buffer so that
@@ -208,11 +387,12 @@ wayland_output_start_repaint_loop(struct weston_output *output_base)
callback = wl_surface_frame(output->parent.surface);
wl_callback_add_listener(callback, &frame_listener, output);
wl_surface_commit(output->parent.surface);
+ wl_display_flush(wc->parent.wl_display);
}
static int
-wayland_output_repaint(struct weston_output *output_base,
- pixman_region32_t *damage)
+wayland_output_repaint_gl(struct weston_output *output_base,
+ pixman_region32_t *damage)
{
struct wayland_output *output = (struct wayland_output *) output_base;
struct weston_compositor *ec = output->base.compositor;
@@ -221,6 +401,8 @@ wayland_output_repaint(struct weston_output *output_base,
callback = wl_surface_frame(output->parent.surface);
wl_callback_add_listener(callback, &frame_listener, output);
+ wayland_output_update_gl_border(output);
+
ec->renderer->repaint_output(&output->base, damage);
pixman_region32_subtract(&ec->primary_plane.damage,
@@ -229,13 +411,159 @@ wayland_output_repaint(struct weston_output *output_base,
}
static void
+wayland_output_update_shm_border(struct wayland_shm_buffer *buffer)
+{
+ int32_t ix, iy, iwidth, iheight, fwidth, fheight;
+ cairo_t *cr;
+
+ if (!buffer->output->frame || !buffer->frame_damaged)
+ return;
+
+ cr = cairo_create(buffer->c_surface);
+
+ frame_interior(buffer->output->frame, &ix, &iy, &iwidth, &iheight);
+ fwidth = frame_width(buffer->output->frame);
+ fheight = frame_height(buffer->output->frame);
+
+ /* Set the clip so we don't unnecisaraly damage the surface */
+ cairo_move_to(cr, ix, iy);
+ cairo_rel_line_to(cr, iwidth, 0);
+ cairo_rel_line_to(cr, 0, iheight);
+ cairo_rel_line_to(cr, -iwidth, 0);
+ cairo_line_to(cr, ix, iy);
+ cairo_line_to(cr, 0, iy);
+ cairo_line_to(cr, 0, fheight);
+ cairo_line_to(cr, fwidth, fheight);
+ cairo_line_to(cr, fwidth, 0);
+ cairo_line_to(cr, 0, 0);
+ cairo_line_to(cr, 0, iy);
+ cairo_close_path(cr);
+ cairo_clip(cr);
+
+ /* Draw using a pattern so that the final result gets clipped */
+ cairo_push_group(cr);
+ frame_repaint(buffer->output->frame, cr);
+ cairo_pop_group_to_source(cr);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(cr);
+
+ cairo_destroy(cr);
+}
+
+static void
+wayland_shm_buffer_attach(struct wayland_shm_buffer *sb)
+{
+ pixman_region32_t damage;
+ pixman_box32_t *rects;
+ int32_t ix, iy, iwidth, iheight, fwidth, fheight;
+ int i, n;
+
+ pixman_region32_init(&damage);
+ weston_transformed_region(sb->output->base.width,
+ sb->output->base.height,
+ sb->output->base.transform,
+ sb->output->base.current_scale,
+ &sb->damage, &damage);
+
+ if (sb->output->frame) {
+ frame_interior(sb->output->frame, &ix, &iy, &iwidth, &iheight);
+ fwidth = frame_width(sb->output->frame);
+ fheight = frame_height(sb->output->frame);
+
+ pixman_region32_translate(&damage, ix, iy);
+
+ if (sb->frame_damaged) {
+ pixman_region32_union_rect(&damage, &damage,
+ 0, 0, fwidth, iy);
+ pixman_region32_union_rect(&damage, &damage,
+ 0, iy, ix, iheight);
+ pixman_region32_union_rect(&damage, &damage,
+ ix + iwidth, iy,
+ fwidth - (ix + iwidth), iheight);
+ pixman_region32_union_rect(&damage, &damage,
+ 0, iy + iheight,
+ fwidth, fheight - (iy + iheight));
+ }
+ }
+
+ rects = pixman_region32_rectangles(&damage, &n);
+ wl_surface_attach(sb->output->parent.surface, sb->buffer, 0, 0);
+ for (i = 0; i < n; ++i)
+ wl_surface_damage(sb->output->parent.surface, rects[i].x1,
+ rects[i].y1, rects[i].x2 - rects[i].x1,
+ rects[i].y2 - rects[i].y1);
+
+ if (sb->output->frame)
+ pixman_region32_fini(&damage);
+}
+
+static int
+wayland_output_repaint_pixman(struct weston_output *output_base,
+ pixman_region32_t *damage)
+{
+ struct wayland_output *output = (struct wayland_output *) output_base;
+ struct wayland_compositor *c =
+ (struct wayland_compositor *)output->base.compositor;
+ struct wl_callback *callback;
+ struct wayland_shm_buffer *sb;
+
+ if (output->frame) {
+ if (frame_status(output->frame) & FRAME_STATUS_REPAINT)
+ wl_list_for_each(sb, &output->shm.buffers, link)
+ sb->frame_damaged = 1;
+ }
+
+ wl_list_for_each(sb, &output->shm.buffers, link)
+ pixman_region32_union(&sb->damage, &sb->damage, damage);
+
+ sb = wayland_output_get_shm_buffer(output);
+
+ wayland_output_update_shm_border(sb);
+ pixman_renderer_output_set_buffer(output_base, sb->pm_image);
+ c->base.renderer->repaint_output(output_base, &sb->damage);
+
+ wayland_shm_buffer_attach(sb);
+
+ callback = wl_surface_frame(output->parent.surface);
+ wl_callback_add_listener(callback, &frame_listener, output);
+ wl_surface_commit(output->parent.surface);
+ wl_display_flush(c->parent.wl_display);
+
+ pixman_region32_fini(&sb->damage);
+ pixman_region32_init(&sb->damage);
+ sb->frame_damaged = 0;
+
+ pixman_region32_subtract(&c->base.primary_plane.damage,
+ &c->base.primary_plane.damage, damage);
+ return 0;
+}
+
+static void
wayland_output_destroy(struct weston_output *output_base)
{
struct wayland_output *output = (struct wayland_output *) output_base;
+ struct wayland_compositor *c =
+ (struct wayland_compositor *) output->base.compositor;
+
+ if (c->use_pixman) {
+ pixman_renderer_output_destroy(output_base);
+ } else {
+ gl_renderer->output_destroy(output_base);
+ }
- gl_renderer_output_destroy(output_base);
+ wl_egl_window_destroy(output->gl.egl_window);
+ wl_surface_destroy(output->parent.surface);
+ wl_shell_surface_destroy(output->parent.shell_surface);
- wl_egl_window_destroy(output->parent.egl_window);
+ if (output->frame)
+ frame_destroy(output->frame);
+
+ cairo_surface_destroy(output->gl.border.top);
+ cairo_surface_destroy(output->gl.border.left);
+ cairo_surface_destroy(output->gl.border.right);
+ cairo_surface_destroy(output->gl.border.bottom);
+
+ weston_output_destroy(&output->base);
free(output);
return;
@@ -244,59 +572,255 @@ wayland_output_destroy(struct weston_output *output_base)
static const struct wl_shell_surface_listener shell_surface_listener;
static int
-wayland_compositor_create_output(struct wayland_compositor *c,
- int width, int height)
+wayland_output_init_gl_renderer(struct wayland_output *output)
{
- struct wayland_output *output;
+ int32_t fwidth = 0, fheight = 0;
+
+ if (output->frame) {
+ fwidth = frame_width(output->frame);
+ fheight = frame_height(output->frame);
+ } else {
+ fwidth = output->base.current_mode->width;
+ fheight = output->base.current_mode->height;
+ }
- output = zalloc(sizeof *output);
- if (output == NULL)
+ output->gl.egl_window =
+ wl_egl_window_create(output->parent.surface,
+ fwidth, fheight);
+ if (!output->gl.egl_window) {
+ weston_log("failure to create wl_egl_window\n");
return -1;
+ }
- output->mode.flags =
- WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
- output->mode.width = width;
- output->mode.height = height;
- output->mode.refresh = 60;
- wl_list_init(&output->base.mode_list);
- wl_list_insert(&output->base.mode_list, &output->mode.link);
+ if (gl_renderer->output_create(&output->base,
+ output->gl.egl_window) < 0)
+ goto cleanup_window;
- output->base.current_mode = &output->mode;
- weston_output_init(&output->base, &c->base, 0, 0, width, height,
- WL_OUTPUT_TRANSFORM_NORMAL, 1);
+ return 0;
+
+cleanup_window:
+ wl_egl_window_destroy(output->gl.egl_window);
+ return -1;
+}
+
+static int
+wayland_output_init_pixman_renderer(struct wayland_output *output)
+{
+ return pixman_renderer_output_create(&output->base);
+}
+
+static void
+wayland_output_resize_surface(struct wayland_output *output)
+{
+ struct wayland_compositor *c =
+ (struct wayland_compositor *)output->base.compositor;
+ struct wayland_shm_buffer *buffer, *next;
+ int32_t ix, iy, iwidth, iheight;
+ int32_t width, height;
+ struct wl_region *region;
+
+ width = output->base.current_mode->width;
+ height = output->base.current_mode->height;
+
+ if (output->frame) {
+ frame_resize_inside(output->frame, width, height);
+
+ frame_input_rect(output->frame, &ix, &iy, &iwidth, &iheight);
+ region = wl_compositor_create_region(c->parent.compositor);
+ wl_region_add(region, ix, iy, iwidth, iheight);
+ wl_surface_set_input_region(output->parent.surface, region);
+ wl_region_destroy(region);
+
+ frame_opaque_rect(output->frame, &ix, &iy, &iwidth, &iheight);
+ region = wl_compositor_create_region(c->parent.compositor);
+ wl_region_add(region, ix, iy, iwidth, iheight);
+ wl_surface_set_opaque_region(output->parent.surface, region);
+ wl_region_destroy(region);
+
+ width = frame_width(output->frame);
+ height = frame_height(output->frame);
+ } else {
+ region = wl_compositor_create_region(c->parent.compositor);
+ wl_region_add(region, 0, 0, width, height);
+ wl_surface_set_input_region(output->parent.surface, region);
+ wl_region_destroy(region);
+
+ region = wl_compositor_create_region(c->parent.compositor);
+ wl_region_add(region, 0, 0, width, height);
+ wl_surface_set_opaque_region(output->parent.surface, region);
+ wl_region_destroy(region);
+ }
+
+ if (output->gl.egl_window) {
+ wl_egl_window_resize(output->gl.egl_window,
+ width, height, 0, 0);
+
+ /* These will need to be re-created due to the resize */
+ gl_renderer->output_set_border(&output->base,
+ GL_RENDERER_BORDER_TOP,
+ 0, 0, 0, NULL);
+ cairo_surface_destroy(output->gl.border.top);
+ output->gl.border.top = NULL;
+ gl_renderer->output_set_border(&output->base,
+ GL_RENDERER_BORDER_LEFT,
+ 0, 0, 0, NULL);
+ cairo_surface_destroy(output->gl.border.left);
+ output->gl.border.left = NULL;
+ gl_renderer->output_set_border(&output->base,
+ GL_RENDERER_BORDER_RIGHT,
+ 0, 0, 0, NULL);
+ cairo_surface_destroy(output->gl.border.right);
+ output->gl.border.right = NULL;
+ gl_renderer->output_set_border(&output->base,
+ GL_RENDERER_BORDER_BOTTOM,
+ 0, 0, 0, NULL);
+ cairo_surface_destroy(output->gl.border.bottom);
+ output->gl.border.bottom = NULL;
+ }
+
+ /* Throw away any remaining SHM buffers */
+ wl_list_for_each_safe(buffer, next, &output->shm.free_buffers, link)
+ wayland_shm_buffer_destroy(buffer);
+ /* These will get thrown away when they get released */
+ wl_list_for_each(buffer, &output->shm.buffers, link)
+ buffer->output = NULL;
+}
+
+static int
+wayland_output_set_windowed(struct wayland_output *output)
+{
+ struct wayland_compositor *c =
+ (struct wayland_compositor *)output->base.compositor;
+ int tlen;
+ char *title;
+
+ if (output->frame)
+ return 0;
+
+ if (output->name) {
+ tlen = strlen(output->name) + strlen(WINDOW_TITLE " - ");
+ title = malloc(tlen + 1);
+ if (!title)
+ return -1;
+
+ snprintf(title, tlen + 1, WINDOW_TITLE " - %s", output->name);
+ } else {
+ title = strdup(WINDOW_TITLE);
+ }
+
+ if (!c->theme) {
+ c->theme = theme_create();
+ if (!c->theme) {
+ free(title);
+ return -1;
+ }
+ }
+ output->frame = frame_create(c->theme, 100, 100,
+ FRAME_BUTTON_CLOSE, title);
+ free(title);
+ if (!output->frame)
+ return -1;
+ if (output->keyboard_count)
+ frame_set_flag(output->frame, FRAME_FLAG_ACTIVE);
+
+ wayland_output_resize_surface(output);
+
+ wl_shell_surface_set_toplevel(output->parent.shell_surface);
+
+ return 0;
+}
+
+static void
+wayland_output_set_fullscreen(struct wayland_output *output,
+ enum wl_shell_surface_fullscreen_method method,
+ uint32_t framerate, struct wl_output *target)
+{
+ if (output->frame) {
+ frame_destroy(output->frame);
+ output->frame = NULL;
+ }
+
+ wayland_output_resize_surface(output);
+
+ wl_shell_surface_set_fullscreen(output->parent.shell_surface,
+ method, framerate, target);
+}
+
+static struct wayland_output *
+wayland_output_create(struct wayland_compositor *c, int x, int y,
+ int width, int height, const char *name, int fullscreen,
+ uint32_t transform, int32_t scale)
+{
+ struct wayland_output *output;
+ int output_width, output_height;
+
+ weston_log("Creating %dx%d wayland output at (%d, %d)\n",
+ width, height, x, y);
+
+ output = zalloc(sizeof *output);
+ if (output == NULL)
+ return NULL;
+
+ output->name = name ? strdup(name) : NULL;
output->base.make = "waywayland";
output->base.model = "none";
- weston_output_move(&output->base, 0, 0);
+ output_width = width * scale;
+ output_height = height * scale;
output->parent.surface =
wl_compositor_create_surface(c->parent.compositor);
+ if (!output->parent.surface)
+ goto err_name;
wl_surface_set_user_data(output->parent.surface, output);
- output->parent.egl_window =
- wl_egl_window_create(output->parent.surface,
- width + c->border.left + c->border.right,
- height + c->border.top + c->border.bottom);
- if (!output->parent.egl_window) {
- weston_log("failure to create wl_egl_window\n");
- goto cleanup_output;
- }
-
- if (gl_renderer_output_create(&output->base,
- output->parent.egl_window) < 0)
- goto cleanup_window;
-
output->parent.draw_initial_frame = 1;
output->parent.shell_surface =
wl_shell_get_shell_surface(c->parent.shell,
output->parent.surface);
+ if (!output->parent.shell_surface)
+ goto err_surface;
wl_shell_surface_add_listener(output->parent.shell_surface,
&shell_surface_listener, output);
- wl_shell_surface_set_toplevel(output->parent.shell_surface);
+
+ if (fullscreen) {
+ wl_shell_surface_set_fullscreen(output->parent.shell_surface,
+ 0, 0, NULL);
+ wl_display_roundtrip(c->parent.wl_display);
+ if (!width)
+ output_width = output->parent.configure_width;
+ if (!height)
+ output_height = output->parent.configure_height;
+ }
+
+ output->mode.flags =
+ WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+ output->mode.width = output_width;
+ output->mode.height = output_height;
+ output->mode.refresh = 60000;
+ output->scale = scale;
+ wl_list_init(&output->base.mode_list);
+ wl_list_insert(&output->base.mode_list, &output->mode.link);
+ output->base.current_mode = &output->mode;
+
+ wl_list_init(&output->shm.buffers);
+ wl_list_init(&output->shm.free_buffers);
+
+ weston_output_init(&output->base, &c->base, x, y, width, height,
+ transform, scale);
+
+ if (c->use_pixman) {
+ if (wayland_output_init_pixman_renderer(output) < 0)
+ goto err_output;
+ output->base.repaint = wayland_output_repaint_pixman;
+ } else {
+ if (wayland_output_init_gl_renderer(output) < 0)
+ goto err_output;
+ output->base.repaint = wayland_output_repaint_gl;
+ }
output->base.start_repaint_loop = wayland_output_start_repaint_loop;
- output->base.repaint = wayland_output_repaint;
output->base.destroy = wayland_output_destroy;
output->base.assign_planes = NULL;
output->base.set_backlight = NULL;
@@ -305,15 +829,96 @@ wayland_compositor_create_output(struct wayland_compositor *c,
wl_list_insert(c->base.output_list.prev, &output->base.link);
- return 0;
+ return output;
+
+err_output:
+ weston_output_destroy(&output->base);
+ wl_shell_surface_destroy(output->parent.shell_surface);
+err_surface:
+ wl_surface_destroy(output->parent.surface);
+err_name:
+ free(output->name);
-cleanup_window:
- wl_egl_window_destroy(output->parent.egl_window);
-cleanup_output:
/* FIXME: cleanup weston_output */
free(output);
- return -1;
+ return NULL;
+}
+
+static struct wayland_output *
+wayland_output_create_for_config(struct wayland_compositor *c,
+ struct weston_config_section *config_section,
+ int option_width, int option_height,
+ int option_scale, int32_t x, int32_t y)
+{
+ struct wayland_output *output;
+ char *mode, *t, *name, *str;
+ int width, height, scale;
+ uint32_t transform;
+ unsigned int i, slen;
+
+ static const struct { const char *name; uint32_t token; } transform_names[] = {
+ { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
+ { "90", WL_OUTPUT_TRANSFORM_90 },
+ { "180", WL_OUTPUT_TRANSFORM_180 },
+ { "270", WL_OUTPUT_TRANSFORM_270 },
+ { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
+ { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
+ { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
+ { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
+ };
+
+ weston_config_section_get_string(config_section, "name", &name, NULL);
+ if (name) {
+ slen = strlen(name);
+ slen += strlen(WINDOW_TITLE " - ");
+ str = malloc(slen + 1);
+ if (str)
+ snprintf(str, slen + 1, WINDOW_TITLE " - %s", name);
+ free(name);
+ name = str;
+ }
+ if (!name)
+ name = WINDOW_TITLE;
+
+ weston_config_section_get_string(config_section,
+ "mode", &mode, "1024x600");
+ if (sscanf(mode, "%dx%d", &width, &height) != 2) {
+ weston_log("Invalid mode \"%s\" for output %s\n",
+ mode, name);
+ width = 1024;
+ height = 640;
+ }
+ free(mode);
+
+ if (option_width)
+ width = option_width;
+ if (option_height)
+ height = option_height;
+
+ weston_config_section_get_int(config_section, "scale", &scale, 1);
+
+ if (option_scale)
+ scale = option_scale;
+
+ weston_config_section_get_string(config_section,
+ "transform", &t, "normal");
+ transform = WL_OUTPUT_TRANSFORM_NORMAL;
+ for (i = 0; i < ARRAY_LENGTH(transform_names); i++) {
+ if (strcmp(transform_names[i].name, t) == 0) {
+ transform = transform_names[i].token;
+ break;
+ }
+ }
+ if (i >= ARRAY_LENGTH(transform_names))
+ weston_log("Invalid transform \"%s\" for output %s\n", t, name);
+ free(t);
+
+ output = wayland_output_create(c, x, y, width, height, name, 0,
+ transform, scale);
+ free(name);
+
+ return output;
}
static void
@@ -327,6 +932,11 @@ static void
shell_surface_configure(void *data, struct wl_shell_surface *shell_surface,
uint32_t edges, int32_t width, int32_t height)
{
+ struct wayland_output *output = data;
+
+ output->parent.configure_width = width;
+ output->parent.configure_height = height;
+
/* FIXME: implement resizing */
}
@@ -343,85 +953,71 @@ static const struct wl_shell_surface_listener shell_surface_listener = {
/* Events received from the wayland-server this compositor is client of: */
-/* parent output interface */
-static void
-display_handle_geometry(void *data,
- struct wl_output *wl_output,
- int x,
- int y,
- int physical_width,
- int physical_height,
- int subpixel,
- const char *make,
- const char *model,
- int transform)
-{
- struct wayland_compositor *c = data;
-
- c->parent.screen_allocation.x = x;
- c->parent.screen_allocation.y = y;
-}
-
+/* parent input interface */
static void
-display_handle_mode(void *data,
- struct wl_output *wl_output,
- uint32_t flags,
- int width,
- int height,
- int refresh)
+input_set_cursor(struct wayland_input *input)
{
- struct wayland_compositor *c = data;
- c->parent.screen_allocation.width = width;
- c->parent.screen_allocation.height = height;
-}
+ struct wl_buffer *buffer;
+ struct wl_cursor_image *image;
-static const struct wl_output_listener output_listener = {
- display_handle_geometry,
- display_handle_mode
-};
+ if (!input->compositor->cursor)
+ return; /* Couldn't load the cursor. Can't set it */
-static void
-check_focus(struct wayland_input *input, wl_fixed_t x, wl_fixed_t y)
-{
- struct wayland_compositor *c = input->compositor;
- int width, height, inside;
+ image = input->compositor->cursor->images[0];
+ buffer = wl_cursor_image_get_buffer(image);
- width = input->output->mode.width;
- height = input->output->mode.height;
- inside = c->border.left <= wl_fixed_to_int(x) &&
- wl_fixed_to_int(x) < width + c->border.left &&
- c->border.top <= wl_fixed_to_int(y) &&
- wl_fixed_to_int(y) < height + c->border.top;
+ wl_pointer_set_cursor(input->parent.pointer, input->enter_serial,
+ input->parent.cursor.surface,
+ image->hotspot_x, image->hotspot_y);
- if (!input->focus && inside) {
- notify_pointer_focus(&input->base, &input->output->base,
- x - wl_fixed_from_int(c->border.left),
- y = wl_fixed_from_int(c->border.top));
- wl_pointer_set_cursor(input->pointer,
- input->enter_serial, NULL, 0, 0);
- } else if (input->focus && !inside) {
- notify_pointer_focus(&input->base, NULL, 0, 0);
- /* FIXME: Should set default cursor here. */
- }
-
- input->focus = inside;
+ wl_surface_attach(input->parent.cursor.surface, buffer, 0, 0);
+ wl_surface_damage(input->parent.cursor.surface, 0, 0,
+ image->width, image->height);
+ wl_surface_commit(input->parent.cursor.surface);
}
-/* parent input interface */
static void
input_handle_pointer_enter(void *data, struct wl_pointer *pointer,
uint32_t serial, struct wl_surface *surface,
wl_fixed_t x, wl_fixed_t y)
{
struct wayland_input *input = data;
+ int32_t fx, fy;
+ enum theme_location location;
/* XXX: If we get a modifier event immediately before the focus,
* we should try to keep the same serial. */
input->enter_serial = serial;
input->output = wl_surface_get_user_data(surface);
- check_focus(input, x, y);
+
+ if (input->output->frame) {
+ location = frame_pointer_enter(input->output->frame, input,
+ wl_fixed_to_int(x),
+ wl_fixed_to_int(y));
+ frame_interior(input->output->frame, &fx, &fy, NULL, NULL);
+ x -= wl_fixed_from_int(fx);
+ y -= wl_fixed_from_int(fy);
+
+ if (frame_status(input->output->frame) & FRAME_STATUS_REPAINT)
+ weston_output_schedule_repaint(&input->output->base);
+ } else {
+ location = THEME_LOCATION_CLIENT_AREA;
+ }
+
+ weston_output_transform_coordinate(&input->output->base, x, y, &x, &y);
+
+ if (location == THEME_LOCATION_CLIENT_AREA) {
+ input->focus = 1;
+ notify_pointer_focus(&input->base, &input->output->base, x, y);
+ wl_pointer_set_cursor(input->parent.pointer,
+ input->enter_serial, NULL, 0, 0);
+ } else {
+ input->focus = 0;
+ notify_pointer_focus(&input->base, NULL, 0, 0);
+ input_set_cursor(input);
+ }
}
static void
@@ -430,6 +1026,13 @@ input_handle_pointer_leave(void *data, struct wl_pointer *pointer,
{
struct wayland_input *input = data;
+ if (input->output->frame) {
+ frame_pointer_leave(input->output->frame, input);
+
+ if (frame_status(input->output->frame) & FRAME_STATUS_REPAINT)
+ weston_output_schedule_repaint(&input->output->base);
+ }
+
notify_pointer_focus(&input->base, NULL, 0, 0);
input->output = NULL;
input->focus = 0;
@@ -440,15 +1043,38 @@ input_handle_motion(void *data, struct wl_pointer *pointer,
uint32_t time, wl_fixed_t x, wl_fixed_t y)
{
struct wayland_input *input = data;
- struct wayland_compositor *c = input->compositor;
+ int32_t fx, fy;
+ enum theme_location location;
+
+ if (input->output->frame) {
+ location = frame_pointer_motion(input->output->frame, input,
+ wl_fixed_to_int(x),
+ wl_fixed_to_int(y));
+ frame_interior(input->output->frame, &fx, &fy, NULL, NULL);
+ x -= wl_fixed_from_int(fx);
+ y -= wl_fixed_from_int(fy);
+
+ if (frame_status(input->output->frame) & FRAME_STATUS_REPAINT)
+ weston_output_schedule_repaint(&input->output->base);
+ } else {
+ location = THEME_LOCATION_CLIENT_AREA;
+ }
+
+ weston_output_transform_coordinate(&input->output->base, x, y, &x, &y);
+
+ if (input->focus && location != THEME_LOCATION_CLIENT_AREA) {
+ input_set_cursor(input);
+ notify_pointer_focus(&input->base, NULL, 0, 0);
+ input->focus = 0;
+ } else if (!input->focus && location == THEME_LOCATION_CLIENT_AREA) {
+ wl_pointer_set_cursor(input->parent.pointer,
+ input->enter_serial, NULL, 0, 0);
+ notify_pointer_focus(&input->base, &input->output->base, x, y);
+ input->focus = 1;
+ }
- check_focus(input, x, y);
- if (input->focus)
- notify_motion(&input->base, time,
- x - wl_fixed_from_int(c->border.left) -
- input->base.pointer->x,
- y - wl_fixed_from_int(c->border.top) -
- input->base.pointer->y);
+ if (location == THEME_LOCATION_CLIENT_AREA)
+ notify_motion_absolute(&input->base, time, x, y);
}
static void
@@ -458,8 +1084,36 @@ input_handle_button(void *data, struct wl_pointer *pointer,
{
struct wayland_input *input = data;
enum wl_pointer_button_state state = state_w;
+ enum frame_button_state fstate;
+ enum theme_location location;
- notify_button(&input->base, time, button, state);
+ if (input->output->frame) {
+ fstate = state == WL_POINTER_BUTTON_STATE_PRESSED ?
+ FRAME_BUTTON_PRESSED : FRAME_BUTTON_RELEASED;
+
+ location = frame_pointer_button(input->output->frame, input,
+ button, fstate);
+
+ if (frame_status(input->output->frame) & FRAME_STATUS_MOVE) {
+
+ wl_shell_surface_move(input->output->parent.shell_surface,
+ input->parent.seat, serial);
+ frame_status_clear(input->output->frame,
+ FRAME_STATUS_MOVE);
+ return;
+ }
+
+ if (frame_status(input->output->frame) & FRAME_STATUS_CLOSE)
+ wl_display_terminate(input->compositor->base.wl_display);
+
+ if (frame_status(input->output->frame) & FRAME_STATUS_REPAINT)
+ weston_output_schedule_repaint(&input->output->base);
+ } else {
+ location = THEME_LOCATION_CLIENT_AREA;
+ }
+
+ if (location == THEME_LOCATION_CLIENT_AREA)
+ notify_button(&input->base, time, button, state);
}
static void
@@ -515,7 +1169,11 @@ input_handle_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format,
return;
}
- weston_seat_init_keyboard(&input->base, keymap);
+ if (input->base.keyboard)
+ weston_seat_update_keymap(&input->base, keymap);
+ else
+ weston_seat_init_keyboard(&input->base, keymap);
+
xkb_map_unref(keymap);
}
@@ -527,6 +1185,28 @@ input_handle_keyboard_enter(void *data,
struct wl_array *keys)
{
struct wayland_input *input = data;
+ struct wayland_output *focus;
+
+ focus = input->keyboard_focus;
+ if (focus) {
+ /* This shouldn't happen */
+ focus->keyboard_count--;
+ if (!focus->keyboard_count && focus->frame)
+ frame_unset_flag(focus->frame, FRAME_FLAG_ACTIVE);
+ if (frame_status(focus->frame) & FRAME_STATUS_REPAINT)
+ weston_output_schedule_repaint(&focus->base);
+ }
+
+ input->keyboard_focus = wl_surface_get_user_data(surface);
+ input->keyboard_focus->keyboard_count++;
+
+ focus = input->keyboard_focus;
+ if (focus->frame) {
+ frame_set_flag(focus->frame, FRAME_FLAG_ACTIVE);
+ if (frame_status(focus->frame) & FRAME_STATUS_REPAINT)
+ weston_output_schedule_repaint(&focus->base);
+ }
+
/* XXX: If we get a modifier event immediately before the focus,
* we should try to keep the same serial. */
@@ -541,8 +1221,22 @@ input_handle_keyboard_leave(void *data,
struct wl_surface *surface)
{
struct wayland_input *input = data;
+ struct wayland_output *focus;
notify_keyboard_focus_out(&input->base);
+
+ focus = input->keyboard_focus;
+ if (!focus)
+ return; /* This shouldn't happen */
+
+ focus->keyboard_count--;
+ if (!focus->keyboard_count && focus->frame) {
+ frame_unset_flag(focus->frame, FRAME_FLAG_ACTIVE);
+ if (frame_status(focus->frame) & FRAME_STATUS_REPAINT)
+ weston_output_schedule_repaint(&focus->base);
+ }
+
+ input->keyboard_focus = NULL;
}
static void
@@ -576,7 +1270,7 @@ input_handle_modifiers(void *data, struct wl_keyboard *keyboard,
else
serial_out = wl_display_next_serial(c->base.wl_display);
- xkb_state_update_mask(input->base.xkb_state.state,
+ xkb_state_update_mask(input->base.keyboard->xkb_state.state,
mods_depressed, mods_latched,
mods_locked, 0, 0, group);
notify_modifiers(&input->base, serial_out);
@@ -596,25 +1290,25 @@ input_handle_capabilities(void *data, struct wl_seat *seat,
{
struct wayland_input *input = data;
- if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
- input->pointer = wl_seat_get_pointer(seat);
- wl_pointer_set_user_data(input->pointer, input);
- wl_pointer_add_listener(input->pointer, &pointer_listener,
- input);
+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->parent.pointer) {
+ input->parent.pointer = wl_seat_get_pointer(seat);
+ wl_pointer_set_user_data(input->parent.pointer, input);
+ wl_pointer_add_listener(input->parent.pointer,
+ &pointer_listener, input);
weston_seat_init_pointer(&input->base);
- } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
- wl_pointer_destroy(input->pointer);
- input->pointer = NULL;
+ } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->parent.pointer) {
+ wl_pointer_destroy(input->parent.pointer);
+ input->parent.pointer = NULL;
}
- if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
- input->keyboard = wl_seat_get_keyboard(seat);
- wl_keyboard_set_user_data(input->keyboard, input);
- wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
- input);
- } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
- wl_keyboard_destroy(input->keyboard);
- input->keyboard = NULL;
+ if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->parent.keyboard) {
+ input->parent.keyboard = wl_seat_get_keyboard(seat);
+ wl_keyboard_set_user_data(input->parent.keyboard, input);
+ wl_keyboard_add_listener(input->parent.keyboard,
+ &keyboard_listener, input);
+ } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->parent.keyboard) {
+ wl_keyboard_destroy(input->parent.keyboard);
+ input->parent.keyboard = NULL;
}
}
@@ -633,12 +1327,15 @@ display_add_seat(struct wayland_compositor *c, uint32_t id)
weston_seat_init(&input->base, &c->base, "default");
input->compositor = c;
- input->seat = wl_registry_bind(c->parent.registry, id,
- &wl_seat_interface, 1);
+ input->parent.seat = wl_registry_bind(c->parent.registry, id,
+ &wl_seat_interface, 1);
wl_list_insert(c->input_list.prev, &input->link);
- wl_seat_add_listener(input->seat, &seat_listener, input);
- wl_seat_set_user_data(input->seat, input);
+ wl_seat_add_listener(input->parent.seat, &seat_listener, input);
+ wl_seat_set_user_data(input->parent.seat, input);
+
+ input->parent.cursor.surface =
+ wl_compositor_create_surface(c->parent.compositor);
}
static void
@@ -651,11 +1348,6 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
c->parent.compositor =
wl_registry_bind(registry, name,
&wl_compositor_interface, 1);
- } else if (strcmp(interface, "wl_output") == 0) {
- c->parent.output =
- wl_registry_bind(registry, name,
- &wl_output_interface, 1);
- wl_output_add_listener(c->parent.output, &output_listener, c);
} else if (strcmp(interface, "wl_shell") == 0) {
c->parent.shell =
wl_registry_bind(registry, name,
@@ -678,6 +1370,11 @@ wayland_compositor_handle_event(int fd, uint32_t mask, void *data)
struct wayland_compositor *c = data;
int count = 0;
+ if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) {
+ wl_display_terminate(c->base.wl_display);
+ return 0;
+ }
+
if (mask & WL_EVENT_READABLE)
count = wl_display_dispatch(c->parent.wl_display);
if (mask & WL_EVENT_WRITABLE)
@@ -701,8 +1398,6 @@ wayland_destroy(struct weston_compositor *ec)
{
struct wayland_compositor *c = (struct wayland_compositor *) ec;
- ec->renderer->destroy(ec);
-
weston_compositor_shutdown(ec);
if (c->parent.shm)
@@ -711,10 +1406,62 @@ wayland_destroy(struct weston_compositor *ec)
free(ec);
}
-static struct weston_compositor *
-wayland_compositor_create(struct wl_display *display,
- int width, int height, const char *display_name,
- int *argc, char *argv[],
+static const char *left_ptrs[] = {
+ "left_ptr",
+ "default",
+ "top_left_arrow",
+ "left-arrow"
+};
+
+static void
+create_cursor(struct wayland_compositor *c, struct weston_config *config)
+{
+ struct weston_config_section *s;
+ int size;
+ char *theme = NULL;
+ unsigned int i;
+
+ s = weston_config_get_section(config, "shell", NULL, NULL);
+ weston_config_section_get_string(s, "cursor-theme", &theme, NULL);
+ weston_config_section_get_int(s, "cursor-size", &size, 32);
+
+ c->cursor_theme = wl_cursor_theme_load(theme, size, c->parent.shm);
+
+ c->cursor = NULL;
+ for (i = 0; !c->cursor && i < ARRAY_LENGTH(left_ptrs); ++i)
+ c->cursor = wl_cursor_theme_get_cursor(c->cursor_theme,
+ left_ptrs[i]);
+ if (!c->cursor) {
+ fprintf(stderr, "could not load left cursor\n");
+ return;
+ }
+}
+
+static void
+fullscreen_binding(struct weston_seat *seat_base, uint32_t time, uint32_t key,
+ void *data)
+{
+ struct wayland_compositor *c = data;
+ struct wayland_input *input = NULL;
+
+ wl_list_for_each(input, &c->input_list, link)
+ if (&input->base == seat_base)
+ break;
+
+ if (!input || !input->output)
+ return;
+
+ if (input->output->frame)
+ wayland_output_set_fullscreen(input->output, 0, 0, NULL);
+ else
+ wayland_output_set_windowed(input->output);
+
+ weston_output_schedule_repaint(&input->output->base);
+}
+
+static struct wayland_compositor *
+wayland_compositor_create(struct wl_display *display, int use_pixman,
+ const char *display_name, int *argc, char *argv[],
struct weston_config *config)
{
struct wayland_compositor *c;
@@ -739,29 +1486,40 @@ wayland_compositor_create(struct wl_display *display,
wl_list_init(&c->input_list);
c->parent.registry = wl_display_get_registry(c->parent.wl_display);
wl_registry_add_listener(c->parent.registry, &registry_listener, c);
- wl_display_dispatch(c->parent.wl_display);
+ wl_display_roundtrip(c->parent.wl_display);
+
+ create_cursor(c, config);
c->base.wl_display = display;
- if (gl_renderer_create(&c->base, c->parent.wl_display,
- gl_renderer_alpha_attribs,
- NULL) < 0)
- goto err_display;
- c->base.destroy = wayland_destroy;
- c->base.restore = wayland_restore;
+ c->use_pixman = use_pixman;
- c->border.top = 30;
- c->border.bottom = 24;
- c->border.left = 25;
- c->border.right = 26;
+ if (!c->use_pixman) {
+ gl_renderer = weston_load_module("gl-renderer.so",
+ "gl_renderer_interface");
+ if (!gl_renderer)
+ c->use_pixman = 1;
+ }
+
+ if (!c->use_pixman) {
+ if (gl_renderer->create(&c->base, c->parent.wl_display,
+ gl_renderer->alpha_attribs,
+ NULL) < 0) {
+ weston_log("Failed to initialize the GL renderer; "
+ "falling back to pixman.\n");
+ c->use_pixman = 1;
+ }
+ }
- /* requires border fields */
- if (wayland_compositor_create_output(c, width, height) < 0)
- goto err_gl;
+ if (c->use_pixman) {
+ if (pixman_renderer_init(&c->base) < 0) {
+ weston_log("Failed to initialize pixman renderer\n");
+ goto err_display;
+ }
+ }
- /* requires gl_renderer_output_state_create called
- * by wayland_compositor_create_output */
- create_border(c);
+ c->base.destroy = wayland_destroy;
+ c->base.restore = wayland_restore;
loop = wl_display_get_event_loop(c->base.wl_display);
@@ -770,13 +1528,16 @@ wayland_compositor_create(struct wl_display *display,
wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
wayland_compositor_handle_event, c);
if (c->parent.wl_source == NULL)
- goto err_gl;
+ goto err_renderer;
wl_event_source_check(c->parent.wl_source);
- return &c->base;
+ weston_compositor_add_key_binding(&c->base, KEY_F,
+ MODIFIER_CTRL | MODIFIER_ALT,
+ fullscreen_binding, c);
-err_gl:
+ return c;
+err_renderer:
c->base.renderer->destroy(&c->base);
err_display:
wl_display_disconnect(c->parent.wl_display);
@@ -787,22 +1548,120 @@ err_free:
return NULL;
}
+static void
+wayland_compositor_destroy(struct wayland_compositor *c)
+{
+ struct weston_output *output;
+
+ wl_list_for_each(output, &c->base.output_list, link)
+ wayland_output_destroy(output);
+
+ c->base.renderer->destroy(&c->base);
+ wl_display_disconnect(c->parent.wl_display);
+
+ if (c->theme)
+ theme_destroy(c->theme);
+ if (c->frame_device)
+ cairo_device_destroy(c->frame_device);
+ wl_cursor_theme_destroy(c->cursor_theme);
+
+ weston_compositor_shutdown(&c->base);
+ free(c);
+}
+
WL_EXPORT struct weston_compositor *
backend_init(struct wl_display *display, int *argc, char *argv[],
struct weston_config *config)
{
- int width = 1024, height = 640;
- char *display_name = NULL;
+ struct wayland_compositor *c;
+ struct wayland_output *output;
+ struct weston_config_section *section;
+ int x, count, width, height, scale, use_pixman, fullscreen;
+ const char *section_name, *display_name;
+ char *name;
const struct weston_option wayland_options[] = {
{ WESTON_OPTION_INTEGER, "width", 0, &width },
{ WESTON_OPTION_INTEGER, "height", 0, &height },
+ { WESTON_OPTION_INTEGER, "scale", 0, &scale },
{ WESTON_OPTION_STRING, "display", 0, &display_name },
+ { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
+ { WESTON_OPTION_INTEGER, "output-count", 0, &count },
+ { WESTON_OPTION_BOOLEAN, "fullscreen", 0, &fullscreen },
};
+ width = 0;
+ height = 0;
+ scale = 0;
+ display_name = NULL;
+ use_pixman = 0;
+ count = 1;
+ fullscreen = 0;
parse_options(wayland_options,
ARRAY_LENGTH(wayland_options), argc, argv);
- return wayland_compositor_create(display, width, height, display_name,
- argc, argv, config);
+ c = wayland_compositor_create(display, use_pixman, display_name,
+ argc, argv, config);
+ if (!c)
+ return NULL;
+
+ if (fullscreen) {
+ output = wayland_output_create(c, 0, 0, width, height,
+ NULL, 1, 0, 1);
+ if (!output)
+ goto err_outputs;
+
+ wayland_output_set_fullscreen(output, 0, 0, NULL);
+ return &c->base;
+ }
+
+ section = NULL;
+ x = 0;
+ while (weston_config_next_section(config, &section, &section_name)) {
+ if (!section_name || strcmp(section_name, "output") != 0)
+ continue;
+ weston_config_section_get_string(section, "name", &name, NULL);
+ if (name == NULL)
+ continue;
+
+ if (name[0] != 'W' || name[1] != 'L') {
+ free(name);
+ continue;
+ }
+ free(name);
+
+ output = wayland_output_create_for_config(c, section, width,
+ height, scale, x, 0);
+ if (!output)
+ goto err_outputs;
+ if (wayland_output_set_windowed(output))
+ goto err_outputs;
+
+ x += output->base.width;
+ --count;
+ }
+
+ if (!width)
+ width = 1024;
+ if (!height)
+ height = 640;
+ if (!scale)
+ scale = 1;
+ while (count > 0) {
+ output = wayland_output_create(c, x, 0, width, height,
+ NULL, 0, 0, scale);
+ if (!output)
+ goto err_outputs;
+ if (wayland_output_set_windowed(output))
+ goto err_outputs;
+
+ x += width;
+ --count;
+ }
+
+ return &c->base;
+
+err_outputs:
+ wayland_compositor_destroy(c);
+ return NULL;
}
diff --git a/src/compositor-x11.c b/src/compositor-x11.c
index e6022f77..6b5eb648 100644
--- a/src/compositor-x11.c
+++ b/src/compositor-x11.c
@@ -115,6 +115,8 @@ struct x11_output {
int32_t scale;
};
+struct gl_renderer_interface *gl_renderer;
+
static struct xkb_keymap *
x11_compositor_get_keymap(struct x11_compositor *c)
{
@@ -160,7 +162,7 @@ x11_compositor_get_keymap(struct x11_compositor *c)
static uint32_t
get_xkb_mod_mask(struct x11_compositor *c, uint32_t in)
{
- struct weston_xkb_info *info = c->core_seat.xkb_info;
+ struct weston_xkb_info *info = c->core_seat.keyboard->xkb_info;
uint32_t ret = 0;
if ((in & ShiftMask) && info->shift_mod != XKB_MOD_INVALID)
@@ -201,6 +203,7 @@ x11_compositor_setup_xkb(struct x11_compositor *c)
xcb_xkb_per_client_flags_reply_t *pcf_reply;
xcb_xkb_get_state_cookie_t state;
xcb_xkb_get_state_reply_t *state_reply;
+ uint32_t values[1] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
c->has_xkb = 0;
c->xkb_event_base = 0;
@@ -270,7 +273,7 @@ x11_compositor_setup_xkb(struct x11_compositor *c)
return;
}
- xkb_state_update_mask(c->core_seat.xkb_state.state,
+ xkb_state_update_mask(c->core_seat.keyboard->xkb_state.state,
get_xkb_mod_mask(c, state_reply->baseMods),
get_xkb_mod_mask(c, state_reply->latchedMods),
get_xkb_mod_mask(c, state_reply->lockedMods),
@@ -280,10 +283,29 @@ x11_compositor_setup_xkb(struct x11_compositor *c)
free(state_reply);
+ xcb_change_window_attributes(c->conn, c->screen->root,
+ XCB_CW_EVENT_MASK, values);
+
c->has_xkb = 1;
#endif
}
+#ifdef HAVE_XCB_XKB
+static void
+update_xkb_keymap(struct x11_compositor *c)
+{
+ struct xkb_keymap *keymap;
+
+ keymap = x11_compositor_get_keymap(c);
+ if (!keymap) {
+ weston_log("failed to get XKB keymap\n");
+ return;
+ }
+ weston_seat_update_keymap(&c->core_seat, keymap);
+ xkb_keymap_unref(keymap);
+}
+#endif
+
static int
x11_input_create(struct x11_compositor *c, int no_input)
{
@@ -346,92 +368,39 @@ set_clip_for_output(struct weston_output *output_base, pixman_region32_t *region
struct x11_output *output = (struct x11_output *)output_base;
struct weston_compositor *ec = output->base.compositor;
struct x11_compositor *c = (struct x11_compositor *)ec;
+ pixman_region32_t transformed_region;
pixman_box32_t *rects;
xcb_rectangle_t *output_rects;
- pixman_box32_t rect, transformed_rect;
xcb_void_cookie_t cookie;
- int width, height, nrects, i;
+ int nrects, i;
xcb_generic_error_t *err;
- rects = pixman_region32_rectangles(region, &nrects);
+ pixman_region32_init(&transformed_region);
+ pixman_region32_copy(&transformed_region, region);
+ pixman_region32_translate(&transformed_region,
+ -output_base->x, -output_base->y);
+ weston_transformed_region(output_base->width, output_base->height,
+ output_base->transform,
+ output_base->current_scale,
+ &transformed_region, &transformed_region);
+
+ rects = pixman_region32_rectangles(&transformed_region, &nrects);
output_rects = calloc(nrects, sizeof(xcb_rectangle_t));
- if (output_rects == NULL)
+ if (output_rects == NULL) {
+ pixman_region32_fini(&transformed_region);
return;
-
- width = output_base->width;
- height = output_base->height;
+ }
for (i = 0; i < nrects; i++) {
- rect = rects[i];
- rect.x1 -= output_base->x;
- rect.y1 -= output_base->y;
- rect.x2 -= output_base->x;
- rect.y2 -= output_base->y;
-
- switch (output_base->transform) {
- default:
- case WL_OUTPUT_TRANSFORM_NORMAL:
- transformed_rect.x1 = rect.x1;
- transformed_rect.y1 = rect.y1;
- transformed_rect.x2 = rect.x2;
- transformed_rect.y2 = rect.y2;
- break;
- case WL_OUTPUT_TRANSFORM_90:
- transformed_rect.x1 = height - rect.y2;
- transformed_rect.y1 = rect.x1;
- transformed_rect.x2 = height - rect.y1;
- transformed_rect.y2 = rect.x2;
- break;
- case WL_OUTPUT_TRANSFORM_180:
- transformed_rect.x1 = width - rect.x2;
- transformed_rect.y1 = height - rect.y2;
- transformed_rect.x2 = width - rect.x1;
- transformed_rect.y2 = height - rect.y1;
- break;
- case WL_OUTPUT_TRANSFORM_270:
- transformed_rect.x1 = rect.y1;
- transformed_rect.y1 = width - rect.x2;
- transformed_rect.x2 = rect.y2;
- transformed_rect.y2 = width - rect.x1;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED:
- transformed_rect.x1 = width - rect.x2;
- transformed_rect.y1 = rect.y1;
- transformed_rect.x2 = width - rect.x1;
- transformed_rect.y2 = rect.y2;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- transformed_rect.x1 = height - rect.y2;
- transformed_rect.y1 = width - rect.x2;
- transformed_rect.x2 = height - rect.y1;
- transformed_rect.y2 = width - rect.x1;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_180:
- transformed_rect.x1 = rect.x1;
- transformed_rect.y1 = height - rect.y2;
- transformed_rect.x2 = rect.x2;
- transformed_rect.y2 = height - rect.y1;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- transformed_rect.x1 = rect.y1;
- transformed_rect.y1 = rect.x1;
- transformed_rect.x2 = rect.y2;
- transformed_rect.y2 = rect.x2;
- break;
- }
-
- transformed_rect.x1 *= output_base->current_scale;
- transformed_rect.y1 *= output_base->current_scale;
- transformed_rect.x2 *= output_base->current_scale;
- transformed_rect.y2 *= output_base->current_scale;
-
- output_rects[i].x = transformed_rect.x1;
- output_rects[i].y = transformed_rect.y1;
- output_rects[i].width = transformed_rect.x2 - transformed_rect.x1;
- output_rects[i].height = transformed_rect.y2 - transformed_rect.y1;
+ output_rects[i].x = rects[i].x1;
+ output_rects[i].y = rects[i].y1;
+ output_rects[i].width = rects[i].x2 - rects[i].x1;
+ output_rects[i].height = rects[i].y2 - rects[i].y1;
}
+ pixman_region32_fini(&transformed_region);
+
cookie = xcb_set_clip_rectangles_checked(c->conn, XCB_CLIP_ORDERING_UNSORTED,
output->gc,
0, 0, nrects,
@@ -514,14 +483,13 @@ x11_output_destroy(struct weston_output *output_base)
struct x11_compositor *compositor =
(struct x11_compositor *)output->base.compositor;
- wl_list_remove(&output->base.link);
wl_event_source_remove(output->finish_frame_timer);
if (compositor->use_pixman) {
pixman_renderer_output_destroy(output_base);
x11_output_deinit_shm(compositor, output);
} else
- gl_renderer_output_destroy(output_base);
+ gl_renderer->output_destroy(output_base);
xcb_destroy_window(compositor->conn, output->window);
@@ -734,6 +702,12 @@ x11_output_init_shm(struct x11_compositor *c, struct x11_output *output,
visual_type->blue_mask == 0x0000ff) {
weston_log("Will use x8r8g8b8 format for SHM surfaces\n");
pixman_format = PIXMAN_x8r8g8b8;
+ } else if (bitsperpixel == 16 &&
+ visual_type->red_mask == 0x00f800 &&
+ visual_type->green_mask == 0x0007e0 &&
+ visual_type->blue_mask == 0x00001f) {
+ weston_log("Will use r5g6b5 format for SHM surfaces\n");
+ pixman_format = PIXMAN_r5g6b5;
} else {
weston_log("Can't find appropriate format for SHM pixmap\n");
errno = ENOTSUP;
@@ -787,6 +761,7 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
struct wm_normal_hints normal_hints;
struct wl_event_loop *loop;
int output_width, output_height;
+ int ret;
uint32_t mask = XCB_CW_EVENT_MASK | XCB_CW_CURSOR;
xcb_atom_t atom_list[1];
uint32_t values[2] = {
@@ -896,6 +871,10 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
output->base.current_mode = &output->mode;
output->base.make = "xwayland";
output->base.model = "none";
+
+ if (configured_name)
+ output->base.name = strdup(configured_name);
+
weston_output_init(&output->base, &c->base,
x, y, width, height, transform, scale);
@@ -909,7 +888,9 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
return NULL;
}
} else {
- if (gl_renderer_output_create(&output->base, (EGLNativeWindowType)output->window) < 0)
+ ret = gl_renderer->output_create(&output->base,
+ (EGLNativeWindowType) output->window);
+ if (ret < 0)
return NULL;
}
@@ -938,11 +919,25 @@ x11_compositor_find_output(struct x11_compositor *c, xcb_window_t window)
assert(0);
}
+static void
+x11_compositor_delete_window(struct x11_compositor *c, xcb_window_t window)
+{
+ struct x11_output *output;
+
+ output = x11_compositor_find_output(c, window);
+ x11_output_destroy(&output->base);
+
+ xcb_flush(c->conn);
+
+ if (wl_list_empty(&c->base.output_list))
+ wl_display_terminate(c->base.wl_display);
+}
+
#ifdef HAVE_XCB_XKB
static void
update_xkb_state(struct x11_compositor *c, xcb_xkb_state_notify_event_t *state)
{
- xkb_state_update_mask(c->core_seat.xkb_state.state,
+ xkb_state_update_mask(c->core_seat.keyboard->xkb_state.state,
get_xkb_mod_mask(c, state->baseMods),
get_xkb_mod_mask(c, state->latchedMods),
get_xkb_mod_mask(c, state->lockedMods),
@@ -972,7 +967,7 @@ update_xkb_state_from_core(struct x11_compositor *c, uint16_t x11_mask)
uint32_t mask = get_xkb_mod_mask(c, x11_mask);
struct weston_keyboard *keyboard = c->core_seat.keyboard;
- xkb_state_update_mask(c->core_seat.xkb_state.state,
+ xkb_state_update_mask(c->core_seat.keyboard->xkb_state.state,
keyboard->modifiers.mods_depressed & mask,
keyboard->modifiers.mods_latched & mask,
keyboard->modifiers.mods_locked & mask,
@@ -1072,8 +1067,9 @@ x11_compositor_deliver_motion_event(struct x11_compositor *c,
update_xkb_state_from_core(c, motion_notify->state);
output = x11_compositor_find_output(c, motion_notify->event);
weston_output_transform_coordinate(&output->base,
- motion_notify->event_x,
- motion_notify->event_y, &x, &y);
+ wl_fixed_from_int(motion_notify->event_x),
+ wl_fixed_from_int(motion_notify->event_y),
+ &x, &y);
notify_motion(&c->core_seat, weston_compositor_get_time(),
x - c->prev_x, y - c->prev_y);
@@ -1097,8 +1093,8 @@ x11_compositor_deliver_enter_event(struct x11_compositor *c,
update_xkb_state_from_core(c, enter_notify->state);
output = x11_compositor_find_output(c, enter_notify->event);
weston_output_transform_coordinate(&output->base,
- enter_notify->event_x,
- enter_notify->event_y, &x, &y);
+ wl_fixed_from_int(enter_notify->event_x),
+ wl_fixed_from_int(enter_notify->event_y), &x, &y);
notify_pointer_focus(&c->core_seat, &output->base, x, y);
@@ -1136,6 +1132,7 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
xcb_focus_in_event_t *focus_in;
xcb_expose_event_t *expose;
xcb_atom_t atom;
+ xcb_window_t window;
uint32_t *k;
uint32_t i, set;
uint8_t response_type;
@@ -1244,6 +1241,7 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
case XCB_EXPOSE:
expose = (xcb_expose_event_t *) event;
output = x11_compositor_find_output(c, expose->window);
+ weston_output_damage(&output->base);
weston_output_schedule_repaint(&output->base);
break;
@@ -1263,8 +1261,9 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
case XCB_CLIENT_MESSAGE:
client_message = (xcb_client_message_event_t *) event;
atom = client_message->data.data32[0];
+ window = client_message->window;
if (atom == c->atom.wm_delete_window)
- wl_display_terminate(c->base.wl_display);
+ x11_compositor_delete_window(c, window);
break;
case XCB_FOCUS_IN:
@@ -1288,12 +1287,20 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
}
#ifdef HAVE_XCB_XKB
- if (c->has_xkb &&
- response_type == c->xkb_event_base) {
- xcb_xkb_state_notify_event_t *state =
- (xcb_xkb_state_notify_event_t *) event;
- if (state->xkbType == XCB_XKB_STATE_NOTIFY)
- update_xkb_state(c, state);
+ if (c->has_xkb) {
+ if (response_type == c->xkb_event_base) {
+ xcb_xkb_state_notify_event_t *state =
+ (xcb_xkb_state_notify_event_t *) event;
+ if (state->xkbType == XCB_XKB_STATE_NOTIFY)
+ update_xkb_state(c, state);
+ } else if (response_type == XCB_PROPERTY_NOTIFY) {
+ xcb_property_notify_event_t *prop_notify =
+ (xcb_property_notify_event_t *) event;
+ if (prop_notify->window == c->screen->root &&
+ prop_notify->atom == c->atom.xkb_names &&
+ prop_notify->state == XCB_PROPERTY_NEW_VALUE)
+ update_xkb_keymap(c);
+ }
}
#endif
@@ -1414,8 +1421,6 @@ x11_destroy(struct weston_compositor *ec)
weston_compositor_shutdown(ec); /* destroys outputs, too */
- ec->renderer->destroy(ec);
-
XCloseDisplay(compositor->dpy);
free(ec);
}
@@ -1445,6 +1450,21 @@ parse_transform(const char *transform, const char *output_name)
return WL_OUTPUT_TRANSFORM_NORMAL;
}
+static int
+init_gl_renderer(struct x11_compositor *c)
+{
+ int ret;
+
+ gl_renderer = weston_load_module("gl-renderer.so",
+ "gl_renderer_interface");
+ if (!gl_renderer)
+ return -1;
+
+ ret = gl_renderer->create(&c->base, (EGLNativeDisplayType) c->dpy,
+ gl_renderer->opaque_attribs, NULL);
+
+ return ret;
+}
static struct weston_compositor *
x11_compositor_create(struct wl_display *display,
int fullscreen,
@@ -1501,10 +1521,8 @@ x11_compositor_create(struct wl_display *display,
if (pixman_renderer_init(&c->base) < 0)
goto err_xdisplay;
}
- else {
- if (gl_renderer_create(&c->base, (EGLNativeDisplayType)c->dpy, gl_renderer_opaque_attribs,
- NULL) < 0)
- goto err_xdisplay;
+ else if (init_gl_renderer(c) < 0) {
+ goto err_xdisplay;
}
weston_log("Using %s renderer\n", use_pixman ? "pixman" : "gl");
diff --git a/src/compositor.c b/src/compositor.c
index 36b54b5b..bb1dfa9c 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -53,7 +53,7 @@
#endif
#include "compositor.h"
-#include "subsurface-server-protocol.h"
+#include "scaler-server-protocol.h"
#include "../shared/os-compatibility.h"
#include "git-version.h"
#include "version.h"
@@ -93,7 +93,7 @@ weston_output_transform_scale_init(struct weston_output *output,
uint32_t transform, uint32_t scale);
static void
-weston_compositor_build_surface_list(struct weston_compositor *compositor);
+weston_compositor_build_view_list(struct weston_compositor *compositor);
WL_EXPORT int
weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode,
@@ -138,7 +138,6 @@ weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode
if (ret < 0)
return ret;
- output->current_mode = mode;
output->current_scale = scale;
break;
case WESTON_MODE_SWITCH_RESTORE_NATIVE:
@@ -347,6 +346,125 @@ region_init_infinite(pixman_region32_t *region)
static struct weston_subsurface *
weston_surface_to_subsurface(struct weston_surface *surface);
+static void
+weston_view_output_move_handler(struct wl_listener *listener,
+ void *data)
+{
+ struct weston_view *ev;
+ struct weston_output *output = data;
+
+ ev = container_of(listener, struct weston_view,
+ output_move_listener);
+
+ /* the child window's view->geometry is a relative coordinate to
+ * parent view, no need to move child_view. */
+ if (ev->geometry.parent)
+ return;
+
+ weston_view_set_position(ev,
+ ev->geometry.x + output->move_x,
+ ev->geometry.y + output->move_y);
+}
+
+static void
+weston_view_output_destroy_handler(struct wl_listener *listener,
+ void *data)
+{
+ struct weston_view *ev;
+ struct weston_compositor *ec;
+ struct weston_output *output, *first_output;
+ float x, y;
+ int visible;
+
+ ev = container_of(listener, struct weston_view,
+ output_destroy_listener);
+
+ ec = ev->surface->compositor;
+
+ /* the child window's view->geometry is a relative coordinate to
+ * parent view, no need to move child_view. */
+ if (ev->geometry.parent)
+ return;
+
+ x = ev->geometry.x;
+ y = ev->geometry.y;
+
+ /* At this point the destroyed output is not in the list anymore.
+ * If the view is still visible somewhere, we leave where it is,
+ * otherwise, move it to the first output. */
+ visible = 0;
+ wl_list_for_each(output, &ec->output_list, link) {
+ if (pixman_region32_contains_point(&output->region,
+ x, y, NULL)) {
+ visible = 1;
+ break;
+ }
+ }
+
+ if (!visible) {
+ first_output = container_of(ec->output_list.next,
+ struct weston_output, link);
+
+ x = first_output->x + first_output->width / 4;
+ y = first_output->y + first_output->height / 4;
+ }
+
+ weston_view_set_position(ev, x, y);
+
+ if (ev->surface->output_destroyed)
+ ev->surface->output_destroyed(ev->surface);
+
+ wl_list_remove(&ev->output_move_listener.link);
+ wl_list_remove(&ev->output_destroy_listener.link);
+
+ wl_list_init(&ev->output_move_listener.link);
+ wl_list_init(&ev->output_destroy_listener.link);
+}
+
+WL_EXPORT struct weston_view *
+weston_view_create(struct weston_surface *surface)
+{
+ struct weston_view *view;
+
+ view = calloc(1, sizeof *view);
+ if (view == NULL)
+ return NULL;
+
+ view->surface = surface;
+
+ /* Assign to surface */
+ wl_list_insert(&surface->views, &view->surface_link);
+
+ wl_signal_init(&view->destroy_signal);
+ wl_list_init(&view->link);
+ wl_list_init(&view->layer_link);
+
+ view->plane = NULL;
+
+ pixman_region32_init(&view->clip);
+
+ view->alpha = 1.0;
+ pixman_region32_init(&view->transform.opaque);
+
+ wl_list_init(&view->geometry.transformation_list);
+ wl_list_insert(&view->geometry.transformation_list,
+ &view->transform.position.link);
+ weston_matrix_init(&view->transform.position.matrix);
+ wl_list_init(&view->geometry.child_list);
+ pixman_region32_init(&view->transform.boundingbox);
+ view->transform.dirty = 1;
+
+ view->output = NULL;
+
+ view->output_move_listener.notify = weston_view_output_move_handler;
+ wl_list_init(&view->output_move_listener.link);
+ view->output_destroy_listener.notify =
+ weston_view_output_destroy_handler;
+ wl_list_init(&view->output_destroy_listener.link);
+
+ return view;
+}
+
WL_EXPORT struct weston_surface *
weston_surface_create(struct weston_compositor *compositor)
{
@@ -360,40 +478,25 @@ weston_surface_create(struct weston_compositor *compositor)
surface->resource = NULL;
- wl_list_init(&surface->link);
- wl_list_init(&surface->layer_link);
-
surface->compositor = compositor;
- surface->alpha = 1.0;
surface->ref_count = 1;
- if (compositor->renderer->create_surface(surface) < 0) {
- free(surface);
- return NULL;
- }
-
- surface->buffer_transform = WL_OUTPUT_TRANSFORM_NORMAL;
- surface->buffer_scale = 1;
- surface->pending.buffer_transform = surface->buffer_transform;
- surface->pending.buffer_scale = surface->buffer_scale;
+ surface->buffer_viewport.transform = WL_OUTPUT_TRANSFORM_NORMAL;
+ surface->buffer_viewport.scale = 1;
+ surface->buffer_viewport.viewport_set = 0;
+ surface->pending.buffer_viewport = surface->buffer_viewport;
surface->output = NULL;
- surface->plane = NULL;
surface->pending.newly_attached = 0;
+ surface->viewport_resource = NULL;
+
pixman_region32_init(&surface->damage);
pixman_region32_init(&surface->opaque);
- pixman_region32_init(&surface->clip);
region_init_infinite(&surface->input);
- pixman_region32_init(&surface->transform.opaque);
- wl_list_init(&surface->frame_callback_list);
- wl_list_init(&surface->geometry.transformation_list);
- wl_list_insert(&surface->geometry.transformation_list,
- &surface->transform.position.link);
- weston_matrix_init(&surface->transform.position.matrix);
- wl_list_init(&surface->geometry.child_list);
- pixman_region32_init(&surface->transform.boundingbox);
- surface->transform.dirty = 1;
+ wl_list_init(&surface->views);
+
+ wl_list_init(&surface->frame_callback_list);
surface->pending.buffer_destroy_listener.notify =
surface_handle_pending_buffer_destroy;
@@ -416,13 +519,13 @@ weston_surface_set_color(struct weston_surface *surface,
}
WL_EXPORT void
-weston_surface_to_global_float(struct weston_surface *surface,
- float sx, float sy, float *x, float *y)
+weston_view_to_global_float(struct weston_view *view,
+ float sx, float sy, float *x, float *y)
{
- if (surface->transform.enabled) {
+ if (view->transform.enabled) {
struct weston_vector v = { { sx, sy, 0.0f, 1.0f } };
- weston_matrix_transform(&surface->transform.matrix, &v);
+ weston_matrix_transform(&view->transform.matrix, &v);
if (fabsf(v.f[3]) < 1e-6) {
weston_log("warning: numerical instability in "
@@ -436,8 +539,8 @@ weston_surface_to_global_float(struct weston_surface *surface,
*x = v.f[0] / v.f[3];
*y = v.f[1] / v.f[3];
} else {
- *x = sx + surface->geometry.x;
- *y = sy + surface->geometry.y;
+ *x = sx + view->geometry.x;
+ *y = sy + view->geometry.y;
}
}
@@ -522,14 +625,129 @@ weston_transformed_rect(int width, int height,
}
WL_EXPORT void
+weston_transformed_region(int width, int height,
+ enum wl_output_transform transform,
+ int32_t scale,
+ pixman_region32_t *src, pixman_region32_t *dest)
+{
+ pixman_box32_t *src_rects, *dest_rects;
+ int nrects, i;
+
+ if (transform == WL_OUTPUT_TRANSFORM_NORMAL && scale == 1) {
+ if (src != dest)
+ pixman_region32_copy(dest, src);
+ return;
+ }
+
+ src_rects = pixman_region32_rectangles(src, &nrects);
+ dest_rects = malloc(nrects * sizeof(*dest_rects));
+ if (!dest_rects)
+ return;
+
+ if (transform == WL_OUTPUT_TRANSFORM_NORMAL) {
+ memcpy(dest_rects, src_rects, nrects * sizeof(*dest_rects));
+ } else {
+ for (i = 0; i < nrects; i++) {
+ switch (transform) {
+ default:
+ case WL_OUTPUT_TRANSFORM_NORMAL:
+ dest_rects[i].x1 = src_rects[i].x1;
+ dest_rects[i].y1 = src_rects[i].y1;
+ dest_rects[i].x2 = src_rects[i].x2;
+ dest_rects[i].y2 = src_rects[i].y2;
+ break;
+ case WL_OUTPUT_TRANSFORM_90:
+ dest_rects[i].x1 = height - src_rects[i].y2;
+ dest_rects[i].y1 = src_rects[i].x1;
+ dest_rects[i].x2 = height - src_rects[i].y1;
+ dest_rects[i].y2 = src_rects[i].x2;
+ break;
+ case WL_OUTPUT_TRANSFORM_180:
+ dest_rects[i].x1 = width - src_rects[i].x2;
+ dest_rects[i].y1 = height - src_rects[i].y2;
+ dest_rects[i].x2 = width - src_rects[i].x1;
+ dest_rects[i].y2 = height - src_rects[i].y1;
+ break;
+ case WL_OUTPUT_TRANSFORM_270:
+ dest_rects[i].x1 = src_rects[i].y1;
+ dest_rects[i].y1 = width - src_rects[i].x2;
+ dest_rects[i].x2 = src_rects[i].y2;
+ dest_rects[i].y2 = width - src_rects[i].x1;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED:
+ dest_rects[i].x1 = width - src_rects[i].x2;
+ dest_rects[i].y1 = src_rects[i].y1;
+ dest_rects[i].x2 = width - src_rects[i].x1;
+ dest_rects[i].y2 = src_rects[i].y2;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+ dest_rects[i].x1 = height - src_rects[i].y2;
+ dest_rects[i].y1 = width - src_rects[i].x2;
+ dest_rects[i].x2 = height - src_rects[i].y1;
+ dest_rects[i].y2 = width - src_rects[i].x1;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+ dest_rects[i].x1 = src_rects[i].x1;
+ dest_rects[i].y1 = height - src_rects[i].y2;
+ dest_rects[i].x2 = src_rects[i].x2;
+ dest_rects[i].y2 = height - src_rects[i].y1;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ dest_rects[i].x1 = src_rects[i].y1;
+ dest_rects[i].y1 = src_rects[i].x1;
+ dest_rects[i].x2 = src_rects[i].y2;
+ dest_rects[i].y2 = src_rects[i].x2;
+ break;
+ }
+ }
+ }
+
+ if (scale != 1) {
+ for (i = 0; i < nrects; i++) {
+ dest_rects[i].x1 *= scale;
+ dest_rects[i].x2 *= scale;
+ dest_rects[i].y1 *= scale;
+ dest_rects[i].y2 *= scale;
+ }
+ }
+
+ pixman_region32_clear(dest);
+ pixman_region32_init_rects(dest, dest_rects, nrects);
+ free(dest_rects);
+}
+
+static void
+scaler_surface_to_buffer(struct weston_surface *surface,
+ float sx, float sy, float *bx, float *by)
+{
+ if (surface->buffer_viewport.viewport_set) {
+ double a, b;
+
+ a = sx / surface->buffer_viewport.dst_width;
+ b = a * wl_fixed_to_double(surface->buffer_viewport.src_width);
+ *bx = b + wl_fixed_to_double(surface->buffer_viewport.src_x);
+
+ a = sy / surface->buffer_viewport.dst_height;
+ b = a * wl_fixed_to_double(surface->buffer_viewport.src_height);
+ *by = b + wl_fixed_to_double(surface->buffer_viewport.src_y);
+ } else {
+ *bx = sx;
+ *by = sy;
+ }
+}
+
+WL_EXPORT void
weston_surface_to_buffer_float(struct weston_surface *surface,
float sx, float sy, float *bx, float *by)
{
- weston_transformed_coord(surface->geometry.width,
- surface->geometry.height,
- surface->buffer_transform,
- surface->buffer_scale,
- sx, sy, bx, by);
+ /* first transform coordinates if the scaler is set */
+ scaler_surface_to_buffer(surface, sx, sy, bx, by);
+
+ weston_transformed_coord(surface->width,
+ surface->height,
+ surface->buffer_viewport.transform,
+ surface->buffer_viewport.scale,
+ *bx, *by, bx, by);
}
WL_EXPORT void
@@ -538,11 +756,9 @@ weston_surface_to_buffer(struct weston_surface *surface,
{
float bxf, byf;
- weston_transformed_coord(surface->geometry.width,
- surface->geometry.height,
- surface->buffer_transform,
- surface->buffer_scale,
- sx, sy, &bxf, &byf);
+ weston_surface_to_buffer_float(surface,
+ sx, sy, &bxf, &byf);
+
*bx = floorf(bxf);
*by = floorf(byf);
}
@@ -551,37 +767,49 @@ WL_EXPORT pixman_box32_t
weston_surface_to_buffer_rect(struct weston_surface *surface,
pixman_box32_t rect)
{
- return weston_transformed_rect(surface->geometry.width,
- surface->geometry.height,
- surface->buffer_transform,
- surface->buffer_scale,
+ float xf, yf;
+
+ /* first transform box coordinates if the scaler is set */
+ scaler_surface_to_buffer(surface, rect.x1, rect.y1, &xf, &yf);
+ rect.x1 = floorf(xf);
+ rect.y1 = floorf(yf);
+
+ scaler_surface_to_buffer(surface, rect.x2, rect.y2, &xf, &yf);
+ rect.x2 = floorf(xf);
+ rect.y2 = floorf(yf);
+
+ return weston_transformed_rect(surface->width,
+ surface->height,
+ surface->buffer_viewport.transform,
+ surface->buffer_viewport.scale,
rect);
}
WL_EXPORT void
-weston_surface_move_to_plane(struct weston_surface *surface,
+weston_view_move_to_plane(struct weston_view *view,
struct weston_plane *plane)
{
- if (surface->plane == plane)
+ if (view->plane == plane)
return;
- weston_surface_damage_below(surface);
- surface->plane = plane;
- weston_surface_damage(surface);
+ weston_view_damage_below(view);
+ view->plane = plane;
+ weston_surface_damage(view->surface);
}
WL_EXPORT void
-weston_surface_damage_below(struct weston_surface *surface)
+weston_view_damage_below(struct weston_view *view)
{
pixman_region32_t damage;
pixman_region32_init(&damage);
- pixman_region32_subtract(&damage, &surface->transform.boundingbox,
- &surface->clip);
- if (surface->plane)
- pixman_region32_union(&surface->plane->damage,
- &surface->plane->damage, &damage);
+ pixman_region32_subtract(&damage, &view->transform.boundingbox,
+ &view->clip);
+ if (view->plane)
+ pixman_region32_union(&view->plane->damage,
+ &view->plane->damage, &damage);
pixman_region32_fini(&damage);
+ weston_view_schedule_repaint(view);
}
static void
@@ -616,10 +844,47 @@ weston_surface_update_output_mask(struct weston_surface *es, uint32_t mask)
}
}
+
static void
weston_surface_assign_output(struct weston_surface *es)
{
- struct weston_compositor *ec = es->compositor;
+ struct weston_output *new_output;
+ struct weston_view *view;
+ pixman_region32_t region;
+ uint32_t max, area, mask;
+ pixman_box32_t *e;
+
+ new_output = NULL;
+ max = 0;
+ mask = 0;
+ pixman_region32_init(&region);
+ wl_list_for_each(view, &es->views, surface_link) {
+ if (!view->output)
+ continue;
+
+ pixman_region32_intersect(&region, &view->transform.boundingbox,
+ &view->output->region);
+
+ e = pixman_region32_extents(&region);
+ area = (e->x2 - e->x1) * (e->y2 - e->y1);
+
+ mask |= view->output_mask;
+
+ if (area >= max) {
+ new_output = view->output;
+ max = area;
+ }
+ }
+ pixman_region32_fini(&region);
+
+ es->output = new_output;
+ weston_surface_update_output_mask(es, mask);
+}
+
+static void
+weston_view_assign_output(struct weston_view *ev)
+{
+ struct weston_compositor *ec = ev->surface->compositor;
struct weston_output *output, *new_output;
pixman_region32_t region;
uint32_t max, area, mask;
@@ -630,7 +895,7 @@ weston_surface_assign_output(struct weston_surface *es)
mask = 0;
pixman_region32_init(&region);
wl_list_for_each(output, &ec->output_list, link) {
- pixman_region32_intersect(&region, &es->transform.boundingbox,
+ pixman_region32_intersect(&region, &ev->transform.boundingbox,
&output->region);
e = pixman_region32_extents(&region);
@@ -646,14 +911,31 @@ weston_surface_assign_output(struct weston_surface *es)
}
pixman_region32_fini(&region);
- es->output = new_output;
- weston_surface_update_output_mask(es, mask);
+ if (ev->output_mask != 0) {
+ wl_list_remove(&ev->output_move_listener.link);
+ wl_list_remove(&ev->output_destroy_listener.link);
+ }
+
+ if (mask != 0) {
+ wl_signal_add(&new_output->move_signal,
+ &ev->output_move_listener);
+ wl_signal_add(&new_output->destroy_signal,
+ &ev->output_destroy_listener);
+ } else {
+ wl_list_init(&ev->output_move_listener.link);
+ wl_list_init(&ev->output_destroy_listener.link);
+ }
+
+ ev->output = new_output;
+ ev->output_mask = mask;
+
+ weston_surface_assign_output(ev->surface);
}
static void
-surface_compute_bbox(struct weston_surface *surface, int32_t sx, int32_t sy,
- int32_t width, int32_t height,
- pixman_region32_t *bbox)
+view_compute_bbox(struct weston_view *view, int32_t sx, int32_t sy,
+ int32_t width, int32_t height,
+ pixman_region32_t *bbox)
{
float min_x = HUGE_VALF, min_y = HUGE_VALF;
float max_x = -HUGE_VALF, max_y = -HUGE_VALF;
@@ -674,8 +956,7 @@ surface_compute_bbox(struct weston_surface *surface, int32_t sx, int32_t sy,
for (i = 0; i < 4; ++i) {
float x, y;
- weston_surface_to_global_float(surface,
- s[i][0], s[i][1], &x, &y);
+ weston_view_to_global_float(view, s[i][0], s[i][1], &x, &y);
if (x < min_x)
min_x = x;
if (x > max_x)
@@ -693,57 +974,57 @@ surface_compute_bbox(struct weston_surface *surface, int32_t sx, int32_t sy,
}
static void
-weston_surface_update_transform_disable(struct weston_surface *surface)
+weston_view_update_transform_disable(struct weston_view *view)
{
- surface->transform.enabled = 0;
+ view->transform.enabled = 0;
/* round off fractions when not transformed */
- surface->geometry.x = roundf(surface->geometry.x);
- surface->geometry.y = roundf(surface->geometry.y);
+ view->geometry.x = roundf(view->geometry.x);
+ view->geometry.y = roundf(view->geometry.y);
/* Otherwise identity matrix, but with x and y translation. */
- surface->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
- surface->transform.position.matrix.d[12] = surface->geometry.x;
- surface->transform.position.matrix.d[13] = surface->geometry.y;
-
- surface->transform.matrix = surface->transform.position.matrix;
-
- surface->transform.inverse = surface->transform.position.matrix;
- surface->transform.inverse.d[12] = -surface->geometry.x;
- surface->transform.inverse.d[13] = -surface->geometry.y;
-
- pixman_region32_init_rect(&surface->transform.boundingbox,
- surface->geometry.x,
- surface->geometry.y,
- surface->geometry.width,
- surface->geometry.height);
-
- if (surface->alpha == 1.0) {
- pixman_region32_copy(&surface->transform.opaque,
- &surface->opaque);
- pixman_region32_translate(&surface->transform.opaque,
- surface->geometry.x,
- surface->geometry.y);
+ view->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
+ view->transform.position.matrix.d[12] = view->geometry.x;
+ view->transform.position.matrix.d[13] = view->geometry.y;
+
+ view->transform.matrix = view->transform.position.matrix;
+
+ view->transform.inverse = view->transform.position.matrix;
+ view->transform.inverse.d[12] = -view->geometry.x;
+ view->transform.inverse.d[13] = -view->geometry.y;
+
+ pixman_region32_init_rect(&view->transform.boundingbox,
+ view->geometry.x,
+ view->geometry.y,
+ view->surface->width,
+ view->surface->height);
+
+ if (view->alpha == 1.0) {
+ pixman_region32_copy(&view->transform.opaque,
+ &view->surface->opaque);
+ pixman_region32_translate(&view->transform.opaque,
+ view->geometry.x,
+ view->geometry.y);
}
}
static int
-weston_surface_update_transform_enable(struct weston_surface *surface)
+weston_view_update_transform_enable(struct weston_view *view)
{
- struct weston_surface *parent = surface->geometry.parent;
- struct weston_matrix *matrix = &surface->transform.matrix;
- struct weston_matrix *inverse = &surface->transform.inverse;
+ struct weston_view *parent = view->geometry.parent;
+ struct weston_matrix *matrix = &view->transform.matrix;
+ struct weston_matrix *inverse = &view->transform.inverse;
struct weston_transform *tform;
- surface->transform.enabled = 1;
+ view->transform.enabled = 1;
/* Otherwise identity matrix, but with x and y translation. */
- surface->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
- surface->transform.position.matrix.d[12] = surface->geometry.x;
- surface->transform.position.matrix.d[13] = surface->geometry.y;
+ view->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
+ view->transform.position.matrix.d[12] = view->geometry.x;
+ view->transform.position.matrix.d[13] = view->geometry.y;
weston_matrix_init(matrix);
- wl_list_for_each(tform, &surface->geometry.transformation_list, link)
+ wl_list_for_each(tform, &view->geometry.transformation_list, link)
weston_matrix_multiply(matrix, &tform->matrix);
if (parent)
@@ -751,143 +1032,144 @@ weston_surface_update_transform_enable(struct weston_surface *surface)
if (weston_matrix_invert(inverse, matrix) < 0) {
/* Oops, bad total transformation, not invertible */
- weston_log("error: weston_surface %p"
- " transformation not invertible.\n", surface);
+ weston_log("error: weston_view %p"
+ " transformation not invertible.\n", view);
return -1;
}
- surface_compute_bbox(surface, 0, 0, surface->geometry.width,
- surface->geometry.height,
- &surface->transform.boundingbox);
+ view_compute_bbox(view, 0, 0,
+ view->surface->width, view->surface->height,
+ &view->transform.boundingbox);
return 0;
}
WL_EXPORT void
-weston_surface_update_transform(struct weston_surface *surface)
+weston_view_update_transform(struct weston_view *view)
{
- struct weston_surface *parent = surface->geometry.parent;
+ struct weston_view *parent = view->geometry.parent;
- if (!surface->transform.dirty)
+ if (!view->transform.dirty)
return;
if (parent)
- weston_surface_update_transform(parent);
+ weston_view_update_transform(parent);
- surface->transform.dirty = 0;
+ view->transform.dirty = 0;
- weston_surface_damage_below(surface);
+ weston_view_damage_below(view);
- pixman_region32_fini(&surface->transform.boundingbox);
- pixman_region32_fini(&surface->transform.opaque);
- pixman_region32_init(&surface->transform.opaque);
+ pixman_region32_fini(&view->transform.boundingbox);
+ pixman_region32_fini(&view->transform.opaque);
+ pixman_region32_init(&view->transform.opaque);
/* transform.position is always in transformation_list */
- if (surface->geometry.transformation_list.next ==
- &surface->transform.position.link &&
- surface->geometry.transformation_list.prev ==
- &surface->transform.position.link &&
+ if (view->geometry.transformation_list.next ==
+ &view->transform.position.link &&
+ view->geometry.transformation_list.prev ==
+ &view->transform.position.link &&
!parent) {
- weston_surface_update_transform_disable(surface);
+ weston_view_update_transform_disable(view);
} else {
- if (weston_surface_update_transform_enable(surface) < 0)
- weston_surface_update_transform_disable(surface);
+ if (weston_view_update_transform_enable(view) < 0)
+ weston_view_update_transform_disable(view);
}
- weston_surface_damage_below(surface);
+ weston_view_damage_below(view);
- weston_surface_assign_output(surface);
+ weston_view_assign_output(view);
- wl_signal_emit(&surface->compositor->transform_signal, surface);
+ wl_signal_emit(&view->surface->compositor->transform_signal,
+ view->surface);
}
WL_EXPORT void
-weston_surface_geometry_dirty(struct weston_surface *surface)
+weston_view_geometry_dirty(struct weston_view *view)
{
- struct weston_surface *child;
+ struct weston_view *child;
/*
- * The invariant: if surface->geometry.dirty, then all surfaces
- * in surface->geometry.child_list have geometry.dirty too.
+ * The invariant: if view->geometry.dirty, then all views
+ * in view->geometry.child_list have geometry.dirty too.
* Corollary: if not parent->geometry.dirty, then all ancestors
* are not dirty.
*/
- if (surface->transform.dirty)
+ if (view->transform.dirty)
return;
- surface->transform.dirty = 1;
+ view->transform.dirty = 1;
- wl_list_for_each(child, &surface->geometry.child_list,
+ wl_list_for_each(child, &view->geometry.child_list,
geometry.parent_link)
- weston_surface_geometry_dirty(child);
+ weston_view_geometry_dirty(child);
}
WL_EXPORT void
-weston_surface_to_global_fixed(struct weston_surface *surface,
- wl_fixed_t sx, wl_fixed_t sy,
- wl_fixed_t *x, wl_fixed_t *y)
+weston_view_to_global_fixed(struct weston_view *view,
+ wl_fixed_t vx, wl_fixed_t vy,
+ wl_fixed_t *x, wl_fixed_t *y)
{
float xf, yf;
- weston_surface_to_global_float(surface,
- wl_fixed_to_double(sx),
- wl_fixed_to_double(sy),
- &xf, &yf);
+ weston_view_to_global_float(view,
+ wl_fixed_to_double(vx),
+ wl_fixed_to_double(vy),
+ &xf, &yf);
*x = wl_fixed_from_double(xf);
*y = wl_fixed_from_double(yf);
}
WL_EXPORT void
-weston_surface_from_global_float(struct weston_surface *surface,
- float x, float y, float *sx, float *sy)
+weston_view_from_global_float(struct weston_view *view,
+ float x, float y, float *vx, float *vy)
{
- if (surface->transform.enabled) {
+ if (view->transform.enabled) {
struct weston_vector v = { { x, y, 0.0f, 1.0f } };
- weston_matrix_transform(&surface->transform.inverse, &v);
+ weston_matrix_transform(&view->transform.inverse, &v);
if (fabsf(v.f[3]) < 1e-6) {
weston_log("warning: numerical instability in "
- "weston_surface_from_global(), divisor = %g\n",
+ "weston_view_from_global(), divisor = %g\n",
v.f[3]);
- *sx = 0;
- *sy = 0;
+ *vx = 0;
+ *vy = 0;
return;
}
- *sx = v.f[0] / v.f[3];
- *sy = v.f[1] / v.f[3];
+ *vx = v.f[0] / v.f[3];
+ *vy = v.f[1] / v.f[3];
} else {
- *sx = x - surface->geometry.x;
- *sy = y - surface->geometry.y;
+ *vx = x - view->geometry.x;
+ *vy = y - view->geometry.y;
}
}
WL_EXPORT void
-weston_surface_from_global_fixed(struct weston_surface *surface,
- wl_fixed_t x, wl_fixed_t y,
- wl_fixed_t *sx, wl_fixed_t *sy)
+weston_view_from_global_fixed(struct weston_view *view,
+ wl_fixed_t x, wl_fixed_t y,
+ wl_fixed_t *vx, wl_fixed_t *vy)
{
- float sxf, syf;
+ float vxf, vyf;
- weston_surface_from_global_float(surface,
- wl_fixed_to_double(x),
- wl_fixed_to_double(y),
- &sxf, &syf);
- *sx = wl_fixed_from_double(sxf);
- *sy = wl_fixed_from_double(syf);
+ weston_view_from_global_float(view,
+ wl_fixed_to_double(x),
+ wl_fixed_to_double(y),
+ &vxf, &vyf);
+ *vx = wl_fixed_from_double(vxf);
+ *vy = wl_fixed_from_double(vyf);
}
WL_EXPORT void
-weston_surface_from_global(struct weston_surface *surface,
- int32_t x, int32_t y, int32_t *sx, int32_t *sy)
+weston_view_from_global(struct weston_view *view,
+ int32_t x, int32_t y, int32_t *vx, int32_t *vy)
{
- float sxf, syf;
+ float vxf, vyf;
- weston_surface_from_global_float(surface, x, y, &sxf, &syf);
- *sx = floorf(sxf);
- *sy = floorf(syf);
+ weston_view_from_global_float(view, x, y, &vxf, &vyf);
+ *vx = floorf(vxf);
+ *vy = floorf(vyf);
}
WL_EXPORT void
@@ -901,67 +1183,77 @@ weston_surface_schedule_repaint(struct weston_surface *surface)
}
WL_EXPORT void
-weston_surface_damage(struct weston_surface *surface)
+weston_view_schedule_repaint(struct weston_view *view)
{
- pixman_region32_union_rect(&surface->damage, &surface->damage,
- 0, 0, surface->geometry.width,
- surface->geometry.height);
+ struct weston_output *output;
- weston_surface_schedule_repaint(surface);
+ wl_list_for_each(output, &view->surface->compositor->output_list, link)
+ if (view->output_mask & (1 << output->id))
+ weston_output_schedule_repaint(output);
}
WL_EXPORT void
-weston_surface_configure(struct weston_surface *surface,
- float x, float y, int width, int height)
+weston_surface_damage(struct weston_surface *surface)
{
- surface->geometry.x = x;
- surface->geometry.y = y;
- surface->geometry.width = width;
- surface->geometry.height = height;
- weston_surface_geometry_dirty(surface);
+ pixman_region32_union_rect(&surface->damage, &surface->damage,
+ 0, 0, surface->width,
+ surface->height);
+
+ weston_surface_schedule_repaint(surface);
}
WL_EXPORT void
-weston_surface_set_position(struct weston_surface *surface,
- float x, float y)
+weston_view_set_position(struct weston_view *view, float x, float y)
{
- surface->geometry.x = x;
- surface->geometry.y = y;
- weston_surface_geometry_dirty(surface);
+ if (view->geometry.x == x && view->geometry.y == y)
+ return;
+
+ view->geometry.x = x;
+ view->geometry.y = y;
+ weston_view_geometry_dirty(view);
}
static void
transform_parent_handle_parent_destroy(struct wl_listener *listener,
void *data)
{
- struct weston_surface *surface =
- container_of(listener, struct weston_surface,
+ struct weston_view *view =
+ container_of(listener, struct weston_view,
geometry.parent_destroy_listener);
- weston_surface_set_transform_parent(surface, NULL);
+ weston_view_set_transform_parent(view, NULL);
}
WL_EXPORT void
-weston_surface_set_transform_parent(struct weston_surface *surface,
- struct weston_surface *parent)
+weston_view_set_transform_parent(struct weston_view *view,
+ struct weston_view *parent)
{
- if (surface->geometry.parent) {
- wl_list_remove(&surface->geometry.parent_destroy_listener.link);
- wl_list_remove(&surface->geometry.parent_link);
+ if (view->geometry.parent) {
+ wl_list_remove(&view->geometry.parent_destroy_listener.link);
+ wl_list_remove(&view->geometry.parent_link);
}
- surface->geometry.parent = parent;
+ view->geometry.parent = parent;
- surface->geometry.parent_destroy_listener.notify =
+ view->geometry.parent_destroy_listener.notify =
transform_parent_handle_parent_destroy;
if (parent) {
wl_signal_add(&parent->destroy_signal,
- &surface->geometry.parent_destroy_listener);
+ &view->geometry.parent_destroy_listener);
wl_list_insert(&parent->geometry.child_list,
- &surface->geometry.parent_link);
+ &view->geometry.parent_link);
}
- weston_surface_geometry_dirty(surface);
+ weston_view_geometry_dirty(view);
+}
+
+WL_EXPORT int
+weston_view_is_mapped(struct weston_view *view)
+{
+ if (view->output)
+ return 1;
+ else
+ return 0;
}
WL_EXPORT int
@@ -973,40 +1265,62 @@ weston_surface_is_mapped(struct weston_surface *surface)
return 0;
}
-WL_EXPORT int32_t
-weston_surface_buffer_width(struct weston_surface *surface)
+static void
+surface_set_size(struct weston_surface *surface, int32_t width, int32_t height)
{
- int32_t width;
- switch (surface->buffer_transform) {
- case WL_OUTPUT_TRANSFORM_90:
- case WL_OUTPUT_TRANSFORM_270:
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- width = surface->buffer_ref.buffer->height;
- break;
- default:
- width = surface->buffer_ref.buffer->width;
- break;
- }
- return width / surface->buffer_scale;
+ struct weston_view *view;
+
+ if (surface->width == width && surface->height == height)
+ return;
+
+ surface->width = width;
+ surface->height = height;
+
+ wl_list_for_each(view, &surface->views, surface_link)
+ weston_view_geometry_dirty(view);
+}
+
+WL_EXPORT void
+weston_surface_set_size(struct weston_surface *surface,
+ int32_t width, int32_t height)
+{
+ assert(!surface->resource);
+ surface_set_size(surface, width, height);
}
-WL_EXPORT int32_t
-weston_surface_buffer_height(struct weston_surface *surface)
+static void
+weston_surface_set_size_from_buffer(struct weston_surface *surface)
{
- int32_t height;
- switch (surface->buffer_transform) {
+ int32_t width, height;
+
+ if (!surface->buffer_ref.buffer) {
+ surface_set_size(surface, 0, 0);
+ return;
+ }
+
+ if (surface->buffer_viewport.viewport_set) {
+ surface->width = surface->buffer_viewport.dst_width;
+ surface->height = surface->buffer_viewport.dst_height;
+ return;
+ }
+
+ switch (surface->buffer_viewport.transform) {
case WL_OUTPUT_TRANSFORM_90:
case WL_OUTPUT_TRANSFORM_270:
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ width = surface->buffer_ref.buffer->height;
height = surface->buffer_ref.buffer->width;
- break;
+ break;
default:
+ width = surface->buffer_ref.buffer->width;
height = surface->buffer_ref.buffer->height;
- break;
+ break;
}
- return height / surface->buffer_scale;
+
+ width = width / surface->buffer_viewport.scale;
+ height = height / surface->buffer_viewport.scale;
+ surface_set_size(surface, width, height);
}
WL_EXPORT uint32_t
@@ -1019,20 +1333,20 @@ weston_compositor_get_time(void)
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
-WL_EXPORT struct weston_surface *
-weston_compositor_pick_surface(struct weston_compositor *compositor,
- wl_fixed_t x, wl_fixed_t y,
- wl_fixed_t *sx, wl_fixed_t *sy)
+WL_EXPORT struct weston_view *
+weston_compositor_pick_view(struct weston_compositor *compositor,
+ wl_fixed_t x, wl_fixed_t y,
+ wl_fixed_t *vx, wl_fixed_t *vy)
{
- struct weston_surface *surface;
+ struct weston_view *view;
- wl_list_for_each(surface, &compositor->surface_list, link) {
- weston_surface_from_global_fixed(surface, x, y, sx, sy);
- if (pixman_region32_contains_point(&surface->input,
- wl_fixed_to_int(*sx),
- wl_fixed_to_int(*sy),
+ wl_list_for_each(view, &compositor->view_list, link) {
+ weston_view_from_global_fixed(view, x, y, vx, vy);
+ if (pixman_region32_contains_point(&view->surface->input,
+ wl_fixed_to_int(*vx),
+ wl_fixed_to_int(*vy),
NULL))
- return surface;
+ return view;
}
return NULL;
@@ -1043,7 +1357,7 @@ weston_compositor_repick(struct weston_compositor *compositor)
{
struct weston_seat *seat;
- if (!compositor->focus)
+ if (!compositor->session_active)
return;
wl_list_for_each(seat, &compositor->seat_list, link)
@@ -1051,30 +1365,51 @@ weston_compositor_repick(struct weston_compositor *compositor)
}
WL_EXPORT void
-weston_surface_unmap(struct weston_surface *surface)
+weston_view_unmap(struct weston_view *view)
{
struct weston_seat *seat;
- weston_surface_damage_below(surface);
- surface->output = NULL;
- surface->plane = NULL;
- wl_list_remove(&surface->layer_link);
- wl_list_remove(&surface->link);
- wl_list_init(&surface->link);
+ if (!weston_view_is_mapped(view))
+ return;
+
+ weston_view_damage_below(view);
+ view->output = NULL;
+ view->plane = NULL;
+ wl_list_remove(&view->layer_link);
+ wl_list_init(&view->layer_link);
+ wl_list_remove(&view->link);
+ wl_list_init(&view->link);
+ wl_list_remove(&view->output_move_listener.link);
+ wl_list_init(&view->output_move_listener.link);
+ wl_list_remove(&view->output_destroy_listener.link);
+ wl_list_init(&view->output_destroy_listener.link);
+ view->output_mask = 0;
+ weston_surface_assign_output(view->surface);
+
+ if (weston_surface_is_mapped(view->surface))
+ return;
- wl_list_for_each(seat, &surface->compositor->seat_list, link) {
- if (seat->keyboard && seat->keyboard->focus == surface)
+ wl_list_for_each(seat, &view->surface->compositor->seat_list, link) {
+ if (seat->keyboard && seat->keyboard->focus == view->surface)
weston_keyboard_set_focus(seat->keyboard, NULL);
- if (seat->pointer && seat->pointer->focus == surface)
+ if (seat->pointer && seat->pointer->focus == view)
weston_pointer_set_focus(seat->pointer,
NULL,
wl_fixed_from_int(0),
wl_fixed_from_int(0));
- if (seat->touch && seat->touch->focus == surface)
+ if (seat->touch && seat->touch->focus == view)
weston_touch_set_focus(seat, NULL);
}
+}
- weston_surface_schedule_repaint(surface);
+WL_EXPORT void
+weston_surface_unmap(struct weston_surface *surface)
+{
+ struct weston_view *view;
+
+ wl_list_for_each(view, &surface->views, surface_link)
+ weston_view_unmap(view);
+ surface->output = NULL;
}
struct weston_frame_callback {
@@ -1082,24 +1417,47 @@ struct weston_frame_callback {
struct wl_list link;
};
+WL_EXPORT void
+weston_view_destroy(struct weston_view *view)
+{
+ wl_signal_emit(&view->destroy_signal, view);
+
+ assert(wl_list_empty(&view->geometry.child_list));
+
+ if (weston_view_is_mapped(view)) {
+ weston_view_unmap(view);
+ weston_compositor_build_view_list(view->surface->compositor);
+ }
+
+ wl_list_remove(&view->link);
+ wl_list_remove(&view->layer_link);
+
+ pixman_region32_fini(&view->clip);
+ pixman_region32_fini(&view->transform.boundingbox);
+
+ weston_view_set_transform_parent(view, NULL);
+
+ wl_list_remove(&view->surface_link);
+
+ free(view);
+}
WL_EXPORT void
weston_surface_destroy(struct weston_surface *surface)
{
- struct weston_compositor *compositor = surface->compositor;
struct weston_frame_callback *cb, *next;
+ struct weston_view *ev, *nv;
if (--surface->ref_count > 0)
return;
wl_signal_emit(&surface->destroy_signal, &surface->resource);
- assert(wl_list_empty(&surface->geometry.child_list));
assert(wl_list_empty(&surface->subsurface_list_pending));
assert(wl_list_empty(&surface->subsurface_list));
- if (weston_surface_is_mapped(surface))
- weston_surface_unmap(surface);
+ wl_list_for_each_safe(ev, nv, &surface->views, surface_link)
+ weston_view_destroy(ev);
wl_list_for_each_safe(cb, next,
&surface->pending.frame_callback_list, link)
@@ -1114,19 +1472,13 @@ weston_surface_destroy(struct weston_surface *surface)
weston_buffer_reference(&surface->buffer_ref, NULL);
- compositor->renderer->destroy_surface(surface);
-
- pixman_region32_fini(&surface->transform.boundingbox);
pixman_region32_fini(&surface->damage);
pixman_region32_fini(&surface->opaque);
- pixman_region32_fini(&surface->clip);
pixman_region32_fini(&surface->input);
wl_list_for_each_safe(cb, next, &surface->frame_callback_list, link)
wl_resource_destroy(cb->resource);
- weston_surface_set_transform_parent(surface, NULL);
-
free(surface);
}
@@ -1135,6 +1487,10 @@ destroy_surface(struct wl_resource *resource)
{
struct weston_surface *surface = wl_resource_get_user_data(resource);
+ /* Set the resource to NULL, since we don't want to leave a
+ * dangling pointer if the surface was refcounted and survives
+ * the weston_surface_destroy() call. */
+ surface->resource = NULL;
weston_surface_destroy(surface);
}
@@ -1225,15 +1581,6 @@ weston_surface_attach(struct weston_surface *surface,
}
WL_EXPORT void
-weston_surface_restack(struct weston_surface *surface, struct wl_list *below)
-{
- wl_list_remove(&surface->layer_link);
- wl_list_insert(below, &surface->layer_link);
- weston_surface_damage_below(surface);
- weston_surface_damage(surface);
-}
-
-WL_EXPORT void
weston_compositor_damage_all(struct weston_compositor *compositor)
{
struct weston_output *output;
@@ -1254,43 +1601,53 @@ weston_output_damage(struct weston_output *output)
}
static void
-surface_accumulate_damage(struct weston_surface *surface,
- pixman_region32_t *opaque)
+surface_flush_damage(struct weston_surface *surface)
{
if (surface->buffer_ref.buffer &&
wl_shm_buffer_get(surface->buffer_ref.buffer->resource))
surface->compositor->renderer->flush_damage(surface);
- if (surface->transform.enabled) {
+ empty_region(&surface->damage);
+}
+
+static void
+view_accumulate_damage(struct weston_view *view,
+ pixman_region32_t *opaque)
+{
+ pixman_region32_t damage;
+
+ pixman_region32_init(&damage);
+ if (view->transform.enabled) {
pixman_box32_t *extents;
- extents = pixman_region32_extents(&surface->damage);
- surface_compute_bbox(surface, extents->x1, extents->y1,
- extents->x2 - extents->x1,
- extents->y2 - extents->y1,
- &surface->damage);
- pixman_region32_translate(&surface->damage,
- -surface->plane->x,
- -surface->plane->y);
+ extents = pixman_region32_extents(&view->surface->damage);
+ view_compute_bbox(view, extents->x1, extents->y1,
+ extents->x2 - extents->x1,
+ extents->y2 - extents->y1,
+ &damage);
+ pixman_region32_translate(&damage,
+ -view->plane->x,
+ -view->plane->y);
} else {
- pixman_region32_translate(&surface->damage,
- surface->geometry.x - surface->plane->x,
- surface->geometry.y - surface->plane->y);
+ pixman_region32_copy(&damage, &view->surface->damage);
+ pixman_region32_translate(&damage,
+ view->geometry.x - view->plane->x,
+ view->geometry.y - view->plane->y);
}
- pixman_region32_subtract(&surface->damage, &surface->damage, opaque);
- pixman_region32_union(&surface->plane->damage,
- &surface->plane->damage, &surface->damage);
- empty_region(&surface->damage);
- pixman_region32_copy(&surface->clip, opaque);
- pixman_region32_union(opaque, opaque, &surface->transform.opaque);
+ pixman_region32_subtract(&damage, &damage, opaque);
+ pixman_region32_union(&view->plane->damage,
+ &view->plane->damage, &damage);
+ pixman_region32_fini(&damage);
+ pixman_region32_copy(&view->clip, opaque);
+ pixman_region32_union(opaque, opaque, &view->transform.opaque);
}
static void
compositor_accumulate_damage(struct weston_compositor *ec)
{
struct weston_plane *plane;
- struct weston_surface *es;
+ struct weston_view *ev;
pixman_region32_t opaque, clip;
pixman_region32_init(&clip);
@@ -1300,11 +1657,11 @@ compositor_accumulate_damage(struct weston_compositor *ec)
pixman_region32_init(&opaque);
- wl_list_for_each(es, &ec->surface_list, link) {
- if (es->plane != plane)
+ wl_list_for_each(ev, &ec->view_list, link) {
+ if (ev->plane != plane)
continue;
- surface_accumulate_damage(es, &opaque);
+ view_accumulate_damage(ev, &opaque);
}
pixman_region32_union(&clip, &clip, &opaque);
@@ -1313,7 +1670,16 @@ compositor_accumulate_damage(struct weston_compositor *ec)
pixman_region32_fini(&clip);
- wl_list_for_each(es, &ec->surface_list, link) {
+ wl_list_for_each(ev, &ec->view_list, link)
+ ev->surface->touched = 0;
+
+ wl_list_for_each(ev, &ec->view_list, link) {
+ if (ev->surface->touched)
+ continue;
+ ev->surface->touched = 1;
+
+ surface_flush_damage(ev->surface);
+
/* Both the renderer and the backend have seen the buffer
* by now. If renderer needs the buffer, it has its own
* reference set. If the backend wants to keep the buffer
@@ -1322,77 +1688,161 @@ compositor_accumulate_damage(struct weston_compositor *ec)
* reference now, and allow early buffer release. This enables
* clients to use single-buffering.
*/
- if (!es->keep_buffer)
- weston_buffer_reference(&es->buffer_ref, NULL);
+ if (!ev->surface->keep_buffer)
+ weston_buffer_reference(&ev->surface->buffer_ref, NULL);
}
}
static void
-surface_list_add(struct weston_compositor *compositor,
- struct weston_surface *surface)
+surface_stash_subsurface_views(struct weston_surface *surface)
{
struct weston_subsurface *sub;
- if (wl_list_empty(&surface->subsurface_list)) {
- weston_surface_update_transform(surface);
- wl_list_insert(compositor->surface_list.prev, &surface->link);
- return;
+ wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
+ if (sub->surface == surface)
+ continue;
+
+ wl_list_insert_list(&sub->unused_views, &sub->surface->views);
+ wl_list_init(&sub->surface->views);
+
+ surface_stash_subsurface_views(sub->surface);
}
+}
+
+static void
+surface_free_unused_subsurface_views(struct weston_surface *surface)
+{
+ struct weston_subsurface *sub;
+ struct weston_view *view, *nv;
wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
- if (!weston_surface_is_mapped(sub->surface))
+ if (sub->surface == surface)
continue;
- if (sub->surface == surface) {
- weston_surface_update_transform(sub->surface);
- wl_list_insert(compositor->surface_list.prev,
- &sub->surface->link);
- } else {
- surface_list_add(compositor, sub->surface);
+ wl_list_for_each_safe(view, nv, &sub->unused_views, surface_link)
+ weston_view_destroy(view);
+
+ surface_free_unused_subsurface_views(sub->surface);
+ }
+}
+
+static void
+view_list_add_subsurface_view(struct weston_compositor *compositor,
+ struct weston_subsurface *sub,
+ struct weston_view *parent)
+{
+ struct weston_subsurface *child;
+ struct weston_view *view = NULL, *iv;
+
+ wl_list_for_each(iv, &sub->unused_views, surface_link) {
+ if (iv->geometry.parent == parent) {
+ view = iv;
+ break;
}
}
+
+ if (view) {
+ /* Put it back in the surface's list of views */
+ wl_list_remove(&view->surface_link);
+ wl_list_insert(&sub->surface->views, &view->surface_link);
+ } else {
+ view = weston_view_create(sub->surface);
+ weston_view_set_position(view,
+ sub->position.x,
+ sub->position.y);
+ weston_view_set_transform_parent(view, parent);
+ }
+
+ weston_view_update_transform(view);
+
+ if (wl_list_empty(&sub->surface->subsurface_list)) {
+ wl_list_insert(compositor->view_list.prev, &view->link);
+ return;
+ }
+
+ wl_list_for_each(child, &sub->surface->subsurface_list, parent_link) {
+ if (child->surface == sub->surface)
+ wl_list_insert(compositor->view_list.prev, &view->link);
+ else
+ view_list_add_subsurface_view(compositor, child, view);
+ }
}
static void
-weston_compositor_build_surface_list(struct weston_compositor *compositor)
+view_list_add(struct weston_compositor *compositor,
+ struct weston_view *view)
{
- struct weston_surface *surface;
+ struct weston_subsurface *sub;
+
+ weston_view_update_transform(view);
+
+ if (wl_list_empty(&view->surface->subsurface_list)) {
+ wl_list_insert(compositor->view_list.prev, &view->link);
+ return;
+ }
+
+ wl_list_for_each(sub, &view->surface->subsurface_list, parent_link) {
+ if (sub->surface == view->surface)
+ wl_list_insert(compositor->view_list.prev, &view->link);
+ else
+ view_list_add_subsurface_view(compositor, sub, view);
+ }
+}
+
+static void
+weston_compositor_build_view_list(struct weston_compositor *compositor)
+{
+ struct weston_view *view;
struct weston_layer *layer;
- wl_list_init(&compositor->surface_list);
+ wl_list_for_each(layer, &compositor->layer_list, link)
+ wl_list_for_each(view, &layer->view_list, layer_link)
+ surface_stash_subsurface_views(view->surface);
+
+ wl_list_init(&compositor->view_list);
wl_list_for_each(layer, &compositor->layer_list, link) {
- wl_list_for_each(surface, &layer->surface_list, layer_link) {
- surface_list_add(compositor, surface);
+ wl_list_for_each(view, &layer->view_list, layer_link) {
+ view_list_add(compositor, view);
}
}
+
+ wl_list_for_each(layer, &compositor->layer_list, link)
+ wl_list_for_each(view, &layer->view_list, layer_link)
+ surface_free_unused_subsurface_views(view->surface);
}
static int
weston_output_repaint(struct weston_output *output, uint32_t msecs)
{
struct weston_compositor *ec = output->compositor;
- struct weston_surface *es;
+ struct weston_view *ev;
struct weston_animation *animation, *next;
struct weston_frame_callback *cb, *cnext;
struct wl_list frame_callback_list;
pixman_region32_t output_damage;
int r;
+ if (output->destroying)
+ return 0;
+
/* Rebuild the surface list and update surface transforms up front. */
- weston_compositor_build_surface_list(ec);
+ weston_compositor_build_view_list(ec);
if (output->assign_planes && !output->disable_planes)
output->assign_planes(output);
else
- wl_list_for_each(es, &ec->surface_list, link)
- weston_surface_move_to_plane(es, &ec->primary_plane);
+ wl_list_for_each(ev, &ec->view_list, link)
+ weston_view_move_to_plane(ev, &ec->primary_plane);
wl_list_init(&frame_callback_list);
- wl_list_for_each(es, &ec->surface_list, link) {
- if (es->output == output) {
+ wl_list_for_each(ev, &ec->view_list, link) {
+ /* Note: This operation is safe to do multiple times on the
+ * same surface.
+ */
+ if (ev->surface->output == output) {
wl_list_insert_list(&frame_callback_list,
- &es->frame_callback_list);
- wl_list_init(&es->frame_callback_list);
+ &ev->surface->frame_callback_list);
+ wl_list_init(&ev->surface->frame_callback_list);
}
}
@@ -1478,7 +1928,7 @@ idle_repaint(void *data)
WL_EXPORT void
weston_layer_init(struct weston_layer *layer, struct wl_list *below)
{
- wl_list_init(&layer->surface_list);
+ wl_list_init(&layer->view_list);
if (below != NULL)
wl_list_insert(below, &layer->link);
}
@@ -1651,29 +2101,23 @@ weston_surface_commit_subsurface_order(struct weston_surface *surface)
static void
weston_surface_commit(struct weston_surface *surface)
{
+ struct weston_view *view;
pixman_region32_t opaque;
- int surface_width = 0;
- int surface_height = 0;
/* wl_surface.set_buffer_transform */
- surface->buffer_transform = surface->pending.buffer_transform;
-
/* wl_surface.set_buffer_scale */
- surface->buffer_scale = surface->pending.buffer_scale;
+ /* wl_viewport.set */
+ surface->buffer_viewport = surface->pending.buffer_viewport;
/* wl_surface.attach */
if (surface->pending.buffer || surface->pending.newly_attached)
weston_surface_attach(surface, surface->pending.buffer);
- if (surface->buffer_ref.buffer) {
- surface_width = weston_surface_buffer_width(surface);
- surface_height = weston_surface_buffer_height(surface);
- }
+ weston_surface_set_size_from_buffer(surface);
if (surface->configure && surface->pending.newly_attached)
surface->configure(surface,
- surface->pending.sx, surface->pending.sy,
- surface_width, surface_height);
+ surface->pending.sx, surface->pending.sy);
if (surface->pending.buffer)
wl_list_remove(&surface->pending.buffer_destroy_listener.link);
@@ -1687,20 +2131,21 @@ weston_surface_commit(struct weston_surface *surface)
&surface->pending.damage);
pixman_region32_intersect_rect(&surface->damage, &surface->damage,
0, 0,
- surface->geometry.width,
- surface->geometry.height);
+ surface->width,
+ surface->height);
empty_region(&surface->pending.damage);
/* wl_surface.set_opaque_region */
pixman_region32_init_rect(&opaque, 0, 0,
- surface->geometry.width,
- surface->geometry.height);
+ surface->width,
+ surface->height);
pixman_region32_intersect(&opaque,
&opaque, &surface->pending.opaque);
if (!pixman_region32_equal(&opaque, &surface->opaque)) {
pixman_region32_copy(&surface->opaque, &opaque);
- weston_surface_geometry_dirty(surface);
+ wl_list_for_each(view, &surface->views, surface_link)
+ weston_view_geometry_dirty(view);
}
pixman_region32_fini(&opaque);
@@ -1708,8 +2153,8 @@ weston_surface_commit(struct weston_surface *surface)
/* wl_surface.set_input_region */
pixman_region32_fini(&surface->input);
pixman_region32_init_rect(&surface->input, 0, 0,
- surface->geometry.width,
- surface->geometry.height);
+ surface->width,
+ surface->height);
pixman_region32_intersect(&surface->input,
&surface->input, &surface->pending.input);
@@ -1755,7 +2200,7 @@ surface_set_buffer_transform(struct wl_client *client,
{
struct weston_surface *surface = wl_resource_get_user_data(resource);
- surface->pending.buffer_transform = transform;
+ surface->pending.buffer_viewport.transform = transform;
}
static void
@@ -1765,7 +2210,7 @@ surface_set_buffer_scale(struct wl_client *client,
{
struct weston_surface *surface = wl_resource_get_user_data(resource);
- surface->pending.buffer_scale = scale;
+ surface->pending.buffer_viewport.scale = scale;
}
static const struct wl_surface_interface surface_interface = {
@@ -1882,29 +2327,23 @@ static void
weston_subsurface_commit_from_cache(struct weston_subsurface *sub)
{
struct weston_surface *surface = sub->surface;
+ struct weston_view *view;
pixman_region32_t opaque;
- int surface_width = 0;
- int surface_height = 0;
/* wl_surface.set_buffer_transform */
- surface->buffer_transform = sub->cached.buffer_transform;
-
/* wl_surface.set_buffer_scale */
- surface->buffer_scale = sub->cached.buffer_scale;
+ /* wl_viewport.set */
+ surface->buffer_viewport = sub->cached.buffer_viewport;
/* wl_surface.attach */
if (sub->cached.buffer_ref.buffer || sub->cached.newly_attached)
weston_surface_attach(surface, sub->cached.buffer_ref.buffer);
weston_buffer_reference(&sub->cached.buffer_ref, NULL);
- if (surface->buffer_ref.buffer) {
- surface_width = weston_surface_buffer_width(surface);
- surface_height = weston_surface_buffer_height(surface);
- }
+ weston_surface_set_size_from_buffer(surface);
if (surface->configure && sub->cached.newly_attached)
- surface->configure(surface, sub->cached.sx, sub->cached.sy,
- surface_width, surface_height);
+ surface->configure(surface, sub->cached.sx, sub->cached.sy);
sub->cached.sx = 0;
sub->cached.sy = 0;
sub->cached.newly_attached = 0;
@@ -1914,20 +2353,21 @@ weston_subsurface_commit_from_cache(struct weston_subsurface *sub)
&sub->cached.damage);
pixman_region32_intersect_rect(&surface->damage, &surface->damage,
0, 0,
- surface->geometry.width,
- surface->geometry.height);
+ surface->width,
+ surface->height);
empty_region(&sub->cached.damage);
/* wl_surface.set_opaque_region */
pixman_region32_init_rect(&opaque, 0, 0,
- surface->geometry.width,
- surface->geometry.height);
+ surface->width,
+ surface->height);
pixman_region32_intersect(&opaque,
&opaque, &sub->cached.opaque);
if (!pixman_region32_equal(&opaque, &surface->opaque)) {
pixman_region32_copy(&surface->opaque, &opaque);
- weston_surface_geometry_dirty(surface);
+ wl_list_for_each(view, &surface->views, surface_link)
+ weston_view_geometry_dirty(view);
}
pixman_region32_fini(&opaque);
@@ -1935,8 +2375,8 @@ weston_subsurface_commit_from_cache(struct weston_subsurface *sub)
/* wl_surface.set_input_region */
pixman_region32_fini(&surface->input);
pixman_region32_init_rect(&surface->input, 0, 0,
- surface->geometry.width,
- surface->geometry.height);
+ surface->width,
+ surface->height);
pixman_region32_intersect(&surface->input,
&surface->input, &sub->cached.input);
@@ -1980,8 +2420,7 @@ weston_subsurface_commit_to_cache(struct weston_subsurface *sub)
surface->pending.sy = 0;
surface->pending.newly_attached = 0;
- sub->cached.buffer_transform = surface->pending.buffer_transform;
- sub->cached.buffer_scale = surface->pending.buffer_scale;
+ sub->cached.buffer_viewport = surface->pending.buffer_viewport;
pixman_region32_copy(&sub->cached.opaque, &surface->pending.opaque);
@@ -2060,9 +2499,13 @@ static void
weston_subsurface_parent_commit(struct weston_subsurface *sub,
int parent_is_synchronized)
{
+ struct weston_view *view;
if (sub->position.set) {
- weston_surface_set_position(sub->surface,
- sub->position.x, sub->position.y);
+ wl_list_for_each(view, &sub->surface->views, surface_link)
+ weston_view_set_position(view,
+ sub->position.x,
+ sub->position.y);
+
sub->position.set = 0;
}
@@ -2071,23 +2514,21 @@ weston_subsurface_parent_commit(struct weston_subsurface *sub,
}
static void
-subsurface_configure(struct weston_surface *surface, int32_t dx, int32_t dy,
- int32_t width, int32_t height)
+subsurface_configure(struct weston_surface *surface, int32_t dx, int32_t dy)
{
struct weston_compositor *compositor = surface->compositor;
+ struct weston_view *view;
- weston_surface_configure(surface,
- surface->geometry.x + dx,
- surface->geometry.y + dy,
- width, height);
+ wl_list_for_each(view, &surface->views, surface_link)
+ weston_view_set_position(view,
+ view->geometry.x + dx,
+ view->geometry.y + dy);
/* No need to check parent mappedness, because if parent is not
* mapped, parent is not in a visible layer, so this sub-surface
* will not be drawn either.
*/
if (!weston_surface_is_mapped(surface)) {
- wl_list_init(&surface->layer_link);
-
/* Cannot call weston_surface_update_transform(),
* because that would call it also for the parent surface,
* which might not be mapped yet. That would lead to
@@ -2359,6 +2800,8 @@ weston_subsurface_link_surface(struct weston_subsurface *sub,
static void
weston_subsurface_destroy(struct weston_subsurface *sub)
{
+ struct weston_view *view, *next;
+
assert(sub->surface);
if (sub->resource) {
@@ -2366,7 +2809,9 @@ weston_subsurface_destroy(struct weston_subsurface *sub)
assert(sub->parent_destroy_listener.notify ==
subsurface_handle_parent_destroy);
- weston_surface_set_transform_parent(sub->surface, NULL);
+ wl_list_for_each_safe(view, next, &sub->surface->views, surface_link)
+ weston_view_destroy(view);
+
if (sub->parent)
weston_subsurface_unlink_parent(sub);
@@ -2405,6 +2850,8 @@ weston_subsurface_create(uint32_t id, struct weston_surface *surface,
if (!sub)
return NULL;
+ wl_list_init(&sub->unused_views);
+
sub->resource =
wl_resource_create(client, &wl_subsurface_interface, 1, id);
if (!sub->resource) {
@@ -2419,7 +2866,6 @@ weston_subsurface_create(uint32_t id, struct weston_surface *surface,
weston_subsurface_link_parent(sub, parent);
weston_subsurface_cache_init(sub);
sub->synchronized = 1;
- weston_surface_set_transform_parent(surface, parent);
return sub;
}
@@ -2631,14 +3077,14 @@ weston_plane_init(struct weston_plane *plane,
WL_EXPORT void
weston_plane_release(struct weston_plane *plane)
{
- struct weston_surface *surface;
+ struct weston_view *view;
pixman_region32_fini(&plane->damage);
pixman_region32_fini(&plane->clip);
- wl_list_for_each(surface, &plane->compositor->surface_list, link) {
- if (surface->plane == plane)
- surface->plane = NULL;
+ wl_list_for_each(view, &plane->compositor->view_list, link) {
+ if (view->plane == plane)
+ view->plane = NULL;
}
wl_list_remove(&plane->link);
@@ -2702,9 +3148,51 @@ bind_output(struct wl_client *client,
wl_output_send_done(resource);
}
+/* Move other outputs when one is removed so the space remains contiguos. */
+static void
+weston_compositor_remove_output(struct weston_compositor *compositor,
+ struct weston_output *remove_output)
+{
+ struct weston_output *output;
+ int offset = 0;
+
+ wl_list_for_each(output, &compositor->output_list, link) {
+ if (output == remove_output) {
+ offset = output->width;
+ continue;
+ }
+
+ if (offset > 0) {
+ weston_output_move(output,
+ output->x - offset, output->y);
+ output->dirty = 1;
+ }
+ }
+}
+
+static void
+weston_compositor_verify_pointers(struct weston_compositor *ec)
+{
+ struct weston_seat *seat;
+
+ wl_list_for_each(seat, &ec->seat_list, link) {
+ if (!seat->pointer)
+ continue;
+
+ weston_pointer_verify(seat->pointer);
+ }
+}
+
WL_EXPORT void
weston_output_destroy(struct weston_output *output)
{
+ output->destroying = 1;
+
+ weston_compositor_remove_output(output->compositor, output);
+ wl_list_remove(&output->link);
+
+ weston_compositor_verify_pointers(output->compositor);
+
wl_signal_emit(&output->destroy_signal, output);
free(output->name);
@@ -2782,12 +3270,12 @@ weston_output_update_matrix(struct weston_output *output)
weston_matrix_init(&output->matrix);
weston_matrix_translate(&output->matrix,
- -(output->x + (output->border.right + output->width - output->border.left) / 2.0),
- -(output->y + (output->border.bottom + output->height - output->border.top) / 2.0), 0);
+ -(output->x + output->width / 2.0),
+ -(output->y + output->height / 2.0), 0);
weston_matrix_scale(&output->matrix,
- 2.0 / (output->width + output->border.left + output->border.right),
- -2.0 / (output->height + output->border.top + output->border.bottom), 1);
+ 2.0 / output->width,
+ -2.0 / output->height, 1);
weston_output_compute_transform(output);
@@ -2795,7 +3283,7 @@ weston_output_update_matrix(struct weston_output *output)
magnification = 1 / (1 - output->zoom.spring_z.current);
weston_matrix_init(&camera);
weston_matrix_init(&modelview);
- weston_output_update_zoom(output, output->zoom.type);
+ weston_output_update_zoom(output);
weston_matrix_translate(&camera, output->zoom.trans_x,
-output->zoom.trans_y, 0);
weston_matrix_invert(&modelview, &camera);
@@ -2836,8 +3324,8 @@ weston_output_transform_scale_init(struct weston_output *output, uint32_t transf
output->height /= scale;
}
-WL_EXPORT void
-weston_output_move(struct weston_output *output, int x, int y)
+static void
+weston_output_init_geometry(struct weston_output *output, int x, int y)
{
output->x = x;
output->y = y;
@@ -2849,6 +3337,41 @@ weston_output_move(struct weston_output *output, int x, int y)
}
WL_EXPORT void
+weston_output_move(struct weston_output *output, int x, int y)
+{
+ pixman_region32_t old_region;
+ struct wl_resource *resource;
+
+ output->move_x = x - output->x;
+ output->move_y = y - output->y;
+
+ if (output->move_x == 0 && output->move_y == 0)
+ return;
+
+ pixman_region32_init(&old_region);
+ pixman_region32_copy(&old_region, &output->region);
+
+ weston_output_init_geometry(output, x, y);
+
+ output->dirty = 1;
+
+ /* Move views on this output. */
+ wl_signal_emit(&output->move_signal, output);
+
+ /* Notify clients of the change for output position. */
+ wl_resource_for_each(resource, &output->resource_list)
+ wl_output_send_geometry(resource,
+ output->x,
+ output->y,
+ output->mm_width,
+ output->mm_height,
+ output->subpixel,
+ output->make,
+ output->model,
+ output->transform);
+}
+
+WL_EXPORT void
weston_output_init(struct weston_output *output, struct weston_compositor *c,
int x, int y, int mm_width, int mm_height, uint32_t transform,
int32_t scale)
@@ -2856,10 +3379,6 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,
output->compositor = c;
output->x = x;
output->y = y;
- output->border.top = 0;
- output->border.bottom = 0;
- output->border.left = 0;
- output->border.right = 0;
output->mm_width = mm_width;
output->mm_height = mm_height;
output->dirty = 1;
@@ -2868,11 +3387,12 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,
weston_output_transform_scale_init(output, transform, scale);
weston_output_init_zoom(output);
- weston_output_move(output, x, y);
+ weston_output_init_geometry(output, x, y);
weston_output_damage(output);
wl_signal_init(&output->frame_signal);
wl_signal_init(&output->destroy_signal);
+ wl_signal_init(&output->move_signal);
wl_list_init(&output->animation_list);
wl_list_init(&output->resource_list);
@@ -2887,7 +3407,7 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,
WL_EXPORT void
weston_output_transform_coordinate(struct weston_output *output,
- int device_x, int device_y,
+ wl_fixed_t device_x, wl_fixed_t device_y,
wl_fixed_t *x, wl_fixed_t *y)
{
wl_fixed_t tx, ty;
@@ -2899,36 +3419,36 @@ weston_output_transform_coordinate(struct weston_output *output,
switch(output->transform) {
case WL_OUTPUT_TRANSFORM_NORMAL:
default:
- tx = wl_fixed_from_int(device_x);
- ty = wl_fixed_from_int(device_y);
+ tx = device_x;
+ ty = device_y;
break;
case WL_OUTPUT_TRANSFORM_90:
- tx = wl_fixed_from_int(device_y);
- ty = height - wl_fixed_from_int(device_x);
+ tx = device_y;
+ ty = height - device_x;
break;
case WL_OUTPUT_TRANSFORM_180:
- tx = width - wl_fixed_from_int(device_x);
- ty = height - wl_fixed_from_int(device_y);
+ tx = width - device_x;
+ ty = height - device_y;
break;
case WL_OUTPUT_TRANSFORM_270:
- tx = width - wl_fixed_from_int(device_y);
- ty = wl_fixed_from_int(device_x);
+ tx = width - device_y;
+ ty = device_x;
break;
case WL_OUTPUT_TRANSFORM_FLIPPED:
- tx = width - wl_fixed_from_int(device_x);
- ty = wl_fixed_from_int(device_y);
+ tx = width - device_x;
+ ty = device_y;
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- tx = width - wl_fixed_from_int(device_y);
- ty = height - wl_fixed_from_int(device_x);
+ tx = width - device_y;
+ ty = height - device_x;
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
- tx = wl_fixed_from_int(device_x);
- ty = height - wl_fixed_from_int(device_y);
+ tx = device_x;
+ ty = height - device_y;
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- tx = wl_fixed_from_int(device_y);
- ty = wl_fixed_from_int(device_x);
+ tx = device_y;
+ ty = device_x;
break;
}
@@ -2937,6 +3457,129 @@ weston_output_transform_coordinate(struct weston_output *output,
}
static void
+destroy_viewport(struct wl_resource *resource)
+{
+ struct weston_surface *surface =
+ wl_resource_get_user_data(resource);
+
+ surface->viewport_resource = NULL;
+ surface->pending.buffer_viewport.viewport_set = 0;
+}
+
+static void
+viewport_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+viewport_set(struct wl_client *client,
+ struct wl_resource *resource,
+ wl_fixed_t src_x,
+ wl_fixed_t src_y,
+ wl_fixed_t src_width,
+ wl_fixed_t src_height,
+ int32_t dst_width,
+ int32_t dst_height)
+{
+ struct weston_surface *surface =
+ wl_resource_get_user_data(resource);
+
+ assert(surface->viewport_resource != NULL);
+
+ if (wl_fixed_to_double(src_width) < 0 ||
+ wl_fixed_to_double(src_height) < 0) {
+ wl_resource_post_error(resource,
+ WL_VIEWPORT_ERROR_BAD_VALUE,
+ "source dimensions must be non-negative (%fx%f)",
+ wl_fixed_to_double(src_width),
+ wl_fixed_to_double(src_height));
+ return;
+ }
+
+ if (dst_width <= 0 || dst_height <= 0) {
+ wl_resource_post_error(resource,
+ WL_VIEWPORT_ERROR_BAD_VALUE,
+ "destination dimensions must be positive (%dx%d)",
+ dst_width, dst_height);
+ return;
+ }
+
+ surface->pending.buffer_viewport.viewport_set = 1;
+
+ surface->pending.buffer_viewport.src_x = src_x;
+ surface->pending.buffer_viewport.src_y = src_y;
+ surface->pending.buffer_viewport.src_width = src_width;
+ surface->pending.buffer_viewport.src_height = src_height;
+ surface->pending.buffer_viewport.dst_width = dst_width;
+ surface->pending.buffer_viewport.dst_height = dst_height;
+}
+
+static const struct wl_viewport_interface viewport_interface = {
+ viewport_destroy,
+ viewport_set
+};
+
+static void
+scaler_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+scaler_get_viewport(struct wl_client *client,
+ struct wl_resource *scaler,
+ uint32_t id,
+ struct wl_resource *surface_resource)
+{
+ struct weston_surface *surface = wl_resource_get_user_data(surface_resource);
+ struct wl_resource *resource;
+
+ if (surface->viewport_resource) {
+ wl_resource_post_error(scaler,
+ WL_SCALER_ERROR_VIEWPORT_EXISTS,
+ "a viewport for that surface already exists");
+ return;
+ }
+
+ resource = wl_resource_create(client, &wl_viewport_interface,
+ 1, id);
+ if (resource == NULL) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(resource, &viewport_interface,
+ surface, destroy_viewport);
+
+ surface->viewport_resource = resource;
+}
+
+static const struct wl_scaler_interface scaler_interface = {
+ scaler_destroy,
+ scaler_get_viewport
+};
+
+static void
+bind_scaler(struct wl_client *client,
+ void *data, uint32_t version, uint32_t id)
+{
+ struct wl_resource *resource;
+
+ resource = wl_resource_create(client, &wl_scaler_interface,
+ 1, id);
+ if (resource == NULL) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(resource, &scaler_interface,
+ NULL, NULL);
+}
+
+static void
compositor_bind(struct wl_client *client,
void *data, uint32_t version, uint32_t id)
{
@@ -3024,12 +3667,17 @@ weston_compositor_init(struct weston_compositor *ec,
ec, bind_subcompositor))
return -1;
- wl_list_init(&ec->surface_list);
+ if (!wl_global_create(ec->wl_display, &wl_scaler_interface, 1,
+ ec, bind_scaler))
+ return -1;
+
+ wl_list_init(&ec->view_list);
wl_list_init(&ec->plane_list);
wl_list_init(&ec->layer_list);
wl_list_init(&ec->seat_list);
wl_list_init(&ec->output_list);
wl_list_init(&ec->key_binding_list);
+ wl_list_init(&ec->modifier_binding_list);
wl_list_init(&ec->button_binding_list);
wl_list_init(&ec->touch_binding_list);
wl_list_init(&ec->axis_binding_list);
@@ -3056,7 +3704,6 @@ weston_compositor_init(struct weston_compositor *ec,
ec->ping_handler = NULL;
screenshooter_create(ec);
- text_cursor_position_notifier_create(ec);
text_backend_init(ec);
wl_data_device_manager_init(ec->wl_display);
@@ -3090,6 +3737,9 @@ weston_compositor_shutdown(struct weston_compositor *ec)
wl_list_for_each_safe(output, next, &ec->output_list, link)
output->destroy(output);
+ if (ec->renderer)
+ ec->renderer->destroy(ec);
+
weston_binding_list_destroy_all(&ec->key_binding_list);
weston_binding_list_destroy_all(&ec->button_binding_list);
weston_binding_list_destroy_all(&ec->touch_binding_list);
@@ -3104,6 +3754,21 @@ weston_compositor_shutdown(struct weston_compositor *ec)
}
WL_EXPORT void
+weston_compositor_set_default_pointer_grab(struct weston_compositor *ec,
+ const struct weston_pointer_grab_interface *interface)
+{
+ struct weston_seat *seat;
+
+ ec->default_pointer_grab = interface;
+ wl_list_for_each(seat, &ec->seat_list, link) {
+ if (seat->pointer) {
+ weston_pointer_set_default_grab(seat->pointer,
+ interface);
+ }
+ }
+}
+
+WL_EXPORT void
weston_version(int *major, int *minor, int *micro)
{
*major = WESTON_VERSION_MAJOR;
@@ -3243,8 +3908,8 @@ on_caught_signal(int s, siginfo_t *siginfo, void *context)
raise(SIGTRAP);
}
-static void *
-load_module(const char *name, const char *entrypoint)
+WL_EXPORT void *
+weston_load_module(const char *name, const char *entrypoint)
{
char path[PATH_MAX];
void *module, *init;
@@ -3294,7 +3959,7 @@ load_modules(struct weston_compositor *ec, const char *modules,
while (*p) {
end = strchrnul(p, ',');
snprintf(buffer, sizeof buffer, "%.*s", (int) (end - p), p);
- module_init = load_module(buffer, "module_init");
+ module_init = weston_load_module(buffer, "module_init");
if (module_init)
module_init(ec, argc, argv);
p = end;
@@ -3397,6 +4062,10 @@ usage(int error_code)
"Options for wayland-backend.so:\n\n"
" --width=WIDTH\t\tWidth of Wayland surface\n"
" --height=HEIGHT\tHeight of Wayland surface\n"
+ " --scale=SCALE\tScale factor of ouput\n"
+ " --fullscreen\t\tRun in fullscreen mode\n"
+ " --use-pixman\t\tUse the pixman (CPU) renderer\n"
+ " --output-count=COUNT\tCreate multiple outputs\n"
" --display=DISPLAY\tWayland display to connect to\n\n");
#if defined(BUILD_RPI_COMPOSITOR) && defined(HAVE_BCM_HOST)
@@ -3406,6 +4075,8 @@ usage(int error_code)
" --single-buffer\tUse single-buffered Dispmanx elements.\n"
" --transform=TR\tThe output transformation, TR is one of:\n"
"\tnormal 90 180 270 flipped flipped-90 flipped-180 flipped-270\n"
+ " --opaque-regions\tEnable support for opaque regions, can be "
+ "very slow without support in the GPU firmware.\n"
"\n");
#endif
@@ -3452,6 +4123,7 @@ int main(int argc, char *argv[])
struct weston_config *config);
int i;
char *backend = NULL;
+ char *option_backend = NULL;
char *shell = NULL;
char *modules, *option_modules = NULL;
char *log = NULL;
@@ -3463,7 +4135,7 @@ int main(int argc, char *argv[])
struct weston_config_section *section;
const struct weston_option core_options[] = {
- { WESTON_OPTION_STRING, "backend", 'B', &backend },
+ { WESTON_OPTION_STRING, "backend", 'B', &option_backend },
{ WESTON_OPTION_STRING, "shell", 0, &shell },
{ WESTON_OPTION_STRING, "socket", 'S', &socket_name },
{ WESTON_OPTION_INTEGER, "idle-time", 'i', &idle_time },
@@ -3509,6 +4181,19 @@ int main(int argc, char *argv[])
signals[3] = wl_event_loop_add_signal(loop, SIGCHLD, sigchld_handler,
NULL);
+ config = weston_config_parse("weston.ini");
+ if (config != NULL) {
+ weston_log("Using config file '%s'\n",
+ weston_config_get_full_path(config));
+ } else {
+ weston_log("Starting with no config file.\n");
+ }
+ section = weston_config_get_section(config, "core", NULL, NULL);
+
+ weston_config_section_get_string(section, "backend", &backend, NULL);
+ if (option_backend) {
+ backend = option_backend;
+ }
if (!backend) {
if (getenv("WAYLAND_DISPLAY"))
backend = "wayland-backend.so";
@@ -3518,17 +4203,9 @@ int main(int argc, char *argv[])
backend = WESTON_NATIVE_BACKEND;
}
- config = weston_config_parse("weston.ini");
- if (config != NULL) {
- weston_log("Using config file '%s'\n",
- weston_config_get_full_path(config));
- } else {
- weston_log("Starting with no config file.\n");
- }
- section = weston_config_get_section(config, "core", NULL, NULL);
weston_config_section_get_string(section, "modules", &modules, "");
- backend_init = load_module(backend, "backend_init");
+ backend_init = weston_load_module(backend, "backend_init");
if (!backend_init)
exit(EXIT_FAILURE);
@@ -3542,6 +4219,7 @@ int main(int argc, char *argv[])
segv_compositor = ec;
ec->idle_time = idle_time;
+ ec->default_pointer_grab = NULL;
setenv("WAYLAND_DISPLAY", socket_name, 1);
diff --git a/src/compositor.h b/src/compositor.h
index 0dcb604e..22a485fc 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -92,6 +92,8 @@ struct weston_shell_interface {
struct shell_surface *(*create_shell_surface)(void *shell,
struct weston_surface *surface,
const struct weston_shell_client *client);
+ struct weston_view *(*get_primary_view)(void *shell,
+ struct shell_surface *shsurf);
void (*set_toplevel)(struct shell_surface *shsurf);
@@ -112,10 +114,6 @@ struct weston_shell_interface {
};
-struct weston_border {
- int32_t left, right, top, bottom;
-};
-
struct weston_animation {
void (*frame)(struct weston_animation *animation,
struct weston_output *output, uint32_t msecs);
@@ -140,18 +138,12 @@ struct weston_spring {
uint32_t clip;
};
-enum {
- ZOOM_FOCUS_POINTER,
- ZOOM_FOCUS_TEXT
-};
-
struct weston_fixed_point {
wl_fixed_t x, y;
};
struct weston_output_zoom {
int active;
- uint32_t type;
float increment;
float level;
float max_level;
@@ -163,7 +155,7 @@ struct weston_output_zoom {
struct weston_fixed_point from;
struct weston_fixed_point to;
struct weston_fixed_point current;
- struct weston_fixed_point text_cursor;
+ struct wl_listener motion_listener;
};
/* bit compatible with drm definitions. */
@@ -194,7 +186,6 @@ struct weston_output {
struct wl_list animation_list;
int32_t x, y, width, height;
int32_t mm_width, mm_height;
- struct weston_border border;
pixman_region32_t region;
pixman_region32_t previous_damage;
int repaint_needed;
@@ -203,8 +194,11 @@ struct weston_output {
int dirty;
struct wl_signal frame_signal;
struct wl_signal destroy_signal;
+ struct wl_signal move_signal;
+ int move_x, move_y;
uint32_t frame_time;
int disable_planes;
+ int destroying;
char *make, *model, *serial_number;
uint32_t subpixel;
@@ -242,7 +236,8 @@ struct weston_output {
struct weston_pointer_grab;
struct weston_pointer_grab_interface {
void (*focus)(struct weston_pointer_grab *grab);
- void (*motion)(struct weston_pointer_grab *grab, uint32_t time);
+ void (*motion)(struct weston_pointer_grab *grab, uint32_t time,
+ wl_fixed_t x, wl_fixed_t y);
void (*button)(struct weston_pointer_grab *grab,
uint32_t time, uint32_t button, uint32_t state);
void (*cancel)(struct weston_pointer_grab *grab);
@@ -314,11 +309,14 @@ struct weston_pointer {
struct wl_list resource_list;
struct wl_list focus_resource_list;
- struct weston_surface *focus;
+ struct weston_view *focus;
uint32_t focus_serial;
+ struct wl_listener focus_view_listener;
+ struct wl_listener focus_resource_listener;
struct wl_signal focus_signal;
+ struct wl_signal motion_signal;
- struct weston_surface *sprite;
+ struct weston_view *sprite;
struct wl_listener sprite_destroy_listener;
int32_t hotspot_x, hotspot_y;
@@ -339,10 +337,14 @@ struct weston_touch {
struct wl_list resource_list;
struct wl_list focus_resource_list;
- struct weston_surface *focus;
+ struct weston_view *focus;
+ struct wl_listener focus_view_listener;
+ struct wl_listener focus_resource_listener;
uint32_t focus_serial;
struct wl_signal focus_signal;
+ uint32_t num_tp;
+
struct weston_touch_grab *grab;
struct weston_touch_grab default_grab;
int grab_touch_id;
@@ -352,12 +354,12 @@ struct weston_touch {
};
struct weston_pointer *
-weston_pointer_create(void);
+weston_pointer_create(struct weston_seat *seat);
void
weston_pointer_destroy(struct weston_pointer *pointer);
void
weston_pointer_set_focus(struct weston_pointer *pointer,
- struct weston_surface *surface,
+ struct weston_view *view,
wl_fixed_t sx, wl_fixed_t sy);
void
weston_pointer_start_grab(struct weston_pointer *pointer,
@@ -367,6 +369,14 @@ weston_pointer_end_grab(struct weston_pointer *pointer);
void
weston_pointer_clamp(struct weston_pointer *pointer,
wl_fixed_t *fx, wl_fixed_t *fy);
+void
+weston_pointer_move(struct weston_pointer *pointer,
+ wl_fixed_t x, wl_fixed_t y);
+void
+weston_pointer_set_default_grab(struct weston_pointer *pointer,
+ const struct weston_pointer_grab_interface *interface);
+void
+weston_pointer_verify(struct weston_pointer *pointer);
struct weston_keyboard *
weston_keyboard_create(void);
@@ -387,7 +397,7 @@ void
weston_touch_destroy(struct weston_touch *touch);
void
weston_touch_set_focus(struct weston_seat *seat,
- struct weston_surface *surface);
+ struct weston_view *view);
void
weston_touch_start_grab(struct weston_touch *device,
struct weston_touch_grab *grab);
@@ -405,10 +415,15 @@ void
weston_seat_set_selection(struct weston_seat *seat,
struct weston_data_source *source, uint32_t serial);
int
-weston_seat_start_drag(struct weston_seat *seat,
+weston_pointer_start_drag(struct weston_pointer *pointer,
struct weston_data_source *source,
struct weston_surface *icon,
struct wl_client *client);
+int
+weston_touch_start_drag(struct weston_touch *touch,
+ struct weston_data_source *source,
+ struct weston_surface *icon,
+ struct wl_client *client);
struct weston_xkb_info {
struct xkb_keymap *keymap;
@@ -435,6 +450,7 @@ struct weston_keyboard {
struct wl_list resource_list;
struct wl_list focus_resource_list;
struct weston_surface *focus;
+ struct wl_listener focus_resource_listener;
uint32_t focus_serial;
struct wl_signal focus_signal;
@@ -455,6 +471,13 @@ struct weston_keyboard {
struct weston_keyboard_grab input_method_grab;
struct wl_resource *input_method_resource;
+
+ struct weston_xkb_info *xkb_info;
+ struct {
+ struct xkb_state *state;
+ enum weston_led leds;
+ } xkb_state;
+ struct xkb_keymap *pending_keymap;
};
struct weston_seat {
@@ -484,16 +507,9 @@ struct weston_seat {
struct wl_listener selection_data_source_listener;
struct wl_signal selection_signal;
- uint32_t num_tp;
-
void (*led_update)(struct weston_seat *ws, enum weston_led leds);
- struct weston_xkb_info *xkb_info;
- struct {
- struct xkb_state *state;
- enum weston_led leds;
- } xkb_state;
-
+ uint32_t slot_map;
struct input_method *input_method;
char *seat_name;
};
@@ -507,7 +523,7 @@ enum {
};
struct weston_layer {
- struct wl_list surface_list;
+ struct wl_list view_list;
struct wl_list link;
};
@@ -528,11 +544,9 @@ struct weston_renderer {
pixman_region32_t *output_damage);
void (*flush_damage)(struct weston_surface *surface);
void (*attach)(struct weston_surface *es, struct weston_buffer *buffer);
- int (*create_surface)(struct weston_surface *surface);
void (*surface_set_color)(struct weston_surface *surface,
float red, float green,
float blue, float alpha);
- void (*destroy_surface)(struct weston_surface *surface);
void (*destroy)(struct weston_compositor *ec);
};
@@ -578,9 +592,10 @@ struct weston_compositor {
struct wl_list output_list;
struct wl_list seat_list;
struct wl_list layer_list;
- struct wl_list surface_list;
+ struct wl_list view_list;
struct wl_list plane_list;
struct wl_list key_binding_list;
+ struct wl_list modifier_binding_list;
struct wl_list button_binding_list;
struct wl_list touch_binding_list;
struct wl_list axis_binding_list;
@@ -591,12 +606,12 @@ struct weston_compositor {
uint32_t idle_inhibit;
int idle_time; /* timeout, s */
+ const struct weston_pointer_grab_interface *default_pointer_grab;
+
/* Repaint state. */
struct weston_plane primary_plane;
uint32_t capabilities; /* combination of enum weston_capability */
- uint32_t focus;
-
struct weston_renderer *renderer;
pixman_format_code_t read_format;
@@ -638,6 +653,23 @@ struct weston_buffer_reference {
struct wl_listener destroy_listener;
};
+struct weston_buffer_viewport {
+ /* wl_surface.set_buffer_transform */
+ uint32_t transform;
+
+ /* wl_surface.set_scaling_factor */
+ int32_t scale;
+
+ /* bool for whether wl_viewport.set has been
+ * called yet (before this is called there is no
+ * cropping or scaling on the surface) */
+ int viewport_set; /* bool */
+
+ wl_fixed_t src_x, src_y;
+ wl_fixed_t src_width, src_height;
+ int32_t dst_width, dst_height;
+};
+
struct weston_region {
struct wl_resource *resource;
pixman_region32_t region;
@@ -684,58 +716,57 @@ struct weston_subsurface {
struct wl_list frame_callback_list;
/* wl_surface.set_buffer_transform */
- uint32_t buffer_transform;
-
/* wl_surface.set_buffer_scale */
- int32_t buffer_scale;
+ struct weston_buffer_viewport buffer_viewport;
} cached;
int synchronized;
+
+ /* Used for constructing the view tree */
+ struct wl_list unused_views;
};
-/* Using weston_surface transformations
+/* Using weston_view transformations
*
- * To add a transformation to a surface, create a struct weston_transform, and
- * add it to the list surface->geometry.transformation_list. Whenever you
- * change the list, anything under surface->geometry, or anything in the
+ * To add a transformation to a view, create a struct weston_transform, and
+ * add it to the list view->geometry.transformation_list. Whenever you
+ * change the list, anything under view->geometry, or anything in the
* weston_transforms linked into the list, you must call
- * weston_surface_geometry_dirty().
+ * weston_view_geometry_dirty().
*
* The order in the list defines the order of transformations. Let the list
* contain the transformation matrices M1, ..., Mn as head to tail. The
- * transformation is applied to surface-local coordinate vector p as
+ * transformation is applied to view-local coordinate vector p as
* P = Mn * ... * M2 * M1 * p
* to produce the global coordinate vector P. The total transform
* Mn * ... * M2 * M1
- * is cached in surface->transform.matrix, and the inverse of it in
- * surface->transform.inverse.
+ * is cached in view->transform.matrix, and the inverse of it in
+ * view->transform.inverse.
*
- * The list always contains surface->transform.position transformation, which
- * is the translation by surface->geometry.x and y.
+ * The list always contains view->transform.position transformation, which
+ * is the translation by view->geometry.x and y.
*
* If you want to apply a transformation in local coordinates, add your
* weston_transform to the head of the list. If you want to apply a
* transformation in global coordinates, add it to the tail of the list.
*
- * If surface->geometry.parent is set, the total transformation of this
- * surface will be the parent's total transformation and this transformation
+ * If view->geometry.parent is set, the total transformation of this
+ * view will be the parent's total transformation and this transformation
* combined:
* Mparent * Mn * ... * M2 * M1
*/
-struct weston_surface {
- struct wl_resource *resource;
+struct weston_view {
+ struct weston_surface *surface;
+ struct wl_list surface_link;
struct wl_signal destroy_signal;
- struct weston_compositor *compositor;
- pixman_region32_t clip;
- pixman_region32_t damage;
- pixman_region32_t opaque; /* part of geometry, see below */
- pixman_region32_t input;
+
struct wl_list link;
struct wl_list layer_link;
- float alpha; /* part of geometry, see below */
struct weston_plane *plane;
- int32_t ref_count;
+
+ pixman_region32_t clip;
+ float alpha; /* part of geometry, see below */
void *renderer_state;
@@ -745,20 +776,19 @@ struct weston_surface {
*/
struct {
float x, y; /* surface translation on display */
- int32_t width, height;
/* struct weston_transform */
struct wl_list transformation_list;
/* managed by weston_surface_set_transform_parent() */
- struct weston_surface *parent;
+ struct weston_view *parent;
struct wl_listener parent_destroy_listener;
struct wl_list child_list; /* geometry.parent_link */
struct wl_list parent_link;
} geometry;
/* State derived from geometry state, read-only.
- * This is updated by weston_surface_update_transform().
+ * This is updated by weston_view_update_transform().
*/
struct {
int dirty;
@@ -789,13 +819,51 @@ struct weston_surface {
*/
uint32_t output_mask;
+ struct wl_listener output_move_listener;
+ struct wl_listener output_destroy_listener;
+};
+
+struct weston_surface {
+ struct wl_resource *resource;
+ struct wl_signal destroy_signal;
+ struct weston_compositor *compositor;
+ pixman_region32_t damage;
+ pixman_region32_t opaque; /* part of geometry, see below */
+ pixman_region32_t input;
+ int32_t width, height;
+ int32_t ref_count;
+
+ /* Not for long-term storage. This exists for book-keeping while
+ * iterating over surfaces and views
+ */
+ int32_t touched;
+
+ void *renderer_state;
+
+ struct wl_list views;
+
+ /*
+ * Which output to vsync this surface to.
+ * Used to determine, whether to send or queue frame events.
+ * Must be NULL, if 'link' is not in weston_compositor::surface_list.
+ */
+ struct weston_output *output;
+
+ /*
+ * A more complete representation of all outputs this surface is
+ * displayed on.
+ */
+ uint32_t output_mask;
+
struct wl_list frame_callback_list;
struct weston_buffer_reference buffer_ref;
- uint32_t buffer_transform;
- int32_t buffer_scale;
+ struct weston_buffer_viewport buffer_viewport;
int keep_buffer; /* bool for backends to prevent early release */
+ /* wl_viewport resource for this surface */
+ struct wl_resource *viewport_resource;
+
/* All the pending state, that wl_surface.commit will apply. */
struct {
/* wl_surface.attach */
@@ -818,10 +886,9 @@ struct weston_surface {
struct wl_list frame_callback_list;
/* wl_surface.set_buffer_transform */
- uint32_t buffer_transform;
-
/* wl_surface.set_scaling_factor */
- int32_t buffer_scale;
+ /* wl_viewport.set */
+ struct weston_buffer_viewport buffer_viewport;
} pending;
/*
@@ -829,9 +896,15 @@ struct weston_surface {
* a new buffer has been set up for this surface. The integer params
* are the sx and sy paramerters supplied to surface::attach .
*/
- void (*configure)(struct weston_surface *es, int32_t sx, int32_t sy, int32_t width, int32_t height);
+ void (*configure)(struct weston_surface *es, int32_t sx, int32_t sy);
void *configure_private;
+ /* If non-NULL, this function will be called on surface->output::
+ * destroy, after the output is removed from the compositor's
+ * output list and the remaining outputs moved.
+ */
+ void (*output_destroyed)(struct weston_surface *surface);
+
/* Parent's list of its sub-surfaces, weston_subsurface:parent_link.
* Contains also the parent itself as a dummy weston_subsurface,
* if the list is not empty.
@@ -849,41 +922,36 @@ void
weston_version(int *major, int *minor, int *micro);
void
-weston_surface_update_transform(struct weston_surface *surface);
+weston_view_update_transform(struct weston_view *view);
void
-weston_surface_geometry_dirty(struct weston_surface *surface);
+weston_view_geometry_dirty(struct weston_view *view);
void
-weston_surface_to_global_fixed(struct weston_surface *surface,
- wl_fixed_t sx, wl_fixed_t sy,
- wl_fixed_t *x, wl_fixed_t *y);
+weston_view_to_global_fixed(struct weston_view *view,
+ wl_fixed_t sx, wl_fixed_t sy,
+ wl_fixed_t *x, wl_fixed_t *y);
void
-weston_surface_to_global_float(struct weston_surface *surface,
- float sx, float sy, float *x, float *y);
+weston_view_to_global_float(struct weston_view *view,
+ float sx, float sy, float *x, float *y);
void
-weston_surface_from_global_float(struct weston_surface *surface,
- float x, float y, float *sx, float *sy);
+weston_view_from_global_float(struct weston_view *view,
+ float x, float y, float *vx, float *vy);
void
-weston_surface_from_global(struct weston_surface *surface,
- int32_t x, int32_t y, int32_t *sx, int32_t *sy);
+weston_view_from_global(struct weston_view *view,
+ int32_t x, int32_t y, int32_t *vx, int32_t *vy);
void
-weston_surface_from_global_fixed(struct weston_surface *surface,
- wl_fixed_t x, wl_fixed_t y,
- wl_fixed_t *sx, wl_fixed_t *sy);
-int32_t
-weston_surface_buffer_width(struct weston_surface *surface);
-int32_t
-weston_surface_buffer_height(struct weston_surface *surface);
+weston_view_from_global_fixed(struct weston_view *view,
+ wl_fixed_t x, wl_fixed_t y,
+ wl_fixed_t *vx, wl_fixed_t *vy);
WL_EXPORT void
weston_surface_to_buffer_float(struct weston_surface *surface,
float x, float y, float *bx, float *by);
WL_EXPORT void
weston_surface_to_buffer(struct weston_surface *surface,
- int sx, int sy, int *bx, int *by);
-
+ int sx, int sy, int *bx, int *by);
pixman_box32_t
weston_surface_to_buffer_rect(struct weston_surface *surface,
pixman_box32_t rect);
@@ -967,10 +1035,10 @@ void
weston_compositor_offscreen(struct weston_compositor *compositor);
void
weston_compositor_sleep(struct weston_compositor *compositor);
-struct weston_surface *
-weston_compositor_pick_surface(struct weston_compositor *compositor,
- wl_fixed_t x, wl_fixed_t y,
- wl_fixed_t *sx, wl_fixed_t *sy);
+struct weston_view *
+weston_compositor_pick_view(struct weston_compositor *compositor,
+ wl_fixed_t x, wl_fixed_t y,
+ wl_fixed_t *sx, wl_fixed_t *sy);
struct weston_binding;
@@ -984,6 +1052,15 @@ weston_compositor_add_key_binding(struct weston_compositor *compositor,
weston_key_binding_handler_t binding,
void *data);
+typedef void (*weston_modifier_binding_handler_t)(struct weston_seat *seat,
+ enum weston_keyboard_modifier modifier,
+ void *data);
+struct weston_binding *
+weston_compositor_add_modifier_binding(struct weston_compositor *compositor,
+ enum weston_keyboard_modifier modifier,
+ weston_modifier_binding_handler_t binding,
+ void *data);
+
typedef void (*weston_button_binding_handler_t)(struct weston_seat *seat,
uint32_t time, uint32_t button,
void *data);
@@ -1028,6 +1105,12 @@ weston_compositor_run_key_binding(struct weston_compositor *compositor,
struct weston_seat *seat, uint32_t time,
uint32_t key,
enum wl_keyboard_key_state state);
+
+void
+weston_compositor_run_modifier_binding(struct weston_compositor *compositor,
+ struct weston_seat *seat,
+ enum weston_keyboard_modifier modifier,
+ enum wl_keyboard_key_state state);
void
weston_compositor_run_button_binding(struct weston_compositor *compositor,
struct weston_seat *seat, uint32_t time,
@@ -1047,6 +1130,10 @@ weston_compositor_run_debug_binding(struct weston_compositor *compositor,
uint32_t key,
enum wl_keyboard_key_state state);
+void
+weston_compositor_set_default_pointer_grab(struct weston_compositor *compositor,
+ const struct weston_pointer_grab_interface *interface);
+
int
weston_environment_get_fd(const char *env);
@@ -1056,24 +1143,33 @@ weston_compositor_top(struct weston_compositor *compositor);
struct weston_surface *
weston_surface_create(struct weston_compositor *compositor);
+struct weston_view *
+weston_view_create(struct weston_surface *surface);
+
void
-weston_surface_configure(struct weston_surface *surface,
- float x, float y, int width, int height);
+weston_view_destroy(struct weston_view *view);
void
-weston_surface_restack(struct weston_surface *surface, struct wl_list *below);
+weston_view_set_position(struct weston_view *view,
+ float x, float y);
void
-weston_surface_set_position(struct weston_surface *surface,
- float x, float y);
+weston_view_set_transform_parent(struct weston_view *view,
+ struct weston_view *parent);
+
+int
+weston_view_is_mapped(struct weston_view *view);
void
-weston_surface_set_transform_parent(struct weston_surface *surface,
- struct weston_surface *parent);
+weston_view_schedule_repaint(struct weston_view *view);
int
weston_surface_is_mapped(struct weston_surface *surface);
+WL_EXPORT void
+weston_surface_set_size(struct weston_surface *surface,
+ int32_t width, int32_t height);
+
void
weston_surface_schedule_repaint(struct weston_surface *surface);
@@ -1081,11 +1177,14 @@ void
weston_surface_damage(struct weston_surface *surface);
void
-weston_surface_damage_below(struct weston_surface *surface);
+weston_view_damage_below(struct weston_view *view);
void
-weston_surface_move_to_plane(struct weston_surface *surface,
- struct weston_plane *plane);
+weston_view_move_to_plane(struct weston_view *view,
+ struct weston_plane *plane);
+void
+weston_view_unmap(struct weston_view *view);
+
void
weston_surface_unmap(struct weston_surface *surface);
@@ -1108,12 +1207,11 @@ weston_compositor_init(struct weston_compositor *ec, struct wl_display *display,
void
weston_compositor_shutdown(struct weston_compositor *ec);
void
-weston_text_cursor_position_notify(struct weston_surface *surface,
- wl_fixed_t x, wl_fixed_t y);
-void
weston_output_init_zoom(struct weston_output *output);
void
-weston_output_update_zoom(struct weston_output *output, uint32_t type);
+weston_output_update_zoom(struct weston_output *output);
+void
+weston_output_activate_zoom(struct weston_output *output);
void
weston_output_update_matrix(struct weston_output *output);
void
@@ -1124,8 +1222,8 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,
void
weston_output_destroy(struct weston_output *output);
void
-weston_output_transform_coordinate(struct weston_output *x11_output,
- int device_x, int device_y,
+weston_output_transform_coordinate(struct weston_output *output,
+ wl_fixed_t device_x, wl_fixed_t device_y,
wl_fixed_t *x, wl_fixed_t *y);
void
@@ -1145,6 +1243,8 @@ void
weston_seat_release_touch(struct weston_seat *seat);
void
weston_seat_repick(struct weston_seat *seat);
+void
+weston_seat_update_keymap(struct weston_seat *seat, struct xkb_keymap *keymap);
void
weston_seat_release(struct weston_seat *seat);
@@ -1195,9 +1295,6 @@ screenshooter_create(struct weston_compositor *ec);
struct clipboard *
clipboard_create(struct weston_seat *seat);
-void
-text_cursor_position_notifier_create(struct weston_compositor *ec);
-
int
text_backend_init(struct weston_compositor *ec);
@@ -1220,23 +1317,37 @@ weston_client_launch(struct weston_compositor *compositor,
void
weston_watch_process(struct weston_process *process);
-struct weston_surface_animation;
-typedef void (*weston_surface_animation_done_func_t)(struct weston_surface_animation *animation, void *data);
+struct weston_view_animation;
+typedef void (*weston_view_animation_done_func_t)(struct weston_view_animation *animation, void *data);
-struct weston_surface_animation *
-weston_zoom_run(struct weston_surface *surface, float start, float stop,
- weston_surface_animation_done_func_t done, void *data);
+void
+weston_view_animation_destroy(struct weston_view_animation *animation);
+
+struct weston_view_animation *
+weston_zoom_run(struct weston_view *view, float start, float stop,
+ weston_view_animation_done_func_t done, void *data);
-struct weston_surface_animation *
-weston_fade_run(struct weston_surface *surface,
+struct weston_view_animation *
+weston_fade_run(struct weston_view *view,
float start, float end, float k,
- weston_surface_animation_done_func_t done, void *data);
+ weston_view_animation_done_func_t done, void *data);
+
+struct weston_view_animation *
+weston_move_scale_run(struct weston_view *view, int dx, int dy,
+ float start, float end, int reverse,
+ weston_view_animation_done_func_t done, void *data);
+
void
-weston_fade_update(struct weston_surface_animation *fade, float target);
+weston_fade_update(struct weston_view_animation *fade, float target);
-struct weston_surface_animation *
-weston_slide_run(struct weston_surface *surface, float start, float stop,
- weston_surface_animation_done_func_t done, void *data);
+struct weston_view_animation *
+weston_stable_fade_run(struct weston_view *front_view, float start,
+ struct weston_view *back_view, float end,
+ weston_view_animation_done_func_t done, void *data);
+
+struct weston_view_animation *
+weston_slide_run(struct weston_view *view, float start, float stop,
+ weston_view_animation_done_func_t done, void *data);
void
weston_surface_set_color(struct weston_surface *surface,
@@ -1270,6 +1381,14 @@ weston_transformed_rect(int width, int height,
enum wl_output_transform transform,
int32_t scale,
pixman_box32_t rect);
+void
+weston_transformed_region(int width, int height,
+ enum wl_output_transform transform,
+ int32_t scale,
+ pixman_region32_t *src, pixman_region32_t *dest);
+
+void *
+weston_load_module(const char *name, const char *entrypoint);
#ifdef __cplusplus
}
diff --git a/src/data-device.c b/src/data-device.c
index c3dc0bda..483e22e9 100644
--- a/src/data-device.c
+++ b/src/data-device.c
@@ -26,6 +26,7 @@
#include <string.h>
#include <unistd.h>
#include <stdio.h>
+#include <assert.h>
#include "compositor.h"
@@ -33,15 +34,24 @@ struct weston_drag {
struct wl_client *client;
struct weston_data_source *data_source;
struct wl_listener data_source_listener;
- struct weston_surface *focus;
+ struct weston_view *focus;
struct wl_resource *focus_resource;
struct wl_listener focus_listener;
- struct weston_pointer_grab grab;
- struct weston_surface *icon;
+ struct weston_view *icon;
struct wl_listener icon_destroy_listener;
int32_t dx, dy;
};
+struct weston_pointer_drag {
+ struct weston_drag base;
+ struct weston_pointer_grab grab;
+};
+
+struct weston_touch_drag {
+ struct weston_drag base;
+ struct weston_touch_grab grab;
+};
+
static void
empty_region(pixman_region32_t *region)
{
@@ -171,30 +181,67 @@ static struct wl_data_source_interface data_source_interface = {
};
static void
-drag_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy, int32_t width, int32_t height)
+drag_surface_configure(struct weston_drag *drag,
+ struct weston_pointer *pointer,
+ struct weston_touch *touch,
+ struct weston_surface *es,
+ int32_t sx, int32_t sy)
{
- struct weston_drag *drag = es->configure_private;
- struct weston_pointer *pointer = drag->grab.pointer;
struct wl_list *list;
float fx, fy;
+ assert((pointer != NULL && touch == NULL) ||
+ (pointer == NULL && touch != NULL));
+
if (!weston_surface_is_mapped(es) && es->buffer_ref.buffer) {
- if (pointer->sprite && weston_surface_is_mapped(pointer->sprite))
+ if (pointer && pointer->sprite &&
+ weston_view_is_mapped(pointer->sprite))
list = &pointer->sprite->layer_link;
else
- list = &es->compositor->cursor_layer.surface_list;
+ list = &es->compositor->cursor_layer.view_list;
- wl_list_insert(list, &es->layer_link);
- weston_surface_update_transform(es);
+ wl_list_remove(&drag->icon->layer_link);
+ wl_list_insert(list, &drag->icon->layer_link);
+ weston_view_update_transform(drag->icon);
empty_region(&es->pending.input);
}
drag->dx += sx;
drag->dy += sy;
- fx = wl_fixed_to_double(pointer->x) + drag->dx;
- fy = wl_fixed_to_double(pointer->y) + drag->dy;
- weston_surface_configure(es, fx, fy, width, height);
+ /* init to 0 for avoiding a compile warning */
+ fx = fy = 0;
+ if (pointer) {
+ fx = wl_fixed_to_double(pointer->x) + drag->dx;
+ fy = wl_fixed_to_double(pointer->y) + drag->dy;
+ } else if (touch) {
+ fx = wl_fixed_to_double(touch->grab_x) + drag->dx;
+ fy = wl_fixed_to_double(touch->grab_y) + drag->dy;
+ }
+ weston_view_set_position(drag->icon, fx, fy);
+}
+
+static void
+pointer_drag_surface_configure(struct weston_surface *es,
+ int32_t sx, int32_t sy)
+{
+ struct weston_pointer_drag *drag = es->configure_private;
+ struct weston_pointer *pointer = drag->grab.pointer;
+
+ assert(es->configure == pointer_drag_surface_configure);
+
+ drag_surface_configure(&drag->base, pointer, NULL, es, sx, sy);
+}
+
+static void
+touch_drag_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
+{
+ struct weston_touch_drag *drag = es->configure_private;
+ struct weston_touch *touch = drag->grab.touch;
+
+ assert(es->configure == touch_drag_surface_configure);
+
+ drag_surface_configure(&drag->base, NULL, touch, es, sx, sy);
}
static void
@@ -207,14 +254,20 @@ destroy_drag_focus(struct wl_listener *listener, void *data)
}
static void
-weston_drag_set_focus(struct weston_drag *drag, struct weston_surface *surface,
- wl_fixed_t sx, wl_fixed_t sy)
+weston_drag_set_focus(struct weston_drag *drag,
+ struct weston_seat *seat,
+ struct weston_view *view,
+ wl_fixed_t sx, wl_fixed_t sy)
{
- struct weston_pointer *pointer = drag->grab.pointer;
struct wl_resource *resource, *offer = NULL;
- struct wl_display *display = pointer->seat->compositor->wl_display;
+ struct wl_display *display = seat->compositor->wl_display;
uint32_t serial;
+ if (drag->focus && view && drag->focus->surface == view->surface) {
+ drag->focus = view;
+ return;
+ }
+
if (drag->focus_resource) {
wl_data_device_send_leave(drag->focus_resource);
wl_list_remove(&drag->focus_listener.link);
@@ -222,15 +275,15 @@ weston_drag_set_focus(struct weston_drag *drag, struct weston_surface *surface,
drag->focus = NULL;
}
- if (!surface)
+ if (!view || !view->surface->resource)
return;
if (!drag->data_source &&
- wl_resource_get_client(surface->resource) != drag->client)
+ wl_resource_get_client(view->surface->resource) != drag->client)
return;
- resource = wl_resource_find_for_client(&pointer->seat->drag_resource_list,
- wl_resource_get_client(surface->resource));
+ resource = wl_resource_find_for_client(&seat->drag_resource_list,
+ wl_resource_get_client(view->surface->resource));
if (!resource)
return;
@@ -243,10 +296,10 @@ weston_drag_set_focus(struct weston_drag *drag, struct weston_surface *surface,
return;
}
- wl_data_device_send_enter(resource, serial, surface->resource,
+ wl_data_device_send_enter(resource, serial, view->surface->resource,
sx, sy, offer);
- drag->focus = surface;
+ drag->focus = view;
drag->focus_listener.notify = destroy_drag_focus;
wl_resource_add_destroy_listener(resource, &drag->focus_listener);
drag->focus_resource = resource;
@@ -255,60 +308,71 @@ weston_drag_set_focus(struct weston_drag *drag, struct weston_surface *surface,
static void
drag_grab_focus(struct weston_pointer_grab *grab)
{
- struct weston_drag *drag =
- container_of(grab, struct weston_drag, grab);
+ struct weston_pointer_drag *drag =
+ container_of(grab, struct weston_pointer_drag, grab);
struct weston_pointer *pointer = grab->pointer;
- struct weston_surface *surface;
+ struct weston_view *view;
wl_fixed_t sx, sy;
- surface = weston_compositor_pick_surface(pointer->seat->compositor,
- pointer->x, pointer->y,
- &sx, &sy);
- if (drag->focus != surface)
- weston_drag_set_focus(drag, surface, sx, sy);
+ view = weston_compositor_pick_view(pointer->seat->compositor,
+ pointer->x, pointer->y,
+ &sx, &sy);
+ if (drag->base.focus != view)
+ weston_drag_set_focus(&drag->base, pointer->seat, view, sx, sy);
}
static void
-drag_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
+drag_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
+ wl_fixed_t x, wl_fixed_t y)
{
- struct weston_drag *drag =
- container_of(grab, struct weston_drag, grab);
+ struct weston_pointer_drag *drag =
+ container_of(grab, struct weston_pointer_drag, grab);
struct weston_pointer *pointer = drag->grab.pointer;
float fx, fy;
wl_fixed_t sx, sy;
- if (drag->icon) {
- fx = wl_fixed_to_double(pointer->x) + drag->dx;
- fy = wl_fixed_to_double(pointer->y) + drag->dy;
- weston_surface_set_position(drag->icon, fx, fy);
- weston_surface_schedule_repaint(drag->icon);
+ weston_pointer_move(pointer, x, y);
+
+ if (drag->base.icon) {
+ fx = wl_fixed_to_double(pointer->x) + drag->base.dx;
+ fy = wl_fixed_to_double(pointer->y) + drag->base.dy;
+ weston_view_set_position(drag->base.icon, fx, fy);
+ weston_view_schedule_repaint(drag->base.icon);
}
- if (drag->focus_resource) {
- weston_surface_from_global_fixed(drag->focus,
- pointer->x, pointer->y,
- &sx, &sy);
+ if (drag->base.focus_resource) {
+ weston_view_from_global_fixed(drag->base.focus,
+ pointer->x, pointer->y,
+ &sx, &sy);
- wl_data_device_send_motion(drag->focus_resource, time, sx, sy);
+ wl_data_device_send_motion(drag->base.focus_resource, time, sx, sy);
}
}
static void
-data_device_end_drag_grab(struct weston_drag *drag)
+data_device_end_drag_grab(struct weston_drag *drag,
+ struct weston_seat *seat)
{
if (drag->icon) {
- if (weston_surface_is_mapped(drag->icon))
- weston_surface_unmap(drag->icon);
+ if (weston_view_is_mapped(drag->icon))
+ weston_view_unmap(drag->icon);
- drag->icon->configure = NULL;
- empty_region(&drag->icon->pending.input);
+ drag->icon->surface->configure = NULL;
+ empty_region(&drag->icon->surface->pending.input);
wl_list_remove(&drag->icon_destroy_listener.link);
+ weston_view_destroy(drag->icon);
}
- weston_drag_set_focus(drag, NULL, 0, 0);
+ weston_drag_set_focus(drag, seat, NULL, 0, 0);
+}
- weston_pointer_end_grab(drag->grab.pointer);
+static void
+data_device_end_pointer_drag_grab(struct weston_pointer_drag *drag)
+{
+ struct weston_pointer *pointer = drag->grab.pointer;
+ data_device_end_drag_grab(&drag->base, pointer->seat);
+ weston_pointer_end_grab(pointer);
free(drag);
}
@@ -316,37 +380,37 @@ static void
drag_grab_button(struct weston_pointer_grab *grab,
uint32_t time, uint32_t button, uint32_t state_w)
{
- struct weston_drag *drag =
- container_of(grab, struct weston_drag, grab);
+ struct weston_pointer_drag *drag =
+ container_of(grab, struct weston_pointer_drag, grab);
struct weston_pointer *pointer = drag->grab.pointer;
enum wl_pointer_button_state state = state_w;
- if (drag->focus_resource &&
+ if (drag->base.focus_resource &&
pointer->grab_button == button &&
state == WL_POINTER_BUTTON_STATE_RELEASED)
- wl_data_device_send_drop(drag->focus_resource);
+ wl_data_device_send_drop(drag->base.focus_resource);
if (pointer->button_count == 0 &&
state == WL_POINTER_BUTTON_STATE_RELEASED) {
- if (drag->data_source)
- wl_list_remove(&drag->data_source_listener.link);
- data_device_end_drag_grab(drag);
+ if (drag->base.data_source)
+ wl_list_remove(&drag->base.data_source_listener.link);
+ data_device_end_pointer_drag_grab(drag);
}
}
static void
drag_grab_cancel(struct weston_pointer_grab *grab)
{
- struct weston_drag *drag =
- container_of(grab, struct weston_drag, grab);
+ struct weston_pointer_drag *drag =
+ container_of(grab, struct weston_pointer_drag, grab);
- if (drag->data_source)
- wl_list_remove(&drag->data_source_listener.link);
+ if (drag->base.data_source)
+ wl_list_remove(&drag->base.data_source_listener.link);
- data_device_end_drag_grab(drag);
+ data_device_end_pointer_drag_grab(drag);
}
-static const struct weston_pointer_grab_interface drag_grab_interface = {
+static const struct weston_pointer_grab_interface pointer_drag_grab_interface = {
drag_grab_focus,
drag_grab_motion,
drag_grab_button,
@@ -354,12 +418,109 @@ static const struct weston_pointer_grab_interface drag_grab_interface = {
};
static void
-destroy_data_device_source(struct wl_listener *listener, void *data)
+drag_grab_touch_down(struct weston_touch_grab *grab, uint32_t time,
+ int touch_id, wl_fixed_t sx, wl_fixed_t sy)
{
- struct weston_drag *drag = container_of(listener, struct weston_drag,
- data_source_listener);
+}
+
+static void
+data_device_end_touch_drag_grab(struct weston_touch_drag *drag)
+{
+ struct weston_touch *touch = drag->grab.touch;
+
+ data_device_end_drag_grab(&drag->base, touch->seat);
+ weston_touch_end_grab(touch);
+ free(drag);
+}
+
+static void
+drag_grab_touch_up(struct weston_touch_grab *grab,
+ uint32_t time, int touch_id)
+{
+ struct weston_touch_drag *touch_drag =
+ container_of(grab, struct weston_touch_drag, grab);
+ struct weston_touch *touch = grab->touch;
+
+ if (touch_id != touch->grab_touch_id)
+ return;
+
+ if (touch_drag->base.focus_resource)
+ wl_data_device_send_drop(touch_drag->base.focus_resource);
+ if (touch_drag->base.data_source)
+ wl_list_remove(&touch_drag->base.data_source_listener.link);
+ data_device_end_touch_drag_grab(touch_drag);
+}
+
+static void
+drag_grab_touch_focus(struct weston_touch_drag *drag)
+{
+ struct weston_touch *touch = drag->grab.touch;
+ struct weston_view *view;
+ wl_fixed_t view_x, view_y;
- data_device_end_drag_grab(drag);
+ view = weston_compositor_pick_view(touch->seat->compositor,
+ touch->grab_x, touch->grab_y,
+ &view_x, &view_y);
+ if (drag->base.focus != view)
+ weston_drag_set_focus(&drag->base, touch->seat,
+ view, view_x, view_y);
+}
+
+static void
+drag_grab_touch_motion(struct weston_touch_grab *grab, uint32_t time,
+ int touch_id, wl_fixed_t sx, wl_fixed_t sy)
+{
+ struct weston_touch_drag *touch_drag =
+ container_of(grab, struct weston_touch_drag, grab);
+ struct weston_touch *touch = grab->touch;
+ wl_fixed_t view_x, view_y;
+ float fx, fy;
+
+ if (touch_id != touch->grab_touch_id)
+ return;
+
+ drag_grab_touch_focus(touch_drag);
+ if (touch_drag->base.icon) {
+ fx = wl_fixed_to_double(touch->grab_x) + touch_drag->base.dx;
+ fy = wl_fixed_to_double(touch->grab_y) + touch_drag->base.dy;
+ weston_view_set_position(touch_drag->base.icon, fx, fy);
+ weston_view_schedule_repaint(touch_drag->base.icon);
+ }
+
+ if (touch_drag->base.focus_resource) {
+ weston_view_from_global_fixed(touch_drag->base.focus,
+ touch->grab_x, touch->grab_y,
+ &view_x, &view_y);
+ wl_data_device_send_motion(touch_drag->base.focus_resource, time,
+ view_x, view_y);
+ }
+}
+
+static void
+drag_grab_touch_cancel(struct weston_touch_grab *grab)
+{
+ struct weston_touch_drag *touch_drag =
+ container_of(grab, struct weston_touch_drag, grab);
+
+ if (touch_drag->base.data_source)
+ wl_list_remove(&touch_drag->base.data_source_listener.link);
+ data_device_end_touch_drag_grab(touch_drag);
+}
+
+static const struct weston_touch_grab_interface touch_drag_grab_interface = {
+ drag_grab_touch_down,
+ drag_grab_touch_up,
+ drag_grab_touch_motion,
+ drag_grab_touch_cancel
+};
+
+static void
+destroy_pointer_data_device_source(struct wl_listener *listener, void *data)
+{
+ struct weston_pointer_drag *drag = container_of(listener,
+ struct weston_pointer_drag, base.data_source_listener);
+
+ data_device_end_pointer_drag_grab(drag);
}
static void
@@ -372,40 +533,102 @@ handle_drag_icon_destroy(struct wl_listener *listener, void *data)
}
WL_EXPORT int
-weston_seat_start_drag(struct weston_seat *seat,
+weston_pointer_start_drag(struct weston_pointer *pointer,
struct weston_data_source *source,
struct weston_surface *icon,
struct wl_client *client)
{
- struct weston_drag *drag;
+ struct weston_pointer_drag *drag;
drag = zalloc(sizeof *drag);
if (drag == NULL)
return -1;
- drag->grab.interface = &drag_grab_interface;
- drag->client = client;
- drag->data_source = source;
- drag->icon = icon;
+ drag->grab.interface = &pointer_drag_grab_interface;
+ drag->base.client = client;
+ drag->base.data_source = source;
+
+ if (icon) {
+ drag->base.icon = weston_view_create(icon);
+ if (drag->base.icon == NULL) {
+ free(drag);
+ return -1;
+ }
+
+ drag->base.icon_destroy_listener.notify = handle_drag_icon_destroy;
+ wl_signal_add(&icon->destroy_signal,
+ &drag->base.icon_destroy_listener);
+
+ icon->configure = pointer_drag_surface_configure;
+ icon->configure_private = drag;
+ } else {
+ drag->base.icon = NULL;
+ }
if (source) {
- drag->data_source_listener.notify = destroy_data_device_source;
+ drag->base.data_source_listener.notify = destroy_pointer_data_device_source;
wl_signal_add(&source->destroy_signal,
- &drag->data_source_listener);
+ &drag->base.data_source_listener);
}
+ weston_pointer_set_focus(pointer, NULL,
+ wl_fixed_from_int(0), wl_fixed_from_int(0));
+ weston_pointer_start_grab(pointer, &drag->grab);
+
+ return 0;
+}
+
+static void
+destroy_touch_data_device_source(struct wl_listener *listener, void *data)
+{
+ struct weston_touch_drag *drag = container_of(listener,
+ struct weston_touch_drag, base.data_source_listener);
+
+ data_device_end_touch_drag_grab(drag);
+}
+
+WL_EXPORT int
+weston_touch_start_drag(struct weston_touch *touch,
+ struct weston_data_source *source,
+ struct weston_surface *icon,
+ struct wl_client *client)
+{
+ struct weston_touch_drag *drag;
+
+ drag = zalloc(sizeof *drag);
+ if (drag == NULL)
+ return -1;
+
+ drag->grab.interface = &touch_drag_grab_interface;
+ drag->base.client = client;
+ drag->base.data_source = source;
+
if (icon) {
- drag->icon_destroy_listener.notify = handle_drag_icon_destroy;
+ drag->base.icon = weston_view_create(icon);
+ if (drag->base.icon == NULL) {
+ free(drag);
+ return -1;
+ }
+
+ drag->base.icon_destroy_listener.notify = handle_drag_icon_destroy;
wl_signal_add(&icon->destroy_signal,
- &drag->icon_destroy_listener);
+ &drag->base.icon_destroy_listener);
- icon->configure = drag_surface_configure;
+ icon->configure = touch_drag_surface_configure;
icon->configure_private = drag;
+ } else {
+ drag->base.icon = NULL;
}
- weston_pointer_set_focus(seat->pointer, NULL,
- wl_fixed_from_int(0), wl_fixed_from_int(0));
- weston_pointer_start_grab(seat->pointer, &drag->grab);
+ if (source) {
+ drag->base.data_source_listener.notify = destroy_touch_data_device_source;
+ wl_signal_add(&source->destroy_signal,
+ &drag->base.data_source_listener);
+ }
+
+ weston_touch_start_grab(touch, &drag->grab);
+
+ drag_grab_touch_focus(drag);
return 0;
}
@@ -419,10 +642,15 @@ data_device_start_drag(struct wl_client *client, struct wl_resource *resource,
struct weston_seat *seat = wl_resource_get_user_data(resource);
struct weston_data_source *source = NULL;
struct weston_surface *icon = NULL;
+ int32_t ret = 0;
- if (seat->pointer->button_count == 0 ||
+ if ((seat->pointer->button_count == 0 ||
seat->pointer->grab_serial != serial ||
- seat->pointer->focus != wl_resource_get_user_data(origin_resource))
+ !seat->pointer->focus ||
+ seat->pointer->focus->surface != wl_resource_get_user_data(origin_resource)) &&
+ (seat->touch->grab_serial != serial ||
+ !seat->touch->focus ||
+ seat->touch->focus->surface != wl_resource_get_user_data(origin_resource)))
return;
/* FIXME: Check that the data source type array isn't empty. */
@@ -438,7 +666,17 @@ data_device_start_drag(struct wl_client *client, struct wl_resource *resource,
return;
}
- if (weston_seat_start_drag(seat, source, icon, client) < 0)
+ if (seat->pointer->button_count == 1 &&
+ seat->pointer->grab_serial == serial &&
+ seat->pointer->focus &&
+ seat->pointer->focus->surface == wl_resource_get_user_data(origin_resource))
+ ret = weston_pointer_start_drag(seat->pointer, source, icon, client);
+ else if (seat->touch->grab_serial != serial ||
+ seat->touch->focus ||
+ seat->touch->focus->surface != wl_resource_get_user_data(origin_resource))
+ ret = weston_touch_start_drag(seat->touch, source, icon, client);
+
+ if (ret < 0)
wl_resource_post_no_memory(resource);
}
diff --git a/src/dbus.c b/src/dbus.c
new file mode 100644
index 00000000..a1abbd54
--- /dev/null
+++ b/src/dbus.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright © 2013 David Herrmann <dh.herrmann@gmail.com>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * DBus Helpers
+ * This file contains the dbus mainloop integration and several helpers to
+ * make lowlevel libdbus access easier.
+ */
+
+#include "config.h"
+
+#include <dbus/dbus.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+#include <wayland-server.h>
+
+#include "compositor.h"
+#include "dbus.h"
+
+/*
+ * DBus Mainloop Integration
+ * weston_dbus_bind() and weston_dbus_unbind() allow to bind an existing
+ * DBusConnection to an existing wl_event_loop object. All dbus dispatching
+ * is then nicely integrated into the wayland event loop.
+ * Note that this only provides basic watch and timeout dispatching. No
+ * remote thread wakeup, signal handling or other dbus insanity is supported.
+ * This is fine as long as you don't use any of the deprecated libdbus
+ * interfaces (like waking up remote threads..). There is really no rational
+ * reason to support these.
+ */
+
+static int weston_dbus_dispatch_watch(int fd, uint32_t mask, void *data)
+{
+ DBusWatch *watch = data;
+ uint32_t flags = 0;
+
+ if (dbus_watch_get_enabled(watch)) {
+ if (mask & WL_EVENT_READABLE)
+ flags |= DBUS_WATCH_READABLE;
+ if (mask & WL_EVENT_WRITABLE)
+ flags |= DBUS_WATCH_WRITABLE;
+ if (mask & WL_EVENT_HANGUP)
+ flags |= DBUS_WATCH_HANGUP;
+ if (mask & WL_EVENT_ERROR)
+ flags |= DBUS_WATCH_ERROR;
+
+ dbus_watch_handle(watch, flags);
+ }
+
+ return 0;
+}
+
+static dbus_bool_t weston_dbus_add_watch(DBusWatch *watch, void *data)
+{
+ struct wl_event_loop *loop = data;
+ struct wl_event_source *s;
+ int fd;
+ uint32_t mask = 0, flags;
+
+ if (dbus_watch_get_enabled(watch)) {
+ flags = dbus_watch_get_flags(watch);
+ if (flags & DBUS_WATCH_READABLE)
+ mask |= WL_EVENT_READABLE;
+ if (flags & DBUS_WATCH_WRITABLE)
+ mask |= WL_EVENT_WRITABLE;
+ }
+
+ fd = dbus_watch_get_unix_fd(watch);
+ s = wl_event_loop_add_fd(loop, fd, mask, weston_dbus_dispatch_watch,
+ watch);
+ if (!s)
+ return FALSE;
+
+ dbus_watch_set_data(watch, s, NULL);
+ return TRUE;
+}
+
+static void weston_dbus_remove_watch(DBusWatch *watch, void *data)
+{
+ struct wl_event_source *s;
+
+ s = dbus_watch_get_data(watch);
+ if (!s)
+ return;
+
+ wl_event_source_remove(s);
+}
+
+static void weston_dbus_toggle_watch(DBusWatch *watch, void *data)
+{
+ struct wl_event_source *s;
+ uint32_t mask = 0, flags;
+
+ s = dbus_watch_get_data(watch);
+ if (!s)
+ return;
+
+ if (dbus_watch_get_enabled(watch)) {
+ flags = dbus_watch_get_flags(watch);
+ if (flags & DBUS_WATCH_READABLE)
+ mask |= WL_EVENT_READABLE;
+ if (flags & DBUS_WATCH_WRITABLE)
+ mask |= WL_EVENT_WRITABLE;
+ }
+
+ wl_event_source_fd_update(s, mask);
+}
+
+static int weston_dbus_dispatch_timeout(void *data)
+{
+ DBusTimeout *timeout = data;
+
+ if (dbus_timeout_get_enabled(timeout))
+ dbus_timeout_handle(timeout);
+
+ return 0;
+}
+
+static int weston_dbus_adjust_timeout(DBusTimeout *timeout,
+ struct wl_event_source *s)
+{
+ int64_t t = 0;
+
+ if (dbus_timeout_get_enabled(timeout))
+ t = dbus_timeout_get_interval(timeout);
+
+ return wl_event_source_timer_update(s, t);
+}
+
+static dbus_bool_t weston_dbus_add_timeout(DBusTimeout *timeout, void *data)
+{
+ struct wl_event_loop *loop = data;
+ struct wl_event_source *s;
+ int r;
+
+ s = wl_event_loop_add_timer(loop, weston_dbus_dispatch_timeout,
+ timeout);
+ if (!s)
+ return FALSE;
+
+ r = weston_dbus_adjust_timeout(timeout, s);
+ if (r < 0) {
+ wl_event_source_remove(s);
+ return FALSE;
+ }
+
+ dbus_timeout_set_data(timeout, s, NULL);
+ return TRUE;
+}
+
+static void weston_dbus_remove_timeout(DBusTimeout *timeout, void *data)
+{
+ struct wl_event_source *s;
+
+ s = dbus_timeout_get_data(timeout);
+ if (!s)
+ return;
+
+ wl_event_source_remove(s);
+}
+
+static void weston_dbus_toggle_timeout(DBusTimeout *timeout, void *data)
+{
+ struct wl_event_source *s;
+
+ s = dbus_timeout_get_data(timeout);
+ if (!s)
+ return;
+
+ weston_dbus_adjust_timeout(timeout, s);
+}
+
+static int weston_dbus_dispatch(int fd, uint32_t mask, void *data)
+{
+ DBusConnection *c = data;
+ int r;
+
+ do {
+ r = dbus_connection_dispatch(c);
+ if (r == DBUS_DISPATCH_COMPLETE)
+ r = 0;
+ else if (r == DBUS_DISPATCH_DATA_REMAINS)
+ r = -EAGAIN;
+ else if (r == DBUS_DISPATCH_NEED_MEMORY)
+ r = -ENOMEM;
+ else
+ r = -EIO;
+ } while (r == -EAGAIN);
+
+ if (r)
+ weston_log("cannot dispatch dbus events: %d\n", r);
+
+ return 0;
+}
+
+static int weston_dbus_bind(struct wl_event_loop *loop, DBusConnection *c,
+ struct wl_event_source **ctx_out)
+{
+ bool b;
+ int r, fd;
+
+ /* Idle events cannot reschedule themselves, therefore we use a dummy
+ * event-fd and mark it for post-dispatch. Hence, the dbus
+ * dispatcher is called after every dispatch-round.
+ * This is required as dbus doesn't allow dispatching events from
+ * within its own event sources. */
+ fd = eventfd(0, EFD_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ *ctx_out = wl_event_loop_add_fd(loop, fd, 0, weston_dbus_dispatch, c);
+ close(fd);
+
+ if (!*ctx_out)
+ return -ENOMEM;
+
+ wl_event_source_check(*ctx_out);
+
+ b = dbus_connection_set_watch_functions(c,
+ weston_dbus_add_watch,
+ weston_dbus_remove_watch,
+ weston_dbus_toggle_watch,
+ loop,
+ NULL);
+ if (!b) {
+ r = -ENOMEM;
+ goto error;
+ }
+
+ b = dbus_connection_set_timeout_functions(c,
+ weston_dbus_add_timeout,
+ weston_dbus_remove_timeout,
+ weston_dbus_toggle_timeout,
+ loop,
+ NULL);
+ if (!b) {
+ r = -ENOMEM;
+ goto error;
+ }
+
+ dbus_connection_ref(c);
+ return 0;
+
+error:
+ dbus_connection_set_timeout_functions(c, NULL, NULL, NULL,
+ NULL, NULL);
+ dbus_connection_set_watch_functions(c, NULL, NULL, NULL,
+ NULL, NULL);
+ wl_event_source_remove(*ctx_out);
+ *ctx_out = NULL;
+ return r;
+}
+
+static void weston_dbus_unbind(DBusConnection *c, struct wl_event_source *ctx)
+{
+ dbus_connection_set_timeout_functions(c, NULL, NULL, NULL,
+ NULL, NULL);
+ dbus_connection_set_watch_functions(c, NULL, NULL, NULL,
+ NULL, NULL);
+ dbus_connection_unref(c);
+ wl_event_source_remove(ctx);
+}
+
+/*
+ * Convenience Helpers
+ * Several convenience helpers are provided to make using dbus in weston
+ * easier. We don't use any of the gdbus or qdbus helpers as they pull in
+ * huge dependencies and actually are quite awful to use. Instead, we only
+ * use the basic low-level libdbus library.
+ */
+
+int weston_dbus_open(struct wl_event_loop *loop, DBusBusType bus,
+ DBusConnection **out, struct wl_event_source **ctx_out)
+{
+ DBusConnection *c;
+ int r;
+
+ /* Ihhh, global state.. stupid dbus. */
+ dbus_connection_set_change_sigpipe(FALSE);
+
+ /* This is actually synchronous. It blocks for some authentication and
+ * setup. We just trust the dbus-server here and accept this blocking
+ * call. There is no real reason to complicate things further and make
+ * this asynchronous/non-blocking. A context should be created during
+ * thead/process/app setup, so blocking calls should be fine. */
+ c = dbus_bus_get_private(bus, NULL);
+ if (!c)
+ return -EIO;
+
+ dbus_connection_set_exit_on_disconnect(c, FALSE);
+
+ r = weston_dbus_bind(loop, c, ctx_out);
+ if (r < 0)
+ goto error;
+
+ *out = c;
+ return r;
+
+error:
+ dbus_connection_close(c);
+ dbus_connection_unref(c);
+ return r;
+}
+
+void weston_dbus_close(DBusConnection *c, struct wl_event_source *ctx)
+{
+ weston_dbus_unbind(c, ctx);
+ dbus_connection_close(c);
+ dbus_connection_unref(c);
+}
+
+int weston_dbus_add_match(DBusConnection *c, const char *format, ...)
+{
+ DBusError err;
+ int r;
+ va_list list;
+ char *str;
+
+ va_start(list, format);
+ r = vasprintf(&str, format, list);
+ va_end(list);
+
+ if (r < 0)
+ return -ENOMEM;
+
+ dbus_error_init(&err);
+ dbus_bus_add_match(c, str, &err);
+ free(str);
+ if (dbus_error_is_set(&err)) {
+ dbus_error_free(&err);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int weston_dbus_add_match_signal(DBusConnection *c, const char *sender,
+ const char *iface, const char *member,
+ const char *path)
+{
+ return weston_dbus_add_match(c,
+ "type='signal',"
+ "sender='%s',"
+ "interface='%s',"
+ "member='%s',"
+ "path='%s'",
+ sender, iface, member, path);
+}
+
+void weston_dbus_remove_match(DBusConnection *c, const char *format, ...)
+{
+ int r;
+ va_list list;
+ char *str;
+
+ va_start(list, format);
+ r = vasprintf(&str, format, list);
+ va_end(list);
+
+ if (r < 0)
+ return;
+
+ dbus_bus_remove_match(c, str, NULL);
+ free(str);
+}
+
+void weston_dbus_remove_match_signal(DBusConnection *c, const char *sender,
+ const char *iface, const char *member,
+ const char *path)
+{
+ return weston_dbus_remove_match(c,
+ "type='signal',"
+ "sender='%s',"
+ "interface='%s',"
+ "member='%s',"
+ "path='%s'",
+ sender, iface, member, path);
+}
diff --git a/src/dbus.h b/src/dbus.h
new file mode 100644
index 00000000..06fe7621
--- /dev/null
+++ b/src/dbus.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright © 2013 David Herrmann <dh.herrmann@gmail.com>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _WESTON_DBUS_H_
+#define _WESTON_DBUS_H_
+
+#include "config.h"
+
+#include <errno.h>
+#include <wayland-server.h>
+
+#include "compositor.h"
+
+#ifdef HAVE_DBUS
+
+#include <dbus/dbus.h>
+
+/*
+ * weston_dbus_open() - Open new dbus connection
+ *
+ * Opens a new dbus connection to the bus given as @bus. It automatically
+ * integrates the new connection into the main-loop @loop. The connection
+ * itself is returned in @out.
+ * This also returns a context source used for dbus dispatching. It is
+ * returned on success in @ctx_out and must be passed to weston_dbus_close()
+ * unchanged. You must not access it from outside of a dbus helper!
+ *
+ * Returns 0 on success, negative error code on failure.
+ */
+int weston_dbus_open(struct wl_event_loop *loop, DBusBusType bus,
+ DBusConnection **out, struct wl_event_source **ctx_out);
+
+/*
+ * weston_dbus_close() - Close dbus connection
+ *
+ * Closes a dbus connection that was previously opened via weston_dbus_open().
+ * It unbinds the connection from the main-loop it was previously bound to,
+ * closes the dbus connection and frees all resources. If you want to access
+ * @c after this call returns, you must hold a dbus-reference to it. But
+ * notice that the connection is closed after this returns so it cannot be
+ * used to spawn new dbus requests.
+ * You must pass the context source returns by weston_dbus_open() as @ctx.
+ */
+void weston_dbus_close(DBusConnection *c, struct wl_event_source *ctx);
+
+/*
+ * weston_dbus_add_match() - Add dbus match
+ *
+ * Configure a dbus-match on the given dbus-connection. This match is saved
+ * on the dbus-server as long as the connection is open. See dbus-manual
+ * for information. Compared to the dbus_bus_add_match() this allows a
+ * var-arg formatted match-string.
+ */
+int weston_dbus_add_match(DBusConnection *c, const char *format, ...);
+
+/*
+ * weston_dbus_add_match_signal() - Add dbus signal match
+ *
+ * Same as weston_dbus_add_match() but does the dbus-match formatting for
+ * signals internally.
+ */
+int weston_dbus_add_match_signal(DBusConnection *c, const char *sender,
+ const char *iface, const char *member,
+ const char *path);
+
+/*
+ * weston_dbus_remove_match() - Remove dbus match
+ *
+ * Remove a previously configured dbus-match from the dbus server. There is
+ * no need to remove dbus-matches if you close the connection, anyway.
+ * Compared to dbus_bus_remove_match() this allows a var-arg formatted
+ * match string.
+ */
+void weston_dbus_remove_match(DBusConnection *c, const char *format, ...);
+
+/*
+ * weston_dbus_remove_match_signal() - Remove dbus signal match
+ *
+ * Same as weston_dbus_remove_match() but does the dbus-match formatting for
+ * signals internally.
+ */
+void weston_dbus_remove_match_signal(DBusConnection *c, const char *sender,
+ const char *iface, const char *member,
+ const char *path);
+
+#endif /* HAVE_DBUS */
+
+#endif // _WESTON_DBUS_H_
diff --git a/src/evdev.c b/src/evdev.c
index eb7631a7..d38f63bd 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -50,7 +50,7 @@ evdev_led_update(struct evdev_device *device, enum weston_led leds)
struct input_event ev[ARRAY_LENGTH(map) + 1];
unsigned int i;
- if (!device->caps & EVDEV_KEYBOARD)
+ if (!(device->seat_caps & EVDEV_SEAT_KEYBOARD))
return;
memset(ev, 0, sizeof(ev));
@@ -90,10 +90,9 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time)
struct weston_seat *master = device->seat;
wl_fixed_t x, y;
int32_t cx, cy;
- int slot;
+ int slot, seat_slot;
slot = device->mt.slot;
-
switch (device->pending_event) {
case EVDEV_NONE:
return;
@@ -104,42 +103,56 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time)
goto handled;
case EVDEV_ABSOLUTE_MT_DOWN:
weston_output_transform_coordinate(device->output,
- device->mt.slots[slot].x,
- device->mt.slots[slot].y,
+ wl_fixed_from_int(device->mt.slots[slot].x),
+ wl_fixed_from_int(device->mt.slots[slot].y),
&x, &y);
- notify_touch(master, time,
- slot, x, y, WL_TOUCH_DOWN);
+ seat_slot = ffs(~master->slot_map) - 1;
+ device->mt.slots[slot].seat_slot = seat_slot;
+ master->slot_map |= 1 << seat_slot;
+
+ notify_touch(master, time, seat_slot, x, y, WL_TOUCH_DOWN);
goto handled;
case EVDEV_ABSOLUTE_MT_MOTION:
weston_output_transform_coordinate(device->output,
- device->mt.slots[slot].x,
- device->mt.slots[slot].y,
+ wl_fixed_from_int(device->mt.slots[slot].x),
+ wl_fixed_from_int(device->mt.slots[slot].y),
&x, &y);
- notify_touch(master, time,
- slot, x, y, WL_TOUCH_MOTION);
+ seat_slot = device->mt.slots[slot].seat_slot;
+ notify_touch(master, time, seat_slot, x, y, WL_TOUCH_MOTION);
goto handled;
case EVDEV_ABSOLUTE_MT_UP:
- notify_touch(master, time, slot, 0, 0,
- WL_TOUCH_UP);
+ seat_slot = device->mt.slots[slot].seat_slot;
+ master->slot_map &= ~(1 << seat_slot);
+ notify_touch(master, time, seat_slot, 0, 0, WL_TOUCH_UP);
goto handled;
case EVDEV_ABSOLUTE_TOUCH_DOWN:
transform_absolute(device, &cx, &cy);
weston_output_transform_coordinate(device->output,
- cx, cy, &x, &y);
- notify_touch(master, time, 0, x, y, WL_TOUCH_DOWN);
+ wl_fixed_from_int(cx),
+ wl_fixed_from_int(cy),
+ &x, &y);
+ seat_slot = ffs(~master->slot_map) - 1;
+ device->abs.seat_slot = seat_slot;
+ master->slot_map |= 1 << seat_slot;
+ notify_touch(master, time, seat_slot, x, y, WL_TOUCH_DOWN);
goto handled;
case EVDEV_ABSOLUTE_MOTION:
transform_absolute(device, &cx, &cy);
weston_output_transform_coordinate(device->output,
- cx, cy, &x, &y);
+ wl_fixed_from_int(cx),
+ wl_fixed_from_int(cy),
+ &x, &y);
- if (device->caps & EVDEV_TOUCH)
- notify_touch(master, time, 0, x, y, WL_TOUCH_MOTION);
- else
+ if (device->seat_caps & EVDEV_SEAT_TOUCH)
+ notify_touch(master, time, device->abs.seat_slot,
+ x, y, WL_TOUCH_MOTION);
+ else if (device->seat_caps & EVDEV_SEAT_POINTER)
notify_motion_absolute(master, time, x, y);
goto handled;
case EVDEV_ABSOLUTE_TOUCH_UP:
- notify_touch(master, time, 0, 0, 0, WL_TOUCH_UP);
+ seat_slot = device->abs.seat_slot;
+ master->slot_map &= ~(1 << seat_slot);
+ notify_touch(master, time, seat_slot, 0, 0, WL_TOUCH_UP);
goto handled;
}
@@ -400,7 +413,7 @@ evdev_device_data(int fd, uint32_t mask, void *data)
int len;
ec = device->seat->compositor;
- if (!ec->focus)
+ if (!ec->session_active)
return 1;
/* If the compositor is repainting, this function is called only once
@@ -433,47 +446,40 @@ evdev_device_data(int fd, uint32_t mask, void *data)
}
static int
-evdev_handle_device(struct evdev_device *device)
+evdev_configure_device(struct evdev_device *device)
{
struct input_absinfo absinfo;
unsigned long ev_bits[NBITS(EV_MAX)];
unsigned long abs_bits[NBITS(ABS_MAX)];
unsigned long rel_bits[NBITS(REL_MAX)];
unsigned long key_bits[NBITS(KEY_MAX)];
- int has_key, has_abs;
+ int has_abs, has_rel, has_mt;
+ int has_button, has_keyboard, has_touch;
unsigned int i;
- has_key = 0;
+ has_rel = 0;
has_abs = 0;
- device->caps = 0;
+ has_mt = 0;
+ has_button = 0;
+ has_keyboard = 0;
+ has_touch = 0;
ioctl(device->fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits);
if (TEST_BIT(ev_bits, EV_ABS)) {
- has_abs = 1;
-
ioctl(device->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)),
abs_bits);
- if (TEST_BIT(abs_bits, ABS_WHEEL) ||
- TEST_BIT(abs_bits, ABS_GAS) ||
- TEST_BIT(abs_bits, ABS_BRAKE) ||
- TEST_BIT(abs_bits, ABS_HAT0X)) {
- weston_log("device %s is a joystick, ignoring\n",
- device->devnode);
- return 0;
- }
-
if (TEST_BIT(abs_bits, ABS_X)) {
ioctl(device->fd, EVIOCGABS(ABS_X), &absinfo);
device->abs.min_x = absinfo.minimum;
device->abs.max_x = absinfo.maximum;
- device->caps |= EVDEV_MOTION_ABS;
+ has_abs = 1;
}
if (TEST_BIT(abs_bits, ABS_Y)) {
ioctl(device->fd, EVIOCGABS(ABS_Y), &absinfo);
device->abs.min_y = absinfo.minimum;
device->abs.max_y = absinfo.maximum;
- device->caps |= EVDEV_MOTION_ABS;
+ has_abs = 1;
}
/* We only handle the slotted Protocol B in weston.
Devices with ABS_MT_POSITION_* but not ABS_MT_SLOT
@@ -489,7 +495,8 @@ evdev_handle_device(struct evdev_device *device)
device->abs.min_y = absinfo.minimum;
device->abs.max_y = absinfo.maximum;
device->is_mt = 1;
- device->caps |= EVDEV_TOUCH;
+ has_touch = 1;
+ has_mt = 1;
if (!TEST_BIT(abs_bits, ABS_MT_SLOT)) {
device->mtdev = mtdev_new_open(device->fd);
@@ -510,15 +517,14 @@ evdev_handle_device(struct evdev_device *device)
ioctl(device->fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)),
rel_bits);
if (TEST_BIT(rel_bits, REL_X) || TEST_BIT(rel_bits, REL_Y))
- device->caps |= EVDEV_MOTION_REL;
+ has_rel = 1;
}
if (TEST_BIT(ev_bits, EV_KEY)) {
- has_key = 1;
ioctl(device->fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)),
key_bits);
if (TEST_BIT(key_bits, BTN_TOOL_FINGER) &&
!TEST_BIT(key_bits, BTN_TOOL_PEN) &&
- has_abs) {
+ (has_abs || has_mt)) {
device->dispatch = evdev_touchpad_create(device);
weston_log("input device %s, %s is a touchpad\n",
device->devname, device->devnode);
@@ -527,59 +533,39 @@ evdev_handle_device(struct evdev_device *device)
if (i >= BTN_MISC && i < KEY_OK)
continue;
if (TEST_BIT(key_bits, i)) {
- device->caps |= EVDEV_KEYBOARD;
+ has_keyboard = 1;
break;
}
}
- if (TEST_BIT(key_bits, BTN_TOUCH)) {
- device->caps |= EVDEV_TOUCH;
- }
+ if (TEST_BIT(key_bits, BTN_TOUCH))
+ has_touch = 1;
for (i = BTN_MISC; i < BTN_JOYSTICK; i++) {
if (TEST_BIT(key_bits, i)) {
- device->caps |= EVDEV_BUTTON;
- device->caps &= ~EVDEV_TOUCH;
+ has_button = 1;
break;
}
}
}
- if (TEST_BIT(ev_bits, EV_LED)) {
- device->caps |= EVDEV_KEYBOARD;
- }
-
- /* This rule tries to catch accelerometer devices and opt out. We may
- * want to adjust the protocol later adding a proper event for dealing
- * with accelerometers and implement here accordingly */
- if (has_abs && !has_key && !device->is_mt) {
- weston_log("input device %s, %s "
- "ignored: unsupported device type\n",
- device->devname, device->devnode);
- return 0;
- }
-
- return 1;
-}
+ if (TEST_BIT(ev_bits, EV_LED))
+ has_keyboard = 1;
-static int
-evdev_configure_device(struct evdev_device *device)
-{
- if ((device->caps & (EVDEV_MOTION_ABS | EVDEV_MOTION_REL)) &&
- (device->caps & EVDEV_BUTTON)) {
+ if ((has_abs || has_rel) && has_button) {
weston_seat_init_pointer(device->seat);
device->seat_caps |= EVDEV_SEAT_POINTER;
weston_log("input device %s, %s is a pointer caps =%s%s%s\n",
device->devname, device->devnode,
- device->caps & EVDEV_MOTION_ABS ? " absolute-motion" : "",
- device->caps & EVDEV_MOTION_REL ? " relative-motion": "",
- device->caps & EVDEV_BUTTON ? " button" : "");
+ has_abs ? " absolute-motion" : "",
+ has_rel ? " relative-motion": "",
+ has_button ? " button" : "");
}
- if ((device->caps & EVDEV_KEYBOARD)) {
+ if (has_keyboard) {
if (weston_seat_init_keyboard(device->seat, NULL) < 0)
return -1;
device->seat_caps |= EVDEV_SEAT_KEYBOARD;
weston_log("input device %s, %s is a keyboard\n",
device->devname, device->devnode);
}
- if ((device->caps & EVDEV_TOUCH)) {
+ if (has_touch && !has_button) {
weston_seat_init_touch(device->seat);
device->seat_caps |= EVDEV_SEAT_TOUCH;
weston_log("input device %s, %s is a touch device\n",
@@ -621,14 +607,14 @@ evdev_device_create(struct weston_seat *seat, const char *path, int device_fd)
devname[sizeof(devname) - 1] = '\0';
device->devname = strdup(devname);
- if (!evdev_handle_device(device)) {
+ if (evdev_configure_device(device) == -1)
+ goto err;
+
+ if (device->seat_caps == 0) {
evdev_device_destroy(device);
return EVDEV_UNHANDLED_DEVICE;
}
- if (evdev_configure_device(device) == -1)
- goto err;
-
/* If the dispatch was not set up use the fallback. */
if (device->dispatch == NULL)
device->dispatch = fallback_dispatch_create();
@@ -672,6 +658,7 @@ evdev_device_destroy(struct evdev_device *device)
close(device->fd);
free(device->devname);
free(device->devnode);
+ free(device->output_name);
free(device);
}
@@ -687,7 +674,7 @@ evdev_notify_keyboard_focus(struct weston_seat *seat,
uint32_t *k;
int ret;
- if (!seat->keyboard)
+ if (!seat->keyboard_device_count > 0)
return;
memset(all_keys, 0, sizeof all_keys);
diff --git a/src/evdev.h b/src/evdev.h
index e146d1a4..36a52e34 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -41,14 +41,6 @@ enum evdev_event_type {
EVDEV_RELATIVE_MOTION,
};
-enum evdev_device_capability {
- EVDEV_KEYBOARD = (1 << 0),
- EVDEV_BUTTON = (1 << 1),
- EVDEV_MOTION_ABS = (1 << 2),
- EVDEV_MOTION_REL = (1 << 3),
- EVDEV_TOUCH = (1 << 4),
-};
-
enum evdev_device_seat_capability {
EVDEV_SEAT_POINTER = (1 << 0),
EVDEV_SEAT_KEYBOARD = (1 << 1),
@@ -63,9 +55,11 @@ struct evdev_device {
struct evdev_dispatch *dispatch;
char *devnode;
char *devname;
+ char *output_name;
int fd;
struct {
int min_x, max_x, min_y, max_y;
+ uint32_t seat_slot;
int32_t x, y;
int apply_calibration;
@@ -76,6 +70,7 @@ struct evdev_device {
int slot;
struct {
int32_t x, y;
+ uint32_t seat_slot;
} slots[MAX_SLOTS];
} mt;
struct mtdev *mtdev;
@@ -85,7 +80,6 @@ struct evdev_device {
} rel;
enum evdev_event_type pending_event;
- enum evdev_device_capability caps;
enum evdev_device_seat_capability seat_caps;
int is_mt;
diff --git a/src/filter.c b/src/filter.c
index a55ebf27..89237bf8 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -323,7 +323,6 @@ create_pointer_accelator_filter(accel_profile_func_t profile)
return NULL;
filter->base.interface = &accelerator_interface;
- wl_list_init(&filter->base.link);
filter->profile = profile;
filter->last_velocity = 0.0;
diff --git a/src/filter.h b/src/filter.h
index 850ce8df..dad538b2 100644
--- a/src/filter.h
+++ b/src/filter.h
@@ -50,7 +50,6 @@ struct weston_motion_filter_interface {
struct weston_motion_filter {
struct weston_motion_filter_interface *interface;
- struct wl_list link;
};
WL_EXPORT struct weston_motion_filter *
diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index ae69f220..0e5afbe3 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -50,9 +50,18 @@ struct gl_shader {
#define BUFFER_DAMAGE_COUNT 2
+struct gl_border_image {
+ GLuint tex;
+ int32_t width, height;
+ int32_t tex_width;
+ int dirty;
+ void *data;
+};
+
struct gl_output_state {
EGLSurface egl_surface;
pixman_region32_t buffer_damage[BUFFER_DAMAGE_COUNT];
+ struct gl_border_image borders[4];
};
enum buffer_type {
@@ -79,25 +88,25 @@ struct gl_surface_state {
int pitch; /* in pixels */
int height; /* in pixels */
int y_inverted;
+
+ struct weston_surface *surface;
+
+ struct wl_listener surface_destroy_listener;
+ struct wl_listener renderer_destroy_listener;
};
struct gl_renderer {
struct weston_renderer base;
int fragment_shader_debug;
int fan_debug;
+ struct weston_binding *fragment_binding;
+ struct weston_binding *fan_binding;
EGLDisplay egl_display;
EGLContext egl_context;
EGLConfig egl_config;
- struct {
- int32_t top, bottom, left, right;
- GLuint texture;
- int32_t width, height;
- } border;
-
struct wl_array vertices;
- struct wl_array indices; /* only used in compositor-wayland */
struct wl_array vtxcnt;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
@@ -124,6 +133,8 @@ struct gl_renderer {
struct gl_shader invert_color_shader;
struct gl_shader solid_shader;
struct gl_shader *current_shader;
+
+ struct wl_signal destroy_signal;
};
static inline struct gl_output_state *
@@ -132,9 +143,15 @@ get_output_state(struct weston_output *output)
return (struct gl_output_state *)output->renderer_state;
}
+static int
+gl_renderer_create_surface(struct weston_surface *surface);
+
static inline struct gl_surface_state *
get_surface_state(struct weston_surface *surface)
{
+ if (!surface->renderer_state)
+ gl_renderer_create_surface(surface);
+
return (struct gl_surface_state *)surface->renderer_state;
}
@@ -170,7 +187,7 @@ egl_error_string(EGLint code)
#undef MYERRCODE
}
-WL_EXPORT void
+static void
gl_renderer_print_egl_error_state(void)
{
EGLint code;
@@ -193,7 +210,7 @@ gl_renderer_print_egl_error_state(void)
* polygon area.
*/
static int
-calculate_edges(struct weston_surface *es, pixman_box32_t *rect,
+calculate_edges(struct weston_view *ev, pixman_box32_t *rect,
pixman_box32_t *surf_rect, GLfloat *ex, GLfloat *ey)
{
@@ -213,8 +230,8 @@ calculate_edges(struct weston_surface *es, pixman_box32_t *rect,
/* transform surface to screen space: */
for (i = 0; i < surf.n; i++)
- weston_surface_to_global_float(es, surf.x[i], surf.y[i],
- &surf.x[i], &surf.y[i]);
+ weston_view_to_global_float(ev, surf.x[i], surf.y[i],
+ &surf.x[i], &surf.y[i]);
/* find bounding box: */
min_x = max_x = surf.x[0];
@@ -238,9 +255,8 @@ calculate_edges(struct weston_surface *es, pixman_box32_t *rect,
* there will be only four edges. We just need to clip the surface
* vertices to the clip rect bounds:
*/
- if (!es->transform.enabled) {
+ if (!ev->transform.enabled)
return clip_simple(&ctx, &surf, ex, ey);
- }
/* Transformed case: use a general polygon clipping algorithm to
* clip the surface rectangle with each side of 'rect'.
@@ -257,11 +273,11 @@ calculate_edges(struct weston_surface *es, pixman_box32_t *rect,
}
static int
-texture_region(struct weston_surface *es, pixman_region32_t *region,
+texture_region(struct weston_view *ev, pixman_region32_t *region,
pixman_region32_t *surf_region)
{
- struct gl_surface_state *gs = get_surface_state(es);
- struct weston_compositor *ec = es->compositor;
+ struct gl_surface_state *gs = get_surface_state(ev->surface);
+ struct weston_compositor *ec = ev->surface->compositor;
struct gl_renderer *gr = get_renderer(ec);
GLfloat *v, inv_width, inv_height;
unsigned int *vtxcnt, nvtx = 0;
@@ -302,18 +318,20 @@ texture_region(struct weston_surface *es, pixman_region32_t *region,
* form the intersection of the clip rect and the transformed
* surface.
*/
- n = calculate_edges(es, rect, surf_rect, ex, ey);
+ n = calculate_edges(ev, rect, surf_rect, ex, ey);
if (n < 3)
continue;
/* emit edge points: */
for (k = 0; k < n; k++) {
- weston_surface_from_global_float(es, ex[k], ey[k], &sx, &sy);
+ weston_view_from_global_float(ev, ex[k], ey[k],
+ &sx, &sy);
/* position: */
*(v++) = ex[k];
*(v++) = ey[k];
/* texcoord: */
- weston_surface_to_buffer_float(es, sx, sy,
+ weston_surface_to_buffer_float(ev->surface,
+ sx, sy,
&bx, &by);
*(v++) = bx * inv_width;
if (gs->y_inverted) {
@@ -331,9 +349,9 @@ texture_region(struct weston_surface *es, pixman_region32_t *region,
}
static void
-triangle_fan_debug(struct weston_surface *surface, int first, int count)
+triangle_fan_debug(struct weston_view *view, int first, int count)
{
- struct weston_compositor *compositor = surface->compositor;
+ struct weston_compositor *compositor = view->surface->compositor;
struct gl_renderer *gr = get_renderer(compositor);
int i;
GLushort *buffer;
@@ -371,10 +389,10 @@ triangle_fan_debug(struct weston_surface *surface, int first, int count)
}
static void
-repaint_region(struct weston_surface *es, pixman_region32_t *region,
+repaint_region(struct weston_view *ev, pixman_region32_t *region,
pixman_region32_t *surf_region)
{
- struct weston_compositor *ec = es->compositor;
+ struct weston_compositor *ec = ev->surface->compositor;
struct gl_renderer *gr = get_renderer(ec);
GLfloat *v;
unsigned int *vtxcnt;
@@ -388,7 +406,7 @@ repaint_region(struct weston_surface *es, pixman_region32_t *region,
* polygon for each pair, and store it as a triangle fan if
* it has a non-zero area (at least 3 vertices1, actually).
*/
- nfans = texture_region(es, region, surf_region);
+ nfans = texture_region(ev, region, surf_region);
v = gr->vertices.data;
vtxcnt = gr->vtxcnt.data;
@@ -404,7 +422,7 @@ repaint_region(struct weston_surface *es, pixman_region32_t *region,
for (i = 0, first = 0; i < nfans; i++) {
glDrawArrays(GL_TRIANGLE_FAN, first, vtxcnt[i]);
if (gr->fan_debug)
- triangle_fan_debug(es, first, vtxcnt[i]);
+ triangle_fan_debug(ev, first, vtxcnt[i]);
first += vtxcnt[i];
}
@@ -464,28 +482,28 @@ use_shader(struct gl_renderer *gr, struct gl_shader *shader)
static void
shader_uniforms(struct gl_shader *shader,
- struct weston_surface *surface,
- struct weston_output *output)
+ struct weston_view *view,
+ struct weston_output *output)
{
int i;
- struct gl_surface_state *gs = get_surface_state(surface);
+ struct gl_surface_state *gs = get_surface_state(view->surface);
glUniformMatrix4fv(shader->proj_uniform,
1, GL_FALSE, output->matrix.d);
glUniform4fv(shader->color_uniform, 1, gs->color);
- glUniform1f(shader->alpha_uniform, surface->alpha);
+ glUniform1f(shader->alpha_uniform, view->alpha);
for (i = 0; i < gs->num_textures; i++)
glUniform1i(shader->tex_uniforms[i], i);
}
static void
-draw_surface(struct weston_surface *es, struct weston_output *output,
- pixman_region32_t *damage) /* in global coordinates */
+draw_view(struct weston_view *ev, struct weston_output *output,
+ pixman_region32_t *damage) /* in global coordinates */
{
- struct weston_compositor *ec = es->compositor;
+ struct weston_compositor *ec = ev->surface->compositor;
struct gl_renderer *gr = get_renderer(ec);
- struct gl_surface_state *gs = get_surface_state(es);
+ struct gl_surface_state *gs = get_surface_state(ev->surface);
/* repaint bounding region in global coordinates: */
pixman_region32_t repaint;
/* non-opaque region in surface coordinates: */
@@ -493,10 +511,16 @@ draw_surface(struct weston_surface *es, struct weston_output *output,
GLint filter;
int i;
+ /* In case of a runtime switch of renderers, we may not have received
+ * an attach for this surface since the switch. In that case we don't
+ * have a valid buffer or a proper shader set up so skip rendering. */
+ if (!gs->shader)
+ return;
+
pixman_region32_init(&repaint);
pixman_region32_intersect(&repaint,
- &es->transform.boundingbox, damage);
- pixman_region32_subtract(&repaint, &repaint, &es->clip);
+ &ev->transform.boundingbox, damage);
+ pixman_region32_subtract(&repaint, &repaint, &ev->clip);
if (!pixman_region32_not_empty(&repaint))
goto out;
@@ -505,13 +529,14 @@ draw_surface(struct weston_surface *es, struct weston_output *output,
if (gr->fan_debug) {
use_shader(gr, &gr->solid_shader);
- shader_uniforms(&gr->solid_shader, es, output);
+ shader_uniforms(&gr->solid_shader, ev, output);
}
use_shader(gr, gs->shader);
- shader_uniforms(gs->shader, es, output);
+ shader_uniforms(gs->shader, ev, output);
- if (es->transform.enabled || output->zoom.active || output->current_scale != es->buffer_scale)
+ if (ev->transform.enabled || output->zoom.active ||
+ output->current_scale != ev->surface->buffer_viewport.scale)
filter = GL_LINEAR;
else
filter = GL_NEAREST;
@@ -525,10 +550,11 @@ draw_surface(struct weston_surface *es, struct weston_output *output,
/* blended region is whole surface minus opaque region: */
pixman_region32_init_rect(&surface_blend, 0, 0,
- es->geometry.width, es->geometry.height);
- pixman_region32_subtract(&surface_blend, &surface_blend, &es->opaque);
+ ev->surface->width, ev->surface->height);
+ pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque);
- if (pixman_region32_not_empty(&es->opaque)) {
+ /* XXX: Should we be using ev->transform.opaque here? */
+ if (pixman_region32_not_empty(&ev->surface->opaque)) {
if (gs->shader == &gr->texture_shader_rgba) {
/* Special case for RGBA textures with possibly
* bad data in alpha channel: use the shader
@@ -536,21 +562,21 @@ draw_surface(struct weston_surface *es, struct weston_output *output,
* Xwayland surfaces need this.
*/
use_shader(gr, &gr->texture_shader_rgbx);
- shader_uniforms(&gr->texture_shader_rgbx, es, output);
+ shader_uniforms(&gr->texture_shader_rgbx, ev, output);
}
- if (es->alpha < 1.0)
+ if (ev->alpha < 1.0)
glEnable(GL_BLEND);
else
glDisable(GL_BLEND);
- repaint_region(es, &repaint, &es->opaque);
+ repaint_region(ev, &repaint, &ev->surface->opaque);
}
if (pixman_region32_not_empty(&surface_blend)) {
use_shader(gr, gs->shader);
glEnable(GL_BLEND);
- repaint_region(es, &repaint, &surface_blend);
+ repaint_region(ev, &repaint, &surface_blend);
}
pixman_region32_fini(&surface_blend);
@@ -560,130 +586,128 @@ out:
}
static void
-repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
+repaint_views(struct weston_output *output, pixman_region32_t *damage)
{
struct weston_compositor *compositor = output->compositor;
- struct weston_surface *surface;
+ struct weston_view *view;
- wl_list_for_each_reverse(surface, &compositor->surface_list, link)
- if (surface->plane == &compositor->primary_plane)
- draw_surface(surface, output, damage);
+ wl_list_for_each_reverse(view, &compositor->view_list, link)
+ if (view->plane == &compositor->primary_plane)
+ draw_view(view, output, damage);
}
-
-static int
-texture_border(struct weston_output *output)
+static void
+draw_output_border_texture(struct gl_border_image *img, int32_t x, int32_t y,
+ int32_t width, int32_t height)
{
- struct weston_compositor *ec = output->compositor;
- struct gl_renderer *gr = get_renderer(ec);
- GLfloat *d;
- unsigned short *p;
- int i, j, k, n;
- GLfloat x[4], y[4], u[4], v[4];
-
- x[0] = -gr->border.left;
- x[1] = 0;
- x[2] = output->current_mode->width;
- x[3] = output->current_mode->width + gr->border.right;
-
- y[0] = -gr->border.top;
- y[1] = 0;
- y[2] = output->current_mode->height;
- y[3] = output->current_mode->height + gr->border.bottom;
-
- u[0] = 0.0;
- u[1] = (GLfloat) gr->border.left / gr->border.width;
- u[2] = (GLfloat) (gr->border.width - gr->border.right) / gr->border.width;
- u[3] = 1.0;
-
- v[0] = 0.0;
- v[1] = (GLfloat) gr->border.top / gr->border.height;
- v[2] = (GLfloat) (gr->border.height - gr->border.bottom) / gr->border.height;
- v[3] = 1.0;
-
- n = 8;
- d = wl_array_add(&gr->vertices, n * 16 * sizeof *d);
- p = wl_array_add(&gr->indices, n * 6 * sizeof *p);
-
- k = 0;
- for (i = 0; i < 3; i++)
- for (j = 0; j < 3; j++) {
-
- if (i == 1 && j == 1)
- continue;
+ static GLushort indices [] = { 0, 1, 3, 3, 1, 2 };
- d[ 0] = x[i];
- d[ 1] = y[j];
- d[ 2] = u[i];
- d[ 3] = v[j];
-
- d[ 4] = x[i];
- d[ 5] = y[j + 1];
- d[ 6] = u[i];
- d[ 7] = v[j + 1];
-
- d[ 8] = x[i + 1];
- d[ 9] = y[j];
- d[10] = u[i + 1];
- d[11] = v[j];
-
- d[12] = x[i + 1];
- d[13] = y[j + 1];
- d[14] = u[i + 1];
- d[15] = v[j + 1];
-
- p[0] = k + 0;
- p[1] = k + 1;
- p[2] = k + 2;
- p[3] = k + 2;
- p[4] = k + 1;
- p[5] = k + 3;
-
- d += 16;
- p += 6;
- k += 4;
+ if (!img->data) {
+ if (img->tex) {
+ glDeleteTextures(1, &img->tex);
+ img->tex = 0;
}
- return k / 4;
+ return;
+ }
+
+ if (!img->tex) {
+ glGenTextures(1, &img->tex);
+ glBindTexture(GL_TEXTURE_2D, img->tex);
+
+ glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ } else {
+ glBindTexture(GL_TEXTURE_2D, img->tex);
+ }
+
+ if (img->dirty) {
+#ifdef GL_EXT_unpack_subimage
+ glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
+#endif
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT,
+ img->tex_width, img->height, 0,
+ GL_BGRA_EXT, GL_UNSIGNED_BYTE, img->data);
+ img->dirty = 0;
+ }
+
+ GLfloat texcoord[] = {
+ 0.0f, 0.0f,
+ (GLfloat)img->width / (GLfloat)img->tex_width, 0.0f,
+ (GLfloat)img->width / (GLfloat)img->tex_width, 1.0f,
+ 0.0f, 1.0f,
+ };
+
+ GLfloat verts[] = {
+ x, y,
+ x + width, y,
+ x + width, y + height,
+ x, y + height
+ };
+
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts);
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord);
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(1);
+
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
+
+ glDisableVertexAttribArray(1);
+ glDisableVertexAttribArray(0);
}
static void
-draw_border(struct weston_output *output)
+draw_output_border(struct weston_output *output)
{
- struct weston_compositor *ec = output->compositor;
- struct gl_renderer *gr = get_renderer(ec);
+ struct gl_output_state *go = get_output_state(output);
+ struct gl_renderer *gr = get_renderer(output->compositor);
struct gl_shader *shader = &gr->texture_shader_rgba;
- GLfloat *v;
- int n;
+ struct gl_border_image *top, *bottom, *left, *right;
+ struct weston_matrix matrix;
+ int full_width, full_height;
+
+ top = &go->borders[GL_RENDERER_BORDER_TOP];
+ bottom = &go->borders[GL_RENDERER_BORDER_BOTTOM];
+ left = &go->borders[GL_RENDERER_BORDER_LEFT];
+ right = &go->borders[GL_RENDERER_BORDER_RIGHT];
+
+ full_width = output->current_mode->width + left->width + right->width;
+ full_height = output->current_mode->height + top->height + bottom->height;
glDisable(GL_BLEND);
use_shader(gr, shader);
- glUniformMatrix4fv(shader->proj_uniform,
- 1, GL_FALSE, output->matrix.d);
+ glViewport(0, 0, full_width, full_height);
+
+ weston_matrix_init(&matrix);
+ weston_matrix_translate(&matrix, -full_width/2.0, -full_height/2.0, 0);
+ weston_matrix_scale(&matrix, 2.0/full_width, -2.0/full_height, 1);
+ glUniformMatrix4fv(shader->proj_uniform, 1, GL_FALSE, matrix.d);
glUniform1i(shader->tex_uniforms[0], 0);
glUniform1f(shader->alpha_uniform, 1);
-
- n = texture_border(output);
-
glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, gr->border.texture);
- v = gr->vertices.data;
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[0]);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[2]);
- glEnableVertexAttribArray(0);
- glEnableVertexAttribArray(1);
-
- glDrawElements(GL_TRIANGLES, n * 6,
- GL_UNSIGNED_SHORT, gr->indices.data);
-
- glDisableVertexAttribArray(1);
- glDisableVertexAttribArray(0);
-
- gr->vertices.size = 0;
- gr->indices.size = 0;
+ draw_output_border_texture(top,
+ 0, 0,
+ full_width, top->height);
+ draw_output_border_texture(left,
+ 0, top->height,
+ left->width, output->current_mode->height);
+ draw_output_border_texture(right,
+ full_width - right->width, top->height,
+ right->width, output->current_mode->height);
+ draw_output_border_texture(bottom,
+ 0, full_height - bottom->height,
+ full_width, bottom->height);
}
static void
@@ -740,15 +764,13 @@ gl_renderer_repaint_output(struct weston_output *output,
struct gl_renderer *gr = get_renderer(compositor);
EGLBoolean ret;
static int errored;
- int32_t width, height;
pixman_region32_t buffer_damage, total_damage;
- width = output->current_mode->width +
- output->border.left + output->border.right;
- height = output->current_mode->height +
- output->border.top + output->border.bottom;
-
- glViewport(0, 0, width, height);
+ /* Calculate the viewport */
+ glViewport(go->borders[GL_RENDERER_BORDER_LEFT].width,
+ go->borders[GL_RENDERER_BORDER_BOTTOM].height,
+ output->current_mode->width,
+ output->current_mode->height);
if (use_output(output) < 0)
return;
@@ -762,7 +784,7 @@ gl_renderer_repaint_output(struct weston_output *output,
pixman_region32_subtract(&undamaged, &output->region,
output_damage);
gr->fan_debug = 0;
- repaint_surfaces(output, &undamaged);
+ repaint_views(output, &undamaged);
gr->fan_debug = 1;
pixman_region32_fini(&undamaged);
}
@@ -775,13 +797,12 @@ gl_renderer_repaint_output(struct weston_output *output,
pixman_region32_union(&total_damage, &buffer_damage, output_damage);
- repaint_surfaces(output, &total_damage);
+ repaint_views(output, &total_damage);
pixman_region32_fini(&total_damage);
pixman_region32_fini(&buffer_damage);
- if (gr->border.texture)
- draw_border(output);
+ draw_output_border(output);
pixman_region32_copy(&output->previous_damage, output_damage);
wl_signal_emit(&output->frame_signal, output);
@@ -830,6 +851,8 @@ gl_renderer_flush_damage(struct weston_surface *surface)
struct gl_renderer *gr = get_renderer(surface->compositor);
struct gl_surface_state *gs = get_surface_state(surface);
struct weston_buffer *buffer = gs->buffer_ref.buffer;
+ struct weston_view *view;
+ int texture_used;
GLenum format;
int pixel_type;
@@ -850,10 +873,18 @@ gl_renderer_flush_damage(struct weston_surface *surface)
* hold the reference to the buffer, in case the surface
* migrates back to the primary plane.
*/
- if (surface->plane != &surface->compositor->primary_plane)
+ texture_used = 0;
+ wl_list_for_each(view, &surface->views, surface_link) {
+ if (view->plane == &surface->compositor->primary_plane) {
+ texture_used = 1;
+ break;
+ }
+ }
+ if (!texture_used)
return;
- if (!pixman_region32_not_empty(&gs->texture_damage))
+ if (!pixman_region32_not_empty(&gs->texture_damage) &&
+ !gs->needs_full_upload)
goto done;
switch (wl_shm_buffer_get_format(buffer->shm_buffer)) {
@@ -875,10 +906,12 @@ gl_renderer_flush_damage(struct weston_surface *surface)
glBindTexture(GL_TEXTURE_2D, gs->textures[0]);
if (!gr->has_unpack_subimage) {
+ wl_shm_buffer_begin_access(buffer->shm_buffer);
glTexImage2D(GL_TEXTURE_2D, 0, format,
gs->pitch, buffer->height, 0,
format, pixel_type,
wl_shm_buffer_get_data(buffer->shm_buffer));
+ wl_shm_buffer_end_access(buffer->shm_buffer);
goto done;
}
@@ -890,13 +923,16 @@ gl_renderer_flush_damage(struct weston_surface *surface)
if (gs->needs_full_upload) {
glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
+ wl_shm_buffer_begin_access(buffer->shm_buffer);
glTexSubImage2D(GL_TEXTURE_2D, 0,
0, 0, gs->pitch, buffer->height,
format, pixel_type, data);
+ wl_shm_buffer_end_access(buffer->shm_buffer);
goto done;
}
rectangles = pixman_region32_rectangles(&gs->texture_damage, &n);
+ wl_shm_buffer_begin_access(buffer->shm_buffer);
for (i = 0; i < n; i++) {
pixman_box32_t r;
@@ -908,6 +944,7 @@ gl_renderer_flush_damage(struct weston_surface *surface)
r.x2 - r.x1, r.y2 - r.y1,
format, pixel_type, data);
}
+ wl_shm_buffer_end_access(buffer->shm_buffer);
#endif
done:
@@ -983,6 +1020,8 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer,
gs->needs_full_upload = 1;
gs->y_inverted = 1;
+ gs->surface = es;
+
ensure_textures(gs, 1);
glBindTexture(GL_TEXTURE_2D, gs->textures[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT,
@@ -1122,10 +1161,59 @@ gl_renderer_surface_set_color(struct weston_surface *surface,
gs->shader = &gr->solid_shader;
}
+static void
+surface_state_destroy(struct gl_surface_state *gs, struct gl_renderer *gr)
+{
+ int i;
+
+ wl_list_remove(&gs->surface_destroy_listener.link);
+ wl_list_remove(&gs->renderer_destroy_listener.link);
+
+ gs->surface->renderer_state = NULL;
+
+ glDeleteTextures(gs->num_textures, gs->textures);
+
+ for (i = 0; i < gs->num_images; i++)
+ gr->destroy_image(gr->egl_display, gs->images[i]);
+
+ weston_buffer_reference(&gs->buffer_ref, NULL);
+ pixman_region32_fini(&gs->texture_damage);
+ free(gs);
+}
+
+static void
+surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
+{
+ struct gl_surface_state *gs;
+ struct gl_renderer *gr;
+
+ gs = container_of(listener, struct gl_surface_state,
+ surface_destroy_listener);
+
+ gr = get_renderer(gs->surface->compositor);
+
+ surface_state_destroy(gs, gr);
+}
+
+static void
+surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
+{
+ struct gl_surface_state *gs;
+ struct gl_renderer *gr;
+
+ gr = data;
+
+ gs = container_of(listener, struct gl_surface_state,
+ renderer_destroy_listener);
+
+ surface_state_destroy(gs, gr);
+}
+
static int
gl_renderer_create_surface(struct weston_surface *surface)
{
struct gl_surface_state *gs;
+ struct gl_renderer *gr = get_renderer(surface->compositor);
gs = calloc(1, sizeof *gs);
if (!gs)
@@ -1138,27 +1226,27 @@ gl_renderer_create_surface(struct weston_surface *surface)
gs->pitch = 1;
gs->y_inverted = 1;
+ gs->surface = surface;
+
pixman_region32_init(&gs->texture_damage);
surface->renderer_state = gs;
- return 0;
-}
-
-static void
-gl_renderer_destroy_surface(struct weston_surface *surface)
-{
- struct gl_surface_state *gs = get_surface_state(surface);
- struct gl_renderer *gr = get_renderer(surface->compositor);
- int i;
+ gs->surface_destroy_listener.notify =
+ surface_state_handle_surface_destroy;
+ wl_signal_add(&surface->destroy_signal,
+ &gs->surface_destroy_listener);
- glDeleteTextures(gs->num_textures, gs->textures);
+ gs->renderer_destroy_listener.notify =
+ surface_state_handle_renderer_destroy;
+ wl_signal_add(&gr->destroy_signal,
+ &gs->renderer_destroy_listener);
- for (i = 0; i < gs->num_images; i++)
- gr->destroy_image(gr->egl_display, gs->images[i]);
+ if (surface->buffer_ref.buffer) {
+ gl_renderer_attach(surface, surface->buffer_ref.buffer);
+ gl_renderer_flush_damage(surface);
+ }
- weston_buffer_reference(&gs->buffer_ref, NULL);
- pixman_region32_fini(&gs->texture_damage);
- free(gs);
+ return 0;
}
static const char vertex_shader[] =
@@ -1432,50 +1520,24 @@ log_egl_config_info(EGLDisplay egldpy, EGLConfig eglconfig)
}
static void
-output_apply_border(struct weston_output *output, struct gl_renderer *gr)
+gl_renderer_output_set_border(struct weston_output *output,
+ enum gl_renderer_border_side side,
+ int32_t width, int32_t height,
+ int32_t tex_width, unsigned char *data)
{
- output->border.top = gr->border.top;
- output->border.bottom = gr->border.bottom;
- output->border.left = gr->border.left;
- output->border.right = gr->border.right;
-}
-
-WL_EXPORT void
-gl_renderer_set_border(struct weston_compositor *ec, int32_t width, int32_t height, void *data,
- int32_t *edges)
-{
- struct gl_renderer *gr = get_renderer(ec);
- struct weston_output *output;
-
- gr->border.left = edges[0];
- gr->border.right = edges[1];
- gr->border.top = edges[2];
- gr->border.bottom = edges[3];
-
- gr->border.width = width;
- gr->border.height = height;
-
- glGenTextures(1, &gr->border.texture);
- glBindTexture(GL_TEXTURE_2D, gr->border.texture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT,
- width,
- height,
- 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE,
- data);
+ struct gl_output_state *go = get_output_state(output);
- wl_list_for_each(output, &ec->output_list, link)
- output_apply_border(output, gr);
+ go->borders[side].width = width;
+ go->borders[side].height = height;
+ go->borders[side].tex_width = tex_width;
+ go->borders[side].data = data;
+ go->borders[side].dirty = 1;
}
static int
gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface);
-WL_EXPORT int
+static int
gl_renderer_output_create(struct weston_output *output,
EGLNativeWindowType window)
{
@@ -1509,12 +1571,10 @@ gl_renderer_output_create(struct weston_output *output,
output->renderer_state = go;
- output_apply_border(output, gr);
-
return 0;
}
-WL_EXPORT void
+static void
gl_renderer_output_destroy(struct weston_output *output)
{
struct gl_renderer *gr = get_renderer(output->compositor);
@@ -1529,7 +1589,7 @@ gl_renderer_output_destroy(struct weston_output *output)
free(go);
}
-WL_EXPORT EGLSurface
+static EGLSurface
gl_renderer_output_surface(struct weston_output *output)
{
return get_output_state(output)->egl_surface;
@@ -1540,6 +1600,8 @@ gl_renderer_destroy(struct weston_compositor *ec)
{
struct gl_renderer *gr = get_renderer(ec);
+ wl_signal_emit(&gr->destroy_signal, gr);
+
if (gr->has_bind_display)
gr->unbind_display(gr->egl_display, ec->wl_display);
@@ -1552,9 +1614,11 @@ gl_renderer_destroy(struct weston_compositor *ec)
eglReleaseThread();
wl_array_release(&gr->vertices);
- wl_array_release(&gr->indices);
wl_array_release(&gr->vtxcnt);
+ weston_binding_destroy(gr->fragment_binding);
+ weston_binding_destroy(gr->fan_binding);
+
free(gr);
}
@@ -1602,7 +1666,7 @@ out:
return -1;
}
-WL_EXPORT const EGLint gl_renderer_opaque_attribs[] = {
+static const EGLint gl_renderer_opaque_attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
@@ -1612,7 +1676,7 @@ WL_EXPORT const EGLint gl_renderer_opaque_attribs[] = {
EGL_NONE
};
-WL_EXPORT const EGLint gl_renderer_alpha_attribs[] = {
+static const EGLint gl_renderer_alpha_attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
@@ -1622,7 +1686,7 @@ WL_EXPORT const EGLint gl_renderer_alpha_attribs[] = {
EGL_NONE
};
-WL_EXPORT int
+static int
gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
const EGLint *attribs, const EGLint *visual_id)
{
@@ -1638,9 +1702,7 @@ gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
gr->base.repaint_output = gl_renderer_repaint_output;
gr->base.flush_damage = gl_renderer_flush_damage;
gr->base.attach = gl_renderer_attach;
- gr->base.create_surface = gl_renderer_create_surface;
gr->base.surface_set_color = gl_renderer_surface_set_color;
- gr->base.destroy_surface = gl_renderer_destroy_surface;
gr->base.destroy = gl_renderer_destroy;
gr->egl_display = eglGetDisplay(display);
@@ -1665,6 +1727,8 @@ gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
+ wl_signal_init(&gr->destroy_signal);
+
return 0;
err_egl:
@@ -1673,7 +1737,7 @@ err_egl:
return -1;
}
-WL_EXPORT EGLDisplay
+static EGLDisplay
gl_renderer_display(struct weston_compositor *ec)
{
return get_renderer(ec)->egl_display;
@@ -1701,7 +1765,7 @@ compile_shaders(struct weston_compositor *ec)
gr->texture_shader_y_u_v.fragment_source =
texture_fragment_shader_y_u_v;
- gr->texture_shader_y_u_v.vertex_source = vertex_shader;
+ gr->texture_shader_y_xuxv.vertex_source = vertex_shader;
gr->texture_shader_y_xuxv.fragment_source =
texture_fragment_shader_y_xuxv;
@@ -1847,10 +1911,14 @@ gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
if (compile_shaders(ec))
return -1;
- weston_compositor_add_debug_binding(ec, KEY_S,
- fragment_debug_binding, ec);
- weston_compositor_add_debug_binding(ec, KEY_F,
- fan_debug_repaint_binding, ec);
+ gr->fragment_binding =
+ weston_compositor_add_debug_binding(ec, KEY_S,
+ fragment_debug_binding,
+ ec);
+ gr->fan_binding =
+ weston_compositor_add_debug_binding(ec, KEY_F,
+ fan_debug_repaint_binding,
+ ec);
weston_log("GL ES 2 renderer features:\n");
weston_log_continue(STAMP_SPACE "read-back format: %s\n",
@@ -1863,3 +1931,16 @@ gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
return 0;
}
+
+WL_EXPORT struct gl_renderer_interface gl_renderer_interface = {
+ .opaque_attribs = gl_renderer_opaque_attribs,
+ .alpha_attribs = gl_renderer_alpha_attribs,
+
+ .create = gl_renderer_create,
+ .display = gl_renderer_display,
+ .output_create = gl_renderer_output_create,
+ .output_destroy = gl_renderer_output_destroy,
+ .output_surface = gl_renderer_output_surface,
+ .output_set_border = gl_renderer_output_set_border,
+ .print_egl_error_state = gl_renderer_print_egl_error_state
+};
diff --git a/src/gl-renderer.h b/src/gl-renderer.h
index d16ade29..dcdf69d8 100644
--- a/src/gl-renderer.h
+++ b/src/gl-renderer.h
@@ -28,27 +28,6 @@
#include <EGL/egl.h>
-extern const EGLint gl_renderer_opaque_attribs[];
-extern const EGLint gl_renderer_alpha_attribs[];
-
-int
-gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
- const EGLint *attribs, const EGLint *visual_id);
-EGLDisplay
-gl_renderer_display(struct weston_compositor *ec);
-int
-gl_renderer_output_create(struct weston_output *output,
- EGLNativeWindowType window);
-void
-gl_renderer_output_destroy(struct weston_output *output);
-EGLSurface
-gl_renderer_output_surface(struct weston_output *output);
-void
-gl_renderer_set_border(struct weston_compositor *ec, int32_t width, int32_t height, void *data,
- int32_t *edges);
-
-void
-gl_renderer_print_egl_error_state(void);
#else
typedef int EGLint;
@@ -56,51 +35,68 @@ typedef void *EGLDisplay;
typedef void *EGLSurface;
typedef intptr_t EGLNativeDisplayType;
typedef intptr_t EGLNativeWindowType;
-#define EGL_DEFAULT_DISPLAY NULL
-
-static const EGLint gl_renderer_opaque_attribs[];
-static const EGLint gl_renderer_alpha_attribs[];
-
-inline static int
-gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
- const EGLint *attribs, const EGLint *visual_id)
-{
- return -1;
-}
-
-inline static EGLDisplay
-gl_renderer_display(struct weston_compositor *ec)
-{
- return 0;
-}
-
-inline static int
-gl_renderer_output_create(struct weston_output *output,
- EGLNativeWindowType window)
-{
- return -1;
-}
-
-inline static void
-gl_renderer_output_destroy(struct weston_output *output)
-{
-}
-
-inline static EGLSurface
-gl_renderer_output_surface(struct weston_output *output)
-{
- return 0;
-}
-
-inline static void
-gl_renderer_set_border(struct weston_compositor *ec, int32_t width, int32_t height, void *data,
- int32_t *edges)
-{
-}
-
-inline static void
-gl_renderer_print_egl_error_state(void)
-{
-}
+#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0)
#endif
+
+enum gl_renderer_border_side {
+ GL_RENDERER_BORDER_TOP = 0,
+ GL_RENDERER_BORDER_LEFT = 1,
+ GL_RENDERER_BORDER_RIGHT = 2,
+ GL_RENDERER_BORDER_BOTTOM = 3,
+};
+
+struct gl_renderer_interface {
+ const EGLint *opaque_attribs;
+ const EGLint *alpha_attribs;
+
+ int (*create)(struct weston_compositor *ec,
+ EGLNativeDisplayType display,
+ const EGLint *attribs,
+ const EGLint *visual_id);
+
+ EGLDisplay (*display)(struct weston_compositor *ec);
+
+ int (*output_create)(struct weston_output *output,
+ EGLNativeWindowType window);
+
+ void (*output_destroy)(struct weston_output *output);
+
+ EGLSurface (*output_surface)(struct weston_output *output);
+
+ /* Sets the output border.
+ *
+ * The side specifies the side for which we are setting the border.
+ * The width and height are the width and height of the border.
+ * The tex_width patemeter specifies the width of the actual
+ * texture; this may be larger than width if the data is not
+ * tightly packed.
+ *
+ * The top and bottom textures will extend over the sides to the
+ * full width of the bordered window while. The right and left
+ * edges, however, will extend only to the top and bottom of the
+ * compositor surface. This is demonstrated by the picture below:
+ *
+ * +-----------------------+
+ * | TOP |
+ * +-+-------------------+-+
+ * | | | |
+ * |L| |R|
+ * |E| |I|
+ * |F| |G|
+ * |T| |H|
+ * | | |T|
+ * | | | |
+ * +-+-------------------+-+
+ * | BOTTOM |
+ * +-----------------------+
+ */
+ void (*output_set_border)(struct weston_output *output,
+ enum gl_renderer_border_side side,
+ int32_t width, int32_t height,
+ int32_t tex_width, unsigned char *data);
+
+ void (*print_egl_error_state)(void);
+};
+
+struct gl_renderer_interface gl_renderer_interface;
diff --git a/src/input.c b/src/input.c
index dd8e4973..157066cc 100644
--- a/src/input.c
+++ b/src/input.c
@@ -29,6 +29,7 @@
#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
+#include <limits.h>
#include "../shared/os-compatibility.h"
#include "compositor.h"
@@ -71,6 +72,56 @@ weston_compositor_idle_release(struct weston_compositor *compositor)
}
static void
+pointer_focus_view_destroyed(struct wl_listener *listener, void *data)
+{
+ struct weston_pointer *pointer =
+ container_of(listener, struct weston_pointer,
+ focus_view_listener);
+
+ weston_pointer_set_focus(pointer, NULL, 0, 0);
+}
+
+static void
+pointer_focus_resource_destroyed(struct wl_listener *listener, void *data)
+{
+ struct weston_pointer *pointer =
+ container_of(listener, struct weston_pointer,
+ focus_resource_listener);
+
+ weston_pointer_set_focus(pointer, NULL, 0, 0);
+}
+
+static void
+keyboard_focus_resource_destroyed(struct wl_listener *listener, void *data)
+{
+ struct weston_keyboard *keyboard =
+ container_of(listener, struct weston_keyboard,
+ focus_resource_listener);
+
+ weston_keyboard_set_focus(keyboard, NULL);
+}
+
+static void
+touch_focus_view_destroyed(struct wl_listener *listener, void *data)
+{
+ struct weston_touch *touch =
+ container_of(listener, struct weston_touch,
+ focus_view_listener);
+
+ weston_touch_set_focus(touch->seat, NULL);
+}
+
+static void
+touch_focus_resource_destroyed(struct wl_listener *listener, void *data)
+{
+ struct weston_touch *touch =
+ container_of(listener, struct weston_touch,
+ focus_resource_listener);
+
+ weston_touch_set_focus(touch->seat, NULL);
+}
+
+static void
move_resources(struct wl_list *destination, struct wl_list *source)
{
wl_list_insert_list(destination, source);
@@ -93,47 +144,50 @@ move_resources_for_client(struct wl_list *destination,
}
static void
-default_grab_focus(struct weston_pointer_grab *grab)
+default_grab_pointer_focus(struct weston_pointer_grab *grab)
{
struct weston_pointer *pointer = grab->pointer;
- struct weston_surface *surface;
+ struct weston_view *view;
wl_fixed_t sx, sy;
if (pointer->button_count > 0)
return;
- surface = weston_compositor_pick_surface(pointer->seat->compositor,
- pointer->x, pointer->y,
- &sx, &sy);
+ view = weston_compositor_pick_view(pointer->seat->compositor,
+ pointer->x, pointer->y,
+ &sx, &sy);
- if (pointer->focus != surface)
- weston_pointer_set_focus(pointer, surface, sx, sy);
+ if (pointer->focus != view)
+ weston_pointer_set_focus(pointer, view, sx, sy);
}
static void
-default_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
+default_grab_pointer_motion(struct weston_pointer_grab *grab, uint32_t time,
+ wl_fixed_t x, wl_fixed_t y)
{
struct weston_pointer *pointer = grab->pointer;
wl_fixed_t sx, sy;
struct wl_list *resource_list;
struct wl_resource *resource;
+ weston_pointer_move(pointer, x, y);
+
resource_list = &pointer->focus_resource_list;
wl_resource_for_each(resource, resource_list) {
- weston_surface_from_global_fixed(pointer->focus,
- pointer->x, pointer->y,
- &sx, &sy);
+ weston_view_from_global_fixed(pointer->focus,
+ pointer->x, pointer->y,
+ &sx, &sy);
wl_pointer_send_motion(resource, time, sx, sy);
}
}
static void
-default_grab_button(struct weston_pointer_grab *grab,
- uint32_t time, uint32_t button, uint32_t state_w)
+default_grab_pointer_button(struct weston_pointer_grab *grab,
+ uint32_t time, uint32_t button, uint32_t state_w)
{
struct weston_pointer *pointer = grab->pointer;
struct weston_compositor *compositor = pointer->seat->compositor;
- struct weston_surface *surface;
+ struct weston_view *view;
struct wl_resource *resource;
uint32_t serial;
enum wl_pointer_button_state state = state_w;
@@ -154,12 +208,11 @@ default_grab_button(struct weston_pointer_grab *grab,
if (pointer->button_count == 0 &&
state == WL_POINTER_BUTTON_STATE_RELEASED) {
- surface = weston_compositor_pick_surface(compositor,
- pointer->x,
- pointer->y,
- &sx, &sy);
+ view = weston_compositor_pick_view(compositor,
+ pointer->x, pointer->y,
+ &sx, &sy);
- weston_pointer_set_focus(pointer, surface, sx, sy);
+ weston_pointer_set_focus(pointer, view, sx, sy);
}
}
@@ -170,9 +223,9 @@ default_grab_pointer_cancel(struct weston_pointer_grab *grab)
static const struct weston_pointer_grab_interface
default_pointer_grab_interface = {
- default_grab_focus,
- default_grab_motion,
- default_grab_button,
+ default_grab_pointer_focus,
+ default_grab_pointer_motion,
+ default_grab_pointer_button,
default_grab_pointer_cancel,
};
@@ -192,7 +245,7 @@ default_grab_touch_down(struct weston_touch_grab *grab, uint32_t time,
serial = wl_display_next_serial(display);
wl_resource_for_each(resource, resource_list)
wl_touch_send_down(resource, serial, time,
- touch->focus->resource,
+ touch->focus->surface->resource,
touch_id, sx, sy);
}
}
@@ -245,8 +298,8 @@ static const struct weston_touch_grab_interface default_touch_grab_interface = {
};
static void
-default_grab_key(struct weston_keyboard_grab *grab,
- uint32_t time, uint32_t key, uint32_t state)
+default_grab_keyboard_key(struct weston_keyboard_grab *grab,
+ uint32_t time, uint32_t key, uint32_t state)
{
struct weston_keyboard *keyboard = grab->keyboard;
struct wl_resource *resource;
@@ -307,10 +360,20 @@ find_resource_for_surface(struct wl_list *list, struct weston_surface *surface)
return wl_resource_find_for_client(list, wl_resource_get_client(surface->resource));
}
+static struct wl_resource *
+find_resource_for_view(struct wl_list *list, struct weston_view *view)
+{
+ if (!view)
+ return NULL;
+
+ return find_resource_for_surface(list, view->surface);
+}
+
static void
-default_grab_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
- uint32_t mods_depressed, uint32_t mods_latched,
- uint32_t mods_locked, uint32_t group)
+default_grab_keyboard_modifiers(struct weston_keyboard_grab *grab,
+ uint32_t serial, uint32_t mods_depressed,
+ uint32_t mods_latched,
+ uint32_t mods_locked, uint32_t group)
{
struct weston_keyboard *keyboard = grab->keyboard;
struct weston_pointer *pointer = grab->keyboard->seat->pointer;
@@ -323,9 +386,10 @@ default_grab_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
wl_keyboard_send_modifiers(resource, serial, mods_depressed,
mods_latched, mods_locked, group);
}
- if (pointer && pointer->focus && pointer->focus != keyboard->focus) {
+ if (pointer && pointer->focus && pointer->focus->surface->resource &&
+ pointer->focus->surface != keyboard->focus) {
struct wl_client *pointer_client =
- wl_resource_get_client(pointer->focus->resource);
+ wl_resource_get_client(pointer->focus->surface->resource);
send_modifiers_to_client_in_list(pointer_client,
&keyboard->resource_list,
serial,
@@ -340,20 +404,21 @@ default_grab_keyboard_cancel(struct weston_keyboard_grab *grab)
static const struct weston_keyboard_grab_interface
default_keyboard_grab_interface = {
- default_grab_key,
- default_grab_modifiers,
+ default_grab_keyboard_key,
+ default_grab_keyboard_modifiers,
default_grab_keyboard_cancel,
};
static void
pointer_unmap_sprite(struct weston_pointer *pointer)
{
- if (weston_surface_is_mapped(pointer->sprite))
- weston_surface_unmap(pointer->sprite);
+ if (weston_surface_is_mapped(pointer->sprite->surface))
+ weston_surface_unmap(pointer->sprite->surface);
wl_list_remove(&pointer->sprite_destroy_listener.link);
- pointer->sprite->configure = NULL;
- pointer->sprite->configure_private = NULL;
+ pointer->sprite->surface->configure = NULL;
+ pointer->sprite->surface->configure_private = NULL;
+ weston_view_destroy(pointer->sprite);
pointer->sprite = NULL;
}
@@ -367,8 +432,14 @@ pointer_handle_sprite_destroy(struct wl_listener *listener, void *data)
pointer->sprite = NULL;
}
+static void
+weston_pointer_reset_state(struct weston_pointer *pointer)
+{
+ pointer->button_count = 0;
+}
+
WL_EXPORT struct weston_pointer *
-weston_pointer_create(void)
+weston_pointer_create(struct weston_seat *seat)
{
struct weston_pointer *pointer;
@@ -378,10 +449,15 @@ weston_pointer_create(void)
wl_list_init(&pointer->resource_list);
wl_list_init(&pointer->focus_resource_list);
- pointer->default_grab.interface = &default_pointer_grab_interface;
+ weston_pointer_set_default_grab(pointer,
+ seat->compositor->default_pointer_grab);
+ wl_list_init(&pointer->focus_resource_listener.link);
+ pointer->focus_resource_listener.notify = pointer_focus_resource_destroyed;
pointer->default_grab.pointer = pointer;
pointer->grab = &pointer->default_grab;
+ wl_signal_init(&pointer->motion_signal);
wl_signal_init(&pointer->focus_signal);
+ wl_list_init(&pointer->focus_view_listener.link);
pointer->sprite_destroy_listener.notify = pointer_handle_sprite_destroy;
@@ -400,9 +476,22 @@ weston_pointer_destroy(struct weston_pointer *pointer)
/* XXX: What about pointer->resource_list? */
+ wl_list_remove(&pointer->focus_resource_listener.link);
+ wl_list_remove(&pointer->focus_view_listener.link);
free(pointer);
}
+void
+weston_pointer_set_default_grab(struct weston_pointer *pointer,
+ const struct weston_pointer_grab_interface *interface)
+{
+ if (interface)
+ pointer->default_grab.interface = interface;
+ else
+ pointer->default_grab.interface =
+ &default_pointer_grab_interface;
+}
+
WL_EXPORT struct weston_keyboard *
weston_keyboard_create(void)
{
@@ -414,6 +503,8 @@ weston_keyboard_create(void)
wl_list_init(&keyboard->resource_list);
wl_list_init(&keyboard->focus_resource_list);
+ wl_list_init(&keyboard->focus_resource_listener.link);
+ keyboard->focus_resource_listener.notify = keyboard_focus_resource_destroyed;
wl_array_init(&keyboard->keys);
keyboard->default_grab.interface = &default_keyboard_grab_interface;
keyboard->default_grab.keyboard = keyboard;
@@ -423,15 +514,36 @@ weston_keyboard_create(void)
return keyboard;
}
+static void
+weston_xkb_info_destroy(struct weston_xkb_info *xkb_info);
+
WL_EXPORT void
weston_keyboard_destroy(struct weston_keyboard *keyboard)
{
/* XXX: What about keyboard->resource_list? */
+#ifdef ENABLE_XKBCOMMON
+ if (keyboard->seat->compositor->use_xkbcommon) {
+ if (keyboard->xkb_state.state != NULL)
+ xkb_state_unref(keyboard->xkb_state.state);
+ if (keyboard->xkb_info)
+ weston_xkb_info_destroy(keyboard->xkb_info);
+ if (keyboard->pending_keymap)
+ xkb_keymap_unref(keyboard->pending_keymap);
+ }
+#endif
+
wl_array_release(&keyboard->keys);
+ wl_list_remove(&keyboard->focus_resource_listener.link);
free(keyboard);
}
+static void
+weston_touch_reset_state(struct weston_touch *touch)
+{
+ touch->num_tp = 0;
+}
+
WL_EXPORT struct weston_touch *
weston_touch_create(void)
{
@@ -443,6 +555,10 @@ weston_touch_create(void)
wl_list_init(&touch->resource_list);
wl_list_init(&touch->focus_resource_list);
+ wl_list_init(&touch->focus_view_listener.link);
+ touch->focus_view_listener.notify = touch_focus_view_destroyed;
+ wl_list_init(&touch->focus_resource_listener.link);
+ touch->focus_resource_listener.notify = touch_focus_resource_destroyed;
touch->default_grab.interface = &default_touch_grab_interface;
touch->default_grab.touch = touch;
touch->grab = &touch->default_grab;
@@ -456,6 +572,8 @@ weston_touch_destroy(struct weston_touch *touch)
{
/* XXX: What about touch->resource_list? */
+ wl_list_remove(&touch->focus_view_listener.link);
+ wl_list_remove(&touch->focus_resource_listener.link);
free(touch);
}
@@ -479,7 +597,7 @@ seat_send_updated_caps(struct weston_seat *seat)
WL_EXPORT void
weston_pointer_set_focus(struct weston_pointer *pointer,
- struct weston_surface *surface,
+ struct weston_view *view,
wl_fixed_t sx, wl_fixed_t sy)
{
struct weston_keyboard *kbd = pointer->seat->keyboard;
@@ -487,27 +605,33 @@ weston_pointer_set_focus(struct weston_pointer *pointer,
struct wl_display *display = pointer->seat->compositor->wl_display;
uint32_t serial;
struct wl_list *focus_resource_list;
+ int different_surface = 0;
+
+ if ((!pointer->focus && view) ||
+ (pointer->focus && !view) ||
+ (pointer->focus && pointer->focus->surface != view->surface))
+ different_surface = 1;
focus_resource_list = &pointer->focus_resource_list;
- if (!wl_list_empty(focus_resource_list) && pointer->focus != surface) {
+ if (!wl_list_empty(focus_resource_list) && different_surface) {
serial = wl_display_next_serial(display);
wl_resource_for_each(resource, focus_resource_list) {
wl_pointer_send_leave(resource, serial,
- pointer->focus->resource);
+ pointer->focus->surface->resource);
}
move_resources(&pointer->resource_list, focus_resource_list);
}
- if (find_resource_for_surface(&pointer->resource_list, surface) &&
- pointer->focus != surface) {
+ if (find_resource_for_view(&pointer->resource_list, view) &&
+ different_surface) {
struct wl_client *surface_client =
- wl_resource_get_client(surface->resource);
+ wl_resource_get_client(view->surface->resource);
serial = wl_display_next_serial(display);
- if (kbd && kbd->focus != pointer->focus)
+ if (kbd && kbd->focus != view->surface)
send_modifiers_to_client_in_list(surface_client,
&kbd->resource_list,
serial,
@@ -520,14 +644,25 @@ weston_pointer_set_focus(struct weston_pointer *pointer,
wl_resource_for_each(resource, focus_resource_list) {
wl_pointer_send_enter(resource,
serial,
- surface->resource,
+ view->surface->resource,
sx, sy);
}
pointer->focus_serial = serial;
}
- pointer->focus = surface;
+ wl_list_remove(&pointer->focus_view_listener.link);
+ wl_list_init(&pointer->focus_view_listener.link);
+ wl_list_remove(&pointer->focus_resource_listener.link);
+ wl_list_init(&pointer->focus_resource_listener.link);
+ if (view)
+ wl_signal_add(&view->destroy_signal, &pointer->focus_view_listener);
+ if (view && view->surface->resource)
+ wl_resource_add_destroy_listener(view->surface->resource,
+ &pointer->focus_resource_listener);
+
+ pointer->focus = view;
+ pointer->focus_view_listener.notify = pointer_focus_view_destroyed;
wl_signal_emit(&pointer->focus_signal, pointer);
}
@@ -584,6 +719,12 @@ weston_keyboard_set_focus(struct weston_keyboard *keyboard,
keyboard->focus_serial = serial;
}
+ wl_list_remove(&keyboard->focus_resource_listener.link);
+ wl_list_init(&keyboard->focus_resource_listener.link);
+ if (surface && surface->resource)
+ wl_resource_add_destroy_listener(surface->resource,
+ &keyboard->focus_resource_listener);
+
keyboard->focus = surface;
wl_signal_emit(&keyboard->focus_signal, keyboard);
}
@@ -651,6 +792,28 @@ weston_touch_cancel_grab(struct weston_touch *touch)
touch->grab->interface->cancel(touch->grab);
}
+static void
+weston_pointer_clamp_for_output(struct weston_pointer *pointer,
+ struct weston_output *output,
+ wl_fixed_t *fx, wl_fixed_t *fy)
+{
+ int x, y;
+
+ x = wl_fixed_to_int(*fx);
+ y = wl_fixed_to_int(*fy);
+
+ if (x < output->x)
+ *fx = wl_fixed_from_int(output->x);
+ else if (x >= output->x + output->width)
+ *fx = wl_fixed_from_int(output->x +
+ output->width - 1);
+ if (y < output->y)
+ *fy = wl_fixed_from_int(output->y);
+ else if (y >= output->y + output->height)
+ *fy = wl_fixed_from_int(output->y +
+ output->height - 1);
+}
+
WL_EXPORT void
weston_pointer_clamp(struct weston_pointer *pointer, wl_fixed_t *fx, wl_fixed_t *fy)
{
@@ -677,27 +840,14 @@ weston_pointer_clamp(struct weston_pointer *pointer, wl_fixed_t *fx, wl_fixed_t
if (!prev)
prev = pointer->seat->output;
- if (prev && !valid) {
- if (x < prev->x)
- *fx = wl_fixed_from_int(prev->x);
- else if (x >= prev->x + prev->width)
- *fx = wl_fixed_from_int(prev->x +
- prev->width - 1);
- if (y < prev->y)
- *fy = wl_fixed_from_int(prev->y);
- else if (y >= prev->y + prev->height)
- *fy = wl_fixed_from_int(prev->y +
- prev->height - 1);
- }
+ if (prev && !valid)
+ weston_pointer_clamp_for_output(pointer, prev, fx, fy);
}
/* Takes absolute values */
-static void
-move_pointer(struct weston_seat *seat, wl_fixed_t x, wl_fixed_t y)
+WL_EXPORT void
+weston_pointer_move(struct weston_pointer *pointer, wl_fixed_t x, wl_fixed_t y)
{
- struct weston_compositor *ec = seat->compositor;
- struct weston_pointer *pointer = seat->pointer;
- struct weston_output *output;
int32_t ix, iy;
weston_pointer_clamp (pointer, &x, &y);
@@ -708,18 +858,54 @@ move_pointer(struct weston_seat *seat, wl_fixed_t x, wl_fixed_t y)
ix = wl_fixed_to_int(x);
iy = wl_fixed_to_int(y);
- wl_list_for_each(output, &ec->output_list, link)
- if (output->zoom.active &&
- pixman_region32_contains_point(&output->region,
- ix, iy, NULL))
- weston_output_update_zoom(output, ZOOM_FOCUS_POINTER);
-
if (pointer->sprite) {
- weston_surface_set_position(pointer->sprite,
- ix - pointer->hotspot_x,
- iy - pointer->hotspot_y);
- weston_surface_schedule_repaint(pointer->sprite);
+ weston_view_set_position(pointer->sprite,
+ ix - pointer->hotspot_x,
+ iy - pointer->hotspot_y);
+ weston_view_schedule_repaint(pointer->sprite);
}
+
+ pointer->grab->interface->focus(pointer->grab);
+ wl_signal_emit(&pointer->motion_signal, pointer);
+}
+
+/** Verify if the pointer is in a valid position and move it if it isn't.
+ */
+WL_EXPORT void
+weston_pointer_verify(struct weston_pointer *pointer)
+{
+ struct weston_compositor *ec = pointer->seat->compositor;
+ struct weston_output *output, *closest = NULL;
+ int x, y, distance, min = INT_MAX;
+ wl_fixed_t fx, fy;
+
+ x = wl_fixed_to_int(pointer->x);
+ y = wl_fixed_to_int(pointer->y);
+
+ wl_list_for_each(output, &ec->output_list, link) {
+ if (pixman_region32_contains_point(&output->region,
+ x, y, NULL))
+ return;
+
+ /* Aproximante the distance from the pointer to the center of
+ * the output. */
+ distance = abs(output->x + output->width / 2 - x) +
+ abs(output->y + output->height / 2 - y);
+ if (distance < min) {
+ min = distance;
+ closest = output;
+ }
+ }
+
+ /* Nothing to do if there's no output left. */
+ if (!closest)
+ return;
+
+ fx = pointer->x;
+ fy = pointer->y;
+
+ weston_pointer_clamp_for_output(pointer, closest, &fx, &fy);
+ weston_pointer_move(pointer, fx, fy);
}
WL_EXPORT void
@@ -730,11 +916,43 @@ notify_motion(struct weston_seat *seat,
struct weston_pointer *pointer = seat->pointer;
weston_compositor_wake(ec);
+ pointer->grab->interface->motion(pointer->grab, time, pointer->x + dx, pointer->y + dy);
+}
- move_pointer(seat, pointer->x + dx, pointer->y + dy);
+static void
+run_modifier_bindings(struct weston_seat *seat, uint32_t old, uint32_t new)
+{
+ struct weston_compositor *compositor = seat->compositor;
+ struct weston_keyboard *keyboard = seat->keyboard;
+ uint32_t diff;
+ unsigned int i;
+ struct {
+ uint32_t xkb;
+ enum weston_keyboard_modifier weston;
+ } mods[] = {
+ { keyboard->xkb_info->ctrl_mod, MODIFIER_CTRL },
+ { keyboard->xkb_info->alt_mod, MODIFIER_ALT },
+ { keyboard->xkb_info->super_mod, MODIFIER_SUPER },
+ { keyboard->xkb_info->shift_mod, MODIFIER_SHIFT },
+ };
+
+ diff = new & ~old;
+ for (i = 0; i < ARRAY_LENGTH(mods); i++) {
+ if (diff & (1 << mods[i].xkb))
+ weston_compositor_run_modifier_binding(compositor,
+ seat,
+ mods[i].weston,
+ WL_KEYBOARD_KEY_STATE_PRESSED);
+ }
- pointer->grab->interface->focus(pointer->grab);
- pointer->grab->interface->motion(pointer->grab, time);
+ diff = old & ~new;
+ for (i = 0; i < ARRAY_LENGTH(mods); i++) {
+ if (diff & (1 << mods[i].xkb))
+ weston_compositor_run_modifier_binding(compositor,
+ seat,
+ mods[i].weston,
+ WL_KEYBOARD_KEY_STATE_RELEASED);
+ }
}
WL_EXPORT void
@@ -745,11 +963,7 @@ notify_motion_absolute(struct weston_seat *seat,
struct weston_pointer *pointer = seat->pointer;
weston_compositor_wake(ec);
-
- move_pointer(seat, x, y);
-
- pointer->grab->interface->focus(pointer->grab);
- pointer->grab->interface->motion(pointer->grab, time);
+ pointer->grab->interface->motion(pointer->grab, time, x, y);
}
WL_EXPORT void
@@ -845,13 +1059,13 @@ notify_modifiers(struct weston_seat *seat, uint32_t serial)
/* Serialize and update our internal state, checking to see if it's
* different to the previous state. */
- mods_depressed = xkb_state_serialize_mods(seat->xkb_state.state,
+ mods_depressed = xkb_state_serialize_mods(keyboard->xkb_state.state,
XKB_STATE_DEPRESSED);
- mods_latched = xkb_state_serialize_mods(seat->xkb_state.state,
+ mods_latched = xkb_state_serialize_mods(keyboard->xkb_state.state,
XKB_STATE_LATCHED);
- mods_locked = xkb_state_serialize_mods(seat->xkb_state.state,
+ mods_locked = xkb_state_serialize_mods(keyboard->xkb_state.state,
XKB_STATE_LOCKED);
- group = xkb_state_serialize_group(seat->xkb_state.state,
+ group = xkb_state_serialize_group(keyboard->xkb_state.state,
XKB_STATE_EFFECTIVE);
if (mods_depressed != seat->keyboard->modifiers.mods_depressed ||
@@ -860,6 +1074,9 @@ notify_modifiers(struct weston_seat *seat, uint32_t serial)
group != seat->keyboard->modifiers.group)
changed = 1;
+ run_modifier_bindings(seat, seat->keyboard->modifiers.mods_depressed,
+ mods_depressed);
+
seat->keyboard->modifiers.mods_depressed = mods_depressed;
seat->keyboard->modifiers.mods_latched = mods_latched;
seat->keyboard->modifiers.mods_locked = mods_locked;
@@ -868,28 +1085,28 @@ notify_modifiers(struct weston_seat *seat, uint32_t serial)
/* And update the modifier_state for bindings. */
mods_lookup = mods_depressed | mods_latched;
seat->modifier_state = 0;
- if (mods_lookup & (1 << seat->xkb_info->ctrl_mod))
+ if (mods_lookup & (1 << keyboard->xkb_info->ctrl_mod))
seat->modifier_state |= MODIFIER_CTRL;
- if (mods_lookup & (1 << seat->xkb_info->alt_mod))
+ if (mods_lookup & (1 << keyboard->xkb_info->alt_mod))
seat->modifier_state |= MODIFIER_ALT;
- if (mods_lookup & (1 << seat->xkb_info->super_mod))
+ if (mods_lookup & (1 << keyboard->xkb_info->super_mod))
seat->modifier_state |= MODIFIER_SUPER;
- if (mods_lookup & (1 << seat->xkb_info->shift_mod))
+ if (mods_lookup & (1 << keyboard->xkb_info->shift_mod))
seat->modifier_state |= MODIFIER_SHIFT;
/* Finally, notify the compositor that LEDs have changed. */
- if (xkb_state_led_index_is_active(seat->xkb_state.state,
- seat->xkb_info->num_led))
+ if (xkb_state_led_index_is_active(keyboard->xkb_state.state,
+ keyboard->xkb_info->num_led))
leds |= LED_NUM_LOCK;
- if (xkb_state_led_index_is_active(seat->xkb_state.state,
- seat->xkb_info->caps_led))
+ if (xkb_state_led_index_is_active(keyboard->xkb_state.state,
+ keyboard->xkb_info->caps_led))
leds |= LED_CAPS_LOCK;
- if (xkb_state_led_index_is_active(seat->xkb_state.state,
- seat->xkb_info->scroll_led))
+ if (xkb_state_led_index_is_active(keyboard->xkb_state.state,
+ keyboard->xkb_info->scroll_led))
leds |= LED_SCROLL_LOCK;
- if (leds != seat->xkb_state.leds && seat->led_update)
+ if (leds != keyboard->xkb_state.leds && seat->led_update)
seat->led_update(seat, leds);
- seat->xkb_state.leds = leds;
+ keyboard->xkb_state.leds = leds;
if (changed) {
grab->interface->modifiers(grab,
@@ -905,6 +1122,7 @@ static void
update_modifier_state(struct weston_seat *seat, uint32_t serial, uint32_t key,
enum wl_keyboard_key_state state)
{
+ struct weston_keyboard *keyboard = seat->keyboard;
enum xkb_key_direction direction;
/* Keyboard modifiers don't exist in raw keyboard mode */
@@ -918,10 +1136,91 @@ update_modifier_state(struct weston_seat *seat, uint32_t serial, uint32_t key,
/* Offset the keycode by 8, as the evdev XKB rules reflect X's
* broken keycode system, which starts at 8. */
- xkb_state_update_key(seat->xkb_state.state, key + 8, direction);
+ xkb_state_update_key(keyboard->xkb_state.state, key + 8, direction);
notify_modifiers(seat, serial);
}
+
+static void
+send_keymap(struct wl_resource *resource, struct weston_xkb_info *xkb_info)
+{
+ wl_keyboard_send_keymap(resource,
+ WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
+ xkb_info->keymap_fd,
+ xkb_info->keymap_size);
+}
+
+static void
+send_modifiers(struct wl_resource *resource, uint32_t serial, struct weston_keyboard *keyboard)
+{
+ wl_keyboard_send_modifiers(resource, serial,
+ keyboard->modifiers.mods_depressed,
+ keyboard->modifiers.mods_latched,
+ keyboard->modifiers.mods_locked,
+ keyboard->modifiers.group);
+}
+
+static struct weston_xkb_info *
+weston_xkb_info_create(struct xkb_keymap *keymap);
+
+static void
+update_keymap(struct weston_seat *seat)
+{
+ struct weston_keyboard *keyboard = seat->keyboard;
+ struct wl_resource *resource;
+ struct weston_xkb_info *xkb_info;
+ struct xkb_state *state;
+ xkb_mod_mask_t latched_mods;
+ xkb_mod_mask_t locked_mods;
+
+ xkb_info = weston_xkb_info_create(keyboard->pending_keymap);
+
+ xkb_keymap_unref(keyboard->pending_keymap);
+ keyboard->pending_keymap = NULL;
+
+ if (!xkb_info) {
+ weston_log("failed to create XKB info\n");
+ return;
+ }
+
+ state = xkb_state_new(xkb_info->keymap);
+ if (!state) {
+ weston_log("failed to initialise XKB state\n");
+ weston_xkb_info_destroy(xkb_info);
+ return;
+ }
+
+ latched_mods = xkb_state_serialize_mods(keyboard->xkb_state.state,
+ XKB_STATE_MODS_LATCHED);
+ locked_mods = xkb_state_serialize_mods(keyboard->xkb_state.state,
+ XKB_STATE_MODS_LOCKED);
+ xkb_state_update_mask(state,
+ 0, /* depressed */
+ latched_mods,
+ locked_mods,
+ 0, 0, 0);
+
+ weston_xkb_info_destroy(keyboard->xkb_info);
+ keyboard->xkb_info = xkb_info;
+
+ xkb_state_unref(keyboard->xkb_state.state);
+ keyboard->xkb_state.state = state;
+
+ wl_resource_for_each(resource, &seat->keyboard->resource_list)
+ send_keymap(resource, xkb_info);
+ wl_resource_for_each(resource, &seat->keyboard->focus_resource_list)
+ send_keymap(resource, xkb_info);
+
+ notify_modifiers(seat, wl_display_next_serial(seat->compositor->wl_display));
+
+ if (!latched_mods && !locked_mods)
+ return;
+
+ wl_resource_for_each(resource, &seat->keyboard->resource_list)
+ send_modifiers(resource, wl_display_get_serial(seat->compositor->wl_display), seat->keyboard);
+ wl_resource_for_each(resource, &seat->keyboard->focus_resource_list)
+ send_modifiers(resource, wl_display_get_serial(seat->compositor->wl_display), seat->keyboard);
+}
#else
WL_EXPORT void
notify_modifiers(struct weston_seat *seat, uint32_t serial)
@@ -933,6 +1232,11 @@ update_modifier_state(struct weston_seat *seat, uint32_t serial, uint32_t key,
enum wl_keyboard_key_state state)
{
}
+
+static void
+update_keymap(struct weston_seat *seat)
+{
+}
#endif
WL_EXPORT void
@@ -942,8 +1246,7 @@ notify_key(struct weston_seat *seat, uint32_t time, uint32_t key,
{
struct weston_compositor *compositor = seat->compositor;
struct weston_keyboard *keyboard = seat->keyboard;
- struct weston_surface *focus =
- (struct weston_surface *) keyboard->focus;
+ struct weston_surface *focus = keyboard->focus;
struct weston_keyboard_grab *grab = keyboard->grab;
uint32_t serial = wl_display_next_serial(compositor->wl_display);
uint32_t *k, *end;
@@ -983,6 +1286,10 @@ notify_key(struct weston_seat *seat, uint32_t time, uint32_t key,
grab->interface->key(grab, time, key, state);
+ if (keyboard->pending_keymap &&
+ keyboard->keys.size == 0)
+ update_keymap(seat);
+
if (update_state == STATE_UPDATE_AUTOMATIC) {
update_modifier_state(seat,
wl_display_get_serial(compositor->wl_display),
@@ -995,13 +1302,9 @@ WL_EXPORT void
notify_pointer_focus(struct weston_seat *seat, struct weston_output *output,
wl_fixed_t x, wl_fixed_t y)
{
- struct weston_compositor *compositor = seat->compositor;
-
if (output) {
- move_pointer(seat, x, y);
- compositor->focus = 1;
+ weston_pointer_move(seat->pointer, x, y);
} else {
- compositor->focus = 0;
/* FIXME: We should call weston_pointer_set_focus(seat,
* NULL) here, but somehow that breaks re-entry... */
}
@@ -1077,31 +1380,44 @@ notify_keyboard_focus_out(struct weston_seat *seat)
weston_keyboard_set_focus(keyboard, NULL);
weston_keyboard_cancel_grab(keyboard);
+ if (seat->pointer)
+ weston_pointer_cancel_grab(seat->pointer);
}
WL_EXPORT void
-weston_touch_set_focus(struct weston_seat *seat, struct weston_surface *surface)
+weston_touch_set_focus(struct weston_seat *seat, struct weston_view *view)
{
struct wl_list *focus_resource_list;
focus_resource_list = &seat->touch->focus_resource_list;
- if (seat->touch->focus == surface)
+ if (view && seat->touch->focus &&
+ seat->touch->focus->surface == view->surface) {
+ seat->touch->focus = view;
return;
+ }
+
+ wl_list_remove(&seat->touch->focus_resource_listener.link);
+ wl_list_init(&seat->touch->focus_resource_listener.link);
+ wl_list_remove(&seat->touch->focus_view_listener.link);
+ wl_list_init(&seat->touch->focus_view_listener.link);
if (!wl_list_empty(focus_resource_list)) {
move_resources(&seat->touch->resource_list,
focus_resource_list);
}
- if (surface) {
+ if (view) {
struct wl_client *surface_client =
- wl_resource_get_client(surface->resource);
+ wl_resource_get_client(view->surface->resource);
move_resources_for_client(focus_resource_list,
&seat->touch->resource_list,
surface_client);
+ wl_resource_add_destroy_listener(view->surface->resource,
+ &seat->touch->focus_resource_listener);
+ wl_signal_add(&view->destroy_signal, &seat->touch->focus_view_listener);
}
- seat->touch->focus = surface;
+ seat->touch->focus = view;
}
/**
@@ -1119,7 +1435,7 @@ notify_touch(struct weston_seat *seat, uint32_t time, int touch_id,
struct weston_compositor *ec = seat->compositor;
struct weston_touch *touch = seat->touch;
struct weston_touch_grab *grab = touch->grab;
- struct weston_surface *es;
+ struct weston_view *ev;
wl_fixed_t sx, sy;
/* Update grab's global coordinates. */
@@ -1132,28 +1448,28 @@ notify_touch(struct weston_seat *seat, uint32_t time, int touch_id,
case WL_TOUCH_DOWN:
weston_compositor_idle_inhibit(ec);
- seat->num_tp++;
+ touch->num_tp++;
- /* the first finger down picks the surface, and all further go
- * to that surface for the remainder of the touch session i.e.
+ /* the first finger down picks the view, and all further go
+ * to that view for the remainder of the touch session i.e.
* until all touch points are up again. */
- if (seat->num_tp == 1) {
- es = weston_compositor_pick_surface(ec, x, y, &sx, &sy);
- weston_touch_set_focus(seat, es);
+ if (touch->num_tp == 1) {
+ ev = weston_compositor_pick_view(ec, x, y, &sx, &sy);
+ weston_touch_set_focus(seat, ev);
} else if (touch->focus) {
- es = (struct weston_surface *) touch->focus;
- weston_surface_from_global_fixed(es, x, y, &sx, &sy);
+ ev = touch->focus;
+ weston_view_from_global_fixed(ev, x, y, &sx, &sy);
} else {
/* Unexpected condition: We have non-initial touch but
* there is no focused surface.
*/
weston_log("touch event received with %d points down"
- "but no surface focused\n", seat->num_tp);
+ "but no surface focused\n", touch->num_tp);
return;
}
grab->interface->down(grab, time, touch_id, sx, sy);
- if (seat->num_tp == 1) {
+ if (touch->num_tp == 1) {
touch->grab_serial =
wl_display_get_serial(ec->wl_display);
touch->grab_touch_id = touch_id;
@@ -1164,19 +1480,27 @@ notify_touch(struct weston_seat *seat, uint32_t time, int touch_id,
break;
case WL_TOUCH_MOTION:
- es = (struct weston_surface *) touch->focus;
- if (!es)
+ ev = touch->focus;
+ if (!ev)
break;
- weston_surface_from_global_fixed(es, x, y, &sx, &sy);
+ weston_view_from_global_fixed(ev, x, y, &sx, &sy);
grab->interface->motion(grab, time, touch_id, sx, sy);
break;
case WL_TOUCH_UP:
+ if (touch->num_tp == 0) {
+ /* This can happen if we start out with one or
+ * more fingers on the touch screen, in which
+ * case we didn't get the corresponding down
+ * event. */
+ weston_log("unmatched touch up event\n");
+ break;
+ }
weston_compositor_idle_release(ec);
- seat->num_tp--;
+ touch->num_tp--;
grab->interface->up(grab, time, touch_id);
- if (seat->num_tp == 0)
+ if (touch->num_tp == 0)
weston_touch_set_focus(seat, NULL);
break;
}
@@ -1186,15 +1510,15 @@ notify_touch(struct weston_seat *seat, uint32_t time, int touch_id,
static void
pointer_cursor_surface_configure(struct weston_surface *es,
- int32_t dx, int32_t dy, int32_t width, int32_t height)
+ int32_t dx, int32_t dy)
{
struct weston_pointer *pointer = es->configure_private;
int x, y;
- if (width == 0)
+ if (es->width == 0)
return;
- assert(es == pointer->sprite);
+ assert(es == pointer->sprite->surface);
pointer->hotspot_x -= dx;
pointer->hotspot_y -= dy;
@@ -1202,14 +1526,14 @@ pointer_cursor_surface_configure(struct weston_surface *es,
x = wl_fixed_to_int(pointer->x) - pointer->hotspot_x;
y = wl_fixed_to_int(pointer->y) - pointer->hotspot_y;
- weston_surface_configure(pointer->sprite, x, y, width, height);
+ weston_view_set_position(pointer->sprite, x, y);
empty_region(&es->pending.input);
if (!weston_surface_is_mapped(es)) {
- wl_list_insert(&es->compositor->cursor_layer.surface_list,
- &es->layer_link);
- weston_surface_update_transform(es);
+ wl_list_insert(&es->compositor->cursor_layer.view_list,
+ &pointer->sprite->layer_link);
+ weston_view_update_transform(pointer->sprite);
}
}
@@ -1226,17 +1550,17 @@ pointer_set_cursor(struct wl_client *client, struct wl_resource *resource,
if (pointer->focus == NULL)
return;
- /* pointer->focus->resource can be NULL. Surfaces like the
+ /* pointer->focus->surface->resource can be NULL. Surfaces like the
black_surface used in shell.c for fullscreen don't have
a resource, but can still have focus */
- if (pointer->focus->resource == NULL)
+ if (pointer->focus->surface->resource == NULL)
return;
- if (wl_resource_get_client(pointer->focus->resource) != client)
+ if (wl_resource_get_client(pointer->focus->surface->resource) != client)
return;
if (pointer->focus_serial - serial > UINT32_MAX / 2)
return;
- if (surface && surface != pointer->sprite) {
+ if (surface && pointer->sprite && surface != pointer->sprite->surface) {
if (surface->configure) {
wl_resource_post_error(surface->resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
@@ -1257,13 +1581,12 @@ pointer_set_cursor(struct wl_client *client, struct wl_resource *resource,
surface->configure = pointer_cursor_surface_configure;
surface->configure_private = pointer;
- pointer->sprite = surface;
+ pointer->sprite = weston_view_create(surface);
pointer->hotspot_x = x;
pointer->hotspot_y = y;
if (surface->buffer_ref.buffer)
- pointer_cursor_surface_configure(surface, 0, 0, weston_surface_buffer_width(surface),
- weston_surface_buffer_height(surface));
+ pointer_cursor_surface_configure(surface, 0, 0);
}
static void
@@ -1301,24 +1624,21 @@ seat_get_pointer(struct wl_client *client, struct wl_resource *resource,
wl_resource_set_implementation(cr, &pointer_interface, seat->pointer,
unbind_resource);
- if (seat->pointer->focus && seat->pointer->focus->resource &&
- wl_resource_get_client(seat->pointer->focus->resource) == client) {
- struct weston_surface *surface;
+ if (seat->pointer->focus && seat->pointer->focus->surface->resource &&
+ wl_resource_get_client(seat->pointer->focus->surface->resource) == client) {
wl_fixed_t sx, sy;
- surface = (struct weston_surface *) seat->pointer->focus;
- weston_surface_from_global_fixed(surface,
- seat->pointer->x,
- seat->pointer->y,
- &sx,
- &sy);
+ weston_view_from_global_fixed(seat->pointer->focus,
+ seat->pointer->x,
+ seat->pointer->y,
+ &sx, &sy);
wl_list_remove(wl_resource_get_link(cr));
wl_list_insert(&seat->pointer->focus_resource_list,
wl_resource_get_link(cr));
wl_pointer_send_enter(cr,
seat->pointer->focus_serial,
- surface->resource,
+ seat->pointer->focus->surface->resource,
sx, sy);
}
}
@@ -1339,12 +1659,14 @@ should_send_modifiers_to_client(struct weston_seat *seat,
{
if (seat->keyboard &&
seat->keyboard->focus &&
+ seat->keyboard->focus->resource &&
wl_resource_get_client(seat->keyboard->focus->resource) == client)
return 1;
if (seat->pointer &&
seat->pointer->focus &&
- wl_resource_get_client(seat->pointer->focus->resource) == client)
+ seat->pointer->focus->surface->resource &&
+ wl_resource_get_client(seat->pointer->focus->surface->resource) == client)
return 1;
return 0;
@@ -1355,6 +1677,7 @@ seat_get_keyboard(struct wl_client *client, struct wl_resource *resource,
uint32_t id)
{
struct weston_seat *seat = wl_resource_get_user_data(resource);
+ struct weston_keyboard *keyboard = seat->keyboard;
struct wl_resource *cr;
if (!seat->keyboard)
@@ -1376,8 +1699,8 @@ seat_get_keyboard(struct wl_client *client, struct wl_resource *resource,
if (seat->compositor->use_xkbcommon) {
wl_keyboard_send_keymap(cr, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
- seat->xkb_info->keymap_fd,
- seat->xkb_info->keymap_size);
+ keyboard->xkb_info->keymap_fd,
+ keyboard->xkb_info->keymap_size);
} else {
int null_fd = open("/dev/null", O_RDONLY);
wl_keyboard_send_keymap(cr, WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP,
@@ -1441,7 +1764,7 @@ seat_get_touch(struct wl_client *client, struct wl_resource *resource,
}
if (seat->touch->focus &&
- wl_resource_get_client(seat->touch->focus->resource) == client) {
+ wl_resource_get_client(seat->touch->focus->surface->resource) == client) {
wl_list_insert(&seat->touch->resource_list,
wl_resource_get_link(cr));
} else {
@@ -1639,6 +1962,7 @@ weston_compositor_build_global_keymap(struct weston_compositor *ec)
}
ec->xkb_info = weston_xkb_info_create(keymap);
+ xkb_keymap_unref(keymap);
if (ec->xkb_info == NULL)
return -1;
@@ -1658,6 +1982,24 @@ weston_compositor_xkb_destroy(struct weston_compositor *ec)
}
#endif
+WL_EXPORT void
+weston_seat_update_keymap(struct weston_seat *seat, struct xkb_keymap *keymap)
+{
+ if (!seat->keyboard || !keymap)
+ return;
+
+#ifdef ENABLE_XKBCOMMON
+ if (!seat->compositor->use_xkbcommon)
+ return;
+
+ xkb_keymap_unref(seat->keyboard->pending_keymap);
+ seat->keyboard->pending_keymap = xkb_keymap_ref(keymap);
+
+ if (seat->keyboard->keys.size == 0)
+ update_keymap(seat);
+#endif
+}
+
WL_EXPORT int
weston_seat_init_keyboard(struct weston_seat *seat, struct xkb_keymap *keymap)
{
@@ -1670,44 +2012,67 @@ weston_seat_init_keyboard(struct weston_seat *seat, struct xkb_keymap *keymap)
return 0;
}
+ keyboard = weston_keyboard_create();
+ if (keyboard == NULL) {
+ weston_log("failed to allocate weston keyboard struct\n");
+ return -1;
+ }
+
+ seat->keyboard = keyboard;
+ seat->keyboard_device_count = 1;
+ keyboard->seat = seat;
+
#ifdef ENABLE_XKBCOMMON
if (seat->compositor->use_xkbcommon) {
if (keymap != NULL) {
- seat->xkb_info = weston_xkb_info_create(keymap);
- if (seat->xkb_info == NULL)
+ keyboard->xkb_info = weston_xkb_info_create(keymap);
+ if (keyboard->xkb_info == NULL)
return -1;
} else {
if (weston_compositor_build_global_keymap(seat->compositor) < 0)
return -1;
- seat->xkb_info = seat->compositor->xkb_info;
- seat->xkb_info->ref_count++;
+ keyboard->xkb_info = seat->compositor->xkb_info;
+ keyboard->xkb_info->ref_count++;
}
- seat->xkb_state.state = xkb_state_new(seat->xkb_info->keymap);
- if (seat->xkb_state.state == NULL) {
+ keyboard->xkb_state.state = xkb_state_new(keyboard->xkb_info->keymap);
+ if (keyboard->xkb_state.state == NULL) {
weston_log("failed to initialise XKB state\n");
return -1;
}
- seat->xkb_state.leds = 0;
+ keyboard->xkb_state.leds = 0;
}
#endif
- keyboard = weston_keyboard_create();
- if (keyboard == NULL) {
- weston_log("failed to allocate weston keyboard struct\n");
- return -1;
- }
-
- seat->keyboard = keyboard;
- seat->keyboard_device_count = 1;
- keyboard->seat = seat;
-
seat_send_updated_caps(seat);
return 0;
}
+static void
+weston_keyboard_reset_state(struct weston_keyboard *keyboard)
+{
+ struct weston_seat *seat = keyboard->seat;
+ struct xkb_state *state;
+
+#ifdef ENABLE_XKBCOMMON
+ if (seat->compositor->use_xkbcommon) {
+ state = xkb_state_new(keyboard->xkb_info->keymap);
+ if (!state) {
+ weston_log("failed to reset XKB state\n");
+ return;
+ }
+ xkb_state_unref(keyboard->xkb_state.state);
+ keyboard->xkb_state.state = state;
+
+ keyboard->xkb_state.leds = 0;
+ }
+#endif
+
+ seat->modifier_state = 0;
+}
+
WL_EXPORT void
weston_seat_release_keyboard(struct weston_seat *seat)
{
@@ -1715,6 +2080,7 @@ weston_seat_release_keyboard(struct weston_seat *seat)
if (seat->keyboard_device_count == 0) {
weston_keyboard_set_focus(seat->keyboard, NULL);
weston_keyboard_cancel_grab(seat->keyboard);
+ weston_keyboard_reset_state(seat->keyboard);
seat_send_updated_caps(seat);
}
}
@@ -1731,7 +2097,7 @@ weston_seat_init_pointer(struct weston_seat *seat)
return;
}
- pointer = weston_pointer_create();
+ pointer = weston_pointer_create(seat);
if (pointer == NULL)
return;
@@ -1757,6 +2123,7 @@ weston_seat_release_pointer(struct weston_seat *seat)
if (pointer->sprite)
pointer_unmap_sprite(pointer);
+ weston_pointer_reset_state(pointer);
seat_send_updated_caps(seat);
}
}
@@ -1791,6 +2158,7 @@ weston_seat_release_touch(struct weston_seat *seat)
if (seat->touch_device_count == 0) {
weston_touch_set_focus(seat, NULL);
weston_touch_cancel_grab(seat->touch);
+ weston_touch_reset_state(seat->touch);
seat_send_updated_caps(seat);
}
}
@@ -1812,7 +2180,6 @@ weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec,
seat->compositor = ec;
seat->modifier_state = 0;
- seat->num_tp = 0;
seat->seat_name = strdup(seat_name);
wl_list_insert(ec->seat_list.prev, &seat->link);
@@ -1827,15 +2194,6 @@ weston_seat_release(struct weston_seat *seat)
{
wl_list_remove(&seat->link);
-#ifdef ENABLE_XKBCOMMON
- if (seat->compositor->use_xkbcommon) {
- if (seat->xkb_state.state != NULL)
- xkb_state_unref(seat->xkb_state.state);
- if (seat->xkb_info)
- weston_xkb_info_destroy(seat->xkb_info);
- }
-#endif
-
if (seat->pointer)
weston_pointer_destroy(seat->pointer);
if (seat->keyboard)
diff --git a/src/launcher-util.c b/src/launcher-util.c
index 4ce06c4f..1b63458c 100644
--- a/src/launcher-util.c
+++ b/src/launcher-util.c
@@ -40,12 +40,9 @@
#include <linux/kd.h>
#include <linux/major.h>
-#ifdef BUILD_DRM_COMPOSITOR
-#include <xf86drm.h>
-#endif
-
#include "compositor.h"
#include "launcher-util.h"
+#include "logind-util.h"
#include "weston-launch.h"
#define DRM_MAJOR 226
@@ -54,42 +51,55 @@
#define KDSKBMUTE 0x4B51
#endif
-union cmsg_data { unsigned char b[4]; int fd; };
-
-struct weston_launcher {
- struct weston_compositor *compositor;
- int fd;
- struct wl_event_source *source;
+#ifdef HAVE_LIBDRM
- int kb_mode, tty, drm_fd;
- struct wl_event_source *vt_source;
-};
+#include <xf86drm.h>
-#ifdef BUILD_DRM_COMPOSITOR
-static int
-drm_drop_master(int drm_fd)
-{
- return drmDropMaster(drm_fd);
-}
-static int
-drm_set_master(int drm_fd)
-{
- return drmSetMaster(drm_fd);
-}
-static int
-drm_is_master(int drm_fd)
+static inline int
+is_drm_master(int drm_fd)
{
drm_magic_t magic;
return drmGetMagic(drm_fd, &magic) == 0 &&
drmAuthMagic(drm_fd, magic) == 0;
}
+
#else
-static int drm_drop_master(int drm_fd) {return 0;}
-static int drm_set_master(int drm_fd) {return 0;}
-static int drm_is_master(int drm_fd) {return 1;}
+
+static inline int
+drmDropMaster(int drm_fd)
+{
+ return 0;
+}
+
+static inline int
+drmSetMaster(int drm_fd)
+{
+ return 0;
+}
+
+static inline int
+is_drm_master(int drm_fd)
+{
+ return 0;
+}
+
#endif
+
+union cmsg_data { unsigned char b[4]; int fd; };
+
+struct weston_launcher {
+ struct weston_compositor *compositor;
+ struct weston_logind *logind;
+ struct wl_event_loop *loop;
+ int fd;
+ struct wl_event_source *source;
+
+ int kb_mode, tty, drm_fd;
+ struct wl_event_source *vt_source;
+};
+
int
weston_launcher_open(struct weston_launcher *launcher,
const char *path, int flags)
@@ -104,6 +114,9 @@ weston_launcher_open(struct weston_launcher *launcher,
struct weston_launcher_open *message;
struct stat s;
+ if (launcher->logind)
+ return weston_logind_open(launcher->logind, path, flags);
+
if (launcher->fd == -1) {
fd = open(path, flags | O_CLOEXEC);
if (fd == -1)
@@ -116,7 +129,7 @@ weston_launcher_open(struct weston_launcher *launcher,
if (major(s.st_rdev) == DRM_MAJOR) {
launcher->drm_fd = fd;
- if (!drm_is_master(fd)) {
+ if (!is_drm_master(fd)) {
weston_log("drm fd not master\n");
close(fd);
return -1;
@@ -174,10 +187,22 @@ weston_launcher_open(struct weston_launcher *launcher,
}
void
+weston_launcher_close(struct weston_launcher *launcher, int fd)
+{
+ if (launcher->logind)
+ return weston_logind_close(launcher->logind, fd);
+
+ close(fd);
+}
+
+void
weston_launcher_restore(struct weston_launcher *launcher)
{
struct vt_mode mode = { 0 };
+ if (launcher->logind)
+ return weston_logind_restore(launcher->logind);
+
if (ioctl(launcher->tty, KDSKBMUTE, 0) &&
ioctl(launcher->tty, KDSKBMODE, launcher->kb_mode))
weston_log("failed to restore kb mode: %m\n");
@@ -188,7 +213,7 @@ weston_launcher_restore(struct weston_launcher *launcher)
/* We have to drop master before we switch the VT back in
* VT_AUTO, so we don't risk switching to a VT with another
* display server, that will then fail to set drm master. */
- drm_drop_master(launcher->drm_fd);
+ drmDropMaster(launcher->drm_fd);
mode.mode = VT_AUTO;
if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0)
@@ -242,11 +267,11 @@ vt_handler(int signal_number, void *data)
if (compositor->session_active) {
compositor->session_active = 0;
wl_signal_emit(&compositor->session_signal, compositor);
- drm_drop_master(launcher->drm_fd);
+ drmDropMaster(launcher->drm_fd);
ioctl(launcher->tty, VT_RELDISP, 1);
} else {
ioctl(launcher->tty, VT_RELDISP, VT_ACKACQ);
- drm_set_master(launcher->drm_fd);
+ drmSetMaster(launcher->drm_fd);
compositor->session_active = 1;
wl_signal_emit(&compositor->session_signal, compositor);
}
@@ -341,19 +366,25 @@ setup_tty(struct weston_launcher *launcher, int tty)
int
weston_launcher_activate_vt(struct weston_launcher *launcher, int vt)
{
+ if (launcher->logind)
+ return weston_logind_activate_vt(launcher->logind, vt);
+
return ioctl(launcher->tty, VT_ACTIVATE, vt);
}
struct weston_launcher *
-weston_launcher_connect(struct weston_compositor *compositor, int tty)
+weston_launcher_connect(struct weston_compositor *compositor, int tty,
+ const char *seat_id)
{
struct weston_launcher *launcher;
struct wl_event_loop *loop;
+ int r;
launcher = malloc(sizeof *launcher);
if (launcher == NULL)
return NULL;
+ launcher->logind = NULL;
launcher->compositor = compositor;
launcher->drm_fd = -1;
launcher->fd = weston_environment_get_fd("WESTON_LAUNCHER_SOCK");
@@ -368,14 +399,21 @@ weston_launcher_connect(struct weston_compositor *compositor, int tty)
free(launcher);
return NULL;
}
- } else if (geteuid() == 0) {
- if (setup_tty(launcher, tty) == -1) {
- free(launcher);
- return NULL;
- }
} else {
- free(launcher);
- return NULL;
+ r = weston_logind_connect(&launcher->logind, compositor,
+ seat_id, tty);
+ if (r < 0) {
+ launcher->logind = NULL;
+ if (geteuid() == 0) {
+ if (setup_tty(launcher, tty) == -1) {
+ free(launcher);
+ return NULL;
+ }
+ } else {
+ free(launcher);
+ return NULL;
+ }
+ }
}
return launcher;
@@ -384,7 +422,9 @@ weston_launcher_connect(struct weston_compositor *compositor, int tty)
void
weston_launcher_destroy(struct weston_launcher *launcher)
{
- if (launcher->fd != -1) {
+ if (launcher->logind) {
+ weston_logind_destroy(launcher->logind);
+ } else if (launcher->fd != -1) {
close(launcher->fd);
wl_event_source_remove(launcher->source);
} else {
@@ -392,6 +432,8 @@ weston_launcher_destroy(struct weston_launcher *launcher)
wl_event_source_remove(launcher->vt_source);
}
- close(launcher->tty);
+ if (launcher->tty >= 0)
+ close(launcher->tty);
+
free(launcher);
}
diff --git a/src/launcher-util.h b/src/launcher-util.h
index 3e7ceb59..d5b2fc98 100644
--- a/src/launcher-util.h
+++ b/src/launcher-util.h
@@ -30,7 +30,8 @@
struct weston_launcher;
struct weston_launcher *
-weston_launcher_connect(struct weston_compositor *compositor, int tty);
+weston_launcher_connect(struct weston_compositor *compositor, int tty,
+ const char *seat_id);
void
weston_launcher_destroy(struct weston_launcher *launcher);
@@ -39,6 +40,9 @@ int
weston_launcher_open(struct weston_launcher *launcher,
const char *path, int flags);
+void
+weston_launcher_close(struct weston_launcher *launcher, int fd);
+
int
weston_launcher_activate_vt(struct weston_launcher *launcher, int vt);
diff --git a/src/logind-util.c b/src/logind-util.c
new file mode 100644
index 00000000..40d811b4
--- /dev/null
+++ b/src/logind-util.c
@@ -0,0 +1,940 @@
+/*
+ * Copyright © 2013 David Herrmann
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <dbus.h>
+#include <fcntl.h>
+#include <linux/vt.h>
+#include <linux/kd.h>
+#include <linux/major.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/signalfd.h>
+#include <sys/stat.h>
+#include <systemd/sd-login.h>
+#include <unistd.h>
+
+#include "compositor.h"
+#include "dbus.h"
+#include "logind-util.h"
+
+#define DRM_MAJOR 226
+
+#ifndef KDSKBMUTE
+#define KDSKBMUTE 0x4B51
+#endif
+
+struct weston_logind {
+ struct weston_compositor *compositor;
+ char *seat;
+ char *sid;
+ unsigned int vtnr;
+ int vt;
+ int kb_mode;
+ int sfd;
+ struct wl_event_source *sfd_source;
+
+ DBusConnection *dbus;
+ struct wl_event_source *dbus_ctx;
+ char *spath;
+ DBusPendingCall *pending_active;
+};
+
+static int
+weston_logind_take_device(struct weston_logind *wl, uint32_t major,
+ uint32_t minor, bool *paused_out)
+{
+ DBusMessage *m, *reply;
+ bool b;
+ int r, fd;
+ dbus_bool_t paused;
+
+ m = dbus_message_new_method_call("org.freedesktop.login1",
+ wl->spath,
+ "org.freedesktop.login1.Session",
+ "TakeDevice");
+ if (!m)
+ return -ENOMEM;
+
+ b = dbus_message_append_args(m,
+ DBUS_TYPE_UINT32, &major,
+ DBUS_TYPE_UINT32, &minor,
+ DBUS_TYPE_INVALID);
+ if (!b) {
+ r = -ENOMEM;
+ goto err_unref;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(wl->dbus, m,
+ -1, NULL);
+ if (!reply) {
+ r = -ENODEV;
+ goto err_unref;
+ }
+
+ b = dbus_message_get_args(reply, NULL,
+ DBUS_TYPE_UNIX_FD, &fd,
+ DBUS_TYPE_BOOLEAN, &paused,
+ DBUS_TYPE_INVALID);
+ if (!b) {
+ r = -ENODEV;
+ goto err_reply;
+ }
+
+ r = fd;
+ if (paused_out)
+ *paused_out = paused;
+
+err_reply:
+ dbus_message_unref(reply);
+err_unref:
+ dbus_message_unref(m);
+ return r;
+}
+
+static void
+weston_logind_release_device(struct weston_logind *wl, uint32_t major,
+ uint32_t minor)
+{
+ DBusMessage *m;
+ bool b;
+
+ m = dbus_message_new_method_call("org.freedesktop.login1",
+ wl->spath,
+ "org.freedesktop.login1.Session",
+ "ReleaseDevice");
+ if (m) {
+ b = dbus_message_append_args(m,
+ DBUS_TYPE_UINT32, &major,
+ DBUS_TYPE_UINT32, &minor,
+ DBUS_TYPE_INVALID);
+ if (b)
+ dbus_connection_send(wl->dbus, m, NULL);
+ dbus_message_unref(m);
+ }
+}
+
+static void
+weston_logind_pause_device_complete(struct weston_logind *wl, uint32_t major,
+ uint32_t minor)
+{
+ DBusMessage *m;
+ bool b;
+
+ m = dbus_message_new_method_call("org.freedesktop.login1",
+ wl->spath,
+ "org.freedesktop.login1.Session",
+ "PauseDeviceComplete");
+ if (m) {
+ b = dbus_message_append_args(m,
+ DBUS_TYPE_UINT32, &major,
+ DBUS_TYPE_UINT32, &minor,
+ DBUS_TYPE_INVALID);
+ if (b)
+ dbus_connection_send(wl->dbus, m, NULL);
+ dbus_message_unref(m);
+ }
+}
+
+WL_EXPORT int
+weston_logind_open(struct weston_logind *wl, const char *path,
+ int flags)
+{
+ struct stat st;
+ int fl, r, fd;
+
+ r = stat(path, &st);
+ if (r < 0)
+ return -1;
+ if (!S_ISCHR(st.st_mode)) {
+ errno = ENODEV;
+ return -1;
+ }
+
+ fd = weston_logind_take_device(wl, major(st.st_rdev),
+ minor(st.st_rdev), NULL);
+ if (fd < 0)
+ return fd;
+
+ /* Compared to weston_launcher_open() we cannot specify the open-mode
+ * directly. Instead, logind passes us an fd with sane default modes.
+ * For DRM and evdev this means O_RDWR | O_CLOEXEC. If we want
+ * something else, we need to change it afterwards. We currently
+ * only support dropping FD_CLOEXEC and setting O_NONBLOCK. Changing
+ * access-modes is not possible so accept whatever logind passes us. */
+
+ fl = fcntl(fd, F_GETFL);
+ if (fl < 0) {
+ r = -errno;
+ goto err_close;
+ }
+
+ if (flags & O_NONBLOCK)
+ fl |= O_NONBLOCK;
+
+ r = fcntl(fd, F_SETFL, fl);
+ if (r < 0) {
+ r = -errno;
+ goto err_close;
+ }
+
+ fl = fcntl(fd, F_GETFD);
+ if (fl < 0) {
+ r = -errno;
+ goto err_close;
+ }
+
+ if (!(flags & O_CLOEXEC))
+ fl &= ~FD_CLOEXEC;
+
+ r = fcntl(fd, F_SETFD, fl);
+ if (r < 0) {
+ r = -errno;
+ goto err_close;
+ }
+
+ return fd;
+
+err_close:
+ close(fd);
+ weston_logind_release_device(wl, major(st.st_rdev),
+ minor(st.st_rdev));
+ errno = -r;
+ return -1;
+}
+
+WL_EXPORT void
+weston_logind_close(struct weston_logind *wl, int fd)
+{
+ struct stat st;
+ int r;
+
+ r = fstat(fd, &st);
+ if (r < 0) {
+ weston_log("logind: cannot fstat fd: %m\n");
+ return;
+ }
+
+ if (!S_ISCHR(st.st_mode)) {
+ weston_log("logind: invalid device passed\n");
+ return;
+ }
+
+ weston_logind_release_device(wl, major(st.st_rdev),
+ minor(st.st_rdev));
+}
+
+WL_EXPORT void
+weston_logind_restore(struct weston_logind *wl)
+{
+ struct vt_mode mode = { 0 };
+
+ ioctl(wl->vt, KDSETMODE, KD_TEXT);
+ ioctl(wl->vt, KDSKBMUTE, 0);
+ ioctl(wl->vt, KDSKBMODE, wl->kb_mode);
+ mode.mode = VT_AUTO;
+ ioctl(wl->vt, VT_SETMODE, &mode);
+}
+
+WL_EXPORT int
+weston_logind_activate_vt(struct weston_logind *wl, int vt)
+{
+ int r;
+
+ r = ioctl(wl->vt, VT_ACTIVATE, vt);
+ if (r < 0)
+ return -1;
+
+ return 0;
+}
+
+static void
+weston_logind_set_active(struct weston_logind *wl, bool active)
+{
+ if (!wl->compositor->session_active == !active)
+ return;
+
+ wl->compositor->session_active = active;
+
+ wl_signal_emit(&wl->compositor->session_signal,
+ wl->compositor);
+}
+
+static void
+get_active_cb(DBusPendingCall *pending, void *data)
+{
+ struct weston_logind *wl = data;
+ DBusMessage *m;
+ DBusMessageIter iter, sub;
+ int type;
+ dbus_bool_t b;
+
+ dbus_pending_call_unref(wl->pending_active);
+ wl->pending_active = NULL;
+
+ m = dbus_pending_call_steal_reply(pending);
+ if (!m)
+ return;
+
+ type = dbus_message_get_type(m);
+ if (type != DBUS_MESSAGE_TYPE_METHOD_RETURN)
+ goto err_unref;
+
+ if (!dbus_message_iter_init(m, &iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ goto err_unref;
+
+ dbus_message_iter_recurse(&iter, &sub);
+
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
+ goto err_unref;
+
+ dbus_message_iter_get_basic(&sub, &b);
+ if (!b)
+ weston_logind_set_active(wl, false);
+
+err_unref:
+ dbus_message_unref(m);
+}
+
+static void
+weston_logind_get_active(struct weston_logind *wl)
+{
+ DBusPendingCall *pending;
+ DBusMessage *m;
+ bool b;
+ const char *iface, *name;
+
+ m = dbus_message_new_method_call("org.freedesktop.login1",
+ wl->spath,
+ "org.freedesktop.DBus.Properties",
+ "Get");
+ if (!m)
+ return;
+
+ iface = "org.freedesktop.login1.Session";
+ name = "Active";
+ b = dbus_message_append_args(m,
+ DBUS_TYPE_STRING, &iface,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID);
+ if (!b)
+ goto err_unref;
+
+ b = dbus_connection_send_with_reply(wl->dbus, m, &pending, -1);
+ if (!b)
+ goto err_unref;
+
+ b = dbus_pending_call_set_notify(pending, get_active_cb, wl, NULL);
+ if (!b) {
+ dbus_pending_call_cancel(pending);
+ dbus_pending_call_unref(pending);
+ goto err_unref;
+ }
+
+ if (wl->pending_active) {
+ dbus_pending_call_cancel(wl->pending_active);
+ dbus_pending_call_unref(wl->pending_active);
+ }
+ wl->pending_active = pending;
+ return;
+
+err_unref:
+ dbus_message_unref(m);
+}
+
+static void
+disconnected_dbus(struct weston_logind *wl)
+{
+ weston_log("logind: dbus connection lost, exiting..\n");
+ weston_logind_restore(wl);
+ exit(-1);
+}
+
+static void
+session_removed(struct weston_logind *wl, DBusMessage *m)
+{
+ const char *name, *obj;
+ bool r;
+
+ r = dbus_message_get_args(m, NULL,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_OBJECT_PATH, &obj,
+ DBUS_TYPE_INVALID);
+ if (!r) {
+ weston_log("logind: cannot parse SessionRemoved dbus signal\n");
+ return;
+ }
+
+ if (!strcmp(name, wl->sid)) {
+ weston_log("logind: our session got closed, exiting..\n");
+ weston_logind_restore(wl);
+ exit(-1);
+ }
+}
+
+static void
+property_changed(struct weston_logind *wl, DBusMessage *m)
+{
+ DBusMessageIter iter, sub, entry;
+ const char *interface, *name;
+ dbus_bool_t b;
+
+ if (!dbus_message_iter_init(m, &iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ goto error;
+
+ dbus_message_iter_get_basic(&iter, &interface);
+
+ if (!dbus_message_iter_next(&iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+ goto error;
+
+ dbus_message_iter_recurse(&iter, &sub);
+
+ while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY) {
+ dbus_message_iter_recurse(&sub, &entry);
+
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+ goto error;
+
+ dbus_message_iter_get_basic(&entry, &name);
+ if (!dbus_message_iter_next(&entry))
+ goto error;
+
+ if (!strcmp(name, "Active")) {
+ if (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_BOOLEAN) {
+ dbus_message_iter_get_basic(&entry, &b);
+ if (!b)
+ weston_logind_set_active(wl, false);
+ return;
+ }
+ }
+
+ dbus_message_iter_next(&sub);
+ }
+
+ if (!dbus_message_iter_next(&iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+ goto error;
+
+ dbus_message_iter_recurse(&iter, &sub);
+
+ while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
+ dbus_message_iter_get_basic(&sub, &name);
+
+ if (!strcmp(name, "Active")) {
+ weston_logind_get_active(wl);
+ return;
+ }
+
+ dbus_message_iter_next(&sub);
+ }
+
+ return;
+
+error:
+ weston_log("logind: cannot parse PropertiesChanged dbus signal\n");
+}
+
+static void
+device_paused(struct weston_logind *wl, DBusMessage *m)
+{
+ bool r;
+ const char *type;
+ uint32_t major, minor;
+
+ r = dbus_message_get_args(m, NULL,
+ DBUS_TYPE_UINT32, &major,
+ DBUS_TYPE_UINT32, &minor,
+ DBUS_TYPE_STRING, &type,
+ DBUS_TYPE_INVALID);
+ if (!r) {
+ weston_log("logind: cannot parse PauseDevice dbus signal\n");
+ return;
+ }
+
+ /* "pause" means synchronous pausing. Acknowledge it unconditionally
+ * as we support asynchronous device shutdowns, anyway.
+ * "force" means asynchronous pausing.
+ * "gone" means the device is gone. We handle it the same as "force" as
+ * a following udev event will be caught, too.
+ *
+ * If it's our main DRM device, tell the compositor to go asleep. */
+
+ if (!strcmp(type, "pause"))
+ weston_logind_pause_device_complete(wl, major, minor);
+
+ if (major == DRM_MAJOR)
+ weston_logind_set_active(wl, false);
+}
+
+static void
+device_resumed(struct weston_logind *wl, DBusMessage *m)
+{
+ bool r;
+ uint32_t major;
+
+ r = dbus_message_get_args(m, NULL,
+ DBUS_TYPE_UINT32, &major,
+ /*DBUS_TYPE_UINT32, &minor,
+ DBUS_TYPE_UNIX_FD, &fd,*/
+ DBUS_TYPE_INVALID);
+ if (!r) {
+ weston_log("logind: cannot parse ResumeDevice dbus signal\n");
+ return;
+ }
+
+ /* DeviceResumed messages provide us a new file-descriptor for
+ * resumed devices. For DRM devices it's the same as before, for evdev
+ * devices it's a new open-file. As we reopen evdev devices, anyway,
+ * there is no need for us to handle this event for evdev. For DRM, we
+ * notify the compositor to wake up. */
+
+ if (major == DRM_MAJOR)
+ weston_logind_set_active(wl, true);
+}
+
+static DBusHandlerResult
+filter_dbus(DBusConnection *c, DBusMessage *m, void *data)
+{
+ struct weston_logind *wl = data;
+
+ if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) {
+ disconnected_dbus(wl);
+ } else if (dbus_message_is_signal(m, "org.freedesktop.login1.Manager",
+ "SessionRemoved")) {
+ session_removed(wl, m);
+ } else if (dbus_message_is_signal(m, "org.freedesktop.DBus.Properties",
+ "PropertiesChanged")) {
+ property_changed(wl, m);
+ } else if (dbus_message_is_signal(m, "org.freedesktop.login1.Session",
+ "PauseDevice")) {
+ device_paused(wl, m);
+ } else if (dbus_message_is_signal(m, "org.freedesktop.login1.Session",
+ "ResumeDevice")) {
+ device_resumed(wl, m);
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static int
+weston_logind_setup_dbus(struct weston_logind *wl)
+{
+ bool b;
+ int r;
+
+ r = asprintf(&wl->spath, "/org/freedesktop/login1/session/%s",
+ wl->sid);
+ if (r < 0)
+ return -ENOMEM;
+
+ b = dbus_connection_add_filter(wl->dbus, filter_dbus, wl, NULL);
+ if (!b) {
+ weston_log("logind: cannot add dbus filter\n");
+ r = -ENOMEM;
+ goto err_spath;
+ }
+
+ r = weston_dbus_add_match_signal(wl->dbus,
+ "org.freedesktop.login1",
+ "org.freedesktop.login1.Manager",
+ "SessionRemoved",
+ "/org/freedesktop/login1");
+ if (r < 0) {
+ weston_log("logind: cannot add dbus match\n");
+ goto err_spath;
+ }
+
+ r = weston_dbus_add_match_signal(wl->dbus,
+ "org.freedesktop.login1",
+ "org.freedesktop.login1.Session",
+ "PauseDevice",
+ wl->spath);
+ if (r < 0) {
+ weston_log("logind: cannot add dbus match\n");
+ goto err_spath;
+ }
+
+ r = weston_dbus_add_match_signal(wl->dbus,
+ "org.freedesktop.login1",
+ "org.freedesktop.login1.Session",
+ "ResumeDevice",
+ wl->spath);
+ if (r < 0) {
+ weston_log("logind: cannot add dbus match\n");
+ goto err_spath;
+ }
+
+ r = weston_dbus_add_match_signal(wl->dbus,
+ "org.freedesktop.login1",
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ wl->spath);
+ if (r < 0) {
+ weston_log("logind: cannot add dbus match\n");
+ goto err_spath;
+ }
+
+ return 0;
+
+err_spath:
+ /* don't remove any dbus-match as the connection is closed, anyway */
+ free(wl->spath);
+ return r;
+}
+
+static void
+weston_logind_destroy_dbus(struct weston_logind *wl)
+{
+ /* don't remove any dbus-match as the connection is closed, anyway */
+ free(wl->spath);
+}
+
+static int
+weston_logind_take_control(struct weston_logind *wl)
+{
+ DBusError err;
+ DBusMessage *m, *reply;
+ dbus_bool_t force;
+ bool b;
+ int r;
+
+ dbus_error_init(&err);
+
+ m = dbus_message_new_method_call("org.freedesktop.login1",
+ wl->spath,
+ "org.freedesktop.login1.Session",
+ "TakeControl");
+ if (!m)
+ return -ENOMEM;
+
+ force = false;
+ b = dbus_message_append_args(m,
+ DBUS_TYPE_BOOLEAN, &force,
+ DBUS_TYPE_INVALID);
+ if (!b) {
+ r = -ENOMEM;
+ goto err_unref;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(wl->dbus,
+ m, -1, &err);
+ if (!reply) {
+ if (dbus_error_has_name(&err, DBUS_ERROR_UNKNOWN_METHOD))
+ weston_log("logind: old systemd version detected\n");
+ else
+ weston_log("logind: cannot take control over session %s\n", wl->sid);
+
+ dbus_error_free(&err);
+ r = -EIO;
+ goto err_unref;
+ }
+
+ dbus_message_unref(reply);
+ dbus_message_unref(m);
+ return 0;
+
+err_unref:
+ dbus_message_unref(m);
+ return r;
+}
+
+static void
+weston_logind_release_control(struct weston_logind *wl)
+{
+ DBusMessage *m;
+
+ m = dbus_message_new_method_call("org.freedesktop.login1",
+ wl->spath,
+ "org.freedesktop.login1.Session",
+ "ReleaseControl");
+ if (m) {
+ dbus_connection_send(wl->dbus, m, NULL);
+ dbus_message_unref(m);
+ }
+}
+
+static int
+signal_event(int fd, uint32_t mask, void *data)
+{
+ struct weston_logind *wl = data;
+ struct signalfd_siginfo sig;
+
+ if (read(fd, &sig, sizeof sig) != sizeof sig) {
+ weston_log("logind: cannot read signalfd: %m\n");
+ return 0;
+ }
+
+ switch (sig.ssi_signo) {
+ case SIGUSR1:
+ ioctl(wl->vt, VT_RELDISP, 1);
+ break;
+ case SIGUSR2:
+ ioctl(wl->vt, VT_RELDISP, VT_ACKACQ);
+ break;
+ }
+
+ return 0;
+}
+
+static int
+weston_logind_setup_vt(struct weston_logind *wl)
+{
+ struct stat st;
+ char buf[64];
+ struct vt_mode mode = { 0 };
+ int r;
+ sigset_t mask;
+ struct wl_event_loop *loop;
+
+ snprintf(buf, sizeof(buf), "/dev/tty%d", wl->vtnr);
+ buf[sizeof(buf) - 1] = 0;
+
+ wl->vt = open(buf, O_RDWR|O_CLOEXEC|O_NONBLOCK);
+
+ if (wl->vt < 0) {
+ r = -errno;
+ weston_log("logind: cannot open VT %s: %m\n", buf);
+ return r;
+ }
+
+ if (fstat(wl->vt, &st) == -1 ||
+ major(st.st_rdev) != TTY_MAJOR || minor(st.st_rdev) <= 0 ||
+ minor(st.st_rdev) >= 64) {
+ r = -EINVAL;
+ weston_log("logind: TTY %s is no virtual terminal\n", buf);
+ goto err_close;
+ }
+
+ /*r = setsid();
+ if (r < 0 && errno != EPERM) {
+ r = -errno;
+ weston_log("logind: setsid() failed: %m\n");
+ goto err_close;
+ }
+
+ r = ioctl(wl->vt, TIOCSCTTY, 0);
+ if (r < 0)
+ weston_log("logind: VT %s already in use\n", buf);*/
+
+ if (ioctl(wl->vt, KDGKBMODE, &wl->kb_mode) < 0) {
+ weston_log("logind: cannot read keyboard mode on %s: %m\n",
+ buf);
+ wl->kb_mode = K_UNICODE;
+ } else if (wl->kb_mode == K_OFF) {
+ wl->kb_mode = K_UNICODE;
+ }
+
+ if (ioctl(wl->vt, KDSKBMUTE, 1) < 0 &&
+ ioctl(wl->vt, KDSKBMODE, K_OFF) < 0) {
+ r = -errno;
+ weston_log("logind: cannot set K_OFF KB-mode on %s: %m\n",
+ buf);
+ goto err_close;
+ }
+
+ if (ioctl(wl->vt, KDSETMODE, KD_GRAPHICS) < 0) {
+ r = -errno;
+ weston_log("logind: cannot set KD_GRAPHICS mode on %s: %m\n",
+ buf);
+ goto err_kbmode;
+ }
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGUSR1);
+ sigaddset(&mask, SIGUSR2);
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+
+ wl->sfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
+ if (wl->sfd < 0) {
+ r = -errno;
+ weston_log("logind: cannot create signalfd: %m\n");
+ goto err_mode;
+ }
+
+ loop = wl_display_get_event_loop(wl->compositor->wl_display);
+ wl->sfd_source = wl_event_loop_add_fd(loop, wl->sfd,
+ WL_EVENT_READABLE,
+ signal_event, wl);
+ if (!wl->sfd_source) {
+ r = -errno;
+ weston_log("logind: cannot create signalfd source: %m\n");
+ goto err_sfd;
+ }
+
+ mode.mode = VT_PROCESS;
+ mode.relsig = SIGUSR1;
+ mode.acqsig = SIGUSR2;
+ if (ioctl(wl->vt, VT_SETMODE, &mode) < 0) {
+ r = -errno;
+ weston_log("logind: cannot take over VT: %m\n");
+ goto err_sfd_source;
+ }
+
+ weston_log("logind: using VT %s\n", buf);
+ return 0;
+
+err_sfd_source:
+ wl_event_source_remove(wl->sfd_source);
+err_sfd:
+ close(wl->sfd);
+err_mode:
+ ioctl(wl->vt, KDSETMODE, KD_TEXT);
+err_kbmode:
+ ioctl(wl->vt, KDSKBMUTE, 0);
+ ioctl(wl->vt, KDSKBMODE, wl->kb_mode);
+err_close:
+ close(wl->vt);
+ return r;
+}
+
+static void
+weston_logind_destroy_vt(struct weston_logind *wl)
+{
+ weston_logind_restore(wl);
+ wl_event_source_remove(wl->sfd_source);
+ close(wl->sfd);
+ close(wl->vt);
+}
+
+WL_EXPORT int
+weston_logind_connect(struct weston_logind **out,
+ struct weston_compositor *compositor,
+ const char *seat_id, int tty)
+{
+ struct weston_logind *wl;
+ struct wl_event_loop *loop;
+ char *t;
+ int r;
+
+ wl = calloc(1, sizeof(*wl));
+ if (!wl) {
+ r = -ENOMEM;
+ goto err_out;
+ }
+
+ wl->compositor = compositor;
+
+ wl->seat = strdup(seat_id);
+ if (!wl->seat) {
+ r = -ENOMEM;
+ goto err_wl;
+ }
+
+ r = sd_pid_get_session(getpid(), &wl->sid);
+ if (r < 0) {
+ weston_log("logind: not running in a systemd session\n");
+ goto err_seat;
+ }
+
+ t = NULL;
+ r = sd_session_get_seat(wl->sid, &t);
+ if (r < 0) {
+ weston_log("logind: failed to get session seat\n");
+ free(t);
+ goto err_session;
+ } else if (strcmp(seat_id, t)) {
+ weston_log("logind: weston's seat '%s' differs from session-seat '%s'\n",
+ seat_id, t);
+ r = -EINVAL;
+ free(t);
+ goto err_session;
+ }
+ free(t);
+
+ r = weston_sd_session_get_vt(wl->sid, &wl->vtnr);
+ if (r < 0) {
+ weston_log("logind: session not running on a VT\n");
+ goto err_session;
+ } else if (tty > 0 && wl->vtnr != (unsigned int )tty) {
+ weston_log("logind: requested VT --tty=%d differs from real session VT %u\n",
+ tty, wl->vtnr);
+ r = -EINVAL;
+ goto err_session;
+ }
+
+ loop = wl_display_get_event_loop(compositor->wl_display);
+ r = weston_dbus_open(loop, DBUS_BUS_SYSTEM, &wl->dbus, &wl->dbus_ctx);
+ if (r < 0) {
+ weston_log("logind: cannot connect to system dbus\n");
+ goto err_session;
+ }
+
+ r = weston_logind_setup_dbus(wl);
+ if (r < 0)
+ goto err_dbus;
+
+ r = weston_logind_take_control(wl);
+ if (r < 0)
+ goto err_dbus_cleanup;
+
+ r = weston_logind_setup_vt(wl);
+ if (r < 0)
+ goto err_control;
+
+ weston_log("logind: session control granted\n");
+ *out = wl;
+ return 0;
+
+err_control:
+ weston_logind_release_control(wl);
+err_dbus_cleanup:
+ weston_logind_destroy_dbus(wl);
+err_dbus:
+ weston_dbus_close(wl->dbus, wl->dbus_ctx);
+err_session:
+ free(wl->sid);
+err_seat:
+ free(wl->seat);
+err_wl:
+ free(wl);
+err_out:
+ weston_log("logind: cannot setup systemd-logind helper (%d), using legacy fallback\n", r);
+ errno = -r;
+ return -1;
+}
+
+WL_EXPORT void
+weston_logind_destroy(struct weston_logind *wl)
+{
+ if (wl->pending_active) {
+ dbus_pending_call_cancel(wl->pending_active);
+ dbus_pending_call_unref(wl->pending_active);
+ }
+
+ weston_logind_destroy_vt(wl);
+ weston_logind_release_control(wl);
+ weston_logind_destroy_dbus(wl);
+ weston_dbus_close(wl->dbus, wl->dbus_ctx);
+ free(wl->sid);
+ free(wl->seat);
+ free(wl);
+}
diff --git a/src/logind-util.h b/src/logind-util.h
new file mode 100644
index 00000000..552395e7
--- /dev/null
+++ b/src/logind-util.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright © 2013 David Herrmann
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "compositor.h"
+
+struct weston_logind;
+
+#if defined(HAVE_SYSTEMD_LOGIN) && defined(HAVE_DBUS)
+
+#include <systemd/sd-login.h>
+
+int
+weston_logind_open(struct weston_logind *wl, const char *path,
+ int flags);
+
+void
+weston_logind_close(struct weston_logind *wl, int fd);
+
+void
+weston_logind_restore(struct weston_logind *wl);
+
+int
+weston_logind_activate_vt(struct weston_logind *wl, int vt);
+
+int
+weston_logind_connect(struct weston_logind **out,
+ struct weston_compositor *compositor,
+ const char *seat_id, int tty);
+
+void
+weston_logind_destroy(struct weston_logind *wl);
+
+static inline int
+weston_sd_session_get_vt(const char *sid, unsigned int *out)
+{
+#ifdef HAVE_SYSTEMD_LOGIN_209
+ return sd_session_get_vt(sid, out);
+#else
+ int r;
+ char *tty;
+
+ r = sd_session_get_tty(sid, &tty);
+ if (r < 0)
+ return r;
+
+ r = sscanf(tty, "tty%u", out);
+ free(tty);
+
+ if (r != 1)
+ return -EINVAL;
+
+ return 0;
+#endif
+}
+
+#else /* defined(HAVE_SYSTEMD_LOGIN) && defined(HAVE_DBUS) */
+
+static inline int
+weston_logind_open(struct weston_logind *wl, const char *path,
+ int flags)
+{
+ return -ENOSYS;
+}
+
+static inline void
+weston_logind_close(struct weston_logind *wl, int fd)
+{
+}
+
+static inline void
+weston_logind_restore(struct weston_logind *wl)
+{
+}
+
+static inline int
+weston_logind_activate_vt(struct weston_logind *wl, int vt)
+{
+ return -ENOSYS;
+}
+
+static inline int
+weston_logind_connect(struct weston_logind **out,
+ struct weston_compositor *compositor,
+ const char *seat_id, int tty)
+{
+ return -ENOSYS;
+}
+
+static inline void
+weston_logind_destroy(struct weston_logind *wl)
+{
+}
+
+#endif /* defined(HAVE_SYSTEMD_LOGIN) && defined(HAVE_DBUS) */
diff --git a/src/noop-renderer.c b/src/noop-renderer.c
index 91659f58..ad750b5a 100644
--- a/src/noop-renderer.c
+++ b/src/noop-renderer.c
@@ -51,12 +51,6 @@ noop_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
{
}
-static int
-noop_renderer_create_surface(struct weston_surface *surface)
-{
- return 0;
-}
-
static void
noop_renderer_surface_set_color(struct weston_surface *surface,
float red, float green, float blue, float alpha)
@@ -64,11 +58,6 @@ noop_renderer_surface_set_color(struct weston_surface *surface,
}
static void
-noop_renderer_destroy_surface(struct weston_surface *surface)
-{
-}
-
-static void
noop_renderer_destroy(struct weston_compositor *ec)
{
free(ec->renderer);
@@ -88,9 +77,7 @@ noop_renderer_init(struct weston_compositor *ec)
renderer->repaint_output = noop_renderer_repaint_output;
renderer->flush_damage = noop_renderer_flush_damage;
renderer->attach = noop_renderer_attach;
- renderer->create_surface = noop_renderer_create_surface;
renderer->surface_set_color = noop_renderer_surface_set_color;
- renderer->destroy_surface = noop_renderer_destroy_surface;
renderer->destroy = noop_renderer_destroy;
ec->renderer = renderer;
diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c
index 987c5393..26f6f279 100644
--- a/src/pixman-renderer.c
+++ b/src/pixman-renderer.c
@@ -37,14 +37,24 @@ struct pixman_output_state {
};
struct pixman_surface_state {
+ struct weston_surface *surface;
+
pixman_image_t *image;
struct weston_buffer_reference buffer_ref;
+
+ struct wl_listener buffer_destroy_listener;
+ struct wl_listener surface_destroy_listener;
+ struct wl_listener renderer_destroy_listener;
};
struct pixman_renderer {
struct weston_renderer base;
+
int repaint_debug;
pixman_image_t *debug_color;
+ struct weston_binding *debug_binding;
+
+ struct wl_signal destroy_signal;
};
static inline struct pixman_output_state *
@@ -53,9 +63,15 @@ get_output_state(struct weston_output *output)
return (struct pixman_output_state *)output->renderer_state;
}
+static int
+pixman_renderer_create_surface(struct weston_surface *surface);
+
static inline struct pixman_surface_state *
get_surface_state(struct weston_surface *surface)
{
+ if (!surface->renderer_state)
+ pixman_renderer_create_surface(surface);
+
return (struct pixman_surface_state *)surface->renderer_state;
}
@@ -112,127 +128,27 @@ pixman_renderer_read_pixels(struct weston_output *output,
}
static void
-box_scale(pixman_box32_t *dst, int scale)
-{
- dst->x1 *= scale;
- dst->x2 *= scale;
- dst->y1 *= scale;
- dst->y2 *= scale;
-}
-
-static void
-scale_region (pixman_region32_t *region, int scale)
-{
- pixman_box32_t *rects, *scaled_rects;
- int nrects, i;
-
- if (scale != 1) {
- rects = pixman_region32_rectangles(region, &nrects);
- scaled_rects = calloc(nrects, sizeof(pixman_box32_t));
-
- for (i = 0; i < nrects; i++) {
- scaled_rects[i] = rects[i];
- box_scale(&scaled_rects[i], scale);
- }
- pixman_region32_clear(region);
-
- pixman_region32_init_rects (region, scaled_rects, nrects);
- free (scaled_rects);
- }
-}
-
-static void
-transform_region (pixman_region32_t *region, int width, int height, enum wl_output_transform transform)
-{
- pixman_box32_t *rects, *transformed_rects;
- int nrects, i;
-
- if (transform == WL_OUTPUT_TRANSFORM_NORMAL)
- return;
-
- rects = pixman_region32_rectangles(region, &nrects);
- transformed_rects = calloc(nrects, sizeof(pixman_box32_t));
-
- for (i = 0; i < nrects; i++) {
- switch (transform) {
- default:
- case WL_OUTPUT_TRANSFORM_NORMAL:
- transformed_rects[i].x1 = rects[i].x1;
- transformed_rects[i].y1 = rects[i].y1;
- transformed_rects[i].x2 = rects[i].x2;
- transformed_rects[i].y2 = rects[i].y2;
- break;
- case WL_OUTPUT_TRANSFORM_90:
- transformed_rects[i].x1 = height - rects[i].y2;
- transformed_rects[i].y1 = rects[i].x1;
- transformed_rects[i].x2 = height - rects[i].y1;
- transformed_rects[i].y2 = rects[i].x2;
- break;
- case WL_OUTPUT_TRANSFORM_180:
- transformed_rects[i].x1 = width - rects[i].x2;
- transformed_rects[i].y1 = height - rects[i].y2;
- transformed_rects[i].x2 = width - rects[i].x1;
- transformed_rects[i].y2 = height - rects[i].y1;
- break;
- case WL_OUTPUT_TRANSFORM_270:
- transformed_rects[i].x1 = rects[i].y1;
- transformed_rects[i].y1 = width - rects[i].x2;
- transformed_rects[i].x2 = rects[i].y2;
- transformed_rects[i].y2 = width - rects[i].x1;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED:
- transformed_rects[i].x1 = width - rects[i].x2;
- transformed_rects[i].y1 = rects[i].y1;
- transformed_rects[i].x2 = width - rects[i].x1;
- transformed_rects[i].y2 = rects[i].y2;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- transformed_rects[i].x1 = height - rects[i].y2;
- transformed_rects[i].y1 = width - rects[i].x2;
- transformed_rects[i].x2 = height - rects[i].y1;
- transformed_rects[i].y2 = width - rects[i].x1;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_180:
- transformed_rects[i].x1 = rects[i].x1;
- transformed_rects[i].y1 = height - rects[i].y2;
- transformed_rects[i].x2 = rects[i].x2;
- transformed_rects[i].y2 = height - rects[i].y1;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- transformed_rects[i].x1 = rects[i].y1;
- transformed_rects[i].y1 = rects[i].x1;
- transformed_rects[i].x2 = rects[i].y2;
- transformed_rects[i].y2 = rects[i].x2;
- break;
- }
- }
- pixman_region32_clear(region);
-
- pixman_region32_init_rects (region, transformed_rects, nrects);
- free (transformed_rects);
-}
-
-static void
region_global_to_output(struct weston_output *output, pixman_region32_t *region)
{
pixman_region32_translate(region, -output->x, -output->y);
- transform_region (region, output->width, output->height, output->transform);
- scale_region (region, output->current_scale);
+ weston_transformed_region(output->width, output->height,
+ output->transform, output->current_scale,
+ region, region);
}
#define D2F(v) pixman_double_to_fixed((double)v)
static void
-repaint_region(struct weston_surface *es, struct weston_output *output,
+repaint_region(struct weston_view *ev, struct weston_output *output,
pixman_region32_t *region, pixman_region32_t *surf_region,
pixman_op_t pixman_op)
{
struct pixman_renderer *pr =
(struct pixman_renderer *) output->compositor->renderer;
- struct pixman_surface_state *ps = get_surface_state(es);
+ struct pixman_surface_state *ps = get_surface_state(ev->surface);
struct pixman_output_state *po = get_output_state(output);
pixman_region32_t final_region;
- float surface_x, surface_y;
+ float view_x, view_y;
pixman_transform_t transform;
pixman_fixed_t fw, fh;
@@ -246,11 +162,11 @@ repaint_region(struct weston_surface *es, struct weston_output *output,
pixman_region32_copy(&final_region, surf_region);
/* Convert from surface to global coordinates */
- if (!es->transform.enabled) {
- pixman_region32_translate(&final_region, es->geometry.x, es->geometry.y);
+ if (!ev->transform.enabled) {
+ pixman_region32_translate(&final_region, ev->geometry.x, ev->geometry.y);
} else {
- weston_surface_to_global_float(es, 0, 0, &surface_x, &surface_y);
- pixman_region32_translate(&final_region, (int)surface_x, (int)surface_y);
+ weston_view_to_global_float(ev, 0, 0, &view_x, &view_y);
+ pixman_region32_translate(&final_region, (int)view_x, (int)view_y);
}
/* We need to paint the intersection */
@@ -314,22 +230,22 @@ repaint_region(struct weston_surface *es, struct weston_output *output,
pixman_double_to_fixed (output->x),
pixman_double_to_fixed (output->y));
- if (es->transform.enabled) {
+ if (ev->transform.enabled) {
/* Pixman supports only 2D transform matrix, but Weston uses 3D,
* so we're omitting Z coordinate here
*/
pixman_transform_t surface_transform = {{
- { D2F(es->transform.matrix.d[0]),
- D2F(es->transform.matrix.d[4]),
- D2F(es->transform.matrix.d[12]),
+ { D2F(ev->transform.matrix.d[0]),
+ D2F(ev->transform.matrix.d[4]),
+ D2F(ev->transform.matrix.d[12]),
},
- { D2F(es->transform.matrix.d[1]),
- D2F(es->transform.matrix.d[5]),
- D2F(es->transform.matrix.d[13]),
+ { D2F(ev->transform.matrix.d[1]),
+ D2F(ev->transform.matrix.d[5]),
+ D2F(ev->transform.matrix.d[13]),
},
- { D2F(es->transform.matrix.d[3]),
- D2F(es->transform.matrix.d[7]),
- D2F(es->transform.matrix.d[15]),
+ { D2F(ev->transform.matrix.d[3]),
+ D2F(ev->transform.matrix.d[7]),
+ D2F(ev->transform.matrix.d[15]),
}
}};
@@ -337,15 +253,37 @@ repaint_region(struct weston_surface *es, struct weston_output *output,
pixman_transform_multiply (&transform, &surface_transform, &transform);
} else {
pixman_transform_translate(&transform, NULL,
- pixman_double_to_fixed ((double)-es->geometry.x),
- pixman_double_to_fixed ((double)-es->geometry.y));
+ pixman_double_to_fixed ((double)-ev->geometry.x),
+ pixman_double_to_fixed ((double)-ev->geometry.y));
}
+ if (ev->surface->buffer_viewport.viewport_set) {
+ double viewport_x, viewport_y, viewport_width, viewport_height;
+ double ratio_x, ratio_y;
+
+ viewport_x = wl_fixed_to_double(ev->surface->buffer_viewport.src_x);
+ viewport_y = wl_fixed_to_double(ev->surface->buffer_viewport.src_y);
+ viewport_width = wl_fixed_to_double(ev->surface->buffer_viewport.src_width);
+ viewport_height = wl_fixed_to_double(ev->surface->buffer_viewport.src_height);
+
+ ratio_x = viewport_width / ev->surface->buffer_viewport.dst_width;
+ ratio_y = viewport_height / ev->surface->buffer_viewport.dst_height;
+
+ pixman_transform_scale(&transform, NULL,
+ pixman_double_to_fixed(ratio_x),
+ pixman_double_to_fixed(ratio_y));
+ pixman_transform_translate(&transform, NULL, pixman_double_to_fixed(viewport_x),
+ pixman_double_to_fixed(viewport_y));
+ }
+
+ pixman_transform_scale(&transform, NULL,
+ pixman_double_to_fixed(ev->surface->buffer_viewport.scale),
+ pixman_double_to_fixed(ev->surface->buffer_viewport.scale));
- fw = pixman_int_to_fixed(es->geometry.width);
- fh = pixman_int_to_fixed(es->geometry.height);
+ fw = pixman_int_to_fixed(pixman_image_get_width(ps->image));
+ fh = pixman_int_to_fixed(pixman_image_get_height(ps->image));
- switch (es->buffer_transform) {
+ switch (ev->surface->buffer_viewport.transform) {
case WL_OUTPUT_TRANSFORM_FLIPPED:
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
@@ -357,7 +295,7 @@ repaint_region(struct weston_surface *es, struct weston_output *output,
break;
}
- switch (es->buffer_transform) {
+ switch (ev->surface->buffer_viewport.transform) {
default:
case WL_OUTPUT_TRANSFORM_NORMAL:
case WL_OUTPUT_TRANSFORM_FLIPPED:
@@ -379,17 +317,16 @@ repaint_region(struct weston_surface *es, struct weston_output *output,
break;
}
- pixman_transform_scale(&transform, NULL,
- pixman_double_to_fixed ((double)es->buffer_scale),
- pixman_double_to_fixed ((double)es->buffer_scale));
-
pixman_image_set_transform(ps->image, &transform);
- if (es->transform.enabled || output->current_scale != es->buffer_scale)
+ if (ev->transform.enabled || output->current_scale != ev->surface->buffer_viewport.scale)
pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0);
else
pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0);
+ if (ps->buffer_ref.buffer)
+ wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
+
pixman_image_composite32(pixman_op,
ps->image, /* src */
NULL /* mask */,
@@ -400,6 +337,9 @@ repaint_region(struct weston_surface *es, struct weston_output *output,
pixman_image_get_width (po->shadow_image), /* width */
pixman_image_get_height (po->shadow_image) /* height */);
+ if (ps->buffer_ref.buffer)
+ wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
+
if (pr->repaint_debug)
pixman_image_composite32(PIXMAN_OP_OVER,
pr->debug_color, /* src */
@@ -417,10 +357,10 @@ repaint_region(struct weston_surface *es, struct weston_output *output,
}
static void
-draw_surface(struct weston_surface *es, struct weston_output *output,
- pixman_region32_t *damage) /* in global coordinates */
+draw_view(struct weston_view *ev, struct weston_output *output,
+ pixman_region32_t *damage) /* in global coordinates */
{
- struct pixman_surface_state *ps = get_surface_state(es);
+ struct pixman_surface_state *ps = get_surface_state(ev->surface);
/* repaint bounding region in global coordinates: */
pixman_region32_t repaint;
/* non-opaque region in surface coordinates: */
@@ -432,8 +372,8 @@ draw_surface(struct weston_surface *es, struct weston_output *output,
pixman_region32_init(&repaint);
pixman_region32_intersect(&repaint,
- &es->transform.boundingbox, damage);
- pixman_region32_subtract(&repaint, &repaint, &es->clip);
+ &ev->transform.boundingbox, damage);
+ pixman_region32_subtract(&repaint, &repaint, &ev->clip);
if (!pixman_region32_not_empty(&repaint))
goto out;
@@ -444,21 +384,21 @@ draw_surface(struct weston_surface *es, struct weston_output *output,
}
/* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */
- if (es->transform.enabled &&
- es->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE) {
- repaint_region(es, output, &repaint, NULL, PIXMAN_OP_OVER);
+ if (ev->transform.enabled &&
+ ev->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE) {
+ repaint_region(ev, output, &repaint, NULL, PIXMAN_OP_OVER);
} else {
/* blended region is whole surface minus opaque region: */
pixman_region32_init_rect(&surface_blend, 0, 0,
- es->geometry.width, es->geometry.height);
- pixman_region32_subtract(&surface_blend, &surface_blend, &es->opaque);
+ ev->surface->width, ev->surface->height);
+ pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque);
- if (pixman_region32_not_empty(&es->opaque)) {
- repaint_region(es, output, &repaint, &es->opaque, PIXMAN_OP_SRC);
+ if (pixman_region32_not_empty(&ev->surface->opaque)) {
+ repaint_region(ev, output, &repaint, &ev->surface->opaque, PIXMAN_OP_SRC);
}
if (pixman_region32_not_empty(&surface_blend)) {
- repaint_region(es, output, &repaint, &surface_blend, PIXMAN_OP_OVER);
+ repaint_region(ev, output, &repaint, &surface_blend, PIXMAN_OP_OVER);
}
pixman_region32_fini(&surface_blend);
}
@@ -471,11 +411,11 @@ static void
repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
{
struct weston_compositor *compositor = output->compositor;
- struct weston_surface *surface;
+ struct weston_view *view;
- wl_list_for_each_reverse(surface, &compositor->surface_list, link)
- if (surface->plane == &compositor->primary_plane)
- draw_surface(surface, output, damage);
+ wl_list_for_each_reverse(view, &compositor->view_list, link)
+ if (view->plane == &compositor->primary_plane)
+ draw_view(view, output, damage);
}
static void
@@ -529,6 +469,22 @@ pixman_renderer_flush_damage(struct weston_surface *surface)
}
static void
+buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
+{
+ struct pixman_surface_state *ps;
+
+ ps = container_of(listener, struct pixman_surface_state,
+ buffer_destroy_listener);
+
+ if (ps->image) {
+ pixman_image_unref(ps->image);
+ ps->image = NULL;
+ }
+
+ ps->buffer_destroy_listener.notify = NULL;
+}
+
+static void
pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
{
struct pixman_surface_state *ps = get_surface_state(es);
@@ -537,6 +493,11 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
weston_buffer_reference(&ps->buffer_ref, buffer);
+ if (ps->buffer_destroy_listener.notify) {
+ wl_list_remove(&ps->buffer_destroy_listener.link);
+ ps->buffer_destroy_listener.notify = NULL;
+ }
+
if (ps->image) {
pixman_image_unref(ps->image);
ps->image = NULL;
@@ -578,12 +539,60 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
buffer->width, buffer->height,
wl_shm_buffer_get_data(shm_buffer),
wl_shm_buffer_get_stride(shm_buffer));
+
+ ps->buffer_destroy_listener.notify =
+ buffer_state_handle_buffer_destroy;
+ wl_signal_add(&buffer->destroy_signal,
+ &ps->buffer_destroy_listener);
+}
+
+static void
+pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
+{
+ wl_list_remove(&ps->surface_destroy_listener.link);
+ wl_list_remove(&ps->renderer_destroy_listener.link);
+ if (ps->buffer_destroy_listener.notify) {
+ wl_list_remove(&ps->buffer_destroy_listener.link);
+ ps->buffer_destroy_listener.notify = NULL;
+ }
+
+ ps->surface->renderer_state = NULL;
+
+ if (ps->image) {
+ pixman_image_unref(ps->image);
+ ps->image = NULL;
+ }
+ weston_buffer_reference(&ps->buffer_ref, NULL);
+ free(ps);
+}
+
+static void
+surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
+{
+ struct pixman_surface_state *ps;
+
+ ps = container_of(listener, struct pixman_surface_state,
+ surface_destroy_listener);
+
+ pixman_renderer_surface_state_destroy(ps);
+}
+
+static void
+surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
+{
+ struct pixman_surface_state *ps;
+
+ ps = container_of(listener, struct pixman_surface_state,
+ renderer_destroy_listener);
+
+ pixman_renderer_surface_state_destroy(ps);
}
static int
pixman_renderer_create_surface(struct weston_surface *surface)
{
struct pixman_surface_state *ps;
+ struct pixman_renderer *pr = get_renderer(surface->compositor);
ps = calloc(1, sizeof *ps);
if (!ps)
@@ -591,6 +600,18 @@ pixman_renderer_create_surface(struct weston_surface *surface)
surface->renderer_state = ps;
+ ps->surface = surface;
+
+ ps->surface_destroy_listener.notify =
+ surface_state_handle_surface_destroy;
+ wl_signal_add(&surface->destroy_signal,
+ &ps->surface_destroy_listener);
+
+ ps->renderer_destroy_listener.notify =
+ surface_state_handle_renderer_destroy;
+ wl_signal_add(&pr->destroy_signal,
+ &ps->renderer_destroy_listener);
+
return 0;
}
@@ -615,22 +636,14 @@ pixman_renderer_surface_set_color(struct weston_surface *es,
}
static void
-pixman_renderer_destroy_surface(struct weston_surface *surface)
+pixman_renderer_destroy(struct weston_compositor *ec)
{
- struct pixman_surface_state *ps = get_surface_state(surface);
+ struct pixman_renderer *pr = get_renderer(ec);
- if (ps->image) {
- pixman_image_unref(ps->image);
- ps->image = NULL;
- }
- weston_buffer_reference(&ps->buffer_ref, NULL);
- free(ps);
-}
+ wl_signal_emit(&pr->destroy_signal, pr);
+ weston_binding_destroy(pr->debug_binding);
+ free(pr);
-static void
-pixman_renderer_destroy(struct weston_compositor *ec)
-{
- free(ec->renderer);
ec->renderer = NULL;
}
@@ -660,7 +673,7 @@ pixman_renderer_init(struct weston_compositor *ec)
{
struct pixman_renderer *renderer;
- renderer = malloc(sizeof *renderer);
+ renderer = calloc(1, sizeof *renderer);
if (renderer == NULL)
return -1;
@@ -670,19 +683,20 @@ pixman_renderer_init(struct weston_compositor *ec)
renderer->base.repaint_output = pixman_renderer_repaint_output;
renderer->base.flush_damage = pixman_renderer_flush_damage;
renderer->base.attach = pixman_renderer_attach;
- renderer->base.create_surface = pixman_renderer_create_surface;
renderer->base.surface_set_color = pixman_renderer_surface_set_color;
- renderer->base.destroy_surface = pixman_renderer_destroy_surface;
renderer->base.destroy = pixman_renderer_destroy;
ec->renderer = &renderer->base;
ec->capabilities |= WESTON_CAP_ROTATION_ANY;
ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
- weston_compositor_add_debug_binding(ec, KEY_R,
- debug_binding, ec);
+ renderer->debug_binding =
+ weston_compositor_add_debug_binding(ec, KEY_R,
+ debug_binding, ec);
wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
+ wl_signal_init(&renderer->destroy_signal);
+
return 0;
}
diff --git a/src/rpi-bcm-stubs.h b/src/rpi-bcm-stubs.h
index 703cd771..fa30570d 100644
--- a/src/rpi-bcm-stubs.h
+++ b/src/rpi-bcm-stubs.h
@@ -303,6 +303,19 @@ vc_dispmanx_get_handle_from_wl_buffer(struct wl_resource *_buffer)
return DISPMANX_NO_HANDLE;
}
+static inline void
+vc_dispmanx_set_wl_buffer_in_use(struct wl_resource *_buffer, int in_use)
+{
+}
+
+static inline int
+vc_dispmanx_element_set_opaque_rect(DISPMANX_UPDATE_HANDLE_T update,
+ DISPMANX_ELEMENT_HANDLE_T element,
+ const VC_RECT_T *opaque_rect)
+{
+ return -1;
+}
+
/* from /opt/vc/include/EGL/eglplatform.h */
typedef struct {
diff --git a/src/rpi-renderer.c b/src/rpi-renderer.c
index a95cc604..c6b924c6 100644
--- a/src/rpi-renderer.c
+++ b/src/rpi-renderer.c
@@ -79,12 +79,16 @@
/* If we had a fully featured vc_dispmanx_resource_write_data()... */
/*#define HAVE_RESOURCE_WRITE_DATA_RECT 1*/
+/* If we had a vc_dispmanx_element_set_opaque_rect()... */
+/*#define HAVE_ELEMENT_SET_OPAQUE_RECT 1*/
+
struct rpi_resource {
DISPMANX_RESOURCE_HANDLE_T handle;
int width;
int height; /* height of the image (valid pixel data) */
int stride; /* bytes */
int buffer_height; /* height of the buffer */
+ int enable_opaque_regions;
VC_IMAGE_TYPE_T ifmt;
};
@@ -104,15 +108,11 @@ enum buffer_type {
struct rpir_surface {
struct weston_surface *surface;
- /* If link is empty, the surface is guaranteed to not be on screen,
- * i.e. updates removing Elements have completed.
- */
- struct wl_list link;
-
- DISPMANX_ELEMENT_HANDLE_T handle;
- int layer;
+ struct wl_list views;
+ int visible_views;
int need_swap;
int single_buffer;
+ int enable_opaque_regions;
struct rpi_resource resources[2];
struct rpi_resource *front;
@@ -125,6 +125,24 @@ struct rpir_surface {
struct weston_buffer_reference buffer_ref;
enum buffer_type buffer_type;
+
+ struct wl_listener surface_destroy_listener;
+};
+
+struct rpir_view {
+ struct rpir_surface *surface;
+ struct wl_list surface_link;
+ struct weston_view *view;
+
+ /* If link is empty, the view is guaranteed to not be on screen,
+ * i.e. updates removing Elements have completed.
+ */
+ struct wl_list link;
+
+ DISPMANX_ELEMENT_HANDLE_T handle;
+ int layer;
+
+ struct wl_listener view_destroy_listener;
};
struct rpir_output {
@@ -134,10 +152,10 @@ struct rpir_output {
struct weston_matrix matrix;
/* all Elements currently on screen */
- struct wl_list surface_list; /* struct rpir_surface::link */
+ struct wl_list view_list; /* struct rpir_surface::link */
/* Elements just removed, waiting for update completion */
- struct wl_list surface_cleanup_list; /* struct rpir_surface::link */
+ struct wl_list view_cleanup_list; /* struct rpir_surface::link */
struct rpi_resource capture_buffer;
uint8_t *capture_data;
@@ -147,6 +165,7 @@ struct rpi_renderer {
struct weston_renderer base;
int single_buffer;
+ int enable_opaque_regions;
#ifdef ENABLE_EGL
EGLDisplay egl_display;
@@ -158,12 +177,33 @@ struct rpi_renderer {
int has_bind_display;
};
+static int
+rpi_renderer_create_surface(struct weston_surface *base);
+
+static int
+rpi_renderer_create_view(struct weston_view *base);
+
+static void
+rpir_view_handle_view_destroy(struct wl_listener *listener, void *data);
+
static inline struct rpir_surface *
to_rpir_surface(struct weston_surface *surface)
{
+ if (!surface->renderer_state)
+ rpi_renderer_create_surface(surface);
+
return surface->renderer_state;
}
+static inline struct rpir_view *
+to_rpir_view(struct weston_view *view)
+{
+ if (!view->renderer_state)
+ rpi_renderer_create_view(view);
+
+ return view->renderer_state;
+}
+
static inline struct rpir_output *
to_rpir_output(struct weston_output *output)
{
@@ -272,9 +312,47 @@ shm_buffer_get_vc_format(struct wl_shm_buffer *buffer)
}
}
+#ifndef HAVE_ELEMENT_SET_OPAQUE_RECT
+static uint32_t *
+apply_opaque_region(struct wl_shm_buffer *buffer,
+ pixman_region32_t *opaque_region)
+{
+ uint32_t *src, *dst;
+ int width;
+ int height;
+ int stride;
+ int x, y;
+
+ width = wl_shm_buffer_get_width(buffer);
+ height = wl_shm_buffer_get_height(buffer);
+ stride = wl_shm_buffer_get_stride(buffer);
+ src = wl_shm_buffer_get_data(buffer);
+
+ dst = malloc(height * stride);
+ if (dst == NULL) {
+ weston_log("rpi-renderer error: out of memory\n");
+ return NULL;
+ }
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ int i = y * stride / 4 + x;
+ pixman_box32_t box;
+ if (pixman_region32_contains_point (opaque_region, x, y, &box)) {
+ dst[i] = src[i] | 0xff000000;
+ } else {
+ dst[i] = src[i];
+ }
+ }
+ }
+
+ return dst;
+}
+#endif
+
static int
rpi_resource_update(struct rpi_resource *resource, struct weston_buffer *buffer,
- pixman_region32_t *region)
+ pixman_region32_t *region, pixman_region32_t *opaque_region)
{
pixman_region32_t write_region;
pixman_box32_t *r;
@@ -298,6 +376,17 @@ rpi_resource_update(struct rpi_resource *resource, struct weston_buffer *buffer,
stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
pixels = wl_shm_buffer_get_data(buffer->shm_buffer);
+#ifndef HAVE_ELEMENT_SET_OPAQUE_RECT
+ if (pixman_region32_not_empty(opaque_region) &&
+ wl_shm_buffer_get_format(buffer->shm_buffer) == WL_SHM_FORMAT_ARGB8888 &&
+ resource->enable_opaque_regions) {
+ pixels = apply_opaque_region(buffer->shm_buffer, opaque_region);
+
+ if (!pixels)
+ return -1;
+ }
+#endif
+
ret = rpi_resource_realloc(resource, ifmt & ~PREMULT_ALPHA_FLAG,
width, height, stride, height);
if (ret < 0)
@@ -308,6 +397,8 @@ rpi_resource_update(struct rpi_resource *resource, struct weston_buffer *buffer,
pixman_region32_intersect(&write_region,
&write_region, region);
+ wl_shm_buffer_begin_access(buffer->shm_buffer);
+
#ifdef HAVE_RESOURCE_WRITE_DATA_RECT
/* XXX: Can this do a format conversion, so that scanout does not have to? */
r = pixman_region32_rectangles(&write_region, &n);
@@ -342,11 +433,58 @@ rpi_resource_update(struct rpi_resource *resource, struct weston_buffer *buffer,
width, r->y2 - r->y1, 0, r->y1, ret);
#endif
+ wl_shm_buffer_end_access(buffer->shm_buffer);
+
pixman_region32_fini(&write_region);
+#ifndef HAVE_ELEMENT_SET_OPAQUE_RECT
+ if (pixman_region32_not_empty(opaque_region) &&
+ wl_shm_buffer_get_format(buffer->shm_buffer) == WL_SHM_FORMAT_ARGB8888 &&
+ resource->enable_opaque_regions)
+ free(pixels);
+#endif
+
return ret ? -1 : 0;
}
+static inline void
+rpi_buffer_egl_lock(struct weston_buffer *buffer)
+{
+#ifdef ENABLE_EGL
+ vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 1);
+#endif
+}
+
+static inline void
+rpi_buffer_egl_unlock(struct weston_buffer *buffer)
+{
+#ifdef ENABLE_EGL
+ vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 0);
+#endif
+}
+
+static void
+rpir_egl_buffer_destroy(struct rpir_egl_buffer *egl_buffer)
+{
+ struct weston_buffer *buffer;
+
+ if (egl_buffer == NULL)
+ return;
+
+ buffer = egl_buffer->buffer_ref.buffer;
+ if (buffer == NULL) {
+ /* The client has already destroyed the wl_buffer, the
+ * compositor has the responsibility to delete the resource.
+ */
+ vc_dispmanx_resource_delete(egl_buffer->resource_handle);
+ } else {
+ rpi_buffer_egl_unlock(buffer);
+ weston_buffer_reference(&egl_buffer->buffer_ref, NULL);
+ }
+
+ free(egl_buffer);
+}
+
static struct rpir_surface *
rpir_surface_create(struct rpi_renderer *renderer)
{
@@ -356,9 +494,10 @@ rpir_surface_create(struct rpi_renderer *renderer)
if (!surface)
return NULL;
- wl_list_init(&surface->link);
+ wl_list_init(&surface->views);
+ surface->visible_views = 0;
surface->single_buffer = renderer->single_buffer;
- surface->handle = DISPMANX_NO_HANDLE;
+ surface->enable_opaque_regions = renderer->enable_opaque_regions;
rpi_resource_init(&surface->resources[0]);
rpi_resource_init(&surface->resources[1]);
surface->front = &surface->resources[0];
@@ -366,6 +505,10 @@ rpir_surface_create(struct rpi_renderer *renderer)
surface->back = &surface->resources[0];
else
surface->back = &surface->resources[1];
+
+ surface->front->enable_opaque_regions = renderer->enable_opaque_regions;
+ surface->back->enable_opaque_regions = renderer->enable_opaque_regions;
+
surface->buffer_type = BUFFER_TYPE_NULL;
pixman_region32_init(&surface->prev_damage);
@@ -376,33 +519,22 @@ rpir_surface_create(struct rpi_renderer *renderer)
static void
rpir_surface_destroy(struct rpir_surface *surface)
{
- wl_list_remove(&surface->link);
-
- if (surface->handle != DISPMANX_NO_HANDLE)
+ if (surface->visible_views)
weston_log("ERROR rpi: destroying on-screen element\n");
+ assert(wl_list_empty(&surface->views));
+
+ if (surface->surface)
+ surface->surface->renderer_state = NULL;
+
pixman_region32_fini(&surface->prev_damage);
rpi_resource_release(&surface->resources[0]);
rpi_resource_release(&surface->resources[1]);
- DBG("rpir_surface %p destroyed (%u)\n", surface, surface->handle);
-
- if (surface->egl_back != NULL) {
- weston_buffer_reference(&surface->egl_back->buffer_ref, NULL);
- free(surface->egl_back);
- surface->egl_back = NULL;
- }
+ DBG("rpir_surface %p destroyed (%u)\n", surface, surface->visible_views);
- if (surface->egl_front != NULL) {
- weston_buffer_reference(&surface->egl_front->buffer_ref, NULL);
- free(surface->egl_front);
- surface->egl_front = NULL;
- }
-
- if (surface->egl_old_front != NULL) {
- weston_buffer_reference(&surface->egl_old_front->buffer_ref, NULL);
- free(surface->egl_old_front);
- surface->egl_old_front = NULL;
- }
+ rpir_egl_buffer_destroy(surface->egl_back);
+ rpir_egl_buffer_destroy(surface->egl_front);
+ rpir_egl_buffer_destroy(surface->egl_old_front);
free(surface);
}
@@ -422,11 +554,13 @@ rpir_surface_damage(struct rpir_surface *surface, struct weston_buffer *buffer,
/* XXX: todo: if no surface->handle, update front buffer directly
* to avoid creating a new back buffer */
if (surface->single_buffer) {
- ret = rpi_resource_update(surface->front, buffer, damage);
+ ret = rpi_resource_update(surface->front, buffer, damage,
+ &surface->surface->opaque);
} else {
pixman_region32_init(&upload);
pixman_region32_union(&upload, &surface->prev_damage, damage);
- ret = rpi_resource_update(surface->back, buffer, &upload);
+ ret = rpi_resource_update(surface->back, buffer, &upload,
+ &surface->surface->opaque);
pixman_region32_fini(&upload);
}
@@ -436,6 +570,46 @@ rpir_surface_damage(struct rpir_surface *surface, struct weston_buffer *buffer,
return ret;
}
+static struct rpir_view *
+rpir_view_create(struct rpir_surface *surface)
+{
+ struct rpir_view *view;
+
+ view = calloc(1, sizeof *view);
+ if (!view)
+ return NULL;
+
+ view->surface = surface;
+ wl_list_insert(&surface->views, &view->surface_link);
+
+ wl_list_init(&view->link);
+ view->handle = DISPMANX_NO_HANDLE;
+
+ return view;
+}
+
+static void
+rpir_view_destroy(struct rpir_view *view)
+{
+ wl_list_remove(&view->link);
+
+ if (view->handle != DISPMANX_NO_HANDLE) {
+ view->surface->visible_views--;
+ weston_log("ERROR rpi: destroying on-screen element\n");
+ }
+
+ if (view->view)
+ view->view->renderer_state = NULL;
+
+ wl_list_remove(&view->surface_link);
+ if (wl_list_empty(&view->surface->views) && view->surface->surface == NULL)
+ rpir_surface_destroy(view->surface);
+
+ DBG("rpir_view %p destroyed (%d)\n", view, view->handle);
+
+ free(view);
+}
+
static void
matrix_type_str(struct weston_matrix *matrix, char *buf, int len)
{
@@ -495,13 +669,13 @@ warn_bad_matrix(struct weston_matrix *total, struct weston_matrix *output,
/*#define SURFACE_TRANSFORM */
static int
-rpir_surface_compute_rects(struct rpir_surface *surface,
- VC_RECT_T *src_rect, VC_RECT_T *dst_rect,
- VC_IMAGE_TRANSFORM_T *flipmask)
+rpir_view_compute_rects(struct rpir_view *view,
+ VC_RECT_T *src_rect, VC_RECT_T *dst_rect,
+ VC_IMAGE_TRANSFORM_T *flipmask)
{
- struct weston_output *output_base = surface->surface->output;
+ struct weston_output *output_base = view->view->surface->output;
struct rpir_output *output = to_rpir_output(output_base);
- struct weston_matrix matrix = surface->surface->transform.matrix;
+ struct weston_matrix matrix = view->view->transform.matrix;
VC_IMAGE_TRANSFORM_T flipt = 0;
int src_x, src_y;
int dst_x, dst_y;
@@ -523,14 +697,15 @@ rpir_surface_compute_rects(struct rpir_surface *surface,
src_x = 0 << 16;
src_y = 0 << 16;
- if (surface->buffer_type == BUFFER_TYPE_EGL) {
- struct weston_buffer *buffer = surface->egl_front->buffer_ref.buffer;
+ if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
+ struct weston_buffer *buffer =
+ view->surface->egl_front->buffer_ref.buffer;
src_width = buffer->width << 16;
src_height = buffer->height << 16;
} else {
- src_width = surface->front->width << 16;
- src_height = surface->front->height << 16;
+ src_width = view->surface->front->width << 16;
+ src_height = view->surface->front->height << 16;
}
weston_matrix_multiply(&matrix, &output->matrix);
@@ -541,7 +716,7 @@ rpir_surface_compute_rects(struct rpir_surface *surface,
if (matrix.type >= WESTON_MATRIX_TRANSFORM_ROTATE) {
#endif
warn_bad_matrix(&matrix, &output->matrix,
- &surface->surface->transform.matrix);
+ &view->view->transform.matrix);
} else {
if (matrix.type & WESTON_MATRIX_TRANSFORM_ROTATE) {
if (fabsf(matrix.d[0]) < 1e-4f &&
@@ -552,13 +727,13 @@ rpir_surface_compute_rects(struct rpir_surface *surface,
/* no transpose */
} else {
warn_bad_matrix(&matrix, &output->matrix,
- &surface->surface->transform.matrix);
+ &view->view->transform.matrix);
}
}
}
- p2.f[0] = surface->surface->geometry.width;
- p2.f[1] = surface->surface->geometry.height;
+ p2.f[0] = view->view->surface->width;
+ p2.f[1] = view->view->surface->height;
/* transform top-left and bot-right corner into screen coordinates */
weston_matrix_transform(&matrix, &p1);
@@ -680,9 +855,9 @@ rpir_surface_compute_rects(struct rpir_surface *surface,
src_width = int_max(src_width, 0);
src_height = int_max(src_height, 0);
- DBG("rpir_surface %p %dx%d: p1 %f, %f; p2 %f, %f\n", surface,
- surface->surface->geometry.width,
- surface->surface->geometry.height,
+ DBG("rpir_view %p %dx%d: p1 %f, %f; p2 %f, %f\n", view,
+ view->view->geometry.width,
+ view->view->geometry.height,
p1.f[0], p1.f[1], p2.f[0], p2.f[1]);
DBG("src rect %d;%d, %d;%d, %d;%dx%d;%d\n",
src_x >> 16, src_x & 0xffff,
@@ -706,7 +881,7 @@ rpir_surface_compute_rects(struct rpir_surface *surface,
}
/* EGL buffers will be upside-down related to what DispmanX expects */
- if (surface->buffer_type == BUFFER_TYPE_EGL)
+ if (view->surface->buffer_type == BUFFER_TYPE_EGL)
flipt ^= TRANSFORM_VFLIP;
vc_dispmanx_rect_set(src_rect, src_x, src_y, src_width, src_height);
@@ -743,7 +918,6 @@ vc_image2dispmanx_transform(VC_IMAGE_TRANSFORM_T t)
}
}
-
static DISPMANX_RESOURCE_HANDLE_T
rpir_surface_get_resource(struct rpir_surface *surface)
{
@@ -759,9 +933,40 @@ rpir_surface_get_resource(struct rpir_surface *surface)
}
}
+#ifdef HAVE_ELEMENT_SET_OPAQUE_RECT
static int
-rpir_surface_dmx_add(struct rpir_surface *surface, struct rpir_output *output,
- DISPMANX_UPDATE_HANDLE_T update, int layer)
+rpir_surface_set_opaque_rect(struct rpir_surface *surface,
+ DISPMANX_UPDATE_HANDLE_T update)
+{
+ int ret;
+
+ if (pixman_region32_not_empty(&surface->surface->opaque) &&
+ surface->opaque_regions) {
+ pixman_box32_t *box;
+ VC_RECT_T opaque_rect;
+
+ box = pixman_region32_extents(&surface->surface->opaque);
+ opaque_rect.x = box->x1;
+ opaque_rect.y = box->y1;
+ opaque_rect.width = box->x2 - box->x1;
+ opaque_rect.height = box->y2 - box->y1;
+
+ ret = vc_dispmanx_element_set_opaque_rect(update,
+ surface->handle,
+ &opaque_rect);
+ if (ret) {
+ weston_log("vc_dispmanx_element_set_opaque_rect failed\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static int
+rpir_view_dmx_add(struct rpir_view *view, struct rpir_output *output,
+ DISPMANX_UPDATE_HANDLE_T update, int layer)
{
/* Do not use DISPMANX_FLAGS_ALPHA_PREMULT here.
* If you define PREMULT and ALPHA_MIX, the hardware will not
@@ -771,7 +976,7 @@ rpir_surface_dmx_add(struct rpir_surface *surface, struct rpir_output *output,
VC_DISPMANX_ALPHA_T alphasetup = {
DISPMANX_FLAGS_ALPHA_FROM_SOURCE |
DISPMANX_FLAGS_ALPHA_MIX,
- float2uint8(surface->surface->alpha), /* opacity 0-255 */
+ float2uint8(view->view->alpha), /* opacity 0-255 */
0 /* mask resource handle */
};
VC_RECT_T dst_rect;
@@ -780,18 +985,17 @@ rpir_surface_dmx_add(struct rpir_surface *surface, struct rpir_output *output,
int ret;
DISPMANX_RESOURCE_HANDLE_T resource_handle;
- resource_handle = rpir_surface_get_resource(surface);
+ resource_handle = rpir_surface_get_resource(view->surface);
if (resource_handle == DISPMANX_NO_HANDLE) {
weston_log("%s: no buffer yet, aborting\n", __func__);
return 0;
}
- ret = rpir_surface_compute_rects(surface, &src_rect, &dst_rect,
- &flipmask);
+ ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
if (ret < 0)
return 0;
- surface->handle = vc_dispmanx_element_add(
+ view->handle = vc_dispmanx_element_add(
update,
output->display,
layer,
@@ -802,37 +1006,48 @@ rpir_surface_dmx_add(struct rpir_surface *surface, struct rpir_output *output,
&alphasetup,
NULL /* clamp */,
vc_image2dispmanx_transform(flipmask));
- DBG("rpir_surface %p add %u, alpha %f resource %d\n", surface,
- surface->handle, surface->surface->alpha, resource_handle);
+ DBG("rpir_surface %p add %u, alpha %f resource %d\n", view,
+ view->handle, view->view->alpha, resource_handle);
+
+ if (view->handle == DISPMANX_NO_HANDLE)
+ return -1;
+
+#ifdef HAVE_ELEMENT_SET_OPAQUE_RECT
+ ret = rpir_surface_set_opaque_rect(surface, update);
+ if (ret < 0)
+ return -1;
+#endif
+
+ view->surface->visible_views++;
return 1;
}
static void
-rpir_surface_dmx_swap(struct rpir_surface *surface,
- DISPMANX_UPDATE_HANDLE_T update)
+rpir_view_dmx_swap(struct rpir_view *view,
+ DISPMANX_UPDATE_HANDLE_T update)
{
VC_RECT_T rect;
pixman_box32_t *r;
/* XXX: skip, iff resource was not reallocated, and single-buffering */
- vc_dispmanx_element_change_source(update, surface->handle,
- surface->front->handle);
+ vc_dispmanx_element_change_source(update, view->handle,
+ view->surface->front->handle);
/* This is current damage now, after rpir_surface_damage() */
- r = pixman_region32_extents(&surface->prev_damage);
+ r = pixman_region32_extents(&view->surface->prev_damage);
vc_dispmanx_rect_set(&rect, r->x1, r->y1,
r->x2 - r->x1, r->y2 - r->y1);
- vc_dispmanx_element_modified(update, surface->handle, &rect);
- DBG("rpir_surface %p swap\n", surface);
+ vc_dispmanx_element_modified(update, view->handle, &rect);
+ DBG("rpir_view %p swap\n", view);
}
static int
-rpir_surface_dmx_move(struct rpir_surface *surface,
- DISPMANX_UPDATE_HANDLE_T update, int layer)
+rpir_view_dmx_move(struct rpir_view *view,
+ DISPMANX_UPDATE_HANDLE_T update, int layer)
{
- uint8_t alpha = float2uint8(surface->surface->alpha);
+ uint8_t alpha = float2uint8(view->view->alpha);
VC_RECT_T dst_rect;
VC_RECT_T src_rect;
VC_IMAGE_TRANSFORM_T flipmask;
@@ -840,28 +1055,27 @@ rpir_surface_dmx_move(struct rpir_surface *surface,
/* XXX: return early, if all attributes stay the same */
- if (surface->buffer_type == BUFFER_TYPE_EGL) {
+ if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
DISPMANX_RESOURCE_HANDLE_T resource_handle;
- resource_handle = rpir_surface_get_resource(surface);
+ resource_handle = rpir_surface_get_resource(view->surface);
if (resource_handle == DISPMANX_NO_HANDLE) {
weston_log("%s: no buffer yet, aborting\n", __func__);
return 0;
}
vc_dispmanx_element_change_source(update,
- surface->handle,
+ view->handle,
resource_handle);
}
- ret = rpir_surface_compute_rects(surface, &src_rect, &dst_rect,
- &flipmask);
+ ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
if (ret < 0)
return 0;
ret = vc_dispmanx_element_change_attributes(
update,
- surface->handle,
+ view->handle,
ELEMENT_CHANGE_LAYER |
ELEMENT_CHANGE_OPACITY |
ELEMENT_CHANGE_TRANSFORM |
@@ -875,24 +1089,31 @@ rpir_surface_dmx_move(struct rpir_surface *surface,
/* This really is DISPMANX_TRANSFORM_T, no matter
* what the header says. */
vc_image2dispmanx_transform(flipmask));
- DBG("rpir_surface %p move\n", surface);
+ DBG("rpir_view %p move\n", view);
if (ret)
return -1;
+#ifdef HAVE_ELEMENT_SET_OPAQUE_RECT
+ ret = rpir_surface_set_opaque_rect(surface, update);
+ if (ret < 0)
+ return -1;
+#endif
+
return 1;
}
static void
-rpir_surface_dmx_remove(struct rpir_surface *surface,
- DISPMANX_UPDATE_HANDLE_T update)
+rpir_view_dmx_remove(struct rpir_view *view,
+ DISPMANX_UPDATE_HANDLE_T update)
{
- if (surface->handle == DISPMANX_NO_HANDLE)
+ if (view->handle == DISPMANX_NO_HANDLE)
return;
- vc_dispmanx_element_remove(update, surface->handle);
- DBG("rpir_surface %p remove %u\n", surface, surface->handle);
- surface->handle = DISPMANX_NO_HANDLE;
+ vc_dispmanx_element_remove(update, view->handle);
+ DBG("rpir_view %p remove %u\n", view, view->handle);
+ view->handle = DISPMANX_NO_HANDLE;
+ view->surface->visible_views--;
}
static void
@@ -900,23 +1121,32 @@ rpir_surface_swap_pointers(struct rpir_surface *surface)
{
struct rpi_resource *tmp;
- tmp = surface->front;
- surface->front = surface->back;
- surface->back = tmp;
- surface->need_swap = 0;
- DBG("new back %p, new front %p\n", surface->back, surface->front);
+ if (surface->buffer_type == BUFFER_TYPE_EGL) {
+ if (surface->egl_back != NULL) {
+ assert(surface->egl_old_front == NULL);
+ surface->egl_old_front = surface->egl_front;
+ surface->egl_front = surface->egl_back;
+ surface->egl_back = NULL;
+ DBG("new front %d\n", surface->egl_front->resource_handle);
+ }
+ } else {
+ tmp = surface->front;
+ surface->front = surface->back;
+ surface->back = tmp;
+ DBG("new back %p, new front %p\n", surface->back, surface->front);
+ }
}
static int
-is_surface_not_visible(struct weston_surface *surface)
+is_view_not_visible(struct weston_view *view)
{
/* Return true, if surface is guaranteed to be totally obscured. */
int ret;
pixman_region32_t unocc;
pixman_region32_init(&unocc);
- pixman_region32_subtract(&unocc, &surface->transform.boundingbox,
- &surface->clip);
+ pixman_region32_subtract(&unocc, &view->transform.boundingbox,
+ &view->clip);
ret = !pixman_region32_not_empty(&unocc);
pixman_region32_fini(&unocc);
@@ -924,81 +1154,54 @@ is_surface_not_visible(struct weston_surface *surface)
}
static void
-rpir_surface_update(struct rpir_surface *surface, struct rpir_output *output,
- DISPMANX_UPDATE_HANDLE_T update, int layer)
+rpir_view_update(struct rpir_view *view, struct rpir_output *output,
+ DISPMANX_UPDATE_HANDLE_T update, int layer)
{
- int need_swap = surface->need_swap;
int ret;
int obscured;
- if (surface->buffer_type == BUFFER_TYPE_EGL) {
- if (surface->egl_back != NULL) {
- assert(surface->egl_old_front == NULL);
- surface->egl_old_front = surface->egl_front;
- surface->egl_front = surface->egl_back;
- surface->egl_back = NULL;
- }
- if (surface->egl_front->buffer_ref.buffer == NULL) {
- weston_log("warning: client unreffed current front buffer\n");
-
- wl_list_remove(&surface->link);
- if (surface->handle == DISPMANX_NO_HANDLE) {
- wl_list_init(&surface->link);
- } else {
- rpir_surface_dmx_remove(surface, update);
- wl_list_insert(&output->surface_cleanup_list,
- &surface->link);
- }
-
- goto out;
- }
- } else {
- if (need_swap)
- rpir_surface_swap_pointers(surface);
- }
-
- obscured = is_surface_not_visible(surface->surface);
+ obscured = is_view_not_visible(view->view);
if (obscured) {
- DBG("rpir_surface %p totally obscured.\n", surface);
+ DBG("rpir_view %p totally obscured.\n", view);
- wl_list_remove(&surface->link);
- if (surface->handle == DISPMANX_NO_HANDLE) {
- wl_list_init(&surface->link);
+ wl_list_remove(&view->link);
+ if (view->handle == DISPMANX_NO_HANDLE) {
+ wl_list_init(&view->link);
} else {
- rpir_surface_dmx_remove(surface, update);
- wl_list_insert(&output->surface_cleanup_list,
- &surface->link);
+ rpir_view_dmx_remove(view, update);
+ wl_list_insert(&output->view_cleanup_list,
+ &view->link);
}
goto out;
}
- if (surface->handle == DISPMANX_NO_HANDLE) {
- ret = rpir_surface_dmx_add(surface, output, update, layer);
+ if (view->handle == DISPMANX_NO_HANDLE) {
+ ret = rpir_view_dmx_add(view, output, update, layer);
if (ret == 0) {
- wl_list_remove(&surface->link);
- wl_list_init(&surface->link);
+ wl_list_remove(&view->link);
+ wl_list_init(&view->link);
} else if (ret < 0) {
- weston_log("ERROR rpir_surface_dmx_add() failed.\n");
+ weston_log("ERROR rpir_view_dmx_add() failed.\n");
}
} else {
- if (need_swap)
- rpir_surface_dmx_swap(surface, update);
+ if (view->surface->need_swap)
+ rpir_view_dmx_swap(view, update);
- ret = rpir_surface_dmx_move(surface, update, layer);
+ ret = rpir_view_dmx_move(view, update, layer);
if (ret == 0) {
- rpir_surface_dmx_remove(surface, update);
+ rpir_view_dmx_remove(view, update);
- wl_list_remove(&surface->link);
- wl_list_insert(&output->surface_cleanup_list,
- &surface->link);
+ wl_list_remove(&view->link);
+ wl_list_insert(&output->view_cleanup_list,
+ &view->link);
} else if (ret < 0) {
- weston_log("ERROR rpir_surface_dmx_move() failed.\n");
+ weston_log("ERROR rpir_view_dmx_move() failed.\n");
}
}
out:
- surface->layer = layer;
+ view->layer = layer;
}
static int
@@ -1105,15 +1308,15 @@ static void
rpir_output_dmx_remove_all(struct rpir_output *output,
DISPMANX_UPDATE_HANDLE_T update)
{
- struct rpir_surface *surface;
+ struct rpir_view *view;
- while (!wl_list_empty(&output->surface_list)) {
- surface = container_of(output->surface_list.next,
- struct rpir_surface, link);
- rpir_surface_dmx_remove(surface, update);
+ while (!wl_list_empty(&output->view_list)) {
+ view = container_of(output->view_list.next,
+ struct rpir_view, link);
+ rpir_view_dmx_remove(view, update);
- wl_list_remove(&surface->link);
- wl_list_insert(&output->surface_cleanup_list, &surface->link);
+ wl_list_remove(&view->link);
+ wl_list_insert(&output->view_cleanup_list, &view->link);
}
}
@@ -1186,8 +1389,8 @@ rpi_renderer_repaint_output(struct weston_output *base,
{
struct weston_compositor *compositor = base->compositor;
struct rpir_output *output = to_rpir_output(base);
- struct weston_surface *ws;
- struct rpir_surface *surface;
+ struct weston_view *wv;
+ struct rpir_view *view;
struct wl_list done_list;
int layer = 1;
@@ -1199,27 +1402,66 @@ rpi_renderer_repaint_output(struct weston_output *base,
free(output->capture_data);
output->capture_data = NULL;
+ /* Swap resources on surfaces as needed */
+ wl_list_for_each_reverse(wv, &compositor->view_list, link)
+ wv->surface->touched = 0;
+
+ wl_list_for_each_reverse(wv, &compositor->view_list, link) {
+ view = to_rpir_view(wv);
+
+ if (!wv->surface->touched) {
+ wv->surface->touched = 1;
+
+ if (view->surface->buffer_type == BUFFER_TYPE_EGL ||
+ view->surface->need_swap)
+ rpir_surface_swap_pointers(view->surface);
+ }
+
+ if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
+ struct weston_buffer *buffer;
+ buffer = view->surface->egl_front->buffer_ref.buffer;
+ if (buffer != NULL) {
+ rpi_buffer_egl_lock(buffer);
+ } else {
+ weston_log("warning: client destroyed current front buffer\n");
+
+ wl_list_remove(&view->link);
+ if (view->handle == DISPMANX_NO_HANDLE) {
+ wl_list_init(&view->link);
+ } else {
+ rpir_view_dmx_remove(view, output->update);
+ wl_list_insert(&output->view_cleanup_list,
+ &view->link);
+ }
+ }
+ }
+ }
+
/* update all renderable surfaces */
wl_list_init(&done_list);
- wl_list_for_each_reverse(ws, &compositor->surface_list, link) {
- if (ws->plane != &compositor->primary_plane)
+ wl_list_for_each_reverse(wv, &compositor->view_list, link) {
+ if (wv->plane != &compositor->primary_plane)
continue;
- surface = to_rpir_surface(ws);
- assert(!wl_list_empty(&surface->link) ||
- surface->handle == DISPMANX_NO_HANDLE);
+ view = to_rpir_view(wv);
+ assert(!wl_list_empty(&view->link) ||
+ view->handle == DISPMANX_NO_HANDLE);
- wl_list_remove(&surface->link);
- wl_list_insert(&done_list, &surface->link);
- rpir_surface_update(surface, output, output->update, layer++);
+ wl_list_remove(&view->link);
+ wl_list_insert(&done_list, &view->link);
+ rpir_view_update(view, output, output->update, layer++);
}
+ /* Mark all surfaces as swapped */
+ wl_list_for_each_reverse(wv, &compositor->view_list, link)
+ to_rpir_surface(wv->surface)->need_swap = 0;
+
/* Remove all surfaces that are still on screen, but were
* not rendered this time.
*/
rpir_output_dmx_remove_all(output, output->update);
- wl_list_insert_list(&output->surface_list, &done_list);
+ wl_list_insert_list(&output->view_list, &done_list);
output->update = DISPMANX_NO_HANDLE;
/* The frame_signal is emitted in rpi_renderer_finish_frame(),
@@ -1263,7 +1505,7 @@ rpi_renderer_attach(struct weston_surface *base, struct weston_buffer *buffer)
/* XXX: need to check if in middle of update */
rpi_resource_release(surface->back);
- if (surface->handle == DISPMANX_NO_HANDLE)
+ if (!surface->visible_views)
/* XXX: cannot do this, if middle of an update */
rpi_resource_release(surface->front);
@@ -1319,6 +1561,27 @@ rpi_renderer_attach(struct weston_surface *base, struct weston_buffer *buffer)
}
}
+static void
+rpir_surface_handle_surface_destroy(struct wl_listener *listener, void *data)
+{
+ struct rpir_surface *surface;
+ struct weston_surface *base = data;
+
+ surface = container_of(listener, struct rpir_surface,
+ surface_destroy_listener);
+
+ assert(surface);
+ assert(surface->surface == base);
+ if (!surface)
+ return;
+
+ surface->surface = NULL;
+ base->renderer_state = NULL;
+
+ if (wl_list_empty(&surface->views))
+ rpir_surface_destroy(surface);
+}
+
static int
rpi_renderer_create_surface(struct weston_surface *base)
{
@@ -1333,6 +1596,35 @@ rpi_renderer_create_surface(struct weston_surface *base)
surface->surface = base;
base->renderer_state = surface;
+
+ surface->surface_destroy_listener.notify =
+ rpir_surface_handle_surface_destroy;
+ wl_signal_add(&base->destroy_signal,
+ &surface->surface_destroy_listener);
+
+ return 0;
+}
+
+static int
+rpi_renderer_create_view(struct weston_view *base)
+{
+ struct rpir_surface *surface = to_rpir_surface(base->surface);
+ struct rpir_view *view;
+
+ assert(base->renderer_state == NULL);
+
+ view = rpir_view_create(surface);
+ if (!view)
+ return -1;
+
+ view->view = base;
+ base->renderer_state = view;
+
+ view->view_destroy_listener.notify =
+ rpir_view_handle_view_destroy;
+ wl_signal_add(&base->destroy_signal,
+ &view->view_destroy_listener);
+
return 0;
}
@@ -1378,25 +1670,28 @@ rpi_renderer_surface_set_color(struct weston_surface *base,
}
static void
-rpi_renderer_destroy_surface(struct weston_surface *base)
+rpir_view_handle_view_destroy(struct wl_listener *listener, void *data)
{
- struct rpir_surface *surface = to_rpir_surface(base);
+ struct rpir_view *view;
+ struct weston_view *base = data;
- assert(surface);
- assert(surface->surface == base);
- if (!surface)
+ view = container_of(listener, struct rpir_view, view_destroy_listener);
+
+ assert(view);
+ assert(view->view == base);
+ if (!view)
return;
- surface->surface = NULL;
+ view->view = NULL;
base->renderer_state = NULL;
- /* If guaranteed to not be on screen, just detroy it. */
- if (wl_list_empty(&surface->link))
- rpir_surface_destroy(surface);
+ /* If guaranteed to not be on screen, just destroy it. */
+ if (wl_list_empty(&view->link))
+ rpir_view_destroy(view);
- /* Otherwise, the surface is either on screen and needs
+ /* Otherwise, the view is either on screen and needs
* to be removed by a repaint update, or it is in the
- * surface_cleanup_list, and will be destroyed by
+ * view_cleanup_list, and will be destroyed by
* rpi_renderer_finish_frame().
*/
}
@@ -1434,14 +1729,13 @@ rpi_renderer_create(struct weston_compositor *compositor,
return -1;
renderer->single_buffer = params->single_buffer;
+ renderer->enable_opaque_regions = params->opaque_regions;
renderer->base.read_pixels = rpi_renderer_read_pixels;
renderer->base.repaint_output = rpi_renderer_repaint_output;
renderer->base.flush_damage = rpi_renderer_flush_damage;
renderer->base.attach = rpi_renderer_attach;
- renderer->base.create_surface = rpi_renderer_create_surface;
renderer->base.surface_set_color = rpi_renderer_surface_set_color;
- renderer->base.destroy_surface = rpi_renderer_destroy_surface;
renderer->base.destroy = rpi_renderer_destroy;
#ifdef ENABLE_EGL
@@ -1504,8 +1798,8 @@ rpi_renderer_output_create(struct weston_output *base,
output->display = display;
output->update = DISPMANX_NO_HANDLE;
- wl_list_init(&output->surface_list);
- wl_list_init(&output->surface_cleanup_list);
+ wl_list_init(&output->view_list);
+ wl_list_init(&output->view_cleanup_list);
rpi_resource_init(&output->capture_buffer);
base->renderer_state = output;
@@ -1516,7 +1810,7 @@ WL_EXPORT void
rpi_renderer_output_destroy(struct weston_output *base)
{
struct rpir_output *output = to_rpir_output(base);
- struct rpir_surface *surface;
+ struct rpir_view *view;
DISPMANX_UPDATE_HANDLE_T update;
rpi_resource_release(&output->capture_buffer);
@@ -1527,12 +1821,10 @@ rpi_renderer_output_destroy(struct weston_output *base)
rpir_output_dmx_remove_all(output, update);
vc_dispmanx_update_submit_sync(update);
- while (!wl_list_empty(&output->surface_cleanup_list)) {
- surface = container_of(output->surface_cleanup_list.next,
- struct rpir_surface, link);
- if (surface->surface)
- surface->surface->renderer_state = NULL;
- rpir_surface_destroy(surface);
+ while (!wl_list_empty(&output->view_cleanup_list)) {
+ view = container_of(output->view_cleanup_list.next,
+ struct rpir_view, link);
+ rpir_view_destroy(view);
}
free(output);
@@ -1553,41 +1845,37 @@ rpi_renderer_finish_frame(struct weston_output *base)
{
struct rpir_output *output = to_rpir_output(base);
struct weston_compositor *compositor = base->compositor;
- struct weston_surface *ws;
- struct rpir_surface *surface;
+ struct weston_view *wv;
+ struct rpir_view *view;
- while (!wl_list_empty(&output->surface_cleanup_list)) {
- surface = container_of(output->surface_cleanup_list.next,
- struct rpir_surface, link);
+ while (!wl_list_empty(&output->view_cleanup_list)) {
+ view = container_of(output->view_cleanup_list.next,
+ struct rpir_view, link);
- if (surface->surface) {
- /* The weston_surface still exists, but is
+ if (view->view) {
+ /* The weston_view still exists, but is
* temporarily not visible, and hence its Element
* was removed. The current front buffer contents
* must be preserved.
*/
- if (!surface->single_buffer)
- rpi_resource_release(surface->back);
+ if (!view->surface->visible_views)
+ rpi_resource_release(view->surface->back);
- wl_list_remove(&surface->link);
- wl_list_init(&surface->link);
+ wl_list_remove(&view->link);
+ wl_list_init(&view->link);
} else {
- rpir_surface_destroy(surface);
+ rpir_view_destroy(view);
}
}
- wl_list_for_each(ws, &compositor->surface_list, link) {
- surface = to_rpir_surface(ws);
-
- if (surface->buffer_type != BUFFER_TYPE_EGL)
- continue;
+ wl_list_for_each(wv, &compositor->view_list, link) {
+ view = to_rpir_view(wv);
- if(surface->egl_old_front == NULL)
+ if (view->surface->buffer_type != BUFFER_TYPE_EGL)
continue;
- weston_buffer_reference(&surface->egl_old_front->buffer_ref, NULL);
- free(surface->egl_old_front);
- surface->egl_old_front = NULL;
+ rpir_egl_buffer_destroy(view->surface->egl_old_front);
+ view->surface->egl_old_front = NULL;
}
wl_signal_emit(&base->frame_signal, base);
diff --git a/src/rpi-renderer.h b/src/rpi-renderer.h
index 28ae3039..885631ab 100644
--- a/src/rpi-renderer.h
+++ b/src/rpi-renderer.h
@@ -25,6 +25,7 @@
struct rpi_renderer_parameters {
int single_buffer;
+ int opaque_regions;
};
int
diff --git a/src/screenshooter.c b/src/screenshooter.c
index 645114d0..26e503ce 100644
--- a/src/screenshooter.c
+++ b/src/screenshooter.c
@@ -144,6 +144,8 @@ screenshooter_frame_notify(struct wl_listener *listener, void *data)
d = wl_shm_buffer_get_data(l->buffer->shm_buffer);
s = pixels + stride * (l->buffer->height - 1);
+ wl_shm_buffer_begin_access(l->buffer->shm_buffer);
+
switch (compositor->read_format) {
case PIXMAN_a8r8g8b8:
case PIXMAN_x8r8g8b8:
@@ -163,6 +165,8 @@ screenshooter_frame_notify(struct wl_listener *listener, void *data)
break;
}
+ wl_shm_buffer_end_access(l->buffer->shm_buffer);
+
screenshooter_send_done(l->resource);
free(pixels);
free(l);
@@ -263,7 +267,7 @@ struct weston_recorder {
uint32_t total;
int fd;
struct wl_listener frame_listener;
- int count;
+ int count, destroying;
};
static uint32_t *
@@ -298,58 +302,7 @@ component_delta(uint32_t next, uint32_t prev)
}
static void
-transform_rect(struct weston_output *output, pixman_box32_t *r)
-{
- pixman_box32_t s = *r;
-
- switch (output->transform) {
- case WL_OUTPUT_TRANSFORM_FLIPPED:
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- case WL_OUTPUT_TRANSFORM_FLIPPED_180:
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- s.x1 = output->width - r->x2;
- s.x2 = output->width - r->x1;
- break;
- default:
- break;
- }
-
- switch (output->transform) {
- case WL_OUTPUT_TRANSFORM_NORMAL:
- case WL_OUTPUT_TRANSFORM_FLIPPED:
- r->x1 = s.x1;
- r->x2 = s.x2;
- break;
- case WL_OUTPUT_TRANSFORM_90:
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- r->x1 = output->current_mode->width - s.y2;
- r->y1 = s.x1;
- r->x2 = output->current_mode->width - s.y1;
- r->y2 = s.x2;
- break;
- case WL_OUTPUT_TRANSFORM_180:
- case WL_OUTPUT_TRANSFORM_FLIPPED_180:
- r->x1 = output->current_mode->width - s.x2;
- r->y1 = output->current_mode->height - s.y2;
- r->x2 = output->current_mode->width - s.x1;
- r->y2 = output->current_mode->height - s.y1;
- break;
- case WL_OUTPUT_TRANSFORM_270:
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- r->x1 = s.y1;
- r->y1 = output->current_mode->height - s.x2;
- r->x2 = s.y2;
- r->y2 = output->current_mode->height - s.x1;
- break;
- default:
- break;
- }
-
- r->x1 *= output->current_scale;
- r->y1 *= output->current_scale;
- r->x2 *= output->current_scale;
- r->y2 *= output->current_scale;
-}
+weston_recorder_destroy(struct weston_recorder *recorder);
static void
weston_recorder_frame_notify(struct wl_listener *listener, void *data)
@@ -360,7 +313,7 @@ weston_recorder_frame_notify(struct wl_listener *listener, void *data)
struct weston_compositor *compositor = output->compositor;
uint32_t msecs = output->frame_time;
pixman_box32_t *r;
- pixman_region32_t damage;
+ pixman_region32_t damage, transformed_damage;
int i, j, k, n, width, height, run, stride;
uint32_t delta, prev, *d, *s, *p, next;
struct {
@@ -379,15 +332,20 @@ weston_recorder_frame_notify(struct wl_listener *listener, void *data)
outbuf = recorder->tmpbuf;
pixman_region32_init(&damage);
+ pixman_region32_init(&transformed_damage);
pixman_region32_intersect(&damage, &output->region,
&output->previous_damage);
+ pixman_region32_translate(&damage, -output->x, -output->y);
+ weston_transformed_region(output->width, output->height,
+ output->transform, output->current_scale,
+ &damage, &transformed_damage);
+ pixman_region32_fini(&damage);
- r = pixman_region32_rectangles(&damage, &n);
- if (n == 0)
+ r = pixman_region32_rectangles(&transformed_damage, &n);
+ if (n == 0) {
+ pixman_region32_fini(&transformed_damage);
return;
-
- for (i = 0; i < n; i++)
- transform_rect(output, &r[i]);
+ }
header.msecs = msecs;
header.nrects = n;
@@ -450,8 +408,11 @@ weston_recorder_frame_notify(struct wl_listener *listener, void *data)
#endif
}
- pixman_region32_fini(&damage);
+ pixman_region32_fini(&transformed_damage);
recorder->count++;
+
+ if (recorder->destroying)
+ weston_recorder_destroy(recorder);
}
static void
@@ -473,6 +434,7 @@ weston_recorder_create(struct weston_output *output, const char *filename)
recorder->rect = malloc(size);
recorder->total = 0;
recorder->count = 0;
+ recorder->destroying = 0;
recorder->output = output;
if (do_yflip)
@@ -532,15 +494,18 @@ recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *da
{
struct weston_seat *ws = (struct weston_seat *) seat;
struct weston_compositor *ec = ws->compositor;
- struct weston_output *output =
- container_of(ec->output_list.next,
- struct weston_output, link);
- struct wl_listener *listener;
+ struct weston_output *output;
+ struct wl_listener *listener = NULL;
struct weston_recorder *recorder;
static const char filename[] = "capture.wcap";
- listener = wl_signal_get(&output->frame_signal,
- weston_recorder_frame_notify);
+ wl_list_for_each(output, &seat->compositor->output_list, link) {
+ listener = wl_signal_get(&output->frame_signal,
+ weston_recorder_frame_notify);
+ if (listener)
+ break;
+ }
+
if (listener) {
recorder = container_of(listener, struct weston_recorder,
frame_listener);
@@ -549,9 +514,18 @@ recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *da
"stopping recorder, total file size %dM, %d frames\n",
recorder->total / (1024 * 1024), recorder->count);
- weston_recorder_destroy(recorder);
+ recorder->destroying = 1;
+ weston_output_schedule_repaint(recorder->output);
} else {
- weston_log("starting recorder, file %s\n", filename);
+ if (seat->keyboard && seat->keyboard->focus &&
+ seat->keyboard->focus->output)
+ output = seat->keyboard->focus->output;
+ else
+ output = container_of(ec->output_list.next,
+ struct weston_output, link);
+
+ weston_log("starting recorder for output %s, file %s\n",
+ output->name, filename);
weston_recorder_create(output, filename);
}
}
diff --git a/src/spring-tool.c b/src/spring-tool.c
index 935acc4b..41cc52ce 100644
--- a/src/spring-tool.c
+++ b/src/spring-tool.c
@@ -25,7 +25,7 @@
#include "compositor.h"
WL_EXPORT void
-weston_surface_geometry_dirty(struct weston_surface *surface)
+weston_view_geometry_dirty(struct weston_view *view)
{
}
@@ -36,7 +36,7 @@ weston_log(const char *fmt, ...)
}
WL_EXPORT void
-weston_compositor_schedule_repaint(struct weston_compositor *compositor)
+weston_view_schedule_repaint(struct weston_view *view)
{
}
diff --git a/src/tablet-shell.c b/src/tablet-shell.c
deleted file mode 100644
index b055ab23..00000000
--- a/src/tablet-shell.c
+++ /dev/null
@@ -1,575 +0,0 @@
-/*
- * Copyright © 2011 Intel Corporation
- *
- * Permission to use, copy, modify, distribute, and sell this software and
- * its documentation for any purpose is hereby granted without fee, provided
- * that the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the copyright holders not be used in
- * advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission. The copyright holders make
- * no representations about the suitability of this software for any
- * purpose. It is provided "as is" without express or implied warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
- * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "config.h"
-
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <linux/input.h>
-
-#include "compositor.h"
-#include "tablet-shell-server-protocol.h"
-
-/*
- * TODO: Don't fade back from black until we've received a lockscreen
- * attachment.
- */
-
-enum {
- STATE_STARTING,
- STATE_LOCKED,
- STATE_HOME,
- STATE_SWITCHER,
- STATE_TASK
-};
-
-struct tablet_shell {
- struct wl_resource *resource;
-
- struct wl_listener lock_listener;
- struct wl_listener unlock_listener;
- struct wl_listener destroy_listener;
-
- struct weston_compositor *compositor;
- struct weston_process process;
- struct wl_client *client;
-
- struct weston_surface *surface;
-
- struct weston_surface *lockscreen_surface;
- struct wl_listener lockscreen_listener;
- struct weston_layer lockscreen_layer;
-
- struct weston_layer application_layer;
-
- struct weston_surface *home_surface;
- struct weston_layer homescreen_layer;
-
- struct weston_surface *switcher_surface;
- struct wl_listener switcher_listener;
-
- struct tablet_client *current_client;
-
- int state, previous_state;
- int long_press_active;
- struct wl_event_source *long_press_source;
-};
-
-struct tablet_client {
- struct wl_resource *resource;
- struct tablet_shell *shell;
- struct wl_client *client;
- struct weston_surface *surface;
- char *name;
-};
-
-static void
-tablet_shell_destroy(struct wl_listener *listener, void *data);
-
-static struct tablet_shell *
-get_shell(struct weston_compositor *compositor)
-{
- struct wl_listener *l;
-
- l = wl_signal_get(&compositor->destroy_signal, tablet_shell_destroy);
- if (l)
- return container_of(l, struct tablet_shell, destroy_listener);
-
- return NULL;
-}
-
-static void
-tablet_shell_sigchld(struct weston_process *process, int status)
-{
- struct tablet_shell *shell =
- container_of(process, struct tablet_shell, process);
-
- shell->process.pid = 0;
-
- weston_log("weston-tablet-shell crashed, exit code %d\n", status);
-}
-
-static void
-tablet_shell_set_state(struct tablet_shell *shell, int state)
-{
- static const char *states[] = {
- "STARTING", "LOCKED", "HOME", "SWITCHER", "TASK"
- };
-
- weston_log("switching to state %s (from %s)\n",
- states[state], states[shell->state]);
- shell->previous_state = shell->state;
- shell->state = state;
-}
-
-static void
-tablet_shell_surface_configure(struct weston_surface *surface,
- int32_t sx, int32_t sy, int32_t width, int32_t height)
-{
- struct tablet_shell *shell = get_shell(surface->compositor);
-
- if (weston_surface_is_mapped(surface) || width == 0)
- return;
-
- weston_surface_configure(surface, 0, 0, width, height);
-
- if (surface == shell->lockscreen_surface) {
- wl_list_insert(&shell->lockscreen_layer.surface_list,
- &surface->layer_link);
- } else if (surface == shell->switcher_surface) {
- /* */
- } else if (surface == shell->home_surface) {
- if (shell->state == STATE_STARTING) {
- /* homescreen always visible, at the bottom */
- wl_list_insert(&shell->homescreen_layer.surface_list,
- &surface->layer_link);
-
- tablet_shell_set_state(shell, STATE_LOCKED);
- shell->previous_state = STATE_HOME;
- tablet_shell_send_show_lockscreen(shell->resource);
- }
- } else if (shell->current_client &&
- shell->current_client->surface != surface &&
- shell->current_client->client == wl_resource_get_client(surface->resource)) {
- tablet_shell_set_state(shell, STATE_TASK);
- shell->current_client->surface = surface;
- weston_zoom_run(surface, 0.3, 1.0, NULL, NULL);
- wl_list_insert(&shell->application_layer.surface_list,
- &surface->layer_link);
- }
-
- weston_surface_update_transform(surface);
-}
-
-static void
-handle_lockscreen_surface_destroy(struct wl_listener *listener, void *data)
-{
- struct tablet_shell *shell =
- container_of(listener,
- struct tablet_shell, lockscreen_listener);
-
- shell->lockscreen_surface = NULL;
- tablet_shell_set_state(shell, shell->previous_state);
-}
-
-static void
-tablet_shell_set_lockscreen(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *surface_resource)
-{
- struct tablet_shell *shell = wl_resource_get_user_data(resource);
- struct weston_surface *es = wl_resource_get_user_data(surface_resource);
-
- weston_surface_set_position(es, 0, 0);
- shell->lockscreen_surface = es;
- shell->lockscreen_surface->configure = tablet_shell_surface_configure;
- shell->lockscreen_listener.notify = handle_lockscreen_surface_destroy;
- wl_signal_add(&es->destroy_signal, &shell->lockscreen_listener);
-}
-
-static void
-handle_switcher_surface_destroy(struct wl_listener *listener, void *data)
-{
- struct tablet_shell *shell =
- container_of(listener,
- struct tablet_shell, switcher_listener);
-
- shell->switcher_surface = NULL;
- if (shell->state != STATE_LOCKED)
- tablet_shell_set_state(shell, shell->previous_state);
-}
-
-static void
-tablet_shell_set_switcher(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *surface_resource)
-{
- struct tablet_shell *shell = wl_resource_get_user_data(resource);
- struct weston_surface *es = wl_resource_get_user_data(surface_resource);
-
- /* FIXME: Switcher should be centered and the compositor
- * should do the tinting of the background. With the cache
- * layer idea, we should be able to hit the framerate on the
- * fade/zoom in. */
- shell->switcher_surface = es;
- weston_surface_set_position(shell->switcher_surface, 0, 0);
-
- shell->switcher_listener.notify = handle_switcher_surface_destroy;
- wl_signal_add(&es->destroy_signal, &shell->switcher_listener);
-}
-
-static void
-tablet_shell_set_homescreen(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *surface_resource)
-{
- struct tablet_shell *shell = wl_resource_get_user_data(resource);
-
- shell->home_surface = wl_resource_get_user_data(surface_resource);
- shell->home_surface->configure = tablet_shell_surface_configure;
-
- weston_surface_set_position(shell->home_surface, 0, 0);
-}
-
-static void
-minimize_zoom_done(struct weston_surface_animation *zoom, void *data)
-{
- struct tablet_shell *shell = data;
- struct weston_compositor *compositor = shell->compositor;
- struct weston_seat *seat;
-
- wl_list_for_each(seat, &compositor->seat_list, link)
- weston_surface_activate(shell->home_surface, seat);
-}
-
-static void
-tablet_shell_switch_to(struct tablet_shell *shell,
- struct weston_surface *surface)
-{
- struct weston_compositor *compositor = shell->compositor;
- struct weston_seat *seat;
- struct weston_surface *current;
-
- if (shell->state == STATE_SWITCHER) {
- wl_list_remove(&shell->switcher_listener.link);
- shell->switcher_surface = NULL;
- };
-
- if (surface == shell->home_surface) {
- tablet_shell_set_state(shell, STATE_HOME);
-
- if (shell->current_client && shell->current_client->surface) {
- current = shell->current_client->surface;
- weston_zoom_run(current, 1.0, 0.3,
- minimize_zoom_done, shell);
- }
- } else {
- fprintf(stderr, "switch to %p\n", surface);
- wl_list_for_each(seat, &compositor->seat_list, link)
- weston_surface_activate(surface, seat);
- tablet_shell_set_state(shell, STATE_TASK);
- weston_zoom_run(surface, 0.3, 1.0, NULL, NULL);
- }
-}
-
-static void
-tablet_shell_show_grid(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *surface_resource)
-{
- struct tablet_shell *shell = wl_resource_get_user_data(resource);
- struct weston_surface *es = wl_resource_get_user_data(surface_resource);
-
- tablet_shell_switch_to(shell, es);
-}
-
-static void
-tablet_shell_show_panels(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *surface_resource)
-{
- struct tablet_shell *shell = wl_resource_get_user_data(resource);
- struct weston_surface *es = wl_resource_get_user_data(surface_resource);
-
- tablet_shell_switch_to(shell, es);
-}
-
-static void
-destroy_tablet_client(struct wl_resource *resource)
-{
- struct tablet_client *tablet_client =
- wl_resource_get_user_data(resource);
-
- free(tablet_client->name);
- free(tablet_client);
-}
-
-static void
-tablet_client_destroy(struct wl_client *client,
- struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-tablet_client_activate(struct wl_client *client, struct wl_resource *resource)
-{
- struct tablet_client *tablet_client = wl_resource_get_user_data(resource);
- struct tablet_shell *shell = tablet_client->shell;
-
- shell->current_client = tablet_client;
- if (!tablet_client->surface)
- return;
-
- tablet_shell_switch_to(shell, tablet_client->surface);
-}
-
-static const struct tablet_client_interface tablet_client_implementation = {
- tablet_client_destroy,
- tablet_client_activate
-};
-
-static void
-tablet_shell_create_client(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t id, const char *name, int fd)
-{
- struct tablet_shell *shell = wl_resource_get_user_data(resource);
- struct weston_compositor *compositor = shell->compositor;
- struct tablet_client *tablet_client;
-
- tablet_client = malloc(sizeof *tablet_client);
- if (tablet_client == NULL) {
- wl_resource_post_no_memory(resource);
- return;
- }
-
- tablet_client->client = wl_client_create(compositor->wl_display, fd);
- tablet_client->shell = shell;
- tablet_client->name = strdup(name);
-
- tablet_client->resource =
- wl_resource_create(client, &tablet_client_interface, 1, id);
- wl_resource_set_implementation(tablet_client->resource,
- &tablet_client_implementation,
- tablet_client, destroy_tablet_client);
-
- tablet_client->surface = NULL;
- shell->current_client = tablet_client;
-
- weston_log("created client %p, id %d, name %s, fd %d\n",
- tablet_client->client, id, name, fd);
-}
-
-static const struct tablet_shell_interface tablet_shell_implementation = {
- tablet_shell_set_lockscreen,
- tablet_shell_set_switcher,
- tablet_shell_set_homescreen,
- tablet_shell_show_grid,
- tablet_shell_show_panels,
- tablet_shell_create_client
-};
-
-static void
-launch_ux_daemon(struct tablet_shell *shell)
-{
- const char *shell_exe = LIBEXECDIR "/weston-tablet-shell";
-
- shell->client = weston_client_launch(shell->compositor,
- &shell->process,
- shell_exe, tablet_shell_sigchld);
-}
-
-static void
-toggle_switcher(struct tablet_shell *shell)
-{
- switch (shell->state) {
- case STATE_SWITCHER:
- tablet_shell_send_hide_switcher(shell->resource);
- break;
- default:
- tablet_shell_send_show_switcher(shell->resource);
- tablet_shell_set_state(shell, STATE_SWITCHER);
- break;
- }
-}
-
-static void
-tablet_shell_lock(struct wl_listener *listener, void *data)
-{
- struct tablet_shell *shell =
- container_of(listener, struct tablet_shell, lock_listener);
-
- if (shell->state == STATE_LOCKED)
- return;
- if (shell->state == STATE_SWITCHER)
- tablet_shell_send_hide_switcher(shell->resource);
-
- tablet_shell_send_show_lockscreen(shell->resource);
- tablet_shell_set_state(shell, STATE_LOCKED);
-}
-
-static void
-tablet_shell_unlock(struct wl_listener *listener, void *data)
-{
- struct tablet_shell *shell =
- container_of(listener, struct tablet_shell, unlock_listener);
-
- tablet_shell_set_state(shell, STATE_HOME);
-}
-
-static void
-go_home(struct tablet_shell *shell, struct weston_seat *seat)
-{
- if (shell->state == STATE_SWITCHER)
- tablet_shell_send_hide_switcher(shell->resource);
-
- weston_surface_activate(shell->home_surface, seat);
-
- tablet_shell_set_state(shell, STATE_HOME);
-}
-
-static int
-long_press_handler(void *data)
-{
- struct tablet_shell *shell = data;
-
- shell->long_press_active = 0;
- toggle_switcher(shell);
-
- return 1;
-}
-
-static void
-menu_key_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
-{
- struct tablet_shell *shell = data;
-
- if (shell->state == STATE_LOCKED)
- return;
-
- toggle_switcher(shell);
-}
-
-static void
-home_key_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
-{
- struct tablet_shell *shell = data;
-
- if (shell->state == STATE_LOCKED)
- return;
-
- if (1) {
- wl_event_source_timer_update(shell->long_press_source, 500);
- shell->long_press_active = 1;
- } else if (shell->long_press_active) {
- /* This code has never been run ... */
- wl_event_source_timer_update(shell->long_press_source, 0);
- shell->long_press_active = 0;
-
- switch (shell->state) {
- case STATE_HOME:
- case STATE_SWITCHER:
- toggle_switcher(shell);
- break;
- default:
- go_home(shell, (struct weston_seat *) seat);
- break;
- }
- }
-}
-
-static void
-destroy_tablet_shell(struct wl_resource *resource)
-{
-}
-
-static void
-bind_tablet_shell(struct wl_client *client, void *data, uint32_t version,
- uint32_t id)
-{
- struct tablet_shell *shell = data;
-
- if (shell->client != client)
- /* Throw an error or just let the client fail when it
- * tries to access the object?. */
- return;
-
- shell->resource =
- wl_resource_create(client, &tablet_shell_interface, 1, id);
- wl_resource_set_implementation(shell->resource,
- &tablet_shell_implementation,
- shell, destroy_tablet_shell);
-}
-
-static void
-tablet_shell_destroy(struct wl_listener *listener, void *data)
-{
- struct tablet_shell *shell =
- container_of(listener, struct tablet_shell, destroy_listener);
-
- if (shell->home_surface)
- shell->home_surface->configure = NULL;
-
- if (shell->lockscreen_surface)
- shell->lockscreen_surface->configure = NULL;
-
- wl_event_source_remove(shell->long_press_source);
- free(shell);
-}
-
-WL_EXPORT int
-module_init(struct weston_compositor *compositor,
- int *argc, char *argv[])
-{
- struct tablet_shell *shell;
- struct wl_event_loop *loop;
-
- shell = zalloc(sizeof *shell);
- if (shell == NULL)
- return -1;
-
- shell->compositor = compositor;
-
- shell->destroy_listener.notify = tablet_shell_destroy;
- wl_signal_add(&compositor->destroy_signal, &shell->destroy_listener);
- shell->lock_listener.notify = tablet_shell_lock;
- wl_signal_add(&compositor->idle_signal, &shell->lock_listener);
- shell->unlock_listener.notify = tablet_shell_unlock;
- wl_signal_add(&compositor->wake_signal, &shell->unlock_listener);
-
- /* FIXME: This will make the object available to all clients. */
- wl_global_create(compositor->wl_display, &tablet_shell_interface, 1,
- shell, bind_tablet_shell);
-
- loop = wl_display_get_event_loop(compositor->wl_display);
- shell->long_press_source =
- wl_event_loop_add_timer(loop, long_press_handler, shell);
-
- weston_compositor_add_key_binding(compositor, KEY_LEFTMETA, 0,
- home_key_binding, shell);
- weston_compositor_add_key_binding(compositor, KEY_RIGHTMETA, 0,
- home_key_binding, shell);
- weston_compositor_add_key_binding(compositor, KEY_LEFTMETA,
- MODIFIER_SUPER, home_key_binding,
- shell);
- weston_compositor_add_key_binding(compositor, KEY_RIGHTMETA,
- MODIFIER_SUPER, home_key_binding,
- shell);
- weston_compositor_add_key_binding(compositor, KEY_COMPOSE, 0,
- menu_key_binding, shell);
-
- weston_layer_init(&shell->homescreen_layer,
- &compositor->cursor_layer.link);
- weston_layer_init(&shell->application_layer,
- &compositor->cursor_layer.link);
- weston_layer_init(&shell->lockscreen_layer,
- &compositor->cursor_layer.link);
- launch_ux_daemon(shell);
-
- tablet_shell_set_state(shell, STATE_STARTING);
-
- return 0;
-}
diff --git a/src/text-backend.c b/src/text-backend.c
index 107ccd63..59a8b946 100644
--- a/src/text-backend.c
+++ b/src/text-backend.c
@@ -598,8 +598,8 @@ input_method_context_grab_keyboard(struct wl_client *client,
context->keyboard = cr;
wl_keyboard_send_keymap(cr, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
- seat->xkb_info->keymap_fd,
- seat->xkb_info->keymap_size);
+ keyboard->xkb_info->keymap_fd,
+ keyboard->xkb_info->keymap_size);
if (keyboard->grab != &keyboard->default_grab) {
weston_keyboard_end_grab(keyboard);
diff --git a/src/udev-seat.c b/src/udev-seat.c
index ffaf08aa..f9723f2f 100644
--- a/src/udev-seat.c
+++ b/src/udev-seat.c
@@ -83,11 +83,11 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
device = evdev_device_create(&seat->base, devnode, fd);
if (device == EVDEV_UNHANDLED_DEVICE) {
- close(fd);
+ weston_launcher_close(c->launcher, fd);
weston_log("not using input device '%s'.\n", devnode);
return 0;
} else if (device == NULL) {
- close(fd);
+ weston_launcher_close(c->launcher, fd);
weston_log("failed to create input device '%s'.\n", devnode);
return 0;
}
@@ -123,8 +123,9 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
output_name = udev_device_get_property_value(udev_device, "WL_OUTPUT");
if (output_name) {
+ device->output_name = strdup(output_name);
wl_list_for_each(output, &c->output_list, link)
- if (strcmp(output->name, output_name) == 0)
+ if (strcmp(output->name, device->output_name) == 0)
device->output = output;
}
@@ -219,9 +220,11 @@ evdev_udev_handler(int fd, uint32_t mask, void *data)
if (!strcmp(device->devnode, devnode)) {
weston_log("input device %s, %s removed\n",
device->devname, device->devnode);
+ weston_launcher_close(input->compositor->launcher,
+ device->fd);
evdev_device_destroy(device);
- break;
- }
+ break;
+ }
}
}
@@ -278,8 +281,11 @@ udev_input_remove_devices(struct udev_input *input)
struct udev_seat *seat;
wl_list_for_each(seat, &input->compositor->seat_list, base.link) {
- wl_list_for_each_safe(device, next, &seat->devices_list, link)
+ wl_list_for_each_safe(device, next, &seat->devices_list, link) {
+ weston_launcher_close(input->compositor->launcher,
+ device->fd);
evdev_device_destroy(device);
+ }
if (seat->base.keyboard)
notify_keyboard_focus_out(&seat->base);
@@ -338,6 +344,20 @@ drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
evdev_led_update(device, leds);
}
+static void
+notify_output_create(struct wl_listener *listener, void *data)
+{
+ struct udev_seat *seat = container_of(listener, struct udev_seat,
+ output_create_listener);
+ struct evdev_device *device;
+ struct weston_output *output = data;
+
+ wl_list_for_each(device, &seat->devices_list, link)
+ if (device->output_name &&
+ strcmp(output->name, device->output_name) == 0)
+ device->output = output;
+}
+
static struct udev_seat *
udev_seat_create(struct weston_compositor *c, const char *seat_name)
{
@@ -350,6 +370,10 @@ udev_seat_create(struct weston_compositor *c, const char *seat_name)
weston_seat_init(&seat->base, c, seat_name);
seat->base.led_update = drm_led_update;
+ seat->output_create_listener.notify = notify_output_create;
+ wl_signal_add(&c->output_created_signal,
+ &seat->output_create_listener);
+
wl_list_init(&seat->devices_list);
return seat;
}
@@ -358,6 +382,7 @@ static void
udev_seat_destroy(struct udev_seat *seat)
{
weston_seat_release(&seat->base);
+ wl_list_remove(&seat->output_create_listener.link);
free(seat);
}
diff --git a/src/udev-seat.h b/src/udev-seat.h
index 4cb6f071..e0d491ab 100644
--- a/src/udev-seat.h
+++ b/src/udev-seat.h
@@ -32,6 +32,7 @@
struct udev_seat {
struct weston_seat base;
struct wl_list devices_list;
+ struct wl_listener output_create_listener;
};
struct udev_input {
@@ -42,7 +43,6 @@ struct udev_input {
int enabled;
};
-
int udev_input_enable(struct udev_input *input, struct udev *udev);
void udev_input_disable(struct udev_input *input);
int udev_input_init(struct udev_input *input,
diff --git a/src/vertex-clipping.c b/src/vertex-clipping.c
index 603ce6f4..db527e14 100644
--- a/src/vertex-clipping.c
+++ b/src/vertex-clipping.c
@@ -23,18 +23,16 @@
#include <float.h>
#include <math.h>
-#include <GLES2/gl2.h>
-
#include "vertex-clipping.h"
-GLfloat
-float_difference(GLfloat a, GLfloat b)
+float
+float_difference(float a, float b)
{
/* http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/ */
- static const GLfloat max_diff = 4.0f * FLT_MIN;
- static const GLfloat max_rel_diff = 4.0e-5;
- GLfloat diff = a - b;
- GLfloat adiff = fabsf(diff);
+ static const float max_diff = 4.0f * FLT_MIN;
+ static const float max_rel_diff = 4.0e-5;
+ float diff = a - b;
+ float adiff = fabsf(diff);
if (adiff <= max_diff)
return 0.0f;
@@ -50,12 +48,12 @@ float_difference(GLfloat a, GLfloat b)
/* A line segment (p1x, p1y)-(p2x, p2y) intersects the line x = x_arg.
* Compute the y coordinate of the intersection.
*/
-static GLfloat
-clip_intersect_y(GLfloat p1x, GLfloat p1y, GLfloat p2x, GLfloat p2y,
- GLfloat x_arg)
+static float
+clip_intersect_y(float p1x, float p1y, float p2x, float p2y,
+ float x_arg)
{
- GLfloat a;
- GLfloat diff = float_difference(p1x, p2x);
+ float a;
+ float diff = float_difference(p1x, p2x);
/* Practically vertical line segment, yet the end points have already
* been determined to be on different sides of the line. Therefore
@@ -72,12 +70,12 @@ clip_intersect_y(GLfloat p1x, GLfloat p1y, GLfloat p2x, GLfloat p2y,
/* A line segment (p1x, p1y)-(p2x, p2y) intersects the line y = y_arg.
* Compute the x coordinate of the intersection.
*/
-static GLfloat
-clip_intersect_x(GLfloat p1x, GLfloat p1y, GLfloat p2x, GLfloat p2y,
- GLfloat y_arg)
+static float
+clip_intersect_x(float p1x, float p1y, float p2x, float p2y,
+ float y_arg)
{
- GLfloat a;
- GLfloat diff = float_difference(p1y, p2y);
+ float a;
+ float diff = float_difference(p1y, p2y);
/* Practically horizontal line segment, yet the end points have already
* been determined to be on different sides of the line. Therefore
@@ -99,32 +97,32 @@ enum path_transition {
};
static void
-clip_append_vertex(struct clip_context *ctx, GLfloat x, GLfloat y)
+clip_append_vertex(struct clip_context *ctx, float x, float y)
{
*ctx->vertices.x++ = x;
*ctx->vertices.y++ = y;
}
static enum path_transition
-path_transition_left_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
+path_transition_left_edge(struct clip_context *ctx, float x, float y)
{
return ((ctx->prev.x >= ctx->clip.x1) << 1) | (x >= ctx->clip.x1);
}
static enum path_transition
-path_transition_right_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
+path_transition_right_edge(struct clip_context *ctx, float x, float y)
{
return ((ctx->prev.x < ctx->clip.x2) << 1) | (x < ctx->clip.x2);
}
static enum path_transition
-path_transition_top_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
+path_transition_top_edge(struct clip_context *ctx, float x, float y)
{
return ((ctx->prev.y >= ctx->clip.y1) << 1) | (y >= ctx->clip.y1);
}
static enum path_transition
-path_transition_bottom_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
+path_transition_bottom_edge(struct clip_context *ctx, float x, float y)
{
return ((ctx->prev.y < ctx->clip.y2) << 1) | (y < ctx->clip.y2);
}
@@ -132,9 +130,9 @@ path_transition_bottom_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
static void
clip_polygon_leftright(struct clip_context *ctx,
enum path_transition transition,
- GLfloat x, GLfloat y, GLfloat clip_x)
+ float x, float y, float clip_x)
{
- GLfloat yi;
+ float yi;
switch (transition) {
case PATH_TRANSITION_IN_TO_IN:
@@ -163,9 +161,9 @@ clip_polygon_leftright(struct clip_context *ctx,
static void
clip_polygon_topbottom(struct clip_context *ctx,
enum path_transition transition,
- GLfloat x, GLfloat y, GLfloat clip_y)
+ float x, float y, float clip_y)
{
- GLfloat xi;
+ float xi;
switch (transition) {
case PATH_TRANSITION_IN_TO_IN:
@@ -193,7 +191,7 @@ clip_polygon_topbottom(struct clip_context *ctx,
static void
clip_context_prepare(struct clip_context *ctx, const struct polygon8 *src,
- GLfloat *dst_x, GLfloat *dst_y)
+ float *dst_x, float *dst_y)
{
ctx->prev.x = src->x[src->n - 1];
ctx->prev.y = src->y[src->n - 1];
@@ -203,7 +201,7 @@ clip_context_prepare(struct clip_context *ctx, const struct polygon8 *src,
static int
clip_polygon_left(struct clip_context *ctx, const struct polygon8 *src,
- GLfloat *dst_x, GLfloat *dst_y)
+ float *dst_x, float *dst_y)
{
enum path_transition trans;
int i;
@@ -219,7 +217,7 @@ clip_polygon_left(struct clip_context *ctx, const struct polygon8 *src,
static int
clip_polygon_right(struct clip_context *ctx, const struct polygon8 *src,
- GLfloat *dst_x, GLfloat *dst_y)
+ float *dst_x, float *dst_y)
{
enum path_transition trans;
int i;
@@ -235,7 +233,7 @@ clip_polygon_right(struct clip_context *ctx, const struct polygon8 *src,
static int
clip_polygon_top(struct clip_context *ctx, const struct polygon8 *src,
- GLfloat *dst_x, GLfloat *dst_y)
+ float *dst_x, float *dst_y)
{
enum path_transition trans;
int i;
@@ -251,7 +249,7 @@ clip_polygon_top(struct clip_context *ctx, const struct polygon8 *src,
static int
clip_polygon_bottom(struct clip_context *ctx, const struct polygon8 *src,
- GLfloat *dst_x, GLfloat *dst_y)
+ float *dst_x, float *dst_y)
{
enum path_transition trans;
int i;
@@ -272,8 +270,8 @@ clip_polygon_bottom(struct clip_context *ctx, const struct polygon8 *src,
int
clip_simple(struct clip_context *ctx,
struct polygon8 *surf,
- GLfloat *ex,
- GLfloat *ey)
+ float *ex,
+ float *ey)
{
int i;
for (i = 0; i < surf->n; i++) {
@@ -286,8 +284,8 @@ clip_simple(struct clip_context *ctx,
int
clip_transformed(struct clip_context *ctx,
struct polygon8 *surf,
- GLfloat *ex,
- GLfloat *ey)
+ float *ex,
+ float *ey)
{
struct polygon8 polygon;
int i, n;
diff --git a/src/vertex-clipping.h b/src/vertex-clipping.h
index a16b1dfc..f6a98b8d 100644
--- a/src/vertex-clipping.h
+++ b/src/vertex-clipping.h
@@ -22,44 +22,42 @@
#ifndef _WESTON_VERTEX_CLIPPING_H
#define _WESTON_VERTEX_CLIPPING_H
-#include <GLES2/gl2.h>
-
struct polygon8 {
- GLfloat x[8];
- GLfloat y[8];
+ float x[8];
+ float y[8];
int n;
};
struct clip_context {
struct {
- GLfloat x;
- GLfloat y;
+ float x;
+ float y;
} prev;
struct {
- GLfloat x1, y1;
- GLfloat x2, y2;
+ float x1, y1;
+ float x2, y2;
} clip;
struct {
- GLfloat *x;
- GLfloat *y;
+ float *x;
+ float *y;
} vertices;
};
-GLfloat
-float_difference(GLfloat a, GLfloat b);
+float
+float_difference(float a, float b);
int
clip_simple(struct clip_context *ctx,
struct polygon8 *surf,
- GLfloat *ex,
- GLfloat *ey);
+ float *ex,
+ float *ey);
int
clip_transformed(struct clip_context *ctx,
struct polygon8 *surf,
- GLfloat *ex,
- GLfloat *ey);\
+ float *ex,
+ float *ey);\
#endif
diff --git a/src/weston-launch.c b/src/weston-launch.c
index d8364c85..56e22b10 100644
--- a/src/weston-launch.c
+++ b/src/weston-launch.c
@@ -50,8 +50,6 @@
#include <grp.h>
#include <security/pam_appl.h>
-#include <xf86drm.h>
-
#ifdef HAVE_SYSTEMD_LOGIN
#include <systemd/sd-login.h>
#endif
@@ -70,6 +68,26 @@
#define MAX_ARGV_SIZE 256
+#ifdef HAVE_LIBDRM
+
+#include <xf86drm.h>
+
+#else
+
+static inline int
+drmDropMaster(int drm_fd)
+{
+ return 0;
+}
+
+static inline int
+drmSetMaster(int drm_fd)
+{
+ return 0;
+}
+
+#endif
+
struct weston_launch {
struct pam_conv pc;
pam_handle_t *ph;
diff --git a/src/zoom.c b/src/zoom.c
index 220b2b6e..622c0d7c 100644
--- a/src/zoom.c
+++ b/src/zoom.c
@@ -27,97 +27,6 @@
#include "compositor.h"
#include "text-cursor-position-server-protocol.h"
-struct text_cursor_position {
- struct weston_compositor *ec;
- struct wl_global *global;
- struct wl_listener destroy_listener;
-};
-
-static void
-text_cursor_position_notify(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *surface_resource,
- wl_fixed_t x, wl_fixed_t y)
-{
- struct weston_surface *surface =
- wl_resource_get_user_data(surface_resource);
-
- weston_text_cursor_position_notify(surface, x, y);
-}
-
-struct text_cursor_position_interface text_cursor_position_implementation = {
- text_cursor_position_notify
-};
-
-static void
-bind_text_cursor_position(struct wl_client *client,
- void *data, uint32_t version, uint32_t id)
-{
- struct wl_resource *resource;
-
- resource = wl_resource_create(client,
- &text_cursor_position_interface, 1, id);
- if (resource)
- wl_resource_set_implementation(resource,
- &text_cursor_position_implementation,
- data, NULL);
-}
-
-static void
-text_cursor_position_notifier_destroy(struct wl_listener *listener, void *data)
-{
- struct text_cursor_position *text_cursor_position =
- container_of(listener, struct text_cursor_position, destroy_listener);
-
- wl_global_destroy(text_cursor_position->global);
- free(text_cursor_position);
-}
-
-void
-text_cursor_position_notifier_create(struct weston_compositor *ec)
-{
- struct text_cursor_position *text_cursor_position;
-
- text_cursor_position = malloc(sizeof *text_cursor_position);
- if (text_cursor_position == NULL)
- return;
-
- text_cursor_position->ec = ec;
-
- text_cursor_position->global =
- wl_global_create(ec->wl_display,
- &text_cursor_position_interface, 1,
- text_cursor_position,
- bind_text_cursor_position);
-
- text_cursor_position->destroy_listener.notify =
- text_cursor_position_notifier_destroy;
- wl_signal_add(&ec->destroy_signal, &text_cursor_position->destroy_listener);
-}
-
-WL_EXPORT void
-weston_text_cursor_position_notify(struct weston_surface *surface,
- wl_fixed_t cur_pos_x,
- wl_fixed_t cur_pos_y)
-{
- struct weston_output *output;
- wl_fixed_t global_x, global_y;
-
- weston_surface_to_global_fixed(surface, cur_pos_x, cur_pos_y,
- &global_x, &global_y);
-
- wl_list_for_each(output, &surface->compositor->output_list, link)
- if (output->zoom.active &&
- pixman_region32_contains_point(&output->region,
- wl_fixed_to_int(global_x),
- wl_fixed_to_int(global_y),
- NULL)) {
- output->zoom.text_cursor.x = global_x;
- output->zoom.text_cursor.y = global_y;
- weston_output_update_zoom(output, ZOOM_FOCUS_TEXT);
- }
-}
-
static void
weston_zoom_frame_z(struct weston_animation *animation,
struct weston_output *output, uint32_t msecs)
@@ -136,6 +45,7 @@ weston_zoom_frame_z(struct weston_animation *animation,
if (output->zoom.active && output->zoom.level <= 0.0) {
output->zoom.active = 0;
output->disable_planes--;
+ wl_list_remove(&output->zoom.motion_listener.link);
}
output->zoom.spring_z.current = output->zoom.level;
wl_list_remove(&animation->link);
@@ -176,12 +86,8 @@ weston_zoom_frame_xy(struct weston_animation *animation,
if (weston_spring_done(&output->zoom.spring_xy)) {
output->zoom.spring_xy.current = output->zoom.spring_xy.target;
- output->zoom.current.x =
- output->zoom.type == ZOOM_FOCUS_POINTER ?
- seat->pointer->x : output->zoom.text_cursor.x;
- output->zoom.current.y =
- output->zoom.type == ZOOM_FOCUS_POINTER ?
- seat->pointer->y : output->zoom.text_cursor.y;
+ output->zoom.current.x = seat->pointer->x;
+ output->zoom.current.y = seat->pointer->y;
wl_list_remove(&animation->link);
wl_list_init(&animation->link);
}
@@ -251,7 +157,6 @@ weston_zoom_apply_output_transform(struct weston_output *output,
static void
weston_output_update_zoom_transform(struct weston_output *output)
{
- uint32_t type = output->zoom.type;
float global_x, global_y;
wl_fixed_t x = output->zoom.current.x;
wl_fixed_t y = output->zoom.current.y;
@@ -265,8 +170,7 @@ weston_output_update_zoom_transform(struct weston_output *output)
level == 0.0f)
return;
- if (type == ZOOM_FOCUS_POINTER &&
- wl_list_empty(&output->zoom.animation_xy.link))
+ if (wl_list_empty(&output->zoom.animation_xy.link))
zoom_area_center_from_pointer(output, &x, &y);
global_x = wl_fixed_to_double(x);
@@ -297,39 +201,8 @@ weston_output_update_zoom_transform(struct weston_output *output)
}
static void
-weston_zoom_transition(struct weston_output *output, uint32_t type,
- wl_fixed_t x, wl_fixed_t y)
+weston_zoom_transition(struct weston_output *output, wl_fixed_t x, wl_fixed_t y)
{
- if (output->zoom.type != type) {
- /* Set from/to points and start animation */
- output->zoom.spring_xy.current = 0.0;
- output->zoom.spring_xy.previous = 0.0;
- output->zoom.spring_xy.target = 1.0;
-
- if (wl_list_empty(&output->zoom.animation_xy.link)) {
- output->zoom.animation_xy.frame_counter = 0;
- wl_list_insert(output->animation_list.prev,
- &output->zoom.animation_xy.link);
-
- output->zoom.from.x = (type == ZOOM_FOCUS_TEXT) ?
- x : output->zoom.text_cursor.x;
- output->zoom.from.y = (type == ZOOM_FOCUS_TEXT) ?
- y : output->zoom.text_cursor.y;
- } else {
- output->zoom.from.x = output->zoom.current.x;
- output->zoom.from.y = output->zoom.current.y;
- }
-
- output->zoom.to.x = (type == ZOOM_FOCUS_POINTER) ?
- x : output->zoom.text_cursor.x;
- output->zoom.to.y = (type == ZOOM_FOCUS_POINTER) ?
- y : output->zoom.text_cursor.y;
- output->zoom.current.x = output->zoom.from.x;
- output->zoom.current.y = output->zoom.from.y;
-
- output->zoom.type = type;
- }
-
if (output->zoom.level != output->zoom.spring_z.current) {
output->zoom.spring_z.target = output->zoom.level;
if (wl_list_empty(&output->zoom.animation_z.link)) {
@@ -344,7 +217,7 @@ weston_zoom_transition(struct weston_output *output, uint32_t type,
}
WL_EXPORT void
-weston_output_update_zoom(struct weston_output *output, uint32_t type)
+weston_output_update_zoom(struct weston_output *output)
{
struct weston_seat *seat = weston_zoom_pick_seat(output->compositor);
wl_fixed_t x = seat->pointer->x;
@@ -352,30 +225,43 @@ weston_output_update_zoom(struct weston_output *output, uint32_t type)
zoom_area_center_from_pointer(output, &x, &y);
- if (type == ZOOM_FOCUS_POINTER) {
- if (wl_list_empty(&output->zoom.animation_xy.link)) {
- output->zoom.current.x = seat->pointer->x;
- output->zoom.current.y = seat->pointer->y;
- } else {
- output->zoom.to.x = x;
- output->zoom.to.y = y;
- }
- }
-
- if (type == ZOOM_FOCUS_TEXT) {
- if (wl_list_empty(&output->zoom.animation_xy.link)) {
- output->zoom.current.x = output->zoom.text_cursor.x;
- output->zoom.current.y = output->zoom.text_cursor.y;
- } else {
- output->zoom.to.x = output->zoom.text_cursor.x;
- output->zoom.to.y = output->zoom.text_cursor.y;
- }
+ if (wl_list_empty(&output->zoom.animation_xy.link)) {
+ output->zoom.current.x = seat->pointer->x;
+ output->zoom.current.y = seat->pointer->y;
+ } else {
+ output->zoom.to.x = x;
+ output->zoom.to.y = y;
}
- weston_zoom_transition(output, type, x, y);
+ weston_zoom_transition(output, x, y);
weston_output_update_zoom_transform(output);
}
+static void
+motion(struct wl_listener *listener, void *data)
+{
+ struct weston_output_zoom *zoom =
+ container_of(listener, struct weston_output_zoom, motion_listener);
+ struct weston_output *output =
+ container_of(zoom, struct weston_output, zoom);
+
+ weston_output_update_zoom(output);
+}
+
+WL_EXPORT void
+weston_output_activate_zoom(struct weston_output *output)
+{
+ struct weston_seat *seat = weston_zoom_pick_seat(output->compositor);
+
+ if (output->zoom.active)
+ return;
+
+ output->zoom.active = 1;
+ output->disable_planes++;
+ wl_signal_add(&seat->pointer->motion_signal,
+ &output->zoom.motion_listener);
+}
+
WL_EXPORT void
weston_output_init_zoom(struct weston_output *output)
{
@@ -385,7 +271,6 @@ weston_output_init_zoom(struct weston_output *output)
output->zoom.level = 0.0;
output->zoom.trans_x = 0.0;
output->zoom.trans_y = 0.0;
- output->zoom.type = ZOOM_FOCUS_POINTER;
weston_spring_init(&output->zoom.spring_z, 250.0, 0.0, 0.0);
output->zoom.spring_z.friction = 1000;
output->zoom.animation_z.frame = weston_zoom_frame_z;
@@ -394,4 +279,5 @@ weston_output_init_zoom(struct weston_output *output)
output->zoom.spring_xy.friction = 1000;
output->zoom.animation_xy.frame = weston_zoom_frame_xy;
wl_list_init(&output->zoom.animation_xy.link);
+ output->zoom.motion_listener.notify = motion;
}
diff --git a/tests/.gitignore b/tests/.gitignore
index aba378c3..32a64921 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1,3 +1,4 @@
+*.log
*.test
*.trs
*.weston
@@ -9,5 +10,3 @@ test-text-client
wayland-test-client-protocol.h
wayland-test-protocol.c
wayland-test-server-protocol.h
-subsurface-client-protocol.h
-subsurface-protocol.c
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 5be52c6e..8b851460 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -8,9 +8,8 @@ module_tests = \
surface-test.la \
surface-global-test.la
-weston_test = weston-test.la
-
weston_tests = \
+ bad_buffer.weston \
keyboard.weston \
event.weston \
button.weston \
@@ -18,6 +17,11 @@ weston_tests = \
subsurface.weston \
$(xwayland_test)
+if ENABLE_EGL
+weston_tests += \
+ buffer-count.weston
+endif
+
AM_TESTS_ENVIRONMENT = \
abs_builddir='$(abs_builddir)'; export abs_builddir;
@@ -32,8 +36,10 @@ clean-local:
export abs_builddir
noinst_LTLIBRARIES = \
- $(weston_test) \
- $(module_tests)
+ weston-test.la \
+ $(module_tests) \
+ libtest-runner.la \
+ libtest-client.la
noinst_PROGRAMS = \
$(setbacklight) \
@@ -54,8 +60,7 @@ surface_global_test_la_LDFLAGS = -module -avoid-version -rpath $(libdir)
surface_test_la_SOURCES = surface-test.c
surface_test_la_LDFLAGS = -module -avoid-version -rpath $(libdir)
-weston_test_la_LIBADD = $(COMPOSITOR_LIBS) \
- ../shared/libshared.la
+weston_test_la_LIBADD = $(COMPOSITOR_LIBS) ../shared/libshared.la
weston_test_la_LDFLAGS = -module -avoid-version -rpath $(libdir)
weston_test_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
weston_test_la_SOURCES = \
@@ -63,63 +68,66 @@ weston_test_la_SOURCES = \
wayland-test-protocol.c \
wayland-test-server-protocol.h
-weston_test_runner_src = \
- weston-test-runner.c \
- weston-test-runner.h
-
-check_LTLIBRARIES = libshared-test.la
+if ENABLE_EGL
+weston_test_la_CFLAGS += $(EGL_TESTS_CFLAGS)
+weston_test_la_LDFLAGS += $(EGL_TESTS_LIBS)
+endif
-libshared_test_la_SOURCES = \
- $(weston_test_runner_src)
-libshared_test_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
+libtest_runner_la_SOURCES = \
+ weston-test-runner.c \
+ weston-test-runner.h
+libtest_runner_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
config_parser_test_LDADD = \
../shared/libshared.la \
- libshared-test.la \
+ libtest-runner.la \
$(COMPOSITOR_LIBS)
config_parser_test_SOURCES = \
config-parser-test.c
+
vertex_clip_test_SOURCES = \
vertex-clip-test.c \
../src/vertex-clipping.c \
../src/vertex-clipping.h
vertex_clip_test_LDADD = \
- libshared-test.la \
+ libtest-runner.la \
-lm -lrt
-weston_test_client_src = \
+libtest_client_la_SOURCES = \
weston-test-client-helper.c \
weston-test-client-helper.h \
wayland-test-protocol.c \
- wayland-test-client-protocol.h \
- subsurface-protocol.c \
- subsurface-client-protocol.h
-weston_test_client_libs = \
- $(SIMPLE_CLIENT_LIBS) \
+ wayland-test-client-protocol.h
+libtest_client_la_LIBADD = \
+ $(TEST_CLIENT_LIBS) \
../shared/libshared.la \
- libshared-test.la
+ libtest-runner.la
-keyboard_weston_SOURCES = keyboard-test.c $(weston_test_client_src)
-keyboard_weston_LDADD = $(weston_test_client_libs)
+bad_buffer_weston_SOURCES = bad-buffer-test.c
+bad_buffer_weston_LDADD = libtest-client.la
-event_weston_SOURCES = event-test.c $(weston_test_client_src)
-event_weston_LDADD = $(weston_test_client_libs)
+keyboard_weston_SOURCES = keyboard-test.c
+keyboard_weston_LDADD = libtest-client.la
-button_weston_SOURCES = button-test.c $(weston_test_client_src)
-button_weston_LDADD = $(weston_test_client_libs)
+event_weston_SOURCES = event-test.c
+event_weston_LDADD = libtest-client.la
-text_weston_SOURCES = \
- text-test.c \
- ../clients/text-protocol.c \
- $(weston_test_client_src)
-text_weston_LDADD = $(weston_test_client_libs)
+button_weston_SOURCES = button-test.c
+button_weston_LDADD = libtest-client.la
-subsurface_weston_SOURCES = subsurface-test.c $(weston_test_client_src)
-subsurface_weston_LDADD = $(weston_test_client_libs)
+text_weston_SOURCES = text-test.c text-protocol.c
+text_weston_LDADD = libtest-client.la
-xwayland_weston_SOURCES = xwayland-test.c $(weston_test_client_src)
+subsurface_weston_SOURCES = subsurface-test.c
+subsurface_weston_LDADD = libtest-client.la
-xwayland_weston_LDADD = $(weston_test_client_libs) $(XWAYLAND_TEST_LIBS)
+buffer_count_weston_SOURCES = buffer-count-test.c
+buffer_count_weston_CFLAGS = $(GCC_CFLAGS) $(EGL_TESTS_CFLAGS)
+buffer_count_weston_LDADD = libtest-client.la $(EGL_TESTS_LIBS)
+
+xwayland_weston_SOURCES = xwayland-test.c
+xwayland_weston_CFLAGS = $(GCC_CFLAGS) $(XWAYLAND_TEST_CFLAGS)
+xwayland_weston_LDADD = libtest-client.la $(XWAYLAND_TEST_LIBS)
if ENABLE_XWAYLAND_TEST
xwayland_test = xwayland.weston
@@ -146,11 +154,11 @@ endif
EXTRA_DIST = weston-tests-env
BUILT_SOURCES = \
- subsurface-protocol.c \
- subsurface-client-protocol.h \
wayland-test-protocol.c \
wayland-test-server-protocol.h \
- wayland-test-client-protocol.h
+ wayland-test-client-protocol.h \
+ text-protocol.c \
+ text-client-protocol.h
CLEANFILES = $(BUILT_SOURCES)
diff --git a/tests/bad-buffer-test.c b/tests/bad-buffer-test.c
new file mode 100644
index 00000000..4f5f8109
--- /dev/null
+++ b/tests/bad-buffer-test.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ * Copyright © 2013 Collabora, Ltd.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "../shared/os-compatibility.h"
+#include "weston-test-client-helper.h"
+
+/* tests, that attempt to crash the compositor on purpose */
+
+static struct wl_buffer *
+create_bad_shm_buffer(struct client *client, int width, int height)
+{
+ struct wl_shm *shm = client->wl_shm;
+ int stride = width * 4;
+ int size = stride * height;
+ struct wl_shm_pool *pool;
+ struct wl_buffer *buffer;
+ int fd;
+
+ fd = os_create_anonymous_file(size);
+ assert(fd >= 0);
+
+ pool = wl_shm_create_pool(shm, fd, size);
+ buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride,
+ WL_SHM_FORMAT_ARGB8888);
+ wl_shm_pool_destroy(pool);
+
+ /* Truncate the file to a small size, so that the compositor
+ * will access it out-of-bounds, and hit SIGBUS.
+ */
+ assert(ftruncate(fd, 12) == 0);
+ close(fd);
+
+ return buffer;
+}
+
+FAIL_TEST(test_truncated_shm_file)
+{
+ struct client *client;
+ struct wl_buffer *bad_buffer;
+ struct wl_surface *surface;
+ int frame;
+
+ client = client_create(46, 76, 111, 134);
+ assert(client);
+ surface = client->surface->wl_surface;
+
+ bad_buffer = create_bad_shm_buffer(client, 200, 200);
+
+ wl_surface_attach(surface, bad_buffer, 0, 0);
+ wl_surface_damage(surface, 0, 0, 200, 200);
+ frame_callback_set(surface, &frame);
+ wl_surface_commit(surface);
+ frame_callback_wait(client, &frame);
+}
diff --git a/tests/buffer-count-test.c b/tests/buffer-count-test.c
new file mode 100644
index 00000000..c7ddeb64
--- /dev/null
+++ b/tests/buffer-count-test.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "weston-test-client-helper.h"
+#include <stdio.h>
+#include <poll.h>
+#include <time.h>
+
+#include <EGL/egl.h>
+#include <wayland-egl.h>
+#include <GLES2/gl2.h>
+
+struct test_data {
+ struct client *client;
+
+ EGLDisplay egl_dpy;
+ EGLContext egl_ctx;
+ EGLConfig egl_conf;
+ EGLSurface egl_surface;
+};
+
+static void
+init_egl(struct test_data *test_data)
+{
+ struct wl_egl_window *native_window;
+ struct surface *surface = test_data->client->surface;
+ const char *str, *mesa;
+
+ static const EGLint context_attribs[] = {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE
+ };
+
+ EGLint config_attribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RED_SIZE, 1,
+ EGL_GREEN_SIZE, 1,
+ EGL_BLUE_SIZE, 1,
+ EGL_ALPHA_SIZE, 0,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE
+ };
+
+ EGLint major, minor, n;
+ EGLBoolean ret;
+
+ test_data->egl_dpy = eglGetDisplay((EGLNativeDisplayType)
+ test_data->client->wl_display);
+ assert(test_data->egl_dpy);
+
+ ret = eglInitialize(test_data->egl_dpy, &major, &minor);
+ assert(ret == EGL_TRUE);
+ ret = eglBindAPI(EGL_OPENGL_ES_API);
+ assert(ret == EGL_TRUE);
+
+ ret = eglChooseConfig(test_data->egl_dpy, config_attribs,
+ &test_data->egl_conf, 1, &n);
+ assert(ret && n == 1);
+
+ test_data->egl_ctx = eglCreateContext(test_data->egl_dpy,
+ test_data->egl_conf,
+ EGL_NO_CONTEXT, context_attribs);
+ assert(test_data->egl_ctx);
+
+ native_window =
+ wl_egl_window_create(surface->wl_surface,
+ surface->width,
+ surface->height);
+ test_data->egl_surface =
+ eglCreateWindowSurface(test_data->egl_dpy,
+ test_data->egl_conf,
+ (EGLNativeWindowType) native_window,
+ NULL);
+
+ ret = eglMakeCurrent(test_data->egl_dpy, test_data->egl_surface,
+ test_data->egl_surface, test_data->egl_ctx);
+ assert(ret == EGL_TRUE);
+
+ /* This test is specific to mesa 10.1 and later, which is the
+ * first release that doesn't accidentally triple-buffer. */
+ str = (const char *) glGetString(GL_VERSION);
+ mesa = strstr(str, "Mesa ");
+ if (mesa == NULL)
+ skip("unknown EGL implementation (%s)\n", str);
+ if (sscanf(mesa + 5, "%d.%d", &major, &minor) != 2)
+ skip("unrecognized mesa version (%s)\n", str);
+ if (major < 10 || (major == 10 && minor < 1))
+ skip("mesa version too old (%s)\n", str);
+
+}
+
+TEST(test_buffer_count)
+{
+ struct test_data test_data;
+ uint32_t buffer_count;
+ int i;
+
+ test_data.client = client_create(10, 10, 10, 10);
+ init_egl(&test_data);
+
+ /* This is meant to represent a typical game loop which is
+ * expecting eglSwapBuffers to block and throttle the
+ * rendering to a sensible frame rate. Therefore it doesn't
+ * expect to have to install a frame callback itself. I'd
+ * imagine this is what a typical SDL game would end up
+ * doing */
+
+ for (i = 0; i < 10; i++) {
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(test_data.egl_dpy, test_data.egl_surface);
+ }
+
+ buffer_count = get_n_egl_buffers(test_data.client);
+
+ printf("buffers used = %i\n", buffer_count);
+
+ /* The implementation should only end up creating two buffers
+ * and cycling between them */
+ assert(buffer_count == 2);
+}
diff --git a/tests/subsurface-test.c b/tests/subsurface-test.c
index 98e00fea..1c2641b6 100644
--- a/tests/subsurface-test.c
+++ b/tests/subsurface-test.c
@@ -23,7 +23,6 @@
#include <string.h>
#include "weston-test-client-helper.h"
-#include "subsurface-client-protocol.h"
#include <stdio.h>
#define NUM_SUBSURFACES 3
diff --git a/tests/surface-global-test.c b/tests/surface-global-test.c
index 04b64d6a..b496635c 100644
--- a/tests/surface-global-test.c
+++ b/tests/surface-global-test.c
@@ -29,39 +29,44 @@ surface_to_from_global(void *data)
{
struct weston_compositor *compositor = data;
struct weston_surface *surface;
+ struct weston_view *view;
float x, y;
wl_fixed_t fx, fy;
int32_t ix, iy;
surface = weston_surface_create(compositor);
assert(surface);
- weston_surface_configure(surface, 5, 10, 50, 50);
- weston_surface_update_transform(surface);
-
- weston_surface_to_global_float(surface, 33, 22, &x, &y);
+ view = weston_view_create(surface);
+ assert(view);
+ surface->width = 50;
+ surface->height = 50;
+ weston_view_set_position(view, 5, 10);
+ weston_view_update_transform(view);
+
+ weston_view_to_global_float(view, 33, 22, &x, &y);
assert(x == 38 && y == 32);
- weston_surface_to_global_float(surface, -8, -2, &x, &y);
+ weston_view_to_global_float(view, -8, -2, &x, &y);
assert(x == -3 && y == 8);
- weston_surface_to_global_fixed(surface, wl_fixed_from_int(12),
+ weston_view_to_global_fixed(view, wl_fixed_from_int(12),
wl_fixed_from_int(5), &fx, &fy);
assert(fx == wl_fixed_from_int(17) && fy == wl_fixed_from_int(15));
- weston_surface_from_global_float(surface, 38, 32, &x, &y);
+ weston_view_from_global_float(view, 38, 32, &x, &y);
assert(x == 33 && y == 22);
- weston_surface_from_global_float(surface, 42, 5, &x, &y);
+ weston_view_from_global_float(view, 42, 5, &x, &y);
assert(x == 37 && y == -5);
- weston_surface_from_global_fixed(surface, wl_fixed_from_int(21),
+ weston_view_from_global_fixed(view, wl_fixed_from_int(21),
wl_fixed_from_int(100), &fx, &fy);
assert(fx == wl_fixed_from_int(16) && fy == wl_fixed_from_int(90));
- weston_surface_from_global(surface, 0, 0, &ix, &iy);
+ weston_view_from_global(view, 0, 0, &ix, &iy);
assert(ix == -5 && iy == -10);
- weston_surface_from_global(surface, 5, 10, &ix, &iy);
+ weston_view_from_global(view, 5, 10, &ix, &iy);
assert(ix == 0 && iy == 0);
wl_display_terminate(compositor->wl_display);
diff --git a/tests/surface-test.c b/tests/surface-test.c
index e8af2ed7..80dce81f 100644
--- a/tests/surface-test.c
+++ b/tests/surface-test.c
@@ -31,20 +31,25 @@ surface_transform(void *data)
{
struct weston_compositor *compositor = data;
struct weston_surface *surface;
+ struct weston_view *view;
float x, y;
surface = weston_surface_create(compositor);
assert(surface);
- weston_surface_configure(surface, 100, 100, 200, 200);
- weston_surface_update_transform(surface);
- weston_surface_to_global_float(surface, 20, 20, &x, &y);
+ view = weston_view_create(surface);
+ assert(view);
+ surface->width = 200;
+ surface->height = 200;
+ weston_view_set_position(view, 100, 100);
+ weston_view_update_transform(view);
+ weston_view_to_global_float(view, 20, 20, &x, &y);
fprintf(stderr, "20,20 maps to %f, %f\n", x, y);
assert(x == 120 && y == 120);
- weston_surface_set_position(surface, 150, 300);
- weston_surface_update_transform(surface);
- weston_surface_to_global_float(surface, 50, 40, &x, &y);
+ weston_view_set_position(view, 150, 300);
+ weston_view_update_transform(view);
+ weston_view_to_global_float(view, 50, 40, &x, &y);
assert(x == 200 && y == 340);
wl_display_terminate(compositor->wl_display);
diff --git a/tests/text-test.c b/tests/text-test.c
index 48f2b5a6..1f10b1bb 100644
--- a/tests/text-test.c
+++ b/tests/text-test.c
@@ -24,7 +24,7 @@
#include <stdio.h>
#include <linux/input.h>
#include "weston-test-client-helper.h"
-#include "../clients/text-client-protocol.h"
+#include "text-client-protocol.h"
struct text_input_state {
int activated;
diff --git a/tests/vertex-clip-test.c b/tests/vertex-clip-test.c
index 5b2e08c5..6d44aa2a 100644
--- a/tests/vertex-clip-test.c
+++ b/tests/vertex-clip-test.c
@@ -56,8 +56,8 @@ populate_clip_context (struct clip_context *ctx)
static int
clip_polygon (struct clip_context *ctx,
struct polygon8 *polygon,
- GLfloat *vertices_x,
- GLfloat *vertices_y)
+ float *vertices_x,
+ float *vertices_y)
{
populate_clip_context(ctx);
return clip_transformed(ctx, polygon, vertices_x, vertices_y);
@@ -181,8 +181,8 @@ TEST_P(clip_polygon_n_vertices_emitted, test_data)
struct vertex_clip_test_data *tdata = data;
struct clip_context ctx;
struct polygon8 polygon;
- GLfloat vertices_x[8];
- GLfloat vertices_y[8];
+ float vertices_x[8];
+ float vertices_y[8];
deep_copy_polygon8(&tdata->surface, &polygon);
int emitted = clip_polygon(&ctx, &polygon, vertices_x, vertices_y);
@@ -194,8 +194,8 @@ TEST_P(clip_polygon_expected_vertices, test_data)
struct vertex_clip_test_data *tdata = data;
struct clip_context ctx;
struct polygon8 polygon;
- GLfloat vertices_x[8];
- GLfloat vertices_y[8];
+ float vertices_x[8];
+ float vertices_y[8];
deep_copy_polygon8(&tdata->surface, &polygon);
int emitted = clip_polygon(&ctx, &polygon, vertices_x, vertices_y);
int i = 0;
diff --git a/tests/weston-test-client-helper.c b/tests/weston-test-client-helper.c
index b19be400..399aa443 100644
--- a/tests/weston-test-client-helper.c
+++ b/tests/weston-test-client-helper.c
@@ -111,6 +111,17 @@ move_client(struct client *client, int x, int y)
frame_callback_wait(client, &done);
}
+int
+get_n_egl_buffers(struct client *client)
+{
+ client->test->n_egl_buffers = -1;
+
+ wl_test_get_n_egl_buffers(client->test->wl_test);
+ wl_display_roundtrip(client->wl_display);
+
+ return client->test->n_egl_buffers;
+}
+
static void
pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, struct wl_surface *wl_surface,
@@ -340,8 +351,17 @@ test_handle_pointer_position(void *data, struct wl_test *wl_test,
test->pointer_x, test->pointer_y);
}
+static void
+test_handle_n_egl_buffers(void *data, struct wl_test *wl_test, uint32_t n)
+{
+ struct test *test = data;
+
+ test->n_egl_buffers = n;
+}
+
static const struct wl_test_listener test_listener = {
- test_handle_pointer_position
+ test_handle_pointer_position,
+ test_handle_n_egl_buffers,
};
static void
@@ -476,6 +496,20 @@ static const struct wl_registry_listener registry_listener = {
handle_global
};
+void
+skip(const char *fmt, ...)
+{
+ va_list argp;
+
+ va_start(argp, fmt);
+ vfprintf(stderr, fmt, argp);
+ va_end(argp);
+
+ /* automake tests uses exit code 77, but we don't have a good
+ * way to make weston exit with that from here. */
+ exit(0);
+}
+
static void
log_handler(const char *fmt, va_list args)
{
diff --git a/tests/weston-test-client-helper.h b/tests/weston-test-client-helper.h
index a5edca90..6670ab37 100644
--- a/tests/weston-test-client-helper.h
+++ b/tests/weston-test-client-helper.h
@@ -51,6 +51,7 @@ struct test {
struct wl_test *wl_test;
int pointer_x;
int pointer_y;
+ uint32_t n_egl_buffers;
};
struct input {
@@ -120,4 +121,10 @@ frame_callback_set(struct wl_surface *surface, int *done);
void
frame_callback_wait(struct client *client, int *done);
+int
+get_n_egl_buffers(struct client *client);
+
+void
+skip(const char *fmt, ...);
+
#endif
diff --git a/tests/weston-test.c b/tests/weston-test.c
index bc5b6e9d..844059dc 100644
--- a/tests/weston-test.c
+++ b/tests/weston-test.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdlib.h>
#include <string.h>
#include <assert.h>
@@ -28,6 +30,11 @@
#include "../src/compositor.h"
#include "wayland-test-server-protocol.h"
+#ifdef ENABLE_EGL
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#endif /* ENABLE_EGL */
+
struct weston_test {
struct weston_compositor *compositor;
struct weston_layer layer;
@@ -36,6 +43,7 @@ struct weston_test {
struct weston_test_surface {
struct weston_surface *surface;
+ struct weston_view *view;
int32_t x, y;
struct weston_test *test;
};
@@ -74,20 +82,19 @@ notify_pointer_position(struct weston_test *test, struct wl_resource *resource)
}
static void
-test_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy, int32_t width, int32_t height)
+test_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
{
struct weston_test_surface *test_surface = surface->configure_private;
struct weston_test *test = test_surface->test;
- if (wl_list_empty(&surface->layer_link))
- wl_list_insert(&test->layer.surface_list,
- &surface->layer_link);
+ if (wl_list_empty(&test_surface->view->layer_link))
+ wl_list_insert(&test->layer.view_list,
+ &test_surface->view->layer_link);
- weston_surface_configure(surface, test_surface->x, test_surface->y,
- width, height);
+ weston_view_set_position(test_surface->view,
+ test_surface->x, test_surface->y);
- if (!weston_surface_is_mapped(surface))
- weston_surface_update_transform(surface);
+ weston_view_update_transform(test_surface->view);
}
static void
@@ -99,13 +106,23 @@ move_surface(struct wl_client *client, struct wl_resource *resource,
wl_resource_get_user_data(surface_resource);
struct weston_test_surface *test_surface;
- surface->configure = test_surface_configure;
- if (surface->configure_private == NULL)
- surface->configure_private = malloc(sizeof *test_surface);
test_surface = surface->configure_private;
- if (test_surface == NULL) {
- wl_resource_post_no_memory(resource);
- return;
+ if (!test_surface) {
+ test_surface = malloc(sizeof *test_surface);
+ if (!test_surface) {
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+
+ test_surface->view = weston_view_create(surface);
+ if (!test_surface->view) {
+ wl_resource_post_no_memory(resource);
+ free(test_surface);
+ return;
+ }
+
+ surface->configure_private = test_surface;
+ surface->configure = test_surface_configure;
}
test_surface->surface = surface;
@@ -122,8 +139,6 @@ move_pointer(struct wl_client *client, struct wl_resource *resource,
struct weston_seat *seat = get_seat(test);
struct weston_pointer *pointer = seat->pointer;
- test->compositor->focus = 1;
-
notify_motion(seat, 100,
wl_fixed_from_int(x) - pointer->x,
wl_fixed_from_int(y) - pointer->y);
@@ -138,8 +153,6 @@ send_button(struct wl_client *client, struct wl_resource *resource,
struct weston_test *test = wl_resource_get_user_data(resource);
struct weston_seat *seat = get_seat(test);
- test->compositor->focus = 1;
-
notify_button(seat, 100, button, state);
}
@@ -172,17 +185,57 @@ send_key(struct wl_client *client, struct wl_resource *resource,
struct weston_test *test = wl_resource_get_user_data(resource);
struct weston_seat *seat = get_seat(test);
- test->compositor->focus = 1;
-
notify_key(seat, 100, key, state, STATE_UPDATE_AUTOMATIC);
}
+#ifdef ENABLE_EGL
+static int
+is_egl_buffer(struct wl_resource *resource)
+{
+ PFNEGLQUERYWAYLANDBUFFERWL query_buffer =
+ (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
+ EGLint format;
+
+ if (query_buffer(eglGetCurrentDisplay(),
+ resource,
+ EGL_TEXTURE_FORMAT,
+ &format))
+ return 1;
+
+ return 0;
+}
+#endif /* ENABLE_EGL */
+
+static void
+get_n_buffers(struct wl_client *client, struct wl_resource *resource)
+{
+ int n_buffers = 0;
+
+#ifdef ENABLE_EGL
+ struct wl_resource *buffer_resource;
+ int i;
+
+ for (i = 0; i < 1000; i++) {
+ buffer_resource = wl_client_get_object(client, i);
+
+ if (buffer_resource == NULL)
+ continue;
+
+ if (is_egl_buffer(buffer_resource))
+ n_buffers++;
+ }
+#endif /* ENABLE_EGL */
+
+ wl_test_send_n_egl_buffers(resource, n_buffers);
+}
+
static const struct wl_test_interface test_implementation = {
move_surface,
move_pointer,
send_button,
activate_surface,
- send_key
+ send_key,
+ get_n_buffers,
};
static void
@@ -208,7 +261,7 @@ idle_launch_client(void *data)
path = getenv("WESTON_TEST_CLIENT_PATH");
if (path == NULL)
- exit(EXIT_FAILURE);
+ return;
pid = fork();
if (pid == -1)
exit(EXIT_FAILURE);
diff --git a/weston.ini b/weston.ini.in
index 70069316..5181a9e5 100644
--- a/weston.ini
+++ b/weston.ini.in
@@ -1,6 +1,7 @@
[core]
#modules=xwayland.so,cms-colord.so
#shell=desktop-shell.so
+#gbm-format=xrgb2101010
[shell]
background-image=/usr/share/backgrounds/gnome/Aqua.jpg
@@ -26,7 +27,7 @@ path=/usr/bin/gnome-terminal
[launcher]
icon=/usr/share/icons/gnome/24x24/apps/utilities-terminal.png
-path=/usr/bin/weston-terminal
+path=@bindir@/weston-terminal
[launcher]
icon=/usr/share/icons/hicolor/24x24/apps/google-chrome.png
@@ -34,15 +35,15 @@ path=/usr/bin/google-chrome
[launcher]
icon=/usr/share/icons/gnome/24x24/apps/arts.png
-path=./clients/weston-flower
+path=@abs_top_builddir@/clients/weston-flower
[screensaver]
# Uncomment path to disable screensaver
-path=/usr/libexec/weston-screensaver
+path=@libexecdir@/weston-screensaver
duration=600
[input-method]
-path=/usr/libexec/weston-keyboard
+path=@libexecdir@/weston-keyboard
#[output]
#name=LVDS1
diff --git a/xwayland/.gitignore b/xwayland/.gitignore
new file mode 100644
index 00000000..2c11e7b0
--- /dev/null
+++ b/xwayland/.gitignore
@@ -0,0 +1,2 @@
+xserver-protocol.c
+xserver-server-protocol.h
diff --git a/src/xwayland/Makefile.am b/xwayland/Makefile.am
index cab59c70..434234aa 100644
--- a/src/xwayland/Makefile.am
+++ b/xwayland/Makefile.am
@@ -1,6 +1,8 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/shared \
+ -I$(top_srcdir)/src \
-I$(top_builddir)/src \
+ -I$(top_builddir)/xwayland \
-DDATADIR='"$(datadir)"' \
-DMODULEDIR='"$(moduledir)"' \
-DLIBEXECDIR='"$(libexecdir)"' \
diff --git a/src/xwayland/dnd.c b/xwayland/dnd.c
index b146e123..daeb08de 100644
--- a/src/xwayland/dnd.c
+++ b/xwayland/dnd.c
@@ -35,8 +35,8 @@
#include "xwayland.h"
-#include "../../shared/cairo-util.h"
-#include "../compositor.h"
+#include "cairo-util.h"
+#include "compositor.h"
#include "xserver-server-protocol.h"
#include "hash.h"
@@ -211,7 +211,7 @@ handle_enter(struct weston_wm *wm, xcb_client_message_event_t *client_message)
}
free(reply);
- weston_seat_start_drag(seat, &source->base, NULL, NULL);
+ weston_pointer_start_drag(seat->pointer, &source->base, NULL, NULL);
}
int
diff --git a/src/xwayland/hash.c b/xwayland/hash.c
index 54f3de93..54f3de93 100644
--- a/src/xwayland/hash.c
+++ b/xwayland/hash.c
diff --git a/src/xwayland/hash.h b/xwayland/hash.h
index 6e1674e1..6e1674e1 100644
--- a/src/xwayland/hash.h
+++ b/xwayland/hash.h
diff --git a/src/xwayland/launcher.c b/xwayland/launcher.c
index 8d8e060a..8d8e060a 100644
--- a/src/xwayland/launcher.c
+++ b/xwayland/launcher.c
diff --git a/src/xwayland/selection.c b/xwayland/selection.c
index b694477e..b694477e 100644
--- a/src/xwayland/selection.c
+++ b/xwayland/selection.c
diff --git a/src/xwayland/window-manager.c b/xwayland/window-manager.c
index f1b58c9b..70c8cf7c 100644
--- a/src/xwayland/window-manager.c
+++ b/xwayland/window-manager.c
@@ -32,11 +32,12 @@
#include <unistd.h>
#include <signal.h>
#include <X11/Xcursor/Xcursor.h>
+#include <linux/input.h>
#include "xwayland.h"
-#include "../../shared/cairo-util.h"
-#include "../compositor.h"
+#include "cairo-util.h"
+#include "compositor.h"
#include "xserver-server-protocol.h"
#include "hash.h"
@@ -119,9 +120,11 @@ struct weston_wm_window {
struct weston_wm *wm;
xcb_window_t id;
xcb_window_t frame_id;
+ struct frame *frame;
cairo_surface_t *cairo_surface;
struct weston_surface *surface;
struct shell_surface *shsurf;
+ struct weston_view *view;
struct wl_listener surface_destroy_listener;
struct wl_event_source *repaint_source;
struct wl_event_source *configure_source;
@@ -140,6 +143,7 @@ struct weston_wm_window {
int override_redirect;
int fullscreen;
int has_alpha;
+ int delete_window;
struct wm_size_hints size_hints;
struct motif_wm_hints motif_hints;
};
@@ -407,6 +411,7 @@ weston_wm_window_read_properties(struct weston_wm_window *window)
window->decorate = !window->override_redirect;
window->size_hints.flags = 0;
window->motif_hints.flags = 0;
+ window->delete_window = 0;
for (i = 0; i < ARRAY_LENGTH(props); i++) {
reply = xcb_get_property_reply(wm->conn, cookie[i], NULL);
@@ -444,6 +449,12 @@ weston_wm_window_read_properties(struct weston_wm_window *window)
*(xcb_atom_t *) p = *atom;
break;
case TYPE_WM_PROTOCOLS:
+ atom = xcb_get_property_value(reply);
+ for (i = 0; i < reply->value_len; i++)
+ if (atom[i] == wm->atom.wm_delete_window)
+ window->delete_window = 1;
+ break;
+
break;
case TYPE_WM_NORMAL_HINTS:
memcpy(&window->size_hints,
@@ -473,6 +484,8 @@ weston_wm_window_read_properties(struct weston_wm_window *window)
if (window->shsurf && window->name)
shell_interface->set_title(window->shsurf, window->name);
+ if (window->frame && window->name)
+ frame_set_title(window->frame, window->name);
}
static void
@@ -484,10 +497,9 @@ weston_wm_window_get_frame_size(struct weston_wm_window *window,
if (window->fullscreen) {
*width = window->width;
*height = window->height;
- } else if (window->decorate) {
- *width = window->width + (t->margin + t->width) * 2;
- *height = window->height +
- t->margin * 2 + t->width + t->titlebar_height;
+ } else if (window->decorate && window->frame) {
+ *width = frame_width(window->frame);
+ *height = frame_height(window->frame);
} else {
*width = window->width + t->margin * 2;
*height = window->height + t->margin * 2;
@@ -503,9 +515,8 @@ weston_wm_window_get_child_position(struct weston_wm_window *window,
if (window->fullscreen) {
*x = 0;
*y = 0;
- } else if (window->decorate) {
- *x = t->margin + t->width;
- *y = t->margin + t->titlebar_height;
+ } else if (window->decorate && window->frame) {
+ frame_interior(window->frame, x, y, NULL, NULL);
} else {
*x = t->margin;
*y = t->margin;
@@ -564,6 +575,9 @@ weston_wm_handle_configure_request(struct weston_wm *wm, xcb_generic_event_t *ev
if (configure_request->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
window->height = configure_request->height;
+ if (window->frame)
+ frame_resize_inside(window->frame, window->width, window->height);
+
weston_wm_window_get_child_position(window, &x, &y);
values[i++] = x;
values[i++] = y;
@@ -621,6 +635,9 @@ weston_wm_handle_configure_notify(struct weston_wm *wm, xcb_generic_event_t *eve
if (window->override_redirect) {
window->width = configure_notify->width;
window->height = configure_notify->height;
+ if (window->frame)
+ frame_resize_inside(window->frame,
+ window->width, window->height);
}
}
@@ -677,11 +694,17 @@ weston_wm_window_activate(struct wl_listener *listener, void *data)
XCB_TIME_CURRENT_TIME);
}
- if (wm->focus_window)
+ if (wm->focus_window) {
+ if (wm->focus_window->frame)
+ frame_unset_flag(wm->focus_window->frame, FRAME_FLAG_ACTIVE);
weston_wm_window_schedule_repaint(wm->focus_window);
+ }
wm->focus_window = window;
- if (wm->focus_window)
+ if (wm->focus_window) {
+ if (wm->focus_window->frame)
+ frame_set_flag(wm->focus_window->frame, FRAME_FLAG_ACTIVE);
weston_wm_window_schedule_repaint(wm->focus_window);
+ }
}
static void
@@ -696,13 +719,13 @@ weston_wm_window_transform(struct wl_listener *listener, void *data)
if (!window || !wm)
return;
- if (!weston_surface_is_mapped(surface))
+ if (!window->view || !weston_view_is_mapped(window->view))
return;
- if (window->x != surface->geometry.x ||
- window->y != surface->geometry.y) {
- values[0] = surface->geometry.x;
- values[1] = surface->geometry.y;
+ if (window->x != window->view->geometry.x ||
+ window->y != window->view->geometry.y) {
+ values[0] = window->view->geometry.x;
+ values[1] = window->view->geometry.y;
mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y;
xcb_configure_window(wm->conn, window->frame_id, mask, values);
@@ -759,6 +782,11 @@ weston_wm_window_create_frame(struct weston_wm_window *window)
uint32_t values[3];
int x, y, width, height;
+ window->frame = frame_create(window->wm->theme,
+ window->width, window->height,
+ FRAME_BUTTON_CLOSE, window->name);
+ frame_resize_inside(window->frame, window->width, window->height);
+
weston_wm_window_get_frame_size(window, &width, &height);
weston_wm_window_get_child_position(window, &x, &y);
@@ -876,6 +904,7 @@ weston_wm_handle_unmap_notify(struct weston_wm *wm, xcb_generic_event_t *event)
wl_list_remove(&window->surface_destroy_listener.link);
window->surface = NULL;
window->shsurf = NULL;
+ window->view = NULL;
xcb_unmap_window(wm->conn, window->frame_id);
}
@@ -887,7 +916,8 @@ weston_wm_window_draw_decoration(void *data)
struct theme *t = wm->theme;
cairo_t *cr;
int x, y, width, height;
- const char *title;
+ int32_t input_x, input_y, input_w, input_h;
+
uint32_t flags = 0;
weston_wm_window_read_properties(window);
@@ -906,12 +936,7 @@ weston_wm_window_draw_decoration(void *data)
if (wm->focus_window == window)
flags |= THEME_FRAME_ACTIVE;
- if (window->name)
- title = window->name;
- else
- title = "untitled";
-
- theme_render_frame(t, cr, width, height, title, flags);
+ frame_repaint(window->frame, cr);
} else {
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(cr, 0, 0, 0, 0);
@@ -937,19 +962,23 @@ weston_wm_window_draw_decoration(void *data)
window->width + 2,
window->height + 2);
}
- weston_surface_geometry_dirty(window->surface);
+ if (window->view)
+ weston_view_geometry_dirty(window->view);
pixman_region32_fini(&window->surface->pending.input);
if (window->fullscreen) {
- pixman_region32_init_rect(&window->surface->pending.input,
- 0, 0, window->width, window->height);
+ input_x = 0;
+ input_y = 0;
+ input_w = window->width;
+ input_h = window->height;
} else if (window->decorate) {
- pixman_region32_init_rect(&window->surface->pending.input,
- t->margin, t->margin,
- width - 2 * t->margin,
- height - 2 * t->margin);
+ frame_input_rect(window->frame, &input_x, &input_y,
+ &input_w, &input_h);
}
+
+ pixman_region32_init_rect(&window->surface->pending.input,
+ input_x, input_y, input_w, input_h);
}
}
@@ -969,7 +998,8 @@ weston_wm_window_schedule_repaint(struct weston_wm_window *window)
pixman_region32_init_rect(&window->surface->pending.opaque, 0, 0,
width, height);
}
- weston_surface_geometry_dirty(window->surface);
+ if (window->view)
+ weston_view_geometry_dirty(window->view);
}
return;
}
@@ -1160,8 +1190,8 @@ weston_wm_window_handle_moveresize(struct weston_wm_window *window,
struct weston_shell_interface *shell_interface =
&wm->server->compositor->shell_interface;
- if (seat->pointer->button_count != 1 ||
- seat->pointer->focus != window->surface)
+ if (seat->pointer->button_count != 1 || !window->view
+ || seat->pointer->focus != window->view)
return;
detail = client_message->data.data32[2];
@@ -1243,6 +1273,10 @@ weston_wm_window_handle_state(struct weston_wm_window *window,
shell_interface->set_toplevel(window->shsurf);
window->width = window->saved_width;
window->height = window->saved_height;
+ if (window->frame)
+ frame_resize_inside(window->frame,
+ window->width,
+ window->height);
weston_wm_window_configure(window);
}
}
@@ -1395,9 +1429,9 @@ weston_wm_destroy_cursors(struct weston_wm *wm)
}
static int
-get_cursor_for_location(struct theme *t, int width, int height, int x, int y)
+get_cursor_for_location(enum theme_location location)
{
- int location = theme_get_location(t, x, y, width, height, 0);
+ // int location = theme_get_location(t, x, y, width, height, 0);
switch (location) {
case THEME_LOCATION_RESIZING_TOP:
@@ -1441,6 +1475,28 @@ weston_wm_window_set_cursor(struct weston_wm *wm, xcb_window_t window_id,
}
static void
+weston_wm_window_close(struct weston_wm_window *window, xcb_timestamp_t time)
+{
+ xcb_client_message_event_t client_message;
+
+ if (window->delete_window) {
+ client_message.response_type = XCB_CLIENT_MESSAGE;
+ client_message.format = 32;
+ client_message.window = window->id;
+ client_message.type = window->wm->atom.wm_protocols;
+ client_message.data.data32[0] =
+ window->wm->atom.wm_delete_window;
+ client_message.data.data32[1] = time;
+
+ xcb_send_event(window->wm->conn, 0, window->id,
+ XCB_EVENT_MASK_NO_EVENT,
+ (char *) &client_message);
+ } else {
+ xcb_kill_client(window->wm->conn, window->id);
+ }
+}
+
+static void
weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event)
{
xcb_button_press_event_t *button = (xcb_button_press_event_t *) event;
@@ -1449,41 +1505,42 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event)
struct weston_seat *seat = weston_wm_pick_seat(wm);
struct weston_wm_window *window;
enum theme_location location;
- struct theme *t = wm->theme;
- int width, height;
+ enum frame_button_state button_state;
+ uint32_t button_id;
wm_log("XCB_BUTTON_%s (detail %d)\n",
button->response_type == XCB_BUTTON_PRESS ?
"PRESS" : "RELEASE", button->detail);
window = hash_table_lookup(wm->window_hash, button->event);
- weston_wm_window_get_frame_size(window, &width, &height);
+ if (!window || !window->decorate)
+ return;
- if (button->response_type == XCB_BUTTON_PRESS &&
- button->detail == 1) {
- location = theme_get_location(t,
- button->event_x,
- button->event_y,
- width, height, 0);
+ if (button->detail != 1 && button->detail != 2)
+ return;
- switch (location) {
- case THEME_LOCATION_TITLEBAR:
- shell_interface->move(window->shsurf, seat);
- break;
- case THEME_LOCATION_RESIZING_TOP:
- case THEME_LOCATION_RESIZING_BOTTOM:
- case THEME_LOCATION_RESIZING_LEFT:
- case THEME_LOCATION_RESIZING_RIGHT:
- case THEME_LOCATION_RESIZING_TOP_LEFT:
- case THEME_LOCATION_RESIZING_TOP_RIGHT:
- case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
- case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
- shell_interface->resize(window->shsurf,
- seat, location);
- break;
- default:
- break;
- }
+ button_state = button->response_type == XCB_BUTTON_PRESS ?
+ FRAME_BUTTON_PRESSED : FRAME_BUTTON_RELEASED;
+ button_id = button->detail == 1 ? BTN_LEFT : BTN_RIGHT;
+
+ location = frame_pointer_button(window->frame, NULL,
+ button_id, button_state);
+ if (frame_status(window->frame) & FRAME_STATUS_REPAINT)
+ weston_wm_window_schedule_repaint(window);
+
+ if (frame_status(window->frame) & FRAME_STATUS_MOVE) {
+ shell_interface->move(window->shsurf, seat);
+ frame_status_clear(window->frame, FRAME_STATUS_MOVE);
+ }
+
+ if (frame_status(window->frame) & FRAME_STATUS_RESIZE) {
+ shell_interface->resize(window->shsurf, seat, location);
+ frame_status_clear(window->frame, FRAME_STATUS_RESIZE);
+ }
+
+ if (frame_status(window->frame) & FRAME_STATUS_CLOSE) {
+ weston_wm_window_close(window, button->time);
+ frame_status_clear(window->frame, FRAME_STATUS_CLOSE);
}
}
@@ -1492,16 +1549,19 @@ weston_wm_handle_motion(struct weston_wm *wm, xcb_generic_event_t *event)
{
xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *) event;
struct weston_wm_window *window;
- int cursor, width, height;
+ enum theme_location location;
+ int cursor;
window = hash_table_lookup(wm->window_hash, motion->event);
if (!window || !window->decorate)
return;
- weston_wm_window_get_frame_size(window, &width, &height);
- cursor = get_cursor_for_location(wm->theme, width, height,
- motion->event_x, motion->event_y);
+ location = frame_pointer_motion(window->frame, NULL,
+ motion->event_x, motion->event_y);
+ if (frame_status(window->frame) & FRAME_STATUS_REPAINT)
+ weston_wm_window_schedule_repaint(window);
+ cursor = get_cursor_for_location(location);
weston_wm_window_set_cursor(wm, window->frame_id, cursor);
}
@@ -1510,16 +1570,19 @@ weston_wm_handle_enter(struct weston_wm *wm, xcb_generic_event_t *event)
{
xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *) event;
struct weston_wm_window *window;
- int cursor, width, height;
+ enum theme_location location;
+ int cursor;
window = hash_table_lookup(wm->window_hash, enter->event);
if (!window || !window->decorate)
return;
- weston_wm_window_get_frame_size(window, &width, &height);
- cursor = get_cursor_for_location(wm->theme, width, height,
- enter->event_x, enter->event_y);
+ location = frame_pointer_enter(window->frame, NULL,
+ enter->event_x, enter->event_y);
+ if (frame_status(window->frame) & FRAME_STATUS_REPAINT)
+ weston_wm_window_schedule_repaint(window);
+ cursor = get_cursor_for_location(location);
weston_wm_window_set_cursor(wm, window->frame_id, cursor);
}
@@ -1533,6 +1596,10 @@ weston_wm_handle_leave(struct weston_wm *wm, xcb_generic_event_t *event)
if (!window || !window->decorate)
return;
+ frame_pointer_leave(window->frame, NULL);
+ if (frame_status(window->frame) & FRAME_STATUS_REPAINT)
+ weston_wm_window_schedule_repaint(window);
+
weston_wm_window_set_cursor(wm, window->frame_id, XWM_CURSOR_LEFT_PTR);
}
@@ -1964,6 +2031,7 @@ surface_destroy(struct wl_listener *listener, void *data)
Don't try to use it later. */
window->shsurf = NULL;
window->surface = NULL;
+ window->view = NULL;
}
static struct weston_wm_window *
@@ -2044,6 +2112,9 @@ send_configure(struct weston_surface *surface,
else
window->height = 1;
+ if (window->frame)
+ frame_resize_inside(window->frame, window->width, window->height);
+
if (window->configure_source)
return;
@@ -2108,14 +2179,20 @@ xserver_map_shell_surface(struct weston_wm *wm,
struct weston_shell_interface *shell_interface =
&wm->server->compositor->shell_interface;
struct weston_output *output;
+ struct weston_wm_window *parent;
if (!shell_interface->create_shell_surface)
return;
+ if (!shell_interface->get_primary_view)
+ return;
+
window->shsurf =
shell_interface->create_shell_surface(shell_interface->shell,
window->surface,
&shell_client);
+ window->view = shell_interface->get_primary_view(shell_interface->shell,
+ window->shsurf);
if (window->name)
shell_interface->set_title(window->shsurf, window->name);
@@ -2132,14 +2209,19 @@ xserver_map_shell_surface(struct weston_wm *wm,
shell_interface->set_fullscreen(window->shsurf,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
0, output);
- } else if (!window->override_redirect && !window->transient_for) {
- shell_interface->set_toplevel(window->shsurf);
- return;
- } else {
+ } else if (window->override_redirect) {
shell_interface->set_xwayland(window->shsurf,
window->x,
window->y,
WL_SHELL_SURFACE_TRANSIENT_INACTIVE);
+ } else if (window->transient_for) {
+ parent = window->transient_for;
+ shell_interface->set_transient(window->shsurf,
+ parent->surface,
+ parent->x - window->x,
+ parent->y - window->y, 0);
+ } else {
+ shell_interface->set_toplevel(window->shsurf);
}
}
diff --git a/src/xwayland/xwayland.h b/xwayland/xwayland.h
index 77262e8f..c684cc51 100644
--- a/src/xwayland/xwayland.h
+++ b/xwayland/xwayland.h
@@ -26,7 +26,7 @@
#include <xcb/composite.h>
#include <cairo/cairo-xcb.h>
-#include "../compositor.h"
+#include "compositor.h"
#define SEND_EVENT_MASK (0x80)
#define EVENT_TYPE(event) ((event)->response_type & ~SEND_EVENT_MASK)