Back to index

tetex-bin  3.0
selection.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2004 Stefan Ulrich
00003  * 
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy
00005  * of this software and associated documentation files (the "Software"), to
00006  * deal in the Software without restriction, including without limitation the
00007  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
00008  * sell copies of the Software, and to permit persons to whom the Software is
00009  * furnished to do so, subject to the following conditions:
00010  * 
00011  * The above copyright notice and this permission notice shall be included in
00012  * all copies or substantial portions of the Software.
00013  * 
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
00017  * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
00018  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00020  * OTHER DEALINGS IN THE SOFTWARE.
00021  */
00022 
00023 #include "xdvi-config.h"
00024 #include "xdvi.h"
00025 
00026 #include <string.h>
00027 
00028 #include <X11/Xatom.h>
00029 #include <X11/StringDefs.h>
00030 
00031 #if HAVE_X11_XMU_XMU_H
00032 #include <X11/Xmu/Atoms.h>
00033 #include <X11/Xmu/Xmu.h>
00034 #endif
00035 
00036 #include "events.h"
00037 #include "util.h"
00038 #include "encodings.h"
00039 #include "message-window.h"
00040 #include "selection.h"
00041 #include "statusline.h"
00042 
00043 /*
00044  * Set the current X selection (i.e. the primary selection AKA XA_PRIMARY).
00045  * Most of this is copied from Asente/Converse/Swick: X Window System Toolkit Manual
00046  */
00047 
00048 /* This is file scope since deliver_selection_cb() needs access to it.
00049  * I guess we could also store it in an Atom, but why bother ...
00050  */
00051 static char *m_selection_text = NULL;
00052 static char *m_cvt_selection_text = NULL;
00053 static size_t m_selection_size = 0;
00054 
00055 /* helper routine */
00056 static Atom
00057 fetch_atom(Widget w, const char *name)
00058 {
00059     Atom a;
00060     XrmValue source, dest;
00061 
00062     source.size = strlen(name) + 1;
00063     source.addr = (char *)name;
00064     dest.size = sizeof a;
00065     dest.addr = (caddr_t)&a;
00066 
00067     (void)XtConvertAndStore(w, XtRString, &source, XtRAtom, &dest);
00068     return a;
00069 }
00070 
00071 /* Lose the selection */
00072 static void
00073 lose_selection_cb(Widget w, Atom *selection)
00074 {
00075     UNUSED(w);
00076     UNUSED(selection);
00077     
00078     text_change_region(TEXT_SEL_CLEAR, NULL);
00079 }
00080 
00081 static char *
00082 utf8_to_native_encoding(const char *utf8)
00083 {
00084     static const char *text_encoding = NULL;
00085 
00086     /* convert to user encoding, similar to search-internal.c */
00087     if (text_encoding == NULL) {
00088        text_encoding = get_text_encoding();
00089     }
00090 
00091     if (memicmp(text_encoding, "iso-8859-1", strlen("iso-8859-1")) == 0
00092        || memicmp(text_encoding, "iso8859-1", strlen("iso8859-1")) == 0) {
00093        return str_utf8_to_iso_8859_1(utf8);
00094     }
00095     else if (memicmp(text_encoding, "utf-8", strlen("utf-8")) != 0
00096             && memicmp(text_encoding, "utf8", strlen("utf8")) != 0) {
00097        /* some other encoding */
00098        return iconv_convert_string("utf-8", text_encoding, utf8);
00099     }
00100     /* fallback */
00101     return xstrdup(utf8);
00102 }
00103 
00104 /* Deliver the selection. Only supports XA_STRING. */
00105 static Boolean
00106 deliver_selection_cb(Widget w,
00107                    Atom *selection,
00108                    Atom *target,
00109                    Atom *type,
00110                    XtPointer *value,
00111                    unsigned long *length,
00112                    int *format)
00113 {
00114     Atom targets = fetch_atom(w, "TARGETS");
00115     Atom utf8_string = fetch_atom(w, "UTF8_STRING");
00116     
00117     TRACE_GUI((stderr, "selection target = %lu (%s)", 
00118               *target, XGetAtomName(DISP, *target)));
00119 
00120     if (m_selection_text == NULL) /* paranoia */
00121        return False;
00122     
00123 #if HAVE_X11_XMU_XMU_H
00124     if (*target == targets) {
00125        /* TARGETS handling copied from xclipboard.c */
00126        Atom* targetP;
00127        Atom* std_targets;
00128        unsigned long std_length;
00129        XSelectionRequestEvent* req = XtGetSelectionRequest(w, *selection, (XtRequestId)NULL);
00130 
00131        TRACE_GUI((stderr, "Selection type: targets"));
00132        XmuConvertStandardSelection(w, req->time, selection,
00133                                 target, type, (XPointer*)&std_targets, &std_length, format);
00134        *value = XtMalloc(sizeof(Atom)*(std_length + 2));
00135        targetP = *(Atom**)value;
00136        *length = std_length + 2;
00137        *targetP++ = XA_COMPOUND_TEXT(DISP);
00138        *targetP++ = XA_STRING;
00139        memcpy((char*)targetP, (char*)std_targets, sizeof(Atom)*std_length);
00140        XtFree((char*)std_targets);
00141        *type = XA_ATOM;
00142        *format = sizeof(Atom) * 8;
00143        return True;
00144     }
00145     else
00146 #endif
00147     if (*target == utf8_string) {
00148        TRACE_GUI((stderr, "Selection type: UTF8_STRING"));
00149        *type = *target;
00150        *value = (XtPointer)XtNewString(m_selection_text);
00151        /* *value = (XtPointer)m_selection_text; */
00152        *length = strlen(m_selection_text);
00153        *format = 8;
00154        return True;
00155     }
00156     else if (*target == XA_STRING) {
00157        char *ptr = utf8_to_native_encoding(m_selection_text);
00158        TRACE_GUI((stderr, "Selection type: XA_STRING"));
00159        strncpy(m_cvt_selection_text, ptr, m_selection_size);
00160        m_cvt_selection_text[m_selection_size - 1] = '\0'; /* ensure termination */
00161        free(ptr);
00162        *type = *target;
00163        *value = (XtPointer)XtNewString(m_cvt_selection_text);
00164        /* *value = (XtPointer)m_selection_text; */
00165        *length = strlen(m_cvt_selection_text);
00166        *format = 8;
00167        return True;
00168     }
00169 #if HAVE_X11_XMU_XMU_H
00170     else if (*target == XA_COMPOUND_TEXT(DISP) || *target == XA_TEXT(DISP)) {
00171        const char *cl[1];
00172        char *ptr;
00173        int retval;
00174        
00175        XTextProperty ct;
00176        XICCEncodingStyle style = XStdICCTextStyle;
00177        
00178        TRACE_GUI((stderr, "Selection type: XA_COMPOUND_TEXT"));
00179        ptr = utf8_to_native_encoding(m_selection_text);
00180        strncpy(m_cvt_selection_text, ptr, m_selection_size);
00181        m_cvt_selection_text[m_selection_size - 1] = '\0'; /* ensure termination */
00182        cl[0] = m_cvt_selection_text;
00183        
00184        *type = *target;
00185        retval = XmbTextListToTextProperty(DISP, (char **)cl, 1, style, &ct);
00186 
00187        if (retval == XNoMemory || retval == XLocaleNotSupported || retval == XConverterNotFound) {
00188            statusline_print(STATUS_MEDIUM, "XmbTextListToTextProperty failed: %d", retval);
00189            return False;
00190        }             
00191        
00192        *value = ct.value;
00193        *length = ct.nitems;
00194        *format = 8;
00195        return True;
00196     }
00197 #endif
00198     else {
00199 #if HAVE_X11_XMU_XMU_H
00200        TRACE_GUI((stderr, "Selection type: standard selection"));
00201        if (XmuConvertStandardSelection(w, CurrentTime, selection,
00202                                    target, type, (XPointer *)value, length, format))
00203            return True;
00204        else {
00205 #endif
00206            TRACE_GUI((stderr, "Selection type unsupported: %lu (%s)",
00207                      (unsigned long)*target, XGetAtomName(DISP, *target)));
00208            statusline_print(STATUS_MEDIUM,
00209                           "X client asked for an unsupported selection target type: %lu (%s)",
00210                           (unsigned long)*target, XGetAtomName(DISP, *target));
00211            return False ;
00212 #if HAVE_X11_XMU_XMU_H
00213        }
00214 #endif
00215     }
00216 }
00217 
00218 /* do it */
00219 Boolean
00220 set_selection(const char *text, Widget w)
00221 {
00222     /* caller should make sure that text is never longer than 4 * XMaxRequestSize(DISP) - 32 */
00223     if (m_selection_text == NULL) {
00224        m_selection_size = 4 * XMaxRequestSize(DISP);
00225        m_selection_text = xmalloc(m_selection_size);
00226        m_cvt_selection_text = xmalloc(m_selection_size);
00227     }
00228     strncpy(m_selection_text, text, m_selection_size);
00229     m_selection_text[m_selection_size - 1] = '\0'; /* ensure termination */
00230 
00231     return XtOwnSelection(w, XA_PRIMARY, XtLastTimestampProcessed(XtDisplay(w)),
00232                        deliver_selection_cb,
00233                        lose_selection_cb,
00234                        (XtSelectionDoneProc)NULL);
00235 }
00236 
00237 void
00238 unset_selection(Widget w)
00239 {
00240     XtDisownSelection(w, XA_PRIMARY, XtLastTimestampProcessed(XtDisplay(w)));
00241 }
00242