diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index b809db43..12ab5898 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -23,7 +23,7 @@ struct roots_output { }; struct roots_desktop { - struct wlr_list *views; + struct wl_list views; // roots_view::link struct wl_list outputs; struct timespec last_frame; @@ -59,6 +59,7 @@ struct roots_desktop *desktop_create(struct roots_server *server, struct roots_config *config); void desktop_destroy(struct roots_desktop *desktop); +void view_init(struct roots_view *view, struct roots_desktop *desktop); void view_destroy(struct roots_view *view); struct roots_view *view_at(struct roots_desktop *desktop, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy); diff --git a/include/rootston/seat.h b/include/rootston/seat.h index bef515a4..a8397d89 100644 --- a/include/rootston/seat.h +++ b/include/rootston/seat.h @@ -9,8 +9,7 @@ struct roots_drag_icon { struct wl_list link; // roots_seat::drag_icons bool mapped; - int32_t sx; - int32_t sy; + int32_t sx, sy; struct wl_listener surface_destroy; struct wl_listener surface_commit; @@ -20,10 +19,11 @@ struct roots_seat { struct roots_input *input; struct wlr_seat *seat; struct roots_cursor *cursor; - struct wl_list link; struct wl_list drag_icons; + struct wl_list link; - struct roots_view *focus; + struct wl_list views; // roots_seat_view::link + struct roots_seat_view *focus; struct wl_list keyboards; struct wl_list pointers; @@ -31,6 +31,14 @@ struct roots_seat { struct wl_list tablet_tools; }; +struct roots_seat_view { + struct roots_seat *seat; + struct roots_view *view; + struct wl_list link; // roots_seat::views + + struct wl_listener destroy; +}; + struct roots_pointer { struct roots_seat *seat; struct wlr_input_device *device; @@ -70,6 +78,10 @@ void roots_seat_add_device(struct roots_seat *seat, void roots_seat_remove_device(struct roots_seat *seat, struct wlr_input_device *device); +void roots_seat_add_view(struct roots_seat *seat, struct roots_view *view); + +void roots_seat_remove_view(struct roots_seat *seat, struct roots_view *view); + void roots_seat_configure_cursor(struct roots_seat *seat); void roots_seat_configure_xcursor(struct roots_seat *seat); diff --git a/include/rootston/view.h b/include/rootston/view.h index 99b4ed78..69034d60 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -9,7 +9,6 @@ struct roots_wl_shell_surface { struct roots_view *view; - // TODO: Maybe destroy listener should go in roots_view struct wl_listener destroy; struct wl_listener request_move; struct wl_listener request_resize; @@ -22,7 +21,6 @@ struct roots_wl_shell_surface { struct roots_xdg_surface_v6 { struct roots_view *view; - // TODO: Maybe destroy listener should go in roots_view struct wl_listener commit; struct wl_listener destroy; struct wl_listener request_move; @@ -33,7 +31,6 @@ struct roots_xdg_surface_v6 { struct roots_xwayland_surface { struct roots_view *view; - // TODO: Maybe destroy listener should go in roots_view struct wl_listener destroy; struct wl_listener request_configure; struct wl_listener request_move; @@ -51,6 +48,7 @@ enum roots_view_type { struct roots_view { struct roots_desktop *desktop; + struct wl_list link; // roots_desktop::views double x, y; float rotation; @@ -80,6 +78,10 @@ struct roots_view { }; struct wlr_surface *wlr_surface; + struct { + struct wl_signal destroy; + } events; + // TODO: This would probably be better as a field that's updated on a // configure event from the xdg_shell // If not then this should follow the typical type/impl pattern we use diff --git a/rootston/cursor.c b/rootston/cursor.c index 5949a364..0dbc413c 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -60,7 +60,7 @@ static void roots_cursor_update_position(struct roots_cursor *cursor, uint32_t t if (seat->focus) { double dx = cursor->cursor->x - cursor->offs_x; double dy = cursor->cursor->y - cursor->offs_y; - view_move(seat->focus, cursor->view_x + dx, + view_move(seat->focus->view, cursor->view_x + dx, cursor->view_y + dy); } break; @@ -68,8 +68,8 @@ static void roots_cursor_update_position(struct roots_cursor *cursor, uint32_t t if (seat->focus) { double dx = cursor->cursor->x - cursor->offs_x; double dy = cursor->cursor->y - cursor->offs_y; - double active_x = seat->focus->x; - double active_y = seat->focus->y; + double active_x = seat->focus->view->x; + double active_y = seat->focus->view->y; int width = cursor->view_width; int height = cursor->view_height; if (cursor->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_TOP) { @@ -98,18 +98,18 @@ static void roots_cursor_update_position(struct roots_cursor *cursor, uint32_t t height = 0; } - if (active_x != seat->focus->x || - active_y != seat->focus->y) { - view_move_resize(seat->focus, active_x, active_y, + if (active_x != seat->focus->view->x || + active_y != seat->focus->view->y) { + view_move_resize(seat->focus->view, active_x, active_y, width, height); } else { - view_resize(seat->focus, width, height); + view_resize(seat->focus->view, width, height); } } break; case ROOTS_CURSOR_ROTATE: if (seat->focus) { - struct roots_view *view = seat->focus; + struct roots_view *view = seat->focus->view; int ox = view->x + view->wlr_surface->current->width/2, oy = view->y + view->wlr_surface->current->height/2; int ux = cursor->offs_x - ox, diff --git a/rootston/desktop.c b/rootston/desktop.c index 1695d007..c607043b 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -18,29 +18,6 @@ #include "rootston/seat.h" #include "rootston/xcursor.h" -// TODO replace me with a signal -void view_destroy(struct roots_view *view) { - struct roots_desktop *desktop = view->desktop; - - struct roots_input *input = desktop->server->input; - struct roots_seat *seat; - wl_list_for_each(seat, &input->seats, link) { - if (seat->focus == view) { - seat->focus = NULL; - seat->cursor->mode = ROOTS_CURSOR_PASSTHROUGH; - } - } - - for (size_t i = 0; i < desktop->views->length; ++i) { - struct roots_view *_view = desktop->views->items[i]; - if (view == _view) { - wlr_list_del(desktop->views, i); - break; - } - } - free(view); -} - void view_get_box(const struct roots_view *view, struct wlr_box *box) { box->x = view->x; box->y = view->y; @@ -201,6 +178,25 @@ bool view_center(struct roots_view *view) { return true; } +void view_destroy(struct roots_view *view) { + wl_signal_emit(&view->events.destroy, view); + + wl_list_remove(&view->link); + free(view); +} + +void view_init(struct roots_view *view, struct roots_desktop *desktop) { + view->desktop = desktop; + wl_signal_init(&view->events.destroy); + + wl_list_insert(&desktop->views, &view->link); + + struct roots_seat *seat; + wl_list_for_each(seat, &desktop->server->input->seats, link) { + roots_seat_add_view(seat, view); + } +} + void view_setup(struct roots_view *view) { struct roots_input *input = view->desktop->server->input; // TODO what seat gets focus? the one with the last input event? @@ -215,25 +211,11 @@ void view_setup(struct roots_view *view) { view_update_output(view, &before); } -void view_teardown(struct roots_view *view) { - // TODO replace me with a signal - /* - struct wlr_list *views = view->desktop->views; - if (views->length < 2 || views->items[views->length-1] != view) { - return; - } - - struct roots_view *prev_view = views->items[views->length-2]; - struct roots_input *input = prev_view->desktop->server->input; - set_view_focus(input, prev_view->desktop, prev_view); - */ -} - struct roots_view *view_at(struct roots_desktop *desktop, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { - for (ssize_t i = desktop->views->length - 1; i >= 0; --i) { - struct roots_view *view = desktop->views->items[i]; - + // TODO: use the seat + struct roots_view *view; + wl_list_for_each(view, &desktop->views, link) { if (view->type == ROOTS_WL_SHELL_VIEW && view->wl_shell_surface->state == WLR_WL_SHELL_SURFACE_STATE_POPUP) { @@ -322,11 +304,7 @@ struct roots_desktop *desktop_create(struct roots_server *server, return NULL; } - desktop->views = wlr_list_create(); - if (desktop->views == NULL) { - free(desktop); - return NULL; - } + wl_list_init(&desktop->views); wl_list_init(&desktop->outputs); desktop->output_add.notify = output_add_notify; @@ -342,7 +320,6 @@ struct roots_desktop *desktop_create(struct roots_server *server, ROOTS_XCURSOR_SIZE); if (desktop->xcursor_manager == NULL) { wlr_log(L_ERROR, "Cannot create XCursor manager"); - wlr_list_free(desktop->views); free(desktop); return NULL; } diff --git a/rootston/input.c b/rootston/input.c index 35a5af97..b2cd6472 100644 --- a/rootston/input.c +++ b/rootston/input.c @@ -116,7 +116,7 @@ bool input_view_has_focus(struct roots_input *input, struct roots_view *view) { } struct roots_seat *seat; wl_list_for_each(seat, &input->seats, link) { - if (seat->focus == view) { + if (seat->focus != NULL && seat->focus->view == view) { return true; } } diff --git a/rootston/keyboard.c b/rootston/keyboard.c index 39f46a32..d16d2b75 100644 --- a/rootston/keyboard.c +++ b/rootston/keyboard.c @@ -87,19 +87,20 @@ static const char *exec_prefix = "exec "; static void keyboard_binding_execute(struct roots_keyboard *keyboard, const char *command) { - struct roots_server *server = keyboard->input->server; + struct roots_seat *seat = keyboard->seat; if (strcmp(command, "exit") == 0) { - wl_display_terminate(server->wl_display); + wl_display_terminate(keyboard->input->server->wl_display); } else if (strcmp(command, "close") == 0) { - if (server->desktop->views->length > 0) { - struct roots_view *view = - server->desktop->views->items[server->desktop->views->length-1]; - view_close(view); + if (!wl_list_empty(&seat->views)) { + struct roots_seat_view *first_seat_view = wl_container_of( + seat->views.next, first_seat_view, link); + view_close(first_seat_view->view); } } else if (strcmp(command, "next_window") == 0) { - if (server->desktop->views->length > 0) { - struct roots_view *view = server->desktop->views->items[0]; - roots_seat_focus_view(keyboard->seat, view); + if (!wl_list_empty(&seat->views)) { + struct roots_seat_view *last_seat_view = wl_container_of( + seat->views.prev, last_seat_view, link); + roots_seat_focus_view(seat, last_seat_view->view); } } else if (strncmp(exec_prefix, command, strlen(exec_prefix)) == 0) { const char *shell_cmd = command + strlen(exec_prefix); diff --git a/rootston/output.c b/rootston/output.c index 28312c2c..41514b60 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -186,8 +186,8 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { wlr_output_make_current(wlr_output); wlr_renderer_begin(server->renderer, wlr_output); - for (size_t i = 0; i < desktop->views->length; ++i) { - struct roots_view *view = desktop->views->items[i]; + struct roots_view *view; + wl_list_for_each_reverse(view, &desktop->views, link) { render_view(view, desktop, wlr_output, &now); } diff --git a/rootston/seat.c b/rootston/seat.c index 1fa37c44..08f1997c 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -246,6 +246,7 @@ struct roots_seat *roots_seat_create(struct roots_input *input, char *name) { wl_list_init(&seat->touch); wl_list_init(&seat->tablet_tools); wl_list_init(&seat->drag_icons); + wl_list_init(&seat->views); seat->input = input; @@ -480,8 +481,7 @@ bool roots_seat_has_meta_pressed(struct roots_seat *seat) { } void roots_seat_focus_view(struct roots_seat *seat, struct roots_view *view) { - struct roots_desktop *desktop = seat->input->server->desktop; - if (seat->focus == view) { + if (seat->focus != NULL && seat->focus->view == view) { return; } @@ -490,12 +490,24 @@ void roots_seat_focus_view(struct roots_seat *seat, struct roots_view *view) { return; } - struct roots_view *prev_focus = seat->focus; - seat->focus = view; + bool found = false; + struct roots_seat_view *seat_view; + wl_list_for_each(seat_view, &seat->views, link) { + if (seat_view->view == view) { + found = true; + break; + } + } + if (!found) { + return; + } + + struct roots_seat_view *prev_focus = seat->focus; + seat->focus = seat_view; // unfocus the old view if it is not focused by some other seat - if (prev_focus && !input_view_has_focus(seat->input, prev_focus)) { - view_activate(prev_focus, false); + if (prev_focus && !input_view_has_focus(seat->input, prev_focus->view)) { + view_activate(prev_focus->view, false); } if (!seat->focus) { @@ -503,20 +515,65 @@ void roots_seat_focus_view(struct roots_seat *seat, struct roots_view *view) { return; } - size_t index = 0; - for (size_t i = 0; i < desktop->views->length; ++i) { - struct roots_view *_view = desktop->views->items[i]; - if (_view == view) { - index = i; + view_activate(view, true); + wl_list_remove(&seat_view->view->link); + wl_list_insert(&seat->input->server->desktop->views, + &seat_view->view->link); + + wl_list_remove(&seat_view->link); + wl_list_insert(&seat->views, &seat_view->link); + wlr_seat_keyboard_notify_enter(seat->seat, view->wlr_surface); +} + +static void seat_view_destroy(struct roots_seat_view *seat_view) { + struct roots_seat *seat = seat_view->seat; + + if (seat->focus == seat_view) { + seat->focus = NULL; + seat->cursor->mode = ROOTS_CURSOR_PASSTHROUGH; + } + + wl_list_remove(&seat_view->destroy.link); + wl_list_remove(&seat_view->link); + free(seat_view); + + // Focus first view + if (!wl_list_empty(&seat->views)) { + struct roots_seat_view *first_seat_view = wl_container_of( + seat->views.next, first_seat_view, link); + roots_seat_focus_view(seat, first_seat_view->view); + } +} + +static void seat_view_handle_destroy(struct wl_listener *listener, void *data) { + struct roots_seat_view *seat_view = + wl_container_of(listener, seat_view, destroy); + seat_view_destroy(seat_view); +} + +void roots_seat_add_view(struct roots_seat *seat, struct roots_view *view) { + struct roots_seat_view *seat_view = + calloc(1, sizeof(struct roots_seat_view)); + if (seat_view == NULL) { + return; + } + seat_view->seat = seat; + seat_view->view = view; + + wl_list_insert(&seat->views, &seat_view->link); + + seat_view->destroy.notify = seat_view_handle_destroy; + wl_signal_add(&view->events.destroy, &seat_view->destroy); +} + +void roots_seat_remove_view(struct roots_seat *seat, struct roots_view *view) { + struct roots_seat_view *seat_view; + wl_list_for_each(seat_view, &seat->views, link) { + if (seat_view->view == view) { + seat_view_destroy(seat_view); break; } } - - view_activate(view, true); - // TODO: list_swap - wlr_list_del(desktop->views, index); - wlr_list_add(desktop->views, view); - wlr_seat_keyboard_notify_enter(seat->seat, view->wlr_surface); } void roots_seat_begin_move(struct roots_seat *seat, struct roots_view *view) { diff --git a/rootston/wl_shell.c b/rootston/wl_shell.c index 96f461fe..7359c878 100644 --- a/rootston/wl_shell.c +++ b/rootston/wl_shell.c @@ -77,7 +77,6 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { static void handle_destroy(struct wl_listener *listener, void *data) { struct roots_wl_shell_surface *roots_surface = wl_container_of(listener, roots_surface, destroy); - view_teardown(roots_surface->view); wl_list_remove(&roots_surface->destroy.link); wl_list_remove(&roots_surface->request_move.link); wl_list_remove(&roots_surface->request_resize.link); @@ -88,14 +87,6 @@ static void handle_destroy(struct wl_listener *listener, void *data) { free(roots_surface); } -static int shell_surface_compare_equals(const void *item, const void *cmp_to) { - const struct roots_view *view = item; - if (view->type == ROOTS_WL_SHELL_VIEW && view->wl_shell_surface == cmp_to) { - return 0; - } - return -1; -} - void handle_wl_shell_surface(struct wl_listener *listener, void *data) { struct roots_desktop *desktop = wl_container_of(listener, desktop, wl_shell_surface); @@ -138,17 +129,23 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { view->wlr_surface = surface->surface; view->resize = resize; view->close = close; - view->desktop = desktop; roots_surface->view = view; - wlr_list_add(desktop->views, view); + view_init(view, desktop); + view_setup(view); if (surface->state == WLR_WL_SHELL_SURFACE_STATE_TRANSIENT) { - // we need to map it relative to the parent - int i = wlr_list_seq_find(desktop->views, shell_surface_compare_equals, - surface->parent); - if (i != -1) { - struct roots_view *parent = desktop->views->items[i]; + // We need to map it relative to the parent + bool found = false; + struct roots_view *parent; + wl_list_for_each(parent, &desktop->views, link) { + if (parent->type == ROOTS_WL_SHELL_VIEW && + parent->wl_shell_surface == surface->parent) { + found = true; + break; + } + } + if (found) { view_move(view, parent->x + surface->transient_state->x, parent->y + surface->transient_state->y); diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 6517c8b4..656231c7 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -161,7 +161,6 @@ static void handle_commit(struct wl_listener *listener, void *data) { static void handle_destroy(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, destroy); - view_teardown(roots_xdg_surface->view); wl_list_remove(&roots_xdg_surface->commit.link); wl_list_remove(&roots_xdg_surface->destroy.link); wl_list_remove(&roots_xdg_surface->request_move.link); @@ -219,9 +218,8 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { view->move_resize = move_resize; view->maximize = maximize; view->close = close; - view->desktop = desktop; roots_surface->view = view; - wlr_list_add(desktop->views, view); + view_init(view, desktop); view_setup(view); } diff --git a/rootston/xwayland.c b/rootston/xwayland.c index f4e100dc..f5cb7857 100644 --- a/rootston/xwayland.c +++ b/rootston/xwayland.c @@ -95,7 +95,6 @@ static void maximize(struct roots_view *view, bool maximized) { static void handle_destroy(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, destroy); - view_teardown(roots_surface->view); wl_list_remove(&roots_surface->destroy.link); wl_list_remove(&roots_surface->request_configure.link); wl_list_remove(&roots_surface->request_move.link); @@ -174,29 +173,24 @@ static void handle_request_maximize(struct wl_listener *listener, void *data) { static void handle_map_notify(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, map_notify); + struct wlr_xwayland_surface *xsurface = data; struct roots_view *view = roots_surface->view; - struct wlr_xwayland_surface *xsurface = view->xwayland_surface; - struct roots_desktop *desktop = view->desktop; + //struct roots_desktop *desktop = view->desktop; view->wlr_surface = xsurface->surface; view->x = (double)xsurface->x; view->y = (double)xsurface->y; - wlr_list_push(desktop->views, roots_surface->view); + // TODO: add view to desktop } static void handle_unmap_notify(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, unmap_notify); - struct roots_desktop *desktop = roots_surface->view->desktop; + //struct roots_desktop *desktop = roots_surface->view->desktop; roots_surface->view->wlr_surface = NULL; - for (size_t i = 0; i < desktop->views->length; i++) { - if (desktop->views->items[i] == roots_surface->view) { - wlr_list_del(desktop->views, i); - break; - } - } + // TODO: remove view from desktop } void handle_xwayland_surface(struct wl_listener *listener, void *data) { @@ -242,7 +236,6 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { view->xwayland_surface = surface; view->roots_xwayland_surface = roots_surface; view->wlr_surface = surface->surface; - view->desktop = desktop; view->activate = activate; view->resize = resize; view->move = move; @@ -250,7 +243,7 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { view->maximize = maximize; view->close = close; roots_surface->view = view; - wlr_list_add(desktop->views, view); + view_init(view, desktop); if (!surface->override_redirect) { view_setup(view);