-
Notifications
You must be signed in to change notification settings - Fork 343
Implement pointer-constraints-unstable-v1 protocol #852
Conversation
Easy test case: https://github.com/Laaas/hello_wayland Also: How would I go about matching on wl_pointer, i.e. get the wl_pointer corresponding to a wlr_cursor? |
Can you add a test client to examples/ instead? |
You cannot, you have to get more creative with it. Where specifically do you need it? |
I need it @ rootston/cursor.c:329. Right now if there are multiple cursors, and the client tries to lock just one of them, both cursors will be locked (if they are both in the region). Preferably, just the cursor that was requested to be locked should be locked. Although I may have misunderstood the whole wl_pointer concept, but as I see it: |
.gitmodules
Outdated
@@ -0,0 +1,3 @@ | |||
[submodule "examples/pointer-constraints-demo-client"] | |||
path = examples/pointer-constraints-demo-client | |||
url = https://github.com/Laaas/hello_wayland.git |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haha, this isn't going to cut it. Look at some of the other example clients, like idle or layer-shell.
rootston/cursor.c
Outdated
@@ -290,18 +294,128 @@ static void roots_cursor_press_button(struct roots_cursor *cursor, | |||
} | |||
} | |||
|
|||
void roots_cursor_handle_motion(struct roots_cursor *cursor, | |||
// TODO: Match on wl_pointer | |||
static void cursor_constrain(struct roots_cursor *roots_cur, void *data, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
80 column limit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the purpose of this function?
rootston/cursor.c
Outdated
// used when there is no specific region in the constraints | ||
struct wlr_box sbox = { | ||
.x = 0, | ||
.y = 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't align things like this (or at all)
rootston/cursor.c
Outdated
wl_list_for_each(view, &desktop->views, link) { | ||
if (view->wlr_surface == wlr_surface) break; | ||
} | ||
if (!view) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
braces are mandatory
} else if (!wlr_box_contains_point(box, sx + deltas[0], sy + deltas[1])) { | ||
deltas[0] = 0, deltas[1] = 0; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be better to have wlr_cursor support taking a constraint - it already supports this via wlr_cursor_map_to_region.
types/wlr_pointer_constraints_v1.c
Outdated
|| | ||
wl_resource_instance_of(resource, &zwp_locked_pointer_v1_interface, | ||
&locked_pointer_impl) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not fond of this indentation here
types/wlr_pointer_constraints_v1.c
Outdated
&b->link != head; | ||
b = tmp, | ||
tmp = wl_container_of(b->link.next, tmp, link) | ||
) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dude just use wl_list_for_each_safe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually can't do that here, since I don't iterate the entire list. wl_list_for_each_safe always iterates the entire list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can break out of a wl_list_for_each (continue too)
types/wlr_pointer_constraints_v1.c
Outdated
struct wl_resource *surface, | ||
struct wl_resource *pointer, | ||
struct wl_resource *region, | ||
uint32_t lifetime) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be done in fewer lines
types/wlr_pointer_constraints_v1.c
Outdated
|
||
static void pointer_constraints_destroy(struct wl_client *client, | ||
struct wl_resource *resource) { | ||
// TODO: Destroy all relevant locked pointers |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need this done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs some work
bc2f669
to
7ccc1d7
Compare
Please review this again |
examples/meson.build
Outdated
threads = dependency('threads') | ||
wayland_cursor = dependency('wayland-cursor') | ||
rt = cc.find_library('rt') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rt is already defined at the top-level meson.build
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I tried removing this but it didn't work without it, saying rt isn't defined.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I was thinking of a different project that already had it at the top-level meson.build. In any case, the top-level meson.build is where this needs to go. We don't resolve dependencies in subprojects.
if (strcmp(interface, interface_wanted.name) == 0) { \ | ||
printf("got %s\n", interface); \ | ||
output = wl_registry_bind(registry, name, &interface_wanted, version); \ | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just because this is an example doesn't mean it's exempt from our style guide
const uint64_t size = 4L * 1024L * 1024L; | ||
int fd = shm_open("pointer-constraints-demo-wlroots", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); | ||
assert(ftruncate(fd, size) == 0); | ||
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size); // 4 MiBs, how many are even needed? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We typically just use EGL surfaces for demos
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you explain how to do that? there's pretty much no tutorials or so for wayland.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just check out some of the other examples, like idle-inhibit.c
wl_surface_commit(surface); | ||
|
||
while (true) { | ||
if (wl_display_dispatch(display) < 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can move this conditional into the loop condition
struct wl_surface *surface = wl_compositor_create_surface(compositor); | ||
wl_surface_attach(surface, buffer, 0, 0); | ||
|
||
struct wl_shell_surface *shell_surface = wl_shell_get_shell_surface(shell, surface); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use xdg-shell
} | ||
|
||
return 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make these the same example with a getopt
flag to control its behavior
include/rootston/cursor.h
Outdated
@@ -14,6 +14,8 @@ struct roots_cursor { | |||
struct roots_seat *seat; | |||
struct wlr_cursor *cursor; | |||
|
|||
struct wlr_box *mapped_box; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mapped
seems weird, not confined
? constrained
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well it's what it's called in wlr_cursor, don't ask me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's the same thing: mapped defines the range of e.g. tablet devices, constrained defines a box outside of which the cursor cannot go? (One is "the whole tablet extends maps to this region", the other is "don't move outside of this box")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did notice this when I was using a touch pad with pointer constraints: my cursor was moving much slower than usual, depending on the size of the constraint.
I don't know whether this is necessarily undesirable, but I leave that up to you guys to decide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the protocol intends constraints, not mappings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bump
include/wlr/types/wlr_box.h
Outdated
@@ -35,4 +36,11 @@ void wlr_box_rotated_bounds(const struct wlr_box *box, float rotation, | |||
|
|||
struct wlr_box wlr_box_from_pixman_box32(const pixman_box32_t box); | |||
|
|||
static const struct wlr_box WLR_BOX_MAX = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this to wlr_box.c
and make this extern
include/wlr/types/wlr_cursor.h
Outdated
@@ -153,6 +153,15 @@ void wlr_cursor_map_to_region(struct wlr_cursor *cur, struct wlr_box *box); | |||
void wlr_cursor_map_input_to_region(struct wlr_cursor *cur, | |||
struct wlr_input_device *dev, struct wlr_box *box); | |||
|
|||
/** | |||
* Locks the cursor to its current position | |||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure wlr_cursor needs to handle this, the compositor can instead just choose to stop processing input events. The cursor does not move itself when input events happen on attached devices, it just fires the signals and the compositor has to do the actual moving.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think having it as a part of the wlr_cursor would be better in the context of relative-pointer, because you still have to process the input from those devices anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that justification makes any sense. wlr_cursor does not move itself in response to input events. The compositor has to explicitly ask it to do so, and can just stop doing so when it wants to be locked. But it can still process input events in that situation...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's true
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is still here?
@@ -4,6 +4,10 @@ | |||
#include <stdint.h> | |||
#include <wayland-server.h> | |||
#include <wlr/types/wlr_box.h> | |||
#include <wlr/types/wlr_seat.h> | |||
|
|||
// needed because of a circular dependency... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But now that you mention it... I wonder if at some point we can find a way to transfer responsibility for its resources away from the seat and into the resources themselves. This isn't a problem unique to your patch.
void* data; | ||
}; | ||
|
||
struct wlr_pointer_constraints_v1 *wlr_pointer_constraints_v1_create(struct wl_display *display); | ||
struct wlr_pointer_constraints_v1_interface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems more appropriate to use wl_signal
here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I could probably do that. It's an interface because I initially had non-void return values.
types/wlr_pointer_constraints_v1.c
Outdated
wl_resource_instance_of(resource, &zwp_locked_pointer_v1_interface, | ||
&locked_pointer_impl) | ||
); | ||
wl_resource_instance_of(resource, &zwp_confined_pointer_v1_interface, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
80 column limit
@laaas Maybe by wrapping a pixman_region inside a wlr_region/box which is aware of rotations (and other transforms)? Or just treating the no-rotation/with-rotation cases separately as you're doing right now. Check out -Wconversion too, but lots of noise; set werror to false. |
I just did a grep for pixman_region32_contains_point, and this implicit conversion of floats to integers is also a problem elsewhere. E.g. in |
…_contains_point I do not think the conversion is specifically defined, but on my system and SirCmpwn's the floats are rounded instead of floored, which is incorrect in this case, since for a range from 0 to 256, any value greater or equal to 0 and less than 256 is valid. I.e. [0;256[, or 0 <= x < 256, but if x is e.g. -0.1, then it will be rounded to 0, which is invalid. The correct behavior would be to floor to -1.
@SirCmpwn it has been fixed. |
Well, sadly, compiling with -Wconversion currently gives all of 672 warnings on master, and 823 on your branch. I did it blind so the numbers may be off a bit, and probably has duplicates, but that's still quite a lot. |
@emersion any objections? |
|
||
struct wlr_pointer_constraints_v1 { | ||
struct wl_list wl_resources; // wl_resource_get_link | ||
struct wl_global *wl_global; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should be named resources
and global
, we renamed those recently
examples/pointer-constraints.c
Outdated
locked_pointer = zwp_pointer_constraints_v1_lock_pointer( | ||
pointer_constraints, surface, pointer, regions[region_type], lifetime); | ||
|
||
zwp_locked_pointer_v1_set_cursor_position_hint(locked_pointer, wl_fixed_from_int(128), wl_fixed_from_int(128)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
80 char limit
examples/pointer-constraints.c
Outdated
|
||
if (lock) { | ||
locked_pointer = zwp_pointer_constraints_v1_lock_pointer( | ||
pointer_constraints, surface, pointer, regions[region_type], lifetime); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
80 char limit
examples/pointer-constraints.c
Outdated
|
||
return EXIT_SUCCESS; | ||
|
||
invalid_args: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style:
- No braces
- Label without indentation
types/wlr_pointer_constraints_v1.c
Outdated
free(constraint->current.region); | ||
} | ||
if (constraint->pending.region && | ||
constraint->current.region != constraint->pending.region) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a use-after-free
* Rename the constraint_create signal to new_constraint for consistency * Move the constraint_destroy signal to the constraint itself * Use rotate_child_position instead of duplicating logic * Fix inert constraint resource handling * Style fixes
rootston/cursor.c
Outdated
dx = sx2_confined - sx1; | ||
dy = sy2_confined - sy1; | ||
} else { | ||
assert(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it isn't working, we should remove this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does work though? Can't see the entire context but I presume that is an assumption derived logically, and not a "unimplemented just fail" assertion. It asserts that that should never happen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, perhaps I forgot to put a FIXME
in there. Seems odd that I've put that there. Good catch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK for me
Follow-up issue: doesn't work yet with rotated views
thanks @SirCmpwn but I could also have done it better. My inexperience was obvious, and there were times where I did not get much work done. |
Is it possible that this PR broke This is what I see in the log:
|
This is seriously awesome to see merged. Thanks a ton @laaas, "could have done it or better" or not, you got it done and it's a huge boost to the project 🎉 |
Fixes #686