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_CONFIG_FILE
);
187 CREATE_(OB_WM_ACTION_UNDECORATE
);
188 CREATE_(OB_WM_STATE_UNDECORATED
);
192 Atom
obt_prop_atom(ObtPropAtom a
)
194 g_assert(prop_started
);
195 g_assert(a
< OBT_PROP_NUM_ATOMS
);
196 return prop_atoms
[a
];
199 static gboolean
get_prealloc(Window win
, Atom prop
, Atom type
, gint size
,
200 guchar
*data
, gulong num
)
202 gboolean ret
= FALSE
;
204 guchar
*xdata
= NULL
;
207 gulong ret_items
, bytes_left
;
208 glong num32
= 32 / size
* num
; /* num in 32-bit elements */
210 res
= XGetWindowProperty(obt_display
, win
, prop
, 0l, num32
,
211 FALSE
, type
, &ret_type
, &ret_size
,
212 &ret_items
, &bytes_left
, &xdata
);
213 if (res
== Success
&& ret_items
&& xdata
) {
214 if (ret_size
== size
&& ret_items
>= num
) {
216 for (i
= 0; i
< num
; ++i
)
222 ((guint16
*)data
)[i
] = ((gushort
*)xdata
)[i
];
225 ((guint32
*)data
)[i
] = ((gulong
*)xdata
)[i
];
228 g_assert_not_reached(); /* unhandled size */
237 static gboolean
get_all(Window win
, Atom prop
, Atom type
, gint size
,
238 guchar
**data
, guint
*num
)
240 gboolean ret
= FALSE
;
242 guchar
*xdata
= NULL
;
245 gulong ret_items
, bytes_left
;
247 res
= XGetWindowProperty(obt_display
, win
, prop
, 0l, G_MAXLONG
,
248 FALSE
, type
, &ret_type
, &ret_size
,
249 &ret_items
, &bytes_left
, &xdata
);
250 if (res
== Success
) {
251 if (ret_size
== size
&& ret_items
> 0) {
254 *data
= g_malloc(ret_items
* (size
/ 8));
255 for (i
= 0; i
< ret_items
; ++i
)
258 (*data
)[i
] = xdata
[i
];
261 ((guint16
*)*data
)[i
] = ((gushort
*)xdata
)[i
];
264 ((guint32
*)*data
)[i
] = ((gulong
*)xdata
)[i
];
267 g_assert_not_reached(); /* unhandled size */
277 static gboolean
get_stringlist(Window win
, Atom prop
, gchar
***list
, gint
*nstr
)
280 gboolean ret
= FALSE
;
282 if (XGetTextProperty(obt_display
, win
, &tprop
, prop
) && tprop
.nitems
) {
283 if (XTextPropertyToStringList(&tprop
, list
, nstr
))
290 gboolean
obt_prop_get32(Window win
, Atom prop
, Atom type
, guint32
*ret
)
292 return get_prealloc(win
, prop
, type
, 32, (guchar
*)ret
, 1);
295 gboolean
obt_prop_get_array32(Window win
, Atom prop
, Atom type
, guint32
**ret
,
298 return get_all(win
, prop
, type
, 32, (guchar
**)ret
, nret
);
301 gboolean
obt_prop_get_string_locale(Window win
, Atom prop
, gchar
**ret
)
307 if (get_stringlist(win
, prop
, &list
, &nstr
) && nstr
) {
308 s
= g_locale_to_utf8(list
[0], -1, NULL
, NULL
, NULL
);
309 XFreeStringList(list
);
318 gboolean
obt_prop_get_strings_locale(Window win
, Atom prop
, gchar
***ret
)
320 GSList
*strs
= NULL
, *it
;
322 guint num
, i
, count
= 0;
324 if (get_all(win
, prop
, OBT_PROP_ATOM(STRING
), 8,
325 (guchar
**)&raw
, &num
))
328 while (p
< raw
+ num
) {
330 strs
= g_slist_append(strs
, p
);
331 p
+= strlen(p
) + 1; /* next string */
334 *ret
= g_new0(gchar
*, count
+ 1);
335 (*ret
)[count
] = NULL
; /* null terminated list */
337 for (i
= 0, it
= strs
; it
; ++i
, it
= g_slist_next(it
)) {
338 (*ret
)[i
] = g_locale_to_utf8(it
->data
, -1, NULL
, NULL
, NULL
);
339 /* make sure translation did not fail */
341 (*ret
)[i
] = g_strdup("");
350 gboolean
obt_prop_get_string_utf8(Window win
, Atom prop
, gchar
**ret
)
356 if (get_all(win
, prop
, OBT_PROP_ATOM(UTF8
), 8,
357 (guchar
**)&raw
, &num
))
359 str
= g_strndup(raw
, num
); /* grab the first string from the list */
361 if (g_utf8_validate(str
, -1, NULL
)) {
370 gboolean
obt_prop_get_strings_utf8(Window win
, Atom prop
, gchar
***ret
)
372 GSList
*strs
= NULL
, *it
;
374 guint num
, i
, count
= 0;
376 if (get_all(win
, prop
, OBT_PROP_ATOM(UTF8
), 8,
377 (guchar
**)&raw
, &num
))
380 while (p
< raw
+ num
) {
382 strs
= g_slist_append(strs
, p
);
383 p
+= strlen(p
) + 1; /* next string */
386 *ret
= g_new0(gchar
*, count
+ 1);
388 for (i
= 0, it
= strs
; it
; ++i
, it
= g_slist_next(it
)) {
389 if (g_utf8_validate(it
->data
, -1, NULL
))
390 (*ret
)[i
] = g_strdup(it
->data
);
392 (*ret
)[i
] = g_strdup("");
401 void obt_prop_set32(Window win
, Atom prop
, Atom type
, gulong val
)
403 XChangeProperty(obt_display
, win
, prop
, type
, 32, PropModeReplace
,
407 void obt_prop_set_array32(Window win
, Atom prop
, Atom type
, gulong
*val
,
410 XChangeProperty(obt_display
, win
, prop
, type
, 32, PropModeReplace
,
414 void obt_prop_set_string_locale(Window win
, Atom prop
, const gchar
*val
)
416 gchar
const *s
[2] = { val
, NULL
};
417 obt_prop_set_strings_locale(win
, prop
, s
);
420 void obt_prop_set_strings_locale(Window win
, Atom prop
, const gchar
**strs
)
426 /* count the strings in strs, and convert them to the locale format */
427 for (count
= 0; strs
[count
]; ++count
);
428 lstrs
= g_new0(char*, count
);
429 for (i
= 0; i
< count
; ++i
) {
430 lstrs
[i
] = g_locale_from_utf8(strs
[i
], -1, NULL
, NULL
, NULL
);
432 lstrs
[i
] = g_strdup(""); /* make it an empty string */
433 g_warning("Unable to translate string '%s' from UTF8 to locale "
439 XStringListToTextProperty(lstrs
, count
, &tprop
);
440 XSetTextProperty(obt_display
, win
, &tprop
, prop
);
444 void obt_prop_set_string_utf8(Window win
, Atom prop
, const gchar
*val
)
446 XChangeProperty(obt_display
, win
, prop
, OBT_PROP_ATOM(UTF8
), 8,
447 PropModeReplace
, (const guchar
*)val
, strlen(val
));
450 void obt_prop_set_strings_utf8(Window win
, Atom prop
, const gchar
**strs
)
455 str
= g_string_sized_new(0);
456 for (s
= strs
; *s
; ++s
) {
457 str
= g_string_append(str
, *s
);
458 str
= g_string_append_c(str
, '\0');
460 XChangeProperty(obt_display
, win
, prop
, obt_prop_atom(OBT_PROP_UTF8
), 8,
461 PropModeReplace
, (guchar
*)str
->str
, str
->len
);
462 g_string_free(str
, TRUE
);
465 void obt_prop_erase(Window win
, Atom prop
)
467 XDeleteProperty(obt_display
, win
, prop
);
470 void obt_prop_message(gint screen
, Window about
, Atom messagetype
,
471 glong data0
, glong data1
, glong data2
, glong data3
,
472 glong data4
, glong mask
)
474 obt_prop_message_to(obt_root(screen
), about
, messagetype
,
475 data0
, data1
, data2
, data3
, data4
, mask
);
478 void obt_prop_message_to(Window to
, Window about
,
480 glong data0
, glong data1
, glong data2
, glong data3
,
481 glong data4
, glong mask
)
484 ce
.xclient
.type
= ClientMessage
;
485 ce
.xclient
.message_type
= messagetype
;
486 ce
.xclient
.display
= obt_display
;
487 ce
.xclient
.window
= about
;
488 ce
.xclient
.format
= 32;
489 ce
.xclient
.data
.l
[0] = data0
;
490 ce
.xclient
.data
.l
[1] = data1
;
491 ce
.xclient
.data
.l
[2] = data2
;
492 ce
.xclient
.data
.l
[3] = data3
;
493 ce
.xclient
.data
.l
[4] = data4
;
494 XSendEvent(obt_display
, to
, FALSE
, mask
, &ce
);