all repos — openbox @ f26f23de50cb7941a7702198e3b4d1b2f9de062e

openbox fork - make it a bit more like ryudo

all my changes while i was offline.
better alt-tabbing. better transient handling. i dont even know. lots of fucking cool shit so WATCH the FUCK OUT.
Dana Jansens danakj@orodu.net
commit

f26f23de50cb7941a7702198e3b4d1b2f9de062e

parent

60065663ba9dc448dcf90fd200cd459bcdb9ef9c

M HACKINGHACKING

@@ -13,6 +13,10 @@ which is not a valid pointer. You must ALWAYS check for TRAN_GROUP before

following transient_for. When TRAN_GROUP is found, Client.group will always be !NULL. Some smart action should be taken using all members of the group in this case. + Smart action idea: + Skip over members of the group that are also transients of the group + (have Client.transient_for set to TRAN_GROUP). These windows are not + ancestors and using them will also end up causing infinite loops! When using coordinates/sizes of windows, make sure you use the right area. The Client.area rect is the reference point and size of the *CLIENT* window. This
M Makefile.amMakefile.am

@@ -1,5 +1,5 @@

#SUBDIRS = po themes doc render cwmcc obcl kernel plugins -SUBDIRS = po themes data render kernel plugins +SUBDIRS = po themes data render kernel plugins tools MAINTAINERCLEANFILES = aclocal.m4 config.h.in configure Makefile.in stamp-h.in doc:
M configure.acconfigure.ac

@@ -57,6 +57,8 @@ AC_SUBST(XFT_LIBS)

# Check for X11 extensions X11_EXT_XKB +X11_EXT_XRANDR +X11_EXT_VIDMODE X11_EXT_SHAPE X11_EXT_XINERAMA

@@ -69,7 +71,9 @@ kernel/Makefile

plugins/Makefile plugins/placement/Makefile plugins/mouse/Makefile - plugins/keyboard/Makefile]) + plugins/keyboard/Makefile + tools/Makefile + tools/slit/Makefile]) AC_OUTPUT AC_MSG_RESULT
M data/rc3data/rc3

@@ -27,6 +27,9 @@ # a special case of focusLast that applies when switching between desktops; if

# set, the previously focused window on the desktop is focused when switching #focusLastOnDesktop = yes +# shows a helpful dialog while cycling focus +#cyclingDialog = yes + [desktops] # The number of virtual desktops to use
M m4/x11.m4m4/x11.m4

@@ -211,6 +211,11 @@ [

AC_MSG_RESULT([yes]) XKB="yes" AC_DEFINE([XKB], [1], [Found the XKB extension]) + + XKB_CFLAGS="" + XKB_LIBS="" + AC_SUBST(XKB_CFLAGS) + AC_SUBST(XKB_LIBS) ], [ AC_MSG_RESULT([no])

@@ -229,6 +234,63 @@ AC_MSG_RESULT([no])

fi ]) +# X11_EXT_XRANDR() +# +# Check for the presence of the "XRandR" X Window System extension. +# Defines "XRANDR" and sets the $(XRANDR) variable to "yes" if the extension is +# present. +AC_DEFUN([X11_EXT_XRANDR], +[ + AC_REQUIRE([X11_DEVEL]) + + # Store these + OLDLIBS=$LIBS + OLDCPPFLAGS=$CPPFLAGS + + CPPFLAGS="$CPPFLAGS $X_CFLAGS" + LIBS="$LIBS $X_PRE_LIBS $X_LIBS $X_EXTRA_LIBS -lXext -lXrender -lXrandr" + + AC_CHECK_LIB([Xrandr], [XRRSelectInput], + AC_MSG_CHECKING([for X11/extensions/Xrandr.h]) + AC_TRY_LINK( + [ + #include <X11/Xlib.h> + #include <X11/extensions/Xrandr.h> + ], + [ + Display *d; + Drawable r; + int i; + XRRQueryExtension(d, &i, &i); + XRRGetScreenInfo(d, r); + ], + [ + AC_MSG_RESULT([yes]) + XRANDR="yes" + AC_DEFINE([XRANDR], [1], [Found the XRandR extension]) + + XRANDR_CFLAGS="" + XRANDR_LIBS="-lXext -lXrender -lXrandr" + AC_SUBST(XRANDR_CFLAGS) + AC_SUBST(XRANDR_LIBS) + ], + [ + AC_MSG_RESULT([no]) + XRANDR="no" + ]) + ) + + LIBS=$OLDLIBS + CPPFLAGS=$OLDCPPFLAGS + + AC_MSG_CHECKING([for the XRandR extension]) + if test "$XRANDR" = "yes"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi +]) + # X11_EXT_SHAPE() # # Check for the presence of the "Shape" X Window System extension.

@@ -260,7 +322,11 @@ [

AC_MSG_RESULT([yes]) SHAPE="yes" AC_DEFINE([SHAPE], [1], [Found the XShape extension]) - LIBS="$LIBS -lXext" + + XSHAPE_CFLAGS="" + XSHAPE_LIBS="-lXext" + AC_SUBST(XSHAPE_CFLAGS) + AC_SUBST(XSHAPE_LIBS) ], [ AC_MSG_RESULT([no])

@@ -271,7 +337,7 @@

LIBS=$OLDLIBS CPPFLAGS=$OLDCPPFLAGS - AC_MSG_CHECKING([for the Shape extension]) + AC_MSG_CHECKING([for the Shape extension]) if test "$SHAPE" = "yes"; then AC_MSG_RESULT([yes]) else

@@ -330,3 +396,59 @@ else

AC_MSG_RESULT([no]) fi ]) + +# VIDMODE() +# +# Check for the presence of the "VidMode" X Window System extension. +# Defines "VIDMODE" and sets the $(VIDMODE) variable to "yes" if the extension +# is present. +AC_DEFUN([X11_EXT_VIDMODE], +[ + AC_REQUIRE([X11_DEVEL]) + + # Store these + OLDLIBS=$LIBS + OLDCPPFLAGS=$CPPFLAGS + + CPPFLAGS="$CPPFLAGS $X_CFLAGS" + LIBS="$LIBS $X_PRE_LIBS $X_LIBS $X_EXTRA_LIBS -lXext -lXxf86vm" + + AC_CHECK_LIB([Xxf86vm], [XF86VidModeGetViewPort], + AC_MSG_CHECKING([for X11/extensions/xf86vmode.h]) + AC_TRY_LINK( + [ + #include <X11/Xlib.h> + #include <X11/extensions/xf86vmode.h> + ], + [ + Display *d; + int i; + XF86VidModeQueryExtension(d, &i, &i); + XF86VidModeGetViewPort(d, i, &i, &i); + ], + [ + AC_MSG_RESULT([yes]) + VIDMODE="yes" + AC_DEFINE([VIDMODE], [1], [Found the VidMode extension]) + + VIDMODE_CFLAGS="" + VIDMODE_LIBS="-lXext -lXxf86vm" + AC_SUBST(VIDMODE_CFLAGS) + AC_SUBST(VIDMODE_LIBS) + ], + [ + AC_MSG_RESULT([no]) + VIDMODE="no" + ]) + ) + + LIBS=$OLDLIBS + CPPFLAGS=$OLDCPPFLAGS + + AC_MSG_CHECKING([for the VidMode extension]) + if test "$VIDMODE" = "yes"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi +])
M openbox/Makefile.amopenbox/Makefile.am

@@ -14,22 +14,24 @@ -DG_LOG_DOMAIN=\"Openbox\" \

-DBINARY=\"$(binary)\" INCLUDES=-I.. -LIBS=$(X_LIBS) $(XFT_LIBS) $(XINERAMA_LIBS) $(GLIB_LIBS) $(GMODULE_LIBS) @LIBS@ +LIBS=$(X_LIBS) $(XFT_LIBS) $(XINERAMA_LIBS) $(XKB_LIBS) $(XRANDR_LIBS) \ + $(VIDMODE_LIBS) $(XSHAPE_LIBS) $(GLIB_LIBS) $(GMODULE_LIBS) @LIBS@ \ + @LIBINTL@ bin_PROGRAMS=$(binary) -openbox3_LDADD=@LIBINTL@ -lobrender -L../render +openbox3_LDADD=-lobrender -L../render openbox3_LDFLAGS=-export-dynamic openbox3_SOURCES=parse.tab.c parse.lex.c action.c client.c config.c \ extensions.c focus.c frame.c grab.c menu.c menu_render.c \ openbox.c framerender.c parse.c plugin.c prop.c screen.c \ stacking.c dispatch.c event.c group.c timer.c xerror.c \ - moveresize.c startup.c + moveresize.c startup.c popup.c noinst_HEADERS=action.h client.h config.h dispatch.h event.h extensions.h \ focus.h frame.h framerender.h geom.h gettext.h grab.h group.h \ menu.h openbox.h parse.h parse.tab.h plugin.h prop.h screen.h \ - stacking.h timer.h xerror.h moveresize.h startup.h + stacking.h timer.h xerror.h moveresize.h startup.h popup.h # kill the implicit .c.y rule %.c: %.y
M openbox/client.copenbox/client.c

