better alt-tabbing. better transient handling. i dont even know. lots of fucking cool shit so WATCH the FUCK OUT.
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
#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:
# Check for X11 extensions
X11_EXT_XKB
+X11_EXT_XRANDR
+X11_EXT_VIDMODE
X11_EXT_SHAPE
X11_EXT_XINERAMA
plugins/Makefile
plugins/placement/Makefile
plugins/mouse/Makefile
- plugins/keyboard/Makefile])
+ plugins/keyboard/Makefile
+ tools/Makefile
+ tools/slit/Makefile])
AC_OUTPUT
AC_MSG_RESULT
# 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
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])
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.
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])
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
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
+])
-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
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; }
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;
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);
}
}
(!parent && (!self->group ||
!self->group->members->next)))))) ||
(parent && (client_focused(parent) ||
- search_focus_tree(parent, parent)))) {
+ client_search_focus_tree(parent)))) {
client_focus(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;
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);
/* 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;
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);
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)
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;
}
}
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;
void client_update_title(Client *self)
{
+ GList *it;
+ guint32 nums;
+ guint i;
char *data = NULL;
g_free(self->title);
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);
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 */
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;
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);
void client_calc_layer(Client *self)
{
StackLayer l;
- gboolean f;
Client *orig;
orig = 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);
}
{
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;
+ /* 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;
- if (c != self && c->transient_for->iconic != iconic &&
- c->transient_for != TRAN_GROUP) {
- self = it->data;
- break;
- }
+ /* 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) break;
}
+ if (it != NULL) return;
}
+ }
if (self->iconic == iconic) return; /* nothing to do */
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);
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;
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;
}
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 */
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;
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.
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
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 */
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
gboolean config_focus_follow;
gboolean config_focus_last;
gboolean config_focus_last_on_desktop;
+gboolean config_focus_popup;
char *config_theme;
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);
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);
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;
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) {
#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);
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
}
}
}
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)) {
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) {
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()
{
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
}
#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? */
/*! 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
#include "event.h"
#include "openbox.h"
-#include "grab.h"
#include "framerender.h"
#include "client.h"
#include "config.h"
#include "focus.h"
#include "parse.h"
#include "stacking.h"
+#include "popup.h"
#include <X11/Xlib.h>
#include <glib.h>
Window focus_backup = None;
static Client *focus_cycle_target = NULL;
+static Popup *focus_cycle_popup = NULL;
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,
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 */
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);
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 */
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);
-
- 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);
+ 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);
+
+ /* 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));
}
}
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);
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;
-}
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
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()
#include "client.h"
#include "dispatch.h"
#include "openbox.h"
+#include "popup.h"
#include <X11/Xlib.h>
#include <glib.h>
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;
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)
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);
}
grab_keyboard(FALSE);
grab_pointer(FALSE, None);
- XDestroyWindow(ob_display, coords);
- coords = None;
+ popup_hide(popup);
if (moving) {
client_configure(moveresize_client, Corner_TopLeft,
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);
}
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);
}
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);
font_startup();
theme_startup();
event_startup();
- moveresize_startup();
grab_startup();
plugin_startup();
/* load the plugins specified in the pluginrc */
menu_startup();
frame_startup();
stacking_startup();
+ moveresize_startup();
focus_startup();
screen_startup();
group_startup();
group_shutdown();
screen_shutdown();
focus_shutdown();
+ moveresize_shutdown();
stacking_shutdown();
frame_shutdown();
menu_shutdown();
TOKEN_INTEGER = INTEGER,
TOKEN_STRING = STRING,
TOKEN_IDENTIFIER = IDENTIFIER,
- TOKEN_BOOL = BOOL,
+ TOKEN_BOOL = BOOLEAN,
TOKEN_LIST,
TOKEN_LBRACE = '{',
TOKEN_RBRACE = '}',
{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; }
%token <integer> INTEGER
%token <string> STRING
%token <identifier> IDENTIFIER
-%token <bool> BOOL
+%token <bool> BOOLEAN
%token <character> '('
%token <character> ')'
%token <character> '{'
| 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; }
| 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; }
#include "frame.h"
#include "focus.h"
#include "dispatch.h"
+#include "extensions.h"
#include "../render/render.h"
#include <X11/Xlib.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)
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*,
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];
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)
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);
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 */
/* 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;
}
/*
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);
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);
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)
}
curpos = p;
} else {
- if (p->action->func != NULL) {
- p->action->data.any.c = focus_client;
-
- if (p->action->func == action_cycle_windows) {
- p->action->data.cycle.final = FALSE;
- p->action->data.cycle.cancel = FALSE;
- }
-
- p->action->func(&p->action->data);
-
- if (p->action->func == action_cycle_windows &&
- !grabbed_key) {
- grab_keyboard(TRUE);
- grabbed_key = p;
+ 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 (act->func == action_cycle_windows) {
+ act->data.cycle.final = FALSE;
+ act->data.cycle.cancel = FALSE;
+ }
+
+ act->func(&act->data);
+
+ if (act->func == action_cycle_windows &&
+ !grabbed_key) {
+ grab_keyboard(TRUE);
+ grabbed_key = p;
+ }
}
}
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;
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;
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]);
/* 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;
+ }
- b->action[a]->func(&b->action[a]->data);
+ act->func(&act->data);
+ }
}
}
/* 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;
-
- 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();
+ for (it = b->actions[a]; it; it = it->next) {
+ Action *act = it->data;
+ if (act->func != NULL) {
+ act->data.any.c = c;
+
+ 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);
+ }
}
}
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;
}
}
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);
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,
#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
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)
{
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;
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;
}
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;
XftDrawStringUtf8(d, &c, t->font->xftfont, x,
t->font->xftfont->ascent + y,
- (FcChar8*)text, l);
+ (FcChar8*)text->str, l);
return;
}
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;
-/* do we use the cache we may have just created, or the original? */
- if (rgba->width != sfw || rgba->height != sfh)
- draw = rgba->cache;
+ alpha = draw[i] >> 24;
+ r = draw[i] >> 16;
+ g = draw[i] >> 8;
+ b = draw[i];
- /* 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];
+ 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);
+ }
}
- }
}
#include "mask.h"
#include "color.h"
#include "image.h"
+#include "theme.h"
#include "kernel/openbox.h"
#ifdef HAVE_STDLIB_H
void appearance_minsize(Appearance *l, int *w, int *h)
{
int i;
+ int m;
*w = *h = 1;
switch (l->surface.type) {
} 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;
break;
case NoTexture:
break;
- }
+ }
+ }
break;
}
}
typedef struct {
XftFont *xftfont;
int height;
+ int elipses_length;
} ObFont;
typedef enum {
} 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;
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()
{
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);
}
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)
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);
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) ==
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",
/* 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 =
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 =
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 =
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();