~ubuntu-branches/debian/sid/openbox/sid

« back to all changes in this revision

Viewing changes to obt/prop.c

  • Committer: Bazaar Package Importer
  • Author(s): Nico Golde, Nico Golde, Eugenio Paolantonio
  • Date: 2011-10-03 22:59:30 UTC
  • mfrom: (1.1.11 upstream)
  • Revision ID: james.westby@ubuntu.com-20111003225930-tdvyax5tx63dyoez
Tags: 3.5.0-1
[Nico Golde]
* New upstream release (Closes: #638783).
  - Fix crashes in the menu code (Closes: #563891).
* Add Brazilian translation to openbox.desktop,
  thanks Sérgio Cipolla (Closes: #627912).
* Remove 06_fix_swap_byte_order.patch, applied upstream.
* Bump debhelper dependency to >= 7.0.50~ due to override.
* Remove CHANGELOG from openbox.docs to prevent double installation.
* Add 02_fix_freedesktop_compliance.dpatch desktop file to
  /usr/share/applications.

[Eugenio Paolantonio]
* debian/patches:
  - Disabled 03_place_windows_in_quadrants.patch
  - Updated 01_rc.xml.patch and 06_fix_swap_byte_order.patch
  - Removed 04_fix_ftbfs_no-add-needed.patch and 20_24bits_support.patch
* debian/control:
  - Added myself to the Uploaders.
  - Build-Depends: removed libxau-dev, libxft-dev and python-xdg;
    added libimlib2-dev
  - openbox Suggests: added python-xdg
  - libobrender21 renamed to libobrender27
  - libobparser21 renamed to libobt0
* debian/rules:
  - Rewrote using a simpler debhelper syntax
  - Moved the install pass to openbox.install
* debian/*.{install,links,dirs}:
  - Updated.
* debian/openbox.xsession:
  - Removed. Openbox now ships it by default.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
 
2
 
 
3
   obt/prop.c for the Openbox window manager
 
4
   Copyright (c) 2006        Mikael Magnusson
 
5
   Copyright (c) 2003-2007   Dana Jansens
 
6
 
 
7
   This program is free software; you can redistribute it and/or modify
 
8
   it under the terms of the GNU General Public License as published by
 
9
   the Free Software Foundation; either version 2 of the License, or
 
10
   (at your option) any later version.
 
11
 
 
12
   This program is distributed in the hope that it will be useful,
 
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
   GNU General Public License for more details.
 
16
 
 
17
   See the COPYING file for a copy of the GNU General Public License.
 
18
*/
 
19
 
 
20
#include "obt/prop.h"
 
21
#include "obt/display.h"
 
22
 
 
23
#include <X11/Xatom.h>
 
24
#ifdef HAVE_STRING_H
 
25
#  include <string.h>
 
26
#endif
 
27
 
 
28
Atom prop_atoms[OBT_PROP_NUM_ATOMS];
 
29
gboolean prop_started = FALSE;
 
30
 
 
31
#define CREATE_NAME(var, name) (prop_atoms[OBT_PROP_##var] = \
 
32
                                XInternAtom((obt_display), (name), FALSE))
 
33
#define CREATE(var) CREATE_NAME(var, #var)
 
34
#define CREATE_(var) CREATE_NAME(var, "_" #var)
 
35
 
 
36
void obt_prop_startup(void)
 
37
{
 
38
    if (prop_started) return;
 
39
    prop_started = TRUE;
 
40
 
 
41
    g_assert(obt_display);
 
42
 
 
43
    CREATE(CARDINAL);
 
44
    CREATE(WINDOW);
 
45
    CREATE(PIXMAP);
 
46
    CREATE(ATOM);
 
47
    CREATE(STRING);
 
48
    CREATE(COMPOUND_TEXT);
 
49
    CREATE(UTF8_STRING);
 
50
 
 
51
    CREATE(MANAGER);
 
52
 
 
53
    CREATE(WM_COLORMAP_WINDOWS);
 
54
    CREATE(WM_PROTOCOLS);
 
55
    CREATE(WM_STATE);
 
56
    CREATE(WM_CHANGE_STATE);
 
57
    CREATE(WM_DELETE_WINDOW);
 
58
    CREATE(WM_TAKE_FOCUS);
 
59
    CREATE(WM_NAME);
 
60
    CREATE(WM_ICON_NAME);
 
61
    CREATE(WM_CLASS);
 
62
    CREATE(WM_WINDOW_ROLE);
 
63
    CREATE(WM_CLIENT_MACHINE);
 
64
    CREATE(WM_COMMAND);
 
65
    CREATE(WM_CLIENT_LEADER);
 
66
    CREATE(WM_TRANSIENT_FOR);
 
67
    CREATE_(MOTIF_WM_HINTS);
 
68
    CREATE_(MOTIF_WM_INFO);
 
69
 
 
70
    CREATE(SM_CLIENT_ID);
 
71
 
 
72
    CREATE_(NET_WM_FULL_PLACEMENT);
 
73
 
 
74
    CREATE_(NET_SUPPORTED);
 
75
    CREATE_(NET_CLIENT_LIST);
 
76
    CREATE_(NET_CLIENT_LIST_STACKING);
 
77
    CREATE_(NET_NUMBER_OF_DESKTOPS);
 
78
    CREATE_(NET_DESKTOP_GEOMETRY);
 
79
    CREATE_(NET_DESKTOP_VIEWPORT);
 
80
    CREATE_(NET_CURRENT_DESKTOP);
 
81
    CREATE_(NET_DESKTOP_NAMES);
 
82
    CREATE_(NET_ACTIVE_WINDOW);
 
83
/*    CREATE_(NET_RESTACK_WINDOW);*/
 
84
    CREATE_(NET_WORKAREA);
 
85
    CREATE_(NET_SUPPORTING_WM_CHECK);
 
86
    CREATE_(NET_DESKTOP_LAYOUT);
 
87
    CREATE_(NET_SHOWING_DESKTOP);
 
88
 
 
89
    CREATE_(NET_CLOSE_WINDOW);
 
90
    CREATE_(NET_WM_MOVERESIZE);
 
91
    CREATE_(NET_MOVERESIZE_WINDOW);
 
92
    CREATE_(NET_REQUEST_FRAME_EXTENTS);
 
93
    CREATE_(NET_RESTACK_WINDOW);
 
94
 
 
95
    CREATE_(NET_STARTUP_ID);
 
96
 
 
97
    CREATE_(NET_WM_NAME);
 
98
    CREATE_(NET_WM_VISIBLE_NAME);
 
99
    CREATE_(NET_WM_ICON_NAME);
 
100
    CREATE_(NET_WM_VISIBLE_ICON_NAME);
 
101
    CREATE_(NET_WM_DESKTOP);
 
102
    CREATE_(NET_WM_WINDOW_TYPE);
 
103
    CREATE_(NET_WM_STATE);
 
104
    CREATE_(NET_WM_STRUT);
 
105
    CREATE_(NET_WM_STRUT_PARTIAL);
 
106
    CREATE_(NET_WM_ICON);
 
107
    CREATE_(NET_WM_ICON_GEOMETRY);
 
108
    CREATE_(NET_WM_PID);
 
109
    CREATE_(NET_WM_ALLOWED_ACTIONS);
 
110
    CREATE_(NET_WM_USER_TIME);
 
111
/*  CREATE_(NET_WM_USER_TIME_WINDOW); */
 
112
    CREATE_(KDE_NET_WM_FRAME_STRUT);
 
113
    CREATE_(NET_FRAME_EXTENTS);
 
114
 
 
115
    CREATE_(NET_WM_PING);
 
116
#ifdef SYNC
 
117
    CREATE_(NET_WM_SYNC_REQUEST);
 
118
    CREATE_(NET_WM_SYNC_REQUEST_COUNTER);
 
119
#endif
 
120
 
 
121
    CREATE_(NET_WM_WINDOW_TYPE_DESKTOP);
 
122
    CREATE_(NET_WM_WINDOW_TYPE_DOCK);
 
123
    CREATE_(NET_WM_WINDOW_TYPE_TOOLBAR);
 
124
    CREATE_(NET_WM_WINDOW_TYPE_MENU);
 
125
    CREATE_(NET_WM_WINDOW_TYPE_UTILITY);
 
126
    CREATE_(NET_WM_WINDOW_TYPE_SPLASH);
 
127
    CREATE_(NET_WM_WINDOW_TYPE_DIALOG);
 
128
    CREATE_(NET_WM_WINDOW_TYPE_NORMAL);
 
129
    CREATE_(NET_WM_WINDOW_TYPE_POPUP_MENU);
 
130
 
 
131
    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPLEFT] = 0;
 
132
    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOP] = 1;
 
133
    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPRIGHT] = 2;
 