@@ -38,10 +38,7 @@ static void client_get_gravity(Client *self);

static void client_showhide(Client *self); static void client_change_allowed_actions(Client *self); static void client_change_state(Client *self); -static void client_move_onscreen(Client *self); -static Client *search_focus_tree(Client *node, Client *skip); static void client_apply_startup_state(Client *self); -static Client *search_modal_tree(Client *node, Client *skip); static guint map_hash(Window *w) { return *w; } static gboolean map_key_comp(Window *w1, Window *w2) { return *w1 == *w2; }

@@ -82,6 +79,37 @@

stacking_set_list(); } +/* +void client_foreach_transient(Client *self, ClientForeachFunc func, void *data) +{ + GSList *it; + + for (it = self->transients; it; it = it->next) { + if (!func(it->data, data)) return; + client_foreach_transient(it->data, func, data); + } +} + +void client_foreach_ancestor(Client *self, ClientForeachFunc func, void *data) +{ + if (self->transient_for) { + if (self->transient_for != TRAN_GROUP) { + if (!func(self->transient_for, data)) return; + client_foreach_ancestor(self->transient_for, func, data); + } else { + GSList *it; + + for (it = self->group->members; it; it = it->next) + if (it->data != self && + ((Client*)it->data)->transient_for != TRAN_GROUP) { + if (!func(it->data, data)) return; + client_foreach_ancestor(it->data, func, data); + } + } + } +} +*/ + void client_manage_all() { unsigned int i, j, nchild;

@@ -137,7 +165,7 @@ startup_stack_size = 0;

if (config_focus_new) { active = g_hash_table_lookup(client_map, &startup_active); - if (!active || !client_focus(active)) + if (!(active && client_focus(active))) focus_fallback(Fallback_NoFocus); } }

@@ -266,7 +294,7 @@ (group_foc ||

(!parent && (!self->group || !self->group->members->next)))))) || (parent && (client_focused(parent) || - search_focus_tree(parent, parent)))) { + client_search_focus_tree(parent)))) { client_focus(self); } }

@@ -399,7 +427,7 @@ /* update the list hints */

client_set_list(); } -static void client_move_onscreen(Client *self) +void client_move_onscreen(Client *self) { Rect *a; int x = self->frame->area.x, y = self->frame->area.y;

@@ -415,7 +443,7 @@ if (y + self->frame->area.height - 1< a->y)

y = a->y; frame_frame_gravity(self->frame, &x, &y); /* get where the client - should be */ + should be */ client_configure(self , Corner_TopLeft, x, y, self->area.width, self->area.height, TRUE, TRUE);

@@ -496,6 +524,7 @@

/* defaults */ self->frame = NULL; self->title = self->icon_title = NULL; + self->title_count = 1; self->name = self->class = self->role = NULL; self->wmstate = NormalState; self->transient = FALSE;

@@ -529,7 +558,6 @@ (min/max sizes), so we're ready to set up the decorations/functions */

client_setup_decor_and_functions(self); client_update_title(self); - client_update_icon_title(self); client_update_class(self); client_update_strut(self); client_update_icons(self);

@@ -782,10 +810,6 @@ self->type = Type_Dialog;

else self->type = Type_Normal; } - - /* this makes sure that these windows appear on all desktops */ - if (self->type == Type_Desktop) - self->desktop = DESKTOP_ALL; } void client_update_protocols(Client *self)

@@ -991,11 +1015,19 @@

client_change_allowed_actions(self); if (self->frame) { + /* this makes sure that these windows appear on all desktops */ + if (self->type == Type_Desktop && self->desktop != DESKTOP_ALL) + client_set_desktop(self, DESKTOP_ALL, FALSE); + /* change the decors on the frame, and with more/less decorations, we may also need to be repositioned */ frame_adjust_area(self->frame, TRUE, TRUE); /* with new decor, the window's maximized size may change */ client_remaximize(self); + } else { + /* this makes sure that these windows appear on all desktops */ + if (self->type == Type_Desktop && self->desktop != DESKTOP_ALL) + self->desktop = DESKTOP_ALL; } }

@@ -1004,7 +1036,9 @@ {

guint32 actions[9]; int num = 0; - actions[num++] = prop_atoms.net_wm_action_change_desktop; + /* desktop windows are kept on all desktops */ + if (self->type != Type_Desktop) + actions[num++] = prop_atoms.net_wm_action_change_desktop; if (self->functions & Func_Shade) actions[num++] = prop_atoms.net_wm_action_shade;

@@ -1154,6 +1188,9 @@ }

void client_update_title(Client *self) { + GList *it; + guint32 nums; + guint i; char *data = NULL; g_free(self->title);

@@ -1165,6 +1202,29 @@ if (!PROP_GETS(self->window, wm_name, locale, &data))

data = g_strdup("Unnamed Window"); /* look for duplicates and append a number */ + nums = 0; + for (it = client_list; it; it = it->next) + if (it->data != self) { + Client *c = it->data; + if (0 == strncmp(c->title, data, strlen(data))) + nums |= 1 << c->title_count; + } + /* find first free number */ + for (i = 1; i <= 32; ++i) + if (!(nums & (1 << i))) { + if (self->title_count == 1 || i == 1) + self->title_count = i; + break; + } + /* dont display the number for the first window */ + if (self->title_count > 1) { + char *vdata, *ndata; + ndata = g_strdup_printf(" - [%u]", self->title_count); + vdata = g_strconcat(data, ndata, NULL); + g_free(ndata); + g_free(data); + data = vdata; + } PROP_SETS(self->window, net_wm_visible_name, data);

@@ -1172,12 +1232,9 @@ self->title = data;

if (self->frame) frame_adjust_title(self->frame); -} -void client_update_icon_title(Client *self) -{ - char *data = NULL; - + /* update the icon title */ + data = NULL; g_free(self->icon_title); /* try netwm */

@@ -1185,6 +1242,16 @@ if (!PROP_GETS(self->window, net_wm_icon_name, utf8, &data))

/* try old x stuff */ if (!PROP_GETS(self->window, wm_icon_name, locale, &data)) data = g_strdup("Unnamed Window"); + + /* append the title count, dont display the number for the first window */ + if (self->title_count > 1) { + char *vdata, *ndata; + ndata = g_strdup_printf(" - [%u]", self->title_count); + vdata = g_strconcat(data, ndata, NULL); + g_free(ndata); + g_free(data); + data = vdata; + } PROP_SETS(self->window, net_wm_visible_icon_name, data);

@@ -1342,28 +1409,70 @@ if (self->frame)

frame_adjust_state(self->frame); } -static Client *search_focus_tree(Client *node, Client *skip) +Client *client_search_focus_tree(Client *self) { GSList *it; Client *ret; - for (it = node->transients; it != NULL; it = it->next) { - Client *c = it->data; - if (c == skip) continue; /* circular? */ - if ((ret = search_focus_tree(c, skip))) return ret; - if (client_focused(c)) return c; + for (it = self->transients; it != NULL; it = it->next) { + if (client_focused(it->data)) return it->data; + if ((ret = client_search_focus_tree(it->data))) return ret; } return NULL; } +Client *client_search_focus_tree_full(Client *self) +{ + if (self->transient_for) { + if (self->transient_for != TRAN_GROUP) { + return client_search_focus_tree_full(self->transient_for); + } else { + GSList *it; + + for (it = self->group->members; it; it = it->next) + if (((Client*)it->data)->transient_for != TRAN_GROUP) { + Client *c; + if ((c = client_search_focus_tree_full(it->data))) + return c; + } + return NULL; + } + } else { + /* this function checks the whole tree, the client_search_focus_tree + does not, so we need to check this window */ + if (client_focused(self)) + return self; + return client_search_focus_tree(self); + } +} + +static StackLayer calc_layer(Client *self) +{ + StackLayer l; + + if (self->iconic) l = Layer_Icon; + else if (self->fullscreen) l = Layer_Fullscreen; + else if (self->type == Type_Desktop) l = Layer_Desktop; + else if (self->type == Type_Dock) { + if (!self->below) l = Layer_Top; + else l = Layer_Normal; + } + else if (self->above) l = Layer_Above; + else if (self->below) l = Layer_Below; + else l = Layer_Normal; + + return l; +} + static void calc_recursive(Client *self, Client *orig, StackLayer l, gboolean raised) { - StackLayer old; + StackLayer old, own; GSList *it; old = self->layer; - self->layer = l; + own = calc_layer(self); + self->layer = l > own ? l : own; for (it = self->transients; it; it = it->next) calc_recursive(it->data, orig, l, raised ? raised : l != old);

@@ -1376,7 +1485,6 @@

void client_calc_layer(Client *self) { StackLayer l; - gboolean f; Client *orig; orig = self;

@@ -1397,25 +1505,7 @@ }

} } - /* is us or one of our transients focused? */ - if (client_focused(self)) - f = TRUE; - else if (search_focus_tree(self, self)) - f = TRUE; - else - f = FALSE; - - if (self->iconic) l = Layer_Icon; - /* fullscreen windows are only in the fullscreen layer while focused */ - else if (self->fullscreen && f) l = Layer_Fullscreen; - else if (self->type == Type_Desktop) l = Layer_Desktop; - else if (self->type == Type_Dock) { - if (!self->below) l = Layer_Top; - else l = Layer_Normal; - } - else if (self->above) l = Layer_Above; - else if (self->below) l = Layer_Below; - else l = Layer_Normal; + l = calc_layer(self); calc_recursive(self, orig, l, FALSE); }

