forked from 12to11/12to11
Implement primary selections, and minor improvements elsewhere
* 12to11.c (XLMain): Initialize primary selections. Transfer between X and Wayland programs is still incomplete. * Imakefile (SRCS, OBJS): Add primary selection related objects and sources. (primary-selection-unstable-v1.h): (primary-selection-unstable-v1.c): New targets. * README: Update what is not supported. * compositor.h: New prototypes. * data_device.c (XLDataDeviceSendEnter): Handle resource allocation failures. * mime1.awk: Update generated code for changes in target entry structures. * seat.c (SetFocusSurface): Handle focus change for primary selections as well. (FindSurfaceUnder): Cut off fractional portion instead of rounding the given coordinates, so the correct surface is found when the cursor is moved just inside the rightmost pixel. * surface.c (XLSurfaceRunFrameCallbacks): Handle timestamp overflow. * xdata.c (struct _TargetMapping): Rename atom to atom_flag, and use it to store flags. (MappingAtom, MappingFlag, MappingIsNextDuplicate, MappingSetFlag) (MappingUnsetFlag, MappingIs): New macros. (struct _TargetMappingTable): New structure. (Duplicate): New definition. (direct_transfer): Update duplicate types. (mapping_table): New hash table. (HashMimeString, SetupMappingTable): New functions. (FindTranslationForMimeType, Receive): Use the target mapping table to look up targets instead. (CheckDuplicate): New function. (SendOffers): Call CheckDuplicates. (XLInitXData): Set up duplicate relationship between UTF8_STRING and is conversion entry, and the targets mapping table.
This commit is contained in:
parent
0965f5b3eb
commit
6c7801f0fd
9 changed files with 219 additions and 31 deletions
1
12to11.c
1
12to11.c
|
@ -155,6 +155,7 @@ XLMain (int argc, char **argv)
|
|||
XLInitXData ();
|
||||
XLInitXSettings ();
|
||||
XLInitIconSurfaces ();
|
||||
XLInitPrimarySelection ();
|
||||
/* This has to come after the rest of the initialization. */
|
||||
DetermineServerTime ();
|
||||
XLRunCompositor ();
|
||||
|
|
18
Imakefile
18
Imakefile
|
@ -21,14 +21,16 @@ SRCS = 12to11.c run.c alloc.c fns.c output.c compositor.c \
|
|||
positioner.c xdg_wm.c xdg_surface.c xdg_toplevel.c \
|
||||
frame_clock.c xerror.c ewmh.c timer.c subsurface.c seat.c \
|
||||
data_device.c xdg_popup.c linux-dmabuf-unstable-v1.c dmabuf.c \
|
||||
buffer.c select.c xdata.c xsettings.c dnd.c icon_surface.c
|
||||
buffer.c select.c xdata.c xsettings.c dnd.c icon_surface.c \
|
||||
primary-selection-unstable-v1.c primary_selection.c
|
||||
|
||||
OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \
|
||||
xdg-shell.o surface.o region.o shm.o atoms.o subcompositor.o \
|
||||
positioner.o xdg_wm.o xdg_surface.o xdg_toplevel.o \
|
||||
frame_clock.o xerror.o ewmh.o timer.o subsurface.o seat.o \
|
||||
data_device.o xdg_popup.o linux-dmabuf-unstable-v1.o dmabuf.o \
|
||||
buffer.o select.o xdata.o xsettings.o dnd.o icon_surface.o
|
||||
buffer.o select.o xdata.o xsettings.o dnd.o icon_surface.o \
|
||||
primary-selection-unstable-v1.o primary_selection.o
|
||||
|
||||
OPTIMIZE = -O0
|
||||
ANALYZE = -fanalyzer
|
||||
|
@ -53,7 +55,7 @@ CDEBUGFLAGS := -fno-common -Wall -Warith-conversion -Wdate-time \
|
|||
$(ANALYZE)
|
||||
|
||||
short_types.txt: media_types.txt
|
||||
XCOMM remove all data types starting with application/vnd.
|
||||
XCOMM Remove all data types starting with application/vnd.
|
||||
XCOMM no program really uses them in clipboard data, and they
|
||||
XCOMM waste a lot of space on disk.
|
||||
sed '/application\/vnd/d' media_types.txt > $@
|
||||
|
@ -81,9 +83,17 @@ xdg-shell.h: xdg-shell.xml
|
|||
xdg-shell.c: xdg-shell.xml xdg-shell.h
|
||||
$(WAYLAND_SCANNER) private-code $< $@
|
||||
|
||||
primary-selection-unstable-v1.h: primary-selection-unstable-v1.xml
|
||||
$(WAYLAND_SCANNER) server-header $< $@
|
||||
|
||||
primary-selection-unstable-v1.c: primary-selection-unstable-v1.xml \
|
||||
primary-selection-unstable-v1.h
|
||||
$(WAYLAND_SCANNER) private-code $< $@
|
||||
|
||||
cleandir::
|
||||
$(RM) linux-dmabuf-unstable-v1.c linux-dmabuf-unstable-v1.h \
|
||||
xdg-shell.c xdg-shell.h
|
||||
xdg-shell.c xdg-shell.h primary-selection-unstable-v1.c \
|
||||
primary-selection-unstable-v1.h
|
||||
$(RM) transfer_atoms.h short_types.txt
|
||||
|
||||
/* Undefine _BSD_SOURCE and _SVID_SOURCE, since both are deprecated
|
||||
|
|
7
README
7
README
|
@ -42,14 +42,15 @@ complete degree:
|
|||
'wl_seat', version: 7
|
||||
'wl_data_device_manager', version: 3
|
||||
'zwp_linux_dmabuf_v1', version: 4
|
||||
'zwp_primary_selection_device_manager_v1', version: 1
|
||||
|
||||
With the main caveat being that zwp_linux_dmabuf_v1 has no real
|
||||
support for multiple-provider setups (help wanted).
|
||||
|
||||
Primary selections and window decorations are also not supported, even
|
||||
though they fit in nicely with X window management.
|
||||
Window decorations are also not supported, even though they fit in
|
||||
nicely with X window management.
|
||||
|
||||
It would also be nice to have pinch gesture support in wl_pointer.
|
||||
It would also be nice to have pinch gesture support.
|
||||
|
||||
This directory is organized as follows:
|
||||
|
||||
|
|
|
@ -965,6 +965,11 @@ extern void XLInitIconSurfaces (void);
|
|||
extern void XLReleaseIconSurface (IconSurface *);
|
||||
extern Bool XLIsWindowIconSurface (Window);
|
||||
|
||||
/* Defined in primary_selection.c. */
|
||||
|
||||
extern void XLInitPrimarySelection (void);
|
||||
extern void XLPrimarySelectionHandleFocusChange (Seat *);
|
||||
|
||||
/* Utility functions that don't belong in a specific file. */
|
||||
|
||||
#define ArrayElements(arr) (sizeof (arr) / sizeof (arr)[0])
|
||||
|
|
|
@ -1364,6 +1364,11 @@ XLDataDeviceSendEnter (Seat *seat, Surface *surface, double x, double y,
|
|||
/* First, create a data offer corresponding to the data
|
||||
source if it exists. */
|
||||
resource = AddDataOffer (client, source);
|
||||
|
||||
if (!resource)
|
||||
/* Allocation of the resource failed. */
|
||||
goto next;
|
||||
|
||||
offer = wl_resource_get_user_data (resource);
|
||||
offer->dnd_serial = serial;
|
||||
offer->last_action = -1;
|
||||
|
@ -1397,6 +1402,7 @@ XLDataDeviceSendEnter (Seat *seat, Surface *surface, double x, double y,
|
|||
|
||||
}
|
||||
|
||||
next:
|
||||
reference = reference->next;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ BEGIN {
|
|||
match ($0, / ([a-z]+\/[-+.[:alnum:]]+) /, array)
|
||||
name = array[1]
|
||||
gsub (/[[:punct:]]/, "_", name) # Convert to a valid atom name
|
||||
printf " table[%d + start].atom = %s;\\\n", i++, name
|
||||
printf " table[%d + start].atom_flag = %s;\\\n", i++, name
|
||||
}
|
||||
|
||||
END {
|
||||
|
|
13
seat.c
13
seat.c
|
@ -2625,7 +2625,12 @@ SetFocusSurface (Seat *seat, Surface *focus)
|
|||
}
|
||||
|
||||
if (!focus)
|
||||
{
|
||||
/* These changes must be handled even if there is no more focus
|
||||
surface. */
|
||||
XLPrimarySelectionHandleFocusChange (seat);
|
||||
return;
|
||||
}
|
||||
|
||||
seat->focus_surface = focus;
|
||||
seat->focus_destroy_callback
|
||||
|
@ -2633,6 +2638,8 @@ SetFocusSurface (Seat *seat, Surface *focus)
|
|||
|
||||
SendKeyboardEnter (seat, focus);
|
||||
|
||||
XLPrimarySelectionHandleFocusChange (seat);
|
||||
|
||||
if (seat->data_device)
|
||||
XLDataDeviceHandleFocusChange (seat->data_device);
|
||||
}
|
||||
|
@ -2670,8 +2677,10 @@ FindSurfaceUnder (Subcompositor *subcompositor, double x, double y)
|
|||
int x_off, y_off;
|
||||
View *view;
|
||||
|
||||
view = SubcompositorLookupView (subcompositor, lrint (x),
|
||||
lrint (y), &x_off, &y_off);
|
||||
/* Do not round these figures. Instead, cut off the fractional,
|
||||
like the X server does when deciding when to set the cursor. */
|
||||
view = SubcompositorLookupView (subcompositor, x, y,
|
||||
&x_off, &y_off);
|
||||
|
||||
if (view)
|
||||
return ViewGetData (view);
|
||||
|
|
|
@ -1167,7 +1167,13 @@ XLSurfaceRunFrameCallbacks (Surface *surface, struct timespec time)
|
|||
uint32_t ms_time;
|
||||
XLList *list;
|
||||
|
||||
ms_time = time.tv_sec * 1000 + time.tv_nsec / 1000000;
|
||||
/* I don't know what else is reasonable in case of overflow. */
|
||||
|
||||
if (IntMultiplyWrapv (time.tv_sec, 1000, &ms_time))
|
||||
ms_time = UINT32_MAX;
|
||||
else if (IntAddWrapv (ms_time, time.tv_nsec / 1000000,
|
||||
&ms_time))
|
||||
ms_time = UINT32_MAX;
|
||||
|
||||
RunFrameCallbacks (&surface->current_state.frame_callbacks,
|
||||
ms_time);
|
||||
|
|
182
xdata.c
182
xdata.c
|
@ -42,6 +42,7 @@ typedef struct _ConversionTransferInfo ConversionTransferInfo;
|
|||
typedef struct _WriteInfo WriteInfo;
|
||||
typedef struct _ConversionWriteInfo ConversionWriteInfo;
|
||||
typedef struct _DataConversion DataConversion;
|
||||
typedef struct _TargetMappingTable TargetMappingTable;
|
||||
|
||||
struct _ReadTargetsData
|
||||
{
|
||||
|
@ -54,8 +55,12 @@ struct _ReadTargetsData
|
|||
|
||||
struct _TargetMapping
|
||||
{
|
||||
/* The atom of the X target. */
|
||||
Atom atom;
|
||||
/* The atom of the X target. The top 3 bits of an XID are
|
||||
guaranteed to be 0, so the 31st bit is used to store a flag
|
||||
meaning that the next entry is a duplicate of this one, and the
|
||||
30th bit is used to store a flag containing state used by
|
||||
SendOffers. */
|
||||
Atom atom_flag;
|
||||
|
||||
/* The name of the Wayland MIME type. */
|
||||
const char *mime_type;
|
||||
|
@ -64,6 +69,13 @@ struct _TargetMapping
|
|||
void (*translation_func) (Time, Atom, Atom, int);
|
||||
};
|
||||
|
||||
#define MappingAtom(mapping) ((mapping)->atom_flag & 0x1fffffff)
|
||||
#define MappingFlag(mapping) ((mapping)->atom_flag & (1 << 29))
|
||||
#define MappingIsNextDuplicate(mapping) ((mapping)->atom_flag & (1 << 30))
|
||||
#define MappingSetFlag(mapping) ((mapping)->atom_flag |= (1 << 29))
|
||||
#define MappingUnsetFlag(mapping) ((mapping)->atom_flag &= ~(1 << 29))
|
||||
#define MappingIs(mapping, atom) (MappingAtom (mapping) == (atom))
|
||||
|
||||
struct _DataConversion
|
||||
{
|
||||
/* The MIME type of the Wayland offer. */
|
||||
|
@ -179,20 +191,43 @@ struct _ConversionWriteInfo
|
|||
iconv_t cd;
|
||||
};
|
||||
|
||||
struct _TargetMappingTable
|
||||
{
|
||||
/* Array of indices into direct_transfer. */
|
||||
unsigned short *buckets[32];
|
||||
|
||||
/* Number of elements in each array. */
|
||||
unsigned short n_elements[32];
|
||||
|
||||
/* Array of indices into direct_transfer. */
|
||||
unsigned short *atom_buckets[16];
|
||||
|
||||
/* Number of elements in each array. */
|
||||
unsigned short n_atom_elements[16];
|
||||
};
|
||||
|
||||
/* Base event code of the Xfixes extension. */
|
||||
static int fixes_event_base;
|
||||
|
||||
/* This means the next item in the targets mapping table has the same
|
||||
MIME type as this one. */
|
||||
|
||||
#define Duplicate (1U << 30)
|
||||
|
||||
/* Map of targets that can be transferred from X to Wayland clients
|
||||
and vice versa. */
|
||||
static TargetMapping direct_transfer[] =
|
||||
{
|
||||
{ XA_STRING, "text/plain;charset=iso-9889-1" },
|
||||
{ 0, "text/plain;charset=utf-8" },
|
||||
{ Duplicate, "text/plain;charset=utf-8" },
|
||||
{ XA_STRING, "text/plain;charset=utf-8" },
|
||||
/* These mappings are automatically generated. */
|
||||
DirectTransferMappings
|
||||
};
|
||||
|
||||
/* Lookup table for such mappings. */
|
||||
static TargetMappingTable mapping_table;
|
||||
|
||||
/* Map of Wayland offer types to X atoms and data conversion
|
||||
functions. */
|
||||
static DataConversion data_conversions[] =
|
||||
|
@ -244,6 +279,53 @@ Accept (struct wl_client *client, struct wl_resource *resource,
|
|||
/* Nothing has to be done here yet. */
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
HashMimeString (const char *string)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
i = 3323198485ul;
|
||||
for (; *string; ++string)
|
||||
{
|
||||
i ^= *string;
|
||||
i *= 0x5bd1e995;
|
||||
i ^= i >> 15;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static void
|
||||
SetupMappingTable (void)
|
||||
{
|
||||
unsigned int idx, i, nelements;
|
||||
|
||||
/* This is needed for the atoms table, since the atom indices are
|
||||
determined by the X server. */
|
||||
XLAssert (ArrayElements (direct_transfer) <= USHRT_MAX);
|
||||
|
||||
for (i = 0; i < ArrayElements (direct_transfer); ++i)
|
||||
{
|
||||
idx = HashMimeString (direct_transfer[i].mime_type) % 32;
|
||||
|
||||
nelements = ++mapping_table.n_elements[idx];
|
||||
mapping_table.buckets[idx]
|
||||
= XLRealloc (mapping_table.buckets[idx],
|
||||
nelements * sizeof (unsigned short));
|
||||
mapping_table.buckets[idx][nelements - 1] = i;
|
||||
|
||||
/* Now, set up the lookup table indexed by atoms. It is faster
|
||||
to compare atoms than strings, so the table is smaller. */
|
||||
|
||||
idx = MappingAtom (&direct_transfer[i]) % 16;
|
||||
|
||||
nelements = ++mapping_table.n_atom_elements[idx];
|
||||
mapping_table.atom_buckets[idx]
|
||||
= XLRealloc (mapping_table.atom_buckets[idx],
|
||||
nelements * sizeof (unsigned short));
|
||||
mapping_table.atom_buckets[idx][nelements - 1] = i;
|
||||
}
|
||||
}
|
||||
|
||||
static Bool
|
||||
HasSelectionTarget (Atom atom)
|
||||
{
|
||||
|
@ -261,13 +343,18 @@ HasSelectionTarget (Atom atom)
|
|||
static TargetMapping *
|
||||
FindTranslationForMimeType (const char *mime_type)
|
||||
{
|
||||
int i;
|
||||
unsigned short *buckets, i;
|
||||
unsigned int idx;
|
||||
|
||||
for (i = 0; i < ArrayElements (direct_transfer); ++i)
|
||||
idx = HashMimeString (mime_type) % 32;
|
||||
buckets = mapping_table.buckets[idx];
|
||||
|
||||
for (i = 0; i < mapping_table.n_elements[idx]; ++i)
|
||||
{
|
||||
if (!strcmp (direct_transfer[i].mime_type, mime_type)
|
||||
&& HasSelectionTarget (direct_transfer[i].atom))
|
||||
return &direct_transfer[i];
|
||||
if (!strcmp (direct_transfer[buckets[i]].mime_type,
|
||||
mime_type)
|
||||
&& HasSelectionTarget (MappingAtom (&direct_transfer[buckets[i]])))
|
||||
return &direct_transfer[buckets[i]];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -575,11 +662,13 @@ Receive (struct wl_client *client, struct wl_resource *resource,
|
|||
{
|
||||
if (!translation->translation_func)
|
||||
/* If a corresponding target exists, ask to receive it. */
|
||||
PostReceiveDirect (time, CLIPBOARD, translation->atom, fd);
|
||||
PostReceiveDirect (time, CLIPBOARD,
|
||||
MappingAtom (translation), fd);
|
||||
else
|
||||
/* Otherwise, use the translation function. */
|
||||
translation->translation_func (time, CLIPBOARD,
|
||||
translation->atom, fd);
|
||||
MappingAtom (translation),
|
||||
fd);
|
||||
}
|
||||
else
|
||||
close (fd);
|
||||
|
@ -632,10 +721,55 @@ CreateOffer (struct wl_client *client, Time time)
|
|||
return resource;
|
||||
}
|
||||
|
||||
static Bool
|
||||
CheckDuplicate (unsigned short index, Atom a)
|
||||
{
|
||||
TargetMapping *start;
|
||||
|
||||
start = &direct_transfer[index];
|
||||
|
||||
/* If the flag is already set, then this type has already been
|
||||
sent. */
|
||||
if (MappingFlag (start))
|
||||
return False;
|
||||
|
||||
/* Set this entry's duplicate flag. */
|
||||
MappingSetFlag (start);
|
||||
|
||||
/* As long as the next index still refers to a duplicate of this
|
||||
item, set its duplicate flag. */
|
||||
|
||||
while (MappingIsNextDuplicate (start))
|
||||
MappingSetFlag (++start);
|
||||
|
||||
/* Do the same backwards. */
|
||||
|
||||
if (index)
|
||||
{
|
||||
start = &direct_transfer[index - 1];
|
||||
|
||||
while (MappingIsNextDuplicate (start))
|
||||
{
|
||||
MappingSetFlag (start);
|
||||
|
||||
/* If this is now the start of the target mapping table,
|
||||
break. */
|
||||
if (start == direct_transfer)
|
||||
break;
|
||||
|
||||
start--;
|
||||
}
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
static void
|
||||
SendOffers (struct wl_resource *resource, Time time)
|
||||
{
|
||||
int i, j;
|
||||
unsigned int idx;
|
||||
unsigned short *buckets;
|
||||
|
||||
if (time < last_x_selection_change)
|
||||
/* This offer is out of date. */
|
||||
|
@ -644,16 +778,29 @@ SendOffers (struct wl_resource *resource, Time time)
|
|||
for (i = 0; i < num_x_selection_targets; ++i)
|
||||
{
|
||||
/* Offer each type corresponding to this target. */
|
||||
idx = x_selection_targets[i] % 16;
|
||||
|
||||
for (j = 0; j < ArrayElements (direct_transfer); ++j)
|
||||
/* N.B. that duplicates do appear in the atom buckets, which
|
||||
is intentional. */
|
||||
buckets = mapping_table.atom_buckets[idx];
|
||||
|
||||
for (j = 0; j < mapping_table.n_atom_elements[idx]; ++j)
|
||||
{
|
||||
if (direct_transfer[j].atom == x_selection_targets[i])
|
||||
/* If it exists, offer it to the client. TODO: handle
|
||||
duplicates. */
|
||||
if (MappingIs (&direct_transfer[buckets[j]],
|
||||
x_selection_targets[i])
|
||||
&& CheckDuplicate (buckets[j],
|
||||
x_selection_targets[i]))
|
||||
/* If it exists and was not previously offered, offer it
|
||||
to the client. */
|
||||
wl_data_offer_send_offer (resource,
|
||||
direct_transfer[j].mime_type);
|
||||
direct_transfer[buckets[j]].mime_type);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the duplicate flag of each item in the targets table that
|
||||
was touched. */
|
||||
for (i = 0; i < ArrayElements (direct_transfer); ++i)
|
||||
MappingUnsetFlag (&direct_transfer[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1751,10 +1898,13 @@ XLInitXData (void)
|
|||
SelectSelectionInput (CLIPBOARD);
|
||||
|
||||
/* Initialize atoms used in the direct transfer table. */
|
||||
direct_transfer[1].atom = UTF8_STRING;
|
||||
direct_transfer[1].atom_flag = UTF8_STRING | Duplicate;
|
||||
direct_transfer[2].translation_func = PostReceiveConversion;
|
||||
DirectTransferInitializer (direct_transfer, 3);
|
||||
|
||||
/* Set up the direct transfer table. */
|
||||
SetupMappingTable ();
|
||||
|
||||
/* And those used in the data conversions table. */
|
||||
data_conversions[0].atom = UTF8_STRING;
|
||||
data_conversions[0].type = UTF8_STRING;
|
||||
|
|
Loading…
Add table
Reference in a new issue