> Date: Mon, 02 Sep 2024 11:15:40 -0700
> From:  Derek Upham via "Bug reports for GNU Emacs,
>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
> 
> 
> Existing code
> -------------
> 
> We'll have to go into some obscure areas of the GUI selection 
> code.
> Let's start with xselect-convert-to-targets (select.el).
> 
>   (defun xselect-convert-to-targets (selection _type value)
>     ;; Return a vector of atoms, but remove duplicates first.
>     (if (eq selection 'XdndSelection)
>         ;; This isn't required by the XDND protocol, and sure 
>         enough no
>         ;; clients seem to dependent on it, but Emacs implements 
>         the
>         ;; receiver side of the Motif drop protocol by looking at 
>         the
>         ;; initiator selection's TARGETS target (which Motif 
>         provides)
>         ;; instead of the target table on the drag window, so it 
>         seems
>         ;; plausible for other clients to rely on that as well.
>         (apply #'vector (mapcar #'intern x-dnd-targets-list))
>       (apply #'vector
>              (delete-dups
>               `( TIMESTAMP MULTIPLENIL
>                  . ,(delq '_EMACS_INTERNAL
>                           (mapcar (lambda (conv)
>                                     (if (or (not (consp (cdr 
>                                     conv)))
>                                             (funcall (cadr conv) 
>                                             selection
>                                                      (car conv) 
>                                                      value))
>                                         (car conv)
>                                       '_EMACS_INTERNAL))
>                                   selection-converter-alist)))))))
> 
> This function evaluates each converter in 
> selection-converter-alist
> against the selection value, and returns the labels of any 
> converters
> that return non-NIL.  The goal here is to filter out targets that 
> Emacs
> can't vend for the current value.  The converters are responsible 
> for
> noticing and rejecting inputs that they can't support.
> 
> Be aware that the "value" parameter may be a string with text
> properties.  The "gui-set-selection" Info documentation mentions 
> this:
> 
>      If DATA is a string, then its text properties can specify 
>      values
>      used for individual data types.  For example, if DATA has a
>      property named ‘text/uri-list’, then a call to 
>      ‘gui-get-selection’
>      with the data type ‘text/uri-list’ will result in the value 
>      of that
>      property being used instead of DATA itself.
> 
> Now compare the xselect-convert-to-targets function with the code 
> in
> x_get_local_selection (xselect.c, excerpted).
> 
>       CHECK_SYMBOL (target_type);
>       handler_fn = CDR (Fassq (target_type, 
>       Vselection_converter_alist));
> 
>       if (CONSP (handler_fn))
>       handler_fn = XCDR (handler_fn);
> 
>       if (!need_alternate)
>       tem = XCAR (XCDR (local_value));
>       else
>       tem = XCAR (XCDR (XCDR (XCDR (XCDR (local_value)))));
> 
>       if (STRINGP (tem))
>       {
>         local_value = Fget_text_property (make_fixnum (0),
>                                           target_type, tem);
> 
>         if (!NILP (local_value))
>           tem = local_value;
>       }
> 
>       if (!NILP (handler_fn))
>       value = call3 (handler_fn, selection_symbol,
>                      ((local_request
>                        && NILP 
>                        (Vx_treat_local_requests_remotely))
>                       ? Qnil
>                       : target_type),
>                      tem);
>       else
>       value = Qnil;
> 
> The caller (possibly another X client) provides the target, which
> defines the converter to use.  If tem is a string, then we check 
> for a
> property that matches the target type.  If such a property exists, 
> we
> clobber the existing string with the associated property's object. 
> Then
> we call the converter.
> 
> 
> Problem
> -------
> 
> This discrepancy trips up potential HTML support.
> 
> A typical application like Firefox or LibreOffice vends both 
> text/html
> and text/plain content.  Clients will ask for the targets, then 
> ask
> for the text/html value if available, falling back to text/plain. 
> For
> example, we might want to support an italiced "foo", while falling
> back to the underlying word.
> 
>   #("foo" 0 3 (text/html "<i>foo</i>"))
> 
> We want to advertise a text/html target only when our value has a
> text/html property.  We can do that with new 
> "xselect-convert-to-html"
> function in selection-converter-alist.
> 
>   (text/html . xselect-convert-to-html)
> 
> The function returns true if the input is a string with a 
> text/html
> property.  But if the client then *asks* for the text/html, the C 
> code
> will send the same function a plain string “<i>foo</i>” without 
> the
> property.  The function bails out with NIL.  Most clients will 
> then fall
> back and ask for the text/plain target.
> 
> In broad terms, we can’t distinguish between regular text and HTML 
> text
> from first principles.  We need guidance from upstream.  Also note 
> that
> if we write the HTML converter function such that it doesn’t test 
> for
> and require that text/html property, then Emacs will happily vend 
> the
> plain text strings to text/html requesters.
> 
> 
> Possible fixes
> --------------
> 
> The current implementation doesn't nail down the protocol and the 
> data types.
> 
> There are a couple of potential fixes; some are more invasive than 
> others.
> 
> 1. We can define that, if we have a string, then the string is 
> always
>    implicitly a variant type that we pass the converters.  Just 
>    take out
>    the local_value clobbering in the C code.  The HTML converter 
>    and all
>    other converters can then consistently look for and extract 
>    their
>    relevant property from the string.  This is a breaking behavior
>    change, but for already-broken behavior.  And the built-in 
>    converters
>    in select.el don’t seem to care about those properties.
> 
> 2. We can put the properties back in.  Once we extract the 
> property
>    string local_value, copy the properties of the original string 
>    tem
>    into local_value.  Then overwrite tem.  The rule for handlers 
>    is then
>    to *look* for the property, but it can use property’s string or 
>    the
>    underlying string.
> 
> 3. We can declare that callers have to add type tags to the 
> property objects.
> 
>      #("foo" 0 3 (text/html (html . "<i>foo</i>")))
> 
>    Then the converters are responsible for receiving that string 
>    *or*
>    (html . "<i>foo</i>"), depending on which function calls them,
>    handling both inputs.  This is ugly, but it works for a 
>    prototype
>    HTML converter on top of the existing v29.4 code.

Po Lu, any comments?



  • bug#72983:... Bug reports for GNU Emacs, the Swiss army knife of text editors
    • bug#7... Eli Zaretskii
      • b... Bug reports for GNU Emacs, the Swiss army knife of text editors

Reply via email to