@@ -1698,31 +1788,30 @@ void client_iconify(Client *self, gboolean iconic, gboolean curdesk)

{ GSList *it; - /* move up the transient chain as far as possible first if deiconifying */ - if (!iconic) - while (self->transient_for) { - if (self->transient_for != TRAN_GROUP) { - if (self->transient_for->iconic == iconic) + /* move up the transient chain as far as possible first */ + if (self->transient_for) { + if (self->transient_for != TRAN_GROUP) { + if (self->transient_for->iconic != iconic) { + client_iconify(self->transient_for, iconic, curdesk); + return; + } + } else { + GSList *it; + + /* the check for TRAN_GROUP is to prevent an infinate loop with + 2 transients of the same group at the head of the group's + members list */ + for (it = self->group->members; it; it = it->next) { + Client *c = it->data; + if (c != self && c->iconic != iconic && + c->transient_for != TRAN_GROUP) { + client_iconify(it->data, iconic, curdesk); break; - self = self->transient_for; - } else { - GSList *it; - - /* the check for TRAN_GROUP is to prevent an infinate loop with - 2 transients of the same group at the head of the group's - members list */ - for (it = self->group->members; it; it = it->next) { - Client *c = it->data; - - if (c != self && c->transient_for->iconic != iconic && - c->transient_for != TRAN_GROUP) { - self = it->data; - break; - } } - if (it == NULL) break; } + if (it != NULL) return; } + } if (self->iconic == iconic) return; /* nothing to do */

@@ -1738,13 +1827,18 @@ /* we unmap the client itself so that we can get MapRequest events,

and because the ICCCM tells us to! */ XUnmapWindow(ob_display, self->window); - /* update the focus lists.. iconic windows go to the bottom */ - focus_order_to_bottom(self); + /* update the focus lists.. iconic windows go to the bottom of the + list, put the new iconic window at the 'top of the bottom'. */ + focus_order_to_top(self); } else { if (curdesk) client_set_desktop(self, screen_desktop, FALSE); self->wmstate = self->shaded ? IconicState : NormalState; XMapWindow(ob_display, self->window); + + /* this puts it after the current focused window */ + focus_order_remove(self); + focus_order_add_new(self); } client_change_state(self); client_showhide(self);

@@ -1941,23 +2035,17 @@

dispatch_client(Event_Client_Desktop, self, target, old); } -static Client *search_modal_tree(Client *node, Client *skip) +Client *client_search_modal_child(Client *self) { GSList *it; Client *ret; - for (it = node->transients; it != NULL; it = it->next) { + for (it = self->transients; it != NULL; it = it->next) { Client *c = it->data; - if (c == skip) continue; /* circular? */ - if ((ret = search_modal_tree(c, skip))) return ret; + if ((ret = client_search_modal_child(c))) return ret; if (c->modal) return c; } return NULL; -} - -Client *client_find_modal_child(Client *self) -{ - return search_modal_tree(self, self); } gboolean client_validate(Client *self)

@@ -2118,7 +2206,7 @@ {

Client *child; /* if we have a modal child, then focus it, not us */ - child = client_find_modal_child(self); + child = client_search_modal_child(self); if (child) return child; return self; }
M openbox/client.hopenbox/client.h

@@ -112,6 +112,7 @@

typedef struct Client { Window window; + /*! The window's decorations. NULL while the window is being managed! */ struct Frame *frame; /*! The number of unmap events to ignore on the window */

@@ -133,10 +134,13 @@ /*! The clients which are transients (children) of this client */

GSList *transients; /*! The desktop on which the window resides (0xffffffff for all desktops) */ - unsigned int desktop; + guint desktop; /*! Normal window title */ gchar *title; + /*! The count for the title. When another window with the same title + exists, a count will be appended to it. */ + guint title_count; /*! Window title when iconified */ gchar *icon_title;

@@ -341,6 +345,11 @@ */

void client_configure(Client *self, Corner anchor, int x, int y, int w, int h, gboolean user, gboolean final); +/*! Moves a client so that it is on screen if it is entirely out of the + viewable screen. +*/ +void client_move_onscreen(Client *self); + /*! Fullscreen's or unfullscreen's the client window @param fs true if the window should be made fullscreen; false if it should be returned to normal state.

@@ -389,11 +398,6 @@ @param donthide If TRUE, the window will not be shown/hidden after its

desktop has been changed. Generally this should be FALSE. */ void client_set_desktop(Client *self, guint target, gboolean donthide); -/*! Return a modal child of the client window - @return A modal child of the client window, or 0 if none was found. -*/ -Client *client_find_modal_child(Client *self); - /*! Validate client, by making sure no Destroy or Unmap events exist in the event queue for the window. @return true if the client is valid; false if the client has already

@@ -440,10 +444,8 @@ WMHints. This should only be used during the mapping

process. */ void client_update_wmhints(Client *self); -/*! Updates the window's title */ +/*! Updates the window's title and icon title */ void client_update_title(Client *self); -/*! Updates the window's icon title */ -void client_update_icon_title(Client *self); /*! Updates the window's application name and class */ void client_update_class(Client *self); /*! Updates the strut for the client */

@@ -463,5 +465,22 @@ /*! Retrieves the window's type and sets Client->type */

void client_get_type(Client *self); Icon *client_icon(Client *self, int w, int h); + +/*! Searches a client's transients for a focused window. The function does not + check for the passed client, only for its transients. + If no focused transient is found, NULL is returned. +*/ +Client *client_search_focus_tree(Client *self); + +/*! Searches a client's transient tree for a focused window. The function + searches up the tree and down other branches as well as the passed client's. + If no focused client is found, NULL is returned. +*/ +Client *client_search_focus_tree_full(Client *self); + +/*! Return a modal child of the client window + @return A modal child of the client window, or 0 if none was found. +*/ +Client *client_search_modal_child(Client *self); #endif
M openbox/config.copenbox/config.c

@@ -5,6 +5,7 @@ gboolean config_focus_new;

gboolean config_focus_follow; gboolean config_focus_last; gboolean config_focus_last_on_desktop; +gboolean config_focus_popup; char *config_theme;

@@ -36,6 +37,12 @@ if (value->type != TOKEN_BOOL)

yyerror("invalid value"); else { config_focus_last_on_desktop = value->data.bool; + } + } else if (!g_ascii_strcasecmp(name, "cyclingdialog")) { + if (value->type != TOKEN_BOOL) + yyerror("invalid value"); + else { + config_focus_popup = value->data.bool; } } else yyerror("invalid option");

@@ -95,6 +102,7 @@ config_focus_new = TRUE;

config_focus_follow = FALSE; config_focus_last = TRUE; config_focus_last_on_desktop = TRUE; + config_focus_popup = TRUE; parse_reg_section("focus", NULL, parse_focus);
M openbox/config.hopenbox/config.h

@@ -11,6 +11,8 @@ /*! Focus the last focused window as a fallback */

extern gboolean config_focus_last; /*! Focus the last focused window as a fallback when switching desktops */ extern gboolean config_focus_last_on_desktop; +/*! Show a popup dialog while cycling focus */ +extern gboolean config_focus_popup; /* The name of the theme */ char *config_theme;
M openbox/event.copenbox/event.c

@@ -144,6 +144,9 @@ break;

case ConfigureRequest: window = e->xconfigurerequest.window; break; + case ConfigureNotify: + window = e->xconfigure.window; + break; default: #ifdef XKB if (extensions_xkb && e->type == extensions_xkb_event_basep) {

@@ -308,6 +311,16 @@ } else {

#ifdef DEBUG_FOCUS g_message("found pending FocusIn"); #endif + /* is the focused window getting a FocusOut/In back to + itself? */ + if (fe.xfocus.window == e->xfocus.window) { +#ifdef DEBUG_FOCUS + g_message("focused window got an Out/In back to " + "itself IGNORED both"); +#endif + return TRUE; + } + /* once all the FocusOut's have been dealt with, if there is a FocusIn still left and it is valid, then use it */ event_process(&fe);

@@ -451,6 +464,21 @@ screen_update_desktop_names();

else if (e->xproperty.atom == prop_atoms.net_desktop_layout) screen_update_layout(); break; + case ConfigureNotify: +#ifdef XRANDR + XRRUpdateConfiguration(e); +#endif + if (e->xconfigure.width != screen_physical_size.width || + e->xconfigure.height != screen_physical_size.height) + screen_resize(e->xconfigure.width, e->xconfigure.height); + break; + default: + ; +#ifdef VIDMODE + if (extensions_vidmode && e->type == extensions_vidmode_event_basep) { + g_message("VIDMODE EVENT"); + } +#endif } }

@@ -490,15 +518,25 @@ break;

} break; case FocusIn: +#ifdef DEBUG_FOCUS + g_message("FocusIn on client for %lx", client->window); +#endif focus_set_client(client); + frame_adjust_focus(client->frame, TRUE); + break; case FocusOut: #ifdef DEBUG_FOCUS - g_message("Focus%s on client for %lx", (e->type==FocusIn?"In":"Out"), - client->window); + g_message("FocusOut on client for %lx", client->window); #endif - /* focus state can affect the stacking layer */ - client_calc_layer(client); - frame_adjust_focus(client->frame, e->type == FocusIn); + /* are we a fullscreen window or a transient of one? (checks layer) + if we are then we need to be iconified since we are losing focus + */ + if (client->layer == Layer_Fullscreen && !client->iconic && + !client_search_focus_tree_full(client)) + /* iconify fullscreen windows when they and their transients + aren't focused */ + client_iconify(client, TRUE, TRUE); + frame_adjust_focus(client->frame, FALSE); break; case EnterNotify: if (client_normal(client)) {

@@ -797,11 +835,10 @@ client_calc_layer(client);

client_setup_decor_and_functions(client); } else if (msgtype == prop_atoms.net_wm_name || - msgtype == prop_atoms.wm_name) + msgtype == prop_atoms.wm_name || + msgtype == prop_atoms.net_wm_icon_name || + msgtype == prop_atoms.wm_icon_name) client_update_title(client); - else if (msgtype == prop_atoms.net_wm_icon_name || - msgtype == prop_atoms.wm_icon_name) - client_update_icon_title(client); else if (msgtype == prop_atoms.wm_class) client_update_class(client); else if (msgtype == prop_atoms.wm_protocols) {
M openbox/extensions.copenbox/extensions.c

@@ -7,7 +7,10 @@ gboolean extensions_shape = FALSE;

int extensions_shape_event_basep; gboolean extensions_xinerama = FALSE; int extensions_xinerama_event_basep; - +gboolean extensions_randr = FALSE; +int extensions_randr_event_basep; +gboolean extensions_vidmode = FALSE; +int extensions_vidmode_event_basep; void extensions_query_all() {

@@ -30,5 +33,17 @@ #ifdef XINERAMA

extensions_xinerama = XineramaQueryExtension(ob_display, &extensions_xinerama_event_basep, &junk); +#endif + +#ifdef XRANDR + extensions_randr = + XRRQueryExtension(ob_display, &extensions_randr_event_basep, + &junk); +#endif + +#ifdef VIDMODE + extensions_vidmode = + XF86VidModeQueryExtension(ob_display, &extensions_vidmode_event_basep, + &junk); #endif }
M openbox/extensions.hopenbox/extensions.h

@@ -11,6 +11,12 @@ #endif

#ifdef XINERAMA #include <X11/extensions/Xinerama.h> #endif +#ifdef XRANDR +#include <X11/extensions/Xrandr.h> +#endif +#ifdef VIDMODE +#include <X11/extensions/xf86vmode.h> +#endif #include <glib.h> /*! Does the display have the XKB extension? */

@@ -27,6 +33,16 @@ /*! Does the display have the Xinerama extension? */

extern gboolean extensions_xinerama; /*! Base for events for the Xinerama extension */ extern int extensions_xinerama_event_basep; + +/*! Does the display have the RandR extension? */ +extern gboolean extensions_randr; +/*! Base for events for the Randr extension */ +extern int extensions_randr_event_basep; + +/*! Does the display have the VidMode extension? */ +extern gboolean extensions_vidmode; +/*! Base for events for the VidMode extension */ +extern int extensions_vidmode_event_basep; void extensions_query_all();
M openbox/focus.copenbox/focus.c

@@ -1,6 +1,5 @@

#include "event.h" #include "openbox.h" -#include "grab.h" #include "framerender.h" #include "client.h" #include "config.h"

@@ -12,6 +11,7 @@ #include "dispatch.h"

#include "focus.h" #include "parse.h" #include "stacking.h" +#include "popup.h" #include <X11/Xlib.h> #include <glib.h>

@@ -23,6 +23,7 @@

Window focus_backup = None; static Client *focus_cycle_target = NULL; +static Popup *focus_cycle_popup = NULL; void focus_startup() {

@@ -32,6 +33,7 @@ mapped. */

XSetWindowAttributes attrib; focus_client = NULL; + focus_cycle_popup = popup_new(TRUE); attrib.override_redirect = TRUE; focus_backup = XCreateWindow(ob_display, ob_root,

@@ -54,6 +56,9 @@ g_list_free(focus_order[i]);

g_free(focus_order); focus_order = NULL; + popup_free(focus_cycle_popup); + focus_cycle_popup = NULL; + XDestroyWindow(ob_display, focus_backup); /* reset focus to root */

@@ -98,9 +103,11 @@ /* move to the top of the list */

if (client != NULL) push_to_top(client); - /* set the NET_ACTIVE_WINDOW hint */ - active = client ? client->window : None; - PROP_SET32(ob_root, net_active_window, window, active); + /* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */ + if (ob_state != State_Exiting) { + active = client ? client->window : None; + PROP_SET32(ob_root, net_active_window, window, active); + } if (focus_client != NULL) dispatch_client(Event_Client_Focus, focus_client, 0, 0);

@@ -206,7 +213,11 @@ }

for (it = focus_order[screen_desktop]; it != NULL; it = it->next) if (type != Fallback_Unfocusing || it->data != old) - if (client_normal(it->data) && client_focus(it->data)) + if (client_normal(it->data) && + /* dont fall back to 'anonymous' fullscreen windows. theres no + checks for this is in transient/group fallbacks. */ + !((Client*)it->data)->fullscreen && + client_focus(it->data)) return; /* nothing to focus */

@@ -215,38 +226,28 @@ }

static void popup_cycle(Client *c, gboolean show) { - XSetWindowAttributes attrib; - static Window coords = None; - - if (coords == None) { - attrib.override_redirect = TRUE; - coords = XCreateWindow(ob_display, ob_root, - 0, 0, 1, 1, 0, render_depth, InputOutput, - render_visual, CWOverrideRedirect, &attrib); - g_assert(coords != None); - - grab_pointer(TRUE, None); - - XMapWindow(ob_display, coords); - } - if (!show) { - XDestroyWindow(ob_display, coords); - coords = None; - - grab_pointer(FALSE, None); + popup_hide(focus_cycle_popup); } else { Rect *a; - Size s; a = screen_area(c->desktop); + popup_position(focus_cycle_popup, CenterGravity, + a->x + a->width / 2, a->y + a->height / 2); +/* popup_size(focus_cycle_popup, a->height/2, a->height/16); + popup_show(focus_cycle_popup, c->title, + client_icon(c, a->height/16, a->height/16)); +*/ + /* XXX the size and the font extents need to be related on some level + */ + popup_size(focus_cycle_popup, 320, 48); - framerender_size_popup_label(c->title, &s); - XMoveResizeWindow(ob_display, coords, - a->x + (a->width - s.width) / 2, - a->y + (a->height - s.height) / 2, - s.width, s.height); - framerender_popup_label(coords, &s, c->title); + /* use the transient's parent's title/icon */ + while (c->transient_for && c->transient_for != TRAN_GROUP) + c = c->transient_for; + + popup_show(focus_cycle_popup, (c->iconic ? c->icon_title : c->title), + client_icon(c, 48, 48)); } }

@@ -294,15 +295,18 @@ } else {

it = it->prev; if (it == NULL) it = g_list_last(list); } - ft = client_focus_target(it->data); - if (ft == it->data && client_normal(ft) && + /*ft = client_focus_target(it->data);*/ + ft = it->data; + if (ft->transients == NULL && /*ft == it->data &&*/client_normal(ft) && (ft->can_focus || ft->focus_notify) && (ft->desktop == screen_desktop || ft->desktop == DESKTOP_ALL)) { - if (focus_cycle_target) - frame_adjust_focus(focus_cycle_target->frame, FALSE); - focus_cycle_target = ft; - frame_adjust_focus(focus_cycle_target->frame, TRUE); - popup_cycle(ft, TRUE); + if (ft != focus_cycle_target) { /* prevents flicker */ + if (focus_cycle_target) + frame_adjust_focus(focus_cycle_target->frame, FALSE); + focus_cycle_target = ft; + frame_adjust_focus(focus_cycle_target->frame, TRUE); + } + popup_cycle(ft, config_focus_popup); return ft; } } while (it != start);
M openbox/framerender.copenbox/framerender.c

@@ -218,34 +218,3 @@ RECT_SET(a->texture[0].position, 0, 0,

theme_button_size, theme_button_size); paint(self->close, a); } - -void framerender_popup_label(Window win, Size *sz, char *text) -{ - Appearance *a; - - a = theme_app_hilite_label; - a->texture[0].data.text.string = text; - RECT_SET(a->area, 0, 0, sz->width, sz->height); - a->texture[0].position = a->area; - a->texture[0].position.x += theme_bevel; - a->texture[0].position.y += theme_bevel; - a->texture[0].position.width -= theme_bevel * 2; - a->texture[0].position.height -= theme_bevel * 2; - - XSetWindowBorderWidth(ob_display, win, theme_bwidth); - XSetWindowBorder(ob_display, win, theme_b_color->pixel); - - paint(win, a); -} - -void framerender_size_popup_label(char *text, Size *sz) -{ - Appearance *a; - - a = theme_app_hilite_label; - a->texture[0].data.text.string = text; - - appearance_minsize(a, &sz->width, &sz->height); - sz->width += theme_bevel * 2; - sz->height += theme_bevel * 2; -}
M openbox/framerender.hopenbox/framerender.h

