diff options
Diffstat (limited to 'openbox')
| -rw-r--r-- | openbox/actions.c | 9 | ||||
| -rw-r--r-- | openbox/actions/execute.c | 2 | ||||
| -rw-r--r-- | openbox/actions/if.c | 17 | ||||
| -rw-r--r-- | openbox/client.c | 443 | ||||
| -rw-r--r-- | openbox/client.h | 9 | ||||
| -rw-r--r-- | openbox/config.c | 54 | ||||
| -rw-r--r-- | openbox/debug.c | 2 | ||||
| -rw-r--r-- | openbox/dock.c | 4 | ||||
| -rw-r--r-- | openbox/event.c | 96 | ||||
| -rw-r--r-- | openbox/event.h | 13 | ||||
| -rw-r--r-- | openbox/focus.c | 4 | ||||
| -rw-r--r-- | openbox/focus_cycle.c | 3 | ||||
| -rw-r--r-- | openbox/frame.c | 13 | ||||
| -rw-r--r-- | openbox/menu.c | 44 | ||||
| -rw-r--r-- | openbox/menu.h | 13 | ||||
| -rw-r--r-- | openbox/menuframe.c | 20 | ||||
| -rw-r--r-- | openbox/moveresize.c | 10 | ||||
| -rw-r--r-- | openbox/openbox.c | 23 | ||||
| -rw-r--r-- | openbox/place.c | 472 | ||||
| -rw-r--r-- | openbox/place.h | 7 | ||||
| -rw-r--r-- | openbox/prompt.c | 2 | ||||
| -rw-r--r-- | openbox/screen.c | 34 | ||||
| -rw-r--r-- | openbox/screen.h | 8 | ||||
| -rw-r--r-- | openbox/stacking.c | 17 | ||||
| -rw-r--r-- | openbox/startupnotify.c | 2 | ||||
| -rw-r--r-- | openbox/window.c | 15 |
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) { |
