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
);
194 CREATE_(OB_APP_ROLE
);
195 CREATE_(OB_APP_TITLE
);
196 CREATE_(OB_APP_NAME
);
197 CREATE_(OB_APP_CLASS
);
198 CREATE_(OB_APP_TYPE
);
201 Atom
obt_prop_atom(ObtPropAtom a
)
203 g_assert(prop_started
);
204 g_assert(a
< OBT_PROP_NUM_ATOMS
);
205 return prop_atoms
[a
];
208 static gboolean
get_prealloc(Window win
, Atom prop
, Atom type
, gint size
,
209 guchar
*data
, gulong num
)
211 gboolean ret
= FALSE
;
213 guchar
*xdata
= NULL
;
216 gulong ret_items
, bytes_left
;
217 glong num32
= 32 / size
* num
; /* num in 32-bit elements */
219 res
= XGetWindowProperty(obt_display
, win
, prop
, 0l, num32
,
220 FALSE
, type
, &ret_type
, &ret_size
,
221 &ret_items
, &bytes_left
, &xdata
);
222 if (res
== Success
&& ret_items
&& xdata
) {
223 if (ret_size
== size
&& ret_items
>= num
) {
225 for (i
= 0; i
< num
; ++i
)
231 ((guint16
*)data
)[i
] = ((gushort
*)xdata
)[i
];
234 ((guint32
*)data
)[i
] = ((gulong
*)xdata
)[i
];
237 g_assert_not_reached(); /* unhandled size */
246 static gboolean
get_all(Window win
, Atom prop
, Atom type
, gint size
,
247 guchar
**data
, guint
*num
)
249 gboolean ret
= FALSE
;
251 guchar
*xdata
= NULL
;
254 gulong ret_items
, bytes_left
;
256 res
= XGetWindowProperty(obt_display
, win
, prop
, 0l, G_MAXLONG
,
257 FALSE
, type
, &ret_type
, &ret_size
,
258 &ret_items
, &bytes_left
, &xdata
);
259 if (res
== Success
) {
260 if (ret_size
== size
&& ret_items
> 0) {
263 *data
= g_malloc(ret_items
* (size
/ 8));
264 for (i
= 0; i
< ret_items
; ++i
)
267 (*data
)[i
] = xdata
[i
];
270 ((guint16
*)*data
)[i
] = ((gushort
*)xdata
)[i
];
273 ((guint32
*)*data
)[i
] = ((gulong
*)xdata
)[i
];
276 g_assert_not_reached(); /* unhandled size */
286 static gboolean
get_stringlist(Window win
, Atom prop
, gchar
***list
, gint
*nstr
)
289 gboolean ret
= FALSE
;
291 if (XGetTextProperty(obt_display
, win
, &tprop
, prop
) && tprop
.nitems
) {
292 if (XTextPropertyToStringList(&tprop
, list
, nstr
))
299 gboolean
obt_prop_get32(Window win
, Atom prop
, Atom type
, guint32
*ret
)
301 return get_prealloc(win
, prop
, type
, 32, (guchar
*)ret
, 1);
304 gboolean
obt_prop_get_array32(Window win
, Atom prop
, Atom type
, guint32
**ret
,
307 return get_all(win
, prop
, type
, 32, (guchar
**)ret
, nret
);
310 gboolean
obt_prop_get_string_locale(Window win
, Atom prop
, gchar
**ret
)
316 if (get_stringlist(win
, prop
, &list
, &nstr
) && nstr
) {
317 s
= g_locale_to_utf8(list
[0], -1, NULL
, NULL
, NULL
);
318 XFreeStringList(list
);
327 gboolean
obt_prop_get_strings_locale(Window win
, Atom prop
, gchar
***ret
)
329 GSList
*strs
= NULL
, *it
;
331 guint num
, i
, count
= 0;
333 if (get_all(win
, prop
, OBT_PROP_ATOM(STRING
), 8,
334 (guchar
**)&raw
, &num
))
337 while (p
< raw
+ num
) {
339 strs
= g_slist_append(strs
, p
);
340 p
+= strlen(p
) + 1; /* next string */
343 *ret
= g_new0(gchar
*, count
+ 1);
344 (*ret
)[count
] = NULL
; /* null terminated list */
346 for (i
= 0, it
= strs
; it
; ++i
, it
= g_slist_next(it
)) {
347 (*ret
)[i
] = g_locale_to_utf8(it
->data
, -1, NULL
, NULL
, NULL
);
348 /* make sure translation did not fail */
350 (*ret
)[i
] = g_strdup("");
359 gboolean
obt_prop_get_string_utf8(Window win
, Atom prop
, gchar
**ret
)
365 if (get_all(win
, prop
, OBT_PROP_ATOM(UTF8
), 8,
366 (guchar
**)&raw
, &num
))
368 str
= g_strndup(raw
, num
); /* grab the first string from the list */
370 if (g_utf8_validate(str
, -1, NULL
)) {
379 gboolean
obt_prop_get_strings_utf8(Window win
, Atom prop
, gchar
***ret
)
381 GSList
*strs
= NULL
, *it
;
383 guint num
, i
, count
= 0;
385 if (get_all(win
, prop
, OBT_PROP_ATOM(UTF8
), 8,
386 (guchar
**)&raw
, &num
))
389 while (p
< raw
+ num
) {
391 strs
= g_slist_append(strs
, p
);
392 p
+= strlen(p
) + 1; /* next string */
395 *ret
= g_new0(gchar
*, count
+ 1);
397 for (i
= 0, it
= strs
; it
; ++i
, it
= g_slist_next(it
)) {
398 if (g_utf8_validate(it
->data
, -1, NULL
))
399 (*ret
)[i
] = g_strdup(it
->data
);
401 (*ret
)[i
] = g_strdup("");
410 void obt_prop_set32(Window win
, Atom prop
, Atom type
, gulong val
)
412 XChangeProperty(obt_display
, win
, prop
, type
, 32, PropModeReplace
,
416 void obt_prop_set_array32(Window win
, Atom prop
, Atom type
, gulong
*val
,
419 XChangeProperty(obt_display
, win
, prop
, type
, 32, PropModeReplace
,
423 void obt_prop_set_string_locale(Window win
, Atom prop
, const gchar
*val
)
425 gchar
const *s
[2] = { val
, NULL
};
426 obt_prop_set_strings_locale(win
, prop
, s
);
429 void obt_prop_set_strings_locale(Window win
, Atom prop
,
430 const gchar
*const *strs
)
436 /* count the strings in strs, and convert them to the locale format */
437 for (count
= 0; strs
[count
]; ++count
);
438 lstrs
= g_new0(char*, count
);
439 for (i
= 0; i
< count
; ++i
) {
440 lstrs
[i
] = g_locale_from_utf8(strs
[i
], -1, NULL
, NULL
, NULL
);
442 lstrs
[i
] = g_strdup(""); /* make it an empty string */
443 g_warning("Unable to translate string '%s' from UTF8 to locale "
449 XStringListToTextProperty(lstrs
, count
, &tprop
);
450 XSetTextProperty(obt_display
, win
, &tprop
, prop
);
454 void obt_prop_set_string_utf8(Window win
, Atom prop
, const gchar
*val
)
456 XChangeProperty(obt_display
, win
, prop
, OBT_PROP_ATOM(UTF8
), 8,
457 PropModeReplace
, (const guchar
*)val
, strlen(val
));
460 void obt_prop_set_strings_utf8(Window win
, Atom prop
,
461 const gchar
*const *strs
)
464 gchar
const *const *s
;
466 str
= g_string_sized_new(0);
467 for (s
= strs
; *s
; ++s
) {
468 str
= g_string_append(str
, *s
);
469 str
= g_string_append_c(str
, '\0');
471 XChangeProperty(obt_display
, win
, prop
, obt_prop_atom(OBT_PROP_UTF8
), 8,
472 PropModeReplace
, (guchar
*)str
->str
, str
->len
);
473 g_string_free(str
, TRUE
);
476 void obt_prop_erase(Window win
, Atom prop
)
478 XDeleteProperty(obt_display
, win
, prop
);
481 void obt_prop_message(gint screen
, Window about
, Atom messagetype
,
482 glong data0
, glong data1
, glong data2
, glong data3
,
483 glong data4
, glong mask
)
485 obt_prop_message_to(obt_root(screen
), about
, messagetype
,
486 data0
, data1
, data2
, data3
, data4
, mask
);
489 void obt_prop_message_to(Window to
, Window about
,
491 glong data0
, glong data1
, glong data2
, glong data3
,
492 glong data4
, glong mask
)
495 ce
.xclient
.type
= ClientMessage
;
496 ce
.xclient
.message_type
= messagetype
;
497 ce
.xclient
.display
= obt_display
;
498 ce
.xclient
.window
= about
;
499 ce
.xclient
.format
= 32;
500 ce
.xclient
.data
.l
[0] = data0
;
501 ce
.xclient
.data
.l
[1] = data1
;
502 ce
.xclient
.data
.l
[2] = data2
;
503 ce
.xclient
.data
.l
[3] = data3
;
504 ce
.xclient
.data
.l
[4] = data4
;
505 XSendEvent(obt_display
, to
, FALSE
, mask
, &ce
);