@@ -5,7 +5,4 @@ #include "frame.h"

void framerender_frame(Frame *self); -void framerender_popup_label(Window win, Size *sz, char *text); -void framerender_size_popup_label(char *text, Size *sz); - #endif
M openbox/menu.copenbox/menu.c

@@ -76,6 +76,16 @@ menu_add_entry(m, menu_entry_new("restart", a));

menu_add_entry(m, menu_entry_new("--", NULL)); a = action_from_string("exit"); menu_add_entry(m, menu_entry_new("exit", a)); + + m = menu_new("client menu", "client", NULL); + a = action_from_string("iconify"); + menu_add_entry(m, menu_entry_new("iconify", a)); + a = action_from_string("toggleshade"); + menu_add_entry(m, menu_entry_new("(un)shade", a)); + a = action_from_string("togglemaximizefull"); + menu_add_entry(m, menu_entry_new("(un)maximize", a)); + a = action_from_string("close"); + menu_add_entry(m, menu_entry_new("close", a)); } void menu_shutdown()
M openbox/moveresize.copenbox/moveresize.c

@@ -4,6 +4,7 @@ #include "prop.h"

#include "client.h" #include "dispatch.h" #include "openbox.h" +#include "popup.h" #include <X11/Xlib.h> #include <glib.h>

