summaryrefslogtreecommitdiff
path: root/openbox
diff options
context:
space:
mode:
authorDana Jansens <danakj@orodu.net>2008-02-02 11:36:17 -0500
committerDana Jansens <danakj@orodu.net>2008-02-02 11:37:35 -0500
commit0dc7eca4cdfff6425e19a0bace0f9ae8834d04e8 (patch)
tree0fe4df591efed9b1d50607ac1ec1d45565714403 /openbox
parent76fcb473fa801728badf916cfebe349822759056 (diff)
parent746859c1017e9cdf73eb91470e795f0c4b98b21a (diff)
Merge branch 'backport' into work
Conflicts: openbox/client.c openbox/event.c openbox/mouse.c openbox/openbox.c openbox/prop.c openbox/prop.h openbox/screen.c parser/parse.c parser/parse.h
Diffstat (limited to 'openbox')
-rw-r--r--openbox/actions.c20
-rw-r--r--openbox/actions.h11
-rw-r--r--openbox/actions/desktop.c2
-rw-r--r--openbox/client.c65
-rw-r--r--openbox/client.h3
-rw-r--r--openbox/event.c4
-rw-r--r--openbox/keyboard.c39
-rw-r--r--openbox/keytree.c26
-rw-r--r--openbox/keytree.h1
-rw-r--r--openbox/mouse.c22
-rw-r--r--openbox/openbox.c37
-rw-r--r--openbox/prop.c471
-rw-r--r--openbox/prop.h256
-rw-r--r--openbox/screen.c1
14 files changed, 915 insertions, 43 deletions
diff --git a/openbox/actions.c b/openbox/actions.c
index 10bf929a..6068f19c 100644
--- a/openbox/actions.c
+++ b/openbox/actions.c
@@ -23,6 +23,7 @@
#include "event.h"
#include "config.h"
#include "client.h"
+#include "openbox.h"
#include "debug.h"
#include "actions/all.h"
@@ -35,6 +36,7 @@ static ObActionsAct* actions_build_act_from_string(const gchar *name);
static ObActionsAct *interactive_act = NULL;
static guint interactive_initial_state = 0;
+static gboolean replay_pointer = FALSE;
struct _ObActionsDefinition {
guint ref;
@@ -220,6 +222,16 @@ static void actions_setup_data(ObActionsData *data,
data->client = client;
}
+void actions_set_need_pointer_replay_before_move(gboolean replay)
+{
+ replay_pointer = replay;
+}
+
+gboolean actions_get_need_pointer_replay_before_move()
+{
+ return replay_pointer;
+}
+
void actions_run_acts(GSList *acts,
ObUserAction uact,
guint state,
@@ -332,8 +344,14 @@ gboolean actions_interactive_input_event(XEvent *e)
void actions_client_move(ObActionsData *data, gboolean start)
{
static gulong ignore_start = 0;
- if (start)
+ if (start) {
ignore_start = event_start_ignore_all_enters();
+ if (replay_pointer) {
+ /* replay the pointer event before any windows move */
+ XAllowEvents(obt_display, ReplayPointer, event_curtime);
+ replay_pointer = FALSE;
+ }
+ }
else if (config_focus_follow &&
data->context != OB_FRAME_CONTEXT_CLIENT)
{
diff --git a/openbox/actions.h b/openbox/actions.h
index 32a94060..7975d4eb 100644
--- a/openbox/actions.h
+++ b/openbox/actions.h
@@ -72,9 +72,16 @@ gboolean actions_act_is_interactive(ObActionsAct *act);
void actions_act_ref(ObActionsAct *act);
void actions_act_unref(ObActionsAct *act);
-/*! Pass in a GSList of ObActionsAct's to be run.
- @return TRUE if an action is in interactive state, FALSE is none are
+/*! When this is true, an XAllowEvents with ReplayPointer will be called
+ if an action is going to maybe try moving windows around on screen (or
+ map/unmap windows)
*/
+void actions_set_need_pointer_replay_before_move(gboolean replay);
+/*! Returns if a ReplayPointer is still needed. If it was called while running
+ actions then this will be false */
+gboolean actions_get_need_pointer_replay_before_move();
+
+/*! Pass in a GSList of ObActionsAct's to be run. */
void actions_run_acts(GSList *acts,
ObUserAction uact,
guint state,
diff --git a/openbox/actions/desktop.c b/openbox/actions/desktop.c
index b50534d1..37268bba 100644
--- a/openbox/actions/desktop.c
+++ b/openbox/actions/desktop.c
@@ -136,12 +136,14 @@ static gboolean run_func(ObActionsData *data, gpointer options)
if (d < screen_num_desktops && d != screen_desktop) {
gboolean go = TRUE;
+ actions_client_move(data, TRUE);
if (o->send && data->client && client_normal(data->client)) {
client_set_desktop(data->client, d, o->follow, FALSE);
go = o->follow;
}
if (go) screen_set_desktop(d, TRUE);
+ actions_client_move(data, FALSE);
}
return FALSE;
}
diff --git a/openbox/client.c b/openbox/client.c
index b1b5e8a3..6534e1b3 100644
--- a/openbox/client.c
+++ b/openbox/client.c
@@ -2393,7 +2393,15 @@ static ObStackingLayer calc_layer(ObClient *self)
(self->decorations == 0 &&
!(self->max_horz && self->max_vert) &&
RECT_EQUAL(self->area, *monitor))) &&
- (client_focused(self) || client_search_focus_tree(self)))
+ /* you are fullscreen while you or your children are focused.. */
+ (client_focused(self) || client_search_focus_tree(self) ||
+ /* you can be fullscreen if you're on another desktop */
+ (self->desktop != screen_desktop &&
+ self->desktop != DESKTOP_ALL) ||
+ /* and you can also be fullscreen if the focused client is on
+ another monitor, or nothing else is focused */
+ (!focus_client ||
+ client_monitor(focus_client) != client_monitor(self))))
l = OB_STACKING_LAYER_FULLSCREEN;
else if (self->above) l = OB_STACKING_LAYER_ABOVE;
else if (self->below) l = OB_STACKING_LAYER_BELOW;
@@ -2419,23 +2427,54 @@ static void client_calc_layer_recursive(ObClient *self, ObClient *orig,
stacking_add_nonintrusive(CLIENT_AS_WINDOW(self));
}
+ /* we've been restacked */
+ self->visited = TRUE;
+
for (it = self->transients; it; it = g_slist_next(it))
client_calc_layer_recursive(it->data, orig,
self->layer);
}
+static void client_calc_layer_internal(ObClient *self)
+{
+ GSList *sit;
+
+ /* transients take on the layer of their parents */
+ sit = client_search_all_top_parents(self);
+
+ for (; sit; sit = g_slist_next(sit))
+ client_calc_layer_recursive(sit->data, self, 0);
+}
+
void client_calc_layer(ObClient *self)
{
- ObClient *orig;
- GSList *it;
+ GList *it;
- orig = self;
+ /* skip over stuff above fullscreen layer */
+ for (it = stacking_list; it; it = g_list_next(it))
+ if (window_layer(it->data) <= OB_STACKING_LAYER_FULLSCREEN) break;
- /* transients take on the layer of their parents */
- it = client_search_all_top_parents(self);
+ /* find the windows in the fullscreen layer, and mark them not-visited */
+ for (; it; it = g_list_next(it)) {
+ if (window_layer(it->data) < OB_STACKING_LAYER_FULLSCREEN) break;
+ else if (WINDOW_IS_CLIENT(it->data))
+ WINDOW_AS_CLIENT(it->data)->visited = FALSE;
+ }
+
+ client_calc_layer_internal(self);
- for (; it; it = g_slist_next(it))
- client_calc_layer_recursive(it->data, orig, 0);
+ /* skip over stuff above fullscreen layer */
+ for (it = stacking_list; it; it = g_list_next(it))
+ if (window_layer(it->data) <= OB_STACKING_LAYER_FULLSCREEN) break;
+
+ /* now recalc any windows in the fullscreen layer which have not
+ had their layer recalced already */
+ for (; it; it = g_list_next(it)) {
+ if (window_layer(it->data) < OB_STACKING_LAYER_FULLSCREEN) break;
+ else if (WINDOW_IS_CLIENT(it->data) &&
+ !WINDOW_AS_CLIENT(it->data)->visited)
+ client_calc_layer_internal(it->data);
+ }
}
gboolean client_should_show(ObClient *self)
@@ -2853,6 +2892,7 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h,
void client_configure(ObClient *self, gint x, gint y, gint w, gint h,
gboolean user, gboolean final, gboolean force_reply)
{
+ Rect oldframe;
gint oldw, oldh;
gboolean send_resize_client;
gboolean moved = FALSE, resized = FALSE, rootmoved = FALSE;
@@ -2875,6 +2915,7 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h,
oldw = self->area.width;
oldh = self->area.height;
+ oldframe = self->frame->area;
RECT_SET(self->area, x, y, w, h);
/* for app-requested resizes, always resize if 'resized' is true.
@@ -2979,6 +3020,14 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h,
}
XFlush(obt_display);
+
+ /* if it moved between monitors, then this can affect the stacking
+ layer of this window or others - for fullscreen windows */
+ if (screen_find_monitor(&self->frame->area) !=
+ screen_find_monitor(&oldframe))
+ {
+ client_calc_layer(self);
+ }
}
void client_fullscreen(ObClient *self, gboolean fs)
diff --git a/openbox/client.h b/openbox/client.h
index c66aaf0a..a27d37c6 100644
--- a/openbox/client.h
+++ b/openbox/client.h
@@ -304,6 +304,9 @@ struct _ObClient
/*! Where the window should iconify to/from */
Rect icon_geometry;
+
+ /*! A boolean used for algorithms which need to mark clients as visited */
+ gboolean visited;
};
extern GList *client_list;
diff --git a/openbox/event.c b/openbox/event.c
index 5207e093..bce1de12 100644
--- a/openbox/event.c
+++ b/openbox/event.c
@@ -521,7 +521,6 @@ static void event_process(const XEvent *ec, gpointer data)
window with RevertToParent focus */
frame_adjust_focus(client->frame, FALSE);
/* focus_set_client(NULL) has already been called */
- client_calc_layer(client);
}
else if (e->xfocus.detail == NotifyPointerRoot ||
e->xfocus.detail == NotifyDetailNone ||
@@ -631,7 +630,6 @@ static void event_process(const XEvent *ec, gpointer data)
frame_adjust_focus(client->frame, FALSE);
/* focus_set_client(NULL) has already been called in this
section or by focus_fallback */
- client_calc_layer(client);
}
}
else if (client)
@@ -708,7 +706,7 @@ static void event_process(const XEvent *ec, gpointer data)
if (e->type == ButtonPress || e->type == ButtonRelease) {
/* If the button press was on some non-root window, or was physically
- on the root window, the process it */
+ on the root window, then process it */
if (window != obt_root(ob_screen) ||
e->xbutton.subwindow == None)
{
diff --git a/openbox/keyboard.c b/openbox/keyboard.c
index c2e567ff..cf1bc55f 100644
--- a/openbox/keyboard.c
+++ b/openbox/keyboard.c
@@ -263,9 +263,46 @@ void keyboard_event(ObClient *client, const XEvent *e)
}
}
+static void node_rebind(KeyBindingTree *node)
+{
+ if (node->first_child) {
+ /* find leaf nodes */
+ node_rebind(node->first_child);
+
+ /* for internal nodes, add them to the tree if they
+ are a chroot, but do this after adding their
+ children */
+ if (node->chroot)
+ keyboard_chroot(node->keylist);
+ }
+ else {
+ /* for leaf nodes, rebind each action assigned to it */
+ GSList *it;
+ while (node->actions) {
+ /* add each action, and remove them from the original tree so
+ they don't get free'd on us */
+ keyboard_bind(node->keylist, node->actions->data);
+ node->actions = g_slist_delete_link(node->actions, node->actions);
+ }
+
+ if (node->chroot)
+ keyboard_chroot(node->keylist);
+ }
+
+ /* go through each sibling */
+ if (node->next_sibling) node_rebind(node->next_sibling);
+}
+
void keyboard_rebind(void)
{
- tree_rebind(keyboard_firstnode);
+ KeyBindingTree *old;
+
+ old = keyboard_firstnode;
+ keyboard_firstnode = NULL;
+ node_rebind(old);
+
+ tree_destroy(old);
+ set_curpos(NULL);
grab_keys(TRUE);
}
diff --git a/openbox/keytree.c b/openbox/keytree.c
index 714fffda..56cc96d4 100644
--- a/openbox/keytree.c
+++ b/openbox/keytree.c
@@ -68,13 +68,6 @@ KeyBindingTree *tree_build(GList *keylist)
return ret;
}
-void tree_rebind(KeyBindingTree *node) {
- GList *it = g_list_last(node->keylist);
- translate_key(it->data, &node->state, &node->key);
- if (node->next_sibling) tree_rebind(node->next_sibling);
- if (node->first_child) tree_rebind(node->first_child);
-}
-
void tree_assimilate(KeyBindingTree *node)
{
KeyBindingTree *a, *b, *tmp, *last;
@@ -139,16 +132,15 @@ KeyBindingTree *tree_find(KeyBindingTree *search, gboolean *conflict)
gboolean tree_chroot(KeyBindingTree *tree, GList *keylist)
{
guint key, state;
- if (translate_key(keylist->data, &state, &key)) {
- while (tree != NULL && !(tree->state == state && tree->key == key))
- tree = tree->next_sibling;
- if (tree != NULL) {
- if (keylist->next == NULL) {
- tree->chroot = TRUE;
- return TRUE;
- } else
- return tree_chroot(tree->first_child, keylist->next);
- }
+ translate_key(keylist->data, &state, &key);
+ while (tree != NULL && !(tree->state == state && tree->key == key))
+ tree = tree->next_sibling;
+ if (tree != NULL) {
+ if (keylist->next == NULL) {
+ tree->chroot = TRUE;
+ return TRUE;
+ } else
+ return tree_chroot(tree->first_child, keylist->next);
}
return FALSE;
}
diff --git a/openbox/keytree.h b/openbox/keytree.h
index 0307378d..391cb154 100644
--- a/openbox/keytree.h
+++ b/openbox/keytree.h
@@ -41,7 +41,6 @@ KeyBindingTree *tree_build(GList *keylist);
void tree_assimilate(KeyBindingTree *node);
KeyBindingTree *tree_find(KeyBindingTree *search, gboolean *conflict);
gboolean tree_chroot(KeyBindingTree *tree, GList *keylist);
-void tree_rebind(KeyBindingTree *node);
#endif
diff --git a/openbox/mouse.c b/openbox/mouse.c
index dca6e6ba..b2893cee 100644
--- a/openbox/mouse.c
+++ b/openbox/mouse.c
@@ -224,6 +224,17 @@ void mouse_event(ObClient *client, XEvent *e)
button = e->xbutton.button;
state = e->xbutton.state;
+ /* if the binding was in a client context, then we need to call
+ XAllowEvents with ReplayPointer at some point, to send the event
+ through to the client. when this happens though depends. if
+ windows are going to be moved on screen, then the click will end
+ up going somewhere wrong, so have the action system perform the
+ ReplayPointer for us if that is the case. */
+ if (CLIENT_CONTEXT(context, client))
+ actions_set_need_pointer_replay_before_move(TRUE);
+ else
+ actions_set_need_pointer_replay_before_move(FALSE);
+
fire_binding(OB_MOUSE_ACTION_PRESS, context,
client, e->xbutton.state,
e->xbutton.button,
@@ -234,11 +245,14 @@ void mouse_event(ObClient *client, XEvent *e)
if (grab_on_pointer())
button = 0;
- if (CLIENT_CONTEXT(context, client)) {
- /* Replay the event, so it goes to the client*/
+ /* replay the pointer event if it hasn't been replayed yet (i.e. no
+ windows were moved) */
+ if (actions_get_need_pointer_replay_before_move())
XAllowEvents(obt_display, ReplayPointer, event_curtime);
- /* Fall through to the release case! */
- } else
+
+ /* in the client context, we won't get a button release because of the
+ way it is grabbed, so just fake one */
+ if (!CLIENT_CONTEXT(context, client))
break;
case ButtonRelease:
diff --git a/openbox/openbox.c b/openbox/openbox.c
index 95a58198..80f81594 100644
--- a/openbox/openbox.c
+++ b/openbox/openbox.c
@@ -103,6 +103,7 @@ static KeyCode keys[OB_NUM_KEYS];
static gint exitcode = 0;
static guint remote_control = 0;
static gboolean being_replaced = FALSE;
+static gchar *config_file = NULL;
static void signal_handler(gint signal, gpointer data);
static void remove_args(gint *argc, gchar **argv, gint index, gint num);
@@ -222,18 +223,29 @@ gint main(gint argc, gchar **argv)
config_startup(i);
/* parse/load user options */
- if (obt_parse_load_config_file(i, "openbox", "rc.xml",
+ if ((config_file &&
+ obt_parse_load_file(i, config_file, "openbox_config")) ||
+ obt_parse_load_config_file(i, "openbox", "rc.xml",
"openbox_config"))
{
obt_parse_tree_from_root(i);
obt_parse_close(i);
- } else
+ }
+ else {
g_message(_("Unable to find a valid config file, using some simple defaults"));
+ config_file = NULL;
+ }
-/*
- if (config_type != NULL)
- PROP_SETS(obt_root(ob_screen), ob_config, config_type);
-*/
+ if (config_file) {
+ gchar *p = g_filename_to_utf8(config_file, -1,
+ NULL, NULL, NULL);
+ if (p)
+ OBT_PROP_SETS(obt_root(ob_screen), OB_CONFIG_FILE,
+ utf8, p);
+ g_free(p);
+ }
+ else
+ OBT_PROP_ERASE(obt_root(ob_screen), OB_CONFIG_FILE);
/* we're done with parsing now, kill it */
obt_parse_instance_unref(i);
@@ -462,6 +474,7 @@ static void print_help()
g_print(_(" --help Display this help and exit\n"));
g_print(_(" --version Display the version and exit\n"));
g_print(_(" --replace Replace the currently running window manager\n"));
+ g_print(_(" --config-file FILE Specify the path to the config file to use\n"));
g_print(_(" --sm-disable Disable connection to the session manager\n"));
g_print(_("\nPassing messages to a running Openbox instance:\n"));
g_print(_(" --reconfigure Reload Openbox's configuration\n"));
@@ -543,6 +556,18 @@ static void parse_args(gint *argc, gchar **argv)
else if (!strcmp(argv[i], "--exit")) {
remote_control = 3;
}
+ else if (!strcmp(argv[i], "--config-file")) {
+ if (i == *argc - 1) /* no args left */
+ /* not translated cuz it's sekret */
+ g_printerr(_("--config-file requires an argument\n"));
+ else {
+ /* this will be in the current locale encoding, which is
+ what we want */
+ config_file = argv[i+1];
+ ++i; /* skip the argument */
+ ob_debug("--config-file %s\n", config_file);
+ }
+ }
else if (!strcmp(argv[i], "--sm-save-file")) {
if (i == *argc - 1) /* no args left */
/* not translated cuz it's sekret */
diff --git a/openbox/prop.c b/openbox/prop.c
new file mode 100644
index 00000000..c2b0b40f
--- /dev/null
+++ b/openbox/prop.c
@@ -0,0 +1,471 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ prop.c for the Openbox window manager
+ Copyright (c) 2006 Mikael Magnusson
+ Copyright (c) 2003-2007 Dana Jansens
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "prop.h"
+#include "openbox.h"
+
+#include <X11/Xatom.h>
+
+Atoms prop_atoms;
+
+#define CREATE(var, name) (prop_atoms.var = \
+ XInternAtom(ob_display, name, FALSE))
+
+void prop_startup(void)
+{
+ CREATE(cardinal, "CARDINAL");
+ CREATE(window, "WINDOW");
+ CREATE(pixmap, "PIXMAP");
+ CREATE(atom, "ATOM");
+ CREATE(string, "STRING");
+ CREATE(utf8, "UTF8_STRING");
+
+ CREATE(manager, "MANAGER");
+
+ CREATE(wm_colormap_windows, "WM_COLORMAP_WINDOWS");
+ CREATE(wm_protocols, "WM_PROTOCOLS");
+ CREATE(wm_state, "WM_STATE");
+ CREATE(wm_change_state, "WM_CHANGE_STATE");
+ CREATE(wm_delete_window, "WM_DELETE_WINDOW");
+ CREATE(wm_take_focus, "WM_TAKE_FOCUS");
+ CREATE(wm_name, "WM_NAME");
+ CREATE(wm_icon_name, "WM_ICON_NAME");
+ CREATE(wm_class, "WM_CLASS");
+ CREATE(wm_window_role, "WM_WINDOW_ROLE");
+ CREATE(wm_client_machine, "WM_CLIENT_MACHINE");
+ CREATE(wm_command, "WM_COMMAND");
+ CREATE(wm_client_leader, "WM_CLIENT_LEADER");
+ CREATE(motif_wm_hints, "_MOTIF_WM_HINTS");
+
+ CREATE(sm_client_id, "SM_CLIENT_ID");
+
+ CREATE(net_wm_full_placement, "_NET_WM_FULL_PLACEMENT");
+
+ CREATE(net_supported, "_NET_SUPPORTED");
+ CREATE(net_client_list, "_NET_CLIENT_LIST");
+ CREATE(net_client_list_stacking, "_NET_CLIENT_LIST_STACKING");
+ CREATE(net_number_of_desktops, "_NET_NUMBER_OF_DESKTOPS");
+ CREATE(net_desktop_geometry, "_NET_DESKTOP_GEOMETRY");
+ CREATE(net_desktop_viewport, "_NET_DESKTOP_VIEWPORT");
+ CREATE(net_current_desktop, "_NET_CURRENT_DESKTOP");
+ CREATE(net_desktop_names, "_NET_DESKTOP_NAMES");
+ CREATE(net_active_window, "_NET_ACTIVE_WINDOW");
+/* CREATE(net_restack_window, "_NET_RESTACK_WINDOW");*/
+ CREATE(net_workarea, "_NET_WORKAREA");
+ CREATE(net_supporting_wm_check, "_NET_SUPPORTING_WM_CHECK");
+ CREATE(net_desktop_layout, "_NET_DESKTOP_LAYOUT");
+ CREATE(net_showing_desktop, "_NET_SHOWING_DESKTOP");
+
+ CREATE(net_close_window, "_NET_CLOSE_WINDOW");
+ CREATE(net_wm_moveresize, "_NET_WM_MOVERESIZE");
+ CREATE(net_moveresize_window, "_NET_MOVERESIZE_WINDOW");
+ CREATE(net_request_frame_extents, "_NET_REQUEST_FRAME_EXTENTS");
+ CREATE(net_restack_window, "_NET_RESTACK_WINDOW");
+
+ CREATE(net_startup_id, "_NET_STARTUP_ID");
+
+ CREATE(net_wm_name, "_NET_WM_NAME");
+ CREATE(net_wm_visible_name, "_NET_WM_VISIBLE_NAME");
+ CREATE(net_wm_icon_name, "_NET_WM_ICON_NAME");
+ CREATE(net_wm_visible_icon_name, "_NET_WM_VISIBLE_ICON_NAME");
+ CREATE(net_wm_desktop, "_NET_WM_DESKTOP");
+ CREATE(net_wm_window_type, "_NET_WM_WINDOW_TYPE");
+ CREATE(net_wm_state, "_NET_WM_STATE");
+ CREATE(net_wm_strut, "_NET_WM_STRUT");
+ CREATE(net_wm_strut_partial, "_NET_WM_STRUT_PARTIAL");
+ CREATE(net_wm_icon, "_NET_WM_ICON");
+ CREATE(net_wm_icon_geometry, "_NET_WM_ICON_GEOMETRY");
+ CREATE(net_wm_pid, "_NET_WM_PID");
+ CREATE(net_wm_allowed_actions, "_NET_WM_ALLOWED_ACTIONS");
+ CREATE(net_wm_user_time, "_NET_WM_USER_TIME");
+/* CREATE(net_wm_user_time_window, "_NET_WM_USER_TIME_WINDOW"); */
+ CREATE(kde_net_wm_frame_strut, "_KDE_NET_WM_FRAME_STRUT");
+ CREATE(net_frame_extents, "_NET_FRAME_EXTENTS");
+
+ CREATE(net_wm_ping, "_NET_WM_PING");
+#ifdef SYNC
+ CREATE(net_wm_sync_request, "_NET_WM_SYNC_REQUEST");
+ CREATE(net_wm_sync_request_counter, "_NET_WM_SYNC_REQUEST_COUNTER");
+#endif
+
+ CREATE(net_wm_window_type_desktop, "_NET_WM_WINDOW_TYPE_DESKTOP");
+ CREATE(net_wm_window_type_dock, "_NET_WM_WINDOW_TYPE_DOCK");
+ CREATE(net_wm_window_type_toolbar, "_NET_WM_WINDOW_TYPE_TOOLBAR");
+ CREATE(net_wm_window_type_menu, "_NET_WM_WINDOW_TYPE_MENU");
+ CREATE(net_wm_window_type_utility, "_NET_WM_WINDOW_TYPE_UTILITY");
+ CREATE(net_wm_window_type_splash, "_NET_WM_WINDOW_TYPE_SPLASH");
+ CREATE(net_wm_window_type_dialog, "_NET_WM_WINDOW_TYPE_DIALOG");
+ CREATE(net_wm_window_type_normal, "_NET_WM_WINDOW_TYPE_NORMAL");
+
+ prop_atoms.net_wm_moveresize_size_topleft = 0;
+ prop_atoms.net_wm_moveresize_size_top = 1;
+ prop_atoms.net_wm_moveresize_size_topright = 2;
+ prop_atoms.net_wm_moveresize_size_right = 3;
+ prop_atoms.net_wm_moveresize_size_bottomright = 4;
+ prop_atoms.net_wm_moveresize_size_bottom = 5;
+ prop_atoms.net_wm_moveresize_size_bottomleft = 6;
+ prop_atoms.net_wm_moveresize_size_left = 7;
+ prop_atoms.net_wm_moveresize_move = 8;
+ prop_atoms.net_wm_moveresize_size_keyboard = 9;
+ prop_atoms.net_wm_moveresize_move_keyboard = 10;
+ prop_atoms.net_wm_moveresize_cancel = 11;
+
+ CREATE(net_wm_action_move, "_NET_WM_ACTION_MOVE");
+ CREATE(net_wm_action_resize, "_NET_WM_ACTION_RESIZE");
+ CREATE(net_wm_action_minimize, "_NET_WM_ACTION_MINIMIZE");
+ CREATE(net_wm_action_shade, "_NET_WM_ACTION_SHADE");
+ CREATE(net_wm_action_maximize_horz, "_NET_WM_ACTION_MAXIMIZE_HORZ");
+ CREATE(net_wm_action_maximize_vert, "_NET_WM_ACTION_MAXIMIZE_VERT");
+ CREATE(net_wm_action_fullscreen, "_NET_WM_ACTION_FULLSCREEN");
+ CREATE(net_wm_action_change_desktop, "_NET_WM_ACTION_CHANGE_DESKTOP");
+ CREATE(net_wm_action_close, "_NET_WM_ACTION_CLOSE");
+ CREATE(net_wm_action_above, "_NET_WM_ACTION_ABOVE");
+ CREATE(net_wm_action_below, "_NET_WM_ACTION_BELOW");
+
+ CREATE(net_wm_state_modal, "_NET_WM_STATE_MODAL");
+/* CREATE(net_wm_state_sticky, "_NET_WM_STATE_STICKY");*/
+ CREATE(net_wm_state_maximized_vert, "_NET_WM_STATE_MAXIMIZED_VERT");
+ CREATE(net_wm_state_maximized_horz, "_NET_WM_STATE_MAXIMIZED_HORZ");
+ CREATE(net_wm_state_shaded, "_NET_WM_STATE_SHADED");
+ CREATE(net_wm_state_skip_taskbar, "_NET_WM_STATE_SKIP_TASKBAR");
+ CREATE(net_wm_state_skip_pager, "_NET_WM_STATE_SKIP_PAGER");
+ CREATE(net_wm_state_hidden, "_NET_WM_STATE_HIDDEN");
+ CREATE(net_wm_state_fullscreen, "_NET_WM_STATE_FULLSCREEN");
+ CREATE(net_wm_state_above, "_NET_WM_STATE_ABOVE");
+ CREATE(net_wm_state_below, "_NET_WM_STATE_BELOW");
+ CREATE(net_wm_state_demands_attention, "_NET_WM_STATE_DEMANDS_ATTENTION");
+
+ prop_atoms.net_wm_state_add = 1;
+ prop_atoms.net_wm_state_remove = 0;
+ prop_atoms.net_wm_state_toggle = 2;
+
+ prop_atoms.net_wm_orientation_horz = 0;
+ prop_atoms.net_wm_orientation_vert = 1;
+ prop_atoms.net_wm_topleft = 0;
+ prop_atoms.net_wm_topright = 1;
+ prop_atoms.net_wm_bottomright = 2;
+ prop_atoms.net_wm_bottomleft = 3;
+
+ CREATE(kde_wm_change_state, "_KDE_WM_CHANGE_STATE");
+ CREATE(kde_net_wm_window_type_override,"_KDE_NET_WM_WINDOW_TYPE_OVERRIDE");
+
+/*
+ CREATE(rootpmapid, "_XROOTPMAP_ID");
+ CREATE(esetrootid, "ESETROOT_PMAP_ID");
+*/
+
+ CREATE(openbox_pid, "_OPENBOX_PID");
+ CREATE(ob_theme, "_OB_THEME");
+ CREATE(ob_config_file, "_OB_CONFIG_FILE");
+ CREATE(ob_wm_action_undecorate, "_OB_WM_ACTION_UNDECORATE");
+ CREATE(ob_wm_state_undecorated, "_OB_WM_STATE_UNDECORATED");
+ CREATE(ob_control, "_OB_CONTROL");
+}
+
+#include <X11/Xutil.h>
+#include <glib.h>
+#include <string.h>
+
+/* this just isn't used... and it also breaks on 64bit, watch out
+static gboolean get(Window win, Atom prop, Atom type, gint size,
+ guchar **data, gulong num)
+{
+ gboolean ret = FALSE;
+ gint res;
+ guchar *xdata = NULL;
+ Atom ret_type;
+ gint ret_size;
+ gulong ret_items, bytes_left;
+ glong num32 = 32 / size * num; /\* num in 32-bit elements *\/
+
+ res = XGetWindowProperty(display, win, prop, 0l, num32,
+ FALSE, type, &ret_type, &ret_size,
+ &ret_items, &bytes_left, &xdata);
+ if (res == Success && ret_items && xdata) {
+ if (ret_size == size && ret_items >= num) {
+ *data = g_memdup(xdata, num * (size / 8));
+ ret = TRUE;
+ }
+ XFree(xdata);
+ }
+ return ret;
+}
+*/
+
+static gboolean get_prealloc(Window win, Atom prop, Atom type, gint size,
+ guchar *data, gulong num)
+{
+ gboolean ret = FALSE;
+ gint res;
+ guchar *xdata = NULL;
+ Atom ret_type;
+ gint ret_size;
+ gulong ret_items, bytes_left;
+ glong num32 = 32 / size * num; /* num in 32-bit elements */
+
+ res = XGetWindowProperty(ob_display, win, prop, 0l, num32,
+ FALSE, type, &ret_type, &ret_size,
+ &ret_items, &bytes_left, &xdata);
+ if (res == Success && ret_items && xdata) {
+ if (ret_size == size && ret_items >= num) {
+ guint i;
+ for (i = 0; i < num; ++i)
+ switch (size) {
+ case 8:
+ data[i] = xdata[i];
+ break;
+ case 16:
+ ((guint16*)data)[i] = ((gushort*)xdata)[i];
+ break;
+ case 32:
+ ((guint32*)data)[i] = ((gulong*)xdata)[i];
+ break;
+ default:
+ g_assert_not_reached(); /* unhandled size */
+ }
+ ret = TRUE;
+ }
+ XFree(xdata);
+ }
+ return ret;
+}
+
+static gboolean get_all(Window win, Atom prop, Atom type, gint size,
+ guchar **data, guint *num)
+{
+ gboolean ret = FALSE;
+ gint res;
+ guchar *xdata = NULL;
+ Atom ret_type;
+ gint ret_size;
+ gulong ret_items, bytes_left;
+
+ res = XGetWindowProperty(ob_display, win, prop, 0l, G_MAXLONG,
+ FALSE, type, &ret_type, &ret_size,
+ &ret_items, &bytes_left, &xdata);
+ if (res == Success) {
+ if (ret_size == size && ret_items > 0) {
+ guint i;
+
+ *data = g_malloc(ret_items * (size / 8));
+ for (i = 0; i < ret_items; ++i)
+ switch (size) {
+ case 8:
+ (*data)[i] = xdata[i];
+ break;
+ case 16:
+ ((guint16*)*data)[i] = ((gushort*)xdata)[i];
+ break;
+ case 32:
+ ((guint32*)*data)[i] = ((gulong*)xdata)[i];
+ break;
+ default:
+ g_assert_not_reached(); /* unhandled size */
+ }
+ *num = ret_items;
+ ret = TRUE;
+ }
+ XFree(xdata);
+ }
+ return ret;
+}
+
+static gboolean get_stringlist(Window win, Atom prop, gchar ***list, gint *nstr)
+{
+ XTextProperty tprop;
+ gboolean ret = FALSE;
+
+ if (XGetTextProperty(ob_display, win, &tprop, prop) && tprop.nitems) {
+ if (XTextPropertyToStringList(&tprop, list, nstr))
+ ret = TRUE;
+ XFree(tprop.value);
+ }
+ return ret;
+}
+
+gboolean prop_get32(Window win, Atom prop, Atom type, guint32 *ret)
+{
+ return get_prealloc(win, prop, type, 32, (guchar*)ret, 1);
+}
+
+gboolean prop_get_array32(Window win, Atom prop, Atom type, guint32 **ret,
+ guint *nret)
+{
+ return get_all(win, prop, type, 32, (guchar**)ret, nret);
+}
+
+gboolean prop_get_string_locale(Window win, Atom prop, gchar **ret)
+{
+ gchar **list;
+ gint nstr;
+ gchar *s;
+
+ if (get_stringlist(win, prop, &list, &nstr) && nstr) {
+ s = g_locale_to_utf8(list[0], -1, NULL, NULL, NULL);
+ XFreeStringList(list);
+ if (s) {
+ *ret = s;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+gboolean prop_get_strings_locale(Window win, Atom prop, gchar ***ret)
+{
+ GSList *strs = NULL, *it;
+ gchar *raw, *p;
+ guint num, i, count = 0;
+
+ if (get_all(win, prop, prop_atoms.string, 8, (guchar**)&raw, &num)) {
+
+ p = raw;
+ while (p < raw + num) {
+ ++count;
+ strs = g_slist_append(strs, p);
+ p += strlen(p) + 1; /* next string */
+ }
+
+ *ret = g_new0(gchar*, count + 1);
+ (*ret)[count] = NULL; /* null terminated list */
+
+ for (i = 0, it = strs; it; ++i, it = g_slist_next(it)) {
+ (*ret)[i] = g_locale_to_utf8(it->data, -1, NULL, NULL, NULL);
+ /* make sure translation did not fail */
+ if (!(*ret)[i])
+ (*ret)[i] = g_strdup("");
+ }
+ g_free(raw);
+ g_slist_free(strs);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+gboolean prop_get_string_utf8(Window win, Atom prop, gchar **ret)
+{
+ gchar *raw;
+ gchar *str;
+ guint num;
+
+ if (get_all(win, prop, prop_atoms.utf8, 8, (guchar**)&raw, &num)) {
+ str = g_strndup(raw, num); /* grab the first string from the list */
+ g_free(raw);
+ if (g_utf8_validate(str, -1, NULL)) {
+ *ret = str;
+ return TRUE;
+ }
+ g_free(str);
+ }
+ return FALSE;
+}
+
+gboolean prop_get_strings_utf8(Window win, Atom prop, gchar ***ret)
+{
+ GSList *strs = NULL, *it;
+ gchar *raw, *p;
+ guint num, i, count = 0;
+
+ if (get_all(win, prop, prop_atoms.utf8, 8, (guchar**)&raw, &num)) {
+
+ p = raw;
+ while (p < raw + num) {
+ ++count;
+ strs = g_slist_append(strs, p);
+ p += strlen(p) + 1; /* next string */
+ }
+
+ *ret = g_new0(gchar*, count + 1);
+
+ for (i = 0, it = strs; it; ++i, it = g_slist_next(it)) {
+ if (g_utf8_validate(it->data, -1, NULL))
+ (*ret)[i] = g_strdup(it->data);
+ else
+ (*ret)[i] = g_strdup("");
+ }
+ g_free(raw);
+ g_slist_free(strs);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void prop_set32(Window win, Atom prop, Atom type, gulong val)
+{
+ XChangeProperty(ob_display, win, prop, type, 32, PropModeReplace,
+ (guchar*)&val, 1);
+}
+
+void prop_set_array32(Window win, Atom prop, Atom type, gulong *val,
+ guint num)
+{
+ XChangeProperty(ob_display, win, prop, type, 32, PropModeReplace,
+ (guchar*)val, num);
+}
+
+void prop_set_string_utf8(Window win, Atom prop, const gchar *val)
+{
+ XChangeProperty(ob_display, win, prop, prop_atoms.utf8, 8,
+ PropModeReplace, (const guchar*)val, strlen(val));
+}
+
+void prop_set_strings_utf8(Window win, Atom prop, gchar **strs)
+{
+ GString *str;
+ gchar **s;
+
+ str = g_string_sized_new(0);
+ for (s = strs; *s; ++s) {
+ str = g_string_append(str, *s);
+ str = g_string_append_c(str, '\0');
+ }
+ XChangeProperty(ob_display, win, prop, prop_atoms.utf8, 8,
+ PropModeReplace, (guchar*)str->str, str->len);
+ g_string_free(str, TRUE);
+}
+
+void prop_erase(Window win, Atom prop)
+{
+ XDeleteProperty(ob_display, win, prop);
+}
+
+void prop_message(Window about, Atom messagetype, glong data0, glong data1,
+ glong data2, glong data3, glong mask)
+{
+ prop_message_to(RootWindow(ob_display, ob_screen), about, messagetype,
+ data0, data1, data2, data3, 0, mask);
+}
+
+void prop_message_to(Window to, Window about, Atom messagetype,
+ glong data0, glong data1, glong data2,
+ glong data3, glong data4, glong mask)
+{
+ XEvent ce;
+ ce.xclient.type = ClientMessage;
+ ce.xclient.message_type = messagetype;
+ ce.xclient.display = ob_display;
+ ce.xclient.window = about;
+ ce.xclient.format = 32;
+ ce.xclient.data.l[0] = data0;
+ ce.xclient.data.l[1] = data1;
+ ce.xclient.data.l[2] = data2;
+ ce.xclient.data.l[3] = data3;
+ ce.xclient.data.l[4] = data4;
+ XSendEvent(ob_display, to, FALSE, mask, &ce);
+}
diff --git a/openbox/prop.h b/openbox/prop.h
new file mode 100644
index 00000000..464fe26d
--- /dev/null
+++ b/openbox/prop.h
@@ -0,0 +1,256 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ prop.h for the Openbox window manager
+ Copyright (c) 2006 Mikael Magnusson
+ Copyright (c) 2003-2007 Dana Jansens
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __atoms_h
+#define __atoms_h
+
+#include <X11/Xlib.h>
+#include <glib.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+
+/*! The atoms on the X server which this class will cache */
+typedef struct Atoms {
+ /* types */
+ Atom cardinal; /*!< The atom which represents the Cardinal data type */
+ Atom window; /*!< The atom which represents window ids */
+ Atom pixmap; /*!< The atom which represents pixmap ids */
+ Atom atom; /*!< The atom which represents atom values */
+ Atom string; /*!< The atom which represents ascii strings */
+ Atom utf8; /*!< The atom which represents utf8-encoded strings */
+
+ /* selection stuff */
+ Atom manager;
+
+ /* window hints */
+ Atom wm_colormap_windows;
+ Atom wm_protocols;
+ Atom wm_state;
+ Atom wm_delete_window;
+ Atom wm_take_focus;
+ Atom wm_change_state;
+ Atom wm_name;
+ Atom wm_icon_name;
+ Atom wm_class;
+ Atom wm_window_role;
+ Atom wm_client_machine;
+ Atom wm_command;
+ Atom wm_client_leader;
+ Atom motif_wm_hints;
+
+ /* SM atoms */
+ Atom sm_client_id;
+
+ /* NETWM atoms */
+
+ /* Atoms that are used inside messages - these don't go in net_supported */
+
+ Atom net_wm_moveresize_size_topleft;
+ Atom net_wm_moveresize_size_top;
+ Atom net_wm_moveresize_size_topright;
+ Atom net_wm_moveresize_size_right;
+ Atom net_wm_moveresize_size_bottomright;
+ Atom net_wm_moveresize_size_bottom;
+ Atom net_wm_moveresize_size_bottomleft;
+ Atom net_wm_moveresize_size_left;
+ Atom net_wm_moveresize_move;
+ Atom net_wm_moveresize_size_keyboard;
+ Atom net_wm_moveresize_move_keyboard;
+ Atom net_wm_moveresize_cancel;
+
+ Atom net_wm_state_add;
+ Atom net_wm_state_remove;
+ Atom net_wm_state_toggle;
+
+ Atom net_wm_orientation_horz;
+ Atom net_wm_orientation_vert;
+ Atom net_wm_topleft;
+ Atom net_wm_topright;
+ Atom net_wm_bottomright;
+ Atom net_wm_bottomleft;
+
+ /* Everything below here must go in net_supported on the root window */
+
+ /* root window properties */
+ Atom net_supported;
+ Atom net_client_list;
+ Atom net_client_list_stacking;
+ Atom net_number_of_desktops;
+ Atom net_desktop_geometry;
+ Atom net_desktop_viewport;
+ Atom net_current_desktop;
+ Atom net_desktop_names;
+ Atom net_active_window;
+/* Atom net_restack_window;*/
+ Atom net_workarea;
+ Atom net_supporting_wm_check;
+ Atom net_desktop_layout;
+ Atom net_showing_desktop;
+
+ /* root window messages */
+ Atom net_close_window;
+ Atom net_wm_moveresize;
+ Atom net_moveresize_window;
+ Atom net_request_frame_extents;
+ Atom net_restack_window;
+
+ /* helpful hints to apps that aren't used for anything */
+ Atom net_wm_full_placement;
+
+ /* startup-notification extension */
+ Atom net_startup_id;
+
+ /* application window properties */
+ Atom net_wm_name;
+ Atom net_wm_visible_name;
+ Atom net_wm_icon_name;
+ Atom net_wm_visible_icon_name;
+ Atom net_wm_desktop;
+ Atom net_wm_window_type;
+ Atom net_wm_state;
+ Atom net_wm_strut;
+ Atom net_wm_strut_partial;
+ Atom net_wm_icon;
+ Atom net_wm_icon_geometry;
+ Atom net_wm_pid;
+ Atom net_wm_allowed_actions;
+ Atom net_wm_user_time;
+/* Atom net_wm_user_time_window; */
+ Atom net_frame_extents;
+
+ /* application protocols */
+ Atom net_wm_ping;
+#ifdef SYNC
+ Atom net_wm_sync_request;
+ Atom net_wm_sync_request_counter;
+#endif
+
+ Atom net_wm_window_type_desktop;
+ Atom net_wm_window_type_dock;
+ Atom net_wm_window_type_toolbar;
+ Atom net_wm_window_type_menu;
+ Atom net_wm_window_type_utility;
+ Atom net_wm_window_type_splash;
+ Atom net_wm_window_type_dialog;
+ Atom net_wm_window_type_normal;
+
+ Atom net_wm_action_move;
+ Atom net_wm_action_resize;
+ Atom net_wm_action_minimize;
+ Atom net_wm_action_shade;
+/* Atom net_wm_action_stick;*/
+ Atom net_wm_action_maximize_horz;
+ Atom net_wm_action_maximize_vert;
+ Atom net_wm_action_fullscreen;
+ Atom net_wm_action_change_desktop;
+ Atom net_wm_action_close;
+ Atom net_wm_action_above;
+ Atom net_wm_action_below;
+
+ Atom net_wm_state_modal;
+/* Atom net_wm_state_sticky;*/
+ Atom net_wm_state_maximized_vert;
+ Atom net_wm_state_maximized_horz;
+ Atom net_wm_state_shaded;
+ Atom net_wm_state_skip_taskbar;
+ Atom net_wm_state_skip_pager;
+ Atom net_wm_state_hidden;
+ Atom net_wm_state_fullscreen;
+ Atom net_wm_state_above;
+ Atom net_wm_state_below;
+ Atom net_wm_state_demands_attention;
+
+ /* KDE atoms */
+
+ Atom kde_wm_change_state;
+ Atom kde_net_wm_frame_strut;
+ Atom kde_net_wm_window_type_override;
+
+/*
+ Atom rootpmapid;
+ Atom esetrootid;
+*/
+
+ /* Openbox specific atoms */
+
+ Atom ob_wm_action_undecorate;
+ Atom ob_wm_state_undecorated;
+ Atom openbox_pid; /* this is depreecated in favour of ob_control */
+ Atom ob_theme;
+ Atom ob_config_file;
+ Atom ob_control;
+} Atoms;
+extern Atoms prop_atoms;
+
+void prop_startup();
+
+gboolean prop_get32(Window win, Atom prop, Atom type, guint32 *ret);
+gboolean prop_get_array32(Window win, Atom prop, Atom type, guint32 **ret,
+ guint *nret);
+gboolean prop_get_string_locale(Window win, Atom prop, gchar **ret);
+gboolean prop_get_string_utf8(Window win, Atom prop, gchar **ret);
+gboolean prop_get_strings_locale(Window win, Atom prop, gchar ***ret);
+gboolean prop_get_strings_utf8(Window win, Atom prop, gchar ***ret);
+
+void prop_set32(Window win, Atom prop, Atom type, gulong val);
+void prop_set_array32(Window win, Atom prop, Atom type, gulong *val,
+ guint num);
+void prop_set_string_utf8(Window win, Atom prop, const gchar *val);
+void prop_set_strings_utf8(Window win, Atom prop, gchar **strs);
+
+void prop_erase(Window win, Atom prop);
+
+void prop_message(Window about, Atom messagetype, glong data0, glong data1,
+ glong data2, glong data3, glong mask);
+void prop_message_to(Window to, Window about, Atom messagetype,
+ glong data0, glong data1, glong data2,
+ glong data3, glong data4, glong mask);
+
+#define PROP_GET32(win, prop, type, ret) \
+ (prop_get32(win, prop_atoms.prop, prop_atoms.type, ret))
+#define PROP_GETA32(win, prop, type, ret, nret) \
+ (prop_get_array32(win, prop_atoms.prop, prop_atoms.type, ret, \
+ nret))
+#define PROP_GETS(win, prop, type, ret) \
+ (prop_get_string_##type(win, prop_atoms.prop, ret))
+#define PROP_GETSS(win, prop, type, ret) \
+ (prop_get_strings_##type(win, prop_atoms.prop, ret))
+
+#define PROP_SET32(win, prop, type, val) \
+ prop_set32(win, prop_atoms.prop, prop_atoms.type, val)
+#define PROP_SETA32(win, prop, type, val, num) \
+ prop_set_array32(win, prop_atoms.prop, prop_atoms.type, val, num)
+#define PROP_SETS(win, prop, val) \
+ prop_set_string_utf8(win, prop_atoms.prop, val)
+#define PROP_SETSS(win, prop, strs) \
+ prop_set_strings_utf8(win, prop_atoms.prop, strs)
+
+#define PROP_ERASE(win, prop) prop_erase(win, prop_atoms.prop)
+
+#define PROP_MSG(about, msgtype, data0, data1, data2, data3) \
+ (prop_message(about, prop_atoms.msgtype, data0, data1, data2, data3, \
+ SubstructureNotifyMask | SubstructureRedirectMask))
+
+#define PROP_MSG_TO(to, about, msgtype, data0, data1, data2, data3, data4, \
+ mask) \
+ (prop_message_to(to, about, prop_atoms.msgtype, \
+ data0, data1, data2, data3, data4, mask))
+
+#endif
diff --git a/openbox/screen.c b/openbox/screen.c
index de3203e3..fcd0de8c 100644
--- a/openbox/screen.c
+++ b/openbox/screen.c
@@ -290,6 +290,7 @@ gboolean screen_annex(void)
supported[i++] = OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED);
supported[i++] = OBT_PROP_ATOM(OPENBOX_PID);
supported[i++] = OBT_PROP_ATOM(OB_THEME);
+ supported[i++] = OBT_PROP_ATOM(OB_CONFIG_FILE);
supported[i++] = OBT_PROP_ATOM(OB_CONTROL);
g_assert(i == num_support);