134
    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_RIGHT] = 3;
 
135
    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT] = 4;
 
136
    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOM] = 5;
 
137
    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT] = 6;
 
138
    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_LEFT] = 7;
 
139
    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_MOVE] = 8;
 
140
    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_KEYBOARD] = 9;
 
141
    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_MOVE_KEYBOARD] = 10;
 
142
    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_CANCEL] = 11;
 
143
 
 
144
    CREATE_(NET_WM_ACTION_MOVE);
 
145
    CREATE_(NET_WM_ACTION_RESIZE);
 
146
    CREATE_(NET_WM_ACTION_MINIMIZE);
 
147
    CREATE_(NET_WM_ACTION_SHADE);
 
148
    CREATE_(NET_WM_ACTION_MAXIMIZE_HORZ);
 
149
    CREATE_(NET_WM_ACTION_MAXIMIZE_VERT);
 
150
    CREATE_(NET_WM_ACTION_FULLSCREEN);
 
151
    CREATE_(NET_WM_ACTION_CHANGE_DESKTOP);
 
152
    CREATE_(NET_WM_ACTION_CLOSE);
 
153
    CREATE_(NET_WM_ACTION_ABOVE);
 
154
    CREATE_(NET_WM_ACTION_BELOW);
 
155
 
 
156
    CREATE_(NET_WM_STATE_MODAL);
 