@@ -13,7 +14,6 @@ Client *moveresize_client = NULL;

static gboolean moving = FALSE; /* TRUE - moving, FALSE - resizing */ -static Window coords = None; static int start_x, start_y, start_cx, start_cy, start_cw, start_ch; static int cur_x, cur_y; static guint button;

@@ -23,6 +23,8 @@

static guint button_return, button_escape, button_left, button_right, button_up, button_down; +static Popup *popup = NULL; + #define POPUP_X (10) #define POPUP_Y (10)

@@ -34,29 +36,24 @@ button_left = XKeysymToKeycode(ob_display, XStringToKeysym("Left"));

button_right = XKeysymToKeycode(ob_display, XStringToKeysym("Right")); button_up = XKeysymToKeycode(ob_display, XStringToKeysym("Up")); button_down = XKeysymToKeycode(ob_display, XStringToKeysym("Down")); + + popup = popup_new(FALSE); + popup_size_to_string(popup, "W: 0000 W: 0000"); + popup_position(popup, NorthWestGravity, POPUP_X, POPUP_Y); +} + +void moveresize_shutdown() +{ + popup_free(popup); + popup = NULL; } static void popup_coords(char *format, int a, int b) { - XSetWindowAttributes attrib; - Size s; char *text; - if (coords == None) { - attrib.override_redirect = TRUE; - coords = XCreateWindow(ob_display, ob_root, - 0, 0, 1, 1, 0, render_depth, InputOutput, - render_visual, CWOverrideRedirect, &attrib); - g_assert(coords != None); - - XMapWindow(ob_display, coords); - } - text = g_strdup_printf(format, a, b); - framerender_size_popup_label(text, &s); - XMoveResizeWindow(ob_display, coords, - POPUP_X, POPUP_Y, s.width, s.height); - framerender_popup_label(coords, &s, text); + popup_show(popup, text, NULL); g_free(text); }

