aboutsummaryrefslogtreecommitdiff
path: root/tinywl/tinywl.c
diff options
context:
space:
mode:
Diffstat (limited to 'tinywl/tinywl.c')
-rw-r--r--tinywl/tinywl.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c
index bd21dd91..0342ec54 100644
--- a/tinywl/tinywl.c
+++ b/tinywl/tinywl.c
@@ -86,6 +86,7 @@ struct tinywl_toplevel {
struct wlr_scene_tree *scene_tree;
struct wl_listener map;
struct wl_listener unmap;
+ struct wl_listener commit;
struct wl_listener destroy;
struct wl_listener request_move;
struct wl_listener request_resize;
@@ -93,6 +94,12 @@ struct tinywl_toplevel {
struct wl_listener request_fullscreen;
};
+struct tinywl_popup {
+ struct wlr_xdg_popup *xdg_popup;
+ struct wl_listener commit;
+ struct wl_listener destroy;
+};
+
struct tinywl_keyboard {
struct wl_list link;
struct tinywl_server *server;
@@ -672,12 +679,26 @@ static void xdg_toplevel_unmap(struct wl_listener *listener, void *data) {
wl_list_remove(&toplevel->link);
}
+static void xdg_toplevel_commit(struct wl_listener *listener, void *data) {
+ /* Called when a new surface state is committed. */
+ struct tinywl_toplevel *toplevel = wl_container_of(listener, toplevel, commit);
+
+ if (toplevel->xdg_toplevel->base->initial_commit) {
+ /* When an xdg_surface performs an initial commit, the compositor must
+ * reply with a configure so the client can map the surface. tinywl
+ * configures the xdg_toplevel with 0,0 size to let the client pick the
+ * dimensions itself. */
+ wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, 0, 0);
+ }
+}
+
static void xdg_toplevel_destroy(struct wl_listener *listener, void *data) {
/* Called when the xdg_toplevel is destroyed. */
struct tinywl_toplevel *toplevel = wl_container_of(listener, toplevel, destroy);
wl_list_remove(&toplevel->map.link);
wl_list_remove(&toplevel->unmap.link);
+ wl_list_remove(&toplevel->commit.link);
wl_list_remove(&toplevel->destroy.link);
wl_list_remove(&toplevel->request_move.link);
wl_list_remove(&toplevel->request_resize.link);
@@ -793,6 +814,8 @@ static void server_new_xdg_toplevel(struct wl_listener *listener, void *data) {
wl_signal_add(&xdg_toplevel->base->surface->events.map, &toplevel->map);
toplevel->unmap.notify = xdg_toplevel_unmap;
wl_signal_add(&xdg_toplevel->base->surface->events.unmap, &toplevel->unmap);
+ toplevel->commit.notify = xdg_toplevel_commit;
+ wl_signal_add(&xdg_toplevel->base->surface->events.commit, &toplevel->commit);
toplevel->destroy.notify = xdg_toplevel_destroy;
wl_signal_add(&xdg_toplevel->events.destroy, &toplevel->destroy);
@@ -808,10 +831,37 @@ static void server_new_xdg_toplevel(struct wl_listener *listener, void *data) {
wl_signal_add(&xdg_toplevel->events.request_fullscreen, &toplevel->request_fullscreen);
}
+static void xdg_popup_commit(struct wl_listener *listener, void *data) {
+ /* Called when a new surface state is committed. */
+ struct tinywl_popup *popup = wl_container_of(listener, popup, commit);
+
+ if (popup->xdg_popup->base->initial_commit) {
+ /* When an xdg_surface performs an initial commit, the compositor must
+ * reply with a configure so the client can map the surface.
+ * tinywl sends an empty configure. A more sophisticated compositor
+ * might change an xdg_popup's geometry to ensure it's not positioned
+ * off-screen, for example. */
+ wlr_xdg_surface_schedule_configure(popup->xdg_popup->base);
+ }
+}
+
+static void xdg_popup_destroy(struct wl_listener *listener, void *data) {
+ /* Called when the xdg_popup is destroyed. */
+ struct tinywl_popup *popup = wl_container_of(listener, popup, destroy);
+
+ wl_list_remove(&popup->commit.link);
+ wl_list_remove(&popup->destroy.link);
+
+ free(popup);
+}
+
static void server_new_xdg_popup(struct wl_listener *listener, void *data) {
/* This event is raised when a client creates a new popup. */
struct wlr_xdg_popup *xdg_popup = data;
+ struct tinywl_popup *popup = calloc(1, sizeof(*popup));
+ popup->xdg_popup = xdg_popup;
+
/* We must add xdg popups to the scene graph so they get rendered. The
* wlroots scene graph provides a helper for this, but to use it we must
* provide the proper parent scene node of the xdg popup. To enable this,
@@ -821,6 +871,12 @@ static void server_new_xdg_popup(struct wl_listener *listener, void *data) {
assert(parent != NULL);
struct wlr_scene_tree *parent_tree = parent->data;
xdg_popup->base->data = wlr_scene_xdg_surface_create(parent_tree, xdg_popup->base);
+
+ popup->commit.notify = xdg_popup_commit;
+ wl_signal_add(&xdg_popup->base->surface->events.commit, &popup->commit);
+
+ popup->destroy.notify = xdg_popup_destroy;
+ wl_signal_add(&xdg_popup->events.destroy, &popup->destroy);
}
int main(int argc, char *argv[]) {