157
/*    CREATE_(NET_WM_STATE_STICKY);*/
 
158
    CREATE_(NET_WM_STATE_MAXIMIZED_VERT);
 
159
    CREATE_(NET_WM_STATE_MAXIMIZED_HORZ);
 
160
    CREATE_(NET_WM_STATE_SHADED);
 
161
    CREATE_(NET_WM_STATE_SKIP_TASKBAR);
 
162
    CREATE_(NET_WM_STATE_SKIP_PAGER);
 
163
    CREATE_(NET_WM_STATE_HIDDEN);
 
164
    CREATE_(NET_WM_STATE_FULLSCREEN);
 
165
    CREATE_(NET_WM_STATE_ABOVE);
 
166
    CREATE_(NET_WM_STATE_BELOW);
 
167
    CREATE_(NET_WM_STATE_DEMANDS_ATTENTION);
 
168
 
 
169
    prop_atoms[OBT_PROP_NET_WM_STATE_ADD] = 1;
 
170
    prop_atoms[OBT_PROP_NET_WM_STATE_REMOVE] = 0;
 
171
    prop_atoms[OBT_PROP_NET_WM_STATE_TOGGLE] = 2;
 
172
 
 
173
    prop_atoms[OBT_PROP_NET_WM_ORIENTATION_HORZ] = 0;
 
174
    prop_atoms[OBT_PROP_NET_WM_ORIENTATION_VERT] = 1;
 
175
    prop_atoms[OBT_PROP_NET_WM_TOPLEFT] = 0;
 
176
    prop_atoms[OBT_PROP_NET_WM_TOPRIGHT] = 1;
 
177
    prop_atoms[OBT_PROP_NET_WM_BOTTOMRIGHT] = 2;
 
178
    prop_atoms[OBT_PROP_NET_WM_BOTTOMLEFT] = 3;
 
179
 
 
180
    CREATE_(KDE_WM_CHANGE_STATE);
 
181
    CREATE_(KDE_NET_WM_WINDOW_TYPE_OVERRIDE);
 
182
 
 
183
/*
 
184
    CREATE_NAME(ROOTPMAPId, "_XROOTPMAP_ID");
 
185
    CREATE_NAME(ESETROOTId, "ESETROOT_PMAP_ID");
 
186
*/
 
187
 
 
188
    CREATE_(OPENBOX_PID);
 
189
    CREATE_(OB_THEME);
 
190
    CREATE_(OB_CONFIG_FILE);
 
191
    CREATE_(OB_WM_ACTION_UNDECORATE);
 
192
    CREATE_(OB_WM_STATE_UNDECORATED);
 
193
    CREATE_(OB_CONTROL);
 
194
    CREATE_(OB_VERSION);
 
195
    CREATE_(OB_APP_ROLE);
 
