diff --git a/README.md b/README.md index fee0d6a..5c42724 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ wlroots-based Wayland compositor with virtual outputs and physical cursor continuity. Originally forked from dwl. -`LOC: 7442 total, 2878 vwl.c` +`LOC: 7494 total, 2878 vwl.c` ## Features diff --git a/share.c b/share.c index c081561..ebe9d35 100644 --- a/share.c +++ b/share.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include "vwl.h" @@ -19,6 +21,12 @@ static struct vwl_vout_image_capture_source_manager_v1 *vout_capture_mgr; static struct wl_event_loop *share_event_loop; static struct wlr_allocator *share_allocator; static struct wlr_renderer *share_renderer; +static struct share_cursor { + struct wlr_buffer *buffer; + int32_t hotspot_x; + int32_t hotspot_y; + Client *last_hovered; +} share_cursor; static bool ensureimagesource(Client *c); static bool ensurevoutimagesource(VirtualOutput *vout); @@ -55,6 +63,7 @@ static struct wl_listener foreign_toplevel_capture_request = { static size_t last_vout_capture_num; +static void loadcursorimage(struct wlr_xcursor_manager *mgr); static struct wlr_box voutcapturebox(VirtualOutput *vout); static void sourceupdateconstraints(struct vout_image_source *source, const struct wlr_output_state *state); static void rendersource(struct vout_image_source *source); @@ -134,7 +143,7 @@ voutcapturebox(VirtualOutput *vout) { if (!vout || !vout->mon) return (struct wlr_box){0}; - if (vout->layout_geom.width > 0 && vout->layout_geom.height > 0) + if (!wlr_box_empty(&vout->layout_geom)) return vout->layout_geom; return vout->mon->window_area; } @@ -155,12 +164,18 @@ share_create_capture_scene(Client *c) goto fail; if (!wlr_scene_surface_create(c->image_capture_tree, client_surface(c))) goto fail; - return true; + } else { + c->image_capture_tree = wlr_scene_xdg_surface_create(&c->image_capture_scene->tree, c->surface.xdg); + if (!c->image_capture_tree) + goto fail; } - c->image_capture_tree = wlr_scene_xdg_surface_create(&c->image_capture_scene->tree, c->surface.xdg); - if (!c->image_capture_tree) - goto fail; + loadcursorimage(cursor_mgr); + if (share_cursor.buffer) { + c->image_capture_cursor = wlr_scene_buffer_create(&c->image_capture_scene->tree, share_cursor.buffer); + if (c->image_capture_cursor) + wlr_scene_node_set_enabled(&c->image_capture_cursor->node, false); + } return true; @@ -197,6 +212,7 @@ share_destroy_capture_scene(Client *c) wlr_scene_node_destroy(&c->image_capture_scene->tree.node); c->image_capture_scene = NULL; c->image_capture_tree = NULL; + c->image_capture_cursor = NULL; } void @@ -205,6 +221,9 @@ share_destroy(Client *c) if (!c) return; + if (share_cursor.last_hovered == c) + share_cursor.last_hovered = NULL; + if (c->image_capture_source) { wl_list_remove(&c->image_capture_source_destroy.link); wl_list_init(&c->image_capture_source_destroy.link); @@ -239,6 +258,46 @@ share_update_title(Client *c) wlr_ext_foreign_toplevel_handle_v1_update_state(c->ext_foreign_toplevel, &state); } +void +share_update_capture_cursors(double lx, double ly, Client *hovered) +{ + if (hovered && (!hovered->image_capture_cursor || !share_is_captured(hovered))) + hovered = NULL; + + if (!share_cursor.last_hovered && !hovered) + return; + + if (share_cursor.last_hovered && share_cursor.last_hovered != hovered) + wlr_scene_node_set_enabled(&share_cursor.last_hovered->image_capture_cursor->node, false); + + share_cursor.last_hovered = hovered; + + if (!hovered) + return; + + wlr_scene_node_set_position(&hovered->image_capture_cursor->node, + (int)(lx - hovered->geom.x - share_cursor.hotspot_x + hovered->bw), + (int)(ly - hovered->geom.y - share_cursor.hotspot_y + hovered->bw)); + wlr_scene_node_set_enabled(&hovered->image_capture_cursor->node, true); +} + +static void +loadcursorimage(struct wlr_xcursor_manager *mgr) +{ + struct wlr_xcursor *xcursor; + struct wlr_xcursor_image *image; + + if (!mgr || share_cursor.buffer) + return; + xcursor = wlr_xcursor_manager_get_xcursor(mgr, "default", 1); + if (!xcursor || xcursor->image_count == 0) + return; + image = xcursor->images[0]; + share_cursor.buffer = wlr_xcursor_image_get_buffer(image); + share_cursor.hotspot_x = (int32_t)image->hotspot_x; + share_cursor.hotspot_y = (int32_t)image->hotspot_y; +} + static void sourceupdateconstraints(struct vout_image_source *source, const struct wlr_output_state *state) { diff --git a/share.h b/share.h index 314e906..af7735d 100644 --- a/share.h +++ b/share.h @@ -8,6 +8,7 @@ typedef struct Client Client; void share_init(struct wl_display *display, struct wl_event_loop *loop, struct wlr_allocator *allocator, struct wlr_renderer *renderer); void share_cleanuplisteners(void); +void share_update_capture_cursors(double lx, double ly, Client *hovered); bool share_create_capture_scene(Client *c); void share_create_toplevel(Client *c); void share_destroy_capture_scene(Client *c); diff --git a/vwl.c b/vwl.c index 33d0d45..c474c94 100644 --- a/vwl.c +++ b/vwl.c @@ -954,7 +954,7 @@ placefloating(Client *c) if (!c || !c->mon || !client_surface(c)->mapped) return; vout = CLIENT_VOUT(c); - if (vout && vout->layout_geom.width > 0 && vout->layout_geom.height > 0) + if (vout && !wlr_box_empty(&vout->layout_geom)) area = vout->layout_geom; else area = c->mon->window_area; @@ -1224,8 +1224,7 @@ focusclient(Client *c, int lift) if (selvout && selvout->lt[selvout->sellt] && selvout->lt[selvout->sellt]->arrange == tabbed) { struct wlr_box area; tabbed_mon = selvout->mon; - area = (selvout->layout_geom.width && selvout->layout_geom.height) ? selvout->layout_geom - : selvout->mon->window_area; + area = !wlr_box_empty(&selvout->layout_geom) ? selvout->layout_geom : selvout->mon->window_area; tabhdr_update(selvout->mon, selvout, area, focustoptiledvout(selvout)); } c->isurgent = 0; @@ -1418,7 +1417,7 @@ tabmove(const Arg *arg) { struct wlr_box area; - area = (vout->layout_geom.width && vout->layout_geom.height) ? vout->layout_geom : selmon->window_area; + area = !wlr_box_empty(&vout->layout_geom) ? vout->layout_geom : selmon->window_area; tabhdr_update(selmon, vout, area, sel); } focusclient(sel, 1); @@ -1691,6 +1690,7 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d hover.vout = hover_vout; hover.ws = hover_vout ? hover_vout->ws : NULL; xytonode(cursor->x, cursor->y, NULL, &hover.client, NULL, NULL, NULL); + share_update_capture_cursors(cursor->x, cursor->y, hover.client); cursorsync(); @@ -1792,7 +1792,7 @@ resize(Client *c, struct wlr_box geo, int interact) if (!c->mon || !client_surface(c)->mapped) return; - limit = (vout && vout->layout_geom.width && vout->layout_geom.height) ? vout->layout_geom : c->mon->window_area; + limit = (vout && !wlr_box_empty(&vout->layout_geom)) ? vout->layout_geom : c->mon->window_area; bbox = interact ? &sgeom : &limit; client_set_bounds(c, geo.width, geo.height); @@ -1929,7 +1929,7 @@ setfullscreen(Client *c, int fullscreen) else wlr_scene_node_reparent(&c->scene->node, layers[LyrTop]); target = c->mon->monitor_area; - if (c->fullscreen_mode == FS_VIRTUAL && vout && vout->layout_geom.width && vout->layout_geom.height) { + if (c->fullscreen_mode == FS_VIRTUAL && vout && !wlr_box_empty(&vout->layout_geom)) { target = vout->layout_geom; if (vout->lt[vout->sellt] && vout->lt[vout->sellt]->arrange == tabbed) { int header = tabhdr_header_height(); @@ -2386,7 +2386,7 @@ tabbed(Monitor *m) if (!vout) return; - area = (vout->layout_geom.width && vout->layout_geom.height) ? vout->layout_geom : m->window_area; + area = !wlr_box_empty(&vout->layout_geom) ? vout->layout_geom : m->window_area; active = focustoptiledvout(vout); header_height = tabhdr_header_height(); @@ -2440,7 +2440,7 @@ tile(Monitor *m) if (!vout) return; - area = (vout->layout_geom.width && vout->layout_geom.height) ? vout->layout_geom : m->window_area; + area = !wlr_box_empty(&vout->layout_geom) ? vout->layout_geom : m->window_area; wl_list_for_each(c, &clients, link) if (CLIENT_VOUT(c) == vout && VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) @@ -2956,7 +2956,7 @@ voutat(Monitor *m, double lx, double ly) if (!m) return NULL; wl_list_for_each(vout, &m->vouts, link) { - if (vout->layout_geom.width <= 0 || vout->layout_geom.height <= 0) + if (wlr_box_empty(&vout->layout_geom)) continue; if (lx >= vout->layout_geom.x && lx < vout->layout_geom.x + vout->layout_geom.width && ly >= vout->layout_geom.y && ly < vout->layout_geom.y + vout->layout_geom.height) diff --git a/vwl.h b/vwl.h index 62f3de7..916fcab 100644 --- a/vwl.h +++ b/vwl.h @@ -112,6 +112,7 @@ struct Client { struct wlr_scene_tree *scene_surface; struct wlr_scene *image_capture_scene; struct wlr_scene_tree *image_capture_tree; + struct wlr_scene_buffer *image_capture_cursor; struct wlr_ext_foreign_toplevel_handle_v1 *ext_foreign_toplevel; struct wlr_ext_image_capture_source_v1 *image_capture_source; struct wl_list link;