]> git.decadent.org.uk Git - ion3.git/blob - ioncore/selection.c
[svn-upgrade] Integrating new upstream version, ion3 (20070608)
[ion3.git] / ioncore / selection.c
1 /*
2  * ion/ioncore/selection.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2007. 
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     sev.target=None;
46     
47     if(selection_data==NULL || ev->property==None)
48         goto refuse;
49     
50     p[0]=selection_data;
51     
52     if(!ioncore_g.use_mb && ev->target==XA_STRING){
53         Status st=XStringListToTextProperty((char **)&p, 1, &prop);
54         ok=st;
55     }else if(ioncore_g.use_mb){
56         XICCEncodingStyle style;
57         
58         if(ev->target==XA_STRING){
59             style=XStringStyle;
60             ok=TRUE;
61         }else if(ev->target==XA_COMPOUND_TEXT(ioncore_g.dpy)){
62             style=XCompoundTextStyle;
63             ok=TRUE;
64         }
65         
66         if(ok){
67             Status st=XmbTextListToTextProperty(ioncore_g.dpy, (char **)p, 1,
68                                                 style, &prop);
69             ok=!st;
70         }
71     }
72     
73     if(ok){
74         XSetTextProperty(ioncore_g.dpy, ev->requestor, &prop, ev->property);
75         sev.target=prop.encoding;
76         sev.property=ev->property;
77         XFree(prop.value);
78     }
79
80 refuse:    
81     sev.type=SelectionNotify;
82     sev.requestor=ev->requestor;
83     sev.selection=ev->selection;
84     sev.time=ev->time;
85     XSendEvent(ioncore_g.dpy, ev->requestor, False, 0L, (XEvent*)&sev);
86 }
87
88
89 static void ins(Window win, const char *str, int n)
90 {
91     if(!continuation_set){
92         WWindow *wwin=XWINDOW_REGION_OF_T(win, WWindow);
93         if(wwin)
94             window_insstr(wwin, str, n);
95     }else{
96         char *tmp=scopyn(str, n);
97         if(tmp!=NULL){
98             extl_call(continuation, "s", NULL, tmp);
99             free(tmp);
100         }
101     }
102 }
103
104     
105 static void insert_selection(Window win, Atom prop)
106 {
107     char **p=xwindow_get_text_property(win, prop, NULL);
108     if(p!=NULL){
109         ins(win, p[0], strlen(p[0]));
110         XFreeStringList(p);
111     }
112 }
113
114
115 static void insert_cutbuffer(Window win)
116 {
117     char *p;
118     int n;
119     
120     p=XFetchBytes(ioncore_g.dpy, &n);
121     
122     if(n<=0 || p==NULL)
123         return;
124     
125     ins(win, p, n);
126 }
127
128
129 void ioncore_handle_selection(XSelectionEvent *ev)
130 {
131     Atom prop=ev->property;
132     Window win=ev->requestor;
133     WWindow *wwin;
134     
135     if(prop==None){
136         insert_cutbuffer(win);
137     }else{
138         insert_selection(win, prop);
139         XDeleteProperty(ioncore_g.dpy, win, prop);
140     }
141     
142     if(continuation_set){
143         extl_unref_fn(continuation);
144         continuation_set=FALSE;
145     }
146 }
147
148
149 void ioncore_clear_selection()
150 {
151     if(selection_data!=NULL){
152         free(selection_data);
153         selection_data=NULL;
154     }
155 }
156
157
158 void ioncore_set_selection_n(const char *p, int n)
159 {
160     if(selection_data!=NULL)
161         free(selection_data);
162     
163     selection_data=ALLOC_N(char, n+1);
164     
165     if(selection_data==NULL)
166         return;
167     
168     memcpy(selection_data, p, n);
169     selection_data[n]='\0';
170     selection_length=n;
171     
172     XStoreBytes(ioncore_g.dpy, p, n);
173     
174     XSetSelectionOwner(ioncore_g.dpy, CLIPATOM(ioncore_g.dpy),
175                        DefaultRootWindow(ioncore_g.dpy),
176                        CurrentTime);
177 }
178
179
180 /*EXTL_DOC
181  * Set primary selection and cutbuffer0 to \var{p}.
182  */
183 EXTL_EXPORT
184 void ioncore_set_selection(const char *p)
185 {
186     if(p==NULL)
187         ioncore_clear_selection();
188     else
189         ioncore_set_selection_n(p, strlen(p));
190 }
191
192
193 void ioncore_request_selection_for(Window win)
194 {
195     Atom a=XA_STRING;
196     
197     if(continuation_set){
198         extl_unref_fn(continuation);
199         continuation_set=FALSE;
200     }
201     
202     if(ioncore_g.use_mb)
203         a=XA_COMPOUND_TEXT(ioncore_g.dpy);
204     
205     XConvertSelection(ioncore_g.dpy, CLIPATOM(ioncore_g.dpy), a,
206                       ioncore_g.atom_selection, win, CurrentTime);
207 }
208
209
210 /*EXTL_DOC
211  * Request (string) selection. The function \var{fn} will be called 
212  * with the selection when and if it is received.
213  */
214 EXTL_EXPORT
215 void ioncore_request_selection(ExtlFn fn)
216 {
217     assert(ioncore_g.rootwins!=NULL);
218     ioncore_request_selection_for(ioncore_g.rootwins->dummy_win);
219     continuation=extl_ref_fn(fn);
220     continuation_set=TRUE;
221 }
222