diff --git a/12to11.c b/12to11.c index ed67ff6..e9b38ce 100644 --- a/12to11.c +++ b/12to11.c @@ -34,7 +34,8 @@ static void DetermineServerTime (void) { Time server_time; - struct timespec clock_spec, server_spec, diff; + struct timespec clock_spec; + uint64_t clock_ms, truncated; /* Try to determine if the X server time is the same as the monotonic time. If it is not, certain features such as "active" @@ -42,20 +43,28 @@ DetermineServerTime (void) clock_gettime (CLOCK_MONOTONIC, &clock_spec); server_time = XLGetServerTimeRoundtrip (); - server_spec.tv_sec = server_time / 1000; - server_spec.tv_nsec = ((server_time - server_time / 1000 * 1000) - * 1000000); - diff = TimespecSub (server_spec, clock_spec); + /* Convert the monotonic time to milliseconds. */ - if (TimespecCmp (diff, MakeTimespec (0, 50000000)) <= 0 - || TimespecCmp (diff, MakeTimespec (0, -50000000)) <= 0) + if (IntMultiplyWrapv (clock_spec.tv_sec, 1000, &clock_ms)) + goto overflow; + + if (IntAddWrapv (clock_ms, clock_spec.tv_nsec / 1000000, + &clock_ms)) + goto overflow; + + /* Truncate the time to 32 bits. */ + truncated = clock_ms; + + /* Compare the clock time with the server time. */ + if (llabs ((long long) server_time - (long long) truncated) <= 5) /* Since the difference between the server time and the monotonic - time is less than 50 ms, the server time is the monotonic - time. */ + time is less than 5 ms, the server time is most likely the + monotonic time. */ compositor.server_time_monotonic = True; else { + overflow: compositor.server_time_monotonic = False; fprintf (stderr, "Warning: the X server time does not seem to" " be synchronized with the monotonic time. Multiple" diff --git a/Imakefile b/Imakefile index 8e2fd63..a9079d4 100644 --- a/Imakefile +++ b/Imakefile @@ -23,7 +23,8 @@ SRCS = 12to11.c run.c alloc.c fns.c output.c compositor.c \ icon_surface.c primary_selection.c renderer.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 + single_pixel_buffer.c drm_lease.c pointer_constraints.c \ + time.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 \ @@ -33,7 +34,8 @@ OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \ icon_surface.o primary_selection.o renderer.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 + single_pixel_buffer.o drm_lease.o pointer_constraints.o \ + time.o GENHEADERS = transfer_atoms.h diff --git a/compositor.h b/compositor.h index b4fb687..e60888b 100644 --- a/compositor.h +++ b/compositor.h @@ -103,6 +103,35 @@ typedef struct _ViewportExt ViewportExt; extern Compositor compositor; +/* Defined in time.c. */ + +typedef struct _Timestamp Timestamp; +typedef enum _TimestampDifference TimestampDifference; + +struct _Timestamp +{ + /* Number of server months passed. */ + unsigned int months; + + /* Millisecond time into those months. */ + unsigned int milliseconds; +}; + +enum _TimestampDifference + { + Earlier, + Same, + Later, + }; + +extern Timestamp TimestampFromServerTime (Time); +extern Timestamp TimestampFromClientTime (Time); +extern TimestampDifference CompareTimestamps (Timestamp, Timestamp); +extern TimestampDifference CompareTimeWith (Time, Timestamp); + +#define TimestampIs(a, op, b) (CompareTimestamps ((a), (b)) == (op)) +#define TimeIs(a, op, b) (CompareTimeWith ((a), (b)) == (op)) + /* Defined in renderer.c. */ typedef struct _RenderFuncs RenderFuncs; @@ -1301,12 +1330,16 @@ typedef struct _DataSource DataSource; typedef struct _CreateOfferFuncs CreateOfferFuncs; typedef struct _DndOfferFuncs DndOfferFuncs; -typedef struct wl_resource *(*CreateOfferFunc) (struct wl_client *, Time); -typedef void (*SendDataFunc) (struct wl_resource *, Time); +typedef struct wl_resource *(*CreateOfferFunc) (struct wl_client *, + Timestamp); +typedef void (*SendDataFunc) (struct wl_resource *, Timestamp); struct _CreateOfferFuncs { + /* Function called to create data offers. */ CreateOfferFunc create_offer; + + /* Function called to send data offers. */ SendDataFunc send_offers; }; @@ -1321,8 +1354,8 @@ extern void XLRetainDataDevice (DataDevice *); extern void XLReleaseDataDevice (DataDevice *); extern void XLDataDeviceClearSeat (DataDevice *); extern void XLDataDeviceHandleFocusChange (DataDevice *); -extern void XLSetForeignSelection (Time, CreateOfferFuncs); -extern void XLClearForeignSelection (Time); +extern void XLSetForeignSelection (Timestamp, CreateOfferFuncs); +extern void XLClearForeignSelection (Timestamp); extern int XLDataSourceTargetCount (DataSource *); extern void XLDataSourceGetTargets (DataSource *, Atom *); extern struct wl_resource *XLResourceFromDataSource (DataSource *); @@ -1391,7 +1424,7 @@ extern Bool XLSeatIsInert (Seat *); extern Bool XLSeatIsClientFocused (Seat *, struct wl_client *); extern Surface *XLSeatGetFocus (Seat *); extern void XLSeatShowWindowMenu (Seat *, Surface *, int, int); -extern Time XLSeatGetLastUserTime (Seat *); +extern Timestamp XLSeatGetLastUserTime (Seat *); extern void XLSeatBeginDrag (Seat *, DataSource *, Surface *, Surface *, uint32_t); extern DataSource *XLSeatGetDragDataSource (Seat *); @@ -1507,8 +1540,8 @@ extern Bool XLIsWindowIconSurface (Window); /* Defined in primary_selection.c. */ extern void XLInitPrimarySelection (void); -extern void XLSetForeignPrimary (Time, CreateOfferFuncs); -extern void XLClearForeignPrimary (Time); +extern void XLSetForeignPrimary (Timestamp, CreateOfferFuncs); +extern void XLClearForeignPrimary (Timestamp); extern Bool XLNoteLocalPrimary (Seat *, PDataSource *); extern void XLPrimarySelectionHandleFocusChange (Seat *); extern struct wl_resource *XLResourceFromPDataSource (PDataSource *); diff --git a/data_device.c b/data_device.c index d708b26..469bafc 100644 --- a/data_device.c +++ b/data_device.c @@ -163,7 +163,7 @@ static DataSource foreign_selection_key; static CreateOfferFuncs foreign_selection_functions; /* Time the foreign selection was changed. */ -static Time foreign_selection_time; +static Timestamp foreign_selection_time; /* When it changed. */ static uint32_t last_selection_change_serial; @@ -759,7 +759,7 @@ UpdateSingleReferenceWithForeignOffer (struct wl_client *client, DataDeviceReference *reference) { struct wl_resource *resource; - Time time; + Timestamp time; time = foreign_selection_time; resource = foreign_selection_functions.create_offer (client, time); @@ -1173,11 +1173,11 @@ XLDataDeviceHandleFocusChange (DataDevice *device) } void -XLSetForeignSelection (Time time, CreateOfferFuncs functions) +XLSetForeignSelection (Timestamp time, CreateOfferFuncs functions) { uint32_t serial; - if (time < foreign_selection_time) + if (TimestampIs (time, Earlier, foreign_selection_time)) return; serial = wl_display_next_serial (compositor.wl_display); @@ -1202,9 +1202,9 @@ XLSetForeignSelection (Time time, CreateOfferFuncs functions) } void -XLClearForeignSelection (Time time) +XLClearForeignSelection (Timestamp time) { - if (time < foreign_selection_time) + if (TimestampIs (time, Earlier, foreign_selection_time)) return; if (current_selection_data == &foreign_selection_key) diff --git a/dnd.c b/dnd.c index 7b134b5..1cd3d97 100644 --- a/dnd.c +++ b/dnd.c @@ -2920,6 +2920,7 @@ XLDoDragMotion (Seat *seat, double root_x, double root_y) { Window toplevel, proxy, self; int version, proxy_version; + Timestamp timestamp; if (finish_source || drag_state.flags & PendingDrop) /* A finish is pending. */ @@ -2960,7 +2961,8 @@ XLDoDragMotion (Seat *seat, double root_x, double root_y) /* Try to own XdndSelection with the last user time. */ if (!(drag_state.flags & SelectionSet)) { - drag_state.timestamp = XLSeatGetLastUserTime (seat); + timestamp = XLSeatGetLastUserTime (seat); + drag_state.timestamp = timestamp.milliseconds; if (!XLOwnDragSelection (drag_state.timestamp, XLSeatGetDragDataSource (seat))) diff --git a/picture_renderer.c b/picture_renderer.c index 8ccf3b7..22a4b92 100644 --- a/picture_renderer.c +++ b/picture_renderer.c @@ -673,8 +673,8 @@ InitRenderFuncs (void) || !XPresentQueryVersion (compositor.display, &major, &minor)) { - fprintf (stderr, "the X presentation extension is not supported" - " by this X server"); + fprintf (stderr, "The X presentation extension is not supported" + " by this X server\n"); return False; } diff --git a/primary_selection.c b/primary_selection.c index 466ac49..aee1b0d 100644 --- a/primary_selection.c +++ b/primary_selection.c @@ -101,7 +101,7 @@ static PDataSource foreign_selection_key; static CreateOfferFuncs foreign_selection_functions; /* The time the foreign selection was set. */ -static Time foreign_selection_time; +static Timestamp foreign_selection_time; /* Forward declaration. */ @@ -354,7 +354,7 @@ UpdateSingleReferenceWithForeignOffer (struct wl_client *client, PDataDevice *reference) { struct wl_resource *scratch, *resource; - Time time; + Timestamp time; time = foreign_selection_time; resource = foreign_selection_functions.create_offer (client, time); @@ -721,12 +721,12 @@ HandleBind (struct wl_client *client, void *data, uint32_t version, void -XLSetForeignPrimary (Time time, CreateOfferFuncs functions) +XLSetForeignPrimary (Timestamp time, CreateOfferFuncs functions) { uint32_t serial; struct wl_resource *scratch; - if (time < foreign_selection_time) + if (TimestampIs (time, Earlier, foreign_selection_time)) return; serial = wl_display_next_serial (compositor.wl_display); @@ -754,9 +754,9 @@ XLSetForeignPrimary (Time time, CreateOfferFuncs functions) } void -XLClearForeignPrimary (Time time) +XLClearForeignPrimary (Timestamp time) { - if (time < foreign_selection_time) + if (TimestampIs (time, Earlier, foreign_selection_time)) return; if (primary_selection == &foreign_selection_key) diff --git a/seat.c b/seat.c index c477c4a..be14fd1 100644 --- a/seat.c +++ b/seat.c @@ -337,6 +337,9 @@ struct _ModifierChangeCallback struct _Seat { + /* The last user time. */ + Timestamp last_user_time; + /* wl_global associated with this seat. */ struct wl_global *global; @@ -2367,6 +2370,9 @@ HandleRawKey (XIRawEvent *event) /* This is used for tracking grabs. */ seat->its_depress_time = event->time; + + /* Update the last user time. */ + seat->last_user_time = TimestampFromServerTime (event->time); } static void @@ -3730,6 +3736,9 @@ DispatchMotion (Subcompositor *subcompositor, XIDeviceEvent *xev) seat->its_root_y = xev->root_y; seat->its_press_time = xev->time; + /* Update the last user time. */ + seat->last_user_time = TimestampFromServerTime (xev->time); + actual_dispatch = FindSurfaceUnder (subcompositor, xev->event_x, xev->event_y); @@ -4375,11 +4384,10 @@ IdentifySeat (WhatEdge *edge, uint32_t serial) return NULL; } -static Time +static Timestamp GetLastUserTime (Seat *seat) { - return MAX (seat->its_press_time, - seat->its_depress_time); + return seat->last_user_time; } static Bool @@ -5361,7 +5369,7 @@ XLSeatBeginDrag (Seat *seat, DataSource *data_source, Surface *start_surface, seat->flags &= ~IsDropped; } -Time +Timestamp XLSeatGetLastUserTime (Seat *seat) { return GetLastUserTime (seat); diff --git a/select.c b/select.c index 1f50d86..1268a53 100644 --- a/select.c +++ b/select.c @@ -757,19 +757,23 @@ GetTransferFunction (SelectionOwnerInfo *info, } static WriteTransfer * -FindWriteTransfer (Window requestor, Atom property) +FindWriteTransfer (Window requestor, Atom property, + int ignore_state) { WriteTransfer *transfer; - transfer = write_transfers.next; + transfer = write_transfers.last; while (transfer != &write_transfers) { if (transfer->requestor == requestor - && transfer->property == property) + && transfer->property == property + && (!ignore_state + || ((transfer->state & ignore_state) + != ignore_state))) return transfer; - transfer = transfer->next; + transfer = transfer->last; } return NULL; @@ -1036,12 +1040,12 @@ TransferFinished (WriteTransfer *transfer) transfer if nothing has previously been written. */ || !(transfer->state & IsFlushed)) { + DebugPrint ("Transfer finished, but there is still property data" + " unwritten (offset %td)\n", transfer->offset); + /* There is still property data left to be written. */ FlushTransfer (transfer, True); transfer->state |= IsFinished; - - DebugPrint ("Transfer finished, but there is still property data" - " unwritten\n"); } else /* The transfer is really finished. */ @@ -1107,8 +1111,9 @@ TransferBecameReadable (WriteTransfer *transfer) } else { - DebugPrint ("Transfer complete, bytes read as part of EOF: %td, off: %td\n", - transfer->offset, transfer->size); + DebugPrint ("Transfer complete, bytes read as part of EOF: %td, " + "off: %td size: %td\n", bytes_read, transfer->offset, + transfer->size); transfer->offset += bytes_read; TransferFinished (transfer); @@ -1239,11 +1244,12 @@ ConvertSelectionMultiple (SelectionOwnerInfo *info, XEvent *event, DebugPrint ("Verifying MULTIPLE transfer; target = %lu, property = %lu\n", atoms[i + 0], atoms[i + 1]); - if (FindWriteTransfer (event->xselectionrequest.requestor, atoms[1]) + if (FindWriteTransfer (event->xselectionrequest.requestor, atoms[1], 0) || FindQueuedTransfer (event->xselectionrequest.requestor, atoms[1])) { DebugPrint ("Found ongoing selection transfer with same requestor " - "and property; this MULTIPLE request will have to be queued.\n"); + "and property; this MULTIPLE request will have to be " + "queued.\n"); QueueTransfer (event); @@ -1390,7 +1396,7 @@ static Bool HandleSelectionRequest (XEvent *event) { XEvent notify; - WriteTransfer *transfer; + WriteTransfer *transfer, *existing_transfer; long quantum; SelectionOwnerInfo *info; @@ -1428,8 +1434,51 @@ HandleSelectionRequest (XEvent *event) /* If a selection request with the same property and window already exists, delay this request for later. */ - if (FindWriteTransfer (event->xselectionrequest.requestor, - event->xselectionrequest.property) + existing_transfer + = FindWriteTransfer (event->xselectionrequest.requestor, + event->xselectionrequest.property, + /* Ignore write transfers that are finished + but pending property deletion. If the + existing transfer is finished, but we are + still waiting for property deletion, allow + the new transfer to take place. This is + because some very popular programs ask for + TARGETS, and then ask for STRING with the + same property, but only delete the + property for the first request after the + data for the second request arrives. This + is against the ICCCM, as it says: + + The requestor should set the property + argument to the name of a property that + the owner can use to report the value of + the selection. Requestors should ensure + that the named property does not exist + on the window before issuing the + ConvertSelection request. + + and: + + Once all the data in the selection has + been retrieved (which may require + getting the values of several properties + -- see the section called "Use of + Selection Properties". ), the requestor + should delete the property in the + SelectionNotify request by using a + GetProperty request with the delete + argument set to True. As previously + discussed, the owner has no way of + knowing when the data has been + transferred to the requestor unless the + property is removed. + + Both paragraphs mean that the property + should have been deleted by the time the + second request is made! */ + IsFinished | IsWaitingForDelete); + + if (existing_transfer /* We need to look at the queue too; otherwise, events from the future might be handled out of order, if the original write transfer is gone, but some events are still queued. */ @@ -1549,9 +1598,9 @@ DrainQueuedTransfers (void) /* Then, read from the other side of the queue, and handle everything. */ - item = queued_transfers.last; + item = temp.last; - while (item != &queued_transfers) + while (item != &temp) { last = item; item = item->last; @@ -1601,53 +1650,63 @@ HandleSelectionNotify (XEvent *event) static Bool HandlePropertyDelete (XEvent *event) { - WriteTransfer *transfer; + WriteTransfer *transfer, *last; - transfer = FindWriteTransfer (event->xproperty.window, - event->xproperty.atom); - if (!transfer) - return False; + transfer = write_transfers.last; - DebugPrint ("Handling property deletion for %lu\n", - event->xproperty.atom); + DebugPrint ("Handling property deletion for %lu; window %lu\n", + event->xproperty.atom, event->xproperty.window); - if (transfer->state & IsFinished) + while (transfer != &write_transfers) { - DebugPrint ("Completing transfer\n"); + last = transfer->last; - /* The transfer is now complete; finish it by freeing its data, - and potentially writing zero-length data. */ - FreeTransfer (transfer); - } - else if (transfer->state & IsWaitingForIncr) - { - /* If transfer is waiting for the INCR property to be deleted, mark - it as started, and flush it again to write the first piece of - property data. */ + /* There can be multiple finished transfers with the same + property pending deletion if a client not compliant with the + ICCCM is in use. See the large comment in + HandleSelectionRequest. */ + DebugPrint ("Handling transfer %p\n", event); - DebugPrint ("Starting transfer in response to INCR property deletion\n"); - - transfer->state |= IsStarted; - transfer->state &= ~IsWaitingForIncr; - transfer->state &= ~IsWaitingForDelete; - - /* Flush the transfer again to write the property data. */ - FlushTransfer (transfer, False); - } - else - { - DebugPrint ("Continuing transfer\n"); - - /* Clear IsWaitingForRelease. */ - transfer->state &= ~IsWaitingForDelete; - - if (transfer->state & IsReadable) + if (transfer->state & IsFinished) { - DebugPrint ("Picking read back up from where it was left\n"); + DebugPrint ("Completing transfer\n"); - /* And signal that the transfer is readable again. */ - TransferBecameReadable (transfer); + /* The transfer is now complete; finish it by freeing its + data, and potentially writing zero-length data. */ + FreeTransfer (transfer); } + else if (transfer->state & IsWaitingForIncr) + { + /* If transfer is waiting for the INCR property to be + deleted, mark it as started, and flush it again to write + the first piece of property data. */ + + DebugPrint ("Starting transfer in response to INCR property deletion\n"); + + transfer->state |= IsStarted; + transfer->state &= ~IsWaitingForIncr; + transfer->state &= ~IsWaitingForDelete; + + /* Flush the transfer again to write the property data. */ + FlushTransfer (transfer, False); + } + else + { + DebugPrint ("Continuing transfer\n"); + + /* Clear IsWaitingForRelease. */ + transfer->state &= ~IsWaitingForDelete; + + if (transfer->state & IsReadable) + { + DebugPrint ("Picking read back up from where it was left\n"); + + /* And signal that the transfer is readable again. */ + TransferBecameReadable (transfer); + } + } + + transfer = last; } return True; @@ -1658,6 +1717,22 @@ HandlePropertyNotify (XEvent *event) { ReadTransfer *transfer; + if (event->xproperty.window != DefaultRootWindow (compositor.display)) + /* Xlib selects for PropertyNotifyMask on the root window, which + results in a lot of noise here. */ + DebugPrint ("PropertyNotify event:\n" + "serial:\t%lu\n" + "window:\t%lu\n" + "atom:\t%lu\n" + "time:\t%lu\n" + "state:\t%s\n", + event->xproperty.serial, + event->xproperty.window, + event->xproperty.atom, + event->xproperty.time, + (event->xproperty.state == PropertyNewValue + ? "PropertyNewValue" : "PropertyDelete")); + if (event->xproperty.state != PropertyNewValue) return HandlePropertyDelete (event); diff --git a/xdata.c b/xdata.c index 8040a4c..e18649a 100644 --- a/xdata.c +++ b/xdata.c @@ -245,14 +245,14 @@ static DataConversion data_conversions[] = }; /* The time of the last X selection change. */ -static Time last_x_selection_change; +static Timestamp last_x_selection_change; /* The time ownership was last asserted over CLIPBOARD, and the last time any client did that. */ -static Time last_clipboard_time, last_clipboard_change; +static Timestamp last_clipboard_time, last_clipboard_change; /* The last time ownership over PRIMARY changed. */ -static Time last_primary_time; +static Timestamp last_primary_time; /* The currently supported selection targets. */ static Atom *x_selection_targets; @@ -688,7 +688,7 @@ PostReceiveDirect (Time time, Atom selection, Atom target, int fd) static void PostReceiveConversion (Time, Atom, Atom, int); #define ReceiveBody(selection, primary) \ - Time time; \ + Timestamp time; \ TargetMapping *translation; \ \ DebugPrint ("Receiving %s from X " #selection " \n", \ @@ -696,7 +696,7 @@ static void PostReceiveConversion (Time, Atom, Atom, int); \ /* Cast to intptr_t to silence warnings when the pointer type is \ larger than long. */ \ - time = (Time) (intptr_t) wl_resource_get_user_data (resource); \ + time = *(Timestamp *) wl_resource_get_user_data (resource); \ \ /* Find which selection target corresponds to MIME_TYPE. */ \ translation = FindTranslationForMimeType (mime_type, primary); \ @@ -705,11 +705,11 @@ static void PostReceiveConversion (Time, Atom, Atom, int); { \ if (!translation->translation_func) \ /* If a corresponding target exists, ask to receive it. */ \ - PostReceiveDirect (time, selection, \ + PostReceiveDirect (time.milliseconds, selection, \ MappingAtom (translation), fd); \ else \ /* Otherwise, use the translation function. */ \ - translation->translation_func (time, selection, \ + translation->translation_func (time.milliseconds, selection, \ MappingAtom (translation), \ fd); \ } \ @@ -753,8 +753,29 @@ static const struct wl_data_offer_interface wl_data_offer_impl = .set_actions = SetActions, }; +static void +HandleOfferResourceDestroy (struct wl_resource *resource) +{ + Timestamp *timestamp; + + timestamp = wl_resource_get_user_data (resource); + + XLFree (timestamp); +} + +static Timestamp * +AllocateTimestamp (Timestamp timestamp) +{ + Timestamp *data; + + data = XLMalloc (sizeof *data); + *data = timestamp; + + return data; +} + static struct wl_resource * -CreateOffer (struct wl_client *client, Time time) +CreateOffer (struct wl_client *client, Timestamp time) { struct wl_resource *resource; @@ -768,7 +789,8 @@ CreateOffer (struct wl_client *client, Time time) /* Otherwise, set the user_data to the time of the selection change. */ wl_resource_set_implementation (resource, &wl_data_offer_impl, - (void *) time, NULL); + AllocateTimestamp (time), + HandleOfferResourceDestroy); return resource; } @@ -786,7 +808,7 @@ static struct zwp_primary_selection_offer_v1_interface primary_offer_impl = }; static struct wl_resource * -CreatePrimaryOffer (struct wl_client *client, Time time) +CreatePrimaryOffer (struct wl_client *client, Timestamp time) { struct wl_resource *resource; @@ -800,7 +822,8 @@ CreatePrimaryOffer (struct wl_client *client, Time time) /* Otherwise, set the user_data to the time of the selection change. */ wl_resource_set_implementation (resource, &primary_offer_impl, - (void *) time, NULL); + AllocateTimestamp (time), + HandleOfferResourceDestroy); return resource; } @@ -883,9 +906,9 @@ SendOffers1 (struct wl_resource *resource, int ntargets, Atom *targets, } static void -SendOffers (struct wl_resource *resource, Time time) +SendOffers (struct wl_resource *resource, Timestamp time) { - if (time < last_x_selection_change) + if (TimestampIs (time, Earlier, last_x_selection_change)) /* This offer is out of date. */ return; @@ -894,9 +917,9 @@ SendOffers (struct wl_resource *resource, Time time) } static void -SendPrimaryOffers (struct wl_resource *resource, Time time) +SendPrimaryOffers (struct wl_resource *resource, Timestamp time) { - if (time < last_primary_time) + if (TimestampIs (time, Earlier, last_primary_time)) /* This offer is out of date. */ return; @@ -916,7 +939,7 @@ HandleNewSelection (Time time, Atom selection, Atom *targets, /* The primary selection changed, and now has the given targets. */ - if (time < last_primary_time) + if (TimeIs (time, Earlier, last_primary_time)) { XLFree (targets); return; @@ -926,21 +949,21 @@ HandleNewSelection (Time time, Atom selection, Atom *targets, XLFree (x_primary_targets); x_primary_targets = targets; num_x_primary_targets = ntargets; - last_primary_time = time; + last_primary_time = TimestampFromClientTime (time); /* Add the right functions and set them as the foreign primary selection handler at TIME. */ funcs.create_offer = CreatePrimaryOffer; funcs.send_offers = SendPrimaryOffers; - XLSetForeignPrimary (time, funcs); + XLSetForeignPrimary (last_primary_time, funcs); return; } /* Else, the selection that changed is CLIPBOARD. */ /* Ignore outdated selection changes. */ - if (time < last_x_selection_change) + if (TimeIs (time, Earlier, last_x_selection_change)) { /* We are responsible for deallocating targets. */ XLFree (targets); @@ -953,7 +976,7 @@ HandleNewSelection (Time time, Atom selection, Atom *targets, x_selection_targets = targets; num_x_selection_targets = ntargets; - last_x_selection_change = time; + last_x_selection_change = TimestampFromClientTime (time); /* Add the right functions and set them as the foreign selection handler at TIME. */ @@ -961,7 +984,7 @@ HandleNewSelection (Time time, Atom selection, Atom *targets, funcs.create_offer = CreateOffer; funcs.send_offers = SendOffers; - XLSetForeignSelection (time, funcs); + XLSetForeignSelection (last_x_selection_change, funcs); } static void @@ -1071,13 +1094,13 @@ static void NoticeClipboardCleared (Time time) { /* Ignore outdated events. */ - if (time < last_x_selection_change) + if (TimeIs (time, Earlier, last_x_selection_change)) return; DebugPrint ("CLIPBOARD was cleared at %lu\n", time); - last_x_selection_change = time; - XLClearForeignSelection (time); + last_x_selection_change = TimestampFromServerTime (time); + XLClearForeignSelection (last_x_selection_change); /* Free data that is no longer used. */ XLFree (x_selection_targets); @@ -1089,13 +1112,13 @@ static void NoticePrimaryCleared (Time time) { /* Ignore outdated events. */ - if (time < last_primary_time) + if (TimeIs (time, Earlier, last_primary_time)) return; DebugPrint ("PRIMARY was cleared at %lu\n", time); - last_primary_time = time; - XLClearForeignPrimary (time); + last_primary_time = TimestampFromServerTime (time); + XLClearForeignPrimary (last_primary_time); /* Free data that is no longer used. */ XLFree (x_primary_targets); @@ -1111,14 +1134,16 @@ HandleSelectionNotify (XFixesSelectionNotifyEvent *event) return; if (event->selection == CLIPBOARD - && event->selection_timestamp > last_clipboard_change) + && TimeIs (event->selection_timestamp, Later, last_clipboard_change)) /* This time is used to keep track of whether or not things like disowning the selection were successful. */ - last_clipboard_change = event->selection_timestamp; + last_clipboard_change + = TimestampFromServerTime (event->selection_timestamp); if (event->selection == XA_PRIMARY - && event->selection_timestamp > last_primary_time) - last_primary_time = event->selection_timestamp; + && TimeIs (event->selection_timestamp, Later, last_primary_time)) + last_primary_time + = TimestampFromServerTime (event->selection_timestamp); if (event->owner != None && event->selection == CLIPBOARD) @@ -1957,9 +1982,10 @@ XLNoteSourceDestroyed (DataSource *source) { if (source == selection_data_source) { - DebugPrint ("Disowning CLIPBOARD at %lu (vs. last change %lu)\n" + DebugPrint ("Disowning CLIPBOARD at %u (vs. last change %u)\n" "This is being done in response to the source being destroyed.\n", - last_clipboard_time, last_x_selection_change); + last_clipboard_time.milliseconds, + last_x_selection_change.milliseconds); /* Disown the selection. */ DisownSelection (CLIPBOARD); @@ -2006,15 +2032,15 @@ FindTargetInArray (Atom *targets, int ntargets, Atom atom) macros... */ #define NoteLocalSelectionBody(callback, time_1, time_2, atom, field, foreign, n_foreign) \ - Time time; \ + Timestamp time; \ Atom *targets; \ int ntargets, i, n_data_conversions; \ Bool rc; \ \ if (source == NULL) \ { \ - DebugPrint ("Disowning " #atom " at %lu (vs. last change %lu)\n", \ - time_1, time_2); \ + DebugPrint ("Disowning " #atom " at %u (vs. last change %u)\n", \ + time_1.milliseconds, time_2.milliseconds); \ \ /* Disown the selection. */ \ DisownSelection (atom); \ @@ -2022,18 +2048,19 @@ FindTargetInArray (Atom *targets, int ntargets, Atom atom) \ /* Return whether or not the selection was actually \ disowned. */ \ - return time_1 >= time_2; \ + return TimestampIs (time_1, Later, time_2); \ } \ \ time = XLSeatGetLastUserTime (seat); \ \ - DebugPrint ("Acquiring ownership of " #atom " at %lu\n", time); \ + DebugPrint ("Acquiring ownership of " #atom " at %u\n", time.milliseconds); \ \ - if (!time) \ + if (!time.months && !time.milliseconds) \ /* Nothing has yet happened on the seat. */ \ return False; \ \ - if (time < time_1 || time < time_2) \ + if (TimestampIs (time, Earlier, time_1) \ + || TimestampIs (time, Earlier, time_2)) \ /* TIME is out of date. */ \ return False; \ \ @@ -2081,7 +2108,7 @@ FindTargetInArray (Atom *targets, int ntargets, Atom atom) /* And own the selection. */ \ field = source; \ \ - rc = OwnSelection (time, atom, callback, targets, ntargets); \ + rc = OwnSelection (time.milliseconds, atom, callback, targets, ntargets); \ XLFree (targets); \ return rc \