@@ 11,8 11,8 @@ static const float rootcolor[] = COLOR(0x222222ff);
static const float bordercolor[] = COLOR(0x444444ff);
static const float focuscolor[] = COLOR(0x005577ff);
static const float urgentcolor[] = COLOR(0xff0000ff);
-/* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */
-static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; /* You can also use glsl colors */
+/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
+static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */
/* tagging - TAGCOUNT must be no greater than 31 */
#define TAGCOUNT (9)
@@ 21,11 21,10 @@ static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; /* You can al
static int log_level = WLR_ERROR;
static const Rule rules[] = {
- /* app_id title tags mask isfloating monitor */
- /* examples:
- { "Gimp", NULL, 0, 1, -1 },
- */
- { "firefox", NULL, 1 << 8, 0, -1 },
+ /* app_id title tags mask isfloating monitor */
+ /* examples: */
+ { "Gimp_EXAMPLE", NULL, 0, 1, -1 }, /* Start on currently visible tags floating, not tiled */
+ { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1 }, /* Start on ONLY tag "9" */
};
/* layout(s) */
@@ 39,12 38,12 @@ static const Layout layouts[] = {
/* monitors */
/* NOTE: ALWAYS add a fallback rule, even if you are completely sure it won't be used */
static const MonitorRule monrules[] = {
- /* name mfact nmaster scale layout rotate/reflect x y */
+ /* name mfact nmaster scale layout rotate/reflect x y */
/* example of a HiDPI laptop monitor:
- { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
+ { "eDP-1", 0.5f, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
*/
/* defaults */
- { NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
+ { NULL, 0.55f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
};
/* keyboard */
@@ 95,6 94,7 @@ LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE
*/
static const enum libinput_config_accel_profile accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
static const double accel_speed = 0.0;
+
/* You can choose between:
LIBINPUT_CONFIG_TAP_MAP_LRM -- 1/2/3 finger tap maps to left/right/middle
LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right
@@ 126,8 126,8 @@ static const Key keys[] = {
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
{ MODKEY, XKB_KEY_d, incnmaster, {.i = -1} },
- { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05} },
- { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05} },
+ { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} },
+ { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05f} },
{ MODKEY, XKB_KEY_Return, zoom, {0} },
{ MODKEY, XKB_KEY_Tab, view, {0} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} },
@@ 35,9 35,11 @@
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output_management_v1.h>
#include <wlr/types/wlr_pointer.h>
+#include <wlr/types/wlr_pointer_constraints_v1.h>
#include <wlr/types/wlr_presentation_time.h>
#include <wlr/types/wlr_primary_selection.h>
#include <wlr/types/wlr_primary_selection_v1.h>
+#include <wlr/types/wlr_relative_pointer_v1.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_screencopy_v1.h>
#include <wlr/types/wlr_seat.h>
@@ 47,12 49,14 @@
#include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_viewporter.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
+#include <wlr/types/wlr_virtual_pointer_v1.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/types/wlr_xdg_activation_v1.h>
#include <wlr/types/wlr_xdg_decoration_v1.h>
#include <wlr/types/wlr_xdg_output_v1.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/log.h>
+#include <wlr/util/region.h>
#include <xkbcommon/xkbcommon.h>
#ifdef XWAYLAND
#include <wlr/xwayland.h>
@@ 65,8 69,9 @@
/* macros */
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#define MIN(A, B) ((A) < (B) ? (A) : (B))
+#define ROUND(X) ((int)((X < 0) ? (X - 0.5) : (X + 0.5)))
#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
-#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]))
+#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]) || (C)->issticky)
#define SVISIBLEON(C, M) ((M) && (C)->mon && ((C)->tags & (M)->tagset[(M)->seltags]))
#define LENGTH(X) (sizeof X / sizeof X[0])
#define END(A) ((A) + LENGTH(A))
@@ 77,7 82,7 @@
/* enums */
enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
enum { XDGShell, LayerShell, X11 }; /* client types */
-enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrFS, LyrTop, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */
+enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */
#ifdef XWAYLAND
enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar,
NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */
@@ 133,7 138,7 @@ typedef struct {
#endif
unsigned int bw;
uint32_t tags;
- int isfloating, isurgent, isfullscreen;
+ int isfloating, isurgent, isfullscreen, issticky;
uint32_t resize; /* configure serial of a pending resize */
} Client;
@@ 197,7 202,7 @@ struct Monitor {
unsigned int seltags;
unsigned int sellt;
uint32_t tagset[2];
- double mfact;
+ float mfact;
int gamma_lut_changed;
int nmaster;
char ltsymbol[16];
@@ 214,6 219,11 @@ typedef struct {
} MonitorRule;
typedef struct {
+ struct wlr_pointer_constraint_v1 *constraint;
+ struct wl_listener destroy;
+} PointerConstraint;
+
+typedef struct {
const char *id;
const char *title;
uint32_t tags;
@@ 255,7 265,10 @@ static void createlocksurface(struct wl_listener *listener, void *data);
static void createmon(struct wl_listener *listener, void *data);
static void createnotify(struct wl_listener *listener, void *data);
static void createpointer(struct wlr_pointer *pointer);
+static void createpointerconstraint(struct wl_listener *listener, void *data);
+static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint);
static void cursorframe(struct wl_listener *listener, void *data);
+static void cursorwarptohint(void);
static void destroydecoration(struct wl_listener *listener, void *data);
static void destroydragicon(struct wl_listener *listener, void *data);
static void destroyidleinhibitor(struct wl_listener *listener, void *data);
@@ 263,6 276,7 @@ static void destroylayersurfacenotify(struct wl_listener *listener, void *data);
static void destroylock(SessionLock *lock, int unlocked);
static void destroylocksurface(struct wl_listener *listener, void *data);
static void destroynotify(struct wl_listener *listener, void *data);
+static void destroypointerconstraint(struct wl_listener *listener, void *data);
static void destroysessionlock(struct wl_listener *listener, void *data);
static void destroysessionmgr(struct wl_listener *listener, void *data);
static Monitor *dirtomon(enum wlr_direction dir);
@@ 286,7 300,8 @@ static void mapnotify(struct wl_listener *listener, void *data);
static void maximizenotify(struct wl_listener *listener, void *data);
static void monocle(Monitor *m);
static void motionabsolute(struct wl_listener *listener, void *data);
-static void motionnotify(uint32_t time);
+static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx,
+ double sy, double sx_unaccel, double sy_unaccel);
static void motionrelative(struct wl_listener *listener, void *data);
static void moveresize(const Arg *arg);
static void outputmgrapply(struct wl_listener *listener, void *data);
@@ 306,6 321,7 @@ static void setcursor(struct wl_listener *listener, void *data);
static void setcursorshape(struct wl_listener *listener, void *data);
static void setfloating(Client *c, int floating);
static void setfullscreen(Client *c, int fullscreen);
+static void setsticky(Client *c, int sticky);
static void setgamma(struct wl_listener *listener, void *data);
static void setlayout(const Arg *arg);
static void setmfact(const Arg *arg);
@@ 319,6 335,7 @@ static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
static void tile(Monitor *m);
static void togglefloating(const Arg *arg);
+static void togglesticky(const Arg *arg);
static void togglefullscreen(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
@@ 330,6 347,7 @@ static void updatetitle(struct wl_listener *listener, void *data);
static void urgent(struct wl_listener *listener, void *data);
static void view(const Arg *arg);
static void virtualkeyboard(struct wl_listener *listener, void *data);
+static void virtualpointer(struct wl_listener *listener, void *data);
static Monitor *xytomon(double x, double y);
static void xytonode(double x, double y, struct wlr_surface **psurface,
Client **pc, LayerSurface **pl, double *nx, double *ny);
@@ 363,8 381,13 @@ static struct wlr_layer_shell_v1 *layer_shell;
static struct wlr_output_manager_v1 *output_mgr;
static struct wlr_gamma_control_manager_v1 *gamma_control_mgr;
static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr;
+static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr;
static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr;
+static struct wlr_pointer_constraints_v1 *pointer_constraints;
+static struct wlr_relative_pointer_manager_v1 *relative_pointer_mgr;
+static struct wlr_pointer_constraint_v1 *active_constraint;
+
static struct wlr_cursor *cursor;
static struct wlr_xcursor_manager *cursor_mgr;
@@ 411,16 434,16 @@ void
applybounds(Client *c, struct wlr_box *bbox)
{
/* set minimum possible */
- c->geom.width = MAX(1, c->geom.width);
- c->geom.height = MAX(1, c->geom.height);
+ c->geom.width = MAX(1 + 2 * (int)c->bw, c->geom.width);
+ c->geom.height = MAX(1 + 2 * (int)c->bw, c->geom.height);
if (c->geom.x >= bbox->x + bbox->width)
c->geom.x = bbox->x + bbox->width - c->geom.width;
if (c->geom.y >= bbox->y + bbox->height)
c->geom.y = bbox->y + bbox->height - c->geom.height;
- if (c->geom.x + c->geom.width + 2 * c->bw <= bbox->x)
+ if (c->geom.x + c->geom.width + 2 * (int)c->bw <= bbox->x)
c->geom.x = bbox->x;
- if (c->geom.y + c->geom.height + 2 * c->bw <= bbox->y)
+ if (c->geom.y + c->geom.height + 2 * (int)c->bw <= bbox->y)
c->geom.y = bbox->y;
}
@@ 429,7 452,8 @@ applyrules(Client *c)
{
/* rule matching */
const char *appid, *title;
- uint32_t i, newtags = 0;
+ uint32_t newtags = 0;
+ int i;
const Rule *r;
Monitor *mon = selmon, *m;
@@ 451,7 475,6 @@ applyrules(Client *c)
}
}
}
- wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]);
setmon(c, mon, newtags);
}
@@ 459,6 482,10 @@ void
arrange(Monitor *m)
{
Client *c;
+
+ if (!m->wlr_output->enabled)
+ return;
+
wl_list_for_each(c, &clients, link) {
if (c->mon == m) {
wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m));
@@ 473,7 500,7 @@ arrange(Monitor *m)
if (m->lt[m->sellt]->arrange)
m->lt[m->sellt]->arrange(m);
- motionnotify(0);
+ motionnotify(0, NULL, 0, 0, 0, 0);
checkidleinhibitor(NULL);
}
@@ 523,7 550,7 @@ arrangelayers(Monitor *m)
arrangelayer(m, &m->layers[i], &usable_area, 0);
/* Find topmost keyboard interactive layer, if such a layer exists */
- for (i = 0; i < LENGTH(layers_above_shell); i++) {
+ for (i = 0; i < (int)LENGTH(layers_above_shell); i++) {
wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) {
if (locked || !l->layer_surface->current.keyboard_interactive || !l->mapped)
continue;
@@ 699,7 726,7 @@ cleanupmon(struct wl_listener *listener, void *data)
{
Monitor *m = wl_container_of(listener, m, destroy);
LayerSurface *l, *tmp;
- int i;
+ size_t i;
/* m->layers[i] are intentionally not unlinked */
for (i = 0; i < LENGTH(m->layers); i++) {
@@ 905,7 932,8 @@ createmon(struct wl_listener *listener, void *data)
m->m.y = r->y;
m->mfact = r->mfact;
m->nmaster = r->nmaster;
- m->lt[0] = m->lt[1] = r->lt;
+ m->lt[0] = r->lt;
+ m->lt[1] = &layouts[LENGTH(layouts) > 1 && r->lt != &layouts[1]];
strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol));
wlr_output_state_set_scale(&state, r->scale);
wlr_output_state_set_transform(&state, r->rr);
@@ 1049,6 1077,28 @@ createpointer(struct wlr_pointer *pointer)
}
void
+createpointerconstraint(struct wl_listener *listener, void *data)
+{
+ PointerConstraint *pointer_constraint = ecalloc(1, sizeof(*pointer_constraint));
+ pointer_constraint->constraint = data;
+ LISTEN(&pointer_constraint->constraint->events.destroy,
+ &pointer_constraint->destroy, destroypointerconstraint);
+}
+
+void
+cursorconstrain(struct wlr_pointer_constraint_v1 *constraint)
+{
+ if (active_constraint == constraint)
+ return;
+
+ if (active_constraint)
+ wlr_pointer_constraint_v1_send_deactivated(active_constraint);
+
+ active_constraint = constraint;
+ wlr_pointer_constraint_v1_send_activated(constraint);
+}
+
+void
cursorframe(struct wl_listener *listener, void *data)
{
/* This event is forwarded by the cursor when a pointer emits an frame
@@ 1060,6 1110,21 @@ cursorframe(struct wl_listener *listener, void *data)
}
void
+cursorwarptohint(void)
+{
+ Client *c = NULL;
+ double sx = active_constraint->current.cursor_hint.x;
+ double sy = active_constraint->current.cursor_hint.y;
+
+ toplevel_from_wlr_surface(active_constraint->surface, &c, NULL);
+ /* TODO: wlroots 0.18: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4478 */
+ if (c && (active_constraint->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT )) {
+ wlr_cursor_warp(cursor, NULL, sx + c->geom.x + c->bw, sy + c->geom.y + c->bw);
+ wlr_seat_pointer_warp(active_constraint->seat, sx, sy);
+ }
+}
+
+void
destroydecoration(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, destroy_decoration);
@@ 1073,7 1138,7 @@ destroydragicon(struct wl_listener *listener, void *data)
{
/* Focus enter isn't sent during drag, so refocus the focused node. */
focusclient(focustop(selmon), 1);
- motionnotify(0);
+ motionnotify(0, NULL, 0, 0, 0, 0);
}
void
@@ 1109,7 1174,7 @@ destroylock(SessionLock *lock, int unlock)
wlr_scene_node_set_enabled(&locked_bg->node, 0);
focusclient(focustop(selmon), 0);
- motionnotify(0);
+ motionnotify(0, NULL, 0, 0, 0, 0);
destroy:
wl_list_remove(&lock->new_surface.link);
@@ 1169,6 1234,20 @@ destroynotify(struct wl_listener *listener, void *data)
}
void
+destroypointerconstraint(struct wl_listener *listener, void *data)
+{
+ PointerConstraint *pointer_constraint = wl_container_of(listener, pointer_constraint, destroy);
+
+ if (active_constraint == pointer_constraint->constraint) {
+ cursorwarptohint();
+ active_constraint = NULL;
+ }
+
+ wl_list_remove(&pointer_constraint->destroy.link);
+ free(pointer_constraint);
+}
+
+void
destroysessionlock(struct wl_listener *listener, void *data)
{
SessionLock *lock = wl_container_of(listener, lock, destroy);
@@ 1264,7 1343,7 @@ focusclient(Client *c, int lift)
}
/* Change cursor surface */
- motionnotify(0);
+ motionnotify(0, NULL, 0, 0, 0, 0);
/* Have a client, so focus its top-level wlr_surface */
client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat));
@@ 1290,7 1369,7 @@ focusstack(const Arg *arg)
{
/* Focus the next or previous client (in tiling order) on selmon */
Client *c, *sel = focustop(selmon);
- if (!sel || sel->isfullscreen)
+ if (!sel || (sel->isfullscreen && !client_has_children(sel)))
return;
if (arg->i > 0) {
wl_list_for_each(c, &sel->link, link) {
@@ 1546,15 1625,15 @@ locksession(struct wl_listener *listener, void *data)
void
maplayersurfacenotify(struct wl_listener *listener, void *data)
{
- LayerSurface *l = wl_container_of(listener, l, map);
- motionnotify(0);
+ motionnotify(0, NULL, 0, 0, 0, 0);
}
void
mapnotify(struct wl_listener *listener, void *data)
{
/* Called when the surface is mapped, or ready to display on-screen. */
- Client *p, *w, *c = wl_container_of(listener, c, map);
+ Client *p = NULL;
+ Client *w, *c = wl_container_of(listener, c, map);
Monitor *m;
int i;
@@ 1600,10 1679,8 @@ mapnotify(struct wl_listener *listener, void *data)
* we always consider floating, clients that have parent and thus
* we set the same tags and monitor than its parent, if not
* try to apply rules for them */
- /* TODO: https://github.com/djpohly/dwl/pull/334#issuecomment-1330166324 */
- if (c->type == XDGShell && (p = client_get_parent(c))) {
+ if ((p = client_get_parent(c))) {
c->isfloating = 1;
- wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]);
setmon(c, p->mon, p->tags);
} else {
applyrules(c);
@@ 1613,7 1690,7 @@ mapnotify(struct wl_listener *listener, void *data)
unset_fullscreen:
m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y);
wl_list_for_each(w, &clients, link) {
- if (w != c && w->isfullscreen && m == w->mon && (w->tags & c->tags))
+ if (w != c && w != p && w->isfullscreen && m == w->mon && (w->tags & c->tags))
setfullscreen(w, 0);
}
}
@@ 1663,20 1740,53 @@ motionabsolute(struct wl_listener *listener, void *data)
* so we have to warp the mouse there. There is also some hardware which
* emits these events. */
struct wlr_pointer_motion_absolute_event *event = data;
- wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y);
- motionnotify(event->time_msec);
+ double lx, ly, dx, dy;
+
+ if (!event->time_msec) /* this is 0 with virtual pointers */
+ wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y);
+
+ wlr_cursor_absolute_to_layout_coords(cursor, &event->pointer->base, event->x, event->y, &lx, &ly);
+ dx = lx - cursor->x;
+ dy = ly - cursor->y;
+ motionnotify(event->time_msec, &event->pointer->base, dx, dy, dx, dy);
}
void
-motionnotify(uint32_t time)
+motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
+ double dx_unaccel, double dy_unaccel)
{
- double sx = 0, sy = 0;
+ double sx = 0, sy = 0, sx_confined, sy_confined;
Client *c = NULL, *w = NULL;
LayerSurface *l = NULL;
struct wlr_surface *surface = NULL;
+ struct wlr_pointer_constraint_v1 *constraint;
/* time is 0 in internal calls meant to restore pointer focus. */
if (time) {
+ wlr_relative_pointer_manager_v1_send_relative_motion(
+ relative_pointer_mgr, seat, (uint64_t)time * 1000,
+ dx, dy, dx_unaccel, dy_unaccel);
+
+ wl_list_for_each(constraint, &pointer_constraints->constraints, link)
+ cursorconstrain(constraint);
+
+ if (active_constraint && cursor_mode != CurResize && cursor_mode != CurMove) {
+ toplevel_from_wlr_surface(active_constraint->surface, &c, NULL);
+ if (c && active_constraint->surface == seat->pointer_state.focused_surface) {
+ sx = cursor->x - c->geom.x - c->bw;
+ sy = cursor->y - c->geom.y - c->bw;
+ if (wlr_region_confine(&active_constraint->region, sx, sy,
+ sx + dx, sy + dy, &sx_confined, &sy_confined)) {
+ dx = sx_confined - sx;
+ dy = sy_confined - sy;
+ }
+
+ if (active_constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED)
+ return;
+ }
+ }
+
+ wlr_cursor_move(cursor, device, dx, dy);
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
/* Update selmon (even while dragging a window) */
@@ 1685,17 1795,17 @@ motionnotify(uint32_t time)
}
/* Update drag icon's position */
- wlr_scene_node_set_position(&drag_icon->node, cursor->x, cursor->y);
+ wlr_scene_node_set_position(&drag_icon->node, ROUND(cursor->x), ROUND(cursor->y));
/* If we are currently grabbing the mouse, handle and return */
if (cursor_mode == CurMove) {
/* Move the grabbed client to the new position. */
- resize(grabc, (struct wlr_box){.x = cursor->x - grabcx, .y = cursor->y - grabcy,
+ resize(grabc, (struct wlr_box){.x = ROUND(cursor->x) - grabcx, .y = ROUND(cursor->y) - grabcy,
.width = grabc->geom.width, .height = grabc->geom.height}, 1);
return;
} else if (cursor_mode == CurResize) {
resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
- .width = cursor->x - grabc->geom.x, .height = cursor->y - grabc->geom.y}, 1);
+ .width = ROUND(cursor->x) - grabc->geom.x, .height = ROUND(cursor->y) - grabc->geom.y}, 1);
return;
}
@@ 1730,8 1840,8 @@ motionrelative(struct wl_listener *listener, void *data)
* special configuration applied for the specific input device which
* generated the event. You can pass NULL for the device if you want to move
* the cursor around without any input. */
- wlr_cursor_move(cursor, &event->pointer->base, event->delta_x, event->delta_y);
- motionnotify(event->time_msec);
+ motionnotify(event->time_msec, &event->pointer->base, event->delta_x, event->delta_y,
+ event->unaccel_dx, event->unaccel_dy);
}
void
@@ 1747,8 1857,8 @@ moveresize(const Arg *arg)
setfloating(grabc, 1);
switch (cursor_mode = arg->ui) {
case CurMove:
- grabcx = cursor->x - grabc->geom.x;
- grabcy = cursor->y - grabc->geom.y;
+ grabcx = ROUND(cursor->x) - grabc->geom.x;
+ grabcy = ROUND(cursor->y) - grabc->geom.y;
wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
break;
case CurResize:
@@ 1839,7 1949,8 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,
{
struct timespec now;
- if (sloppyfocus && time && c && !client_is_unmanaged(c))
+ if ((!active_constraint || active_constraint->surface != surface) &&
+ sloppyfocus && time && c && !client_is_unmanaged(c))
focusclient(c, 0);
/* If surface is NULL, clear pointer focus */
@@ 1858,7 1969,6 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,
* wlroots makes this a no-op if surface is already focused */
wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
wlr_seat_pointer_notify_motion(seat, time, sx, sy);
-
}
void
@@ 1881,8 1991,8 @@ printstatus(void)
appid = client_get_appid(c);
printf("%s title %s\n", m->wlr_output->name, title ? title : broken);
printf("%s appid %s\n", m->wlr_output->name, appid ? appid : broken);
- printf("%s fullscreen %u\n", m->wlr_output->name, c->isfullscreen);
- printf("%s floating %u\n", m->wlr_output->name, c->isfloating);
+ printf("%s fullscreen %d\n", m->wlr_output->name, c->isfullscreen);
+ printf("%s floating %d\n", m->wlr_output->name, c->isfloating);
sel = c->tags;
} else {
printf("%s title \n", m->wlr_output->name);
@@ 1893,8 2003,8 @@ printstatus(void)
}
printf("%s selmon %u\n", m->wlr_output->name, m == selmon);
- printf("%s tags %u %u %u %u\n", m->wlr_output->name, occ,
- m->tagset[m->seltags], sel, urg);
+ printf("%s tags %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32"\n",
+ m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg);
printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol);
}
fflush(stdout);
@@ 2102,11 2212,13 @@ setcursorshape(struct wl_listener *listener, void *data)
void
setfloating(Client *c, int floating)
{
+ Client *p = client_get_parent(c);
c->isfloating = floating;
if (!c->mon)
return;
- wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen
- ? LyrFS : c->isfloating ? LyrFloat : LyrTile]);
+ wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
+ (p && p->isfullscreen) ? LyrFS
+ : c->isfloating ? LyrFloat : LyrTile]);
arrange(c->mon);
printstatus();
}
@@ 2139,11 2251,24 @@ setgamma(struct wl_listener *listener, void *data)
{
struct wlr_gamma_control_manager_v1_set_gamma_event *event = data;
Monitor *m = event->output->data;
+ if (!m)
+ return;
m->gamma_lut_changed = 1;
wlr_output_schedule_frame(m->wlr_output);
}
void
+setsticky(Client *c, int sticky)
+{
+ if(sticky && !c->issticky) {
+ c->issticky = 1;
+ } else if(!sticky && c->issticky) {
+ c->issticky = 0;
+ arrange(c->mon);
+ }
+}
+
+void
setlayout(const Arg *arg)
{
if (!selmon)
@@ 2165,7 2290,7 @@ setmfact(const Arg *arg)
if (!arg || !selmon || !selmon->lt[selmon->sellt]->arrange)
return;
- f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
+ f = arg->f < 1.0f ? arg->f + selmon->mfact : arg->f - 1.0f;
if (f < 0.1 || f > 0.9)
return;
selmon->mfact = f;
@@ 2227,7 2352,7 @@ setup(void)
struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig};
sigemptyset(&sa.sa_mask);
- for (i = 0; i < LENGTH(sig); i++)
+ for (i = 0; i < (int)LENGTH(sig); i++)
sigaction(sig[i], &sa, NULL);
wlr_log_init(log_level, NULL);
@@ 2337,7 2462,7 @@ setup(void)
wl_signal_add(&session_lock_mgr->events.new_lock, &lock_listener);
LISTEN_STATIC(&session_lock_mgr->events.destroy, destroysessionmgr);
locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height,
- (float [4]){0.1, 0.1, 0.1, 1.0});
+ (float [4]){0.1f, 0.1f, 0.1f, 1.0f});
wlr_scene_node_set_enabled(&locked_bg->node, 0);
/* Use decoration protocols to negotiate server-side decorations */
@@ 2347,6 2472,11 @@ setup(void)
xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy);
LISTEN_STATIC(&xdg_decoration_mgr->events.new_toplevel_decoration, createdecoration);
+ pointer_constraints = wlr_pointer_constraints_v1_create(dpy);
+ LISTEN_STATIC(&pointer_constraints->events.new_constraint, createpointerconstraint);
+
+ relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy);
+
/*
* Creates a cursor, which is a wlroots utility for tracking the cursor
* image shown on screen.
@@ 2389,6 2519,9 @@ setup(void)
LISTEN_STATIC(&backend->events.new_input, inputdevice);
virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy);
LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, virtualkeyboard);
+ virtual_pointer_mgr = wlr_virtual_pointer_manager_v1_create(dpy);
+ LISTEN_STATIC(&virtual_pointer_mgr->events.new_virtual_pointer, virtualpointer);
+
seat = wlr_seat_create(dpy, "seat0");
LISTEN_STATIC(&seat->events.request_set_cursor, setcursor);
LISTEN_STATIC(&seat->events.request_set_selection, setsel);
@@ 2526,7 2659,8 @@ tagmon(const Arg *arg)
void
tile(Monitor *m)
{
- unsigned int i, n = 0, mw, my, ty;
+ unsigned int mw, my, ty;
+ int i, n = 0;
Client *c;
wl_list_for_each(c, &clients, link)
@@ 2536,7 2670,7 @@ tile(Monitor *m)
return;
if (n > m->nmaster)
- mw = m->nmaster ? m->w.width * m->mfact : 0;
+ mw = m->nmaster ? ROUND(m->w.width * m->mfact) : 0;
else
mw = m->w.width;
i = my = ty = 0;
@@ 2574,6 2708,16 @@ togglefullscreen(const Arg *arg)
}
void
+togglesticky(const Arg *arg)
+{
+ Client *c = focustop(selmon);
+ if(!c)
+ return;
+
+ setsticky(c, !c->issticky);
+}
+
+void
toggletag(const Arg *arg)
{
Monitor *m;
@@ 2632,7 2776,7 @@ unmaplayersurfacenotify(struct wl_listener *listener, void *data)
arrangelayers(l->mon);
if (l->layer_surface->surface == seat->keyboard_state.focused_surface)
focusclient(focustop(selmon), 1);
- motionnotify(0);
+ motionnotify(0, NULL, 0, 0, 0, 0);
}
void
@@ 2658,7 2802,7 @@ unmapnotify(struct wl_listener *listener, void *data)
wlr_scene_node_destroy(&c->scene->node);
printstatus();
- motionnotify(0);
+ motionnotify(0, NULL, 0, 0, 0, 0);
}
void
@@ 2838,6 2982,17 @@ virtualkeyboard(struct wl_listener *listener, void *data)
wlr_keyboard_group_add_keyboard(vkb_group.wlr_group, &keyboard->keyboard);
}
+void
+virtualpointer(struct wl_listener *listener, void *data)
+{
+ struct wlr_virtual_pointer_v1_new_pointer_event *event = data;
+ struct wlr_pointer pointer = event->new_pointer->pointer;
+
+ wlr_cursor_attach_input_device(cursor, &pointer.base);
+ if (event->suggested_output)
+ wlr_cursor_map_input_to_output(cursor, &pointer.base, event->suggested_output);
+}
+
Monitor *
xytomon(double x, double y)
{
@@ 2934,11 3089,15 @@ configurex11(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, configure);
struct wlr_xwayland_surface_configure_event *event = data;
- if (!c->mon)
+ /* TODO: figure out if there is another way to do this */
+ if (!c->mon) {
+ wlr_xwayland_surface_configure(c->surface.xwayland,
+ event->x, event->y, event->width, event->height);
return;
+ }
if (c->isfloating || client_is_unmanaged(c))
resize(c, (struct wlr_box){.x = event->x, .y = event->y,
- .width = event->width, .height = event->height}, 0);
+ .width = event->width + c->bw * 2, .height = event->height + c->bw * 2}, 0);
else
arrange(c->mon);
}