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(var, name) (prop_atoms[OBT_PROP_##var] = \
32 XInternAtom((obt_display), (name), FALSE))
34 void obt_prop_startup()
36 if (prop_started
) return;
39 g_assert(obt_display
);
41 CREATE(CARDINAL
, "CARDINAL");
42 CREATE(WINDOW
, "WINDOW");
43 CREATE(PIXMAP
, "PIXMAP");
45 CREATE(STRING
, "STRING");
46 CREATE(UTF8
, "UTF8_STRING");
48 CREATE(MANAGER
, "MANAGER");
50 CREATE(WM_COLORMAP_WINDOWS
, "WM_COLORMAP_WINDOWS");
51 CREATE(WM_PROTOCOLS
, "WM_PROTOCOLS");
52 CREATE(WM_STATE
, "WM_STATE");
53 CREATE(WM_CHANGE_STATE
, "WM_CHANGE_STATE");
54 CREATE(WM_DELETE_WINDOW
, "WM_DELETE_WINDOW");
55 CREATE(WM_TAKE_FOCUS
, "WM_TAKE_FOCUS");
56 CREATE(WM_NAME
, "WM_NAME");
57 CREATE(WM_ICON_NAME
, "WM_ICON_NAME");
58 CREATE(WM_CLASS
, "WM_CLASS");
59 CREATE(WM_WINDOW_ROLE
, "WM_WINDOW_ROLE");
60 CREATE(WM_CLIENT_MACHINE
, "WM_CLIENT_MACHINE");
61 CREATE(WM_COMMAND
, "WM_COMMAND");
62 CREATE(WM_CLIENT_LEADER
, "WM_CLIENT_LEADER");
63 CREATE(MOTIF_WM_HINTS
, "_MOTIF_WM_HINTS");
65 CREATE(SM_CLIENT_ID
, "SM_CLIENT_ID");
67 CREATE(NET_WM_FULL_PLACEMENT
, "_NET_WM_FULL_PLACEMENT");
69 CREATE(NET_SUPPORTED
, "_NET_SUPPORTED");
70 CREATE(NET_CLIENT_LIST
, "_NET_CLIENT_LIST");
71 CREATE(NET_CLIENT_LIST_STACKING
, "_NET_CLIENT_LIST_STACKING");
72 CREATE(NET_NUMBER_OF_DESKTOPS
, "_NET_NUMBER_OF_DESKTOPS");
73 CREATE(NET_DESKTOP_GEOMETRY
, "_NET_DESKTOP_GEOMETRY");
74 CREATE(NET_DESKTOP_VIEWPORT
, "_NET_DESKTOP_VIEWPORT");
75 CREATE(NET_CURRENT_DESKTOP
, "_NET_CURRENT_DESKTOP");
76 CREATE(NET_DESKTOP_NAMES
, "_NET_DESKTOP_NAMES");
77 CREATE(NET_ACTIVE_WINDOW
, "_NET_ACTIVE_WINDOW");
78 /* CREATE(NET_RESTACK_WINDOW, "_NET_RESTACK_WINDOW");*/
79 CREATE(NET_WORKAREA
, "_NET_WORKAREA");
80 CREATE(NET_SUPPORTING_WM_CHECK
, "_NET_SUPPORTING_WM_CHECK");
81 CREATE(NET_DESKTOP_LAYOUT
, "_NET_DESKTOP_LAYOUT");
82 CREATE(NET_SHOWING_DESKTOP
, "_NET_SHOWING_DESKTOP");
84 CREATE(NET_CLOSE_WINDOW
, "_NET_CLOSE_WINDOW");
85 CREATE(NET_WM_MOVERESIZE
, "_NET_WM_MOVERESIZE");
86 CREATE(NET_MOVERESIZE_WINDOW
, "_NET_MOVERESIZE_WINDOW");
87 CREATE(NET_REQUEST_FRAME_EXTENTS
, "_NET_REQUEST_FRAME_EXTENTS");
88 CREATE(NET_RESTACK_WINDOW
, "_NET_RESTACK_WINDOW");
90 CREATE(NET_STARTUP_ID
, "_NET_STARTUP_ID");
92 CREATE(NET_WM_NAME
, "_NET_WM_NAME");
93 CREATE(NET_WM_VISIBLE_NAME
, "_NET_WM_VISIBLE_NAME");
94 CREATE(NET_WM_ICON_NAME
, "_NET_WM_ICON_NAME");
95 CREATE(NET_WM_VISIBLE_ICON_NAME
, "_NET_WM_VISIBLE_ICON_NAME");
96 CREATE(NET_WM_DESKTOP
, "_NET_WM_DESKTOP");
97 CREATE(NET_WM_WINDOW_TYPE
, "_NET_WM_WINDOW_TYPE");
98 CREATE(NET_WM_STATE
, "_NET_WM_STATE");
99 CREATE(NET_WM_STRUT
, "_NET_WM_STRUT");
100 CREATE(NET_WM_STRUT_PARTIAL
, "_NET_WM_STRUT_PARTIAL");
101 CREATE(NET_WM_ICON
, "_NET_WM_ICON");
102 CREATE(NET_WM_ICON_GEOMETRY
, "_NET_WM_ICON_GEOMETRY");
103 CREATE(NET_WM_PID
, "_NET_WM_PID");
104 CREATE(NET_WM_ALLOWED_ACTIONS
, "_NET_WM_ALLOWED_ACTIONS");
105 CREATE(NET_WM_USER_TIME
, "_NET_WM_USER_TIME");
106 /* CREATE(NET_WM_USER_TIME_WINDOW, "_NET_WM_USER_TIME_WINDOW"); */
107 CREATE(KDE_NET_WM_FRAME_STRUT
, "_KDE_NET_WM_FRAME_STRUT");
108 CREATE(NET_FRAME_EXTENTS
, "_NET_FRAME_EXTENTS");
110 CREATE(NET_WM_PING
, "_NET_WM_PING");
112 CREATE(NET_WM_SYNC_REQUEST
, "_NET_WM_SYNC_REQUEST");
113 CREATE(NET_WM_SYNC_REQUEST_COUNTER
, "_NET_WM_SYNC_REQUEST_COUNTER");
116 CREATE(NET_WM_WINDOW_TYPE_DESKTOP
, "_NET_WM_WINDOW_TYPE_DESKTOP");
117 CREATE(NET_WM_WINDOW_TYPE_DOCK
, "_NET_WM_WINDOW_TYPE_DOCK");
118 CREATE(NET_WM_WINDOW_TYPE_TOOLBAR
, "_NET_WM_WINDOW_TYPE_TOOLBAR");
119 CREATE(NET_WM_WINDOW_TYPE_MENU
, "_NET_WM_WINDOW_TYPE_MENU");
120 CREATE(NET_WM_WINDOW_TYPE_UTILITY
, "_NET_WM_WINDOW_TYPE_UTILITY");
121 CREATE(NET_WM_WINDOW_TYPE_SPLASH
, "_NET_WM_WINDOW_TYPE_SPLASH");
122 CREATE(NET_WM_WINDOW_TYPE_DIALOG
, "_NET_WM_WINDOW_TYPE_DIALOG");
123 CREATE(NET_WM_WINDOW_TYPE_NORMAL
, "_NET_WM_WINDOW_TYPE_NORMAL");
125 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPLEFT
] = 0;
126 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOP
] = 1;
127 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPRIGHT
] = 2;
128 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_RIGHT
] = 3;
129 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
] = 4;
130 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOM
] = 5;
131 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
] = 6;
132 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_LEFT
] = 7;
133 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_MOVE
] = 8;
134 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_SIZE_KEYBOARD
] = 9;
135 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_MOVE_KEYBOARD
] = 10;
136 prop_atoms
[OBT_PROP_NET_WM_MOVERESIZE_CANCEL
] = 11;
138 CREATE(NET_WM_ACTION_MOVE
, "_NET_WM_ACTION_MOVE");
139 CREATE(NET_WM_ACTION_RESIZE
, "_NET_WM_ACTION_RESIZE");
140 CREATE(NET_WM_ACTION_MINIMIZE
, "_NET_WM_ACTION_MINIMIZE");
141 CREATE(NET_WM_ACTION_SHADE
, "_NET_WM_ACTION_SHADE");
142 CREATE(NET_WM_ACTION_MAXIMIZE_HORZ
, "_NET_WM_ACTION_MAXIMIZE_HORZ");
143 CREATE(NET_WM_ACTION_MAXIMIZE_VERT
, "_NET_WM_ACTION_MAXIMIZE_VERT");
144 CREATE(NET_WM_ACTION_FULLSCREEN
, "_NET_WM_ACTION_FULLSCREEN");
145 CREATE(NET_WM_ACTION_CHANGE_DESKTOP
, "_NET_WM_ACTION_CHANGE_DESKTOP");
146 CREATE(NET_WM_ACTION_CLOSE
, "_NET_WM_ACTION_CLOSE");
147 CREATE(NET_WM_ACTION_ABOVE
, "_NET_WM_ACTION_ABOVE");
148 CREATE(NET_WM_ACTION_BELOW
, "_NET_WM_ACTION_BELOW");
150 CREATE(NET_WM_STATE_MODAL
, "_NET_WM_STATE_MODAL");
151 /* CREATE(NET_WM_STATE_STICKY, "_NET_WM_STATE_STICKY");*/
152 CREATE(NET_WM_STATE_MAXIMIZED_VERT
, "_NET_WM_STATE_MAXIMIZED_VERT");
153 CREATE(NET_WM_STATE_MAXIMIZED_HORZ
, "_NET_WM_STATE_MAXIMIZED_HORZ");
154 CREATE(NET_WM_STATE_SHADED
, "_NET_WM_STATE_SHADED");
155 CREATE(NET_WM_STATE_SKIP_TASKBAR
, "_NET_WM_STATE_SKIP_TASKBAR");
156 CREATE(NET_WM_STATE_SKIP_PAGER
, "_NET_WM_STATE_SKIP_PAGER");
157 CREATE(NET_WM_STATE_HIDDEN
, "_NET_WM_STATE_HIDDEN");
158 CREATE(NET_WM_STATE_FULLSCREEN
, "_NET_WM_STATE_FULLSCREEN");
159 CREATE(NET_WM_STATE_ABOVE
, "_NET_WM_STATE_ABOVE");
160 CREATE(NET_WM_STATE_BELOW
, "_NET_WM_STATE_BELOW");
161 CREATE(NET_WM_STATE_DEMANDS_ATTENTION
, "_NET_WM_STATE_DEMANDS_ATTENTION");
163 prop_atoms
[OBT_PROP_NET_WM_STATE_ADD
] = 1;
164 prop_atoms
[OBT_PROP_NET_WM_STATE_REMOVE
] = 0;
165 prop_atoms
[OBT_PROP_NET_WM_STATE_TOGGLE
] = 2;
167 prop_atoms
[OBT_PROP_NET_WM_ORIENTATION_HORZ
] = 0;
168 prop_atoms
[OBT_PROP_NET_WM_ORIENTATION_VERT
] = 1;
169 prop_atoms
[OBT_PROP_NET_WM_TOPLEFT
] = 0;
170 prop_atoms
[OBT_PROP_NET_WM_TOPRIGHT
] = 1;
171 prop_atoms
[OBT_PROP_NET_WM_BOTTOMRIGHT
] = 2;
172 prop_atoms
[OBT_PROP_NET_WM_BOTTOMLEFT
] = 3;
174 CREATE(KDE_WM_CHANGE_STATE
, "_KDE_WM_CHANGE_STATE");
175 CREATE(KDE_NET_WM_WINDOW_TYPE_OVERRIDE
,"_KDE_NET_WM_WINDOW_TYPE_OVERRIDE");
178 CREATE(ROOTPMAPId, "_XROOTPMAP_ID");
179 CREATE(ESETROOTId, "ESETROOT_PMAP_ID");
182 CREATE(OPENBOX_PID
, "_OPENBOX_PID");
183 CREATE(OB_THEME
, "_OB_THEME");
184 CREATE(OB_WM_ACTION_UNDECORATE
, "_OB_WM_ACTION_UNDECORATE");
185 CREATE(OB_WM_STATE_UNDECORATED
, "_OB_WM_STATE_UNDECORATED");
186 CREATE(OB_CONTROL
, "_OB_CONTROL");
189 Atom
obt_prop_atom(ObtPropAtom a
)
191 g_assert(prop_started
);
192 g_assert(a
< OBT_PROP_NUM_ATOMS
);
193 return prop_atoms
[a
];
196 static gboolean
get_prealloc(Window win
, Atom prop
, Atom type
, gint size
,
197 guchar
*data
, gulong num
)
199 gboolean ret
= FALSE
;
201 guchar
*xdata
= NULL
;
204 gulong ret_items
, bytes_left
;
205 glong num32
= 32 / size
* num
; /* num in 32-bit elements */
207 res
= XGetWindowProperty(obt_display
, win
, prop
, 0l, num32
,
208 FALSE
, type
, &ret_type
, &ret_size
,
209 &ret_items
, &bytes_left
, &xdata
);
210 if (res
== Success
&& ret_items
&& xdata
) {
211 if (ret_size
== size
&& ret_items
>= num
) {
213 for (i
= 0; i
< num
; ++i
)
219 ((guint16
*)data
)[i
] = ((gushort
*)xdata
)[i
];
222 ((guint32
*)data
)[i
] = ((gulong
*)xdata
)[i
];
225 g_assert_not_reached(); /* unhandled size */
234 static gboolean
get_all(Window win
, Atom prop
, Atom type
, gint size
,
235 guchar
**data
, guint
*num
)
237 gboolean ret
= FALSE
;
239 guchar
*xdata
= NULL
;
242 gulong ret_items
, bytes_left
;
244 res
= XGetWindowProperty(obt_display
, win
, prop
, 0l, G_MAXLONG
,
245 FALSE
, type
, &ret_type
, &ret_size
,
246 &ret_items
, &bytes_left
, &xdata
);
247 if (res
== Success
) {
248 if (ret_size
== size
&& ret_items
> 0) {
251 *data
= g_malloc(ret_items
* (size
/ 8));
252 for (i
= 0; i
< ret_items
; ++i
)
255 (*data
)[i
] = xdata
[i
];
258 ((guint16
*)*data
)[i
] = ((gushort
*)xdata
)[i
];
261 ((guint32
*)*data
)[i
] = ((gulong
*)xdata
)[i
];
264 g_assert_not_reached(); /* unhandled size */
274 static gboolean
get_stringlist(Window win
, Atom prop
, gchar
***list
, gint
*nstr
)
277 gboolean ret
= FALSE
;
279 if (XGetTextProperty(obt_display
, win
, &tprop
, prop
) && tprop
.nitems
) {
280 if (XTextPropertyToStringList(&tprop
, list
, nstr
))
287 gboolean
obt_prop_get32(Window win
, Atom prop
, Atom type
, guint32
*ret
)
289 return get_prealloc(win
, prop
, type
, 32, (guchar
*)ret
, 1);
292 gboolean
obt_prop_get_array32(Window win
, Atom prop
, Atom type
, guint32
**ret
,
295 return get_all(win
, prop
, type
, 32, (guchar
**)ret
, nret
);
298 gboolean
obt_prop_get_string_locale(Window win
, Atom prop
, gchar
**ret
)
304 if (get_stringlist(win
, prop
, &list
, &nstr
) && nstr
) {
305 s
= g_locale_to_utf8(list
[0], -1, NULL
, NULL
, NULL
);
306 XFreeStringList(list
);
315 gboolean
obt_prop_get_strings_locale(Window win
, Atom prop
, gchar
***ret
)
317 GSList
*strs
= NULL
, *it
;
319 guint num
, i
, count
= 0;
321 if (get_all(win
, prop
, OBT_PROP_ATOM(STRING
), 8,
322 (guchar
**)&raw
, &num
))
325 while (p
< raw
+ num
) {
327 strs
= g_slist_append(strs
, p
);
328 p
+= strlen(p
) + 1; /* next string */
331 *ret
= g_new0(gchar
*, count
+ 1);
332 (*ret
)[count
] = NULL
; /* null terminated list */
334 for (i
= 0, it
= strs
; it
; ++i
, it
= g_slist_next(it
)) {
335 (*ret
)[i
] = g_locale_to_utf8(it
->data
, -1, NULL
, NULL
, NULL
);
336 /* make sure translation did not fail */
338 (*ret
)[i
] = g_strdup("");
347 gboolean
obt_prop_get_string_utf8(Window win
, Atom prop
, gchar
**ret
)
353 if (get_all(win
, prop
, OBT_PROP_ATOM(UTF8
), 8,
354 (guchar
**)&raw
, &num
))
356 str
= g_strndup(raw
, num
); /* grab the first string from the list */
358 if (g_utf8_validate(str
, -1, NULL
)) {
367 gboolean
obt_prop_get_strings_utf8(Window win
, Atom prop
, gchar
***ret
)
369 GSList
*strs
= NULL
, *it
;
371 guint num
, i
, count
= 0;
373 if (get_all(win
, prop
, OBT_PROP_ATOM(UTF8
), 8,
374 (guchar
**)&raw
, &num
))
377 while (p
< raw
+ num
) {
379 strs
= g_slist_append(strs
, p
);
380 p
+= strlen(p
) + 1; /* next string */
383 *ret
= g_new0(gchar
*, count
+ 1);
385 for (i
= 0, it
= strs
; it
; ++i
, it
= g_slist_next(it
)) {
386 if (g_utf8_validate(it
->data
, -1, NULL
))
387 (*ret
)[i
] = g_strdup(it
->data
);
389 (*ret
)[i
] = g_strdup("");
398 void obt_prop_set32(Window win
, Atom prop
, Atom type
, gulong val
)
400 XChangeProperty(obt_display
, win
, prop
, type
, 32, PropModeReplace
,
404 void obt_prop_set_array32(Window win
, Atom prop
, Atom type
, gulong
*val
,
407 XChangeProperty(obt_display
, win
, prop
, type
, 32, PropModeReplace
,
411 void obt_prop_set_string_locale(Window win
, Atom prop
, const gchar
*val
)
413 gchar
const *s
[2] = { val
, NULL
};
414 obt_prop_set_strings_locale(win
, prop
, s
);
417 void obt_prop_set_strings_locale(Window win
, Atom prop
, const gchar
**strs
)
423 /* count the strings in strs, and convert them to the locale format */
424 for (count
= 0; strs
[count
]; ++count
);
425 lstrs
= g_new0(char*, count
);
426 for (i
= 0; i
< count
; ++i
) {
427 lstrs
[i
] = g_locale_from_utf8(strs
[i
], -1, NULL
, NULL
, NULL
);
429 lstrs
[i
] = g_strdup(""); /* make it an empty string */
430 g_warning("Unable to translate string '%s' from UTF8 to locale "
436 XStringListToTextProperty(lstrs
, count
, &tprop
);
437 XSetTextProperty(obt_display
, win
, &tprop
, prop
);
441 void obt_prop_set_string_utf8(Window win
, Atom prop
, const gchar
*val
)
443 XChangeProperty(obt_display
, win
, prop
, OBT_PROP_ATOM(UTF8
), 8,
444 PropModeReplace
, (const guchar
*)val
, strlen(val
));
447 void obt_prop_set_strings_utf8(Window win
, Atom prop
, const gchar
**strs
)
452 str
= g_string_sized_new(0);
453 for (s
= strs
; *s
; ++s
) {
454 str
= g_string_append(str
, *s
);
455 str
= g_string_append_c(str
, '\0');
457 XChangeProperty(obt_display
, win
, prop
, obt_prop_atom(OBT_PROP_UTF8
), 8,
458 PropModeReplace
, (guchar
*)str
->str
, str
->len
);
459 g_string_free(str
, TRUE
);
462 void obt_prop_erase(Window win
, Atom prop
)
464 XDeleteProperty(obt_display
, win
, prop
);
467 void obt_prop_message(gint screen
, Window about
, Atom messagetype
,
468 glong data0
, glong data1
, glong data2
, glong data3
,
469 glong data4
, glong mask
)
471 obt_prop_message_to(RootWindow(obt_display
, screen
), about
, messagetype
,
472 data0
, data1
, data2
, data3
, data4
, mask
);
475 void obt_prop_message_to(Window to
, Window about
,
477 glong data0
, glong data1
, glong data2
, glong data3
,
478 glong data4
, glong mask
)
481 ce
.xclient
.type
= ClientMessage
;
482 ce
.xclient
.message_type
= messagetype
;
483 ce
.xclient
.display
= obt_display
;
484 ce
.xclient
.window
= about
;
485 ce
.xclient
.format
= 32;
486 ce
.xclient
.data
.l
[0] = data0
;
487 ce
.xclient
.data
.l
[1] = data1
;
488 ce
.xclient
.data
.l
[2] = data2
;
489 ce
.xclient
.data
.l
[3] = data3
;
490 ce
.xclient
.data
.l
[4] = data4
;
491 XSendEvent(obt_display
, to
, FALSE
, mask
, &ce
);