196
    CREATE_(OB_APP_TITLE);
 
197
    CREATE_(OB_APP_NAME);
 
198
    CREATE_(OB_APP_CLASS);
 
199
    CREATE_(OB_APP_TYPE);
 
200
}
 
201
 
 
202
Atom obt_prop_atom(ObtPropAtom a)
 
203
{
 
204
    g_assert(prop_started);
 
205
    g_assert(a < OBT_PROP_NUM_ATOMS);
 
206
    return prop_atoms[a];
 
207
}
 
208
 
 
209
static gboolean get_prealloc(Window win, Atom prop, Atom type, gint size,
 
210
                             guchar *data, gulong num)
 
211
{
 
212
    gboolean ret = FALSE;
 
213
    gint res;
 
214
    guchar *xdata = NULL;
 
215
    Atom ret_type;
 
216
    gint ret_size;
 
217
    gulong ret_items, bytes_left;
 
218
    glong num32 = 32 / size * num; /* num in 32-bit elements */
 
219
 
 
220
    res = XGetWindowProperty(obt_display, win, prop, 0l, num32,
 
221
                             FALSE, type, &ret_type, &ret_size,
 
222
                             &ret_items, &bytes_left, &xdata);
 
223
    if (res == Success && ret_items && xdata) {
 
224
        if (ret_size == size && ret_items >= num) {
 
225
            guint i;
 
226
            for (i = 0; i < num; ++i)
 
227
                switch (size) {
 
228
                case 8:
 
229
                    data[i] = xdata[i];
 
230
                    break;
 
231
                case 16:
 
232
                    ((guint16*)data)[i] = ((gushort*)xdata)[i];
 
233
                    break;
 
234
                case 32:
 
235
                    ((guint32*)data)[i] = ((gulong*)xdata)[i];
 
236
                    break;
 
237
                default:
 
238
                    g_assert_not_reached(); /* unhandled size */
 
239
                }
 
240
            ret = TRUE;
 
241
        }
 
242
        XFree(xdata);
 
243
    }
 
244
    return ret;
 
245
}
 
246
 
 
247
static gboolean get_all(Window win, Atom prop, Atom type, gint size,
 
248
                        guchar **data, guint *num)
 
249
{
 
250
    gboolean ret = FALSE;
 
251
    gint res;
 
252
    guchar *xdata = NULL;
 
253
    Atom ret_type;
 
254
    gint ret_size;
 
255
    gulong ret_items, bytes_left;
 
256
 
 
257
    res = XGetWindowProperty(obt_display, win, prop, 0l, G_MAXLONG,
 
258
                             FALSE, type, &ret_type, &ret_size,
 
259
                             &ret_items, &bytes_left, &xdata);
 
260
    if (res == Success) {
 
261
        if (ret_size == size && ret_items > 0) {
 
262
            guint i;
 
263
 
 
264
            *data = g_malloc(ret_items * (size / 8));
 
265
            for (i = 0; i < ret_items; ++i)
 
266
                switch (size) {
 
267
                case 8:
 
268
                    (*data)[i] = xdata[i];
 
269
                    break;
 
270
                case 16:
 
271
                    ((guint16*)*data)[i] = ((gushort*)xdata)[i];
 
272
                    break;
 
273
                case 32:
 
274
                    ((guint32*)*data)[i] = ((gulong*)xdata)[i];
 
275
                    break;
 
276
                default:
 
277
                    g_assert_not_reached(); /* unhandled size */
 
278
                }
 
279
            *num = ret_items;
 
280
            ret = TRUE;
 
281
        }
 
282
        XFree(xdata);
 
283
    }
 
284
    return ret;
 
285
}
 
286
 
 
287
/*! Get a text property from a window, and fill out the XTextProperty with it.
 
288
  @param win The window to read the property from.
 
289
  @param prop The atom of the property to read off the window.
 
290
  @param tprop The XTextProperty to fill out.
 
291
  @param type 0 to get text of any type, or a value from
 
292
    ObtPropTextType to restrict the value to a specific type.
 
293
  @return TRUE if the text was read and validated against the @type, and FALSE
 
294
    otherwise.
 
295
*/
 
296
static gboolean get_text_property(Window win, Atom prop,
 
297
                                  XTextProperty *tprop, ObtPropTextType type)
 
