summaryrefslogtreecommitdiff
path: root/openbox
diff options
context:
space:
mode:
Diffstat (limited to 'openbox')
-rw-r--r--openbox/actions.c9
-rw-r--r--openbox/actions/execute.c2
-rw-r--r--openbox/actions/if.c17
-rw-r--r--openbox/client.c443
-rw-r--r--openbox/client.h9
-rw-r--r--openbox/config.c54
-rw-r--r--openbox/debug.c2
-rw-r--r--openbox/dock.c4
-rw-r--r--openbox/event.c96
-rw-r--r--openbox/event.h13
-rw-r--r--openbox/focus.c4
-rw-r--r--openbox/focus_cycle.c3
-rw-r--r--openbox/frame.c13
-rw-r--r--openbox/menu.c44
-rw-r--r--openbox/menu.h13
-rw-r--r--openbox/menuframe.c20
-rw-r--r--openbox/moveresize.c10
-rw-r--r--openbox/openbox.c23
-rw-r--r--openbox/place.c472
-rw-r--r--openbox/place.h7
-rw-r--r--openbox/prompt.c2
-rw-r--r--openbox/screen.c34
-rw-r--r--openbox/screen.h8
-rw-r--r--openbox/stacking.c17
-rw-r--r--openbox/startupnotify.c2
-rw-r--r--openbox/window.c15
26 files changed, 775 insertions, 561 deletions
diff --git a/openbox/actions.c b/openbox/actions.c
index 125084e8..ee9d55f1 100644
--- a/openbox/actions.c
+++ b/openbox/actions.c
@@ -1,6 +1,6 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
- actions.h for the Openbox window manager
+ actions.c for the Openbox window manager
Copyright (c) 2007 Dana Jansens
This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,7 @@
#include "event.h"
#include "config.h"
#include "client.h"
+#include "focus.h"
#include "openbox.h"
#include "debug.h"
@@ -300,6 +301,7 @@ void actions_run_acts(GSList *acts,
struct _ObClient *client)
{
GSList *it;
+ gboolean update_user_time;
/* Don't allow saving the initial state when running things from the
menu */
@@ -309,6 +311,7 @@ void actions_run_acts(GSList *acts,
if (x < 0 && y < 0)
screen_pointer_pos(&x, &y);
+ update_user_time = FALSE;
for (it = acts; it; it = g_slist_next(it)) {
ObActionsData data;
ObActionsAct *act = it->data;
@@ -337,6 +340,8 @@ void actions_run_acts(GSList *acts,
if (!act->def->run(&data, act->options)) {
if (actions_act_is_interactive(act))
actions_interactive_end_act();
+ if (client && client == focus_client)
+ update_user_time = TRUE;
} else {
/* make sure its interactive if it returned TRUE */
g_assert(act->i_input);
@@ -346,6 +351,8 @@ void actions_run_acts(GSList *acts,
}
}
}
+ if (update_user_time)
+ event_update_user_time();
}
gboolean actions_interactive_act_running(void)
diff --git a/openbox/actions/execute.c b/openbox/actions/execute.c
index fdce77b7..380ffa00 100644
--- a/openbox/actions/execute.c
+++ b/openbox/actions/execute.c
@@ -260,7 +260,7 @@ static gboolean run_func(ObActionsData *data, gpointer options)
if (o->sn) {
if (!ok) sn_spawn_cancel();
- unsetenv("DESKTOP_STARTUP_ID");
+ g_unsetenv("DESKTOP_STARTUP_ID");
}
g_free(program);
diff --git a/openbox/actions/if.c b/openbox/actions/if.c
index 28010d38..0e055a98 100644
--- a/openbox/actions/if.c
+++ b/openbox/actions/if.c
@@ -98,13 +98,16 @@ static gpointer setup_func(xmlNodePtr node)
o->decor_on = TRUE;
}
if ((n = obt_xml_find_node(node, "desktop"))) {
- gchar *s = obt_xml_node_string(n);
- if (!g_ascii_strcasecmp(s, "current"))
- o->desktop_current = TRUE;
- if (!g_ascii_strcasecmp(s, "other"))
- o->desktop_other = TRUE;
- else
- o->desktop_number = atoi(s);
+ gchar *s;
+ if ((s = obt_xml_node_string(n))) {
+ if (!g_ascii_strcasecmp(s, "current"))
+ o->desktop_current = TRUE;
+ if (!g_ascii_strcasecmp(s, "other"))
+ o->desktop_other = TRUE;
+ else
+ o->desktop_number = atoi(s);
+ g_free(s);
+ }
}
if ((n = obt_xml_find_node(node, "omnipresent"))) {
if (obt_xml_node_bool(n))
diff --git a/openbox/client.c b/openbox/client.c
index e666d589..1b010e4b 100644
--- a/openbox/client.c
+++ b/openbox/client.c
@@ -110,22 +110,14 @@ static void client_ping_event(ObClient *self, gboolean dead);
static void client_prompt_kill(ObClient *self);
static gboolean client_can_steal_focus(ObClient *self,
gboolean allow_other_desktop,
+ gboolean request_from_user,
Time steal_time, Time launch_time);
void client_startup(gboolean reconfig)
{
- if ((client_default_icon = RrImageCacheFind(ob_rr_icons,
- ob_rr_theme->def_win_icon,
- ob_rr_theme->def_win_icon_w,
- ob_rr_theme->def_win_icon_h)))
- RrImageRef(client_default_icon);
- else {
- client_default_icon = RrImageNew(ob_rr_icons);
- RrImageAddPicture(client_default_icon,
- ob_rr_theme->def_win_icon,
- ob_rr_theme->def_win_icon_w,
- ob_rr_theme->def_win_icon_h);
- }
+ client_default_icon = RrImageNewFromData(
+ ob_rr_icons, ob_rr_theme->def_win_icon,
+ ob_rr_theme->def_win_icon_w, ob_rr_theme->def_win_icon_h);
if (reconfig) return;
@@ -201,7 +193,8 @@ void client_manage(Window window, ObPrompt *prompt)
{
ObClient *self;
XSetWindowAttributes attrib_set;
- gboolean activate = FALSE;
+ gboolean try_activate = FALSE;
+ gboolean do_activate;
ObAppSettings *settings;
gboolean transient = FALSE;
Rect place;
@@ -293,7 +286,7 @@ void client_manage(Window window, ObPrompt *prompt)
FALSE, FALSE, TRUE, TRUE, FALSE, FALSE,
settings->focus == 1))
{
- activate = TRUE;
+ try_activate = TRUE;
}
/* remove the client's border */
@@ -307,6 +300,16 @@ void client_manage(Window window, ObPrompt *prompt)
/* where the frame was placed is where the window was originally */
place = self->area;
+ ob_debug("Going to try activate new window? %s",
+ try_activate ? "yes" : "no");
+ if (try_activate)
+ do_activate = client_can_steal_focus(
+ self, settings->focus == 1,
+ (!!launch_time || settings->focus == 1),
+ event_time(), launch_time);
+ else
+ do_activate = FALSE;
+
/* figure out placement for the window if the window is new */
if (ob_state() == OB_STATE_RUNNING) {
ob_debug("Positioned: %s @ %d %d",
@@ -325,7 +328,8 @@ void client_manage(Window window, ObPrompt *prompt)
"program + user specified" :
"BADNESS !?")))), place.width, place.height);
- obplaced = place_client(self, &place.x, &place.y, settings);
+ obplaced = place_client(self, do_activate, &place.x, &place.y,
+ settings);
/* watch for buggy apps that ask to be placed at (0,0) when there is
a strut there */
@@ -433,13 +437,34 @@ void client_manage(Window window, ObPrompt *prompt)
client_apply_startup_state(self, place.x, place.y,
place.width, place.height);
- ob_debug_type(OB_DEBUG_FOCUS, "Going to try activate new window? %s",
- activate ? "yes" : "no");
- if (activate) {
- activate = client_can_steal_focus(self, settings->focus,
- event_time(), launch_time);
+ /* set the initial value of the desktop hint, when one wasn't requested
+ on map. */
+ OBT_PROP_SET32(self->window, NET_WM_DESKTOP, CARDINAL, self->desktop);
+
+ /* grab mouse bindings before showing the window */
+ mouse_grab_for_client(self, TRUE);
+
+ /* this has to happen before we try focus the window, but we want it to
+ happen after the client's stacking has been determined or it looks bad
+ */
+ {
+ gulong ignore_start;
+ if (!config_focus_under_mouse)
+ ignore_start = event_start_ignore_all_enters();
- if (!activate) {
+ client_show(self);
+
+ if (!config_focus_under_mouse)
+ event_end_ignore_all_enters(ignore_start);
+ }
+
+ /* activate/hilight/raise the window */
+ if (try_activate) {
+ if (do_activate) {
+ gboolean stacked = client_restore_session_stacking(self);
+ client_present(self, FALSE, !stacked, TRUE);
+ }
+ else {
/* if the client isn't stealing focus, then hilite it so the user
knows it is there, but don't do this if we're restoring from a
session */
@@ -459,27 +484,6 @@ void client_manage(Window window, ObPrompt *prompt)
stacking_raise(CLIENT_AS_WINDOW(self));
}
- mouse_grab_for_client(self, TRUE);
-
- /* this has to happen before we try focus the window, but we want it to
- happen after the client's stacking has been determined or it looks bad
- */
- {
- gulong ignore_start;
- if (!config_focus_under_mouse)
- ignore_start = event_start_ignore_all_enters();
-
- client_show(self);
-
- if (!config_focus_under_mouse)
- event_end_ignore_all_enters(ignore_start);
- }
-
- if (activate) {
- gboolean stacked = client_restore_session_stacking(self);
- client_present(self, FALSE, !stacked, TRUE);
- }
-
/* add to client list/map */
client_list = g_list_append(client_list, self);
window_add(&self->window, CLIENT_AS_WINDOW(self));
@@ -697,105 +701,157 @@ void client_fake_unmanage(ObClient *self)
static gboolean client_can_steal_focus(ObClient *self,
gboolean allow_other_desktop,
+ gboolean request_from_user,
Time steal_time,
Time launch_time)
{
gboolean steal;
gboolean relative_focused;
- gboolean parent_focused;
steal = TRUE;
- parent_focused = (focus_client != NULL &&
- client_search_focus_parent(self));
relative_focused = (focus_client != NULL &&
(client_search_focus_tree_full(self) != NULL ||
client_search_focus_group_full(self) != NULL));
/* This is focus stealing prevention */
- ob_debug_type(OB_DEBUG_FOCUS,
- "Want to focus window 0x%x at time %u "
- "launched at %u (last user interaction time %u)",
- self->window, steal_time, launch_time,
- event_last_user_time);
+ ob_debug("Want to focus window 0x%x at time %u "
+ "launched at %u (last user interaction time %u) "
+ "request from %s, allow other desktop: %s",
+ self->window, steal_time, launch_time,
+ event_last_user_time,
+ (request_from_user ? "user" : "other"),
+ (allow_other_desktop ? "yes" : "no"));
+
+ /*
+ if no launch time is provided for an application, make one up.
+
+ if the window is related to other existing windows
+ and one of those windows was the last used
+ then we will give it a launch time equal to the last user time,
+ which will end up giving the window focus probably.
+ else
+ the window is related to other windows, but you are not working in
+ them?
+ seems suspicious, so we will give it a launch time of
+ NOW - STEAL_INTERVAL,
+ so it will be given focus only if we didn't use something else
+ during the steal interval.
+ else
+ the window is all on its own, so we can't judge it. give it a launch
+ time equal to the last user time, so it will probably take focus.
+
+ this way running things from a terminal will give them focus, but popups
+ without a launch time shouldn't steal focus so easily.
+ */
+
+ if (!launch_time) {
+ if (client_has_relative(self)) {
+ if (event_last_user_time && client_search_focus_group_full(self)) {
+ /* our relative is focused */
+ launch_time = event_last_user_time;
+ ob_debug("Unknown launch time, using %u - window in active "
+ "group", launch_time);
+ }
+ else if (!request_from_user) {
+ /* has relatives which are not being used. suspicious */
+ launch_time = event_time() - OB_EVENT_USER_TIME_DELAY;
+ ob_debug("Unknown launch time, using %u - window in inactive "
+ "group", launch_time);
+ }
+ else {
+ /* has relatives which are not being used, but the user seems
+ to want to go there! */
+ launch_time = event_last_user_time;
+ ob_debug("Unknown launch time, using %u - user request",
+ launch_time);
+ }
+ }
+ else {
+ /* the window is on its own, probably the user knows it is going
+ to appear */
+ launch_time = event_last_user_time;
+ ob_debug("Unknown launch time, using %u - independent window",
+ launch_time);
+ }
+ }
- /* if it's on another desktop... */
+ /* if it's on another desktop
+ then if allow_other_desktop is true, we don't want to let it steal
+ focus, unless it was launched after we changed desktops and the request
+ came from the user
+ */
if (!(self->desktop == screen_desktop ||
self->desktop == DESKTOP_ALL) &&
- /* and (we dont know when it launched, and we don't want to allow
- focus stealing from other desktops */
- ((!launch_time && !allow_other_desktop) ||
- /* or the timestamp is from before you changed desktops) */
- (screen_desktop_user_time &&
+ (!allow_other_desktop ||
+ (request_from_user && screen_desktop_user_time &&
!event_time_after(launch_time, screen_desktop_user_time))))
{
steal = FALSE;
- ob_debug_type(OB_DEBUG_FOCUS,
- "Not focusing the window because its on another "
- "desktop\n");
+ ob_debug("Not focusing the window because its on another desktop\n");
}
/* If something is focused... */
else if (focus_client) {
/* If the user is working in another window right now, then don't
steal focus */
- if (!parent_focused &&
- event_last_user_time && launch_time &&
- event_time_after(event_last_user_time, launch_time) &&
- event_last_user_time != launch_time &&
+ if (!relative_focused &&
+ event_last_user_time &&
+ /* last user time must be strictly > launch_time to block focus */
+ (event_time_after(event_last_user_time, launch_time) &&
+ event_last_user_time != launch_time) &&
event_time_after(event_last_user_time,
steal_time - OB_EVENT_USER_TIME_DELAY))
{
steal = FALSE;
- ob_debug_type(OB_DEBUG_FOCUS,
- "Not focusing the window because the user is "
- "working in another window that is not "
- "its parent");
- }
- /* If the new window is a transient (and its relatives aren't
- focused) */
- else if (client_has_parent(self) && !relative_focused) {
- steal = FALSE;
- ob_debug_type(OB_DEBUG_FOCUS,
- "Not focusing the window because it is a "
- "transient, and its relatives aren't focused");
- }
- /* Don't steal focus from globally active clients.
- I stole this idea from KWin. It seems nice.
- */
- else if (!(focus_client->can_focus ||
- focus_client->focus_notify))
- {
- steal = FALSE;
- ob_debug_type(OB_DEBUG_FOCUS,
- "Not focusing the window because a globally "
- "active client has focus");
+ ob_debug("Not focusing the window because the user is "
+ "working in another window that is not its relative");
}
/* Don't move focus if it's not going to go to this window
anyway */
else if (client_focus_target(self) != self) {
steal = FALSE;
- ob_debug_type(OB_DEBUG_FOCUS,
- "Not focusing the window because another window "
- "would get the focus anyway");
+ ob_debug("Not focusing the window because another window "
+ "would get the focus anyway");
}
- /* Don't move focus if the window is not visible on the current
- desktop and none of its relatives are focused */
- else if (!(self->desktop == screen_desktop ||
- self->desktop == DESKTOP_ALL) &&
- !relative_focused)
- {
- steal = FALSE;
- ob_debug_type(OB_DEBUG_FOCUS,
- "Not focusing the window because it is on "
- "another desktop and no relatives are focused ");
+ /* For requests that don't come from the user */
+ else if (!request_from_user) {
+ /* If the new window is a transient (and its relatives aren't
+ focused) */
+ if (client_has_parent(self) && !relative_focused) {
+ steal = FALSE;
+ ob_debug("Not focusing the window because it is a "
+ "transient, and its relatives aren't focused");
+ }
+ /* Don't steal focus from globally active clients.
+ I stole this idea from KWin. It seems nice.
+ */
+ else if (!(focus_client->can_focus || focus_client->focus_notify))
+ {
+ steal = FALSE;
+ ob_debug("Not focusing the window because a globally "
+ "active client has focus");
+ }
+ /* Don't move focus if the window is not visible on the current
+ desktop and none of its relatives are focused */
+ else if (!allow_other_desktop &&
+ !screen_compare_desktops(self->desktop, screen_desktop) &&
+ !relative_focused)
+ {
+ steal = FALSE;
+ ob_debug("Not focusing the window because it is on "
+ "another desktop and no relatives are focused ");
+ }
}
}
if (!steal)
- ob_debug_type(OB_DEBUG_FOCUS,
- "Focus stealing prevention activated for %s at "
- "time %u (last user interaction time %u)",
- self->title, steal_time, event_last_user_time);
+ ob_debug("Focus stealing prevention activated for %s at "
+ "time %u (last user interaction time %u)",
+ self->title, steal_time, event_last_user_time);
+ else
+ ob_debug("Allowing focus stealing for %s at time %u (last user "
+ "interaction time %u)",
+ self->title, steal_time, event_last_user_time);
return steal;
}
@@ -1154,11 +1210,10 @@ static void client_get_all(ObClient *self, gboolean real)
static void client_get_startup_id(ObClient *self)
{
- if (!(OBT_PROP_GETS(self->window, NET_STARTUP_ID, utf8,
- &self->startup_id)))
+ if (!(OBT_PROP_GETS_UTF8(self->window, NET_STARTUP_ID, &self->startup_id)))
if (self->group)
- OBT_PROP_GETS(self->group->leader,
- NET_STARTUP_ID, utf8, &self->startup_id);
+ OBT_PROP_GETS_UTF8(self->group->leader, NET_STARTUP_ID,
+ &self->startup_id);
}
static void client_get_area(ObClient *self)
@@ -1969,15 +2024,14 @@ void client_update_title(ObClient *self)
g_free(self->original_title);
/* try netwm */
- if (!OBT_PROP_GETS(self->window, NET_WM_NAME, utf8, &data)) {
+ if (!OBT_PROP_GETS_UTF8(self->window, NET_WM_NAME, &data)) {
/* try old x stuff */
- if (!(OBT_PROP_GETS(self->window, WM_NAME, locale, &data)
- || OBT_PROP_GETS(self->window, WM_NAME, utf8, &data))) {
+ if (!OBT_PROP_GETS(self->window, WM_NAME, &data)) {
if (self->transient) {
- /*
- GNOME alert windows are not given titles:
- http://developer.gnome.org/projects/gup/hig/draft_hig_new/windows-alert.html
- */
+ /*
+ GNOME alert windows are not given titles:
+ http://developer.gnome.org/projects/gup/hig/draft_hig_new/windows-alert.html
+ */
data = g_strdup("");
} else
data = g_strdup(_("Unnamed Window"));
@@ -2000,7 +2054,7 @@ void client_update_title(ObClient *self)
g_free(data);
}
- OBT_PROP_SETS(self->window, NET_WM_VISIBLE_NAME, utf8, visible);
+ OBT_PROP_SETS(self->window, NET_WM_VISIBLE_NAME, visible);
self->title = visible;
if (self->frame)
@@ -2011,10 +2065,9 @@ void client_update_title(ObClient *self)
g_free(self->icon_title);
/* try netwm */
- if (!OBT_PROP_GETS(self->window, NET_WM_ICON_NAME, utf8, &data))
+ if (!OBT_PROP_GETS_UTF8(self->window, NET_WM_ICON_NAME, &data))
/* try old x stuff */
- if (!(OBT_PROP_GETS(self->window, WM_ICON_NAME, locale, &data) ||
- OBT_PROP_GETS(self->window, WM_ICON_NAME, utf8, &data)))
+ if (!OBT_PROP_GETS(self->window, WM_ICON_NAME, &data))
data = g_strdup(self->title);
if (self->client_machine) {
@@ -2032,7 +2085,7 @@ void client_update_title(ObClient *self)
g_free(data);
}
- OBT_PROP_SETS(self->window, NET_WM_VISIBLE_ICON_NAME, utf8, visible);
+ OBT_PROP_SETS(self->window, NET_WM_VISIBLE_ICON_NAME, visible);
self->icon_title = visible;
}
@@ -2095,7 +2148,6 @@ void client_update_icons(ObClient *self)
guint num;
guint32 *data;
guint w, h, i, j;
- guint num_seen; /* number of icons present */
RrImage *img;
img = NULL;
@@ -2108,13 +2160,15 @@ void client_update_icons(ObClient *self)
if (OBT_PROP_GETA32(self->window, NET_WM_ICON, CARDINAL, &data, &num)) {
/* figure out how many valid icons are in here */
i = 0;
- num_seen = 0;
while (i + 2 < num) { /* +2 is to make sure there is a w and h */
w = data[i++];
h = data[i++];
/* watch for the data being too small for the specified size,
or for zero sized icons. */
- if (i + w*h > num || w == 0 || h == 0) break;
+ if (i + w*h > num || w == 0 || h == 0) {
+ i += w*h;
+ continue;
+ }
/* convert it to the right bit order for ObRender */
for (j = 0; j < w*h; ++j)
@@ -2124,29 +2178,13 @@ void client_update_icons(ObClient *self)
(((data[i+j] >> 8) & 0xff) << RrDefaultGreenOffset) +
(((data[i+j] >> 0) & 0xff) << RrDefaultBlueOffset);
- /* is it in the cache? */
- img = RrImageCacheFind(ob_rr_icons, &data[i], w, h);
- if (img) RrImageRef(img); /* own it */
+ /* add it to the image cache as an original */
+ if (!img)
+ img = RrImageNewFromData(ob_rr_icons, &data[i], w, h);
+ else
+ RrImageAddFromData(img, &data[i], w, h);
i += w*h;
- ++num_seen;
-
- /* don't bother looping anymore if we already found it in the cache
- since we'll just use that! */
- if (img) break;
- }
-
- /* if it's not in the cache yet, then add it to the cache now.
- we have already converted it to the correct bit order above */
- if (!img && num_seen > 0) {
- img = RrImageNew(ob_rr_icons);
- i = 0;
- for (j = 0; j < num_seen; ++j) {
- w = data[i++];
- h = data[i++];
- RrImageAddPicture(img, &data[i], w, h);
- i += w*h;
- }
}
g_free(data);
@@ -2170,15 +2208,10 @@ void client_update_icons(ObClient *self)
if (xicon) {
if (w > 0 && h > 0) {
- /* is this icon in the cache yet? */
- img = RrImageCacheFind(ob_rr_icons, data, w, h);
- if (img) RrImageRef(img); /* own it */
-
- /* if not, then add it */
- if (!img) {
- img = RrImageNew(ob_rr_icons);
- RrImageAddPicture(img, data, w, h);
- }
+ if (!img)
+ img = RrImageNewFromData(ob_rr_icons, data, w, h);
+ else
+ RrImageAddFromData(img, data, w, h);
}
g_free(data);
@@ -2248,19 +2281,14 @@ static void client_get_session_ids(ObClient *self)
leader = None;
/* get the SM_CLIENT_ID */
- got = FALSE;
- if (leader)
- got = OBT_PROP_GETS(leader, SM_CLIENT_ID, locale, &self->sm_client_id);
- if (!got)
- OBT_PROP_GETS(self->window, SM_CLIENT_ID, locale, &self->sm_client_id);
+ if (leader && leader != self->window)
+ OBT_PROP_GETS_XPCS(leader, SM_CLIENT_ID, &self->sm_client_id);
+ else
+ OBT_PROP_GETS_XPCS(self->window, SM_CLIENT_ID, &self->sm_client_id);
/* get the WM_CLASS (name and class). make them "" if they are not
provided */
- got = FALSE;
- if (leader)
- got = OBT_PROP_GETSS(leader, WM_CLASS, locale, &ss);
- if (!got)
- got = OBT_PROP_GETSS(self->window, WM_CLASS, locale, &ss);
+ got = OBT_PROP_GETSS_TYPE(self->window, WM_CLASS, STRING_NO_CC, &ss);
if (got) {
if (ss[0]) {
@@ -2275,11 +2303,7 @@ static void client_get_session_ids(ObClient *self)
if (self->class == NULL) self->class = g_strdup("");
/* get the WM_WINDOW_ROLE. make it "" if it is not provided */
- got = FALSE;
- if (leader)
- got = OBT_PROP_GETS(leader, WM_WINDOW_ROLE, locale, &s);
- if (!got)
- got = OBT_PROP_GETS(self->window, WM_WINDOW_ROLE, locale, &s);
+ got = OBT_PROP_GETS_XPCS(self->window, WM_WINDOW_ROLE, &s);
if (got)
self->role = s;
@@ -2290,9 +2314,9 @@ static void client_get_session_ids(ObClient *self)
got = FALSE;
if (leader)
- got = OBT_PROP_GETSS(leader, WM_COMMAND, locale, &ss);
+ got = OBT_PROP_GETSS(leader, WM_COMMAND, &ss);
if (!got)
- got = OBT_PROP_GETSS(self->window, WM_COMMAND, locale, &ss);
+ got = OBT_PROP_GETSS(self->window, WM_COMMAND, &ss);
if (got) {
/* merge/mash them all together */
@@ -2315,9 +2339,9 @@ static void client_get_session_ids(ObClient *self)
/* get the WM_CLIENT_MACHINE */
got = FALSE;
if (leader)
- got = OBT_PROP_GETS(leader, WM_CLIENT_MACHINE, locale, &s);
+ got = OBT_PROP_GETS(leader, WM_CLIENT_MACHINE, &s);
if (!got)
- got = OBT_PROP_GETS(self->window, WM_CLIENT_MACHINE, locale, &s);
+ got = OBT_PROP_GETS(self->window, WM_CLIENT_MACHINE, &s);
if (got) {
gchar localhost[128];
@@ -2344,10 +2368,10 @@ static void client_save_app_rule_values(ObClient *self)
{
const gchar *type;
- OBT_PROP_SETS(self->window, OB_APP_ROLE, utf8, self->role);
- OBT_PROP_SETS(self->window, OB_APP_NAME, utf8, self->name);
- OBT_PROP_SETS(self->window, OB_APP_CLASS, utf8, self->class);
- OBT_PROP_SETS(self->window, OB_APP_TITLE, utf8, self->original_title);
+ OBT_PROP_SETS(self->window, OB_APP_ROLE, self->role);
+ OBT_PROP_SETS(self->window, OB_APP_NAME, self->name);
+ OBT_PROP_SETS(self->window, OB_APP_CLASS, self->class);
+ OBT_PROP_SETS(self->window, OB_APP_TITLE, self->original_title);
switch (self->type) {
case OB_CLIENT_TYPE_NORMAL:
@@ -2367,7 +2391,7 @@ static void client_save_app_rule_values(ObClient *self)
case OB_CLIENT_TYPE_DOCK:
type = "dock"; break;
}
- OBT_PROP_SETS(self->window, OB_APP_TYPE, utf8, type);
+ OBT_PROP_SETS(self->window, OB_APP_TYPE, type);
}
static void client_change_wm_state(ObClient *self)
@@ -2484,6 +2508,11 @@ gboolean client_has_parent(ObClient *self)
return self->parents != NULL;
}
+gboolean client_has_children(ObClient *self)
+{
+ return self->transients != NULL;
+}
+
gboolean client_is_oldfullscreen(const ObClient *self,
const Rect *area)
{
@@ -2767,9 +2796,6 @@ static void client_apply_startup_state(ObClient *self,
self->area = oldarea;
client_configure(self, x, y, w, h, FALSE, TRUE, FALSE);
- /* set the desktop hint, to make sure that it always exists */
- OBT_PROP_SET32(self->window, NET_WM_DESKTOP, CARDINAL, self->desktop);
-
/* nothing to do for the other states:
skip_taskbar
skip_pager
@@ -2849,6 +2875,13 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h,
the updated frame dimensions. */
frame_adjust_area(self->frame, FALSE, TRUE, TRUE);
+ /* cap any X windows at the size of an unsigned short */
+ *w = MIN(*w,
+ G_MAXUSHORT - self->frame->size.left - self->frame->size.right);
+ *h = MIN(*h,
+ G_MAXUSHORT - self->frame->size.top - self->frame->size.bottom);
+
+
/* gets the frame's position */
frame_client_gravity(self->frame, x, y);
@@ -3957,13 +3990,10 @@ void client_activate(ObClient *self, gboolean desktop,
gboolean here, gboolean raise,
gboolean unshade, gboolean user)
{
- if ((user && (desktop ||
- self->desktop == DESKTOP_ALL ||
- self->desktop == screen_desktop)) ||
- client_can_steal_focus(self, desktop, event_time(), CurrentTime))
- {
+ self = client_focus_target(self);
+
+ if (client_can_steal_focus(self, desktop, user, event_time(), CurrentTime))
client_present(self, here, raise, unshade);
- }
else
client_hilite(self, TRUE);
}
@@ -4296,32 +4326,26 @@ void client_find_edge_directional(ObClient *self, ObDirection dir,
}
/* search for edges of clients */
- if (((dir == OB_DIRECTION_NORTH || dir == OB_DIRECTION_SOUTH) &&
- !self->max_vert) ||
- ((dir == OB_DIRECTION_EAST || dir == OB_DIRECTION_WEST) &&
- !self->max_horz))
- {
- for (it = client_list; it; it = g_list_next(it)) {
- ObClient *cur = it->data;
+ for (it = client_list; it; it = g_list_next(it)) {
+ ObClient *cur = it->data;
- /* skip windows to not bump into */
- if (cur == self)
- continue;
- if (cur->iconic)
- continue;
- if (self->desktop != cur->desktop && cur->desktop != DESKTOP_ALL &&
- cur->desktop != screen_desktop)
- continue;
+ /* skip windows to not bump into */
+ if (cur == self)
+ continue;
+ if (cur->iconic)
+ continue;
+ if (self->desktop != cur->desktop && cur->desktop != DESKTOP_ALL &&
+ cur->desktop != screen_desktop)
+ continue;
- ob_debug("trying window %s", cur->title);
+ ob_debug("trying window %s", cur->title);
- detect_edge(cur->frame->area, dir, my_head, my_size, my_edge_start,
- my_edge_size, dest, near_edge);
- }
- dock_get_area(&dock_area);
- detect_edge(dock_area, dir, my_head, my_size, my_edge_start,
+ detect_edge(cur->frame->area, dir, my_head, my_size, my_edge_start,
my_edge_size, dest, near_edge);
}
+ dock_get_area(&dock_area);
+ detect_edge(dock_area, dir, my_head, my_size, my_edge_start,
+ my_edge_size, dest, near_edge);
g_slice_free(Rect, a);
}
@@ -4508,6 +4532,13 @@ gboolean client_has_group_siblings(ObClient *self)
return self->group && self->group->members->next;
}
+gboolean client_has_relative(ObClient *self)
+{
+ return client_has_parent(self) ||
+ client_has_group_siblings(self) ||
+ client_has_children(self);
+}
+
/*! Returns TRUE if the client is running on the same machine as Openbox */
gboolean client_on_localhost(ObClient *self)
{
diff --git a/openbox/client.h b/openbox/client.h
index 47da397a..b36bef5a 100644
--- a/openbox/client.h
+++ b/openbox/client.h
@@ -657,6 +657,10 @@ RrImage* client_icon(ObClient *self);
transient for */
gboolean client_has_parent(ObClient *self);
+/*! Return TRUE if the client has some transient children, and FALSE otherwise.
+*/
+gboolean client_has_children(ObClient *self);
+
/*! Searches a client's immediate parents for a focused window. The function
does not check for the passed client, only for *ONE LEVEL* of its parents.
If no focused parent is found, NULL is returned.
@@ -741,6 +745,11 @@ ObClient* client_under_pointer(void);
gboolean client_has_group_siblings(ObClient *self);
+/*! Returns TRUE if the client has a transient child, a parent, or a
+ group member. Returns FALSE otherwise.
+*/
+gboolean client_has_relative(ObClient *self);
+
/*! Returns TRUE if the client is running on the same machine as Openbox */
gboolean client_on_localhost(ObClient *self);
diff --git a/openbox/config.c b/openbox/config.c
index 025a6833..debd9fba 100644
--- a/openbox/config.c
+++ b/openbox/config.c
@@ -370,7 +370,8 @@ static void parse_per_app_settings(xmlNodePtr node, gpointer d)
g_free(class);
g_free(role);
g_free(title);
- name = class = role = title = NULL;
+ g_free(type_str);
+ name = class = role = title = type_str = NULL;
}
app = obt_xml_find_node(app->next, "application");
@@ -389,39 +390,44 @@ static void parse_per_app_settings(xmlNodePtr node, gpointer d)
static void parse_key(xmlNodePtr node, GList *keylist)
{
- gchar *key;
+ gchar *keystring, **keys, **key;
xmlNodePtr n;
gboolean is_chroot = FALSE;
- if (!obt_xml_attr_string(node, "key", &key))
+ if (!obt_xml_attr_string(node, "key", &keystring))
return;
obt_xml_attr_bool(node, "chroot", &is_chroot);
- keylist = g_list_append(keylist, key);
+ keys = g_strsplit(keystring, " ", 0);
+ for (key = keys; *key; ++key) {
+ keylist = g_list_append(keylist, *key);
- if ((n = obt_xml_find_node(node->children, "keybind"))) {
- while (n) {
- parse_key(n, keylist);
- n = obt_xml_find_node(n->next, "keybind");
+ if ((n = obt_xml_find_node(node->children, "keybind"))) {
+ while (n) {
+ parse_key(n, keylist);
+ n = obt_xml_find_node(n->next, "keybind");
+ }
}
- }
- else if ((n = obt_xml_find_node(node->children, "action"))) {
- while (n) {
- ObActionsAct *action;
-
- action = actions_parse(n);
- if (action)
- keyboard_bind(keylist, action);
- n = obt_xml_find_node(n->next, "action");
+ else if ((n = obt_xml_find_node(node->children, "action"))) {
+ while (n) {
+ ObActionsAct *action;
+
+ action = actions_parse(n);
+ if (action)
+ keyboard_bind(keylist, action);
+ n = obt_xml_find_node(n->next, "action");
+ }
}
- }
- if (is_chroot)
- keyboard_chroot(keylist);
- g_free(key);
- keylist = g_list_delete_link(keylist, g_list_last(keylist));
+ if (is_chroot)
+ keyboard_chroot(keylist);
+ keylist = g_list_delete_link(keylist, g_list_last(keylist));
+ }
+
+ g_strfreev(keys);
+ g_free(keystring);
}
static void parse_keyboard(xmlNodePtr node, gpointer d)
@@ -576,6 +582,8 @@ static void parse_placement(xmlNodePtr node, gpointer d)
config_place_monitor = OB_PLACE_MONITOR_ACTIVE;
else if (obt_xml_node_contains(n, "mouse"))
config_place_monitor = OB_PLACE_MONITOR_MOUSE;
+ else if (obt_xml_node_contains(n, "any"))
+ config_place_monitor = OB_PLACE_MONITOR_ANY;
}
if ((n = obt_xml_find_node(node, "primaryMonitor"))) {
config_primary_monitor_index = obt_xml_node_int(n);
@@ -997,7 +1005,7 @@ void config_startup(ObtXmlInst *i)
config_place_policy = OB_PLACE_POLICY_SMART;
config_place_center = TRUE;
- config_place_monitor = OB_PLACE_MONITOR_ANY;
+ config_place_monitor = OB_PLACE_MONITOR_PRIMARY;
config_primary_monitor_index = 1;
config_primary_monitor = OB_PLACE_MONITOR_ACTIVE;
diff --git a/openbox/debug.c b/openbox/debug.c
index 8423e8ab..358b090b 100644
--- a/openbox/debug.c
+++ b/openbox/debug.c
@@ -135,7 +135,7 @@ static void prompt_handler(const gchar *log_domain, GLogLevelFlags log_level,
const gchar *message, gpointer data)
{
if (ob_state() == OB_STATE_RUNNING)
- prompt_show_message(message, _("Openbox"), _("Close"));
+ prompt_show_message(message, "Openbox", _("Close"));
else
log_handler(log_domain, log_level, message, data);
}
diff --git a/openbox/dock.c b/openbox/dock.c
index 06d2280a..c26eee62 100644
--- a/openbox/dock.c
+++ b/openbox/dock.c
@@ -145,7 +145,7 @@ void dock_manage(Window icon_win, Window name_win)
app->name_win = name_win;
app->icon_win = icon_win;
- if (OBT_PROP_GETSS(app->name_win, WM_CLASS, locale, &data)) {
+ if (OBT_PROP_GETSS_TYPE(app->name_win, WM_CLASS, STRING_NO_CC, &data)) {
if (data[0]) {
app->name = g_strdup(data[0]);
if (data[1])
@@ -551,6 +551,8 @@ void dock_configure(void)
dock->area.height += ob_rr_theme->obwidth * 2;
}
+ /* screen_resize() depends on this function to call screen_update_areas(),
+ so if this changes, also update screen_resize(). */
screen_update_areas();
}
diff --git a/openbox/event.c b/openbox/event.c
index b59707bb..2dde1329 100644
--- a/openbox/event.c
+++ b/openbox/event.c
@@ -273,7 +273,7 @@ static void event_set_curtime(XEvent *e)
which can happen if the clock goes backwards, we erase the last
specified user_time */
if (t && event_last_user_time && event_time_after(event_last_user_time, t))
- event_last_user_time = CurrentTime;
+ event_reset_user_time();
event_sourcetime = CurrentTime;
event_curtime = t;
@@ -1103,7 +1103,9 @@ static void event_handle_client(ObClient *client, XEvent *e)
if (grab_on_keyboard())
break;
if (e->xcrossing.mode == NotifyGrab ||
- e->xcrossing.mode == NotifyUngrab ||
+ (e->xcrossing.mode == NotifyUngrab &&
+ /* ungrab enters are used when _under_ mouse is being used */
+ !(config_focus_follow && config_focus_under_mouse)) ||
/*ignore enters when we're already in the window */
e->xcrossing.detail == NotifyInferior)
{
@@ -1443,9 +1445,15 @@ static void event_handle_client(ObClient *client, XEvent *e)
ob_debug_type(OB_DEBUG_APP_BUGS,
"_NET_ACTIVE_WINDOW message for window %s is "
"missing source indication", client->title);
- client_activate(client, FALSE, FALSE, TRUE, TRUE,
- (e->xclient.data.l[0] == 0 ||
- e->xclient.data.l[0] == 2));
+ /* TODO(danakj) This should use
+ (e->xclient.data.l[0] == 0 ||
+ e->xclient.data.l[0] == 2)
+ to determine if a user requested the activation, however GTK+
+ applications seem unable to make this distinction ever
+ (including panels such as xfce4-panel and gnome-panel).
+ So we are left just assuming all activations are from the user.
+ */
+ client_activate(client, FALSE, FALSE, TRUE, TRUE, TRUE);
} else if (msgtype == OBT_PROP_ATOM(NET_WM_MOVERESIZE)) {
ob_debug("net_wm_moveresize for 0x%lx direction %d",
client->window, e->xclient.data.l[2]);
@@ -1695,10 +1703,12 @@ static void event_handle_client(ObClient *client, XEvent *e)
client->shaped = ((XShapeEvent*)e)->shaped;
kind = ShapeBounding;
break;
+#ifdef ShapeInput
case ShapeInput:
client->shaped_input = ((XShapeEvent*)e)->shaped;
kind = ShapeInput;
break;
+#endif
default:
g_assert_not_reached();
}
@@ -1792,8 +1802,9 @@ static gboolean event_handle_menu_input(XEvent *ev)
if (ev->type == ButtonRelease || ev->type == ButtonPress) {
ObMenuEntryFrame *e;
- if (menu_hide_delay_reached() &&
- (ev->xbutton.button < 4 || ev->xbutton.button > 5))
+ if ((ev->xbutton.button < 4 || ev->xbutton.button > 5) &&
+ ((ev->type == ButtonRelease && menu_hide_delay_reached()) ||
+ ev->type == ButtonPress))
{
if ((e = menu_entry_frame_under(ev->xbutton.x_root,
ev->xbutton.y_root)))
@@ -1804,23 +1815,11 @@ static gboolean event_handle_menu_input(XEvent *ev)
if (ev->type == ButtonRelease)
menu_entry_frame_execute(e, ev->xbutton.state);
}
- else if (ev->type == ButtonRelease)
+ else
menu_frame_hide_all();
}
ret = TRUE;
}
- else if (ev->type == MotionNotify) {
- ObMenuFrame *f;
- ObMenuEntryFrame *e;
-
- if ((e = menu_entry_frame_under(ev->xmotion.x_root,
- ev->xmotion.y_root)))
- if (!(f = find_active_menu()) ||
- f == e->frame ||
- f->parent == e->frame ||
- f->child == e->frame)
- menu_frame_select(e->frame, e, FALSE);
- }
else if (ev->type == KeyPress || ev->type == KeyRelease) {
guint mods;
ObMenuFrame *frame;
@@ -1860,14 +1859,23 @@ static gboolean event_handle_menu_input(XEvent *ev)
ret = TRUE;
}
- else if (sym == XK_Right) {
- /* Right goes to the selected submenu */
- if (frame->selected &&
- frame->selected->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)
- {
- /* make sure it is visible */
- menu_frame_select(frame, frame->selected, TRUE);
- menu_frame_select_next(frame->child);
+ else if (sym == XK_Right || sym == XK_Return || sym == XK_KP_Enter)
+ {
+ /* Right and enter goes to the selected submenu.
+ Enter executes instead if it's not on a submenu. */
+
+ if (frame->selected) {
+ const ObMenuEntryType t = frame->selected->entry->type;
+
+ if (t == OB_MENU_ENTRY_TYPE_SUBMENU) {
+ /* make sure it is visible */
+ menu_frame_select(frame, frame->selected, TRUE);
+ /* move focus to the child menu */
+ menu_frame_select_next(frame->child);
+ }
+ else if (sym != XK_Right) {
+ frame->press_doexec = TRUE;
+ }
}
ret = TRUE;
}
@@ -1892,11 +1900,6 @@ static gboolean event_handle_menu_input(XEvent *ev)
ret = TRUE;
}
- else if (sym == XK_Return || sym == XK_KP_Enter) {
- frame->press_doexec = TRUE;
- ret = TRUE;
- }
-
/* keyboard accelerator shortcuts. (if it was a valid key) */
else if (frame->entries &&
(unikey =
@@ -1942,8 +1945,15 @@ static gboolean event_handle_menu_input(XEvent *ev)
if (found) {
menu_frame_select(frame, found, TRUE);
- if (num_found == 1)
- frame->press_doexec = TRUE;
+ if (num_found == 1) {
+ if (found->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) {
+ /* move focus to the child menu */
+ menu_frame_select_next(frame->child);
+ }
+ else {
+ frame->press_doexec = TRUE;
+ }
+ }
ret = TRUE;
}
}
@@ -1958,9 +1968,7 @@ static gboolean event_handle_menu_input(XEvent *ev)
frame->got_press &&
frame->press_doexec)
{
- if (frame->child)
- menu_frame_select_next(frame->child);
- else if (frame->selected)
+ if (frame->selected)
menu_entry_frame_execute(frame->selected, ev->xkey.state);
}
}
@@ -2213,7 +2221,7 @@ gboolean event_time_after(guint32 t1, guint32 t2)
gboolean find_timestamp(XEvent *e, gpointer data)
{
const Time t = event_get_timestamp(e);
- if (t > event_curtime) {
+ if (t && t >= event_curtime) {
event_curtime = t;
return TRUE;
}
@@ -2257,3 +2265,13 @@ void event_reset_time(void)
{
next_time();
}
+
+void event_update_user_time(void)
+{
+ event_last_user_time = event_time();
+}
+
+void event_reset_user_time(void)
+{
+ event_last_user_time = CurrentTime;
+}
diff --git a/openbox/event.h b/openbox/event.h
index f0e2d397..4d9984e1 100644
--- a/openbox/event.h
+++ b/openbox/event.h
@@ -26,7 +26,7 @@ struct _ObClient;
/*! The amount of time before a window appears that is checked for user input
to determine if the user is working in another window */
-#define OB_EVENT_USER_TIME_DELAY (500) /* 0.5 seconds */
+#define OB_EVENT_USER_TIME_DELAY (1000) /* 1.0 seconds */
/*! The last user-interaction time, as given by the clients */
extern Time event_last_user_time;
@@ -76,7 +76,16 @@ void event_reset_time(void);
/*! A time at which an event happened that caused this current event to be
generated. This is a user-provided time and not to be trusted.
Returns CurrentTime if there was no source time provided.
- */
+*/
Time event_source_time(void);
+/*! Update the timestamp for when the user has last used the focused window.
+ This updates the timestamp to the time of the last event, given by
+ event_time().
+*/
+void event_update_user_time(void);
+
+/*! Reset the timestamp for when the user has last used the focused window. */
+void event_reset_user_time(void);
+
#endif
diff --git a/openbox/focus.c b/openbox/focus.c
index 8c023618..a4626bf8 100644
--- a/openbox/focus.c
+++ b/openbox/focus.c
@@ -100,6 +100,10 @@ void focus_set_client(ObClient *client)
active = client ? client->window : None;
OBT_PROP_SET32(obt_root(ob_screen), NET_ACTIVE_WINDOW, WINDOW, active);
}
+
+ /* when focus is moved to a new window, the last_user_time timestamp would
+ no longer be valid, as it applies for the focused window */
+ event_reset_user_time();
}
static ObClient* focus_fallback_target(gboolean allow_refocus,
diff --git a/openbox/focus_cycle.c b/openbox/focus_cycle.c
index 39d704cc..6d4cc2a5 100644
--- a/openbox/focus_cycle.c
+++ b/openbox/focus_cycle.c
@@ -93,7 +93,8 @@ void focus_cycle_reorder()
focus_cycle_update_indicator(focus_cycle_target);
if (!focus_cycle_target)
focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
- TRUE, TRUE, TRUE, TRUE, TRUE);
+ TRUE, TRUE, OB_FOCUS_CYCLE_POPUP_MODE_NONE,
+ TRUE, TRUE);
}
}
diff --git a/openbox/frame.c b/openbox/frame.c
index 8a9a5a64..3aa3ab7f 100644
--- a/openbox/frame.c
+++ b/openbox/frame.c
@@ -276,9 +276,14 @@ void frame_adjust_shape_kind(ObFrame *self, int kind)
{
gint num;
XRectangle xrect[2];
+ gboolean shaped;
- if (!((kind == ShapeBounding && self->client->shaped) ||
- (kind == ShapeInput && self->client->shaped_input))) {
+ shaped = (kind == ShapeBounding && self->client->shaped);
+#ifdef ShapeInput
+ shaped |= (kind == ShapeInput && self->client->shaped_input);
+#endif
+
+ if (!shaped) {
/* clear the shape on the frame window */
XShapeCombineMask(obt_display, self->window, kind,
self->size.left,
@@ -323,8 +328,10 @@ void frame_adjust_shape(ObFrame *self)
{
#ifdef SHAPE
frame_adjust_shape_kind(self, ShapeBounding);
+#ifdef ShapeInput
frame_adjust_shape_kind(self, ShapeInput);
#endif
+#endif
}
void frame_adjust_area(ObFrame *self, gboolean moved,
@@ -953,7 +960,7 @@ void frame_adjust_state(ObFrame *self)
void frame_adjust_focus(ObFrame *self, gboolean hilite)
{
ob_debug_type(OB_DEBUG_FOCUS,
- "Frame for 0x%x has focus: %d\n",
+ "Frame for 0x%x has focus: %d",
self->client->window, hilite);
self->focused = hilite;
self->need_render = TRUE;
diff --git a/openbox/menu.c b/openbox/menu.c
index 374aeec1..daea0b65 100644
--- a/openbox/menu.c
+++ b/openbox/menu.c
@@ -49,6 +49,7 @@ static GHashTable *menu_hash = NULL;
static ObtXmlInst *menu_parse_inst;
static ObMenuParseState menu_parse_state;
static gboolean menu_can_hide = FALSE;
+static guint menu_timeout_id = 0;
static void menu_destroy_hash_value(ObMenu *self);
static void parse_menu_item(xmlNodePtr node, gpointer data);
@@ -293,19 +294,7 @@ static void parse_menu_item(xmlNodePtr node, gpointer data)
if (config_menu_show_icons &&
obt_xml_attr_string(node, "icon", &icon))
{
- RrImage *ic;
-
- ic = RrImageCacheFindName(ob_rr_icons, icon);
- if (ic)
- RrImageRef(ic);
- else {
- ic = RrImageNew(ob_rr_icons);
- if (!RrImageAddPictureName(ic, icon)) {
- RrImageUnref(ic); /* no need to keep it around */
- ic = NULL;
- }
- }
- e->data.normal.icon = ic;
+ e->data.normal.icon = RrImageNewFromName(ob_rr_icons, icon);
if (e->data.normal.icon)
e->data.normal.icon_alpha = 0xff;
@@ -337,6 +326,8 @@ static void parse_menu(xmlNodePtr node, gpointer data)
ObMenuParseState *state = data;
gchar *name = NULL, *title = NULL, *script = NULL;
ObMenu *menu;
+ ObMenuEntry *e;
+ gchar *icon;
if (!obt_xml_attr_string(node, "id", &name))
goto parse_menu_fail;
@@ -360,8 +351,20 @@ static void parse_menu(xmlNodePtr node, gpointer data)
}
}
- if (state->parent)
- menu_add_submenu(state->parent, -1, name);
+ if (state->parent) {
+ e = menu_add_submenu(state->parent, -1, name);
+
+ if (config_menu_show_icons &&
+ obt_xml_attr_string(node, "icon", &icon))
+ {
+ e->data.submenu.icon = RrImageNewFromName(ob_rr_icons, icon);
+
+ if (e->data.submenu.icon)
+ e->data.submenu.icon_alpha = 0xff;
+
+ g_free(icon);
+ }
+ }
parse_menu_fail:
g_free(name);
@@ -437,6 +440,7 @@ void menu_free(ObMenu *menu)
static gboolean menu_hide_delay_func(gpointer data)
{
menu_can_hide = TRUE;
+ menu_timeout_id = 0;
return FALSE; /* no repeat */
}
@@ -486,10 +490,11 @@ void menu_show(gchar *name, gint x, gint y, gboolean mouse, ObClient *client)
menu_can_hide = TRUE;
else {
menu_can_hide = FALSE;
- g_timeout_add_full(G_PRIORITY_DEFAULT,
- config_menu_hide_delay,
- menu_hide_delay_func,
- NULL, NULL);
+ if (menu_timeout_id) g_source_remove(menu_timeout_id);
+ menu_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
+ config_menu_hide_delay,
+ menu_hide_delay_func,
+ NULL, NULL);
}
}
}
@@ -543,6 +548,7 @@ void menu_entry_unref(ObMenuEntry *self)
}
break;
case OB_MENU_ENTRY_TYPE_SUBMENU:
+ RrImageUnref(self->data.submenu.icon);
g_free(self->data.submenu.name);
break;
case OB_MENU_ENTRY_TYPE_SEPARATOR:
diff --git a/openbox/menu.h b/openbox/menu.h
index c0cc199d..76cc238f 100644
--- a/openbox/menu.h
+++ b/openbox/menu.h
@@ -103,6 +103,10 @@ typedef enum
} ObMenuEntryType;
struct _ObNormalMenuEntry {
+ /* Icon stuff. If you set this, make sure you RrImageRef() it too. */
+ RrImage *icon;
+ gint icon_alpha;
+
gchar *label;
/*! The shortcut key that would be used to activate this menu entry */
gunichar shortcut;
@@ -117,10 +121,6 @@ struct _ObNormalMenuEntry {
/* List of ObActions */
GSList *actions;
- /* Icon stuff. If you set this, make sure you RrImageRef() it too. */
- RrImage *icon;
- gint icon_alpha;
-
/* Mask icon */
RrPixmapMask *mask;
RrColor *mask_normal_color;
@@ -132,8 +132,13 @@ struct _ObNormalMenuEntry {
};
struct _ObSubmenuMenuEntry {
+ /* Icon stuff. If you set this, make sure you RrImageRef() it too. */
+ RrImage *icon;
+ gint icon_alpha;
+
gchar *name;
ObMenu *submenu;
+
guint show_from;
};
diff --git a/openbox/menuframe.c b/openbox/menuframe.c
index 5708cdf8..6110045c 100644
--- a/openbox/menuframe.c
+++ b/openbox/menuframe.c
@@ -181,7 +181,8 @@ static ObMenuEntryFrame* menu_entry_frame_new(ObMenuEntry *entry,
self->text = createWindow(self->window, 0, NULL);
g_hash_table_insert(menu_frame_map, &self->window, self);
g_hash_table_insert(menu_frame_map, &self->text, self);
- if (entry->type == OB_MENU_ENTRY_TYPE_NORMAL) {
+ if ((entry->type == OB_MENU_ENTRY_TYPE_NORMAL) ||
+ (entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)) {
self->icon = createWindow(self->window, 0, NULL);
g_hash_table_insert(menu_frame_map, &self->icon, self);
}
@@ -209,7 +210,8 @@ static void menu_entry_frame_free(ObMenuEntryFrame *self)
XDestroyWindow(obt_display, self->window);
g_hash_table_remove(menu_frame_map, &self->text);
g_hash_table_remove(menu_frame_map, &self->window);
- if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL) {
+ if ((self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL) ||
+ (self->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)) {
XDestroyWindow(obt_display, self->icon);
g_hash_table_remove(menu_frame_map, &self->icon);
}
@@ -324,11 +326,18 @@ void menu_frame_move_on_screen(ObMenuFrame *self, gint x, gint y,
gint *dx, gint *dy)
{
const Rect *a = NULL;
- gint pos, half;
+ Rect search = self->area;
+ gint pos, half, monitor;
*dx = *dy = 0;
+ RECT_SET_POINT(search, x, y);
- a = screen_physical_area_monitor(screen_find_monitor_point(x, y));
+ if (self->parent)
+ monitor = self->parent->monitor;
+ else
+ monitor = screen_find_monitor(&search);
+
+ a = screen_physical_area_monitor(monitor);
half = g_list_length(self->entries) / 2;
pos = g_list_index(self->entries, self->selected);
@@ -515,7 +524,8 @@ static void menu_entry_frame_render(ObMenuEntryFrame *self)
g_assert_not_reached();
}
- if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
+ if (((self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL) ||
+ (self->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)) &&
self->entry->data.normal.icon)
{
RrAppearance *clear;
diff --git a/openbox/moveresize.c b/openbox/moveresize.c
index 2f68395a..3a98db37 100644
--- a/openbox/moveresize.c
+++ b/openbox/moveresize.c
@@ -21,6 +21,7 @@
#include "framerender.h"
#include "screen.h"
#include "client.h"
+#include "focus.h"
#include "frame.h"
#include "openbox.h"
#include "resist.h"
@@ -63,8 +64,8 @@ static ObDirection edge_warp_dir = -1;
static gboolean edge_warp_odd = FALSE;
static guint edge_warp_timer = 0;
static ObDirection key_resize_edge = -1;
-#ifdef SYNC
static guint waiting_for_sync;
+#ifdef SYNC
static guint sync_timer = 0;
#endif
@@ -262,6 +263,7 @@ void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr)
cur_h = start_ch;
moveresize_in_progress = TRUE;
+ waiting_for_sync = 0;
#ifdef SYNC
if (config_resize_redraw && !moving && obt_display_extension_sync &&
@@ -300,8 +302,6 @@ void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr)
XSyncCADelta |
XSyncCAEvents,
&aa);
-
- waiting_for_sync = 0;
}
#endif
}
@@ -1084,5 +1084,9 @@ gboolean moveresize_event(XEvent *e)
used = TRUE;
}
#endif
+
+ if (used && moveresize_client == focus_client)
+ event_update_user_time();
+
return used;
}
diff --git a/openbox/openbox.c b/openbox/openbox.c
index ae0ba8ae..0782794c 100644
--- a/openbox/openbox.c
+++ b/openbox/openbox.c
@@ -196,7 +196,7 @@ gint main(gint argc, gchar **argv)
/* set the DISPLAY environment variable for any lauched children, to the
display we're using, so they open in the right place. */
- setenv("DISPLAY", DisplayString(obt_display), TRUE);
+ g_setenv("DISPLAY", DisplayString(obt_display), TRUE);
/* create available cursors */
cursors[OB_CURSOR_NONE] = None;
@@ -258,8 +258,7 @@ gint main(gint argc, gchar **argv)
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);
+ OBT_PROP_SETS(obt_root(ob_screen), OB_CONFIG_FILE, p);
g_free(p);
}
else
@@ -286,8 +285,8 @@ gint main(gint argc, gchar **argv)
if (ob_rr_theme == NULL)
ob_exit_with_error(_("Unable to load a theme."));
- OBT_PROP_SETS(obt_root(ob_screen),
- OB_THEME, utf8, ob_rr_theme->name);
+ OBT_PROP_SETS(obt_root(ob_screen), OB_THEME,
+ ob_rr_theme->name);
}
if (reconfigure) {
@@ -356,11 +355,11 @@ gint main(gint argc, gchar **argv)
}
}
- reconfigure = FALSE;
-
ob_set_state(OB_STATE_RUNNING);
- if (startup_cmd) run_startup_cmd();
+ if (!reconfigure && startup_cmd) run_startup_cmd();
+
+ reconfigure = FALSE;
/* look for parsing errors */
{
@@ -590,12 +589,12 @@ static void parse_env(void)
const gchar *id;
/* unset this so we don't pass it on unknowingly */
- unsetenv("DESKTOP_STARTUP_ID");
+ g_unsetenv("DESKTOP_STARTUP_ID");
/* this is how gnome-session passes in a session client id */
id = g_getenv("DESKTOP_AUTOSTART_ID");
if (id) {
- unsetenv("DESKTOP_AUTOSTART_ID");
+ g_unsetenv("DESKTOP_AUTOSTART_ID");
if (ob_sm_id) g_free(ob_sm_id);
ob_sm_id = g_strdup(id);
ob_debug_type(OB_DEBUG_SM,
@@ -630,7 +629,7 @@ static void parse_args(gint *argc, gchar **argv)
}
else if (!strcmp(argv[i], "--startup")) {
if (i == *argc - 1) /* no args left */
- g_printerr(_("--startup requires an argument\n"));
+ g_printerr(_("%s requires an argument\n"), "--startup");
else {
/* this will be in the current locale encoding, which is
what we want */
@@ -664,7 +663,7 @@ static void parse_args(gint *argc, gchar **argv)
}
else if (!strcmp(argv[i], "--config-file")) {
if (i == *argc - 1) /* no args left */
- g_printerr(_("--config-file requires an argument\n"));
+ g_printerr(_("%s requires an argument\n"), "--config-file");
else {
/* this will be in the current locale encoding, which is
what we want */
diff --git a/openbox/place.c b/openbox/place.c
index d9919d0c..d56adfc8 100644
--- a/openbox/place.c
+++ b/openbox/place.c
@@ -28,129 +28,209 @@
extern ObDock *dock;
-static void add_choice(guint *choice, guint mychoice)
+static Rect *pick_pointer_head(ObClient *c)
{
- guint i;
- for (i = 0; i < screen_num_monitors; ++i) {
- if (choice[i] == mychoice)
- return;
- else if (choice[i] == screen_num_monitors) {
- choice[i] = mychoice;
- return;
- }
- }
+ return screen_area(c->desktop, screen_monitor_pointer(), NULL);
}
-static Rect *pick_pointer_head(ObClient *c)
+/* use the following priority lists for pick_head()
+
+ When a window is being placed in the FOREGROUND, use a monitor chosen in
+ the following order:
+ 1. same monitor as parent
+ 2. primary monitor if placement=PRIMARY
+ active monitor if placement=ACTIVE
+ pointer monitor if placement=MOUSE
+ 3. primary monitor
+ 4. other monitors where the window has group members on the same desktop
+ 5. other monitors where the window has group members on other desktops
+ 6. other monitors
+
+ When a window is being placed in the BACKGROUND, use a monitor chosen in the
+ following order:
+ 1. same monitor as parent
+ 2. other monitors where the window has group members on the same desktop
+ 2a. primary monitor in this set
+ 2b. other monitors in this set
+ 3. other monitors where the window has group members on other desktops
+ 3a. primary monitor in this set
+ 3b. other monitors in this set
+ 4. other monitors
+ 4a. primary monitor in this set
+ 4b. other monitors in this set
+*/
+
+/*! One for each possible head, used to sort them in order of precedence. */
+typedef struct {
+ guint monitor;
+ guint flags;
+} ObPlaceHead;
+
+/*! Flags for ObPlaceHead */
+enum {
+ HEAD_PARENT = 1 << 0, /* parent's monitor */
+ HEAD_PLACED = 1 << 1, /* chosen monitor by placement */
+ HEAD_PRIMARY = 1 << 2, /* primary monitor */
+ HEAD_GROUP_DESK = 1 << 3, /* has a group member on the same desktop */
+ HEAD_GROUP = 1 << 4, /* has a group member on another desktop */
+};
+
+gint cmp_foreground(const void *a, const void *b)
{
- return screen_area(c->desktop, screen_monitor_pointer(), NULL);
+ const ObPlaceHead *h1 = a;
+ const ObPlaceHead *h2 = b;
+ gint i = 0;
+
+ if (h1->monitor == h2->monitor) return 0;
+
+ if (h1->flags & HEAD_PARENT) --i;
+ if (h2->flags & HEAD_PARENT) ++i;
+ if (i) return i;
+
+ if (h1->flags & HEAD_PLACED) --i;
+ if (h2->flags & HEAD_PLACED) ++i;
+ if (i) return i;
+
+ if (h1->flags & HEAD_PRIMARY) --i;
+ if (h2->flags & HEAD_PRIMARY) ++i;
+ if (i) return i;
+
+ if (h1->flags & HEAD_GROUP_DESK) --i;
+ if (h2->flags & HEAD_GROUP_DESK) ++i;
+ if (i) return i;
+
+ if (h1->flags & HEAD_GROUP) --i;
+ if (h2->flags & HEAD_GROUP) ++i;
+ if (i) return i;
+
+ return h1->monitor - h2->monitor;
+}
+
+gint cmp_background(const void *a, const void *b)
+{
+ const ObPlaceHead *h1 = a;
+ const ObPlaceHead *h2 = b;
+ gint i = 0;
+
+ if (h1->monitor == h2->monitor) return 0;
+
+ if (h1->flags & HEAD_PARENT) --i;
+ if (h2->flags & HEAD_PARENT) ++i;
+ if (i) return i;
+
+ if (h1->flags & HEAD_GROUP_DESK || h2->flags & HEAD_GROUP_DESK) {
+ if (h1->flags & HEAD_GROUP_DESK) --i;
+ if (h2->flags & HEAD_GROUP_DESK) ++i;
+ if (i) return i;
+ if (h1->flags & HEAD_PRIMARY) --i;
+ if (h2->flags & HEAD_PRIMARY) ++i;
+ if (i) return i;
+ }
+
+ if (h1->flags & HEAD_GROUP || h2->flags & HEAD_GROUP) {
+ if (h1->flags & HEAD_GROUP) --i;
+ if (h2->flags & HEAD_GROUP) ++i;
+ if (i) return i;
+ if (h1->flags & HEAD_PRIMARY) --i;
+ if (h2->flags & HEAD_PRIMARY) ++i;
+ if (i) return i;
+ }
+
+ if (h1->flags & HEAD_PRIMARY) --i;
+ if (h2->flags & HEAD_PRIMARY) ++i;
+ if (i) return i;
+
+ return h1->monitor - h2->monitor;
}
/*! Pick a monitor to place a window on. */
-static Rect **pick_head(ObClient *c)
+static Rect *pick_head(ObClient *c, gboolean foreground)
{
- Rect **area;
- guint *choice;
+ Rect *area;
+ ObPlaceHead *choice;
guint i;
- gint px, py;
ObClient *p;
+ GSList *it;
- area = g_new(Rect*, screen_num_monitors);
- choice = g_new(guint, screen_num_monitors);
- for (i = 0; i < screen_num_monitors; ++i)
- choice[i] = screen_num_monitors; /* make them all invalid to start */
-
- /* try direct parent first */
- if ((p = client_direct_parent(c))) {
- add_choice(choice, client_monitor(p));
- ob_debug("placement adding choice %d for parent",
- client_monitor(p));
+ choice = g_new(ObPlaceHead, screen_num_monitors);
+ for (i = 0; i < screen_num_monitors; ++i) {
+ choice[i].monitor = i;
+ choice[i].flags = 0;
}
- /* more than one window in its group (more than just this window) */
- if (client_has_group_siblings(c)) {
- GSList *it;
-
- /* try on the client's desktop */
- for (it = c->group->members; it; it = g_slist_next(it)) {
- ObClient *itc = it->data;
- if (itc != c &&
- (itc->desktop == c->desktop ||
- itc->desktop == DESKTOP_ALL || c->desktop == DESKTOP_ALL))
- {
- add_choice(choice, client_monitor(it->data));
- ob_debug("placement adding choice %d for group sibling",
- client_monitor(it->data));
- }
- }
-
- /* try on all desktops */
+ /* find monitors with group members */
+ if (c->group) {
for (it = c->group->members; it; it = g_slist_next(it)) {
ObClient *itc = it->data;
if (itc != c) {
- add_choice(choice, client_monitor(it->data));
- ob_debug("placement adding choice %d for group sibling on "
- "another desktop", client_monitor(it->data));
+ guint m = client_monitor(itc);
+
+ if (m < screen_num_monitors) {
+ if (screen_compare_desktops(itc->desktop, c->desktop))
+ choice[m].flags |= HEAD_GROUP_DESK;
+ else
+ choice[m].flags |= HEAD_GROUP;
+ }
}
}
}
- /* skip this if placing by the mouse position */
- if (focus_client && client_normal(focus_client) &&
- config_place_monitor != OB_PLACE_MONITOR_MOUSE)
- {
- add_choice(choice, client_monitor(focus_client));
- ob_debug("placement adding choice %d for normal focused window",
- client_monitor(focus_client));
+ i = screen_monitor_primary(FALSE);
+ if (i < screen_num_monitors) {
+ choice[i].flags |= HEAD_PRIMARY;
+ if (config_place_monitor == OB_PLACE_MONITOR_PRIMARY)
+ choice[i].flags |= HEAD_PLACED;
}
- screen_pointer_pos(&px, &py);
-
- for (i = 0; i < screen_num_monitors; i++) {
- const Rect *monitor = screen_physical_area_monitor(i);
- gboolean contain = RECT_CONTAINS(*monitor, px, py);
- if (contain) {
- add_choice(choice, i);
- ob_debug("placement adding choice %d for mouse pointer", i);
- break;
- }
+ /* direct parent takes highest precedence */
+ if ((p = client_direct_parent(c))) {
+ i = client_monitor(p);
+ if (i < screen_num_monitors)
+ choice[i].flags |= HEAD_PARENT;
}
- /* add any leftover choices */
- for (i = 0; i < screen_num_monitors; ++i)
- add_choice(choice, i);
+ qsort(choice, screen_num_monitors, sizeof(ObPlaceHead),
+ foreground ? cmp_foreground : cmp_background);
+ /* save the areas of the monitors in order of their being chosen */
for (i = 0; i < screen_num_monitors; ++i)
- area[i] = screen_area(c->desktop, choice[i], NULL);
+ {
+ ob_debug("placement choice %d is monitor %d", i, choice[i].monitor);
+ if (choice[i].flags & HEAD_PARENT)
+ ob_debug(" - parent on monitor");
+ if (choice[i].flags & HEAD_PLACED)
+ ob_debug(" - placement choice");
+ if (choice[i].flags & HEAD_PRIMARY)
+ ob_debug(" - primary monitor");
+ if (choice[i].flags & HEAD_GROUP_DESK)
+ ob_debug(" - group on same desktop");
+ if (choice[i].flags & HEAD_GROUP)
+ ob_debug(" - group on other desktop");
+ }
+
+ area = screen_area(c->desktop, choice[0].monitor, NULL);
g_free(choice);
+ /* return the area for the chosen monitor */
return area;
}
-static gboolean place_random(ObClient *client, gint *x, gint *y)
+static gboolean place_random(ObClient *client, Rect *area, gint *x, gint *y)
{
gint l, r, t, b;
- Rect **areas;
- guint i;
- areas = pick_head(client);
- i = (config_place_monitor != OB_PLACE_MONITOR_ANY) ?
- 0 : g_random_int_range(0, screen_num_monitors);
+ ob_debug("placing randomly");
- l = areas[i]->x;
- t = areas[i]->y;
- r = areas[i]->x + areas[i]->width - client->frame->area.width;
- b = areas[i]->y + areas[i]->height - client->frame->area.height;
+ l = area->x;
+ t = area->y;
+ r = area->x + area->width - client->frame->area.width;
+ b = area->y + area->height - client->frame->area.height;
if (r > l) *x = g_random_int_range(l, r + 1);
- else *x = areas[i]->x;
+ else *x = area->x;
if (b > t) *y = g_random_int_range(t, b + 1);
- else *y = areas[i]->y;
-
- for (i = 0; i < screen_num_monitors; ++i)
- g_slice_free(Rect, areas[i]);
- g_free(areas);
+ else *y = area->y;
return TRUE;
}
@@ -228,118 +308,108 @@ enum {
IGNORE_END = 7
};
-static gboolean place_nooverlap(ObClient *c, gint *x, gint *y)
+static gboolean place_nooverlap(ObClient *c, Rect *area, gint *x, gint *y)
{
- Rect **areas;
gint ignore;
gboolean ret;
gint maxsize;
GSList *spaces = NULL, *sit, *maxit;
- guint i;
- areas = pick_head(c);
+ ob_debug("placing nonoverlap");
+
ret = FALSE;
maxsize = 0;
maxit = NULL;
/* try ignoring different things to find empty space */
for (ignore = 0; ignore < IGNORE_END && !ret; ignore++) {
- /* try all monitors in order of preference, but only the first one
- if config_place_monitor is MOUSE or ACTIVE */
- for (i = 0; (i < (config_place_monitor != OB_PLACE_MONITOR_ANY ?
- 1 : screen_num_monitors) && !ret); ++i)
- {
- GList *it;
-
- /* add the whole monitor */
- spaces = area_add(spaces, areas[i]);
-
- /* go thru all the windows */
- for (it = client_list; it; it = g_list_next(it)) {
- ObClient *test = it->data;
-
- /* should we ignore this client? */
- if (screen_showing_desktop) continue;
- if (c == test) continue;
- if (test->iconic) continue;
- if (c->desktop != DESKTOP_ALL) {
- if (test->desktop != c->desktop &&
- test->desktop != DESKTOP_ALL) continue;
- } else {
- if (test->desktop != screen_desktop &&
- test->desktop != DESKTOP_ALL) continue;
- }
- if (test->type == OB_CLIENT_TYPE_SPLASH ||
- test->type == OB_CLIENT_TYPE_DESKTOP) continue;
-
-
- if ((ignore >= IGNORE_FULLSCREEN) &&
- test->fullscreen) continue;
- if ((ignore >= IGNORE_MAXIMIZED) &&
- test->max_horz && test->max_vert) continue;
- if ((ignore >= IGNORE_MENUTOOL) &&
- (test->type == OB_CLIENT_TYPE_MENU ||
- test->type == OB_CLIENT_TYPE_TOOLBAR) &&
- client_has_parent(c)) continue;
- /*
- if ((ignore >= IGNORE_SHADED) &&
- test->shaded) continue;
- */
- if ((ignore >= IGNORE_NONGROUP) &&
- client_has_group_siblings(c) &&
- test->group != c->group) continue;
- if ((ignore >= IGNORE_BELOW) &&
- test->layer < c->layer) continue;
- /*
- if ((ignore >= IGNORE_NONFOCUS) &&
- focus_client != test) continue;
- */
- /* don't ignore this window, so remove it from the available
- area */
- spaces = area_remove(spaces, &test->frame->area);
+ GList *it;
+
+ /* add the whole monitor */
+ spaces = area_add(spaces, area);
+
+ /* go thru all the windows */
+ for (it = client_list; it; it = g_list_next(it)) {
+ ObClient *test = it->data;
+
+ /* should we ignore this client? */
+ if (screen_showing_desktop) continue;
+ if (c == test) continue;
+ if (test->iconic) continue;
+ if (c->desktop != DESKTOP_ALL) {
+ if (test->desktop != c->desktop &&
+ test->desktop != DESKTOP_ALL) continue;
+ } else {
+ if (test->desktop != screen_desktop &&
+ test->desktop != DESKTOP_ALL) continue;
}
+ if (test->type == OB_CLIENT_TYPE_SPLASH ||
+ test->type == OB_CLIENT_TYPE_DESKTOP) continue;
+
+
+ if ((ignore >= IGNORE_FULLSCREEN) &&
+ test->fullscreen) continue;
+ if ((ignore >= IGNORE_MAXIMIZED) &&
+ test->max_horz && test->max_vert) continue;
+ if ((ignore >= IGNORE_MENUTOOL) &&
+ (test->type == OB_CLIENT_TYPE_MENU ||
+ test->type == OB_CLIENT_TYPE_TOOLBAR) &&
+ client_has_parent(c)) continue;
+ /*
+ if ((ignore >= IGNORE_SHADED) &&
+ test->shaded) continue;
+ */
+ if ((ignore >= IGNORE_NONGROUP) &&
+ client_has_group_siblings(c) &&
+ test->group != c->group) continue;
+ if ((ignore >= IGNORE_BELOW) &&
+ test->layer < c->layer) continue;
+ /*
+ if ((ignore >= IGNORE_NONFOCUS) &&
+ focus_client != test) continue;
+ */
+ /* don't ignore this window, so remove it from the available
+ area */
+ spaces = area_remove(spaces, &test->frame->area);
+ }
- if (ignore < IGNORE_DOCK) {
- Rect a;
- dock_get_area(&a);
- spaces = area_remove(spaces, &a);
- }
+ if (ignore < IGNORE_DOCK) {
+ Rect a;
+ dock_get_area(&a);
+ spaces = area_remove(spaces, &a);
+ }
- for (sit = spaces; sit; sit = g_slist_next(sit)) {
- Rect *r = sit->data;
+ for (sit = spaces; sit; sit = g_slist_next(sit)) {
+ Rect *r = sit->data;
- if (r->width >= c->frame->area.width &&
- r->height >= c->frame->area.height &&
- r->width * r->height > maxsize)
- {
- maxsize = r->width * r->height;
- maxit = sit;
- }
+ if (r->width >= c->frame->area.width &&
+ r->height >= c->frame->area.height &&
+ r->width * r->height > maxsize)
+ {
+ maxsize = r->width * r->height;
+ maxit = sit;
}
+ }
- if (maxit) {
- Rect *r = maxit->data;
+ if (maxit) {
+ Rect *r = maxit->data;
- /* center it in the area */
- *x = r->x;
- *y = r->y;
- if (config_place_center) {
- *x += (r->width - c->frame->area.width) / 2;
- *y += (r->height - c->frame->area.height) / 2;
- }
- ret = TRUE;
+ /* center it in the area */
+ *x = r->x;
+ *y = r->y;
+ if (config_place_center) {
+ *x += (r->width - c->frame->area.width) / 2;
+ *y += (r->height - c->frame->area.height) / 2;
}
+ ret = TRUE;
+ }
- while (spaces) {
- g_slice_free(Rect, spaces->data);
- spaces = g_slist_delete_link(spaces, spaces);
- }
+ while (spaces) {
+ g_slice_free(Rect, spaces->data);
+ spaces = g_slist_delete_link(spaces, spaces);
}
}
- for (i = 0; i < screen_num_monitors; ++i)
- g_slice_free(Rect, areas[i]);
- g_free(areas);
return ret;
}
@@ -349,6 +419,8 @@ static gboolean place_under_mouse(ObClient *client, gint *x, gint *y)
gint px, py;
Rect *area;
+ ob_debug("placing under mouse");
+
if (!screen_pointer_pos(&px, &py))
return FALSE;
area = pick_pointer_head(client);
@@ -376,27 +448,17 @@ static gboolean place_per_app_setting(ObClient *client, gint *x, gint *y,
if (!settings || (settings && !settings->pos_given))
return FALSE;
+ ob_debug("placing by per-app settings");
+
/* Find which head the pointer is on */
if (settings->monitor == 0)
/* this can return NULL */
screen = pick_pointer_head(client);
- else if (settings->monitor > 0 &&
- (guint)settings->monitor <= screen_num_monitors)
- screen = screen_area(client->desktop, (guint)settings->monitor - 1,
- NULL);
-
- /* if we have't found a screen yet.. */
- if (!screen) {
- Rect **areas;
- guint i;
-
- areas = pick_head(client);
- screen = areas[0];
-
- /* don't free the first one, it's being set as "screen" */
- for (i = 1; i < screen_num_monitors; ++i)
- g_slice_free(Rect, areas[i]);
- g_free(areas);
+ else {
+ guint m = settings->monitor;
+ if (m < 1 || m > screen_num_monitors)
+ m = screen_monitor_primary(TRUE) + 1;
+ screen = screen_area(client->desktop, m - 1, NULL);
}
if (settings->position.x.center)
@@ -423,12 +485,16 @@ static gboolean place_per_app_setting(ObClient *client, gint *x, gint *y,
return TRUE;
}
-static gboolean place_transient_splash(ObClient *client, gint *x, gint *y)
+static gboolean place_transient_splash(ObClient *client, Rect *area,
+ gint *x, gint *y)
{
if (client->type == OB_CLIENT_TYPE_DIALOG) {
GSList *it;
gboolean first = TRUE;
gint l, r, t, b;
+
+ ob_debug("placing dialog");
+
for (it = client->parents; it; it = g_slist_next(it)) {
ObClient *m = it->data;
if (!m->iconic) {
@@ -456,17 +522,10 @@ static gboolean place_transient_splash(ObClient *client, gint *x, gint *y)
if (client->type == OB_CLIENT_TYPE_DIALOG ||
client->type == OB_CLIENT_TYPE_SPLASH)
{
- Rect **areas;
- guint i;
-
- areas = pick_head(client);
+ ob_debug("placing dialog or splash");
- *x = (areas[0]->width - client->frame->area.width) / 2 + areas[0]->x;
- *y = (areas[0]->height - client->frame->area.height) / 2 + areas[0]->y;
-
- for (i = 0; i < screen_num_monitors; ++i)
- g_slice_free(Rect, areas[i]);
- g_free(areas);
+ *x = (area->width - client->frame->area.width) / 2 + area->x;
+ *y = (area->height - client->frame->area.height) / 2 + area->y;
return TRUE;
}
@@ -475,9 +534,10 @@ static gboolean place_transient_splash(ObClient *client, gint *x, gint *y)
/*! Return TRUE if openbox chose the position for the window, and FALSE if
the application chose it */
-gboolean place_client(ObClient *client, gint *x, gint *y,
+gboolean place_client(ObClient *client, gboolean foreground, gint *x, gint *y,
ObAppSettings *settings)
{
+ Rect *area;
gboolean ret;
/* per-app settings override program specified position
@@ -488,15 +548,19 @@ gboolean place_client(ObClient *client, gint *x, gint *y,
!(settings && settings->pos_given)))
return FALSE;
+ area = pick_head(client, foreground);
+
/* try a number of methods */
ret = place_per_app_setting(client, x, y, settings) ||
- place_transient_splash(client, x, y) ||
+ place_transient_splash(client, area, x, y) ||
(config_place_policy == OB_PLACE_POLICY_MOUSE &&
place_under_mouse(client, x, y)) ||
- place_nooverlap(client, x, y) ||
- place_random(client, x, y);
+ place_nooverlap(client, area, x, y) ||
+ place_random(client, area, x, y);
g_assert(ret);
+ g_slice_free(Rect, area);
+
/* get where the client should be */
frame_frame_gravity(client->frame, x, y);
return TRUE;
diff --git a/openbox/place.h b/openbox/place.h
index 6a9add40..94e2dc0f 100644
--- a/openbox/place.h
+++ b/openbox/place.h
@@ -35,10 +35,11 @@ typedef enum
{
OB_PLACE_MONITOR_ANY,
OB_PLACE_MONITOR_ACTIVE,
- OB_PLACE_MONITOR_MOUSE
+ OB_PLACE_MONITOR_MOUSE,
+ OB_PLACE_MONITOR_PRIMARY
} ObPlaceMonitor;
-gboolean place_client(struct _ObClient *client, gint *x, gint *y,
- struct _ObAppSettings *settings);
+gboolean place_client(struct _ObClient *client, gboolean foreground,
+ gint *x, gint *y, struct _ObAppSettings *settings);
#endif
diff --git a/openbox/prompt.c b/openbox/prompt.c
index ae7f38f0..785b46c7 100644
--- a/openbox/prompt.c
+++ b/openbox/prompt.c
@@ -175,7 +175,7 @@ ObPrompt* prompt_new(const gchar *msg, const gchar *title,
/* set the window's title */
if (title)
- OBT_PROP_SETS(self->super.window, NET_WM_NAME, utf8, title);
+ OBT_PROP_SETS(self->super.window, NET_WM_NAME, title);
/* listen for key presses on the window */
self->event_mask = KeyPressMask;
diff --git a/openbox/screen.c b/openbox/screen.c
index 353d2de0..d368cab6 100644
--- a/openbox/screen.c
+++ b/openbox/screen.c
@@ -206,7 +206,7 @@ gboolean screen_annex(void)
NET_SUPPORTING_WM_CHECK, WINDOW, screen_support_win);
/* set properties on the supporting window */
- OBT_PROP_SETS(screen_support_win, NET_WM_NAME, utf8, "Openbox");
+ OBT_PROP_SETS(screen_support_win, NET_WM_NAME, "Openbox");
OBT_PROP_SET32(screen_support_win, NET_SUPPORTING_WM_CHECK,
WINDOW, screen_support_win);
@@ -311,7 +311,7 @@ gboolean screen_annex(void)
NET_SUPPORTED, ATOM, supported, num_support);
g_free(supported);
- OBT_PROP_SETS(RootWindow(obt_display, ob_screen), OB_VERSION, utf8,
+ OBT_PROP_SETS(RootWindow(obt_display, ob_screen), OB_VERSION,
OPENBOX_VERSION);
screen_tell_ksplash();
@@ -375,7 +375,7 @@ void screen_startup(gboolean reconfig)
screen_resize();
/* have names already been set for the desktops? */
- if (OBT_PROP_GETSS(obt_root(ob_screen), NET_DESKTOP_NAMES, utf8, &names)) {
+ if (OBT_PROP_GETSS_UTF8(obt_root(ob_screen), NET_DESKTOP_NAMES, &names)) {
g_strfreev(names);
namesexist = TRUE;
}
@@ -397,7 +397,7 @@ void screen_startup(gboolean reconfig)
/* set the root window property */
OBT_PROP_SETSS(obt_root(ob_screen),
- NET_DESKTOP_NAMES, utf8, (const gchar*const*)names);
+ NET_DESKTOP_NAMES, (const gchar*const*)names);
g_strfreev(names);
}
@@ -500,11 +500,12 @@ void screen_resize(void)
if (ob_state() != OB_STATE_RUNNING)
return;
- screen_update_areas();
+ /* this calls screen_update_areas(), which we need ! */
dock_configure();
- for (it = client_list; it; it = g_list_next(it))
- client_move_onscreen(it->data, FALSE);
+ if (oldw)
+ for (it = client_list; it; it = g_list_next(it))
+ client_move_onscreen(it->data, FALSE);
}
void screen_set_num_desktops(guint num)
@@ -1182,7 +1183,7 @@ void screen_update_desktop_names(void)
screen_desktop_names = NULL;
if (OBT_PROP_GETSS(obt_root(ob_screen),
- NET_DESKTOP_NAMES, utf8, &screen_desktop_names))
+ NET_DESKTOP_NAMES, &screen_desktop_names))
for (i = 0; screen_desktop_names[i] && i < screen_num_desktops; ++i);
else
i = 0;
@@ -1209,7 +1210,7 @@ void screen_update_desktop_names(void)
/* if we changed any names, then set the root property so we can
all agree on the names */
OBT_PROP_SETSS(obt_root(ob_screen), NET_DESKTOP_NAMES,
- utf8, (const gchar*const*)screen_desktop_names);
+ (const gchar*const*)screen_desktop_names);
}
/* resize the pager for these names */
@@ -1458,10 +1459,8 @@ void screen_update_areas(void)
dims, 4 * screen_num_desktops);
/* the area has changed, adjust all the windows if they need it */
- for (it = onscreen; it; it = g_list_next(it)) {
- client_move_onscreen(it->data, FALSE);
+ for (it = onscreen; it; it = g_list_next(it))
client_reconfigure(it->data, FALSE);
- }
g_free(dims);
}
@@ -1653,7 +1652,7 @@ guint screen_find_monitor(const Rect *search)
}
}
}
- return most;
+ return most < screen_num_monitors ? most : screen_monitor_primary(FALSE);
}
const Rect* screen_physical_area_all_monitors(void)
@@ -1754,3 +1753,12 @@ gboolean screen_pointer_pos(gint *x, gint *y)
}
return ret;
}
+
+gboolean screen_compare_desktops(guint a, guint b)
+{
+ if (a == DESKTOP_ALL)
+ a = screen_desktop;
+ if (b == DESKTOP_ALL)
+ b = screen_desktop;
+ return a == b;
+}
diff --git a/openbox/screen.h b/openbox/screen.h
index d15b352c..a6a3995b 100644
--- a/openbox/screen.h
+++ b/openbox/screen.h
@@ -164,4 +164,12 @@ gboolean screen_pointer_pos(gint *x, gint *y);
/*! Returns the monitor which contains the pointer device */
guint screen_monitor_pointer(void);
+/*! Compare the desktop for two windows to see if they are considered on the
+ same desktop.
+ Windows that are on "all desktops" are treated like they are only on the
+ current desktop, so they are only in one place at a time.
+ @return TRUE if they are on the same desktop, FALSE otherwise.
+*/
+gboolean screen_compare_desktops(guint a, guint b);
+
#endif
diff --git a/openbox/stacking.c b/openbox/stacking.c
index 58a85eca..58551b5d 100644
--- a/openbox/stacking.c
+++ b/openbox/stacking.c
@@ -571,17 +571,16 @@ static gboolean stacking_occluded(ObClient *client, ObClient *sibling)
{
GList *it;
gboolean occluded = FALSE;
- gboolean found = FALSE;
/* no need for any looping in this case */
if (sibling && client->layer != sibling->layer)
return occluded;
- for (it = stacking_list; it;
- it = (found ? g_list_previous(it) :g_list_next(it)))
+ for (it = g_list_previous(g_list_find(stacking_list, client)); it;
+ it = g_list_previous(it))
if (WINDOW_IS_CLIENT(it->data)) {
ObClient *c = it->data;
- if (found && !c->iconic &&
+ if (!c->iconic &&
(c->desktop == DESKTOP_ALL || client->desktop == DESKTOP_ALL ||
c->desktop == client->desktop) &&
!client_search_transient(client, c))
@@ -602,8 +601,6 @@ static gboolean stacking_occluded(ObClient *client, ObClient *sibling)
break; /* we past its layer */
}
}
- else if (c == client)
- found = TRUE;
}
return occluded;
}
@@ -615,16 +612,16 @@ static gboolean stacking_occludes(ObClient *client, ObClient *sibling)
{
GList *it;
gboolean occludes = FALSE;
- gboolean found = FALSE;
/* no need for any looping in this case */
if (sibling && client->layer != sibling->layer)
return occludes;
- for (it = stacking_list; it; it = g_list_next(it))
+ for (it = g_list_next(g_list_find(stacking_list, client));
+ it; it = g_list_next(it))
if (WINDOW_IS_CLIENT(it->data)) {
ObClient *c = it->data;
- if (found && !c->iconic &&
+ if (!c->iconic &&
(c->desktop == DESKTOP_ALL || client->desktop == DESKTOP_ALL ||
c->desktop == client->desktop) &&
!client_search_transient(c, client))
@@ -645,8 +642,6 @@ static gboolean stacking_occludes(ObClient *client, ObClient *sibling)
break; /* we past its layer */
}
}
- else if (c == client)
- found = TRUE;
}
return occludes;
}
diff --git a/openbox/startupnotify.c b/openbox/startupnotify.c
index 16654cfd..e249002b 100644
--- a/openbox/startupnotify.c
+++ b/openbox/startupnotify.c
@@ -263,7 +263,7 @@ void sn_setup_spawn_environment(const gchar *program, const gchar *name,
20 * 1000, sn_launch_wait_timeout, sn_launcher,
(GDestroyNotify)sn_launcher_context_unref);
- setenv("DESKTOP_STARTUP_ID", id, TRUE);
+ g_setenv("DESKTOP_STARTUP_ID", id, TRUE);
g_free(desc);
}
diff --git a/openbox/window.c b/openbox/window.c
index ad61294d..51806f9c 100644
--- a/openbox/window.c
+++ b/openbox/window.c
@@ -26,6 +26,7 @@
#include "prompt.h"
#include "debug.h"
#include "grab.h"
+#include "obt/prop.h"
#include "obt/xqueue.h"
static GHashTable *window_map;
@@ -186,6 +187,20 @@ void window_manage(Window win)
}
XFree(wmhints);
}
+ /* This is a new method to declare that a window is a dockapp, being
+ implemented by Windowmaker, to alleviate pain in writing GTK+
+ dock apps.
+ http://thread.gmane.org/gmane.comp.window-managers.openbox/4881
+ */
+ if (!is_dockapp) {
+ gchar **ss;
+ if (OBT_PROP_GETSS_TYPE(win, WM_CLASS, STRING_NO_CC, &ss))
+ {
+ if (ss[0] && ss[1] && strcmp(ss[1], "DockApp") == 0)
+ is_dockapp = TRUE;
+ g_strfreev(ss);
+ }
+ }
}
if (!no_manage) {