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.
This commit is contained in:
Dana Jansens 2003-05-09 16:57:17 +00:00
parent 60065663ba
commit f26f23de50
37 changed files with 753 additions and 393 deletions

View file

@ -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

View file

@ -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:

View file

@ -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 @@ AC_CONFIG_FILES([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

View file

@ -27,6 +27,9 @@
# 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

126
m4/x11.m4
View file

@ -211,6 +211,11 @@ AC_DEFUN([X11_EXT_XKB],
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_DEFUN([X11_EXT_XKB],
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_DEFUN([X11_EXT_SHAPE],
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 @@ AC_DEFUN([X11_EXT_SHAPE],
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 @@ AC_DEFUN([X11_EXT_XINERAMA],
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
])

View file

@ -14,22 +14,24 @@ CPPFLAGS=$(X_CFLAGS) $(XFT_CFLAGS) $(GLIB_CFLAGS) $(GMODULE_CFLAGS) \
-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

View file

@ -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 @@ void client_set_list()
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 @@ void client_manage_all()
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 @@ void client_manage(Window window)
(!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 @@ void client_unmanage(Client *self)
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 @@ static void client_move_onscreen(Client *self)
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 @@ static void client_get_all(Client *self)
/* 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 @@ static void client_get_all(Client *self)
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 @@ void client_get_type(Client *self)
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 @@ void client_setup_decor_and_functions(Client *self)
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 @@ static void client_change_allowed_actions(Client *self)
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_wmhints(Client *self)
void client_update_title(Client *self)
{
GList *it;
guint32 nums;
guint i;
char *data = NULL;
g_free(self->title);
@ -1165,6 +1202,29 @@ void client_update_title(Client *self)
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 @@ void client_update_title(Client *self)
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 */
@ -1186,6 +1243,16 @@ void client_update_icon_title(Client *self)
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);
self->icon_title = data;
@ -1342,28 +1409,70 @@ static void client_change_state(Client *self)
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 @@ static void calc_recursive(Client *self, Client *orig, StackLayer l,
void client_calc_layer(Client *self)
{
StackLayer l;
gboolean f;
Client *orig;
orig = self;
@ -1397,25 +1505,7 @@ void client_calc_layer(Client *self)
}
}
/* 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)
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;
/* 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;
}
}
if (it != NULL) return;
}
}
if (self->iconic == iconic) return; /* nothing to do */
@ -1738,13 +1827,18 @@ void client_iconify(Client *self, gboolean iconic, gboolean curdesk)
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,25 +2035,19 @@ void client_set_desktop(Client *self, guint target, gboolean donthide)
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)
{
XEvent e;
@ -2118,7 +2206,7 @@ Client *client_focus_target(Client *self)
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;
}

View file

@ -112,6 +112,7 @@ typedef enum {
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 @@ typedef struct 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 @@ gboolean client_focused(Client *self);
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 @@ void client_kill(Client *self);
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 @@ void client_update_normal_hints(Client *self);
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 */
@ -464,4 +466,21 @@ 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

View file

@ -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;
@ -37,6 +38,12 @@ static void parse_focus(char *name, ParseToken *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");
parse_free_token(value);
@ -95,6 +102,7 @@ void config_startup()
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);

View file

@ -11,6 +11,8 @@ extern gboolean config_focus_follow;
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;

View file

@ -144,6 +144,9 @@ static Window event_get_window(XEvent *e)
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 @@ static gboolean event_ignore(XEvent *e, Client *client)
#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 @@ static void event_handle_root(XEvent *e)
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 @@ static void event_handle_client(Client *client, XEvent *e)
}
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 @@ static void event_handle_client(Client *client, XEvent *e)
client_setup_decor_and_functions(client);
}
else if (msgtype == prop_atoms.net_wm_name ||
msgtype == prop_atoms.wm_name)
client_update_title(client);
else if (msgtype == prop_atoms.net_wm_icon_name ||
msgtype == prop_atoms.wm_name ||
msgtype == prop_atoms.net_wm_icon_name ||
msgtype == prop_atoms.wm_icon_name)
client_update_icon_title(client);
client_update_title(client);
else if (msgtype == prop_atoms.wm_class)
client_update_class(client);
else if (msgtype == prop_atoms.wm_protocols) {

View file

@ -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()
{
@ -31,4 +34,16 @@ void extensions_query_all()
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
}

View file

@ -11,6 +11,12 @@
#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? */
@ -28,6 +34,16 @@ 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();
#endif

View file

@ -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 "focus.h"
#include "parse.h"
#include "stacking.h"
#include "popup.h"
#include <X11/Xlib.h>
#include <glib.h>
@ -23,6 +23,7 @@ GList **focus_order = NULL; /* these lists are created when screen_startup
Window focus_backup = None;
static Client *focus_cycle_target = NULL;
static Popup *focus_cycle_popup = NULL;
void focus_startup()
{
@ -32,6 +33,7 @@ void focus_startup()
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 @@ void focus_shutdown()
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 @@ void focus_set_client(Client *client)
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 @@ void focus_fallback(FallbackType type)
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 @@ void focus_fallback(FallbackType type)
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 @@ Client *focus_cycle(gboolean forward, gboolean linear, gboolean done,
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);

View file

@ -218,34 +218,3 @@ static void framerender_close(Frame *self, Appearance *a)
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;
}

View file

@ -5,7 +5,4 @@
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

View file

@ -76,6 +76,16 @@ void menu_startup()
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()

View file

@ -4,6 +4,7 @@
#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 Corner lockcorner;
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 @@ void moveresize_startup()
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 @@ void moveresize_end(gboolean cancel)
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 @@ static void do_move()
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 @@ static void do_resize()
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);
}

View file

@ -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);

View file

@ -166,7 +166,6 @@ int main(int argc, char **argv)
font_startup();
theme_startup();
event_startup();
moveresize_startup();
grab_startup();
plugin_startup();
/* load the plugins specified in the pluginrc */
@ -187,6 +186,7 @@ int main(int argc, char **argv)
menu_startup();
frame_startup();
stacking_startup();
moveresize_startup();
focus_startup();
screen_startup();
group_startup();
@ -210,6 +210,7 @@ int main(int argc, char **argv)
group_shutdown();
screen_shutdown();
focus_shutdown();
moveresize_shutdown();
stacking_shutdown();
frame_shutdown();
menu_shutdown();

View file

@ -11,7 +11,7 @@ typedef enum {
TOKEN_INTEGER = INTEGER,
TOKEN_STRING = STRING,
TOKEN_IDENTIFIER = IDENTIFIER,
TOKEN_BOOL = BOOL,
TOKEN_BOOL = BOOLEAN,
TOKEN_LIST,
TOKEN_LBRACE = '{',
TOKEN_RBRACE = '}',

View file

@ -31,7 +31,7 @@ bool ([tT][rR][uU][eE]|[fF][aA][lL][sS][eE]|[yY][eE][sS]|[nN][oO]|[oO][nN]|[oO][
{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; }

View file

@ -41,7 +41,7 @@ void parse_set_section(char *section);
%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 @@ token:
| 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 @@ listtoken:
| 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; }

View file

@ -7,6 +7,7 @@
#include "frame.h"
#include "focus.h"
#include "dispatch.h"
#include "extensions.h"
#include "../render/render.h"
#include <X11/Xlib.h>
@ -16,7 +17,7 @@
#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 @@ void screen_startup()
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 @@ void screen_shutdown()
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 @@ void screen_resize()
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)

View file

@ -43,7 +43,7 @@ void screen_startup();
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);

View file

@ -70,7 +70,7 @@ static GList *find_lowest_transient(Client *c)
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 @@ static void raise_recursive(Client *client)
/* 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;
}
/*

View file

@ -56,12 +56,15 @@ gboolean kbind(GList *keylist, Action *action)
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 @@ gboolean kbind(GList *keylist, Action *action)
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 @@ static void event(ObEvent *e, void *foo)
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 @@ static void event(ObEvent *e, void *foo)
}
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;
}
}
}

View file

@ -11,10 +11,13 @@ void tree_destroy(KeyBindingTree *tree)
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;

View file

@ -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;

View file

@ -96,9 +96,13 @@ static void clearall()
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 @@ static void fire_button(MouseAction a, Context context, Client *c, guint state,
/* 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 (b->action[a]->func == action_showmenu) {
b->action[a]->data.showmenu.x = x;
b->action[a]->data.showmenu.y = y;
if (act->func == action_showmenu) {
act->data.showmenu.x = x;
act->data.showmenu.y = y;
}
act->func(&act->data);
}
b->action[a]->func(&b->action[a]->data);
}
}
@ -148,24 +155,27 @@ static void fire_motion(MouseAction a, Context context, Client *c,
/* 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 @@ gboolean mbind(char *buttonstr, char *contextstr, MouseAction mact,
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 @@ gboolean mbind(char *buttonstr, char *contextstr, MouseAction mact,
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);

View file

@ -15,7 +15,7 @@ typedef enum {
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,

View file

@ -8,6 +8,10 @@
#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 @@ static void measure_height(ObFont *f)
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 @@ void font_draw(XftDraw *d, TextureText *t, Rect *position)
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 @@ void font_draw(XftDraw *d, TextureText *t, Rect *position)
}
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 @@ void font_draw(XftDraw *d, TextureText *t, Rect *position)
XftDrawStringUtf8(d, &c, t->font->xftfont, x,
t->font->xftfont->ascent + y,
(FcChar8*)text, l);
(FcChar8*)text->str, l);
return;
}

View file

@ -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;
/* 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 */
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);
target[t] = (r << default_red_shift) | (g << default_green_shift) |
(b << default_blue_shift);
}
}
/* 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];
/* 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;
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);
}
}
}

View file

@ -7,6 +7,7 @@
#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 pixel32_to_pixmap(pixel32 *in, Pixmap out, int x, int y, int w, int h)
void appearance_minsize(Appearance *l, int *w, int *h)
{
int i;
int m;
*w = *h = 1;
switch (l->surface.type) {
@ -437,20 +439,22 @@ void appearance_minsize(Appearance *l, int *w, int *h)
} 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 @@ void appearance_minsize(Appearance *l, int *w, int *h)
break;
case NoTexture:
break;
}
}
}
break;
}
}

View file

@ -79,6 +79,7 @@ typedef struct Surface {
typedef struct {
XftFont *xftfont;
int height;
int elipses_length;
} ObFont;
typedef enum {
@ -109,12 +110,12 @@ typedef struct TextureMask {
} 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;

View file

@ -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 @@ void theme_startup()
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 @@ void theme_shutdown()
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 @@ static gboolean read_mask(XrmDatabase db, char *rname, char *theme,
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 @@ static gboolean read_mask(XrmDatabase db, char *rname, char *theme,
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 @@ char *theme_load(char *theme)
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 @@ char *theme_load(char *theme)
/* 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 @@ char *theme_load(char *theme)
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 @@ char *theme_load(char *theme)
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 =

View file

@ -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();