298
{
 
299
    if (!(XGetTextProperty(obt_display, win, tprop, prop) && tprop->nitems))
 
300
        return FALSE;
 
301
    if (!type)
 
302
        return TRUE; /* no type checking */
 
303
    switch (type) {
 
304
    case OBT_PROP_TEXT_STRING:
 
305
    case OBT_PROP_TEXT_STRING_XPCS:
 
306
    case OBT_PROP_TEXT_STRING_NO_CC:
 
307
        return tprop->encoding == OBT_PROP_ATOM(STRING);
 
308
    case OBT_PROP_TEXT_COMPOUND_TEXT:
 
309
        return tprop->encoding == OBT_PROP_ATOM(COMPOUND_TEXT);
 
310
    case OBT_PROP_TEXT_UTF8_STRING:
 
311
        return tprop->encoding == OBT_PROP_ATOM(UTF8_STRING);
 
312
    default:
 
313
        g_assert_not_reached();
 
314
    }
 
315
}
 
316
 
 
317
/*! Returns one or more UTF-8 encoded strings from the text property.
 
318
  @param tprop The XTextProperty to convert into UTF-8 string(s).
 
319
  @param type The type which specifies the format that the text must meet, or
 
320
    0 to allow any valid characters that can be converted to UTF-8 through.
 
321
  @param max The maximum number of strings to return.  -1 to return them all.
 
322
  @return If max is 1, then this returns a gchar* with the single string.
 
323
    Otherwise, this returns a gchar** of no more than max strings (or all
 
324
    strings read, if max is negative). If an error occurs, NULL is returned.
 
325
 */
 
326
static void* convert_text_property(XTextProperty *tprop,
 
327
                                   ObtPropTextType type, gint max)
 
