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()
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_(MOTIF_WM_HINTS
);
69 CREATE_(NET_WM_FULL_PLACEMENT
);
71 CREATE_(NET_SUPPORTED
);
72 CREATE_(NET_CLIENT_LIST
);
73 CREATE_(NET_CLIENT_LIST_STACKING
);
74 CREATE_(NET_NUMBER_OF_DESKTOPS
);
75 CREATE_(NET_DESKTOP_GEOMETRY
);
76 CREATE_(NET_DESKTOP_VIEWPORT
);
77 CREATE_(NET_CURRENT_DESKTOP
);
78 CREATE_(NET_DESKTOP_NAMES
);
79 CREATE_(NET_ACTIVE_WINDOW
);
80 /* CREATE_(NET_RESTACK_WINDOW);*/
81 CREATE_(NET_WORKAREA
);
82 CREATE_(NET_SUPPORTING_WM_CHECK
);
83 CREATE_(NET_DESKTOP_LAYOUT
);
84 CREATE_(NET_SHOWING_DESKTOP
);
86 CREATE_(NET_CLOSE_WINDOW
);
87 CREATE_(NET_WM_MOVERESIZE
);
88 CREATE_(NET_MOVERESIZE_WINDOW
);
89 CREATE_(NET_REQUEST_FRAME_EXTENTS
);
90 CREATE_(NET_RESTACK_WINDOW
);
92 CREATE_(NET_STARTUP_ID
);
95 CREATE_(NET_WM_VISIBLE_NAME
);
96 CREATE_(NET_WM_ICON_NAME
);
97 CREATE_(NET_WM_VISIBLE_ICON_NAME
);
98 CREATE_(NET_WM_DESKTOP
);
99 CREATE_(NET_WM_WINDOW_TYPE
);
100 CREATE_(NET_WM_STATE
);
101 CREATE_(NET_WM_STRUT
);
102 CREATE_(NET_WM_STRUT_PARTIAL
);
103 CREATE_(NET_WM_ICON
);
104 CREATE_(NET_WM_ICON_GEOMETRY
);
106 CREATE_(NET_WM_ALLOWED_ACTIONS
);
107 CREATE_(NET_WM_USER_TIME
);
108 /* CREATE_(NET_WM_USER_TIME_WINDOW); */
109 CREATE_(KDE_NET_WM_FRAME_STRUT
);
110 CREATE_(NET_FRAME_EXTENTS
);
112 CREATE_(NET_WM_PING
);
114 CREATE_(NET_WM_SYNC_REQUEST
);
115 CREATE_(NET_WM_SYNC_REQUEST_COUNTER
);
118 CREATE_(NET_WM_WINDOW_TYPE_DESKTOP
);
119 CREATE_(NET_WM_WINDOW_TYPE_DOCK
);
120 CREATE_(NET_WM_WINDOW_TYPE_TOOLBAR
);
121 CREATE_(NET_WM_WINDOW_TYPE_MENU
);
122 CREATE_(NET_WM_WINDOW_TYPE_UTILITY
);
123 CREATE_(NET_WM_WINDOW_TYPE_SPLASH
);
124 CREATE_(NET_WM_WINDOW_TYPE_DIALOG
);
125 CREATE_(NET_WM_WINDOW_TYPE_NORMAL
);
126 CREATE_(NET_WM_WINDOW_TYPE_POPUP_MENU
);
128 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPLEFT
] = 0;
129 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOP
] = 1;
130 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPRIGHT
] = 2;
131 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_RIGHT
] = 3;
132 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
] = 4;
133 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOM
] = 5;
134 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
] = 6;
135 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_LEFT
] = 7;
136 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_MOVE
] = 8;
137 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_KEYBOARD
] = 9;
138 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_MOVE_KEYBOARD
] = 10;
139 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_CANCEL
] = 11;
141 CREATE_(NET_WM_ACTION_MOVE
);
142 CREATE_(NET_WM_ACTION_RESIZE
);
143 CREATE_(NET_WM_ACTION_MINIMIZE
);
144 CREATE_(NET_WM_ACTION_SHADE
);
145 CREATE_(NET_WM_ACTION_MAXIMIZE_HORZ
);
146 CREATE_(NET_WM_ACTION_MAXIMIZE_VERT
);
147 CREATE_(NET_WM_ACTION_FULLSCREEN
);
148 CREATE_(NET_WM_ACTION_CHANGE_DESKTOP
);
149 CREATE_(NET_WM_ACTION_CLOSE
);
150 CREATE_(NET_WM_ACTION_ABOVE
);
151 CREATE_(NET_WM_ACTION_BELOW
);
153 CREATE_(NET_WM_STATE_MODAL
);
154 /* CREATE_(NET_WM_STATE_STICKY);*/
155 CREATE_(NET_WM_STATE_MAXIMIZED_VERT
);
156 CREATE_(NET_WM_STATE_MAXIMIZED_HORZ
);
157 CREATE_(NET_WM_STATE_SHADED
);
158 CREATE_(NET_WM_STATE_SKIP_TASKBAR
);
159 CREATE_(NET_WM_STATE_SKIP_PAGER
);
160 CREATE_(NET_WM_STATE_HIDDEN
);
161 CREATE_(NET_WM_STATE_FULLSCREEN
);
162 CREATE_(NET_WM_STATE_ABOVE
);
163 CREATE_(NET_WM_STATE_BELOW
);
164 CREATE_(NET_WM_STATE_DEMANDS_ATTENTION
);
166 prop_atoms
[OBT_PROP_NET_WM_STATE_ADD
] = 1;
167 prop_atoms
[OBT_PROP_NET_WM_STATE_REMOVE
] = 0;
168 prop_atoms
[OBT_PROP_NET_WM_STATE_TOGGLE
] = 2;
170 prop_atoms
[OBT_PROP_NET_WM_ORIENTATION_HORZ
] = 0;
171 prop_atoms
[OBT_PROP_NET_WM_ORIENTATION_VERT
] = 1;
172 prop_atoms
[OBT_PROP_NET_WM_TOPLEFT
] = 0;
173 prop_atoms
[OBT_PROP_NET_WM_TOPRIGHT
] = 1;
174 prop_atoms
[OBT_PROP_NET_WM_BOTTOMRIGHT
] = 2;
175 prop_atoms
[OBT_PROP_NET_WM_BOTTOMLEFT
] = 3;
177 CREATE_(KDE_WM_CHANGE_STATE
);
178 CREATE_(KDE_NET_WM_WINDOW_TYPE_OVERRIDE
);
181 CREATE_NAME(ROOTPMAPId, "_XROOTPMAP_ID");
182 CREATE_NAME(ESETROOTId, "ESETROOT_PMAP_ID");
185 CREATE_(OPENBOX_PID
);
187 CREATE_(OB_CONFIG_FILE
);
188 CREATE_(OB_WM_ACTION_UNDECORATE
);
189 CREATE_(OB_WM_STATE_UNDECORATED
);
193 Atom
obt_prop_atom(ObtPropAtom a
)
195 g_assert(prop_started
);
196 g_assert(a
< OBT_PROP_NUM_ATOMS
);
197 return prop_atoms
[a
];
200 static gboolean
get_prealloc(Window win
, Atom prop
, Atom type
, gint size
,
201 guchar
*data
, gulong num
)
203 gboolean ret
= FALSE
;
205 guchar
*xdata
= NULL
;
208 gulong ret_items
, bytes_left
;
209 glong num32
= 32 / size
* num
; /* num in 32-bit elements */
211 res
= XGetWindowProperty(obt_display
, win
, prop
, 0l, num32
,
212 FALSE
, type
, &ret_type
, &ret_size
,
213 &ret_items
, &bytes_left
, &xdata
);
214 if (res
== Success
&& ret_items
&& xdata
) {
215 if (ret_size
== size
&& ret_items
>= num
) {
217 for (i
= 0; i
< num
; ++i
)
223 ((guint16
*)data
)[i
] = ((gushort
*)xdata
)[i
];
226 ((guint32
*)data
)[i
] = ((gulong
*)xdata
)[i
];
229 g_assert_not_reached(); /* unhandled size */
238 static gboolean
get_all(Window win
, Atom prop
, Atom type
, gint size
,
239 guchar
**data
, guint
*num
)
241 gboolean ret
= FALSE
;
243 guchar
*xdata
= NULL
;
246 gulong ret_items
, bytes_left
;
248 res
= XGetWindowProperty(obt_display
, win
, prop
, 0l, G_MAXLONG
,
249 FALSE
, type
, &ret_type
, &ret_size
,
250 &ret_items
, &bytes_left
, &xdata
);
251 if (res
== Success
) {
252 if (ret_size
== size
&& ret_items
> 0) {
255 *data
= g_malloc(ret_items
* (size
/ 8));
256 for (i
= 0; i
< ret_items
; ++i
)
259 (*data
)[i
] = xdata
[i
];
262 ((guint16
*)*data
)[i
] = ((gushort
*)xdata
)[i
];
265 ((guint32
*)*data
)[i
] = ((gulong
*)xdata
)[i
];
268 g_assert_not_reached(); /* unhandled size */
278 static gboolean
get_stringlist(Window win
, Atom prop
, gchar
***list
, gint
*nstr
)
281 gboolean ret
= FALSE
;
283 if (XGetTextProperty(obt_display
, win
, &tprop
, prop
) && tprop
.nitems
) {
284 if (XTextPropertyToStringList(&tprop
, list
, nstr
))
291 gboolean
obt_prop_get32(Window win
, Atom prop
, Atom type
, guint32
*ret
)
293 return get_prealloc(win
, prop
, type
, 32, (guchar
*)ret
, 1);
296 gboolean
obt_prop_get_array32(Window win
, Atom prop
, Atom type
, guint32
**ret
,
299 return get_all(win
, prop
, type
, 32, (guchar
**)ret
, nret
);
302 gboolean
obt_prop_get_string_locale(Window win
, Atom prop
, gchar
**ret
)
308 if (get_stringlist(win
, prop
, &list
, &nstr
) && nstr
) {
309 s
= g_locale_to_utf8(list
[0], -1, NULL
, NULL
, NULL
);
310 XFreeStringList(list
);
319 gboolean
obt_prop_get_strings_locale(Window win
, Atom prop
, gchar
***ret
)
321 GSList
*strs
= NULL
, *it
;
323 guint num
, i
, count
= 0;
325 if (get_all(win
, prop
, OBT_PROP_ATOM(STRING
), 8,
326 (guchar
**)&raw
, &num
))
329 while (p
< raw
+ num
) {
331 strs
= g_slist_append(strs
, p
);
332 p
+= strlen(p
) + 1; /* next string */
335 *ret
= g_new0(gchar
*, count
+ 1);
336 (*ret
)[count
] = NULL
; /* null terminated list */
338 for (i
= 0, it
= strs
; it
; ++i
, it
= g_slist_next(it
)) {
339 (*ret
)[i
] = g_locale_to_utf8(it
->data
, -1, NULL
, NULL
, NULL
);
340 /* make sure translation did not fail */
342 (*ret
)[i
] = g_strdup("");
351 gboolean
obt_prop_get_string_utf8(Window win
, Atom prop
, gchar
**ret
)
357 if (get_all(win
, prop
, OBT_PROP_ATOM(UTF8
), 8,
358 (guchar
**)&raw
, &num
))
360 str
= g_strndup(raw
, num
); /* grab the first string from the list */
362 if (g_utf8_validate(str
, -1, NULL
)) {
371 gboolean
obt_prop_get_strings_utf8(Window win
, Atom prop
, gchar
***ret
)
373 GSList
*strs
= NULL
, *it
;
375 guint num
, i
, count
= 0;
377 if (get_all(win
, prop
, OBT_PROP_ATOM(UTF8
), 8,
378 (guchar
**)&raw
, &num
))
381 while (p
< raw
+ num
) {
383 strs
= g_slist_append(strs
, p
);
384 p
+= strlen(p
) + 1; /* next string */
387 *ret
= g_new0(gchar
*, count
+ 1);
389 for (i
= 0, it
= strs
; it
; ++i
, it
= g_slist_next(it
)) {
390 if (g_utf8_validate(it
->data
, -1, NULL
))
391 (*ret
)[i
] = g_strdup(it
->data
);
393 (*ret
)[i
] = g_strdup("");
402 void obt_prop_set32(Window win
, Atom prop
, Atom type
, gulong val
)
404 XChangeProperty(obt_display
, win
, prop
, type
, 32, PropModeReplace
,
408 void obt_prop_set_array32(Window win
, Atom prop
, Atom type
, gulong
*val
,
411 XChangeProperty(obt_display
, win
, prop
, type
, 32, PropModeReplace
,
415 void obt_prop_set_string_locale(Window win
, Atom prop
, const gchar
*val
)
417 gchar
const *s
[2] = { val
, NULL
};
418 obt_prop_set_strings_locale(win
, prop
, s
);
421 void obt_prop_set_strings_locale(Window win
, Atom prop
, const gchar
**strs
)
427 /* count the strings in strs, and convert them to the locale format */
428 for (count
= 0; strs
[count
]; ++count
);
429 lstrs
= g_new0(char*, count
);
430 for (i
= 0; i
< count
; ++i
) {
431 lstrs
[i
] = g_locale_from_utf8(strs
[i
], -1, NULL
, NULL
, NULL
);
433 lstrs
[i
] = g_strdup(""); /* make it an empty string */
434 g_warning("Unable to translate string '%s' from UTF8 to locale "
440 XStringListToTextProperty(lstrs
, count
, &tprop
);
441 XSetTextProperty(obt_display
, win
, &tprop
, prop
);
445 void obt_prop_set_string_utf8(Window win
, Atom prop
, const gchar
*val
)
447 XChangeProperty(obt_display
, win
, prop
, OBT_PROP_ATOM(UTF8
), 8,
448 PropModeReplace
, (const guchar
*)val
, strlen(val
));
451 void obt_prop_set_strings_utf8(Window win
, Atom prop
, const gchar
**strs
)
456 str
= g_string_sized_new(0);
457 for (s
= strs
; *s
; ++s
) {
458 str
= g_string_append(str
, *s
);
459 str
= g_string_append_c(str
, '\0');
461 XChangeProperty(obt_display
, win
, prop
, obt_prop_atom(OBT_PROP_UTF8
), 8,
462 PropModeReplace
, (guchar
*)str
->str
, str
->len
);
463 g_string_free(str
, TRUE
);
466 void obt_prop_erase(Window win
, Atom prop
)
468 XDeleteProperty(obt_display
, win
, prop
);
471 void obt_prop_message(gint screen
, Window about
, Atom messagetype
,
472 glong data0
, glong data1
, glong data2
, glong data3
,
473 glong data4
, glong mask
)
475 obt_prop_message_to(obt_root(screen
), about
, messagetype
,
476 data0
, data1
, data2
, data3
, data4
, mask
);
479 void obt_prop_message_to(Window to
, Window about
,
481 glong data0
, glong data1
, glong data2
, glong data3
,
482 glong data4
, glong mask
)
485 ce
.xclient
.type
= ClientMessage
;
486 ce
.xclient
.message_type
= messagetype
;
487 ce
.xclient
.display
= obt_display
;
488 ce
.xclient
.window
= about
;
489 ce
.xclient
.format
= 32;
490 ce
.xclient
.data
.l
[0] = data0
;
491 ce
.xclient
.data
.l
[1] = data1
;
492 ce
.xclient
.data
.l
[2] = data2
;
493 ce
.xclient
.data
.l
[3] = data3
;
494 ce
.xclient
.data
.l
[4] = data4
;
495 XSendEvent(obt_display
, to
, FALSE
, mask
, &ce
);