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
);
127 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPLEFT
] = 0;
128 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOP
] = 1;
129 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPRIGHT
] = 2;
130 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_RIGHT
] = 3;
131 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
] = 4;
132 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOM
] = 5;
133 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
] = 6;
134 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_LEFT
] = 7;
135 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_MOVE
] = 8;
136 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_KEYBOARD
] = 9;
137 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_MOVE_KEYBOARD
] = 10;
138 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_CANCEL
] = 11;
140 CREATE_(NET_WM_ACTION_MOVE
);
141 CREATE_(NET_WM_ACTION_RESIZE
);
142 CREATE_(NET_WM_ACTION_MINIMIZE
);
143 CREATE_(NET_WM_ACTION_SHADE
);
144 CREATE_(NET_WM_ACTION_MAXIMIZE_HORZ
);
145 CREATE_(NET_WM_ACTION_MAXIMIZE_VERT
);
146 CREATE_(NET_WM_ACTION_FULLSCREEN
);
147 CREATE_(NET_WM_ACTION_CHANGE_DESKTOP
);
148 CREATE_(NET_WM_ACTION_CLOSE
);
149 CREATE_(NET_WM_ACTION_ABOVE
);
150 CREATE_(NET_WM_ACTION_BELOW
);
152 CREATE_(NET_WM_STATE_MODAL
);
153 /* CREATE_(NET_WM_STATE_STICKY);*/
154 CREATE_(NET_WM_STATE_MAXIMIZED_VERT
);
155 CREATE_(NET_WM_STATE_MAXIMIZED_HORZ
);
156 CREATE_(NET_WM_STATE_SHADED
);
157 CREATE_(NET_WM_STATE_SKIP_TASKBAR
);
158 CREATE_(NET_WM_STATE_SKIP_PAGER
);
159 CREATE_(NET_WM_STATE_HIDDEN
);
160 CREATE_(NET_WM_STATE_FULLSCREEN
);
161 CREATE_(NET_WM_STATE_ABOVE
);
162 CREATE_(NET_WM_STATE_BELOW
);
163 CREATE_(NET_WM_STATE_DEMANDS_ATTENTION
);
165 prop_atoms
[OBT_PROP_NET_WM_STATE_ADD
] = 1;
166 prop_atoms
[OBT_PROP_NET_WM_STATE_REMOVE
] = 0;
167 prop_atoms
[OBT_PROP_NET_WM_STATE_TOGGLE
] = 2;
169 prop_atoms
[OBT_PROP_NET_WM_ORIENTATION_HORZ
] = 0;
170 prop_atoms
[OBT_PROP_NET_WM_ORIENTATION_VERT
] = 1;
171 prop_atoms
[OBT_PROP_NET_WM_TOPLEFT
] = 0;
172 prop_atoms
[OBT_PROP_NET_WM_TOPRIGHT
] = 1;
173 prop_atoms
[OBT_PROP_NET_WM_BOTTOMRIGHT
] = 2;
174 prop_atoms
[OBT_PROP_NET_WM_BOTTOMLEFT
] = 3;
176 CREATE_(KDE_WM_CHANGE_STATE
);
177 CREATE_(KDE_NET_WM_WINDOW_TYPE_OVERRIDE
);
180 CREATE_NAME(ROOTPMAPId, "_XROOTPMAP_ID");
181 CREATE_NAME(ESETROOTId, "ESETROOT_PMAP_ID");
184 CREATE_(OPENBOX_PID
);
186 CREATE_(OB_WM_ACTION_UNDECORATE
);
187 CREATE_(OB_WM_STATE_UNDECORATED
);
191 Atom
obt_prop_atom(ObtPropAtom a
)
193 g_assert(prop_started
);
194 g_assert(a
< OBT_PROP_NUM_ATOMS
);
195 return prop_atoms
[a
];
198 static gboolean
get_prealloc(Window win
, Atom prop
, Atom type
, gint size
,
199 guchar
*data
, gulong num
)
201 gboolean ret
= FALSE
;
203 guchar
*xdata
= NULL
;
206 gulong ret_items
, bytes_left
;
207 glong num32
= 32 / size
* num
; /* num in 32-bit elements */
209 res
= XGetWindowProperty(obt_display
, win
, prop
, 0l, num32
,
210 FALSE
, type
, &ret_type
, &ret_size
,
211 &ret_items
, &bytes_left
, &xdata
);
212 if (res
== Success
&& ret_items
&& xdata
) {
213 if (ret_size
== size
&& ret_items
>= num
) {
215 for (i
= 0; i
< num
; ++i
)
221 ((guint16
*)data
)[i
] = ((gushort
*)xdata
)[i
];
224 ((guint32
*)data
)[i
] = ((gulong
*)xdata
)[i
];
227 g_assert_not_reached(); /* unhandled size */
236 static gboolean
get_all(Window win
, Atom prop
, Atom type
, gint size
,
237 guchar
**data
, guint
*num
)
239 gboolean ret
= FALSE
;
241 guchar
*xdata
= NULL
;
244 gulong ret_items
, bytes_left
;
246 res
= XGetWindowProperty(obt_display
, win
, prop
, 0l, G_MAXLONG
,
247 FALSE
, type
, &ret_type
, &ret_size
,
248 &ret_items
, &bytes_left
, &xdata
);
249 if (res
== Success
) {
250 if (ret_size
== size
&& ret_items
> 0) {
253 *data
= g_malloc(ret_items
* (size
/ 8));
254 for (i
= 0; i
< ret_items
; ++i
)
257 (*data
)[i
] = xdata
[i
];
260 ((guint16
*)*data
)[i
] = ((gushort
*)xdata
)[i
];
263 ((guint32
*)*data
)[i
] = ((gulong
*)xdata
)[i
];
266 g_assert_not_reached(); /* unhandled size */
276 static gboolean
get_stringlist(Window win
, Atom prop
, gchar
***list
, gint
*nstr
)
279 gboolean ret
= FALSE
;
281 if (XGetTextProperty(obt_display
, win
, &tprop
, prop
) && tprop
.nitems
) {
282 if (XTextPropertyToStringList(&tprop
, list
, nstr
))
289 gboolean
obt_prop_get32(Window win
, Atom prop
, Atom type
, guint32
*ret
)
291 return get_prealloc(win
, prop
, type
, 32, (guchar
*)ret
, 1);
294 gboolean
obt_prop_get_array32(Window win
, Atom prop
, Atom type
, guint32
**ret
,
297 return get_all(win
, prop
, type
, 32, (guchar
**)ret
, nret
);
300 gboolean
obt_prop_get_string_locale(Window win
, Atom prop
, gchar
**ret
)
306 if (get_stringlist(win
, prop
, &list
, &nstr
) && nstr
) {
307 s
= g_locale_to_utf8(list
[0], -1, NULL
, NULL
, NULL
);
308 XFreeStringList(list
);
317 gboolean
obt_prop_get_strings_locale(Window win
, Atom prop
, gchar
***ret
)
319 GSList
*strs
= NULL
, *it
;
321 guint num
, i
, count
= 0;
323 if (get_all(win
, prop
, OBT_PROP_ATOM(STRING
), 8,
324 (guchar
**)&raw
, &num
))
327 while (p
< raw
+ num
) {
329 strs
= g_slist_append(strs
, p
);
330 p
+= strlen(p
) + 1; /* next string */
333 *ret
= g_new0(gchar
*, count
+ 1);
334 (*ret
)[count
] = NULL
; /* null terminated list */
336 for (i
= 0, it
= strs
; it
; ++i
, it
= g_slist_next(it
)) {
337 (*ret
)[i
] = g_locale_to_utf8(it
->data
, -1, NULL
, NULL
, NULL
);
338 /* make sure translation did not fail */
340 (*ret
)[i
] = g_strdup("");
349 gboolean
obt_prop_get_string_utf8(Window win
, Atom prop
, gchar
**ret
)
355 if (get_all(win
, prop
, OBT_PROP_ATOM(UTF8
), 8,
356 (guchar
**)&raw
, &num
))
358 str
= g_strndup(raw
, num
); /* grab the first string from the list */
360 if (g_utf8_validate(str
, -1, NULL
)) {
369 gboolean
obt_prop_get_strings_utf8(Window win
, Atom prop
, gchar
***ret
)
371 GSList
*strs
= NULL
, *it
;
373 guint num
, i
, count
= 0;
375 if (get_all(win
, prop
, OBT_PROP_ATOM(UTF8
), 8,
376 (guchar
**)&raw
, &num
))
379 while (p
< raw
+ num
) {
381 strs
= g_slist_append(strs
, p
);
382 p
+= strlen(p
) + 1; /* next string */
385 *ret
= g_new0(gchar
*, count
+ 1);
387 for (i
= 0, it
= strs
; it
; ++i
, it
= g_slist_next(it
)) {
388 if (g_utf8_validate(it
->data
, -1, NULL
))
389 (*ret
)[i
] = g_strdup(it
->data
);
391 (*ret
)[i
] = g_strdup("");
400 void obt_prop_set32(Window win
, Atom prop
, Atom type
, gulong val
)
402 XChangeProperty(obt_display
, win
, prop
, type
, 32, PropModeReplace
,
406 void obt_prop_set_array32(Window win
, Atom prop
, Atom type
, gulong
*val
,
409 XChangeProperty(obt_display
, win
, prop
, type
, 32, PropModeReplace
,
413 void obt_prop_set_string_locale(Window win
, Atom prop
, const gchar
*val
)
415 gchar
const *s
[2] = { val
, NULL
};
416 obt_prop_set_strings_locale(win
, prop
, s
);
419 void obt_prop_set_strings_locale(Window win
, Atom prop
, const gchar
**strs
)
425 /* count the strings in strs, and convert them to the locale format */
426 for (count
= 0; strs
[count
]; ++count
);
427 lstrs
= g_new0(char*, count
);
428 for (i
= 0; i
< count
; ++i
) {
429 lstrs
[i
] = g_locale_from_utf8(strs
[i
], -1, NULL
, NULL
, NULL
);
431 lstrs
[i
] = g_strdup(""); /* make it an empty string */
432 g_warning("Unable to translate string '%s' from UTF8 to locale "
438 XStringListToTextProperty(lstrs
, count
, &tprop
);
439 XSetTextProperty(obt_display
, win
, &tprop
, prop
);
443 void obt_prop_set_string_utf8(Window win
, Atom prop
, const gchar
*val
)
445 XChangeProperty(obt_display
, win
, prop
, OBT_PROP_ATOM(UTF8
), 8,
446 PropModeReplace
, (const guchar
*)val
, strlen(val
));
449 void obt_prop_set_strings_utf8(Window win
, Atom prop
, const gchar
**strs
)
454 str
= g_string_sized_new(0);
455 for (s
= strs
; *s
; ++s
) {
456 str
= g_string_append(str
, *s
);
457 str
= g_string_append_c(str
, '\0');
459 XChangeProperty(obt_display
, win
, prop
, obt_prop_atom(OBT_PROP_UTF8
), 8,
460 PropModeReplace
, (guchar
*)str
->str
, str
->len
);
461 g_string_free(str
, TRUE
);
464 void obt_prop_erase(Window win
, Atom prop
)
466 XDeleteProperty(obt_display
, win
, prop
);
469 void obt_prop_message(gint screen
, Window about
, Atom messagetype
,
470 glong data0
, glong data1
, glong data2
, glong data3
,
471 glong data4
, glong mask
)
473 obt_prop_message_to(obt_root(screen
), about
, messagetype
,
474 data0
, data1
, data2
, data3
, data4
, mask
);
477 void obt_prop_message_to(Window to
, Window about
,
479 glong data0
, glong data1
, glong data2
, glong data3
,
480 glong data4
, glong mask
)
483 ce
.xclient
.type
= ClientMessage
;
484 ce
.xclient
.message_type
= messagetype
;
485 ce
.xclient
.display
= obt_display
;
486 ce
.xclient
.window
= about
;
487 ce
.xclient
.format
= 32;
488 ce
.xclient
.data
.l
[0] = data0
;
489 ce
.xclient
.data
.l
[1] = data1
;
490 ce
.xclient
.data
.l
[2] = data2
;
491 ce
.xclient
.data
.l
[3] = data3
;
492 ce
.xclient
.data
.l
[4] = data4
;
493 XSendEvent(obt_display
, to
, FALSE
, mask
, &ce
);