328
{
 
329
    enum {
 
330
        LATIN1,
 
331
        UTF8,
 
332
        LOCALE
 
333
    } encoding;
 
334
    const gboolean return_single = (max == 1);
 
335
    gboolean ok = FALSE;
 
336
    gchar **strlist = NULL;
 
337
    gchar *single[1] = { NULL };
 
338
    gchar **retlist = single; /* single is used when max == 1 */
 
339
    gint i, n_strs;
 
340
 
 
341
    /* Read each string in the text property and store a pointer to it in
 
342
       retlist.  These pointers point into the X data structures directly.
 
343
 
 
344
       Then we will convert them to UTF-8, and replace the retlist pointer with
 
345
       a new one.
 
346
    */
 
347
    if (tprop->encoding == OBT_PROP_ATOM(COMPOUND_TEXT))
 
348
    {
 
349
        encoding = LOCALE;
 
350
        ok = (XmbTextPropertyToTextList(
 
351
                   obt_display, tprop, &strlist, &n_strs) == Success);
 
352
        if (ok) {
 
353
            if (max >= 0)
 
354
                n_strs = MIN(max, n_strs);
 
355
            if (!return_single)
 
356
                retlist = g_new0(gchar*, n_strs+1);
 
357
            if (retlist)
 
358
                for (i = 0; i < n_strs; ++i)
 
359
                    retlist[i] = strlist[i];
 
360
        }
 
361
    }
 
362
    else if (tprop->encoding == OBT_PROP_ATOM(UTF8_STRING) ||
 
363
             tprop->encoding == OBT_PROP_ATOM(STRING))
 
364
    {
 
365
        gchar *p; /* iterator */
 
366
 
 
367
        if (tprop->encoding == OBT_PROP_ATOM(STRING))
 
368
            encoding = LATIN1;
 
369
        else
 
370
            encoding = UTF8;
 
371
        ok = TRUE;
 
372
 
 
373
        /* First, count the number of strings. Then make a structure for them
 
374
           and copy pointers to them into it. */
 
375
        p = (gchar*)tprop->value;
 
376
        n_strs = 0;
 
377
        while (p < (gchar*)tprop->value + tprop->nitems) {
 
378
            p += strlen(p) + 1; /* next string */
 
379
            ++n_strs;
 
380
        }
 
381
 
 
382
        if (max >= 0)
 
383
            n_strs = MIN(max, n_strs);
 
384
        if (!return_single)
 
385
            retlist = g_new0(gchar*, n_strs+1);
 
386
        if (retlist) {
 
387
            p = (gchar*)tprop->value;
 
388
            for (i = 0; i < n_strs; ++i) {
 
389
                retlist[i] = p;
 
390
                p += strlen(p) + 1; /* next string */
 
391
            }
 
392
        }
 
393
    }
 
394
 
 
395
    if (!(ok && retlist)) {
 
396
        if (strlist) XFreeStringList(strlist);
 
397
        return NULL;
 
398
    }
 
399
 
 
400
    /* convert each element in retlist to UTF-8, and replace it. */
 
401
    for (i = 0; i < n_strs; ++i) {
 
402
        if (encoding == UTF8) {
 
403
            const gchar *end; /* the first byte past the valid data */
 
404
 
 
405
            g_utf8_validate(retlist[i], -1, &end);
 
406
            retlist[i] = g_strndup(retlist[i], end-retlist[i]);
 
407
        }
 
408
        else if (encoding == LOCALE) {
 
409
            gsize nvalid; /* the number of valid bytes at the front of the
 
410
                             string */
 
411
            gchar *utf; /* the string converted into utf8 */
 
412
 
 
413
            utf = g_locale_to_utf8(retlist[i], -1, &nvalid, NULL, NULL);
 
414
            if (!utf)
 
415
                utf = g_locale_to_utf8(retlist[i], nvalid, NULL, NULL, NULL);
 
416
            g_assert(utf);
 
417
            retlist[i] = utf;
 
418
        }
 
419
        else { /* encoding == LATIN1 */
 
420
            gsize nvalid; /* the number of valid bytes at the front of the
 
421
                             string */
 
422
            gchar *utf; /* the string converted into utf8 */
 
423
            gchar *p; /* iterator */
 
424
 
 
425
            /* look for invalid characters */
 
426
            for (p = retlist[i], nvalid = 0; *p; ++p, ++nvalid) {
 
427
                /* The only valid control characters are TAB(HT)=9 and
 
428
                   NEWLINE(LF)=10.
 
429
                   This is defined in ICCCM section 2:
 
430
                     http://tronche.com/gui/x/icccm/sec-2.html.
 
431
                   See a definition of the latin1 codepage here:
 
432
                     http://en.wikipedia.org/wiki/ISO/IEC_8859-1.
 
433
                   The above page includes control characters in the table,
 
434
                   which we must explicitly exclude, as the g_convert function
 
435
                   will happily take them.
 
436
                */
 
437
                const register guchar c = (guchar)*p; /* unsigned value at p */
 
438
                if ((c < 32 && c != 9 && c != 10) || (c >= 127 && c <= 160))
 
439
                    break; /* found a control character that isn't allowed */
 
440
 
 
441
                if (type == OBT_PROP_TEXT_STRING_NO_CC && c < 32)
 
442
                    break; /* absolutely no control characters are allowed */
 
443
 
 
444
                if (type == OBT_PROP_TEXT_STRING_XPCS) {
 
445
                    const gboolean valid = (
 
446
                        (c >= 32 && c < 128) || c == 9 || c == 10);
 
447
                    if (!valid)
 
448
                        break; /* strict whitelisting for XPCS */
 
449
                }
 
450
            }
 
451
            /* look for invalid latin1 characters */
 
452
            utf = g_convert(retlist[i], nvalid, "utf-8", "iso-8859-1",
 
453
                            &nvalid, NULL, NULL);
 
454
            if (!utf)
 
455
                utf = g_convert(retlist[i], nvalid, "utf-8", "iso-8859-1",
 
456
                                NULL, NULL, NULL);
 
457
            g_assert(utf);
 
458
            retlist[i] = utf;
 
459
        }
 
460
    }
 
461
 
 
462
    if (strlist) XFreeStringList(strlist);
 
463
    if (return_single)
 
464
        return retlist[0];
 
465
    else
 
466
        return retlist;
 
467
}
 
468
 
 
469
gboolean obt_prop_get32(Window win, Atom prop, Atom type, guint32 *ret)
 
470
{
 
471
    return get_prealloc(win, prop, type, 32, (guchar*)ret, 1);
 
472
}
 
473
 
 
474
gboolean obt_prop_get_array32(Window win, Atom prop, Atom type, guint32 **ret,
 
475
                              guint *nret)
 
476
{
 
477
    return get_all(win, prop, type, 32, (guchar**)ret, nret);
 
478
}
 
479
 
 
480
gboolean obt_prop_get_text(Window win, Atom prop, ObtPropTextType type,
 
481
                           gchar **ret_string)
 
