]> git.decadent.org.uk Git - ion3.git/blob - ioncore/property.c
798dbf5e32cc0ef2746eaa72083dd9ea531636df
[ion3.git] / ioncore / property.c
1 /*
2  * ion/ioncore/property.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2007. 
5  *
6  * Ion is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  */
11
12 #include <X11/Xmd.h>
13 #include <string.h>
14
15 #include "common.h"
16 #include "property.h"
17 #include "global.h"
18
19
20 /*{{{ Primitives */
21
22
23 static ulong xwindow_get_property_(Window win, Atom atom, Atom type, 
24                                    ulong n32expected, bool more, uchar **p,
25                                    int *format)
26 {
27     Atom real_type;
28     ulong n=-1, extra=0;
29     int status;
30     
31     do{
32         status=XGetWindowProperty(ioncore_g.dpy, win, atom, 0L, n32expected, 
33                                   False, type, &real_type, format, &n,
34                                   &extra, p);
35         
36         if(status!=Success || *p==NULL)
37             return -1;
38     
39         if(extra==0 || !more)
40             break;
41         
42         XFree((void*)*p);
43         n32expected+=(extra+4)/4;
44         more=FALSE;
45     }while(1);
46
47     if(n==0){
48         XFree((void*)*p);
49         *p=NULL;
50         return -1;
51     }
52     
53     return n;
54 }
55
56
57 ulong xwindow_get_property(Window win, Atom atom, Atom type, 
58                            ulong n32expected, bool more, uchar **p)
59 {
60     int format=0;
61     return xwindow_get_property_(win, atom, type, n32expected, more, p, 
62                                  &format);
63 }
64
65
66 /*}}}*/
67
68
69 /*{{{ String property stuff */
70
71
72 char *xwindow_get_string_property(Window win, Atom a, int *nret)
73 {
74     char *p;
75     int n;
76     
77     n=xwindow_get_property(win, a, XA_STRING, 64L, TRUE, (uchar**)&p);
78     
79     if(nret!=NULL)
80         *nret=n;
81     
82     return (n<=0 ? NULL : p);
83 }
84
85
86 void xwindow_set_string_property(Window win, Atom a, const char *value)
87 {
88     if(value==NULL){
89         XDeleteProperty(ioncore_g.dpy, win, a);
90     }else{
91         XChangeProperty(ioncore_g.dpy, win, a, XA_STRING,
92                         8, PropModeReplace, (uchar*)value, strlen(value));
93     }
94 }
95
96
97 /*}}}*/
98
99
100 /*{{{ Integer property stuff */
101
102
103 bool xwindow_get_integer_property(Window win, Atom a, int *vret)
104 {
105     long *p=NULL;
106     ulong n;
107     
108     n=xwindow_get_property(win, a, XA_INTEGER, 1L, FALSE, (uchar**)&p);
109     
110     if(n>0 && p!=NULL){
111         *vret=*p;
112         XFree((void*)p);
113         return TRUE;
114     }
115     
116     return FALSE;
117 }
118
119
120 void xwindow_set_integer_property(Window win, Atom a, int value)
121 {
122     CARD32 data[2];
123     
124     data[0]=value;
125     
126     XChangeProperty(ioncore_g.dpy, win, a, XA_INTEGER,
127                     32, PropModeReplace, (uchar*)data, 1);
128 }
129
130
131 /* WM_STATE
132  */
133
134 bool xwindow_get_state_property(Window win, int *state)
135 {
136     CARD32 *p=NULL;
137     
138     if(xwindow_get_property(win, ioncore_g.atom_wm_state, 
139                             ioncore_g.atom_wm_state, 
140                             2L, FALSE, (uchar**)&p)<=0)
141         return FALSE;
142     
143     *state=*p;
144     
145     XFree((void*)p);
146     
147     return TRUE;
148 }
149
150
151 void xwindow_set_state_property(Window win, int state)
152 {
153     CARD32 data[2];
154     
155     data[0]=state;
156     data[1]=None;
157     
158     XChangeProperty(ioncore_g.dpy, win,
159                     ioncore_g.atom_wm_state, ioncore_g.atom_wm_state,
160                     32, PropModeReplace, (uchar*)data, 2);
161 }
162
163
164 /*}}}*/
165
166
167 /*{{{ Text property stuff */
168
169
170 char **xwindow_get_text_property(Window win, Atom a, int *nret)
171 {
172     XTextProperty prop;
173     char **list=NULL;
174     int n=0;
175     Status st=0;
176     
177     st=XGetTextProperty(ioncore_g.dpy, win, &prop, a);
178
179     if(nret)
180         *nret=(!st ? 0 : -1);
181     
182     if(!st)
183         return NULL;
184
185 #ifdef CF_XFREE86_TEXTPROP_BUG_WORKAROUND
186     while(prop.nitems>0){
187         if(prop.value[prop.nitems-1]=='\0')
188             prop.nitems--;
189         else
190             break;
191     }
192 #endif
193
194     if(!ioncore_g.use_mb){
195         st=XTextPropertyToStringList(&prop, &list, &n);
196     }else{
197         st=XmbTextPropertyToTextList(ioncore_g.dpy, &prop, &list, &n);
198         st=!st;
199     }
200
201     XFree(prop.value);
202     
203     if(!st || n==0 || list==NULL)
204         return NULL;
205     
206     if(nret)
207         *nret=n;
208     
209     return list;
210 }
211
212
213 void xwindow_set_text_property(Window win, Atom a, const char **ptr, int n)
214 {
215     XTextProperty prop;
216     Status st;
217
218     if(!ioncore_g.use_mb){
219         st=XStringListToTextProperty((char **)&ptr, n, &prop);
220     }else{
221 #ifdef X_HAVE_UTF8_STRING        
222         st=XmbTextListToTextProperty(ioncore_g.dpy, (char **)ptr, n,
223                                      XUTF8StringStyle, &prop);
224 #else        
225         st=XmbTextListToTextProperty(ioncore_g.dpy, (char **)ptr, n,
226                                      XTextStyle, &prop);
227 #endif        
228         st=!st;
229     }
230     
231     if(!st)
232         return;
233     
234     XSetTextProperty(ioncore_g.dpy, win, &prop, a);
235     XFree(prop.value);
236 }
237
238
239 /*}}}*/
240
241
242 /*{{{ Exports */
243
244
245 /*EXTL_DOC
246  * Create a new atom. See \code{XInternAtom}(3) manual page for details.
247  */
248 EXTL_EXPORT
249 int ioncore_x_intern_atom(const char *name, bool only_if_exists)
250 {
251     return XInternAtom(ioncore_g.dpy, name, only_if_exists);
252 }
253
254
255 /*EXTL_DOC
256  * Get the name of an atom. See \code{XGetAtomName}(3) manual page for 
257  * details.
258  */
259 EXTL_EXPORT
260 char *ioncore_x_get_atom_name(int atom)
261 {
262     return XGetAtomName(ioncore_g.dpy, atom);
263 }
264
265
266 #define CP(TYPE)                                              \
267     {                                                         \
268         TYPE *d=(TYPE*)p;                                     \
269         for(i=0; i<n; i++) extl_table_seti_i(tab, i+1, d[i]); \
270     }
271
272
273 /*EXTL_DOC
274  * Get a property \var{atom} of type \var{atom_type} for window \var{win}. 
275  * The \var{n32expected} parameter indicates the expected number of 32bit
276  * words, and \var{more} indicates whether all or just this amount of data
277  * should be fetched. Each 8, 16 or 32bit element of the property, as
278  * deciphered from \var{atom_type} is a field in the returned table.
279  * See \code{XGetWindowProperty}(3) manual page for more information.
280  */
281 EXTL_SAFE
282 EXTL_EXPORT
283 ExtlTab ioncore_x_get_window_property(int win, int atom, int atom_type,
284                                       int n32expected, bool more)
285 {
286     uchar *p=NULL;
287     ExtlTab tab;
288     int format=0;
289     int i, n;
290     
291     n=xwindow_get_property_(win, atom, atom_type, n32expected, more, &p, 
292                             &format);
293     
294     if(p==NULL)
295         return extl_table_none();
296     
297     if(n<=0 || (format!=8 && format!=16 && format!=32)){
298         free(p);
299         return extl_table_none();
300     }
301     
302     tab=extl_create_table();
303     
304     switch(format){
305     case 8: CP(char); break;
306     case 16: CP(short); break;
307     case 32: CP(long); break;
308     }
309
310     return tab;
311 }
312
313
314 #define GET(TYPE)                                          \
315     {                                                      \
316         TYPE *d=ALLOC_N(TYPE, n);                          \
317         if(d==NULL) return;                                \
318         for(i=0; i<n; i++) {                               \
319             if(!extl_table_geti_i(tab, i+1, &tmp)) return; \
320             d[i]=tmp;                                      \
321         }                                                  \
322         p=(uchar*)d;                                       \
323     }
324
325         
326 static bool get_mode(const char *mode, int *m)
327 {
328     if(strcmp(mode, "replace")==0)
329         *m=PropModeReplace;
330     else if(strcmp(mode, "prepend")==0)
331         *m=PropModePrepend;
332     else if(strcmp(mode, "append")==0)
333         *m=PropModeAppend;
334     else
335         return FALSE;
336     
337     return TRUE;
338 }
339
340
341 /*EXTL_DOC
342  * Modify a window property. The \var{mode} is one of
343  * \code{"replace"}, \code{"prepend"} or \code{"append"}, and format
344  * is either 8, 16 or 32. Also see \fnref{ioncore.x_get_window_property}
345  * and the \code{XChangeProperty}(3) manual page.
346  */
347 EXTL_EXPORT
348 void ioncore_x_change_property(int win, int atom, int atom_type,
349                                int format, const char *mode, ExtlTab tab)
350 {
351     int tmp, m, i, n=extl_table_get_n(tab);
352     uchar *p;
353         
354     if(n<0 || !get_mode(mode, &m)){
355         warn(TR("Invalid arguments."));
356         return;
357     }
358
359     switch(format){
360     case 8: GET(char); break;
361     case 16: GET(short); break;
362     case 32: GET(long); break;
363     default:
364         warn(TR("Invalid arguments."));
365         return;
366     }
367     
368     XChangeProperty(ioncore_g.dpy, win, atom, atom_type, format, m, p, n);
369     
370     free(p);
371 }
372
373
374 /*EXTL_DOC
375  * Delete a window property.
376  */
377 EXTL_EXPORT
378 void ioncore_x_delete_property(int win, int atom)
379 {
380     XDeleteProperty(ioncore_g.dpy, win, atom);
381 }
382
383
384 /*EXTL_DOC
385  * Get a text property for a window (\code{STRING}, \code{COMPOUND_TEXT},
386  * or \code{UTF8_STRING} property converted). The fields in the returned
387  * table (starting from 1) are the null-separated parts of the property.
388  * See the \code{XGetTextProperty}(3) manual page for more information.
389  */
390 EXTL_SAFE
391 EXTL_EXPORT
392 ExtlTab ioncore_x_get_text_property(int win, int atom)
393 {
394     char **list;
395     int i, n;
396     ExtlTab tab=extl_table_none();
397     
398     list=xwindow_get_text_property(win, atom, &n);
399     
400     if(list!=NULL){
401         if(n!=0){
402             tab=extl_create_table();
403             for(i=0; i<n; i++)
404                 extl_table_seti_s(tab, i+1, list[i]);
405         }
406         XFreeStringList(list);
407     }
408     
409     return tab;
410 }
411
412
413 /*EXTL_DOC
414  * Set a text property for a window. The fields of \var{tab} starting from
415  * 1 should be the different null-separated parts of the property.
416  * See the \code{XSetTextProperty}(3) manual page for more information.
417  */
418 EXTL_EXPORT
419 void ioncore_x_set_text_property(int win, int atom, ExtlTab tab)
420 {
421     char **list;
422     int i, n=extl_table_get_n(tab);
423     
424     list=ALLOC_N(char*, n);
425
426     if(list==NULL)
427         return;
428     
429     for(i=0; i<n; i++){
430         list[i]=NULL;
431         extl_table_geti_s(tab, i+1, &(list[i]));
432     }
433     
434     xwindow_set_text_property(win, atom, (const char **)list, n);
435     
436     XFreeStringList(list);
437 }
438
439
440 /*}}}*/
441