@@ -127,8 +124,7 @@ {

grab_keyboard(FALSE); grab_pointer(FALSE, None); - XDestroyWindow(ob_display, coords); - coords = None; + popup_hide(popup); if (moving) { client_configure(moveresize_client, Corner_TopLeft,

@@ -156,7 +152,9 @@ frame_frame_gravity(moveresize_client->frame, &cur_x, &cur_y);

client_configure(moveresize_client, Corner_TopLeft, cur_x, cur_y, start_cw, start_ch, TRUE, FALSE); - popup_coords("X: %d Y: %d", moveresize_client->frame->area.x, + /* this would be better with a fixed width font ... XXX can do it better + if there are 2 text boxes */ + popup_coords("X: %4d Y: %4d", moveresize_client->frame->area.x, moveresize_client->frame->area.y); }

@@ -178,7 +176,9 @@

client_configure(moveresize_client, lockcorner, moveresize_client->area.x, moveresize_client->area.y, cur_x, cur_y, TRUE, FALSE); - popup_coords("W: %d H: %d", moveresize_client->logical_size.width, + /* this would be better with a fixed width font ... XXX can do it better + if there are 2 text boxes */ + popup_coords("W: %4d H: %4d", moveresize_client->logical_size.width, moveresize_client->logical_size.height); }
M openbox/moveresize.hopenbox/moveresize.h

@@ -9,6 +9,7 @@ extern gboolean moveresize_in_progress;

extern Client *moveresize_client; void moveresize_startup(); +void moveresize_shutdown(); void moveresize_start(Client *c, int x, int y, guint button, guint32 corner); void moveresize_end(gboolean cancel);
M openbox/openbox.copenbox/openbox.c

@@ -166,7 +166,6 @@ render_startup();

font_startup(); theme_startup(); event_startup(); - moveresize_startup(); grab_startup(); plugin_startup(); /* load the plugins specified in the pluginrc */

@@ -187,6 +186,7 @@

menu_startup(); frame_startup(); stacking_startup(); + moveresize_startup(); focus_startup(); screen_startup(); group_startup();

@@ -210,6 +210,7 @@ client_shutdown();

group_shutdown(); screen_shutdown(); focus_shutdown(); + moveresize_shutdown(); stacking_shutdown(); frame_shutdown(); menu_shutdown();
M openbox/parse.hopenbox/parse.h

@@ -11,7 +11,7 @@ TOKEN_REAL = REAL,

TOKEN_INTEGER = INTEGER, TOKEN_STRING = STRING, TOKEN_IDENTIFIER = IDENTIFIER, - TOKEN_BOOL = BOOL, + TOKEN_BOOL = BOOLEAN, TOKEN_LIST, TOKEN_LBRACE = '{', TOKEN_RBRACE = '}',
M openbox/parse.lopenbox/parse.l

@@ -31,7 +31,7 @@ }

{bool} { yylval.bool = (!g_ascii_strcasecmp("true", yytext) || !g_ascii_strcasecmp("yes", yytext) || !g_ascii_strcasecmp("on", yytext)); - return BOOL; + return BOOLEAN; } {identifier} { yylval.identifier = g_strdup(yytext); return IDENTIFIER; } [{}()\[\]=,] { yylval.character = *yytext; return *yytext; }
M openbox/parse.yopenbox/parse.y

@@ -41,7 +41,7 @@ %token <real> REAL

%token <integer> INTEGER %token <string> STRING %token <identifier> IDENTIFIER -%token <bool> BOOL +%token <bool> BOOLEAN %token <character> '(' %token <character> ')' %token <character> '{'

@@ -78,7 +78,7 @@ REAL { t.type = TOKEN_REAL; t.data.real = $1; }

| INTEGER { t.type = TOKEN_INTEGER; t.data.integer = $1; } | STRING { t.type = TOKEN_STRING; t.data.string = $1; } | IDENTIFIER { t.type = TOKEN_IDENTIFIER; t.data.identifier = $1; } - | BOOL { t.type = TOKEN_BOOL; t.data.bool = $1; } + | BOOLEAN { t.type = TOKEN_BOOL; t.data.bool = $1; } | list { t.type = TOKEN_LIST; t.data.list = $1; } | '{' { t.type = $1; t.data.character = $1; } | '}' { t.type = $1; t.data.character = $1; }

@@ -107,7 +107,7 @@ REAL { t.type = TOKEN_REAL; t.data.real = $1; }

| INTEGER { t.type = TOKEN_INTEGER; t.data.integer = $1; } | STRING { t.type = TOKEN_STRING; t.data.string = $1; } | IDENTIFIER { t.type = TOKEN_IDENTIFIER; t.data.identifier = $1; } - | BOOL { t.type = TOKEN_BOOL; t.data.bool = $1; } + | BOOLEAN { t.type = TOKEN_BOOL; t.data.bool = $1; } | list { t.type = TOKEN_LIST; t.data.list = $1; } | '{' { t.type = $1; t.data.character = $1; } | '}' { t.type = $1; t.data.character = $1; }
M openbox/screen.copenbox/screen.c

@@ -7,6 +7,7 @@ #include "client.h"

#include "frame.h" #include "focus.h" #include "dispatch.h" +#include "extensions.h" #include "../render/render.h" #include <X11/Xlib.h>

@@ -16,7 +17,7 @@ # include <unistd.h>

#endif /*! The event mask to grab on the root window */ -#define ROOT_EVENTMASK (/*ColormapChangeMask |*/ PropertyChangeMask | \ +#define ROOT_EVENTMASK (StructureNotifyMask | PropertyChangeMask | \ EnterWindowMask | LeaveWindowMask | \ SubstructureNotifyMask | SubstructureRedirectMask | \ ButtonPressMask | ButtonReleaseMask | ButtonMotionMask)

@@ -160,7 +161,8 @@ GSList *it;

guint i; /* get the initial size */ - screen_resize(); + screen_resize(WidthOfScreen(ScreenOfDisplay(ob_display, ob_screen)), + HeightOfScreen(ScreenOfDisplay(ob_display, ob_screen))); /* set the names */ screen_desktop_names = g_new(char*,

@@ -201,14 +203,14 @@ g_free(strut);

g_free(area); } -void screen_resize() +void screen_resize(int w, int h) { - /* XXX RandR support here? */ + GList *it; guint32 geometry[2]; /* Set the _NET_DESKTOP_GEOMETRY hint */ - geometry[0] = WidthOfScreen(ScreenOfDisplay(ob_display, ob_screen)); - geometry[1] = HeightOfScreen(ScreenOfDisplay(ob_display, ob_screen)); + geometry[0] = w; + geometry[1] = h; PROP_SETA32(ob_root, net_desktop_geometry, cardinal, geometry, 2); screen_physical_size.width = geometry[0]; screen_physical_size.height = geometry[1];

@@ -218,7 +220,8 @@ return;

screen_update_struts(); - /* XXX adjust more stuff ? */ + for (it = client_list; it; it = it->next) + client_move_onscreen(it->data); } void screen_set_num_desktops(guint num)
M openbox/screen.hopenbox/screen.h

@@ -43,7 +43,7 @@ /*! Free resources */

void screen_shutdown(); /*! Figure out the new size of the screen and adjust stuff for it */ -void screen_resize(); +void screen_resize(int w, int h); /*! Change the number of available desktops */ void screen_set_num_desktops(guint num);
M openbox/stacking.copenbox/stacking.c

@@ -70,7 +70,7 @@

static void raise_recursive(Client *client) { Window wins[2]; /* only ever restack 2 windows. */ - GList *it; + GList *it, *low; GSList *sit; g_assert(stacking_list != NULL); /* this would be bad */

@@ -86,15 +86,15 @@

/* find 'it' where it is the positiion in the stacking order where 'client' will be inserted *before* */ - it = find_lowest_transient(client); - if (it) - it = it->next; - else { - /* the stacking list is from highest to lowest */ - for (it = stacking_list; it; it = it->next) { - if (client->layer >= ((Client*)it->data)->layer) - break; + low = find_lowest_transient(client); + /* the stacking list is from highest to lowest */ + for (it = g_list_last(stacking_list); it; it = it->prev) { + if (it == low || client->layer < ((Client*)it->data)->layer) { + it = it->next; + break; } + if (it == stacking_list) + break; } /*
M plugins/keyboard/keyboard.cplugins/keyboard/keyboard.c

@@ -56,12 +56,15 @@ g_assert(action != NULL);

if (!(tree = tree_build(keylist))) return FALSE; + if ((t = tree_find(tree, &conflict)) != NULL) { - /* already bound to something */ - g_message("keychain is already bound"); + /* already bound to something, use the existing tree */ tree_destroy(tree); - return FALSE; - } + tree = NULL; + } else + t = tree; + while (t->first_child) t = t->first_child; + if (conflict) { g_message("conflict with binding"); tree_destroy(tree);

@@ -73,12 +76,10 @@ grab_server(TRUE);

grab_keys(FALSE); /* set the action */ - t = tree; - while (t->first_child) t = t->first_child; - t->action = action; + t->actions = g_slist_append(t->actions, action); /* assimilate this built tree into the main tree. assimilation destroys/uses the tree */ - tree_assimilate(tree); + if (tree) tree_assimilate(tree); grab_keys(TRUE); grab_server(FALSE);

@@ -100,17 +101,25 @@ else if (e->type == Event_X_KeyPress) {

if (e->data.x.e->xkey.keycode == button_return) done = TRUE; else if (e->data.x.e->xkey.keycode == button_escape) { - grabbed_key->action->data.cycle.cancel = TRUE; + GSList *it; + for (it = grabbed_key->actions; it; it = it->next) { + Action *act = it->data; + act->data.cycle.cancel = TRUE; + } done = TRUE; } } - if (done) { - grabbed_key->action->data.cycle.final = TRUE; - grabbed_key->action->func(&grabbed_key->action->data); - grab_keyboard(FALSE); - grabbed_key = NULL; - reset_chains(); - return; + if (done) { + GSList *it; + for (it = grabbed_key->actions; it; it = it->next) { + Action *act = it->data; + act->data.cycle.final = TRUE; + act->func(&act->data); + grab_keyboard(FALSE); + grabbed_key = NULL; + reset_chains(); + return; + } } } if (e->type == Event_X_KeyRelease)

@@ -140,20 +149,24 @@ event_lasttime);

} curpos = p; } else { - if (p->action->func != NULL) { - p->action->data.any.c = focus_client; + GSList *it; + for (it = p->actions; it; it = it->next) { + Action *act = it->data; + if (act->func != NULL) { + act->data.any.c = focus_client; - if (p->action->func == action_cycle_windows) { - p->action->data.cycle.final = FALSE; - p->action->data.cycle.cancel = FALSE; - } + if (act->func == action_cycle_windows) { + act->data.cycle.final = FALSE; + act->data.cycle.cancel = FALSE; + } - p->action->func(&p->action->data); + act->func(&act->data); - if (p->action->func == action_cycle_windows && - !grabbed_key) { - grab_keyboard(TRUE); - grabbed_key = p; + if (act->func == action_cycle_windows && + !grabbed_key) { + grab_keyboard(TRUE); + grabbed_key = p; + } } }
M plugins/keyboard/tree.cplugins/keyboard/tree.c

@@ -11,10 +11,13 @@ tree_destroy(tree->next_sibling);

c = tree->first_child; if (c == NULL) { GList *it; + GSList *sit; for (it = tree->keylist; it != NULL; it = it->next) g_free(it->data); g_list_free(tree->keylist); - action_free(tree->action); + for (it = tree->actions; it != NULL; it = it->next) + action_free(it->data); + g_slist_free(tree->actions); } g_free(tree); tree = c;
M plugins/keyboard/tree.hplugins/keyboard/tree.h

@@ -8,7 +8,7 @@ typedef struct KeyBindingTree {

guint state; guint key; GList *keylist; - Action *action; + GSList *actions; /* list of Action pointers */ /* the next binding in the tree at the same level */ struct KeyBindingTree *next_sibling;
M plugins/mouse/mouse.cplugins/mouse/mouse.c

@@ -96,9 +96,13 @@ for (it = bound_contexts[i]; it != NULL; it = it->next) {

int j; MouseBinding *b = it->data; - for (j = 0; j < NUM_MOUSEACTION; ++j) - if (b->action[j] != NULL) - action_free(b->action[j]); + for (j = 0; j < NUM_MOUSEACTION; ++j) { + GSList *it; + for (it = b->actions[j]; it; it = it->next) { + action_free(it->data); + } + g_slist_free(b->actions[j]); + } g_free(b); } g_slist_free(bound_contexts[i]);

@@ -119,17 +123,20 @@ }

/* if not bound, then nothing to do! */ if (it == NULL) return; - if (b->action[a] != NULL && b->action[a]->func != NULL) { - b->action[a]->data.any.c = c; + for (it = b->actions[a]; it; it = it->next) { + Action *act = it->data; + if (act->func != NULL) { + act->data.any.c = c; - g_assert(b->action[a]->func != action_moveresize); + g_assert(act->func != action_moveresize); + + if (act->func == action_showmenu) { + act->data.showmenu.x = x; + act->data.showmenu.y = y; + } - if (b->action[a]->func == action_showmenu) { - b->action[a]->data.showmenu.x = x; - b->action[a]->data.showmenu.y = y; + act->func(&act->data); } - - b->action[a]->func(&b->action[a]->data); } }

@@ -148,24 +155,27 @@ }

/* if not bound, then nothing to do! */ if (it == NULL) return; - if (b->action[a] != NULL && b->action[a]->func != NULL) { - b->action[a]->data.any.c = c; + for (it = b->actions[a]; it; it = it->next) { + Action *act = it->data; + if (act->func != NULL) { + act->data.any.c = c; - if (b->action[a]->func == action_moveresize) { - b->action[a]->data.moveresize.x = x_root; - b->action[a]->data.moveresize.y = y_root; - b->action[a]->data.moveresize.button = button; - if (!(b->action[a]->data.moveresize.corner == - prop_atoms.net_wm_moveresize_move || - b->action[a]->data.moveresize.corner == - prop_atoms.net_wm_moveresize_move_keyboard || - b->action[a]->data.moveresize.corner == - prop_atoms.net_wm_moveresize_size_keyboard)) - b->action[a]->data.moveresize.corner = corner; - } else - g_assert_not_reached(); + if (act->func == action_moveresize) { + act->data.moveresize.x = x_root; + act->data.moveresize.y = y_root; + act->data.moveresize.button = button; + if (!(act->data.moveresize.corner == + prop_atoms.net_wm_moveresize_move || + act->data.moveresize.corner == + prop_atoms.net_wm_moveresize_move_keyboard || + act->data.moveresize.corner == + prop_atoms.net_wm_moveresize_size_keyboard)) + act->data.moveresize.corner = corner; + } else + g_assert_not_reached(); - b->action[a]->func(&b->action[a]->data); + act->func(&act->data); + } } }

@@ -338,12 +348,7 @@

for (it = bound_contexts[context]; it != NULL; it = it->next){ b = it->data; if (b->state == state && b->button == button) { - /* already bound */ - if (b->action[mact] != NULL) { - g_warning("duplicate binding"); - return FALSE; - } - b->action[mact] = action; + b->actions[mact] = g_slist_append(b->actions[mact], action); return TRUE; } }

@@ -354,7 +359,7 @@ /* add the binding */

b = g_new0(MouseBinding, 1); b->state = state; b->button = button; - b->action[mact] = action; + b->actions[mact] = g_slist_append(NULL, action); bound_contexts[context] = g_slist_append(bound_contexts[context], b); grab_all_clients(TRUE);
M plugins/mouse/mouse.hplugins/mouse/mouse.h

@@ -15,7 +15,7 @@

typedef struct { guint state; guint button; - Action *action[NUM_MOUSEACTION]; + GSList *actions[NUM_MOUSEACTION]; /* lists of Action pointers */ } MouseBinding; gboolean mbind(char *buttonstr, char *contextstr, MouseAction mact,
M render/font.crender/font.c

@@ -8,6 +8,10 @@ #include <X11/Xft/Xft.h>

#include <glib.h> #include "../kernel/geom.h" +#define ELIPSES "..." +#define ELIPSES_LENGTH(font, shadow, offset) \ + (font->elipses_length + (shadow ? offset : 0)) + void font_startup(void) { #ifdef DEBUG

@@ -38,6 +42,11 @@

XftTextExtentsUtf8(ob_display, f->xftfont, (FcChar8*)str, strlen(str), &info); f->height = (signed) info.height; + + /* measure an elipses */ + XftTextExtentsUtf8(ob_display, f->xftfont, + (FcChar8*)ELIPSES, strlen(ELIPSES), &info); + f->elipses_length = (signed) info.xOff; } ObFont *font_open(char *fontstring)

@@ -98,9 +107,10 @@ void font_draw(XftDraw *d, TextureText *t, Rect *position)

{ int x,y,w,h; XftColor c; - char *text; - int m; + GString *text; + int m, em; size_t l; + gboolean shortened = FALSE; y = position->y; w = position->width;

@@ -110,12 +120,22 @@ /* accomidate for areas bigger/smaller than Xft thinks the font is tall */

y -= (2 * (t->font->xftfont->ascent + t->font->xftfont->descent) - (t->font->height + h) - 1) / 2; - text = g_strdup(t->string); - l = strlen(text); - m = font_measure_string(t->font, text, t->shadow, t->offset); + text = g_string_new(t->string); + l = g_utf8_strlen(text->str, -1); + m = font_measure_string(t->font, text->str, t->shadow, t->offset); while (l && m > position->width) { - text[--l] = '\0'; - m = font_measure_string(t->font, text, t->shadow, t->offset); + shortened = TRUE; + /* remove a character from the middle */ + text = g_string_erase(text, l-- / 2, 1); + em = ELIPSES_LENGTH(t->font, t->shadow, t->offset); + /* if the elipses are too large, don't show them at all */ + if (em > position->width) + shortened = FALSE; + m = font_measure_string(t->font, text->str, t->shadow, t->offset) + em; + } + if (shortened) { + text = g_string_insert(text, (l + 1) / 2, ELIPSES); + l += 3; } if (!l) return;

@@ -147,7 +167,7 @@ c.pixel = WhitePixel(ob_display, ob_screen);

} XftDrawStringUtf8(d, &c, t->font->xftfont, x + t->offset, t->font->xftfont->ascent + y + t->offset, - (FcChar8*)text, l); + (FcChar8*)text->str, l); } c.color.red = t->color->r | t->color->r << 8; c.color.green = t->color->g | t->color->g << 8;

@@ -157,6 +177,6 @@ c.pixel = t->color->pixel;

XftDrawStringUtf8(d, &c, t->font->xftfont, x, t->font->xftfont->ascent + y, - (FcChar8*)text, l); + (FcChar8*)text->str, l); return; }
M render/image.crender/image.c

