diff options
Diffstat (limited to 'openbox')
45 files changed, 967 insertions, 274 deletions
diff --git a/openbox/actions.c b/openbox/actions.c index 75d4af05..0c84489a 100644 --- a/openbox/actions.c +++ b/openbox/actions.c @@ -124,7 +124,7 @@ static void actions_definition_unref(ObActionsDefinition *def) } } -ObActionsAct* actions_build_act_from_string(const gchar *name) +static ObActionsAct* actions_build_act_from_string(const gchar *name) { GSList *it; ObActionsDefinition *def = NULL; diff --git a/openbox/actions/cyclewindows.c b/openbox/actions/cyclewindows.c index 965ac993..059db93f 100644 --- a/openbox/actions/cyclewindows.c +++ b/openbox/actions/cyclewindows.c @@ -1,4 +1,6 @@ #include "openbox/actions.h" +#include "openbox/stacking.h" +#include "openbox/window.h" #include "openbox/event.h" #include "openbox/focus_cycle.h" #include "openbox/openbox.h" @@ -11,6 +13,8 @@ typedef struct { gboolean desktop_windows; gboolean all_desktops; gboolean forward; + gboolean bar; + gboolean raise; GSList *actions; } Options; @@ -46,11 +50,16 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node) o = g_new0(Options, 1); o->dialog = TRUE; + o->bar = TRUE; if ((n = parse_find_node("linear", node))) o->linear = parse_bool(doc, n); if ((n = parse_find_node("dialog", node))) o->dialog = parse_bool(doc, n); + if ((n = parse_find_node("bar", node))) + o->bar = parse_bool(doc, n); + if ((n = parse_find_node("raise", node))) + o->raise = parse_bool(doc, n); if ((n = parse_find_node("panels", node))) o->dock_windows = parse_bool(doc, n); if ((n = parse_find_node("desktop", node))) @@ -111,17 +120,22 @@ static void free_func(gpointer options) static gboolean run_func(ObActionsData *data, gpointer options) { Options *o = options; + struct _ObClient *ft; - focus_cycle(o->forward, - o->all_desktops, - o->dock_windows, - o->desktop_windows, - o->linear, - TRUE, - o->dialog, - FALSE, FALSE); + ft = focus_cycle(o->forward, + o->all_desktops, + o->dock_windows, + o->desktop_windows, + o->linear, + TRUE, + o->bar, + o->dialog, + FALSE, FALSE); cycling = TRUE; + stacking_restore(); + if (o->raise) stacking_temp_raise(CLIENT_AS_WINDOW(ft)); + return TRUE; } @@ -174,12 +188,14 @@ static void end_cycle(gboolean cancel, guint state, Options *o) o->desktop_windows, o->linear, TRUE, + o->bar, o->dialog, TRUE, cancel); cycling = FALSE; - if (ft) { + if (ft) actions_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY, state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft); - } + + stacking_restore(); } diff --git a/openbox/actions/directionalwindows.c b/openbox/actions/directionalwindows.c index 707659eb..c575d84e 100644 --- a/openbox/actions/directionalwindows.c +++ b/openbox/actions/directionalwindows.c @@ -1,5 +1,7 @@ #include "openbox/actions.h" #include "openbox/event.h" +#include "openbox/stacking.h" +#include "openbox/window.h" #include "openbox/focus_cycle.h" #include "openbox/openbox.h" #include "openbox/misc.h" @@ -11,6 +13,8 @@ typedef struct { gboolean dock_windows; gboolean desktop_windows; ObDirection direction; + gboolean bar; + gboolean raise; GSList *actions; } Options; @@ -46,9 +50,14 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node) o = g_new0(Options, 1); o->dialog = TRUE; + o->bar = TRUE; if ((n = parse_find_node("dialog", node))) o->dialog = parse_bool(doc, n); + if ((n = parse_find_node("bar", node))) + o->bar = parse_bool(doc, n); + if ((n = parse_find_node("raise", node))) + o->raise = parse_bool(doc, n); if ((n = parse_find_node("panels", node))) o->dock_windows = parse_bool(doc, n); if ((n = parse_find_node("desktop", node))) @@ -135,13 +144,19 @@ static gboolean run_func(ObActionsData *data, gpointer options) if (!o->interactive) end_cycle(FALSE, data->state, o); else { - focus_directional_cycle(o->direction, - o->dock_windows, - o->desktop_windows, - TRUE, - o->dialog, - FALSE, FALSE); + struct _ObClient *ft; + + ft = focus_directional_cycle(o->direction, + o->dock_windows, + o->desktop_windows, + TRUE, + o->bar, + o->dialog, + FALSE, FALSE); cycling = TRUE; + + stacking_restore(); + if (o->raise) stacking_temp_raise(CLIENT_AS_WINDOW(ft)); } return o->interactive; @@ -194,12 +209,14 @@ static void end_cycle(gboolean cancel, guint state, Options *o) o->dock_windows, o->desktop_windows, o->interactive, + o->bar, o->dialog, TRUE, cancel); cycling = FALSE; - if (ft) { + if (ft) actions_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY, state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft); - } + + stacking_restore(); } diff --git a/openbox/actions/lower.c b/openbox/actions/lower.c index 3a214ea7..d34e933b 100644 --- a/openbox/actions/lower.c +++ b/openbox/actions/lower.c @@ -1,5 +1,6 @@ #include "openbox/actions.h" #include "openbox/stacking.h" +#include "openbox/window.h" static gboolean run_func(ObActionsData *data, gpointer options); diff --git a/openbox/actions/raise.c b/openbox/actions/raise.c index 5dfe281a..6837bce2 100644 --- a/openbox/actions/raise.c +++ b/openbox/actions/raise.c @@ -1,5 +1,6 @@ #include "openbox/actions.h" #include "openbox/stacking.h" +#include "openbox/window.h" static gboolean run_func(ObActionsData *data, gpointer options); diff --git a/openbox/actions/resize.c b/openbox/actions/resize.c index 81901bdd..3714e38b 100644 --- a/openbox/actions/resize.c +++ b/openbox/actions/resize.c @@ -5,6 +5,7 @@ #include "openbox/frame.h" typedef struct { + gboolean corner_specified; guint32 corner; } Options; @@ -33,6 +34,8 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node) if ((n = parse_find_node("edge", node))) { gchar *s = parse_string(doc, n); + + o->corner_specified = TRUE; if (!g_ascii_strcasecmp(s, "top")) o->corner = prop_atoms.net_wm_moveresize_size_top; else if (!g_ascii_strcasecmp(s, "bottom")) @@ -49,6 +52,9 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node) o->corner = prop_atoms.net_wm_moveresize_size_bottomleft; else if (!g_ascii_strcasecmp(s, "bottomright")) o->corner = prop_atoms.net_wm_moveresize_size_bottomright; + else + o->corner_specified = FALSE; + g_free(s); } return o; @@ -72,7 +78,7 @@ static gboolean run_func(ObActionsData *data, gpointer options) if (!data->button) corner = prop_atoms.net_wm_moveresize_size_keyboard; - else if (o->corner) + else if (o->corner_specified) corner = o->corner; /* it was specified in the binding */ else corner = pick_corner(data->x, data->y, diff --git a/openbox/client.c b/openbox/client.c index d0fed545..63245a3c 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -24,6 +24,7 @@ #include "xerror.h" #include "screen.h" #include "moveresize.h" +#include "ping.h" #include "place.h" #include "prop.h" #include "extensions.h" @@ -40,11 +41,16 @@ #include "keyboard.h" #include "mouse.h" #include "render/render.h" +#include "gettext.h" #ifdef HAVE_UNISTD_H # include <unistd.h> #endif +#ifdef HAVE_SIGNAL_H +# include <signal.h> /* for kill() */ +#endif + #include <glib.h> #include <X11/Xutil.h> @@ -74,6 +80,10 @@ static void client_get_state(ObClient *self); static void client_get_shaped(ObClient *self); static void client_get_mwm_hints(ObClient *self); static void client_get_colormap(ObClient *self); +static void client_set_desktop_recursive(ObClient *self, + guint target, + gboolean donthide, + gboolean dontraise); static void client_change_allowed_actions(ObClient *self); static void client_change_state(ObClient *self); static void client_change_wm_state(ObClient *self); @@ -93,6 +103,7 @@ static GSList *client_search_all_top_parents_internal(ObClient *self, gboolean bylayer, ObStackingLayer layer); static void client_call_notifies(ObClient *self, GSList *list); +static void client_ping_event(ObClient *self, gboolean dead); void client_startup(gboolean reconfig) @@ -450,6 +461,8 @@ void client_manage(Window window) g_free(monitor); monitor = NULL; + ob_debug_type(OB_DEBUG_FOCUS, "Going to try activate new window? %s\n", + activate ? "yes" : "no"); if (activate) { gboolean raise = FALSE; @@ -594,6 +607,15 @@ void client_manage(Window window) /* update the list hints */ client_set_list(); + /* watch for when the application stops responding. only do this for + normal windows, i.e. windows which have titlebars and close buttons + and things like that. + we don't need to stop pinging on unmanage, because it will be handled + automatically by the destroy callback! + */ + if (self->ping && client_normal(self)) + ping_start(self, client_ping_event); + /* free the ObAppSettings shallow copy */ g_free(settings); @@ -760,6 +782,11 @@ void client_unmanage(ObClient *self) XMapWindow(ob_display, self->window); } + /* these should not be left on the window ever. other window managers + don't necessarily use them and it will mess them up (like compiz) */ + PROP_ERASE(self->window, net_wm_visible_name); + PROP_ERASE(self->window, net_wm_visible_icon_name); + /* update the list hints */ client_set_list(); @@ -1500,6 +1527,10 @@ void client_update_protocols(ObClient *self) /* if this protocol is requested, then the window will be notified whenever we want it to receive focus */ self->focus_notify = TRUE; + else if (proto[i] == prop_atoms.net_wm_ping) + /* if this protocol is requested, then the window will allow + pings to determine if it is still alive */ + self->ping = TRUE; #ifdef SYNC else if (proto[i] == prop_atoms.net_wm_sync_request) /* if this protocol is requested, then resizing the @@ -1524,7 +1555,7 @@ void client_update_sync_request_counter(ObClient *self) } #endif -void client_get_colormap(ObClient *self) +static void client_get_colormap(ObClient *self) { XWindowAttributes wa; @@ -1634,11 +1665,16 @@ void client_setup_decor_and_functions(ObClient *self, gboolean reconfig) switch (self->type) { case OB_CLIENT_TYPE_NORMAL: /* normal windows retain all of the possible decorations and - functionality, and are the only windows that you can fullscreen */ + functionality, and can be fullscreen */ self->functions |= OB_CLIENT_FUNC_FULLSCREEN; break; case OB_CLIENT_TYPE_DIALOG: + /* sometimes apps make dialog windows fullscreen for some reason (for + e.g. kpdf does this..) */ + self->functions |= OB_CLIENT_FUNC_FULLSCREEN; + break; + case OB_CLIENT_TYPE_UTILITY: /* these windows don't have anything added or removed by default */ break; @@ -1931,6 +1967,15 @@ void client_update_title(ObClient *self) } else visible = data; + if (self->not_responding) { + data = visible; + if (self->close_tried_term) + visible = g_strdup_printf("%s - [%s]", data, _("Killing...")); + else + visible = g_strdup_printf("%s - [%s]", data, _("Not Responding")); + g_free(data); + } + PROP_SETS(self->window, net_wm_visible_name, visible); self->title = visible; @@ -1954,6 +1999,15 @@ void client_update_title(ObClient *self) } else visible = data; + if (self->not_responding) { + data = visible; + if (self->close_tried_term) + visible = g_strdup_printf("%s - [%s]", data, _("Killing...")); + else + visible = g_strdup_printf("%s - [%s]", data, _("Not Responding")); + g_free(data); + } + PROP_SETS(self->window, net_wm_visible_icon_name, visible); self->icon_title = visible; } @@ -2214,6 +2268,7 @@ static void client_get_session_ids(ObClient *self) if (got) { gchar localhost[128]; + guint32 pid; gethostname(localhost, 127); localhost[127] = '\0'; @@ -2221,6 +2276,11 @@ static void client_get_session_ids(ObClient *self) self->client_machine = s; else g_free(s); + + /* see if it has the PID set too (the PID requires that the + WM_CLIENT_MACHINE be set) */ + if (PROP_GET32(self->window, net_wm_pid, cardinal, &pid)) + self->pid = pid; } } @@ -3150,41 +3210,58 @@ void client_shade(ObClient *self, gboolean shade) frame_adjust_area(self->frame, FALSE, TRUE, FALSE); } -void client_close(ObClient *self) +static void client_ping_event(ObClient *self, gboolean dead) { - XEvent ce; + self->not_responding = dead; + client_update_title(self); + + if (!dead) { + /* try kill it nicely the first time again, if it started responding + at some point */ + self->close_tried_term = FALSE; + } +} +void client_close(ObClient *self) +{ if (!(self->functions & OB_CLIENT_FUNC_CLOSE)) return; /* in the case that the client provides no means to requesting that it close, we just kill it */ if (!self->delete_window) + /* don't use client_kill(), we should only kill based on PID in + response to a lack of PING replies */ + XKillClient(ob_display, self->window); + else if (self->not_responding) client_kill(self); - - /* - XXX: itd be cool to do timeouts and shit here for killing the client's - process off - like... if the window is around after 5 seconds, then the close button - turns a nice red, and if this function is called again, the client is - explicitly killed. - */ - - ce.xclient.type = ClientMessage; - ce.xclient.message_type = prop_atoms.wm_protocols; - ce.xclient.display = ob_display; - ce.xclient.window = self->window; - ce.xclient.format = 32; - ce.xclient.data.l[0] = prop_atoms.wm_delete_window; - ce.xclient.data.l[1] = event_curtime; - ce.xclient.data.l[2] = 0l; - ce.xclient.data.l[3] = 0l; - ce.xclient.data.l[4] = 0l; - XSendEvent(ob_display, self->window, FALSE, NoEventMask, &ce); + else + /* request the client to close with WM_DELETE_WINDOW */ + PROP_MSG_TO(self->window, self->window, wm_protocols, + prop_atoms.wm_delete_window, event_curtime, 0, 0, 0, + NoEventMask); } void client_kill(ObClient *self) { - XKillClient(ob_display, self->window); + if (!self->client_machine && self->pid) { + /* running on the local host */ + if (!self->close_tried_term) { + ob_debug("killing window 0x%x with pid %lu, with SIGTERM\n", + self->window, self->pid); + kill(self->pid, SIGTERM); + self->close_tried_term = TRUE; + + /* show that we're trying to kill it */ + client_update_title(self); + } + else { + ob_debug("killing window 0x%x with pid %lu, with SIGKILL\n", + self->window, self->pid); + kill(self->pid, SIGKILL); /* kill -9 */ + } + } + else + XKillClient(ob_display, self->window); } void client_hilite(ObClient *self, gboolean hilite) @@ -3203,10 +3280,10 @@ void client_hilite(ObClient *self, gboolean hilite) } } -void client_set_desktop_recursive(ObClient *self, - guint target, - gboolean donthide, - gboolean dontraise) +static void client_set_desktop_recursive(ObClient *self, + guint target, + gboolean donthide, + gboolean dontraise) { guint old; GSList *it; diff --git a/openbox/client.h b/openbox/client.h index b4b165f8..0efeb197 100644 --- a/openbox/client.h +++ b/openbox/client.h @@ -24,11 +24,16 @@ #include "mwm.h" #include "geom.h" #include "stacking.h" +#include "window.h" #include "render/color.h" #include <glib.h> #include <X11/Xlib.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> /* for pid_t */ +#endif + struct _ObFrame; struct _ObGroup; struct _ObSessionState; @@ -114,6 +119,8 @@ struct _ObClient gchar *client_machine; /*! The command used to run the program. Pre-XSMP window identification. */ gchar *wm_command; + /*! The PID of the process which owns the window */ + pid_t pid; /*! The application that created the window */ gchar *name; @@ -219,6 +226,14 @@ struct _ObClient /*! Notify the window when it receives focus? */ gboolean focus_notify; + /*! Will the client respond to pings? */ + gboolean ping; + /*! Indicates if the client is trying to close but has stopped responding + to pings */ + gboolean not_responding; + /*! We tried to close the window with a SIGTERM */ + gboolean close_tried_term; + #ifdef SYNC /*! The client wants to sync during resizes */ gboolean sync_request; diff --git a/openbox/client_list_combined_menu.c b/openbox/client_list_combined_menu.c index 194c927e..f7fc36b8 100644 --- a/openbox/client_list_combined_menu.c +++ b/openbox/client_list_combined_menu.c @@ -30,7 +30,7 @@ #define MENU_NAME "client-list-combined-menu" -ObMenu *combined_menu; +static ObMenu *combined_menu; #define SEPARATOR -1 #define ADD_DESKTOP -2 diff --git a/openbox/config.c b/openbox/config.c index ff4c542b..867dfb51 100644 --- a/openbox/config.c +++ b/openbox/config.c @@ -38,6 +38,7 @@ gboolean config_focus_under_mouse; ObPlacePolicy config_place_policy; gboolean config_place_center; +gboolean config_place_active; StrutPartial config_margins; @@ -59,10 +60,10 @@ GSList *config_desktops_names; guint config_screen_firstdesk; guint config_desktop_popup_time; -gboolean config_resize_redraw; -gboolean config_resize_four_corners; -gint config_resize_popup_show; -gint config_resize_popup_pos; +gboolean config_resize_redraw; +gint config_resize_popup_show; +ObResizePopupPos config_resize_popup_pos; +GravityPoint config_resize_popup_fixed; ObStackingLayer config_dock_layer; gboolean config_dock_floating; @@ -136,16 +137,28 @@ void config_app_settings_copy_non_defaults(const ObAppSettings *src, if (src->pos_given) { dst->pos_given = TRUE; - dst->center_x = src->center_x; - dst->center_y = src->center_y; - dst->opposite_x = src->opposite_x; - dst->opposite_y = src->opposite_y; - dst->position.x = src->position.x; - dst->position.y = src->position.y; + dst->position = src->position; dst->monitor = src->monitor; } } +static void config_parse_gravity_coord(xmlDocPtr doc, xmlNodePtr node, + GravityCoord *c) +{ + gchar *s = parse_string(doc, node); + if (!g_ascii_strcasecmp(s, "center")) + c->center = TRUE; + else { + if (s[0] == '-') + c->opposite = TRUE; + if (s[0] == '-' || s[0] == '+') + c->pos = atoi(s+1); + else + c->pos = atoi(s); + } + g_free(s); +} + /* <applications> <application name="aterm"> @@ -211,38 +224,16 @@ static void parse_per_app_settings(ObParseInst *inst, xmlDocPtr doc, if ((n = parse_find_node("position", app->children))) { if ((c = parse_find_node("x", n->children))) if (!parse_contains("default", doc, c)) { - gchar *s = parse_string(doc, c); - if (!g_ascii_strcasecmp(s, "center")) { - settings->center_x = TRUE; - x_pos_given = TRUE; - } else { - if (s[0] == '-') - settings->opposite_x = TRUE; - if (s[0] == '-' || s[0] == '+') - settings->position.x = atoi(s+1); - else - settings->position.x = atoi(s); - x_pos_given = TRUE; - } - g_free(s); + config_parse_gravity_coord(doc, c, + &settings->position.x); + x_pos_given = TRUE; } if (x_pos_given && (c = parse_find_node("y", n->children))) if (!parse_contains("default", doc, c)) { - gchar *s = parse_string(doc, c); - if (!g_ascii_strcasecmp(s, "center")) { - settings->center_y = TRUE; - settings->pos_given = TRUE; - } else { - if (s[0] == '-') - settings->opposite_y = TRUE; - if (s[0] == '-' || s[0] == '+') - settings->position.y = atoi(s+1); - else - settings->position.y = atoi(s); - settings->pos_given = TRUE; - } - g_free(s); + config_parse_gravity_coord(doc, c, + &settings->position.y); + settings->pos_given = TRUE; } if (settings->pos_given && @@ -500,6 +491,8 @@ static void parse_placement(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node, config_place_policy = OB_PLACE_POLICY_MOUSE; if ((n = parse_find_node("center", node))) config_place_center = parse_bool(doc, n); + if ((n = parse_find_node("active", node))) + config_place_active = parse_bool(doc, n); } static void parse_margins(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node, @@ -658,11 +651,24 @@ static void parse_resize(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node, config_resize_popup_show = 1; } if ((n = parse_find_node("popupPosition", node))) { - config_resize_popup_pos = parse_int(doc, n); if (parse_contains("Top", doc, n)) - config_resize_popup_pos = 1; + config_resize_popup_pos = OB_RESIZE_POS_TOP; else if (parse_contains("Center", doc, n)) - config_resize_popup_pos = 0; + config_resize_popup_pos = OB_RESIZE_POS_CENTER; + else if (parse_contains("Fixed", doc, n)) { + config_resize_popup_pos = OB_RESIZE_POS_FIXED; + + if ((n = parse_find_node("popupFixedPosition", node))) { + xmlNodePtr n2; + + if ((n2 = parse_find_node("x", n->children))) + config_parse_gravity_coord(doc, n2, + &config_resize_popup_fixed.x); + if ((n2 = parse_find_node("y", n->children))) + config_parse_gravity_coord(doc, n2, + &config_resize_popup_fixed.y); + } + } } } @@ -880,6 +886,7 @@ void config_startup(ObParseInst *i) config_place_policy = OB_PLACE_POLICY_SMART; config_place_center = TRUE; + config_place_active = FALSE; parse_register(i, "placement", parse_placement, NULL); @@ -908,9 +915,10 @@ void config_startup(ObParseInst *i) parse_register(i, "desktops", parse_desktops, NULL); config_resize_redraw = TRUE; - config_resize_four_corners = FALSE; config_resize_popup_show = 1; /* nonpixel increments */ - config_resize_popup_pos = 0; /* center of client */ + config_resize_popup_pos = OB_RESIZE_POS_CENTER; + GRAVITY_COORD_SET(config_resize_popup_fixed.x, 0, FALSE, FALSE); + GRAVITY_COORD_SET(config_resize_popup_fixed.y, 0, FALSE, FALSE); parse_register(i, "resize", parse_resize, NULL); diff --git a/openbox/config.h b/openbox/config.h index 9d0602e2..240b04f1 100644 --- a/openbox/config.h +++ b/openbox/config.h @@ -24,6 +24,7 @@ #include "stacking.h" #include "place.h" #include "geom.h" +#include "moveresize.h" #include "render/render.h" #include <glib.h> @@ -38,11 +39,7 @@ struct _ObAppSettings GPatternSpec *name; GPatternSpec *role; - Point position; - gboolean center_x; - gboolean center_y; - gboolean opposite_x; - gboolean opposite_y; + GravityPoint position; gboolean pos_given; guint desktop; @@ -75,9 +72,13 @@ extern gboolean config_focus_last; */ extern gboolean config_focus_under_mouse; +/*! The algorithm to use for placing new windows */ extern ObPlacePolicy config_place_policy; /*! Place windows in the center of the free area */ extern gboolean config_place_center; +/*! Place windows on the active monitor (unless they are part of an application + already on another monitor) */ +extern gboolean config_place_active; /*! User-specified margins around the edge of the screen(s) */ extern StrutPartial config_margins; @@ -88,8 +89,10 @@ extern gboolean config_resize_redraw; /*! show move/resize popups? 0 = no, 1 = always, 2 = only resizing !1 increments */ extern gint config_resize_popup_show; -/*! where to show the popup, currently above the window or centered */ -extern gint config_resize_popup_pos; +/*! where to show the resize popup */ +extern ObResizePopupPos config_resize_popup_pos; +/*! where to place the popup if it's in a fixed position */ +extern GravityPoint config_resize_popup_fixed; /*! The stacking layer the dock will reside in */ extern ObStackingLayer config_dock_layer; diff --git a/openbox/dock.c b/openbox/dock.c index 9d4b56c4..ed8bed4b 100644 --- a/openbox/dock.c +++ b/openbox/dock.c @@ -227,8 +227,10 @@ void dock_configure(void) gint l, r, t, b; gint strw, strh; Rect *a; + gint hidesize; RrMargins(dock->a_frame, &l, &t, &r, &b); + hidesize = MAX(1, ob_rr_theme->obwidth); dock->area.width = dock->area.height = 0; @@ -361,51 +363,51 @@ void dock_configure(void) case OB_DIRECTION_NORTHWEST: switch (config_dock_orient) { case OB_ORIENTATION_HORZ: - dock->area.y -= dock->area.height - ob_rr_theme->obwidth; + dock->area.y -= dock->area.height - hidesize; break; case OB_ORIENTATION_VERT: - dock->area.x -= dock->area.width - ob_rr_theme->obwidth; + dock->area.x -= dock->area.width - hidesize; break; } break; case OB_DIRECTION_NORTH: - dock->area.y -= dock->area.height - ob_rr_theme->obwidth; + dock->area.y -= dock->area.height - hidesize; break; case OB_DIRECTION_NORTHEAST: switch (config_dock_orient) { case OB_ORIENTATION_HORZ: - dock->area.y -= dock->area.height - ob_rr_theme->obwidth; + dock->area.y -= dock->area.height - hidesize; break; case OB_ORIENTATION_VERT: - dock->area.x += dock->area.width - ob_rr_theme->obwidth; + dock->area.x += dock->area.width - hidesize; break; } break; case OB_DIRECTION_WEST: - dock->area.x -= dock->area.width - ob_rr_theme->obwidth; + dock->area.x -= dock->area.width - hidesize; break; case OB_DIRECTION_EAST: - dock->area.x += dock->area.width - ob_rr_theme->obwidth; + dock->area.x += dock->area.width - hidesize; break; case OB_DIRECTION_SOUTHWEST: switch (config_dock_orient) { case OB_ORIENTATION_HORZ: - dock->area.y += dock->area.height - ob_rr_theme->obwidth; + dock->area.y += dock->area.height - hidesize; break; case OB_ORIENTATION_VERT: - dock->area.x -= dock->area.width - ob_rr_theme->obwidth; + dock->area.x -= dock->area.width - hidesize; break; } break; case OB_DIRECTION_SOUTH: - dock->area.y += dock->area.height - ob_rr_theme->obwidth; + dock->area.y += dock->area.height - hidesize; break; case OB_DIRECTION_SOUTHEAST: switch (config_dock_orient) { case OB_ORIENTATION_HORZ: - dock->area.y += dock->area.height - ob_rr_theme->obwidth; + dock->area.y += dock->area.height - hidesize; break; case OB_ORIENTATION_VERT: - dock->area.x += dock->area.width - ob_rr_theme->obwidth; + dock->area.x += dock->area.width - hidesize; break; } break; @@ -414,8 +416,8 @@ void dock_configure(void) } if (!config_dock_floating && config_dock_hide) { - strw = ob_rr_theme->obwidth; - strh = ob_rr_theme->obwidth; + strw = hidesize; + strh = hidesize; } else { strw = dock->area.width; strh = dock->area.height; diff --git a/openbox/event.c b/openbox/event.c index 5e44bc9f..025f1188 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -43,6 +43,7 @@ #include "stacking.h" #include "extensions.h" #include "translate.h" +#include "ping.h" #include <X11/Xlib.h> #include <X11/Xatom.h> @@ -74,6 +75,7 @@ typedef struct { ObClient *client; Time time; + gulong serial; } ObFocusDelayData; typedef struct @@ -91,6 +93,7 @@ static void event_handle_dockapp(ObDockApp *app, XEvent *e); static void event_handle_client(ObClient *c, XEvent *e); static void event_handle_user_input(ObClient *client, XEvent *e); static gboolean is_enter_focus_event_ignored(XEvent *e); +static void event_ignore_enter_range(gulong start, gulong end); static void focus_delay_dest(gpointer data); static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2); @@ -99,7 +102,9 @@ static void focus_delay_client_dest(ObClient *client, gpointer data); Time event_curtime = CurrentTime; Time event_last_user_time = CurrentTime; +/*! The serial of the current X event */ +static gulong event_curserial; static gboolean focus_left_screen = FALSE; /*! A list of ObSerialRanges which are to be ignored for mouse enter events */ static GSList *ignore_serials = NULL; @@ -247,6 +252,10 @@ static void event_set_curtime(XEvent *e) static void event_hack_mods(XEvent *e) { +#ifdef XKB + XkbStateRec xkb_state; +#endif + switch (e->type) { case ButtonPress: case ButtonRelease: @@ -256,10 +265,20 @@ static void event_hack_mods(XEvent *e) e->xkey.state = modkeys_only_modifier_masks(e->xkey.state); break; case KeyRelease: - e->xkey.state = modkeys_only_modifier_masks(e->xkey.state); - /* remove from the state the mask of the modifier key being released, - if it is a modifier key being released that is */ - e->xkey.state &= ~modkeys_keycode_to_mask(e->xkey.keycode); +#ifdef XKB + /* If XKB is present, then the modifiers are all strange from its + magic. Our X core protocol stuff won't work, so we use this to + find what the modifier state is instead. */ + if (XkbGetState(ob_display, XkbUseCoreKbd, &xkb_state) == Success) + e->xkey.state = xkb_state.compat_state; + else +#endif + { + e->xkey.state = modkeys_only_modifier_masks(e->xkey.state); + /* remove from the state the mask of the modifier key being + released, if it is a modifier key being released that is */ + e->xkey.state &= ~modkeys_keycode_to_mask(e->xkey.keycode); + } break; case MotionNotify: e->xmotion.state = modkeys_only_modifier_masks(e->xmotion.state); @@ -457,14 +476,17 @@ static void event_process(const XEvent *ec, gpointer data) client = WINDOW_AS_CLIENT(obwin); break; case Window_Menu: - case Window_Internal: /* not to be used for events */ g_assert_not_reached(); break; + case Window_Internal: + /* we don't do anything with events directly on these windows */ + break; } } event_set_curtime(e); + event_curserial = e->xany.serial; event_hack_mods(e); if (event_ignore(e, client)) { if (ed) @@ -619,6 +641,14 @@ static void event_process(const XEvent *ec, gpointer data) event_handle_root(e); else if (e->type == MapRequest) client_manage(window); + else if (e->type == MappingNotify) { + /* keyboard layout changes for modifier mapping changes. reload the + modifier map, and rebind all the key bindings as appropriate */ + ob_debug("Kepboard map changed. Reloading keyboard bindings.\n"); + modkeys_shutdown(TRUE); + modkeys_startup(TRUE); + keyboard_rebind(); + } else if (e->type == ClientMessage) { /* This is for _NET_WM_REQUEST_FRAME_EXTENTS messages. They come for windows that are not managed yet. */ @@ -670,16 +700,34 @@ static void event_process(const XEvent *ec, gpointer data) } #endif - if (e->type == ButtonPress || e->type == ButtonRelease || - e->type == MotionNotify || e->type == KeyPress || - e->type == KeyRelease) - { - event_handle_user_input(client, e); + 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 */ + if (window != RootWindow(ob_display, ob_screen) || + e->xbutton.subwindow == None) + { + event_handle_user_input(client, e); + } + /* Otherwise only process it if it was physically on an openbox + internal window */ + else { + ObWindow *w; + + if ((w = g_hash_table_lookup(window_map, &e->xbutton.subwindow)) && + WINDOW_IS_INTERNAL(w)) + { + event_handle_user_input(client, e); + } + } } + else if (e->type == KeyPress || e->type == KeyRelease || + e->type == MotionNotify) + event_handle_user_input(client, e); /* if something happens and it's not from an XEvent, then we don't know the time */ event_curtime = CurrentTime; + event_curserial = 0; } static void event_handle_root(XEvent *e) @@ -720,6 +768,9 @@ static void event_handle_root(XEvent *e) ob_restart(); else if (e->xclient.data.l[0] == 3) ob_exit(0); + } else if (msgtype == prop_atoms.wm_protocols) { + if ((Atom)e->xclient.data.l[0] == prop_atoms.net_wm_ping) + ping_got_pong(e->xclient.data.l[1]); } break; case PropertyNotify: @@ -754,6 +805,7 @@ void event_enter_client(ObClient *client) data = g_new(ObFocusDelayData, 1); data->client = client; data->time = event_curtime; + data->serial = event_curserial; ob_main_loop_timeout_add(ob_main_loop, config_focus_delay * 1000, @@ -763,6 +815,7 @@ void event_enter_client(ObClient *client) ObFocusDelayData data; data.client = client; data.time = event_curtime; + data.serial = event_curserial; focus_delay_func(&data); } } @@ -991,18 +1044,23 @@ static void event_handle_client(ObClient *client, XEvent *e) is_enter_focus_event_ignored(e)) { ob_debug_type(OB_DEBUG_FOCUS, - "%sNotify mode %d detail %d on %lx IGNORED\n", + "%sNotify mode %d detail %d serial %lu on %lx " + "IGNORED\n", (e->type == EnterNotify ? "Enter" : "Leave"), e->xcrossing.mode, - e->xcrossing.detail, client?client->window:0); + e->xcrossing.detail, + e->xcrossing.serial, + client?client->window:0); } else { ob_debug_type(OB_DEBUG_FOCUS, - "%sNotify mode %d detail %d on %lx, " + "%sNotify mode %d detail %d serial %lu on %lx, " "focusing window\n", (e->type == EnterNotify ? "Enter" : "Leave"), e->xcrossing.mode, - e->xcrossing.detail, (client?client->window:0)); + e->xcrossing.detail, + e->xcrossing.serial, + (client?client->window:0)); if (config_focus_follow) event_enter_client(client); } @@ -1622,6 +1680,8 @@ static gboolean event_handle_menu_keyboard(XEvent *ev) /* Allow control while going thru the menu */ else if (ev->type == KeyPress && (state & ~ControlMask) == 0) { + frame->got_press = TRUE; + if (keycode == ob_keycode(OB_KEY_ESCAPE)) { menu_frame_hide_all(); ret = TRUE; @@ -1655,7 +1715,7 @@ static gboolean event_handle_menu_keyboard(XEvent *ev) Allow ControlMask only, and don't bother if the menu is empty */ else if (ev->type == KeyRelease && (state & ~ControlMask) == 0 && - frame->entries) + frame->entries && frame->got_press) { if (keycode == ob_keycode(OB_KEY_RETURN)) { /* Enter runs the active item or goes into the submenu. @@ -1845,10 +1905,9 @@ static gboolean focus_delay_func(gpointer data) if (menu_frame_visible || moveresize_in_progress) return FALSE; event_curtime = d->time; - if (focus_client != d->client) { - if (client_focus(d->client) && config_focus_raise) - stacking_raise(CLIENT_AS_WINDOW(d->client)); - } + event_curserial = d->serial; + if (client_focus(d->client) && config_focus_raise) + stacking_raise(CLIENT_AS_WINDOW(d->client)); event_curtime = old; return FALSE; /* no repeat */ } @@ -1861,8 +1920,8 @@ static void focus_delay_client_dest(ObClient *client, gpointer data) void event_halt_focus_delay(void) { - /* ignore all enter events up till now */ - event_end_ignore_all_enters(1); + /* ignore all enter events up till the event which caused this to occur */ + if (event_curserial) event_ignore_enter_range(1, event_curserial); ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func); } @@ -1872,22 +1931,31 @@ gulong event_start_ignore_all_enters(void) return LastKnownRequestProcessed(ob_display); } -void event_end_ignore_all_enters(gulong start) +static void event_ignore_enter_range(gulong start, gulong end) { ObSerialRange *r; g_assert(start != 0); - XSync(ob_display, FALSE); + g_assert(end != 0); r = g_new(ObSerialRange, 1); r->start = start; - r->end = LastKnownRequestProcessed(ob_display); + r->end = end; ignore_serials = g_slist_prepend(ignore_serials, r); + ob_debug_type(OB_DEBUG_FOCUS, "ignoring enters from %lu until %lu\n", + r->start, r->end); + /* increment the serial so we don't ignore events we weren't meant to */ XSync(ob_display, FALSE); } +void event_end_ignore_all_enters(gulong start) +{ + XSync(ob_display, FALSE); + event_ignore_enter_range(start, LastKnownRequestProcessed(ob_display)); +} + static gboolean is_enter_focus_event_ignored(XEvent *e) { GSList *it, *next; @@ -1933,6 +2001,8 @@ void event_cancel_all_key_grabs(void) } else ungrab_passive_key(); + + XSync(ob_display, FALSE); } gboolean event_time_after(Time t1, Time t2) diff --git a/openbox/extensions.c b/openbox/extensions.c index ee73e9ec..d1088361 100644 --- a/openbox/extensions.c +++ b/openbox/extensions.c @@ -86,6 +86,16 @@ void extensions_xinerama_screens(Rect **xin_areas, guint *nxin) { guint i; gint l, r, t, b; + if (ob_debug_xinerama) { + g_print("Using fake xinerama !\n"); + gint w = WidthOfScreen(ScreenOfDisplay(ob_display, ob_screen)); + gint h = HeightOfScreen(ScreenOfDisplay(ob_display, ob_screen)); + *nxin = 2; + *xin_areas = g_new(Rect, *nxin + 1); + RECT_SET((*xin_areas)[0], 0, 0, w/2, h); + RECT_SET((*xin_areas)[1], w/2, 0, w-(w/2), h); + } + else #ifdef XINERAMA if (extensions_xinerama) { guint i; @@ -97,17 +107,10 @@ void extensions_xinerama_screens(Rect **xin_areas, guint *nxin) RECT_SET((*xin_areas)[i], info[i].x_org, info[i].y_org, info[i].width, info[i].height); XFree(info); - } else -#endif - if (ob_debug_xinerama) { - gint w = WidthOfScreen(ScreenOfDisplay(ob_display, ob_screen)); - gint h = HeightOfScreen(ScreenOfDisplay(ob_display, ob_screen)); - *nxin = 2; - *xin_areas = g_new(Rect, *nxin + 1); - RECT_SET((*xin_areas)[0], 0, 0, w/2, h); - RECT_SET((*xin_areas)[1], w/2, 0, w-(w/2), h); } - else { + else +#endif + { *nxin = 1; *xin_areas = g_new(Rect, *nxin + 1); RECT_SET((*xin_areas)[0], 0, 0, diff --git a/openbox/focus.c b/openbox/focus.c index df02cb76..a4eb2cfa 100644 --- a/openbox/focus.c +++ b/openbox/focus.c @@ -337,13 +337,9 @@ gboolean focus_valid_target(ObClient *ft, that can be focused instead */ !focus_target_has_siblings(ft, iconic_windows, all_desktops)))); - /* it's not set to skip the taskbar (unless it is a type that would be - expected to set this hint, or modal) */ - ok = ok && ((ft->type == OB_CLIENT_TYPE_DOCK || - ft->type == OB_CLIENT_TYPE_DESKTOP || - ft->type == OB_CLIENT_TYPE_TOOLBAR || - ft->type == OB_CLIENT_TYPE_MENU || - ft->type == OB_CLIENT_TYPE_UTILITY) || + /* it's not set to skip the taskbar (but this only applies to normal typed + windows, and is overridden if the window is modal) */ + ok = ok && (ft->type != OB_CLIENT_TYPE_NORMAL || ft->modal || !ft->skip_taskbar); diff --git a/openbox/focus_cycle.c b/openbox/focus_cycle.c index 85cdf480..2348f8d0 100644 --- a/openbox/focus_cycle.c +++ b/openbox/focus_cycle.c @@ -62,15 +62,16 @@ void focus_cycle_stop(ObClient *ifclient) focus_cycle_dock_windows, focus_cycle_desktop_windows)) { - focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE); - focus_directional_cycle(0, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE); + focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,TRUE); + focus_directional_cycle(0, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE); } } ObClient* focus_cycle(gboolean forward, gboolean all_desktops, gboolean dock_windows, gboolean desktop_windows, gboolean linear, gboolean interactive, - gboolean dialog, gboolean done, gboolean cancel) + gboolean showbar, gboolean dialog, + gboolean done, gboolean cancel) { static ObClient *t = NULL; static GList *order = NULL; @@ -128,7 +129,7 @@ ObClient* focus_cycle(gboolean forward, gboolean all_desktops, if (interactive) { if (ft != focus_cycle_target) { /* prevents flicker */ focus_cycle_target = ft; - focus_cycle_draw_indicator(ft); + focus_cycle_draw_indicator(showbar ? ft : NULL); } if (dialog) /* same arguments as focus_target_valid */ @@ -261,7 +262,7 @@ static ObClient *focus_find_directional(ObClient *c, ObDirection dir, ObClient* focus_directional_cycle(ObDirection dir, gboolean dock_windows, gboolean desktop_windows, gboolean interactive, - gboolean dialog, + gboolean showbar, gboolean dialog, gboolean done, gboolean cancel) { static ObClient *first = NULL; @@ -307,7 +308,7 @@ ObClient* focus_directional_cycle(ObDirection dir, gboolean dock_windows, focus_cycle_target = ft; if (!interactive) goto done_cycle; - focus_cycle_draw_indicator(ft); + focus_cycle_draw_indicator(showbar ? ft : NULL); } if (focus_cycle_target && dialog) /* same arguments as focus_target_valid */ diff --git a/openbox/focus_cycle.h b/openbox/focus_cycle.h index 68b8d929..6e1c2c9d 100644 --- a/openbox/focus_cycle.h +++ b/openbox/focus_cycle.h @@ -37,11 +37,13 @@ void focus_cycle_shutdown(gboolean reconfig); struct _ObClient* focus_cycle(gboolean forward, gboolean all_desktops, gboolean dock_windows, gboolean desktop_windows, gboolean linear, gboolean interactive, - gboolean dialog, gboolean done, gboolean cancel); + gboolean showbar, gboolean dialog, + gboolean done, gboolean cancel); struct _ObClient* focus_directional_cycle(ObDirection dir, gboolean dock_windows, gboolean desktop_windows, gboolean interactive, + gboolean showbar, gboolean dialog, gboolean done, gboolean cancel); diff --git a/openbox/focus_cycle_indicator.c b/openbox/focus_cycle_indicator.c index 79071314..0aa65a75 100644 --- a/openbox/focus_cycle_indicator.c +++ b/openbox/focus_cycle_indicator.c @@ -18,6 +18,7 @@ */ #include "focus_cycle.h" +#include "focus_cycle_indicator.h" #include "client.h" #include "openbox.h" #include "frame.h" @@ -29,7 +30,7 @@ #define FOCUS_INDICATOR_WIDTH 6 -struct +static struct { InternalWindow top; InternalWindow left; @@ -39,6 +40,7 @@ struct static RrAppearance *a_focus_indicator; static RrColor *color_white; +static gboolean visible; static Window create_window(Window parent, gulong mask, XSetWindowAttributes *attrib) @@ -53,6 +55,8 @@ void focus_cycle_indicator_startup(gboolean reconfig) { XSetWindowAttributes attr; + visible = FALSE; + if (reconfig) return; focus_indicator.top.obwin.type = Window_Internal; @@ -79,6 +83,14 @@ void focus_cycle_indicator_startup(gboolean reconfig) stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.left)); stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.right)); stacking_add(INTERNAL_AS_WINDOW(&focus_indicator.bottom)); + g_hash_table_insert(window_map, &focus_indicator.top.win, + &focus_indicator.top); + g_hash_table_insert(window_map, &focus_indicator.left.win, + &focus_indicator.left); + g_hash_table_insert(window_map, &focus_indicator.right.win, + &focus_indicator.right); + g_hash_table_insert(window_map, &focus_indicator.bottom.win, + &focus_indicator.bottom); color_white = RrColorNew(ob_rr_inst, 0xff, 0xff, 0xff); @@ -105,6 +117,11 @@ void focus_cycle_indicator_shutdown(gboolean reconfig) RrAppearanceFree(a_focus_indicator); + g_hash_table_remove(window_map, &focus_indicator.top.win); + g_hash_table_remove(window_map, &focus_indicator.left.win); + g_hash_table_remove(window_map, &focus_indicator.right.win); + g_hash_table_remove(window_map, &focus_indicator.bottom.win); + stacking_remove(INTERNAL_AS_WINDOW(&focus_indicator.top)); stacking_remove(INTERNAL_AS_WINDOW(&focus_indicator.left)); stacking_remove(INTERNAL_AS_WINDOW(&focus_indicator.right)); @@ -118,7 +135,7 @@ void focus_cycle_indicator_shutdown(gboolean reconfig) void focus_cycle_draw_indicator(ObClient *c) { - if (!c) { + if (!c && visible) { gulong ignore_start; /* kill enter events cause by this unmapping */ @@ -130,7 +147,10 @@ void focus_cycle_draw_indicator(ObClient *c) XUnmapWindow(ob_display, focus_indicator.bottom.win); event_end_ignore_all_enters(ignore_start); - } else { + + visible = FALSE; + } + else if (c) { /* if (c) frame_adjust_focus(c->frame, FALSE); @@ -249,5 +269,7 @@ void focus_cycle_draw_indicator(ObClient *c) XMapWindow(ob_display, focus_indicator.left.win); XMapWindow(ob_display, focus_indicator.right.win); XMapWindow(ob_display, focus_indicator.bottom.win); + + visible = TRUE; } } diff --git a/openbox/focus_cycle_popup.c b/openbox/focus_cycle_popup.c index 488ecce1..9a6f2420 100644 --- a/openbox/focus_cycle_popup.c +++ b/openbox/focus_cycle_popup.c @@ -128,12 +128,14 @@ void focus_cycle_popup_startup(gboolean reconfig) XMapWindow(ob_display, popup.text); stacking_add(INTERNAL_AS_WINDOW(&popup)); + g_hash_table_insert(window_map, &popup.bg, &popup); } void focus_cycle_popup_shutdown(gboolean reconfig) { icon_popup_free(single_popup); + g_hash_table_remove(window_map, &popup.bg); stacking_remove(INTERNAL_AS_WINDOW(&popup)); while(popup.targets) { @@ -146,6 +148,7 @@ void focus_cycle_popup_shutdown(gboolean reconfig) } g_free(popup.hilite_rgba); + popup.hilite_rgba = NULL; XDestroyWindow(ob_display, popup.text); XDestroyWindow(ob_display, popup.bg); diff --git a/openbox/frame.c b/openbox/frame.c index b10f793b..a47c2f06 100644 --- a/openbox/frame.c +++ b/openbox/frame.c @@ -377,10 +377,12 @@ void frame_adjust_area(ObFrame *self, gboolean moved, STRUT_SET(self->size, self->cbwidth_l + (!self->max_horz ? self->bwidth : 0), - self->cbwidth_t + self->bwidth, + self->cbwidth_t + + (!self->max_horz || !self->max_vert || + !self->client->undecorated ? self->bwidth : 0), self->cbwidth_r + (!self->max_horz ? self->bwidth : 0), self->cbwidth_b + - (!self->max_horz || !self->max_vert ? self->bwidth : 0)); + (!self->max_horz || !self->max_vert ? self->bwidth : 0)); if (self->decorations & OB_FRAME_DECOR_TITLEBAR) self->size.top += ob_rr_theme->title_height + self->bwidth; @@ -1005,6 +1007,10 @@ void frame_grab_client(ObFrame *self) g_hash_table_insert(window_map, &self->innertop, self->client); g_hash_table_insert(window_map, &self->innerright, self->client); g_hash_table_insert(window_map, &self->innerbottom, self->client); + g_hash_table_insert(window_map, &self->innerblb, self->client); + g_hash_table_insert(window_map, &self->innerbll, self->client); + g_hash_table_insert(window_map, &self->innerbrb, self->client); + g_hash_table_insert(window_map, &self->innerbrr, self->client); g_hash_table_insert(window_map, &self->title, self->client); g_hash_table_insert(window_map, &self->label, self->client); g_hash_table_insert(window_map, &self->max, self->client); @@ -1085,6 +1091,10 @@ void frame_release_client(ObFrame *self) g_hash_table_remove(window_map, &self->innertop); g_hash_table_remove(window_map, &self->innerright); g_hash_table_remove(window_map, &self->innerbottom); + g_hash_table_remove(window_map, &self->innerblb); + g_hash_table_remove(window_map, &self->innerbll); + g_hash_table_remove(window_map, &self->innerbrb); + g_hash_table_remove(window_map, &self->innerbrr); g_hash_table_remove(window_map, &self->title); g_hash_table_remove(window_map, &self->label); g_hash_table_remove(window_map, &self->max); @@ -1436,9 +1446,9 @@ ObFrameContext frame_context(ObClient *client, Window win, gint x, gint y) if (win == self->lgripbottom) return OB_FRAME_CONTEXT_BLCORNER; if (win == self->handleright) return OB_FRAME_CONTEXT_BRCORNER; if (win == self->rgrip) return OB_FRAME_CONTEXT_BRCORNER; - if (win == self->rgripright) return OB_FRAME_CONTEXT_BLCORNER; - if (win == self->rgriptop) return OB_FRAME_CONTEXT_BLCORNER; - if (win == self->rgripbottom) return OB_FRAME_CONTEXT_BLCORNER; + if (win == self->rgripright) return OB_FRAME_CONTEXT_BRCORNER; + if (win == self->rgriptop) return OB_FRAME_CONTEXT_BRCORNER; + if (win == self->rgripbottom) return OB_FRAME_CONTEXT_BRCORNER; if (win == self->title) return OB_FRAME_CONTEXT_TITLEBAR; if (win == self->titlebottom) return OB_FRAME_CONTEXT_TITLEBAR; if (win == self->titleleft) return OB_FRAME_CONTEXT_TLCORNER; @@ -1457,6 +1467,10 @@ ObFrameContext frame_context(ObClient *client, Window win, gint x, gint y) if (win == self->innerleft) return OB_FRAME_CONTEXT_LEFT; if (win == self->innerbottom) return OB_FRAME_CONTEXT_BOTTOM; if (win == self->innerright) return OB_FRAME_CONTEXT_RIGHT; + if (win == self->innerbll) return OB_FRAME_CONTEXT_BLCORNER; + if (win == self->innerblb) return OB_FRAME_CONTEXT_BLCORNER; + if (win == self->innerbrr) return OB_FRAME_CONTEXT_BRCORNER; + if (win == self->innerbrb) return OB_FRAME_CONTEXT_BRCORNER; if (win == self->max) return OB_FRAME_CONTEXT_MAXIMIZE; if (win == self->iconify) return OB_FRAME_CONTEXT_ICONIFY; if (win == self->close) return OB_FRAME_CONTEXT_CLOSE; diff --git a/openbox/geom.h b/openbox/geom.h index 43eb8ea3..bdcd3c55 100644 --- a/openbox/geom.h +++ b/openbox/geom.h @@ -20,6 +20,23 @@ #ifndef __geom_h #define __geom_h +#include <glib.h> + +typedef struct _GravityCoord { + int pos; + gboolean center; + gboolean opposite; +} GravityCoord; + +typedef struct _GravityPoint { + GravityCoord x; + GravityCoord y; +} GravityPoint; + +#define GRAVITY_COORD_SET(c, p, cen, opp) \ + (c).pos = (p), (c).center = (cen), (c).opposite = (opp) + + typedef struct _Point { int x; int y; diff --git a/openbox/keyboard.c b/openbox/keyboard.c index 0aade9ab..4c570dfb 100644 --- a/openbox/keyboard.c +++ b/openbox/keyboard.c @@ -51,8 +51,9 @@ static void grab_keys(gboolean grab) if (grab) { p = curpos ? curpos->first_child : keyboard_firstnode; while (p) { - grab_key(p->key, p->state, RootWindow(ob_display, ob_screen), - GrabModeAsync); + if (p->key) + grab_key(p->key, p->state, RootWindow(ob_display, ob_screen), + GrabModeAsync); p = p->next_sibling; } if (curpos) @@ -264,6 +265,12 @@ void keyboard_event(ObClient *client, const XEvent *e) } } +void keyboard_rebind(void) +{ + tree_rebind(keyboard_firstnode); + grab_keys(TRUE); +} + void keyboard_startup(gboolean reconfig) { grab_keys(TRUE); diff --git a/openbox/keyboard.h b/openbox/keyboard.h index 1c55e050..995cdbc5 100644 --- a/openbox/keyboard.h +++ b/openbox/keyboard.h @@ -34,6 +34,8 @@ extern KeyBindingTree *keyboard_firstnode; void keyboard_startup(gboolean reconfig); void keyboard_shutdown(gboolean reconfig); +void keyboard_rebind(); + void keyboard_chroot(GList *keylist); gboolean keyboard_bind(GList *keylist, struct _ObActionsAct *action); void keyboard_unbind_all(); diff --git a/openbox/keytree.c b/openbox/keytree.c index fb26624d..714fffda 100644 --- a/openbox/keytree.c +++ b/openbox/keytree.c @@ -63,14 +63,18 @@ KeyBindingTree *tree_build(GList *keylist) g_strdup(kit->data)); /* deep copy */ ret->first_child = p; if (p != NULL) p->parent = ret; - if (!translate_key(it->data, &ret->state, &ret->key)) { - tree_destroy(ret); - return NULL; - } + translate_key(it->data, &ret->state, &ret->key); } 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; diff --git a/openbox/keytree.h b/openbox/keytree.h index 391cb154..0307378d 100644 --- a/openbox/keytree.h +++ b/openbox/keytree.h @@ -41,6 +41,7 @@ KeyBindingTree *tree_build(GList *keylist); void tree_assimilate(KeyBindingTree *node); KeyBindingTree *tree_find(KeyBindingTree *search, gboolean *conflict); gboolean tree_chroot(KeyBindingTree *tree, GList *keylist); +void tree_rebind(KeyBindingTree *node); #endif diff --git a/openbox/mainloop.c b/openbox/mainloop.c index 7c6a9566..b2921207 100644 --- a/openbox/mainloop.c +++ b/openbox/mainloop.c @@ -39,13 +39,13 @@ typedef struct _ObMainLoopFdHandlerType ObMainLoopFdHandlerType; static GSList *all_loops; /* signals are global to all loops */ -struct { +static struct { guint installed; /* a ref count */ struct sigaction oldact; } all_signals[NUM_SIGNALS]; /* a set of all possible signals */ -sigset_t all_signals_set; +static sigset_t all_signals_set; /* signals which cause a core dump, these can't be used for callbacks */ static gint core_signals[] = @@ -104,6 +104,10 @@ struct _ObMainLoopTimer GTimeVal last; /* When this timer will next trigger */ GTimeVal timeout; + + /* Only allow a timer's function to fire once per run through the list, + so that it doesn't get locked in there forever */ + gboolean fired; }; struct _ObMainLoopSignalHandlerType @@ -500,10 +504,8 @@ void ob_main_loop_fd_remove(ObMainLoop *loop, static glong timecompare(GTimeVal *a, GTimeVal *b) { glong r; - - if ((r = b->tv_sec - a->tv_sec)) return r; - return b->tv_usec - a->tv_usec; - + if ((r = a->tv_sec - b->tv_sec)) return r; + return a->tv_usec - b->tv_usec; } static void insert_timer(ObMainLoop *loop, ObMainLoopTimer *ins) @@ -511,7 +513,7 @@ static void insert_timer(ObMainLoop *loop, ObMainLoopTimer *ins) GSList *it; for (it = loop->timers; it; it = g_slist_next(it)) { ObMainLoopTimer *t = it->data; - if (timecompare(&ins->timeout, &t->timeout) >= 0) { + if (timecompare(&ins->timeout, &t->timeout) <= 0) { loop->timers = g_slist_insert_before(loop->timers, it, ins); break; } @@ -528,6 +530,9 @@ void ob_main_loop_timeout_add(ObMainLoop *loop, GDestroyNotify notify) { ObMainLoopTimer *t = g_new(ObMainLoopTimer, 1); + + g_assert(microseconds > 0); /* if it's 0 it'll cause an infinite loop */ + t->delay = microseconds; t->func = handler; t->data = data; @@ -618,7 +623,7 @@ static void timer_dispatch(ObMainLoop *loop, GTimeVal **wait) /* the queue is sorted, so if this timer shouldn't fire, none are ready */ - if (timecompare(&NEAREST_TIMEOUT(loop), &loop->now) < 0) + if (timecompare(&NEAREST_TIMEOUT(loop), &loop->now) > 0) break; /* we set the last fired time to delay msec after the previous firing, @@ -636,6 +641,10 @@ static void timer_dispatch(ObMainLoop *loop, GTimeVal **wait) g_free(curr); } + /* the timer queue has been shuffled, start from the beginning + (which is the next one to fire) */ + next = loop->timers; + fired = TRUE; } diff --git a/openbox/menuframe.h b/openbox/menuframe.h index 191bcfe8..06975972 100644 --- a/openbox/menuframe.h +++ b/openbox/menuframe.h @@ -73,6 +73,11 @@ struct _ObMenuFrame RrAppearance *a_title; RrAppearance *a_items; + + gboolean got_press; /* don't allow a KeyRelease event to run things in the + menu until it has seen a KeyPress. this is to + avoid having the keybinding used to show the menu + end up running something inside the menu */ }; struct _ObMenuEntryFrame diff --git a/openbox/modkeys.c b/openbox/modkeys.c index c993cfc1..9e8da321 100644 --- a/openbox/modkeys.c +++ b/openbox/modkeys.c @@ -35,21 +35,7 @@ static void set_modkey_mask(guchar mask, KeySym sym); -/* This is 8 lists of keycodes that are bound to the given mod mask. - If contains more than the one given to us by X cuz XKB is weird apparently. - We will look up all keycodes for a given keysym that is bound to the mask, - and add them all here. - - With XKB, you can have a keycode bound to a modifier that isn't in the - modifier map somehow. So this means that when we try translate from the - KeyRelease to a mod mask, we are unable to. So this array stores *all* - the KeyCodes for each KeySym for each KeyCode bound to a mod mask. - Confused? Haha... - - ModMask -> n KeyCodes -> n*m KeySyms (up to m for each KeyCode) -> - n*m*p KeyCodes (up to p for each KeySym) -*/ -static GArray *modmap[NUM_MASKS]; +static XModifierKeymap *modmap; static KeySym *keymap; static gint min_keycode, max_keycode, keysyms_per_keycode; /* This is a bitmask of the different masks for each modifier key */ @@ -62,15 +48,14 @@ static gboolean hyper_l = FALSE; void modkeys_startup(gboolean reconfigure) { - static XModifierKeymap *xmodmap; - gint i, j, k, l, m; + gint i, j, k; /* reset the keys to not be bound to any masks */ for (i = 0; i < OB_MODKEY_NUM_KEYS; ++i) modkeys_keys[i] = 0; - xmodmap = XGetModifierMapping(ob_display); - g_assert(xmodmap->max_keypermod > 0); + modmap = XGetModifierMapping(ob_display); + g_assert(modmap->max_keypermod > 0); XDisplayKeycodes(ob_display, &min_keycode, &max_keycode); keymap = XGetKeyboardMapping(ob_display, min_keycode, @@ -81,31 +66,17 @@ void modkeys_startup(gboolean reconfigure) /* go through each of the modifier masks (eg ShiftMask, CapsMask...) */ for (i = 0; i < NUM_MASKS; ++i) { - /* reset the modmap list */ - modmap[i] = g_array_new(FALSE, FALSE, sizeof(KeyCode)); - /* go through each keycode that is bound to the mask */ - for (j = 0; j < xmodmap->max_keypermod; ++j) { + for (j = 0; j < modmap->max_keypermod; ++j) { KeySym sym; /* get a keycode that is bound to the mask (i) */ - KeyCode keycode = xmodmap->modifiermap[i*xmodmap->max_keypermod+j]; + KeyCode keycode = modmap->modifiermap[i*modmap->max_keypermod + j]; if (keycode) { /* go through each keysym bound to the given keycode */ for (k = 0; k < keysyms_per_keycode; ++k) { sym = keymap[(keycode-min_keycode) * keysyms_per_keycode + k]; if (sym != NoSymbol) { - /* find all keycodes for the given keysym */ - for (l = min_keycode; l <= max_keycode; ++l) - for (m = 0; m < keysyms_per_keycode; ++m) - if (keymap[(l-min_keycode) * - keysyms_per_keycode + m] == sym) - { - /* add all keycodes for the keysym to our - modmap */ - g_array_append_val(modmap[i], l); - } - /* bind the key to the mask (e.g. Alt_L => Mod1Mask) */ set_modkey_mask(nth_mask(i), sym); } @@ -118,22 +89,17 @@ void modkeys_startup(gboolean reconfigure) modkeys_keys[OB_MODKEY_KEY_CAPSLOCK] = LockMask; modkeys_keys[OB_MODKEY_KEY_SHIFT] = ShiftMask; modkeys_keys[OB_MODKEY_KEY_CONTROL] = ControlMask; - - XFreeModifiermap(xmodmap); } void modkeys_shutdown(gboolean reconfigure) { - guint i; - - for (i = 0; i < NUM_MASKS; ++i) - g_array_free(modmap[i], TRUE); + XFreeModifiermap(modmap); XFree(keymap); } guint modkeys_keycode_to_mask(guint keycode) { - guint i, j; + gint i, j; guint mask = 0; if (keycode == NoSymbol) return 0; @@ -141,9 +107,9 @@ guint modkeys_keycode_to_mask(guint keycode) /* go through each of the modifier masks (eg ShiftMask, CapsMask...) */ for (i = 0; i < NUM_MASKS; ++i) { /* go through each keycode that is bound to the mask */ - for (j = 0; j < modmap[i]->len; ++j) { + for (j = 0; j < modmap->max_keypermod; ++j) { /* compare with a keycode that is bound to the mask (i) */ - if (g_array_index(modmap[i], KeyCode, j) == keycode) + if (modmap->modifiermap[i*modmap->max_keypermod + j] == keycode) mask |= nth_mask(i); } } diff --git a/openbox/moveresize.c b/openbox/moveresize.c index bb17d4a0..675cbe9c 100644 --- a/openbox/moveresize.c +++ b/openbox/moveresize.c @@ -101,17 +101,66 @@ static void popup_coords(ObClient *c, const gchar *format, gint a, gint b) gchar *text; text = g_strdup_printf(format, a, b); - if (config_resize_popup_pos == 1) /* == "Top" */ + if (config_resize_popup_pos == OB_RESIZE_POS_TOP) popup_position(popup, SouthGravity, c->frame->area.x + c->frame->area.width/2, c->frame->area.y - ob_rr_theme->fbwidth); - else /* == "Center" */ + else if (config_resize_popup_pos == OB_RESIZE_POS_CENTER) popup_position(popup, CenterGravity, c->frame->area.x + c->frame->size.left + c->area.width / 2, c->frame->area.y + c->frame->size.top + c->area.height / 2); + else /* Fixed */ { + Rect *area = screen_physical_area_active(); + gint gravity, x, y; + + x = config_resize_popup_fixed.x.pos; + if (config_resize_popup_fixed.x.center) + x = area->x + area->width/2; + else if (config_resize_popup_fixed.x.opposite) + x = RECT_RIGHT(*area) - x; + else + x = area->x + x; + + y = config_resize_popup_fixed.y.pos; + if (config_resize_popup_fixed.y.center) + y = area->y + area->height/2; + else if (config_resize_popup_fixed.y.opposite) + y = RECT_RIGHT(*area) - y; + else + y = area->y + y; + + if (config_resize_popup_fixed.x.center) { + if (config_resize_popup_fixed.y.center) + gravity = CenterGravity; + else if (config_resize_popup_fixed.y.opposite) + gravity = SouthGravity; + else + gravity = NorthGravity; + } + else if (config_resize_popup_fixed.x.opposite) { + if (config_resize_popup_fixed.y.center) + gravity = EastGravity; + else if (config_resize_popup_fixed.y.opposite) + gravity = SouthEastGravity; + else + gravity = NorthEastGravity; + } + else { + if (config_resize_popup_fixed.y.center) + gravity = WestGravity; + else if (config_resize_popup_fixed.y.opposite) + gravity = SouthWestGravity; + else + gravity = NorthWestGravity; + } + + popup_position(popup, gravity, x, y); + + g_free(area); + } popup_show(popup, text); g_free(text); } diff --git a/openbox/moveresize.h b/openbox/moveresize.h index 2f8d3e6a..2d0f7dce 100644 --- a/openbox/moveresize.h +++ b/openbox/moveresize.h @@ -27,6 +27,12 @@ struct _ObClient; +typedef enum { + OB_RESIZE_POS_CENTER, + OB_RESIZE_POS_TOP, + OB_RESIZE_POS_FIXED +} ObResizePopupPos; + extern gboolean moveresize_in_progress; extern struct _ObClient *moveresize_client; #ifdef SYNC diff --git a/openbox/openbox.c b/openbox/openbox.c index 6f47fbd0..48f31f91 100644 --- a/openbox/openbox.c +++ b/openbox/openbox.c @@ -43,6 +43,7 @@ #include "grab.h" #include "group.h" #include "config.h" +#include "ping.h" #include "mainloop.h" #include "gettext.h" #include "parser/parse.h" @@ -292,15 +293,16 @@ gint main(gint argc, gchar **argv) event_startup(reconfigure); /* focus_backup is used for stacking, so this needs to come before anything that calls stacking_add */ + sn_startup(reconfigure); + window_startup(reconfigure); focus_startup(reconfigure); focus_cycle_startup(reconfigure); focus_cycle_indicator_startup(reconfigure); focus_cycle_popup_startup(reconfigure); - window_startup(reconfigure); - sn_startup(reconfigure); screen_startup(reconfigure); grab_startup(reconfigure); group_startup(reconfigure); + ping_startup(reconfigure); client_startup(reconfigure); dock_startup(reconfigure); moveresize_startup(reconfigure); @@ -360,6 +362,7 @@ gint main(gint argc, gchar **argv) moveresize_shutdown(reconfigure); dock_shutdown(reconfigure); client_shutdown(reconfigure); + ping_shutdown(reconfigure); group_shutdown(reconfigure); grab_shutdown(reconfigure); screen_shutdown(reconfigure); @@ -367,8 +370,8 @@ gint main(gint argc, gchar **argv) focus_cycle_indicator_shutdown(reconfigure); focus_cycle_shutdown(reconfigure); focus_shutdown(reconfigure); - sn_shutdown(reconfigure); window_shutdown(reconfigure); + sn_shutdown(reconfigure); event_shutdown(reconfigure); config_shutdown(); actions_shutdown(reconfigure); @@ -470,9 +473,9 @@ static void print_version() { g_print("Openbox %s\n", PACKAGE_VERSION); g_print(_("Copyright (c)")); - g_print(" 2007 Mikael Magnusson\n"); + g_print(" 2008 Mikael Magnusson\n"); g_print(_("Copyright (c)")); - g_print(" 2003-2007 Dana Jansens\n\n"); + g_print(" 2003-2006 Dana Jansens\n\n"); g_print("This program comes with ABSOLUTELY NO WARRANTY.\n"); g_print("This is free software, and you are welcome to redistribute it\n"); g_print("under certain conditions. See the file COPYING for details.\n\n"); @@ -512,7 +515,9 @@ static void remove_args(gint *argc, gchar **argv, gint index, gint num) static void parse_env() { /* unset this so we don't pass it on unknowingly */ - putenv("DESKTOP_STARTUP_ID"); + gchar *s = g_strdup("DESKTOP_STARTUP_ID"); + putenv(s); + g_free(s); } static void parse_args(gint *argc, gchar **argv) diff --git a/openbox/ping.c b/openbox/ping.c new file mode 100644 index 00000000..37b5d30c --- /dev/null +++ b/openbox/ping.c @@ -0,0 +1,166 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + client.h for the Openbox window manager + Copyright (c) 2006 Mikael Magnusson + Copyright (c) 2003-2008 Dana Jansens + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + See the COPYING file for a copy of the GNU General Public License. +*/ + +#include "ping.h" +#include "client.h" +#include "prop.h" +#include "event.h" +#include "debug.h" +#include "mainloop.h" +#include "openbox.h" + +typedef struct _ObPingTarget +{ + ObClient *client; + ObPingEventHandler h; + guint32 id; + gint waiting; +} ObPingTarget; + +static GHashTable *ping_ids = NULL; +static guint32 ping_next_id = 1; + +#define PING_TIMEOUT (G_USEC_PER_SEC * 3) +/*! Warn the user after this many PING_TIMEOUT intervals */ +#define PING_TIMEOUT_WARN 3 + +static void ping_send(ObPingTarget *t); +static void ping_end(ObClient *client, gpointer data); +static gboolean ping_timeout(gpointer data); +static gboolean find_client(gpointer key, gpointer value, gpointer client); + +void ping_startup(gboolean reconfigure) +{ + if (reconfigure) return; + + ping_ids = g_hash_table_new(g_int_hash, g_int_equal); + + /* listen for clients to disappear */ + client_add_destroy_notify(ping_end, NULL); +} + +void ping_shutdown(gboolean reconfigure) +{ + if (reconfigure) return; + + g_hash_table_unref(ping_ids); + ping_ids = NULL; + + client_remove_destroy_notify(ping_end); +} + +void ping_start(struct _ObClient *client, ObPingEventHandler h) +{ + ObPingTarget *t; + + /* make sure we're not already pinging the client */ + g_assert(g_hash_table_find(ping_ids, find_client, client) == NULL); + + g_assert(client->ping == TRUE); + + t = g_new0(ObPingTarget, 1); + t->client = client; + t->h = h; + + ob_main_loop_timeout_add(ob_main_loop, PING_TIMEOUT, ping_timeout, + t, g_direct_equal, NULL); + /* act like we just timed out immediately, to start the pinging process + now instead of after the first delay. this makes sure the client + ends up in the ping_ids hash table now. */ + ping_timeout(t); + + /* make sure we can remove the client later */ + g_assert(g_hash_table_find(ping_ids, find_client, client) != NULL); +} + +void ping_stop(struct _ObClient *c) +{ + ping_end(c, NULL); +} + +void ping_got_pong(guint32 id) +{ + ObPingTarget *t; + + if ((t = g_hash_table_lookup(ping_ids, &id))) { + /*ob_debug("-PONG: '%s' (id %u)\n", t->client->title, t->id);*/ + if (t->waiting > PING_TIMEOUT_WARN) { + /* we had notified that they weren't responding, so now we + need to notify that they are again */ + t->h(t->client, FALSE); + } + t->waiting = 0; /* not waiting for a reply anymore */ + } + else + ob_debug("Got PONG with id %u but not waiting for one\n", id); +} + +static gboolean find_client(gpointer key, gpointer value, gpointer client) +{ + ObPingTarget *t = value; + return t->client == client; +} + +static void ping_send(ObPingTarget *t) +{ + /* t->id is 0 when it hasn't been assigned an id ever yet. + we can reuse ids when t->waiting == 0, because we won't be getting a + pong for that id in the future again. that way for apps that aren't + timing out we don't need to remove/add them from/to the hash table */ + if (t->id == 0 || t->waiting > 0) { + /* pick an id, and reinsert in the hash table with the new id */ + if (t->id) g_hash_table_remove(ping_ids, &t->id); + t->id = ping_next_id; + if (++ping_next_id == 0) ++ping_next_id; /* skip 0 on wraparound */ + g_hash_table_insert(ping_ids, &t->id, t); + } + + /*ob_debug("+PING: '%s' (id %u)\n", t->client->title, t->id);*/ + PROP_MSG_TO(t->client->window, t->client->window, wm_protocols, + prop_atoms.net_wm_ping, t->id, t->client->window, 0, 0, + NoEventMask); +} + +static gboolean ping_timeout(gpointer data) +{ + ObPingTarget *t = data; + + ping_send(t); + + /* if the client hasn't been responding then do something about it */ + if (t->waiting == PING_TIMEOUT_WARN) + t->h(t->client, TRUE); /* notify that the client isn't responding */ + + ++t->waiting; + + return TRUE; /* repeat */ +} + +static void ping_end(ObClient *client, gpointer data) +{ + ObPingTarget *t; + + if ((t = g_hash_table_find(ping_ids, find_client, client))) { + g_hash_table_remove(ping_ids, &t->id); + + ob_main_loop_timeout_remove_data(ob_main_loop, ping_timeout, t, FALSE); + + g_free(t); + } +} diff --git a/openbox/ping.h b/openbox/ping.h new file mode 100644 index 00000000..1333ea0f --- /dev/null +++ b/openbox/ping.h @@ -0,0 +1,44 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + client.h for the Openbox window manager + Copyright (c) 2006 Mikael Magnusson + Copyright (c) 2003-2008 Dana Jansens + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + See the COPYING file for a copy of the GNU General Public License. +*/ + +#ifndef __ping_h +#define __ping_h + +#include <X11/Xlib.h> +#include <glib.h> + +struct _ObClient; + +/*! + Notifies when the client application isn't responding to pings, or when it + starts responding again. + @param dead TRUE if the app isn't responding, FALSE if it starts responding + again +*/ +typedef void (*ObPingEventHandler) (struct _ObClient *c, gboolean dead); + +void ping_startup(gboolean reconfigure); +void ping_shutdown(gboolean reconfigure); + +void ping_start(struct _ObClient *c, ObPingEventHandler h); +void ping_stop(struct _ObClient *c); + +void ping_got_pong(guint32 id); + +#endif diff --git a/openbox/place.c b/openbox/place.c index aa572db2..058bbfbe 100644 --- a/openbox/place.c +++ b/openbox/place.c @@ -108,9 +108,9 @@ static Rect **pick_head(ObClient *c) } } - if (focus_client) { + if (focus_client && client_normal(focus_client)) { add_choice(choice, client_monitor(focus_client)); - ob_debug("placement adding choice %d for focused window\n", + ob_debug("placement adding choice %d for normal focused window\n", client_monitor(focus_client)); } @@ -146,7 +146,7 @@ static gboolean place_random(ObClient *client, gint *x, gint *y) guint i; areas = pick_head(client); - i = g_random_int_range(0, screen_num_monitors); + i = config_place_active ? 0 : g_random_int_range(0, screen_num_monitors); l = areas[i]->x; t = areas[i]->y; @@ -254,8 +254,11 @@ static gboolean place_nooverlap(ObClient *c, gint *x, gint *y) /* try ignoring different things to find empty space */ for (ignore = 0; ignore < IGNORE_END && !ret; ignore++) { - /* try all monitors in order of preference */ - for (i = 0; i < screen_num_monitors && !ret; ++i) { + /* try all monitors in order of preference, but only the first one + if config_place_active is true */ + for (i = 0; (i < (config_place_active ? 1 : screen_num_monitors) && + !ret); ++i) + { GList *it; /* add the whole monitor */ @@ -404,21 +407,21 @@ static gboolean place_per_app_setting(ObClient *client, gint *x, gint *y, g_free(areas); } - if (settings->center_x) + if (settings->position.x.center) *x = screen->x + screen->width / 2 - client->area.width / 2; - else if (settings->opposite_x) + else if (settings->position.x.opposite) *x = screen->x + screen->width - client->frame->area.width - - settings->position.x; + settings->position.x.pos; else - *x = screen->x + settings->position.x; + *x = screen->x + settings->position.x.pos; - if (settings->center_y) + if (settings->position.y.center) *y = screen->y + screen->height / 2 - client->area.height / 2; - else if (settings->opposite_y) + else if (settings->position.y.opposite) *y = screen->y + screen->height - client->frame->area.height - - settings->position.y; + settings->position.y.pos; else - *y = screen->y + settings->position.y; + *y = screen->y + settings->position.y.pos; g_free(screen); return TRUE; diff --git a/openbox/popup.c b/openbox/popup.c index 071f5b62..283348e7 100644 --- a/openbox/popup.c +++ b/openbox/popup.c @@ -58,6 +58,7 @@ ObPopup *popup_new(void) XMapWindow(ob_display, self->text); stacking_add(INTERNAL_AS_WINDOW(self)); + g_hash_table_insert(window_map, &self->bg, self); return self; } @@ -68,6 +69,7 @@ void popup_free(ObPopup *self) XDestroyWindow(ob_display, self->text); RrAppearanceFree(self->a_bg); RrAppearanceFree(self->a_text); + g_hash_table_remove(window_map, &self->bg); stacking_remove(self); g_free(self); } diff --git a/openbox/prop.c b/openbox/prop.c index 44abdfe6..c4b8baea 100644 --- a/openbox/prop.c +++ b/openbox/prop.c @@ -91,14 +91,14 @@ void prop_startup(void) CREATE(net_wm_strut_partial, "_NET_WM_STRUT_PARTIAL"); CREATE(net_wm_icon, "_NET_WM_ICON"); CREATE(net_wm_icon_geometry, "_NET_WM_ICON_GEOMETRY"); -/* CREATE(net_wm_pid, "_NET_WM_PID"); */ + CREATE(net_wm_pid, "_NET_WM_PID"); CREATE(net_wm_allowed_actions, "_NET_WM_ALLOWED_ACTIONS"); CREATE(net_wm_user_time, "_NET_WM_USER_TIME"); /* CREATE(net_wm_user_time_window, "_NET_WM_USER_TIME_WINDOW"); */ CREATE(kde_net_wm_frame_strut, "_KDE_NET_WM_FRAME_STRUT"); CREATE(net_frame_extents, "_NET_FRAME_EXTENTS"); -/* CREATE(net_wm_ping, "_NET_WM_PING"); */ + CREATE(net_wm_ping, "_NET_WM_PING"); #ifdef SYNC CREATE(net_wm_sync_request, "_NET_WM_SYNC_REQUEST"); CREATE(net_wm_sync_request_counter, "_NET_WM_SYNC_REQUEST_COUNTER"); @@ -447,6 +447,14 @@ void prop_erase(Window win, Atom prop) void prop_message(Window about, Atom messagetype, glong data0, glong data1, glong data2, glong data3, glong mask) { + prop_message_to(RootWindow(ob_display, ob_screen), about, messagetype, + data0, data1, data2, data3, 0, mask); +} + +void prop_message_to(Window to, Window about, Atom messagetype, + glong data0, glong data1, glong data2, + glong data3, glong data4, glong mask) +{ XEvent ce; ce.xclient.type = ClientMessage; ce.xclient.message_type = messagetype; @@ -457,7 +465,6 @@ void prop_message(Window about, Atom messagetype, glong data0, glong data1, ce.xclient.data.l[1] = data1; ce.xclient.data.l[2] = data2; ce.xclient.data.l[3] = data3; - ce.xclient.data.l[4] = 0; - XSendEvent(ob_display, RootWindow(ob_display, ob_screen), FALSE, - mask, &ce); + ce.xclient.data.l[4] = data4; + XSendEvent(ob_display, to, FALSE, mask, &ce); } diff --git a/openbox/prop.h b/openbox/prop.h index f0c4f5e9..5ca70470 100644 --- a/openbox/prop.h +++ b/openbox/prop.h @@ -129,14 +129,14 @@ typedef struct Atoms { Atom net_wm_strut_partial; Atom net_wm_icon; Atom net_wm_icon_geometry; -/* Atom net_wm_pid; */ + Atom net_wm_pid; Atom net_wm_allowed_actions; Atom net_wm_user_time; /* Atom net_wm_user_time_window; */ Atom net_frame_extents; /* application protocols */ -/* Atom net_wm_ping; */ + Atom net_wm_ping; #ifdef SYNC Atom net_wm_sync_request; Atom net_wm_sync_request_counter; @@ -196,7 +196,7 @@ typedef struct Atoms { Atom ob_theme; Atom ob_control; } Atoms; -Atoms prop_atoms; +extern Atoms prop_atoms; void prop_startup(); @@ -218,6 +218,9 @@ void prop_erase(Window win, Atom prop); void prop_message(Window about, Atom messagetype, glong data0, glong data1, glong data2, glong data3, glong mask); +void prop_message_to(Window to, Window about, Atom messagetype, + glong data0, glong data1, glong data2, + glong data3, glong data4, glong mask); #define PROP_GET32(win, prop, type, ret) \ (prop_get32(win, prop_atoms.prop, prop_atoms.type, ret)) @@ -244,4 +247,9 @@ void prop_message(Window about, Atom messagetype, glong data0, glong data1, (prop_message(about, prop_atoms.msgtype, data0, data1, data2, data3, \ SubstructureNotifyMask | SubstructureRedirectMask)) +#define PROP_MSG_TO(to, about, msgtype, data0, data1, data2, data3, data4, \ + mask) \ + (prop_message_to(to, about, prop_atoms.msgtype, \ + data0, data1, data2, data3, data4, mask)) + #endif diff --git a/openbox/resist.c b/openbox/resist.c index 62c2b293..f21eb8e6 100644 --- a/openbox/resist.c +++ b/openbox/resist.c @@ -23,6 +23,7 @@ #include "screen.h" #include "dock.h" #include "config.h" +#include "resist.h" #include "parser/parse.h" #include <glib.h> diff --git a/openbox/screen.c b/openbox/screen.c index a8da15c0..e008ffe5 100644 --- a/openbox/screen.c +++ b/openbox/screen.c @@ -59,14 +59,16 @@ static void screen_fallback_focus(void); guint screen_num_desktops; guint screen_num_monitors; guint screen_desktop; -guint screen_last_desktop; -Size screen_physical_size; +guint screen_last_desktop = 1; gboolean screen_showing_desktop; ObDesktopLayout screen_desktop_layout; gchar **screen_desktop_names; Window screen_support_win; Time screen_desktop_user_time = CurrentTime; +static Size screen_physical_size; +static guint screen_old_desktop; +static gboolean screen_desktop_timeout = TRUE; /*! An array of desktops, holding array of areas per monitor */ static Rect *monitor_area = NULL; /*! An array of desktops, holding an array of struts */ @@ -77,6 +79,10 @@ static GSList *struts_bottom = NULL; static ObPagerPopup *desktop_popup; +/*! The number of microseconds that you need to be on a desktop before it will + replace the remembered "last desktop" */ +#define REMEMBER_LAST_DESKTOP_TIME 750000 + static gboolean replace_wm(void) { gchar *wm_sn; @@ -283,6 +289,8 @@ gboolean screen_annex(void) supported[i++] = prop_atoms.net_wm_sync_request; supported[i++] = prop_atoms.net_wm_sync_request_counter; #endif + supported[i++] = prop_atoms.net_wm_pid; + supported[i++] = prop_atoms.net_wm_ping; supported[i++] = prop_atoms.kde_wm_change_state; supported[i++] = prop_atoms.kde_net_wm_frame_strut; @@ -577,23 +585,90 @@ static void screen_fallback_focus(void) } } +static gboolean last_desktop_func(gpointer data) +{ + screen_desktop_timeout = TRUE; + return FALSE; +} + void screen_set_desktop(guint num, gboolean dofocus) { GList *it; - guint old; + guint previous; gulong ignore_start; g_assert(num < screen_num_desktops); - old = screen_desktop; + previous = screen_desktop; screen_desktop = num; - if (old == num) return; + if (previous == num) return; PROP_SET32(RootWindow(ob_display, ob_screen), net_current_desktop, cardinal, num); - screen_last_desktop = old; + /* This whole thing decides when/how to save the screen_last_desktop so + that it can be restored later if you want */ + if (screen_desktop_timeout) { + /* If screen_desktop_timeout is true, then we've been on this desktop + long enough and we can save it as the last desktop. */ + + /* save the "last desktop" as the "old desktop" */ + screen_old_desktop = screen_last_desktop; + /* save the desktop we're coming from as the "last desktop" */ + screen_last_desktop = previous; + } + else { + /* If screen_desktop_timeout is false, then we just got to this desktop + and we are moving away again. */ + + if (screen_desktop == screen_last_desktop) { + /* If we are moving to the "last desktop" .. */ + if (previous == screen_old_desktop) { + /* .. from the "old desktop", change the last desktop to + be where we are coming from */ + screen_last_desktop = screen_old_desktop; + } + else if (screen_last_desktop == screen_old_desktop) { + /* .. and also to the "old desktop", change the "last + desktop" to be where we are coming from */ + screen_last_desktop = previous; + } + else { + /* .. from some other desktop, then set the "last desktop" to + be the saved "old desktop", i.e. where we were before the + "last desktop" */ + screen_last_desktop = screen_old_desktop; + } + } + else { + /* If we are moving to any desktop besides the "last desktop".. + (this is the normal case) */ + if (screen_desktop == screen_old_desktop) { + /* If moving to the "old desktop", which is not the + "last desktop", don't save anything */ + } + else if (previous == screen_old_desktop) { + /* If moving from the "old desktop", and not to the + "last desktop", don't save anything */ + } + else if (screen_last_desktop == screen_old_desktop) { + /* If the "last desktop" is the same as "old desktop" and + you're not moving to the "last desktop" then save where + we're coming from as the "last desktop" */ + screen_last_desktop = previous; + } + else { + /* If the "last desktop" is different from the "old desktop" + and you're not moving to the "last desktop", then don't save + anything */ + } + } + } + screen_desktop_timeout = FALSE; + ob_main_loop_timeout_remove(ob_main_loop, last_desktop_func); + ob_main_loop_timeout_add(ob_main_loop, REMEMBER_LAST_DESKTOP_TIME, + last_desktop_func, NULL, NULL, NULL); ob_debug("Moving to desktop %d\n", num+1); diff --git a/openbox/stacking.c b/openbox/stacking.c index b23e6eac..b18c02af 100644 --- a/openbox/stacking.c +++ b/openbox/stacking.c @@ -28,6 +28,10 @@ #include "debug.h" GList *stacking_list = NULL; +/*! When true, stacking changes will not be reflected on the screen. This is + to freeze the on-screen stacking order while a window is being temporarily + raised during focus cycling */ +static gboolean pause_changes = FALSE; void stacking_set_list(void) { @@ -99,12 +103,53 @@ static void do_restack(GList *wins, GList *before) } #endif - XRestackWindows(ob_display, win, i); + if (!pause_changes) + XRestackWindows(ob_display, win, i); g_free(win); stacking_set_list(); } +void stacking_temp_raise(ObWindow *window) +{ + Window win[2]; + GList *it; + + /* don't use this for internal windows..! it would lower them.. */ + g_assert(window_layer(window) < OB_STACKING_LAYER_INTERNAL); + + /* find the window to drop it underneath */ + win[0] = screen_support_win; + for (it = stacking_list; it; it = g_list_next(it)) { + ObWindow *w = it->data; + if (window_layer(w) >= OB_STACKING_LAYER_INTERNAL) + win[0] = window_top(w); + else + break; + } + + win[1] = window_top(window); + XRestackWindows(ob_display, win, 2); + + pause_changes = TRUE; +} + +void stacking_restore(void) +{ + Window *win; + GList *it; + gint i; + + win = g_new(Window, g_list_length(stacking_list) + 1); + win[0] = screen_support_win; + for (i = 1, it = stacking_list; it; ++i, it = g_list_next(it)) + win[i] = window_top(it->data); + XRestackWindows(ob_display, win, i); + g_free(win); + + pause_changes = FALSE; +} + static void do_raise(GList *wins) { GList *it; diff --git a/openbox/stacking.h b/openbox/stacking.h index ac9c8239..e226f36f 100644 --- a/openbox/stacking.h +++ b/openbox/stacking.h @@ -20,11 +20,12 @@ #ifndef __stacking_h #define __stacking_h -#include "window.h" - #include <glib.h> #include <X11/Xlib.h> +struct _ObWindow; +struct _ObClient; + /*! The possible stacking layers a client window can be a part of */ typedef enum { OB_STACKING_LAYER_INVALID, @@ -44,21 +45,27 @@ extern GList *stacking_list; stacking_list */ void stacking_set_list(); -void stacking_add(ObWindow *win); -void stacking_add_nonintrusive(ObWindow *win); +void stacking_add(struct _ObWindow *win); +void stacking_add_nonintrusive(struct _ObWindow *win); #define stacking_remove(win) stacking_list = g_list_remove(stacking_list, win); /*! Raises a window above all others in its stacking layer */ -void stacking_raise(ObWindow *window); +void stacking_raise(struct _ObWindow *window); + +/*! Temporarily raises a window above all others */ +void stacking_temp_raise(struct _ObWindow *window); + +/*! Restores any temporarily raised windows to their correct place */ +void stacking_restore(); /*! Lowers a window below all others in its stacking layer */ -void stacking_lower(ObWindow *window); +void stacking_lower(struct _ObWindow *window); /*! Moves a window below another if its in the same layer. This function does not enforce stacking rules IRT transients n such, and so it should really ONLY be used to restore stacking orders from saved sessions */ -void stacking_below(ObWindow *window, ObWindow *below); +void stacking_below(struct _ObWindow *window, struct _ObWindow *below); /*! Restack a window based upon a sibling (or all windows) in various ways. @param client The client to be restacked diff --git a/openbox/translate.c b/openbox/translate.c index 21015578..c697679d 100644 --- a/openbox/translate.c +++ b/openbox/translate.c @@ -20,6 +20,7 @@ #include "openbox.h" #include "mouse.h" #include "modkeys.h" +#include "translate.h" #include "gettext.h" #include <glib.h> #include <string.h> @@ -111,6 +112,8 @@ gboolean translate_key(const gchar *str, guint *state, guint *keycode) parsed = g_strsplit(str, "-", -1); + *state = *keycode = 0; + /* first, find the key (last token) */ l = NULL; for (i = 0; parsed[i] != NULL; ++i) diff --git a/openbox/window.c b/openbox/window.c index 19b39c09..c5e6a4ea 100644 --- a/openbox/window.c +++ b/openbox/window.c @@ -63,7 +63,7 @@ Window window_top(ObWindow *self) return None; } -Window window_layer(ObWindow *self) +ObStackingLayer window_layer(ObWindow *self) { switch (self->type) { case Window_Menu: diff --git a/openbox/window.h b/openbox/window.h index ef29edd7..a172cfce 100644 --- a/openbox/window.h +++ b/openbox/window.h @@ -19,6 +19,8 @@ #ifndef __window_h #define __window_h +#include "stacking.h" + #include <X11/Xlib.h> #include <glib.h> @@ -30,7 +32,8 @@ typedef enum { Window_Dock, Window_DockApp, /* used for events but not stacking */ Window_Client, - Window_Internal /* used for stacking but not events */ + Window_Internal /* used for stacking but not events (except to filter + events on the root window) */ } Window_InternalType; struct _ObWindow @@ -74,6 +77,6 @@ void window_startup(gboolean reconfig); void window_shutdown(gboolean reconfig); Window window_top(ObWindow *self); -Window window_layer(ObWindow *self); +ObStackingLayer window_layer(ObWindow *self); #endif diff --git a/openbox/xerror.c b/openbox/xerror.c index 6e884607..2657b8ea 100644 --- a/openbox/xerror.c +++ b/openbox/xerror.c @@ -20,6 +20,7 @@ #include "openbox.h" #include "gettext.h" #include "debug.h" +#include "xerror.h" #include <glib.h> #include <X11/Xlib.h> |
