1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 obt/prop.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
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.
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.
17 See the COPYING file for a copy of the GNU General Public License.
21 #include "obt/display.h"
23 #include <X11/Xatom.h>
28 Atom prop_atoms
[OBT_PROP_NUM_ATOMS
];
29 gboolean prop_started
= FALSE
;
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)
36 void obt_prop_startup(void)
38 if (prop_started
) return;
41 g_assert(obt_display
);
48 CREATE_NAME(UTF8
, "UTF8_STRING");
52 CREATE(WM_COLORMAP_WINDOWS
);
55 CREATE(WM_CHANGE_STATE
);
56 CREATE(WM_DELETE_WINDOW
);
57 CREATE(WM_TAKE_FOCUS
);
61 CREATE(WM_WINDOW_ROLE
);
62 CREATE(WM_CLIENT_MACHINE
);
64 CREATE(WM_CLIENT_LEADER
);
65 CREATE(WM_TRANSIENT_FOR
);
66 CREATE_(MOTIF_WM_HINTS
);
67 CREATE_(MOTIF_WM_INFO
);
71 CREATE_(NET_WM_FULL_PLACEMENT
);
73 CREATE_(NET_SUPPORTED
);
74 CREATE_(NET_CLIENT_LIST
);
75 CREATE_(NET_CLIENT_LIST_STACKING
);
76 CREATE_(NET_NUMBER_OF_DESKTOPS
);
77 CREATE_(NET_DESKTOP_GEOMETRY
);
78 CREATE_(NET_DESKTOP_VIEWPORT
);
79 CREATE_(NET_CURRENT_DESKTOP
);
80 CREATE_(NET_DESKTOP_NAMES
);
81 CREATE_(NET_ACTIVE_WINDOW
);
82 /* CREATE_(NET_RESTACK_WINDOW);*/
83 CREATE_(NET_WORKAREA
);
84 CREATE_(NET_SUPPORTING_WM_CHECK
);
85 CREATE_(NET_DESKTOP_LAYOUT
);
86 CREATE_(NET_SHOWING_DESKTOP
);
88 CREATE_(NET_CLOSE_WINDOW
);
89 CREATE_(NET_WM_MOVERESIZE
);
90 CREATE_(NET_MOVERESIZE_WINDOW
);
91 CREATE_(NET_REQUEST_FRAME_EXTENTS
);
92 CREATE_(NET_RESTACK_WINDOW
);
94 CREATE_(NET_STARTUP_ID
);
97 CREATE_(NET_WM_VISIBLE_NAME
);
98 CREATE_(NET_WM_ICON_NAME
);
99 CREATE_(NET_WM_VISIBLE_ICON_NAME
);
100 CREATE_(NET_WM_DESKTOP
);
101 CREATE_(NET_WM_WINDOW_TYPE
);
102 CREATE_(NET_WM_STATE
);
103 CREATE_(NET_WM_STRUT
);
104 CREATE_(NET_WM_STRUT_PARTIAL
);
105 CREATE_(NET_WM_ICON
);
106 CREATE_(NET_WM_ICON_GEOMETRY
);
108 CREATE_(NET_WM_ALLOWED_ACTIONS
);
109 CREATE_(NET_WM_USER_TIME
);
110 /* CREATE_(NET_WM_USER_TIME_WINDOW); */
111 CREATE_(KDE_NET_WM_FRAME_STRUT
);
112 CREATE_(NET_FRAME_EXTENTS
);
114 CREATE_(NET_WM_PING
);
116 CREATE_(NET_WM_SYNC_REQUEST
);
117 CREATE_(NET_WM_SYNC_REQUEST_COUNTER
);
120 CREATE_(NET_WM_WINDOW_TYPE_DESKTOP
);
121 CREATE_(NET_WM_WINDOW_TYPE_DOCK
);
122 CREATE_(NET_WM_WINDOW_TYPE_TOOLBAR
);
123 CREATE_(NET_WM_WINDOW_TYPE_MENU
);
124 CREATE_(NET_WM_WINDOW_TYPE_UTILITY
);
125 CREATE_(NET_WM_WINDOW_TYPE_SPLASH
);
126 CREATE_(NET_WM_WINDOW_TYPE_DIALOG
);
127 CREATE_(NET_WM_WINDOW_TYPE_NORMAL
);
128 CREATE_(NET_WM_WINDOW_TYPE_POPUP_MENU
);
130 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPLEFT
] = 0;
131 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOP
] = 1;
132 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPRIGHT
] = 2;
133 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_RIGHT
] = 3;
134 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
] = 4;
135 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOM
] = 5;
136 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
] = 6;
137 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_LEFT
] = 7;
138 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_MOVE
] = 8;
139 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_KEYBOARD
] = 9;
140 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_MOVE_KEYBOARD
] = 10;
141 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_CANCEL
] = 11;
143 CREATE_(NET_WM_ACTION_MOVE
);
144 CREATE_(NET_WM_ACTION_RESIZE
);
145 CREATE_(NET_WM_ACTION_MINIMIZE
);
146 CREATE_(NET_WM_ACTION_SHADE
);
147 CREATE_(NET_WM_ACTION_MAXIMIZE_HORZ
);
148 CREATE_(NET_WM_ACTION_MAXIMIZE_VERT
);
149 CREATE_(NET_WM_ACTION_FULLSCREEN
);
150 CREATE_(NET_WM_ACTION_CHANGE_DESKTOP
);
151 CREATE_(NET_WM_ACTION_CLOSE
);
152 CREATE_(NET_WM_ACTION_ABOVE
);
153 CREATE_(NET_WM_ACTION_BELOW
);
155 CREATE_(NET_WM_STATE_MODAL
);
156 /* CREATE_(NET_WM_STATE_STICKY);*/
157 CREATE_(NET_WM_STATE_MAXIMIZED_VERT
);
158 CREATE_(NET_WM_STATE_MAXIMIZED_HORZ
);
159 CREATE_(NET_WM_STATE_SHADED
);
160 CREATE_(NET_WM_STATE_SKIP_TASKBAR
);
161 CREATE_(NET_WM_STATE_SKIP_PAGER
);
162 CREATE_(NET_WM_STATE_HIDDEN
);
163 CREATE_(NET_WM_STATE_FULLSCREEN
);
164 CREATE_(NET_WM_STATE_ABOVE
);
165 CREATE_(NET_WM_STATE_BELOW
);
166 CREATE_(NET_WM_STATE_DEMANDS_ATTENTION
);
168 prop_atoms
[OBT_PROP_NET_WM_STATE_ADD
] = 1;
169 prop_atoms
[OBT_PROP_NET_WM_STATE_REMOVE
] = 0;
170 prop_atoms
[OBT_PROP_NET_WM_STATE_TOGGLE
] = 2;
172 prop_atoms
[OBT_PROP_NET_WM_ORIENTATION_HORZ
] = 0;
173 prop_atoms
[OBT_PROP_NET_WM_ORIENTATION_VERT
] = 1;
174 prop_atoms
[OBT_PROP_NET_WM_TOPLEFT
] = 0;
175 prop_atoms
[OBT_PROP_NET_WM_TOPRIGHT
] = 1;
176 prop_atoms
[OBT_PROP_NET_WM_BOTTOMRIGHT
] = 2;
177 prop_atoms
[OBT_PROP_NET_WM_BOTTOMLEFT
] = 3;
179 CREATE_(KDE_WM_CHANGE_STATE
);
180 CREATE_(KDE_NET_WM_WINDOW_TYPE_OVERRIDE
);
183 CREATE_NAME(ROOTPMAPId, "_XROOTPMAP_ID");
184 CREATE_NAME(ESETROOTId, "ESETROOT_PMAP_ID");
187 CREATE_(OPENBOX_PID
);
189 CREATE_(OB_CONFIG_FILE
);
190 CREATE_(OB_WM_ACTION_UNDECORATE
);
191 CREATE_(OB_WM_STATE_UNDECORATED
);
198 Atom
obt_prop_atom(ObtPropAtom a
)
200 g_assert(prop_started
);
201 g_assert(a
< OBT_PROP_NUM_ATOMS
);
202 return prop_atoms
[a
];
205 static gboolean
get_prealloc(Window win
, Atom prop
, Atom type
, gint size
,
206 guchar
*data
, gulong num
)
208 gboolean ret
= FALSE
;
210 guchar
*xdata
= NULL
;
213 gulong ret_items
, bytes_left
;
214 glong num32
= 32 / size
* num
; /* num in 32-bit elements */
216 res
= XGetWindowProperty(obt_display
, win
, prop
, 0l, num32
,
217 FALSE
, type
, &ret_type
, &ret_size
,
218 &ret_items
, &bytes_left
, &xdata
);
219 if (res
== Success
&& ret_items
&& xdata
) {
220 if (ret_size
== size
&& ret_items
>= num
) {
222 for (i
= 0; i
< num
; ++i
)
228 ((guint16
*)data
)[i
] = ((gushort
*)xdata
)[i
];
231 ((guint32
*)data
)[i
] = ((gulong
*)xdata
)[i
];
234 g_assert_not_reached(); /* unhandled size */
243 static gboolean
get_all(Window win
, Atom prop
, Atom type
, gint size
,
244 guchar
**data
, guint
*num
)
246 gboolean ret
= FALSE
;
248 guchar
*xdata
= NULL
;
251 gulong ret_items
, bytes_left
;
253 res
= XGetWindowProperty(obt_display
, win
, prop
, 0l, G_MAXLONG
,
254 FALSE
, type
, &ret_type
, &ret_size
,
255 &ret_items
, &bytes_left
, &xdata
);
256 if (res
== Success
) {
257 if (ret_size
== size
&& ret_items
> 0) {
260 *data
= g_malloc(ret_items
* (size
/ 8));
261 for (i
= 0; i
< ret_items
; ++i
)
264 (*data
)[i
] = xdata
[i
];
267 ((guint16
*)*data
)[i
] = ((gushort
*)xdata
)[i
];
270 ((guint32
*)*data
)[i
] = ((gulong
*)xdata
)[i
];
273 g_assert_not_reached(); /* unhandled size */
283 static gboolean
get_stringlist(Window win
, Atom prop
, gchar
***list
, gint
*nstr
)
286 gboolean ret
= FALSE
;
288 if (XGetTextProperty(obt_display
, win
, &tprop
, prop
) && tprop
.nitems
) {
289 if (XTextPropertyToStringList(&tprop
, list
, nstr
))
296 gboolean
obt_prop_get32(Window win
, Atom prop
, Atom type
, guint32
*ret
)
298 return get_prealloc(win
, prop
, type
, 32, (guchar
*)ret
, 1);
301 gboolean
obt_prop_get_array32(Window win
, Atom prop
, Atom type
, guint32
**ret
,
304 return get_all(win
, prop
, type
, 32, (guchar
**)ret
, nret
);
307 gboolean
obt_prop_get_string_locale(Window win
, Atom prop
, gchar
**ret
)
313 if (get_stringlist(win
, prop
, &list
, &nstr
) && nstr
) {
314 s
= g_locale_to_utf8(list
[0], -1, NULL
, NULL
, NULL
);
315 XFreeStringList(list
);
324 gboolean
obt_prop_get_strings_locale(Window win
, Atom prop
, gchar
***ret
)
326 GSList
*strs
= NULL
, *it
;
328 guint num
, i
, count
= 0;
330 if (get_all(win
, prop
, OBT_PROP_ATOM(STRING
), 8,
331 (guchar
**)&raw
, &num
))
334 while (p
< raw
+ num
) {
336 strs
= g_slist_append(strs
, p
);
337 p
+= strlen(p
) + 1; /* next string */
340 *ret
= g_new0(gchar
*, count
+ 1);
341 (*ret
)[count
] = NULL
; /* null terminated list */
343 for (i
= 0, it
= strs
; it
; ++i
, it
= g_slist_next(it
)) {
344 (*ret
)[i
] = g_locale_to_utf8(it
->data
, -1, NULL
, NULL
, NULL
);
345 /* make sure translation did not fail */
347 (*ret
)[i
] = g_strdup("");
356 gboolean
obt_prop_get_string_utf8(Window win
, Atom prop
, gchar
**ret
)
362 if (get_all(win
, prop
, OBT_PROP_ATOM(UTF8
), 8,
363 (guchar
**)&raw
, &num
))
365 str
= g_strndup(raw
, num
); /* grab the first string from the list */
367 if (g_utf8_validate(str
, -1, NULL
)) {
376 gboolean
obt_prop_get_strings_utf8(Window win
, Atom prop
, gchar
***ret
)
378 GSList
*strs
= NULL
, *it
;
380 guint num
, i
, count
= 0;
382 if (get_all(win
, prop
, OBT_PROP_ATOM(UTF8
), 8,
383 (guchar
**)&raw
, &num
))
386 while (p
< raw
+ num
) {
388 strs
= g_slist_append(strs
, p
);
389 p
+= strlen(p
) + 1; /* next string */
392 *ret
= g_new0(gchar
*, count
+ 1);
394 for (i
= 0, it
= strs
; it
; ++i
, it
= g_slist_next(it
)) {
395 if (g_utf8_validate(it
->data
, -1, NULL
))
396 (*ret
)[i
] = g_strdup(it
->data
);
398 (*ret
)[i
] = g_strdup("");
407 void obt_prop_set32(Window win
, Atom prop
, Atom type
, gulong val
)
409 XChangeProperty(obt_display
, win
, prop
, type
, 32, PropModeReplace
,
413 void obt_prop_set_array32(Window win
, Atom prop
, Atom type
, gulong
*val
,
416 XChangeProperty(obt_display
, win
, prop
, type
, 32, PropModeReplace
,
420 void obt_prop_set_string_locale(Window win
, Atom prop
, const gchar
*val
)
422 gchar
const *s
[2] = { val
, NULL
};
423 obt_prop_set_strings_locale(win
, prop
, s
);
426 void obt_prop_set_strings_locale(Window win
, Atom prop
, const gchar
**strs
)
432 /* count the strings in strs, and convert them to the locale format */
433 for (count
= 0; strs
[count
]; ++count
);
434 lstrs
= g_new0(char*, count
);
435 for (i
= 0; i
< count
; ++i
) {
436 lstrs
[i
] = g_locale_from_utf8(strs
[i
], -1, NULL
, NULL
, NULL
);
438 lstrs
[i
] = g_strdup(""); /* make it an empty string */
439 g_warning("Unable to translate string '%s' from UTF8 to locale "
445 XStringListToTextProperty(lstrs
, count
, &tprop
);
446 XSetTextProperty(obt_display
, win
, &tprop
, prop
);
450 void obt_prop_set_string_utf8(Window win
, Atom prop
, const gchar
*val
)
452 XChangeProperty(obt_display
, win
, prop
, OBT_PROP_ATOM(UTF8
), 8,
453 PropModeReplace
, (const guchar
*)val
, strlen(val
));
456 void obt_prop_set_strings_utf8(Window win
, Atom prop
, const gchar
**strs
)
461 str
= g_string_sized_new(0);
462 for (s
= strs
; *s
; ++s
) {
463 str
= g_string_append(str
, *s
);
464 str
= g_string_append_c(str
, '\0');
466 XChangeProperty(obt_display
, win
, prop
, obt_prop_atom(OBT_PROP_UTF8
), 8,
467 PropModeReplace
, (guchar
*)str
->str
, str
->len
);
468 g_string_free(str
, TRUE
);
471 void obt_prop_erase(Window win
, Atom prop
)
473 XDeleteProperty(obt_display
, win
, prop
);
476 void obt_prop_message(gint screen
, Window about
, Atom messagetype
,
477 glong data0
, glong data1
, glong data2
, glong data3
,
478 glong data4
, glong mask
)
480 obt_prop_message_to(obt_root(screen
), about
, messagetype
,
481 data0
, data1
, data2
, data3
, data4
, mask
);
484 void obt_prop_message_to(Window to
, Window about
,
486 glong data0
, glong data1
, glong data2
, glong data3
,
487 glong data4
, glong mask
)
490 ce
.xclient
.type
= ClientMessage
;
491 ce
.xclient
.message_type
= messagetype
;
492 ce
.xclient
.display
= obt_display
;
493 ce
.xclient
.window
= about
;
494 ce
.xclient
.format
= 32;
495 ce
.xclient
.data
.l
[0] = data0
;
496 ce
.xclient
.data
.l
[1] = data1
;
497 ce
.xclient
.data
.l
[2] = data2
;
498 ce
.xclient
.data
.l
[3] = data3
;
499 ce
.xclient
.data
.l
[4] = data4
;
500 XSendEvent(obt_display
, to
, FALSE
, mask
, &ce
);