]> git.decadent.org.uk Git - ion3.git/blob - ioncore/selection.c
1e99ed91924ce696a7c574d74368c4208e015a00
[ion3.git] / ioncore / selection.c
1 /*
2  * ion/ioncore/selection.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2008. 
5  *
6  * See the included file LICENSE for details.
7  */
8
9 #include <X11/Xmd.h>
10 #include <string.h>
11
12 #include "common.h"
13 #include "global.h"
14 #include "property.h"
15 #include "xwindow.h"
16 #include <libextl/extl.h>
17
18
19 static char *selection_data=NULL;
20 static int selection_length;
21 static bool continuation_set=FALSE;
22 static ExtlFn continuation;
23
24 #define CLIPATOM(X) XA_PRIMARY
25
26 static Atom XA_COMPOUND_TEXT(Display *unused)
27 {
28     static Atom a=None;
29     
30     if(a==None)
31         a=XInternAtom(ioncore_g.dpy, "COMPOUND_TEXT", False);
32         
33     return a;
34 }
35
36
37 void ioncore_handle_selection_request(XSelectionRequestEvent *ev)
38 {
39     XSelectionEvent sev;
40     XTextProperty prop;
41     const char *p[1];
42     bool ok=FALSE;
43     
44     sev.property=None;
45     
46     if(selection_data==NULL || ev->property==None)
47         goto refuse;
48     
49     p[0]=selection_data;
50     
51     if(!ioncore_g.use_mb && ev->target==XA_STRING){
52         Status st=XStringListToTextProperty((char **)p, 1, &prop);
53         ok=(st!=0);
54     }else if(ioncore_g.use_mb){
55         XICCEncodingStyle style;
56         
57         if(ev->target==XA_STRING){
58             style=XStringStyle;
59             ok=TRUE;
60         }else if(ev->target==XA_COMPOUND_TEXT(ioncore_g.dpy)){
61             style=XCompoundTextStyle;
62             ok=TRUE;
63         }
64         
65         if(ok){
66             int st=XmbTextListToTextProperty(ioncore_g.dpy, (char **)p, 1,
67                                              style, &prop);
68             ok=(st>=0);
69         }
70     }
71     
72     if(ok){
73         XSetTextProperty(ioncore_g.dpy, ev->requestor, &prop, ev->property);
74         sev.property=ev->property;
75         XFree(prop.value);
76     }
77
78 refuse:    
79     sev.type=SelectionNotify;
80     sev.requestor=ev->requestor;
81     sev.selection=ev->selection;
82     sev.target=ev->target;
83     sev.time=ev->time;
84     XSendEvent(ioncore_g.dpy, ev->requestor, False, 0L, (XEvent*)&sev);
85 }
86
87
88 static void ins(Window win, const char *str, int n)
89 {
90     if(!continuation_set){
91         WWindow *wwin=XWINDOW_REGION_OF_T(win, WWindow);
92         if(wwin)
93             window_insstr(wwin, str, n);
94     }else{
95         char *tmp=scopyn(str, n);
96         if(tmp!=NULL){
97             extl_call(continuation, "s", NULL, tmp);
98             free(tmp);
99         }
100     }
101 }
102
103     
104 static void insert_selection(Window win, Atom prop)
105 {
106     char **p=xwindow_get_text_property(win, prop, NULL);
107     if(p!=NULL){
108         ins(win, p[0], strlen(p[0]));
109         XFreeStringList(p);
110     }
111 }
112
113
114 void ioncore_handle_selection(XSelectionEvent *ev)
115 {
116     Atom prop=ev->property;
117     Window win=ev->requestor;
118     WWindow *wwin;
119     
120     if(prop!=None){
121         insert_selection(win, prop);
122         XDeleteProperty(ioncore_g.dpy, win, prop);
123     }
124     
125     if(continuation_set){
126         extl_unref_fn(continuation);
127         continuation_set=FALSE;
128     }
129 }
130
131
132 void ioncore_clear_selection()
133 {
134     if(selection_data!=NULL){
135         free(selection_data);
136         selection_data=NULL;
137     }
138 }
139
140
141 void ioncore_set_selection_n(const char *p, int n)
142 {
143     if(selection_data!=NULL)
144         free(selection_data);
145     
146     selection_data=ALLOC_N(char, n+1);
147     
148     if(selection_data==NULL)
149         return;
150     
151     memcpy(selection_data, p, n);
152     selection_data[n]='\0';
153     selection_length=n;
154     
155     XSetSelectionOwner(ioncore_g.dpy, CLIPATOM(ioncore_g.dpy),
156                        DefaultRootWindow(ioncore_g.dpy),
157                        CurrentTime);
158 }
159
160
161 /*EXTL_DOC
162  * Set primary selection and cutbuffer0 to \var{p}.
163  */
164 EXTL_EXPORT
165 void ioncore_set_selection(const char *p)
166 {
167     if(p==NULL)
168         ioncore_clear_selection();
169     else
170         ioncore_set_selection_n(p, strlen(p));
171 }
172
173
174 void ioncore_request_selection_for(Window win)
175 {
176     Atom a=XA_STRING;
177     
178     if(continuation_set){
179         extl_unref_fn(continuation);
180         continuation_set=FALSE;
181     }
182     
183     if(ioncore_g.use_mb)
184         a=XA_COMPOUND_TEXT(ioncore_g.dpy);
185     
186     XConvertSelection(ioncore_g.dpy, CLIPATOM(ioncore_g.dpy), a,
187                       ioncore_g.atom_selection, win, CurrentTime);
188 }
189
190
191 /*EXTL_DOC
192  * Request (string) selection. The function \var{fn} will be called 
193  * with the selection when and if it is received.
194  */
195 EXTL_EXPORT
196 void ioncore_request_selection(ExtlFn fn)
197 {
198     assert(ioncore_g.rootwins!=NULL);
199     ioncore_request_selection_for(ioncore_g.rootwins->dummy_win);
200     continuation=extl_ref_fn(fn);
201     continuation_set=TRUE;
202 }
203