aboutsummaryrefslogtreecommitdiff
path: root/rootston/desktop.c
diff options
context:
space:
mode:
Diffstat (limited to 'rootston/desktop.c')
-rw-r--r--rootston/desktop.c186
1 files changed, 150 insertions, 36 deletions
diff --git a/rootston/desktop.c b/rootston/desktop.c
index 29f78ac7..1695d007 100644
--- a/rootston/desktop.c
+++ b/rootston/desktop.c
@@ -10,19 +10,25 @@
#include <wlr/types/wlr_server_decoration.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_wl_shell.h>
+#include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/types/wlr_xdg_shell_v6.h>
#include <wlr/util/log.h>
#include <server-decoration-protocol.h>
#include "rootston/server.h"
-#include "rootston/server.h"
+#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;
- if (input->active_view == view) {
- input->active_view = NULL;
- input->mode = ROOTS_CURSOR_PASSTHROUGH;
+ 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) {
@@ -35,36 +41,64 @@ void view_destroy(struct roots_view *view) {
free(view);
}
-void view_get_size(struct roots_view *view, struct wlr_box *box) {
+void view_get_box(const struct roots_view *view, struct wlr_box *box) {
+ box->x = view->x;
+ box->y = view->y;
if (view->get_size) {
view->get_size(view, box);
- return;
+ } else {
+ box->width = view->wlr_surface->current->width;
+ box->height = view->wlr_surface->current->height;
}
- box->x = box->y = 0;
- box->width = view->wlr_surface->current->width;
- box->height = view->wlr_surface->current->height;
}
-void view_activate(struct roots_view *view, bool activate) {
- if (view->activate) {
- view->activate(view, activate);
+static void view_update_output(const struct roots_view *view,
+ const struct wlr_box *before) {
+ struct roots_desktop *desktop = view->desktop;
+ struct roots_output *output;
+ struct wlr_box box;
+ view_get_box(view, &box);
+ wl_list_for_each(output, &desktop->outputs, link) {
+ bool intersected = before->x != -1 && wlr_output_layout_intersects(
+ desktop->layout, output->wlr_output,
+ before->x, before->y, before->x + before->width,
+ before->y + before->height);
+ bool intersects = wlr_output_layout_intersects(
+ desktop->layout, output->wlr_output,
+ view->x, view->y, view->x + box.width, view->y + box.height);
+ if (intersected && !intersects) {
+ wlr_surface_send_leave(view->wlr_surface, output->wlr_output);
+ }
+ if (!intersected && intersects) {
+ wlr_surface_send_enter(view->wlr_surface, output->wlr_output);
+ }
}
}
void view_move(struct roots_view *view, double x, double y) {
+ struct wlr_box before;
+ view_get_box(view, &before);
if (view->move) {
view->move(view, x, y);
- return;
+ } else {
+ view->x = x;
+ view->y = y;
}
+}
- view->x = x;
- view->y = y;
+void view_activate(struct roots_view *view, bool activate) {
+ if (view->activate) {
+ view->activate(view, activate);
+ }
}
void view_resize(struct roots_view *view, uint32_t width, uint32_t height) {
+ struct wlr_box before;
+ view_get_box(view, &before);
if (view->resize) {
view->resize(view, width, height);
}
+ view_update_output(view, &before);
}
void view_move_resize(struct roots_view *view, double x, double y,
@@ -78,6 +112,50 @@ void view_move_resize(struct roots_view *view, double x, double y,
view_resize(view, width, height);
}
+void view_maximize(struct roots_view *view, bool maximized) {
+ if (view->maximized == maximized) {
+ return;
+ }
+
+ if (view->maximize) {
+ view->maximize(view, maximized);
+ }
+
+ if (!view->maximized && maximized) {
+ struct wlr_box view_box;
+ view_get_box(view, &view_box);
+
+ view->maximized = true;
+ view->saved.x = view->x;
+ view->saved.y = view->y;
+ view->saved.rotation = view->rotation;
+ view->saved.width = view_box.width;
+ view->saved.height = view_box.height;
+
+ double output_x, output_y;
+ wlr_output_layout_closest_point(view->desktop->layout, NULL,
+ view->x + (double)view_box.width/2,
+ view->y + (double)view_box.height/2,
+ &output_x, &output_y);
+ struct wlr_output *output = wlr_output_layout_output_at(
+ view->desktop->layout, output_x, output_y);
+ struct wlr_box *output_box =
+ wlr_output_layout_get_box(view->desktop->layout, output);
+
+ view_move_resize(view, output_box->x, output_box->y, output_box->width,
+ output_box->height);
+ view->rotation = 0;
+ }
+
+ if (view->maximized && !maximized) {
+ view->maximized = false;
+
+ view_move_resize(view, view->saved.x, view->saved.y, view->saved.width,
+ view->saved.height);
+ view->rotation = view->saved.rotation;
+ }
+}
+
void view_close(struct roots_view *view) {
if (view->close) {
view->close(view);
@@ -85,19 +163,26 @@ void view_close(struct roots_view *view) {
}
bool view_center(struct roots_view *view) {
- struct wlr_box size;
- view_get_size(view, &size);
+ struct wlr_box box;
+ view_get_box(view, &box);
struct roots_desktop *desktop = view->desktop;
- struct wlr_cursor *cursor = desktop->server->input->cursor;
-
- struct wlr_output *output =
- wlr_output_layout_output_at(desktop->layout, cursor->x, cursor->y);
-
- if (!output) {
- output = wlr_output_layout_get_center_output(desktop->layout);
+ struct roots_input *input = desktop->server->input;
+ struct roots_seat *seat = NULL, *_seat;
+ wl_list_for_each(_seat, &input->seats, link) {
+ if (!seat || (seat->seat->last_event.tv_sec > _seat->seat->last_event.tv_sec &&
+ seat->seat->last_event.tv_nsec > _seat->seat->last_event.tv_nsec)) {
+ seat = _seat;
+ }
+ }
+ if (!seat) {
+ return false;
}
+ struct wlr_output *output =
+ wlr_output_layout_output_at(desktop->layout,
+ seat->cursor->cursor->x,
+ seat->cursor->cursor->y);
if (!output) {
// empty layout
return false;
@@ -109,22 +194,30 @@ bool view_center(struct roots_view *view) {
int width, height;
wlr_output_effective_resolution(output, &width, &height);
- double view_x = (double)(width - size.width) / 2 + l_output->x;
- double view_y = (double)(height - size.height) / 2 + l_output->y;
-
+ double view_x = (double)(width - box.width) / 2 + l_output->x;
+ double view_y = (double)(height - box.height) / 2 + l_output->y;
view_move(view, view_x, view_y);
return true;
}
void view_setup(struct roots_view *view) {
- view_center(view);
-
struct roots_input *input = view->desktop->server->input;
- set_view_focus(input, view->desktop, view);
+ // TODO what seat gets focus? the one with the last input event?
+ struct roots_seat *seat;
+ wl_list_for_each(seat, &input->seats, link) {
+ roots_seat_focus_view(seat, view);
+ }
+
+ view_center(view);
+ struct wlr_box before;
+ view_get_box(view, &before);
+ 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;
@@ -133,12 +226,12 @@ void view_teardown(struct roots_view *view) {
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);
- wlr_seat_keyboard_notify_enter(input->wl_seat, prev_view->wlr_surface);
+ */
}
struct roots_view *view_at(struct roots_desktop *desktop, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) {
- for (int i = desktop->views->length - 1; i >= 0; --i) {
+ for (ssize_t i = desktop->views->length - 1; i >= 0; --i) {
struct roots_view *view = desktop->views->items[i];
if (view->type == ROOTS_WL_SHELL_VIEW &&
@@ -150,11 +243,12 @@ struct roots_view *view_at(struct roots_desktop *desktop, double lx, double ly,
double view_sx = lx - view->x;
double view_sy = ly - view->y;
+ struct wlr_surface_state *state = view->wlr_surface->current;
struct wlr_box box = {
.x = 0,
.y = 0,
- .width = view->wlr_surface->current->buffer_width,
- .height = view->wlr_surface->current->buffer_height,
+ .width = state->buffer_width / state->scale,
+ .height = state->buffer_height / state->scale,
};
if (view->rotation != 0.0) {
// Coordinates relative to the center of the view
@@ -168,7 +262,6 @@ struct roots_view *view_at(struct roots_desktop *desktop, double lx, double ly,
}
if (view->type == ROOTS_XDG_SHELL_V6_VIEW) {
- // TODO: test if this works with rotated views
double popup_sx, popup_sy;
struct wlr_xdg_surface_v6 *popup =
wlr_xdg_surface_v6_popup_at(view->xdg_surface_v6,
@@ -183,7 +276,6 @@ struct roots_view *view_at(struct roots_desktop *desktop, double lx, double ly,
}
if (view->type == ROOTS_WL_SHELL_VIEW) {
- // TODO: test if this works with rotated views
double popup_sx, popup_sy;
struct wlr_wl_shell_surface *popup =
wlr_wl_shell_surface_popup_at(view->wl_shell_surface,
@@ -245,6 +337,16 @@ struct roots_desktop *desktop_create(struct roots_server *server,
desktop->server = server;
desktop->config = config;
+
+ desktop->xcursor_manager = wlr_xcursor_manager_create(NULL,
+ 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;
+ }
+
desktop->layout = wlr_output_layout_create();
desktop->compositor = wlr_compositor_create(server->wl_display,
server->renderer);
@@ -266,6 +368,18 @@ struct roots_desktop *desktop_create(struct roots_server *server,
wl_signal_add(&desktop->xwayland->events.new_surface,
&desktop->xwayland_surface);
desktop->xwayland_surface.notify = handle_xwayland_surface;
+
+ if (wlr_xcursor_manager_load(desktop->xcursor_manager, 1)) {
+ wlr_log(L_ERROR, "Cannot load XWayland XCursor theme");
+ }
+ struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor(
+ desktop->xcursor_manager, ROOTS_XCURSOR_DEFAULT, 1);
+ if (xcursor != NULL) {
+ struct wlr_xcursor_image *image = xcursor->images[0];
+ wlr_xwayland_set_cursor(desktop->xwayland, image->buffer,
+ image->width, image->width, image->height, image->hotspot_x,
+ image->hotspot_y);
+ }
}
#endif