diff --git a/12to11.c b/12to11.c index e9b38ce..3b19f2f 100644 --- a/12to11.c +++ b/12to11.c @@ -235,6 +235,7 @@ XLMain (int argc, char **argv) XLInitSinglePixelBuffer (); XLInitDrmLease (); XLInitPointerConstraints (); + XLInitRelativePointer (); /* This has to come after the rest of the initialization. */ DetermineServerTime (); diff --git a/12to11.man b/12to11.man index b3758f3..2da1b11 100644 --- a/12to11.man +++ b/12to11.man @@ -202,6 +202,7 @@ zxdg_decoration_manager_v1 1 zwp_text_input_manager_v3 1 wp_single_pixel_buffer_manager_v1 1 zwp_pointer_constraints_v1 1 +zwp_relative_pointer_manager 1 .TE .PP When the protocol translator is built with EGL support, the following @@ -235,11 +236,6 @@ size. Setting the .B APPLY_STATE_WORKAROUND environment variable may help. .PP -Mozilla Firefox also does not work correctly. Resizing the Firefox -window leads to screen tearing, and Firefox often resizes its toplevel -windows outside their normal boundaries, causing invalid screen -contents to be displayed over other applications. -.PP Using this protocol translator under a window manager that does not at least support the .B _NET_WM_SYNC_REQUEST diff --git a/Imakefile b/Imakefile index a9079d4..4c79140 100644 --- a/Imakefile +++ b/Imakefile @@ -24,7 +24,7 @@ SRCS = 12to11.c run.c alloc.c fns.c output.c compositor.c \ picture_renderer.c explicit_synchronization.c transform.c \ wp_viewporter.c decoration.c text_input.c \ single_pixel_buffer.c drm_lease.c pointer_constraints.c \ - time.c + time.c relative_pointer.c OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \ surface.o region.o shm.o atoms.o subcompositor.o positioner.o \ @@ -35,7 +35,7 @@ OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \ picture_renderer.o explicit_synchronization.o transform.o \ wp_viewporter.o decoration.o text_input.o \ single_pixel_buffer.o drm_lease.o pointer_constraints.o \ - time.o + time.o relative_pointer.o GENHEADERS = transfer_atoms.h @@ -120,6 +120,7 @@ ScannerTarget(text-input-unstable-v3) ScannerTarget(single-pixel-buffer-v1) ScannerTarget(drm-lease-v1) ScannerTarget(pointer-constraints-unstable-v1) +ScannerTarget(relative-pointer-unstable-v1) /* Make OBJS depend on scanner headers, and depend on both them and SRCS. */ $(OBJS): $(GENHEADERS) diff --git a/README b/README index f6385d4..cfa9c28 100644 --- a/README +++ b/README @@ -66,6 +66,7 @@ complete degree: 'zwp_text_input_manager_v3', version: 1 'wp_single_pixel_buffer_manager_v1', version: 1 'zwp_pointer_constraints_v1', version: 1 + 'zwp_relative_pointer_manager_v1', version: 1 When built with EGL, the following Wayland protocol is also supported: diff --git a/compositor.h b/compositor.h index e60888b..974f185 100644 --- a/compositor.h +++ b/compositor.h @@ -90,6 +90,7 @@ struct _Compositor typedef struct _Seat Seat; typedef struct _Pointer Pointer; +typedef struct _RelativePointer RelativePointer; /* Forward declarations from primary_selection.c. */ @@ -1444,6 +1445,8 @@ extern void XLSeatGetMouseData (Seat *, Surface **, double *, double *, double *, double *); extern void XLSeatLockPointer (Seat *); extern void XLSeatUnlockPointer (Seat *); +extern RelativePointer *XLSeatGetRelativePointer (Seat *, struct wl_resource *); +extern void XLSeatDestroyRelativePointer (RelativePointer *); extern Cursor InitDefaultCursor (void); @@ -1611,6 +1614,12 @@ extern void XLPointerConstraintsSurfaceMovedTo (Surface *, int, int); extern void XLPointerConstraintsSubsurfaceMoved (Surface *); extern void XLPointerConstraintsReconfineSurface (Surface *); +/* Defined in relative_pointer.c. */ + +extern void XLInitRelativePointer (void); +extern void XLRelativePointerSendRelativeMotion (struct wl_resource *, + uint64_t, double, double); + /* Utility functions that don't belong in a specific file. */ #define ArrayElements(arr) (sizeof (arr) / sizeof (arr)[0]) diff --git a/pointer_constraints.c b/pointer_constraints.c index 5bc5157..ea20b51 100644 --- a/pointer_constraints.c +++ b/pointer_constraints.c @@ -905,7 +905,8 @@ HandleResourceDestroy (struct wl_resource *resource) confinement->surface = NULL; /* Remove the commit callback. */ - XLSurfaceCancelCommitCallback (confinement->commit_callback); + if (confinement->commit_callback) + XLSurfaceCancelCommitCallback (confinement->commit_callback); confinement->commit_callback = NULL; } @@ -961,7 +962,8 @@ HandleSeatDestroyed (void *data) confinement->surface = NULL; /* Cancel the commit callback. */ - XLSurfaceCancelCommitCallback (confinement->commit_callback); + if (confinement->commit_callback) + XLSurfaceCancelCommitCallback (confinement->commit_callback); confinement->commit_callback = NULL; } diff --git a/seat.c b/seat.c index be14fd1..279e584 100644 --- a/seat.c +++ b/seat.c @@ -88,6 +88,7 @@ enum IsDropped = (1 << 4), IsTextInputSeat = (1 << 5), IsPointerLocked = (1 << 6), + IsSurfaceCoordSet = (1 << 7), }; enum @@ -105,6 +106,7 @@ typedef struct _Seat Seat; typedef struct _SeatClientInfo SeatClientInfo; typedef struct _Pointer Pointer; typedef struct _Keyboard Keyboard; +typedef struct _RelativePointer RelativePointer; typedef struct _SeatCursor SeatCursor; typedef struct _ResizeDoneCallback ResizeDoneCallback; typedef struct _ScrollValuator ScrollValuator; @@ -288,7 +290,7 @@ struct _Pointer struct _Keyboard { - /* The keyboard this pointer object refers to. */ + /* The seat this keyboard object refers to. */ Seat *seat; /* The struct wl_resource associated with this keyboard. */ @@ -302,25 +304,45 @@ struct _Keyboard Keyboard *next, *next1, *last, *last1; }; +struct _RelativePointer +{ + /* The seat this relative pointer refers to. */ + Seat *seat; + + /* The struct wl_resource associated with this relative pointer. */ + struct wl_resource *resource; + + /* The seat client info associated with this relative pointer + resource. */ + SeatClientInfo *info; + + /* The next and last relative pointers attached to the seat client + info. */ + RelativePointer *next, *last; +}; + struct _SeatClientInfo { - /* Number of references to this seat client information. */ - int refcount; - /* The next and last structures in the client info chain. */ SeatClientInfo *next, *last; /* The client corresponding to this object. */ struct wl_client *client; - /* List of pointer objects on this seat for this client. */ - Pointer pointers; + /* Number of references to this seat client information. */ + int refcount; /* The serial of the last enter event sent. */ uint32_t last_enter_serial; + /* List of pointer objects on this seat for this client. */ + Pointer pointers; + /* List of keyboard objects on this seat for this client. */ Keyboard keyboards; + + /* List of relative pointers on this seat for this client. */ + RelativePointer relative_pointers; }; struct _ModifierChangeCallback @@ -653,6 +675,8 @@ CreateSeatClientInfo (Seat *seat, struct wl_client *client) info->pointers.last = &info->pointers; info->keyboards.next = &info->keyboards; info->keyboards.last = &info->keyboards; + info->relative_pointers.next = &info->relative_pointers; + info->relative_pointers.last = &info->relative_pointers; } /* Increase the reference count of info. */ @@ -671,6 +695,7 @@ ReleaseSeatClientInfo (SeatClientInfo *info) /* Assert that there are no more keyboards or pointers attached. */ XLAssert (info->keyboards.next == &info->keyboards); XLAssert (info->pointers.next == &info->pointers); + XLAssert (info->relative_pointers.next == &info->relative_pointers); /* Unlink the client info structure if it is still linked. */ if (info->next) @@ -3081,6 +3106,40 @@ SendMotion (Seat *seat, Surface *surface, double x, double y, } } +static void +SendRelativeMotion (Seat *seat, Surface *surface, double dx, double dy, + Time time) +{ + SeatClientInfo *info; + uint64_t microsecond_time; + RelativePointer *relative_pointer; + + /* Unfortunately there is no way to determine whether or not a + valuator specified in a raw event really corresponds to pointer + motion, so we can't get unaccelerated deltas. It may be worth + wiring up raw events for the X.org server, since we do know how + it specifically behaves. */ + + info = ClientInfoForResource (seat, surface->resource); + + if (!info) + return; + + /* Hmm... */ + microsecond_time = time * 1000; + + relative_pointer = info->relative_pointers.next; + while (relative_pointer != &info->relative_pointers) + { + /* Send the relative deltas. */ + XLRelativePointerSendRelativeMotion (relative_pointer->resource, + microsecond_time, dx, dy); + + /* Move to the next relative pointer. */ + relative_pointer = relative_pointer->next; + } +} + static void SendLeave (Seat *seat, Surface *surface) { @@ -3333,6 +3392,9 @@ EnteredSurface (Seat *seat, Surface *surface, Time time, XLSurfaceCancelRunOnFree (seat->last_seen_surface_callback); seat->last_seen_surface = NULL; seat->last_seen_surface_callback = NULL; + + /* Mark the last surface motion coords as no longer set. */ + seat->flags &= ~IsSurfaceCoordSet; } if (surface) @@ -3811,6 +3873,16 @@ DispatchMotion (Subcompositor *subcompositor, XIDeviceEvent *xev) /* Send the motion event. */ SendMotion (seat, dispatch, x, y, xev->time); + /* Send relative motion. Relative motion is handled by + subtracting x and y from seat->last_surface_x and + seat->last_surface_y, unless pointer motion reporting is + locked, in which case XI barrier motion events are used + instead. */ + if (x - seat->last_surface_x != 0.0 + || y - seat->last_surface_y != 0.0) + SendRelativeMotion (seat, dispatch, x - seat->last_surface_x, + y - seat->last_surface_y, xev->time); + /* Check if this motion would cause a pointer constraint to activate. */ CheckPointerBarrier (seat, dispatch, x, y, xev->root_x, @@ -3820,6 +3892,7 @@ DispatchMotion (Subcompositor *subcompositor, XIDeviceEvent *xev) /* Set the last movement location. */ seat->last_surface_x = x; seat->last_surface_y = y; + seat->flags |= IsSurfaceCoordSet; } /* These values are for tracking the output that a cursor is in. */ @@ -4158,6 +4231,27 @@ DispatchKey (XIDeviceEvent *xev) } } +static void +DispatchBarrierHit (XIBarrierEvent *barrier) +{ + Seat *seat; + + seat = XLLookUpAssoc (seats, barrier->deviceid); + + if (!seat) + return; + + /* Report a barrier hit event as relative motion. */ + + if (seat->focus_surface) + SendRelativeMotion (seat, seat->focus_surface, + barrier->dx, barrier->dy, + barrier->time); + + /* Set the last user time. */ + seat->last_user_time = TimestampFromServerTime (barrier->time); +} + static void WriteKeymap (void) { @@ -4614,6 +4708,7 @@ XLGetGEWindowForSeats (XEvent *event) XIFocusInEvent *focusin; XIEnterEvent *enter; XIDeviceEvent *xev; + XIBarrierEvent *barrier; if (event->type == GenericEvent && event->xgeneric.extension == xi2_opcode) @@ -4637,6 +4732,10 @@ XLGetGEWindowForSeats (XEvent *event) case XI_Leave: enter = event->xcookie.data; return enter->event; + + case XI_BarrierHit: + barrier = event->xcookie.data; + return barrier->event; } } @@ -4665,6 +4764,7 @@ XLSelectStandardEvents (Window window) XISetMask (mask.mask, XI_ButtonRelease); XISetMask (mask.mask, XI_KeyPress); XISetMask (mask.mask, XI_KeyRelease); + XISetMask (mask.mask, XI_BarrierHit); XISelectEvents (compositor.display, window, &mask, 1); } @@ -4688,6 +4788,8 @@ XLDispatchGEForSeats (XEvent *event, Surface *surface, else if (event->xgeneric.evtype == XI_KeyPress || event->xgeneric.evtype == XI_KeyRelease) DispatchKey (event->xcookie.data); + else if (event->xgeneric.evtype == XI_BarrierHit) + DispatchBarrierHit (event->xcookie.data); } Cursor @@ -5589,3 +5691,44 @@ XLSeatUnlockPointer (Seat *seat) { seat->flags &= ~IsPointerLocked; } + +RelativePointer * +XLSeatGetRelativePointer (Seat *seat, struct wl_resource *resource) +{ + RelativePointer *relative_pointer; + SeatClientInfo *info; + + /* Create a relative pointer object for the relative pointer + resource RESOURCE. */ + + relative_pointer = XLCalloc (1, sizeof *relative_pointer); + info = CreateSeatClientInfo (seat, wl_resource_get_client (resource)); + + /* Link the relative pointer onto the seat client info. */ + relative_pointer->next = info->relative_pointers.next; + relative_pointer->last = &info->relative_pointers; + info->relative_pointers.next->last = relative_pointer; + info->relative_pointers.next = relative_pointer; + relative_pointer->info = info; + + /* Then, the seat. */ + relative_pointer->seat = seat; + RetainSeat (seat); + + /* Add the resource. */ + relative_pointer->resource = resource; + + return relative_pointer; +} + +void +XLSeatDestroyRelativePointer (RelativePointer *relative_pointer) +{ + relative_pointer->last->next = relative_pointer->next; + relative_pointer->next->last = relative_pointer->last; + + ReleaseSeatClientInfo (relative_pointer->info); + ReleaseSeat (relative_pointer->seat); + + XLFree (relative_pointer); +}