482
{
 
483
    XTextProperty tprop;
 
484
    gchar *str;
 
485
    gboolean ret = FALSE;
 
486
 
 
487
    if (get_text_property(win, prop, &tprop, type)) {
 
488
        str = (gchar*)convert_text_property(&tprop, type, 1);
 
489
 
 
490
        if (str) {
 
491
            *ret_string = str;
 
492
            ret = TRUE;
 
493
        }
 
494
    }
 
495
    XFree(tprop.value);
 
496
    return ret;
 
497
}
 
498
 
 
499
gboolean obt_prop_get_array_text(Window win, Atom prop,
 
500
                                 ObtPropTextType type,
 
501
                                 gchar ***ret_strings)
 
502
{
 
503
    XTextProperty tprop;
 
504
    gchar **strs;
 
505
    gboolean ret = FALSE;
 
506
 
 
507
    if (get_text_property(win, prop, &tprop, type)) {
 
508
        strs = (gchar**)convert_text_property(&tprop, type, -1);
 
509
 
 
510
        if (strs) {
 
511
            *ret_strings = strs;
 
512
            ret = TRUE;
 
513
        }
 
514
    }
 
515
    XFree(tprop.value);
 
516
    return ret;
 
517
}
 
518
 
 
519
void obt_prop_set32(Window win, Atom prop, Atom type, gulong val)
 
520
{
 
521
    XChangeProperty(obt_display, win, prop, type, 32, PropModeReplace,
 
522
                    (guchar*)&val, 1);
 
523
}
 
524
 
 
525
void obt_prop_set_array32(Window win, Atom prop, Atom type, gulong *val,
 
526
                      guint num)
 
527
{
 
528
    XChangeProperty(obt_display, win, prop, type, 32, PropModeReplace,
 
529
                    (guchar*)val, num);
 
530
}
 
531
 
 
532
void obt_prop_set_text(Window win, Atom prop, const gchar *val)
 
533
{
 
534
    XChangeProperty(obt_display, win, prop, OBT_PROP_ATOM(UTF8_STRING), 8,
 
535
                    PropModeReplace, (const guchar*)val, strlen(val));
 
536
}
 
537
 
 
538
void obt_prop_set_array_text(Window win, Atom prop, const gchar *const *strs)
 
539
{
 
540
    GString *str;
 
541
    gchar const *const *s;
 
542
 
 
543
    str = g_string_sized_new(0);
 
544
    for (s = strs; *s; ++s) {
 
545
        str = g_string_append(str, *s);
 
546
        str = g_string_append_c(str, '\0');
 
547
    }
 
548
    XChangeProperty(obt_display, win, prop, OBT_PROP_ATOM(UTF8_STRING), 8,
 
549
                    PropModeReplace, (guchar*)str->str, str->len);
 
550
    g_string_free(str, TRUE);
 
551
}
 
552
 
 
553
void obt_prop_erase(Window win, Atom prop)
 
554
{
 
555
    XDeleteProperty(obt_display, win, prop);
 
556
}
 
557
 
 
558
void obt_prop_message(gint screen, Window about, Atom messagetype,
 
559
                      glong data0, glong data1, glong data2, glong data3,
 
560
                      glong data4, glong mask)
 
561
{
 
562
    obt_prop_message_to(obt_root(screen), about, messagetype,
 
563
                        data0, data1, data2, data3, data4, mask);
 
564
}
 
565
 
 
566
void obt_prop_message_to(Window to, Window about,
 
567
                         Atom messagetype,
 
568
                         glong data0, glong data1, glong data2, glong data3,
 
569
                         glong data4, glong mask)
 
570
{
 
571
    XEvent ce;
 
572
    ce.xclient.type = ClientMessage;
 
573
    ce.xclient.message_type = messagetype;
 
574
    ce.xclient.display = obt_display;
 
575
    ce.xclient.window = about;
 
576
    ce.xclient.format = 32;
 
577
    ce.xclient.data.l[0] = data0;
 
578
    ce.xclient.data.l[1] = data1;
 
579
    ce.xclient.data.l[2] = data2;
 
580
    ce.xclient.data.l[3] = data3;
 
581
    ce.xclient.data.l[4] = data4;
 
582
    XSendEvent(obt_display, to, FALSE, mask, &ce);
 
583
}