@@ -5,66 +5,72 @@

void image_draw(pixel32 *target, TextureRGBA *rgba, Rect *position, Rect *surarea) { - unsigned long *draw = rgba->data; - int c, sfw, sfh; - unsigned int i, e; - sfw = position->width; - sfh = position->height; + gulong *draw = rgba->data; + guint c, i, e, t, sfw, sfh; + sfw = position->width; + sfh = position->height; - /* it would be nice if this worked, but this function is well broken in these - cercumstances. */ - g_assert(position->width == surarea->width && - position->height == surarea->height); + /* it would be nice if this worked, but this function is well broken in + these circumstances. */ + g_assert(position->width == surarea->width && + position->height == surarea->height); - g_assert(rgba->data != NULL); + g_assert(rgba->data != NULL); - if ((rgba->width != sfw || rgba->height != sfh) && - (rgba->width != rgba->cwidth || rgba->height != rgba->cheight)) { - double dx = rgba->width / (double)sfw; - double dy = rgba->height / (double)sfh; - double px = 0.0; - double py = 0.0; - int iy = 0; + if ((rgba->width != sfw || rgba->height != sfh) && + (rgba->width != rgba->cwidth || rgba->height != rgba->cheight)) { + double dx = rgba->width / (double)sfw; + double dy = rgba->height / (double)sfh; + double px = 0.0; + double py = 0.0; + int iy = 0; - /* scale it and cache it */ - if (rgba->cache != NULL) - g_free(rgba->cache); - rgba->cache = g_new(unsigned long, sfw * sfh); - rgba->cwidth = sfw; - rgba->cheight = sfh; - for (i = 0, c = 0, e = sfw*sfh; i < e; ++i) { - rgba->cache[i] = rgba->data[(int)px + iy]; - if (++c >= sfw) { - c = 0; - px = 0; - py += dy; - iy = (int)py * rgba->width; - } else - px += dx; - } + /* scale it and cache it */ + if (rgba->cache != NULL) + g_free(rgba->cache); + rgba->cache = g_new(unsigned long, sfw * sfh); + rgba->cwidth = sfw; + rgba->cheight = sfh; + for (i = 0, c = 0, e = sfw*sfh; i < e; ++i) { + rgba->cache[i] = rgba->data[(int)px + iy]; + if (++c >= sfw) { + c = 0; + px = 0; + py += dy; + iy = (int)py * rgba->width; + } else + px += dx; + } -/* do we use the cache we may have just created, or the original? */ - if (rgba->width != sfw || rgba->height != sfh) - draw = rgba->cache; + /* do we use the cache we may have just created, or the original? */ + if (rgba->width != sfw || rgba->height != sfh) + draw = rgba->cache; - /* apply the alpha channel */ - for (i = 0, c = 0, e = sfw*sfh; i < e; ++i) { - unsigned char alpha = draw[i] >> 24; - unsigned char r = draw[i] >> 16; - unsigned char g = draw[i] >> 8; - unsigned char b = draw[i]; + /* apply the alpha channel */ + for (i = 0, c = 0, t = position->x, e = sfw*sfh; i < e; ++i, ++t) { + guchar alpha, r, g, b, bgr, bgg, bgb; + + alpha = draw[i] >> 24; + r = draw[i] >> 16; + g = draw[i] >> 8; + b = draw[i]; + + if (c >= sfw) { + c = 0; + t += surarea->width - sfw; + } - /* background color */ - unsigned char bgr = target[i] >> default_red_shift; - unsigned char bgg = target[i] >> default_green_shift; - unsigned char bgb = target[i] >> default_blue_shift; + /* background color */ + bgr = target[t] >> default_red_shift; + bgg = target[t] >> default_green_shift; + bgb = target[t] >> default_blue_shift; - r = bgr + (((r - bgr) * alpha) >> 8); - g = bgg + (((g - bgg) * alpha) >> 8); - b = bgb + (((b - bgb) * alpha) >> 8); + r = bgr + (((r - bgr) * alpha) >> 8); + g = bgg + (((g - bgg) * alpha) >> 8); + b = bgb + (((b - bgb) * alpha) >> 8); - target[i] = (r << default_red_shift) | (g << default_green_shift) | - (b << default_blue_shift); + target[t] = (r << default_red_shift) | (g << default_green_shift) | + (b << default_blue_shift); + } } - } }
M render/render.crender/render.c

@@ -7,6 +7,7 @@ #include "font.h"

#include "mask.h" #include "color.h" #include "image.h" +#include "theme.h" #include "kernel/openbox.h" #ifdef HAVE_STDLIB_H

@@ -421,6 +422,7 @@

void appearance_minsize(Appearance *l, int *w, int *h) { int i; + int m; *w = *h = 1; switch (l->surface.type) {

@@ -437,20 +439,22 @@ }

} else if (l->surface.data.planar.border) *w = *h = 2; - for (i = 0; i < l->textures; ++i) + for (i = 0; i < l->textures; ++i) { switch (l->texture[i].type) { case Bitmask: *w += l->texture[i].data.mask.mask->w; *h += l->texture[i].data.mask.mask->h; break; case Text: - *w +=font_measure_string(l->texture[i].data.text.font, - l->texture[i].data.text.string, - l->texture[i].data.text.shadow, - l->texture[i].data.text.offset); - *h += font_height(l->texture[i].data.text.font, - l->texture[i].data.text.shadow, - l->texture[i].data.text.offset); + m = font_measure_string(l->texture[i].data.text.font, + l->texture[i].data.text.string, + l->texture[i].data.text.shadow, + l->texture[i].data.text.offset); + *w += m; + m = font_height(l->texture[i].data.text.font, + l->texture[i].data.text.shadow, + l->texture[i].data.text.offset); + *h += m; break; case RGBA: *w += l->texture[i].data.rgba.width;

@@ -458,7 +462,8 @@ *h += l->texture[i].data.rgba.height;

break; case NoTexture: break; - } + } + } break; } }
M render/render.hrender/render.h

