From 3b0f41dc66da86aaad4f0343bbfb632c7bbfd0c7 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Sat, 2 Feb 2008 00:59:59 -0500 Subject: fix a crash from chroot of invalid keys, and make keybindings reload better since invalid(not translated) keybindings are allowed in the tree, the tree's structure may actually need to change when reconfiguring. actually, it could need to anyways. so when re-translating all the keybindings, actually rebuild the keybinding tree. also, make the chroot building code not fail when translate fails, to match the rest of the code and avoid segfaults with chroots on invalid keys. --- openbox/keyboard.c | 39 ++++++++++++++++++++++++++++++++++++++- openbox/keytree.c | 26 +++++++++----------------- openbox/keytree.h | 1 - 3 files changed, 47 insertions(+), 19 deletions(-) (limited to 'openbox') diff --git a/openbox/keyboard.c b/openbox/keyboard.c index 4c570dfb..82d6dfdc 100644 --- a/openbox/keyboard.c +++ b/openbox/keyboard.c @@ -265,9 +265,46 @@ void keyboard_event(ObClient *client, const XEvent *e) } } +static void node_rebind(KeyBindingTree *node) +{ + if (node->first_child) { + /* find leaf nodes */ + node_rebind(node->first_child); + + /* for internal nodes, add them to the tree if they + are a chroot, but do this after adding their + children */ + if (node->chroot) + keyboard_chroot(node->keylist); + } + else { + /* for leaf nodes, rebind each action assigned to it */ + GSList *it; + while (node->actions) { + /* add each action, and remove them from the original tree so + they don't get free'd on us */ + keyboard_bind(node->keylist, node->actions->data); + node->actions = g_slist_delete_link(node->actions, node->actions); + } + + if (node->chroot) + keyboard_chroot(node->keylist); + } + + /* go through each sibling */ + if (node->next_sibling) node_rebind(node->next_sibling); +} + void keyboard_rebind(void) { - tree_rebind(keyboard_firstnode); + KeyBindingTree *old; + + old = keyboard_firstnode; + keyboard_firstnode = NULL; + node_rebind(old); + + tree_destroy(old); + set_curpos(NULL); grab_keys(TRUE); } diff --git a/openbox/keytree.c b/openbox/keytree.c index 714fffda..56cc96d4 100644 --- a/openbox/keytree.c +++ b/openbox/keytree.c @@ -68,13 +68,6 @@ KeyBindingTree *tree_build(GList *keylist) return ret; } -void tree_rebind(KeyBindingTree *node) { - GList *it = g_list_last(node->keylist); - translate_key(it->data, &node->state, &node->key); - if (node->next_sibling) tree_rebind(node->next_sibling); - if (node->first_child) tree_rebind(node->first_child); -} - void tree_assimilate(KeyBindingTree *node) { KeyBindingTree *a, *b, *tmp, *last; @@ -139,16 +132,15 @@ KeyBindingTree *tree_find(KeyBindingTree *search, gboolean *conflict) gboolean tree_chroot(KeyBindingTree *tree, GList *keylist) { guint key, state; - if (translate_key(keylist->data, &state, &key)) { - while (tree != NULL && !(tree->state == state && tree->key == key)) - tree = tree->next_sibling; - if (tree != NULL) { - if (keylist->next == NULL) { - tree->chroot = TRUE; - return TRUE; - } else - return tree_chroot(tree->first_child, keylist->next); - } + translate_key(keylist->data, &state, &key); + while (tree != NULL && !(tree->state == state && tree->key == key)) + tree = tree->next_sibling; + if (tree != NULL) { + if (keylist->next == NULL) { + tree->chroot = TRUE; + return TRUE; + } else + return tree_chroot(tree->first_child, keylist->next); } return FALSE; } diff --git a/openbox/keytree.h b/openbox/keytree.h index 0307378d..391cb154 100644 --- a/openbox/keytree.h +++ b/openbox/keytree.h @@ -41,7 +41,6 @@ KeyBindingTree *tree_build(GList *keylist); void tree_assimilate(KeyBindingTree *node); KeyBindingTree *tree_find(KeyBindingTree *search, gboolean *conflict); gboolean tree_chroot(KeyBindingTree *tree, GList *keylist); -void tree_rebind(KeyBindingTree *node); #endif -- cgit v1.2.3 From b1d4bbdb54bd4525692745bf5267765adcf8cc3e Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Sat, 2 Feb 2008 09:01:56 -0500 Subject: make fullscreen windows more xinerama and multi-screen aware instead of calling it every time a window loses focus, it is only called when a window gains focus. then, check fullscreen layered windows, if they should be moved to a lower layer. when moving a window between monitors, also check its layer and that of any fullscreen windows. let a window stay in the fullscreen layer even when it is not focused, if it is on a non-visible desktop, or if it is on a different monitor from the focused window, or if nothing else is focused --- openbox/client.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++------- openbox/client.h | 3 +++ openbox/event.c | 2 -- 3 files changed, 60 insertions(+), 10 deletions(-) (limited to 'openbox') diff --git a/openbox/client.c b/openbox/client.c index a0ba3431..e7290ca5 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -2471,7 +2471,15 @@ static ObStackingLayer calc_layer(ObClient *self) (self->decorations == 0 && !(self->max_horz && self->max_vert) && RECT_EQUAL(self->area, *monitor))) && - (client_focused(self) || client_search_focus_tree(self))) + /* you are fullscreen while you or your children are focused.. */ + (client_focused(self) || client_search_focus_tree(self) || + /* you can be fullscreen if you're on another desktop */ + (self->desktop != screen_desktop && + self->desktop != DESKTOP_ALL) || + /* and you can also be fullscreen if the focused client is on + another monitor, or nothing else is focused */ + (!focus_client || + client_monitor(focus_client) != client_monitor(self)))) l = OB_STACKING_LAYER_FULLSCREEN; else if (self->above) l = OB_STACKING_LAYER_ABOVE; else if (self->below) l = OB_STACKING_LAYER_BELOW; @@ -2497,23 +2505,54 @@ static void client_calc_layer_recursive(ObClient *self, ObClient *orig, stacking_add_nonintrusive(CLIENT_AS_WINDOW(self)); } + /* we've been restacked */ + self->visited = TRUE; + for (it = self->transients; it; it = g_slist_next(it)) client_calc_layer_recursive(it->data, orig, self->layer); } +static void client_calc_layer_internal(ObClient *self) +{ + GSList *sit; + + /* transients take on the layer of their parents */ + sit = client_search_all_top_parents(self); + + for (; sit; sit = g_slist_next(sit)) + client_calc_layer_recursive(sit->data, self, 0); +} + void client_calc_layer(ObClient *self) { - ObClient *orig; - GSList *it; + GList *it; - orig = self; + /* skip over stuff above fullscreen layer */ + for (it = stacking_list; it; it = g_list_next(it)) + if (window_layer(it->data) <= OB_STACKING_LAYER_FULLSCREEN) break; - /* transients take on the layer of their parents */ - it = client_search_all_top_parents(self); + /* find the windows in the fullscreen layer, and mark them not-visited */ + for (; it; it = g_list_next(it)) { + if (window_layer(it->data) < OB_STACKING_LAYER_FULLSCREEN) break; + else if (WINDOW_IS_CLIENT(it->data)) + WINDOW_AS_CLIENT(it->data)->visited = FALSE; + } + + client_calc_layer_internal(self); - for (; it; it = g_slist_next(it)) - client_calc_layer_recursive(it->data, orig, 0); + /* skip over stuff above fullscreen layer */ + for (it = stacking_list; it; it = g_list_next(it)) + if (window_layer(it->data) <= OB_STACKING_LAYER_FULLSCREEN) break; + + /* now recalc any windows in the fullscreen layer which have not + had their layer recalced already */ + for (; it; it = g_list_next(it)) { + if (window_layer(it->data) < OB_STACKING_LAYER_FULLSCREEN) break; + else if (WINDOW_IS_CLIENT(it->data) && + !WINDOW_AS_CLIENT(it->data)->visited) + client_calc_layer_internal(it->data); + } } gboolean client_should_show(ObClient *self) @@ -2931,6 +2970,7 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h, void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gboolean user, gboolean final, gboolean force_reply) { + Rect oldframe; gint oldw, oldh; gboolean send_resize_client; gboolean moved = FALSE, resized = FALSE, rootmoved = FALSE; @@ -2953,6 +2993,7 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, oldw = self->area.width; oldh = self->area.height; + oldframe = self->frame->area; RECT_SET(self->area, x, y, w, h); /* for app-requested resizes, always resize if 'resized' is true. @@ -3057,6 +3098,14 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, } XFlush(ob_display); + + /* if it moved between monitors, then this can affect the stacking + layer of this window or others - for fullscreen windows */ + if (screen_find_monitor(&self->frame->area) != + screen_find_monitor(&oldframe)) + { + client_calc_layer(self); + } } void client_fullscreen(ObClient *self, gboolean fs) diff --git a/openbox/client.h b/openbox/client.h index 0efeb197..84da49a3 100644 --- a/openbox/client.h +++ b/openbox/client.h @@ -304,6 +304,9 @@ struct _ObClient /*! Where the window should iconify to/from */ Rect icon_geometry; + + /*! A boolean used for algorithms which need to mark clients as visited */ + gboolean visited; }; extern GList *client_list; diff --git a/openbox/event.c b/openbox/event.c index 535e9f14..9362c80d 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -519,7 +519,6 @@ static void event_process(const XEvent *ec, gpointer data) window with RevertToParent focus */ frame_adjust_focus(client->frame, FALSE); /* focus_set_client(NULL) has already been called */ - client_calc_layer(client); } else if (e->xfocus.detail == NotifyPointerRoot || e->xfocus.detail == NotifyDetailNone || @@ -629,7 +628,6 @@ static void event_process(const XEvent *ec, gpointer data) frame_adjust_focus(client->frame, FALSE); /* focus_set_client(NULL) has already been called in this section or by focus_fallback */ - client_calc_layer(client); } } else if (client) -- cgit v1.2.3 From bbad88aa21f01a70faf824cbb2825bd7f9d95253 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Sat, 2 Feb 2008 09:22:50 -0500 Subject: add a --config-file command line option, and OB_CONFIG_FILE root hint --- openbox/openbox.c | 37 ++++++++++++++++++++++++++++++------- openbox/prop.c | 1 + openbox/prop.h | 1 + openbox/screen.c | 1 + 4 files changed, 33 insertions(+), 7 deletions(-) (limited to 'openbox') diff --git a/openbox/openbox.c b/openbox/openbox.c index 18c34d2f..7d7e0d0d 100644 --- a/openbox/openbox.c +++ b/openbox/openbox.c @@ -107,6 +107,7 @@ static KeyCode keys[OB_NUM_KEYS]; static gint exitcode = 0; static guint remote_control = 0; static gboolean being_replaced = FALSE; +static gchar *config_file = NULL; static void signal_handler(gint signal, gpointer data); static void remove_args(gint *argc, gchar **argv, gint index, gint num); @@ -246,17 +247,26 @@ gint main(gint argc, gchar **argv) config_startup(i); /* parse/load user options */ - if (parse_load_rc(NULL, &doc, &node)) { + if (parse_load_rc(config_file, &doc, &node)) { parse_tree(i, doc, node->xmlChildrenNode); parse_close(doc); - } else + } + else { g_message(_("Unable to find a valid config file, using some simple defaults")); + config_file = NULL; + } -/* - if (config_type != NULL) - PROP_SETS(RootWindow(ob_display, ob_screen), - ob_config, config_type); -*/ + if (config_file) { + gchar *p = g_filename_to_utf8(config_file, -1, + NULL, NULL, NULL); + if (p) + PROP_SETS(RootWindow(ob_display, ob_screen), + ob_config_file, p); + g_free(p); + } + else + PROP_ERASE(RootWindow(ob_display, ob_screen), + ob_config_file); /* we're done with parsing now, kill it */ parse_shutdown(i); @@ -489,6 +499,7 @@ static void print_help() g_print(_(" --help Display this help and exit\n")); g_print(_(" --version Display the version and exit\n")); g_print(_(" --replace Replace the currently running window manager\n")); + g_print(_(" --config-file FILE Specify the path to the config file to use\n")); g_print(_(" --sm-disable Disable connection to the session manager\n")); g_print(_("\nPassing messages to a running Openbox instance:\n")); g_print(_(" --reconfigure Reload Openbox's configuration\n")); @@ -566,6 +577,18 @@ static void parse_args(gint *argc, gchar **argv) else if (!strcmp(argv[i], "--exit")) { remote_control = 3; } + else if (!strcmp(argv[i], "--config-file")) { + if (i == *argc - 1) /* no args left */ + /* not translated cuz it's sekret */ + g_printerr(_("--config-file requires an argument\n")); + else { + /* this will be in the current locale encoding, which is + what we want */ + config_file = argv[i+1]; + ++i; /* skip the argument */ + ob_debug("--config-file %s\n", config_file); + } + } else if (!strcmp(argv[i], "--sm-save-file")) { if (i == *argc - 1) /* no args left */ /* not translated cuz it's sekret */ diff --git a/openbox/prop.c b/openbox/prop.c index c4b8baea..c2b0b40f 100644 --- a/openbox/prop.c +++ b/openbox/prop.c @@ -172,6 +172,7 @@ void prop_startup(void) CREATE(openbox_pid, "_OPENBOX_PID"); CREATE(ob_theme, "_OB_THEME"); + CREATE(ob_config_file, "_OB_CONFIG_FILE"); CREATE(ob_wm_action_undecorate, "_OB_WM_ACTION_UNDECORATE"); CREATE(ob_wm_state_undecorated, "_OB_WM_STATE_UNDECORATED"); CREATE(ob_control, "_OB_CONTROL"); diff --git a/openbox/prop.h b/openbox/prop.h index 5ca70470..464fe26d 100644 --- a/openbox/prop.h +++ b/openbox/prop.h @@ -194,6 +194,7 @@ typedef struct Atoms { Atom ob_wm_state_undecorated; Atom openbox_pid; /* this is depreecated in favour of ob_control */ Atom ob_theme; + Atom ob_config_file; Atom ob_control; } Atoms; extern Atoms prop_atoms; diff --git a/openbox/screen.c b/openbox/screen.c index 932b157e..73429bc9 100644 --- a/openbox/screen.c +++ b/openbox/screen.c @@ -300,6 +300,7 @@ gboolean screen_annex(void) supported[i++] = prop_atoms.ob_wm_state_undecorated; supported[i++] = prop_atoms.openbox_pid; supported[i++] = prop_atoms.ob_theme; + supported[i++] = prop_atoms.ob_config_file; supported[i++] = prop_atoms.ob_control; g_assert(i == num_support); -- cgit v1.2.3 From c64be9066eaae89839bb59c4d4e9539f2a7e8fc1 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Sat, 2 Feb 2008 11:01:14 -0500 Subject: comment typo --- openbox/event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbox') diff --git a/openbox/event.c b/openbox/event.c index 9362c80d..caf6f5af 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -701,7 +701,7 @@ static void event_process(const XEvent *ec, gpointer data) if (e->type == ButtonPress || e->type == ButtonRelease) { /* If the button press was on some non-root window, or was physically - on the root window, the process it */ + on the root window, then process it */ if (window != RootWindow(ob_display, ob_screen) || e->xbutton.subwindow == None) { -- cgit v1.2.3 From 746859c1017e9cdf73eb91470e795f0c4b98b21a Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Sat, 2 Feb 2008 11:22:17 -0500 Subject: if windows on screen are going to be moved, then do the ReplayPointer before that occurs, so it goes to the right window. if they are not, then just wait until after the actions are run (for kdesktop's sake really) --- openbox/actions.c | 20 +++++++++++++++++++- openbox/actions.h | 11 +++++++++-- openbox/actions/desktop.c | 2 ++ openbox/mouse.c | 22 ++++++++++++++++++---- 4 files changed, 48 insertions(+), 7 deletions(-) (limited to 'openbox') diff --git a/openbox/actions.c b/openbox/actions.c index a236b581..b7ba5b44 100644 --- a/openbox/actions.c +++ b/openbox/actions.c @@ -23,6 +23,7 @@ #include "event.h" #include "config.h" #include "client.h" +#include "openbox.h" #include "debug.h" #include "actions/all.h" @@ -35,6 +36,7 @@ static ObActionsAct* actions_build_act_from_string(const gchar *name); static ObActionsAct *interactive_act = NULL; static guint interactive_initial_state = 0; +static gboolean replay_pointer = FALSE; struct _ObActionsDefinition { guint ref; @@ -222,6 +224,16 @@ static void actions_setup_data(ObActionsData *data, data->client = client; } +void actions_set_need_pointer_replay_before_move(gboolean replay) +{ + replay_pointer = replay; +} + +gboolean actions_get_need_pointer_replay_before_move() +{ + return replay_pointer; +} + void actions_run_acts(GSList *acts, ObUserAction uact, guint state, @@ -334,8 +346,14 @@ gboolean actions_interactive_input_event(XEvent *e) void actions_client_move(ObActionsData *data, gboolean start) { static gulong ignore_start = 0; - if (start) + if (start) { ignore_start = event_start_ignore_all_enters(); + if (replay_pointer) { + /* replay the pointer event before any windows move */ + XAllowEvents(ob_display, ReplayPointer, event_curtime); + replay_pointer = FALSE; + } + } else if (config_focus_follow && data->context != OB_FRAME_CONTEXT_CLIENT) { diff --git a/openbox/actions.h b/openbox/actions.h index 477e4ba1..6db6f8d6 100644 --- a/openbox/actions.h +++ b/openbox/actions.h @@ -74,9 +74,16 @@ gboolean actions_act_is_interactive(ObActionsAct *act); void actions_act_ref(ObActionsAct *act); void actions_act_unref(ObActionsAct *act); -/*! Pass in a GSList of ObActionsAct's to be run. - @return TRUE if an action is in interactive state, FALSE is none are +/*! When this is true, an XAllowEvents with ReplayPointer will be called + if an action is going to maybe try moving windows around on screen (or + map/unmap windows) */ +void actions_set_need_pointer_replay_before_move(gboolean replay); +/*! Returns if a ReplayPointer is still needed. If it was called while running + actions then this will be false */ +gboolean actions_get_need_pointer_replay_before_move(); + +/*! Pass in a GSList of ObActionsAct's to be run. */ void actions_run_acts(GSList *acts, ObUserAction uact, guint state, diff --git a/openbox/actions/desktop.c b/openbox/actions/desktop.c index 69275252..d939ed51 100644 --- a/openbox/actions/desktop.c +++ b/openbox/actions/desktop.c @@ -140,12 +140,14 @@ static gboolean run_func(ObActionsData *data, gpointer options) if (d < screen_num_desktops && d != screen_desktop) { gboolean go = TRUE; + actions_client_move(data, TRUE); if (o->send && data->client && client_normal(data->client)) { client_set_desktop(data->client, d, o->follow, FALSE); go = o->follow; } if (go) screen_set_desktop(d, TRUE); + actions_client_move(data, FALSE); } return FALSE; } diff --git a/openbox/mouse.c b/openbox/mouse.c index 66615585..711317ec 100644 --- a/openbox/mouse.c +++ b/openbox/mouse.c @@ -225,6 +225,17 @@ void mouse_event(ObClient *client, XEvent *e) button = e->xbutton.button; state = e->xbutton.state; + /* if the binding was in a client context, then we need to call + XAllowEvents with ReplayPointer at some point, to send the event + through to the client. when this happens though depends. if + windows are going to be moved on screen, then the click will end + up going somewhere wrong, so have the action system perform the + ReplayPointer for us if that is the case. */ + if (CLIENT_CONTEXT(context, client)) + actions_set_need_pointer_replay_before_move(TRUE); + else + actions_set_need_pointer_replay_before_move(FALSE); + fire_binding(OB_MOUSE_ACTION_PRESS, context, client, e->xbutton.state, e->xbutton.button, @@ -235,11 +246,14 @@ void mouse_event(ObClient *client, XEvent *e) if (grab_on_pointer()) button = 0; - if (CLIENT_CONTEXT(context, client)) { - /* Replay the event, so it goes to the client*/ + /* replay the pointer event if it hasn't been replayed yet (i.e. no + windows were moved) */ + if (actions_get_need_pointer_replay_before_move()) XAllowEvents(ob_display, ReplayPointer, event_curtime); - /* Fall through to the release case! */ - } else + + /* in the client context, we won't get a button release because of the + way it is grabbed, so just fake one */ + if (!CLIENT_CONTEXT(context, client)) break; case ButtonRelease: -- cgit v1.2.3