summaryrefslogtreecommitdiff
path: root/openbox
diff options
context:
space:
mode:
Diffstat (limited to 'openbox')
-rw-r--r--openbox/actions.c2
-rw-r--r--openbox/actions/cyclewindows.c36
-rw-r--r--openbox/actions/directionalwindows.c33
-rw-r--r--openbox/actions/lower.c1
-rw-r--r--openbox/actions/raise.c1
-rw-r--r--openbox/actions/resize.c8
-rw-r--r--openbox/client.c135
-rw-r--r--openbox/client.h15
-rw-r--r--openbox/client_list_combined_menu.c2
-rw-r--r--openbox/config.c94
-rw-r--r--openbox/config.h17
-rw-r--r--openbox/dock.c30
-rw-r--r--openbox/event.c118
-rw-r--r--openbox/extensions.c23
-rw-r--r--openbox/focus.c10
-rw-r--r--openbox/focus_cycle.c13
-rw-r--r--openbox/focus_cycle.h4
-rw-r--r--openbox/focus_cycle_indicator.c28
-rw-r--r--openbox/focus_cycle_popup.c3
-rw-r--r--openbox/frame.c24
-rw-r--r--openbox/geom.h17
-rw-r--r--openbox/keyboard.c11
-rw-r--r--openbox/keyboard.h2
-rw-r--r--openbox/keytree.c12
-rw-r--r--openbox/keytree.h1
-rw-r--r--openbox/mainloop.c25
-rw-r--r--openbox/menuframe.h5
-rw-r--r--openbox/modkeys.c54
-rw-r--r--openbox/moveresize.c53
-rw-r--r--openbox/moveresize.h6
-rw-r--r--openbox/openbox.c17
-rw-r--r--openbox/ping.c166
-rw-r--r--openbox/ping.h44
-rw-r--r--openbox/place.c29
-rw-r--r--openbox/popup.c2
-rw-r--r--openbox/prop.c17
-rw-r--r--openbox/prop.h14
-rw-r--r--openbox/resist.c1
-rw-r--r--openbox/screen.c87
-rw-r--r--openbox/stacking.c47
-rw-r--r--openbox/stacking.h21
-rw-r--r--openbox/translate.c3
-rw-r--r--openbox/window.c2
-rw-r--r--openbox/window.h7
-rw-r--r--openbox/xerror.c1
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>