@@ -79,6 +79,7 @@

typedef struct { XftFont *xftfont; int height; + int elipses_length; } ObFont; typedef enum {

@@ -109,12 +110,12 @@ pixmap_mask *mask;

} TextureMask; typedef struct TextureRGBA { - int width; - int height; + guint width; + guint height; unsigned long *data; /* cached scaled so we don't have to scale often */ - int cwidth; - int cheight; + guint cwidth; + guint cheight; unsigned long *cache; } TextureRGBA;
M render/theme.crender/theme.c

@@ -93,8 +93,11 @@ Appearance *theme_a_menu_item;

Appearance *theme_a_menu_disabled; Appearance *theme_a_menu_hilite; +Appearance *theme_app_hilite_bg; +Appearance *theme_app_unhilite_bg; Appearance *theme_app_hilite_label; Appearance *theme_app_unhilite_label; +Appearance *theme_app_icon; void theme_startup() {

@@ -151,8 +154,11 @@ theme_a_menu_item = appearance_new(Surface_Planar, 1);

theme_a_menu_disabled = appearance_new(Surface_Planar, 1); theme_a_menu_hilite = appearance_new(Surface_Planar, 1); + theme_app_hilite_bg = appearance_new(Surface_Planar, 0); + theme_app_unhilite_bg = appearance_new(Surface_Planar, 0); theme_app_hilite_label = appearance_new(Surface_Planar, 1); theme_app_unhilite_label = appearance_new(Surface_Planar, 1); + theme_app_icon = appearance_new(Surface_Planar, 1); }

@@ -221,8 +227,11 @@ appearance_free(theme_a_menu_title);

appearance_free(theme_a_menu_item); appearance_free(theme_a_menu_disabled); appearance_free(theme_a_menu_hilite); + appearance_free(theme_app_hilite_bg); + appearance_free(theme_app_unhilite_bg); appearance_free(theme_app_hilite_label); appearance_free(theme_app_unhilite_label); + appearance_free(theme_app_icon); } static XrmDatabase loaddb(char *theme)

@@ -330,7 +339,7 @@

if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr != NULL) { - button_dir = g_strdup_printf("%s_buttons", theme); + button_dir = g_strdup_printf("%s_data", theme); s = g_build_filename(g_get_home_dir(), ".openbox", "themes", button_dir, retvalue.addr, NULL);

@@ -348,7 +357,7 @@ char *themename;

g_free(s); themename = g_path_get_basename(theme); - s = g_strdup_printf("%s/%s_buttons/%s", theme, + s = g_strdup_printf("%s/%s_data/%s", theme, themename, retvalue.addr); g_free(themename); if (XReadBitmapFileData(s, &w, &h, &b, &hx, &hy) ==

@@ -728,26 +737,15 @@ set_default_appearance(theme_a_menu_title);

if (!read_appearance(db, "menu.hilite", theme_a_menu_hilite)) set_default_appearance(theme_a_menu_hilite); - /* read the appearances for rendering non-decorations. these cannot be - parent-relative */ - if (theme_a_focused_label->surface.data.planar.grad != - Background_ParentRelative) { - if (!read_appearance(db, "window.label.focus", theme_app_hilite_label)) - set_default_appearance(theme_app_hilite_label); - } else { - if (!read_appearance(db, "window.title.focus", theme_app_hilite_label)) - set_default_appearance(theme_app_hilite_label); - } - if (theme_a_unfocused_label->surface.data.planar.grad != - Background_ParentRelative) { - if (!read_appearance(db, "window.label.unfocus", - theme_app_unhilite_label)) - set_default_appearance(theme_app_unhilite_label); - } else { - if (!read_appearance(db, "window.title.unfocus", - theme_app_unhilite_label)) - set_default_appearance(theme_app_unhilite_label); - } + /* read the appearances for rendering non-decorations */ + if (!read_appearance(db, "window.title.focus", theme_app_hilite_bg)) + set_default_appearance(theme_app_hilite_bg); + if (!read_appearance(db, "window.label.focus", theme_app_hilite_label)) + set_default_appearance(theme_app_hilite_label); + if (!read_appearance(db, "window.title.unfocus", theme_app_unhilite_bg)) + set_default_appearance(theme_app_unhilite_bg); + if (!read_appearance(db, "window.label.unfocus", theme_app_unhilite_label)) + set_default_appearance(theme_app_unhilite_label); /* read buttons textures */ if (!read_appearance(db, "window.button.pressed.focus",

@@ -817,8 +815,8 @@

/* set up the textures */ theme_a_focused_label->texture[0].type = theme_app_hilite_label->texture[0].type = Text; - theme_a_focused_label->texture[0].data.text.justify = - theme_app_hilite_label->texture[0].data.text.justify = winjust; + theme_a_focused_label->texture[0].data.text.justify = winjust; + theme_app_hilite_label->texture[0].data.text.justify = Justify_Left; theme_a_focused_label->texture[0].data.text.font = theme_app_hilite_label->texture[0].data.text.font = theme_winfont; theme_a_focused_label->texture[0].data.text.shadow =

@@ -836,8 +834,8 @@ theme_title_focused_color;

theme_a_unfocused_label->texture[0].type = theme_app_unhilite_label->texture[0].type = Text; - theme_a_unfocused_label->texture[0].data.text.justify = - theme_app_unhilite_label->texture[0].data.text.justify = winjust; + theme_a_unfocused_label->texture[0].data.text.justify = winjust; + theme_app_unhilite_label->texture[0].data.text.justify = Justify_Left; theme_a_unfocused_label->texture[0].data.text.font = theme_app_unhilite_label->texture[0].data.text.font = theme_winfont; theme_a_unfocused_label->texture[0].data.text.shadow =

@@ -865,6 +863,7 @@ theme_a_menu_title->texture[0].data.text.color = theme_menu_title_color;

theme_a_menu_item->surface.data.planar.grad = theme_a_menu_disabled->surface.data.planar.grad = + theme_app_icon->surface.data.planar.grad = Background_ParentRelative; theme_a_menu_item->texture[0].type =
M render/theme.hrender/theme.h

@@ -78,8 +78,11 @@ extern Appearance *theme_a_menu_item;

extern Appearance *theme_a_menu_disabled; extern Appearance *theme_a_menu_hilite; +extern Appearance *theme_app_hilite_bg; +extern Appearance *theme_app_unhilite_bg; extern Appearance *theme_app_hilite_label; extern Appearance *theme_app_unhilite_label; +extern Appearance *theme_app_icon; void theme_startup(); void theme_shutdown();