diff --git a/awesomerc.5.txt b/awesomerc.5.txt
index 1af42c91c..f9fed8563 100644
--- a/awesomerc.5.txt
+++ b/awesomerc.5.txt
@@ -44,6 +44,8 @@ general
^^^^^^^
General is a section containing some general options for this screen.
+titlebar::
+ This option defines the position of window titlebar.
border::
This defines the window borders size in pixel.
font::
diff --git a/client.c b/client.c
index 165f48a3d..3149429dd 100644
--- a/client.c
+++ b/client.c
@@ -132,6 +132,39 @@ client_get_byname(Client *list, char *name)
return NULL;
}
+static void
+client_updatetitlebar(Client *c)
+{
+ DrawCtx *ctx;
+ int phys_screen;
+ style_t style;
+ area_t geometry;
+
+ if(!c->titlebar)
+ return;
+
+ phys_screen = get_phys_screen(c->screen);
+
+ ctx = draw_context_new(globalconf.display, phys_screen,
+ c->titlebar->geometry.width,
+ c->titlebar->geometry.height,
+ c->titlebar->drawable);
+
+ style = globalconf.focus->client == c ?
+ globalconf.screens[c->screen].styles.focus :
+ globalconf.screens[c->screen].styles.normal;
+
+ geometry = c->titlebar->geometry;
+ geometry.x = geometry.y = 0;
+
+ draw_text(ctx, geometry, AlignCenter, 0,
+ c->name, style);
+
+ simplewindow_refresh_drawable(c->titlebar, phys_screen);
+
+ draw_context_delete(ctx);
+}
+
/** Update client name attribute with its title
* \param c the client
*/
@@ -143,6 +176,8 @@ client_updatetitle(Client *c)
xgettextprop(globalconf.display, c->win,
XInternAtom(globalconf.display, "WM_NAME", False), c->name, sizeof(c->name));
+ client_updatetitlebar(c);
+
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
}
@@ -151,10 +186,11 @@ client_unfocus(Client *c)
{
if(globalconf.screens[c->screen].opacity_unfocused != -1)
window_settrans(c->win, globalconf.screens[c->screen].opacity_unfocused);
+ focus_add_client(NULL);
XSetWindowBorder(globalconf.display, c->win,
globalconf.screens[c->screen].styles.normal.border.pixel);
widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
- focus_add_client(NULL);
+ client_updatetitlebar(c);
}
/** Ban client and unmap it
@@ -167,6 +203,8 @@ client_ban(Client *c)
client_unfocus(c);
XUnmapWindow(globalconf.display, c->win);
window_setstate(c->win, IconicState);
+ if(c->titlebar)
+ XUnmapWindow(globalconf.display, c->titlebar->window);
}
/** Give focus to client, or to first client if c is NULL
@@ -201,13 +239,18 @@ client_focus(Client *c, int screen, Bool raise)
window_settrans(c->win, -1);
XSetWindowBorder(globalconf.display, c->win,
globalconf.screens[screen].styles.focus.border.pixel);
+ client_updatetitlebar(c);
XSetInputFocus(globalconf.display, c->win, RevertToPointerRoot, CurrentTime);
if(raise)
{
XWindowChanges wc;
Layout *curlay = layout_get_current(screen);
if(c->isfloating || curlay->arrange == layout_floating)
+ {
XRaiseWindow(globalconf.display, c->win);
+ if(c->titlebar)
+ XRaiseWindow(globalconf.display, c->titlebar->window);
+ }
else
{
Client *client;
@@ -216,14 +259,32 @@ client_focus(Client *c, int screen, Bool raise)
for(client = globalconf.clients; client; client = client->next)
if(client != c && client_isvisible(client, c->screen) && client->isfloating)
{
+ if(client->titlebar)
+ {
+ XConfigureWindow(globalconf.display, client->titlebar->window,
+ CWSibling | CWStackMode, &wc);
+ wc.sibling = client->titlebar->window;
+ }
XConfigureWindow(globalconf.display, client->win, CWSibling | CWStackMode, &wc);
wc.sibling = client->win;
}
+ if(c->titlebar)
+ {
+ XConfigureWindow(globalconf.display, c->titlebar->window,
+ CWSibling | CWStackMode, &wc);
+ wc.sibling = c->titlebar->window;
+ }
XConfigureWindow(globalconf.display, c->win, CWSibling | CWStackMode, &wc);
wc.sibling = c->win;
for(client = globalconf.clients; client; client = client->next)
if(client != c && IS_TILED(client, c->screen))
{
+ if(client->titlebar)
+ {
+ XConfigureWindow(globalconf.display, client->titlebar->window,
+ CWSibling | CWStackMode, &wc);
+ wc.sibling = client->titlebar->window;
+ }
XConfigureWindow(globalconf.display, client->win, CWSibling | CWStackMode, &wc);
wc.sibling = client->win;
}
@@ -257,7 +318,7 @@ client_manage(Window w, XWindowAttributes *wa, int screen)
Tag *tag;
Rule *rule;
area_t screen_geom;
- int phys_screen = get_phys_screen(screen);
+ int phys_screen = get_phys_screen(screen), titlebar_height;
long flags;
c = p_new(Client, 1);
@@ -286,6 +347,23 @@ client_manage(Window w, XWindowAttributes *wa, int screen)
/* propagates border_width, if size doesn't change */
window_configure(c->win, c->geometry, c->border);
+ switch(globalconf.screens[c->screen].titlebar)
+ {
+ case Top:
+ titlebar_height = 1.5 * MAX(globalconf.screens[c->screen].styles.normal.font->height,
+ MAX(globalconf.screens[c->screen].styles.focus.font->height,
+ globalconf.screens[c->screen].styles.urgent.font->height)),
+ c->titlebar = simplewindow_new(globalconf.display,
+ phys_screen,
+ c->geometry.x,
+ c->geometry.y - titlebar_height,
+ c->geometry.width,
+ titlebar_height,
+ 0);
+ break;
+ default:
+ break;
+ }
/* update window title */
client_updatetitle(c);
@@ -387,6 +465,53 @@ client_manage(Window w, XWindowAttributes *wa, int screen)
ewmh_update_net_client_list(phys_screen);
}
+static area_t
+client_geometry_sizehint(Client *c, area_t geometry)
+{
+ double dx, dy, max, min, ratio;
+
+ if(c->minay > 0 && c->maxay > 0 && (geometry.height - c->baseh) > 0
+ && (geometry.width - c->basew) > 0)
+ {
+ dx = (double) (geometry.width - c->basew);
+ dy = (double) (geometry.height - c->baseh);
+ min = (double) (c->minax) / (double) (c->minay);
+ max = (double) (c->maxax) / (double) (c->maxay);
+ ratio = dx / dy;
+ if(max > 0 && min > 0 && ratio > 0)
+ {
+ if(ratio < min)
+ {
+ dy = (dx * min + dy) / (min * min + 1);
+ dx = dy * min;
+ geometry.width = (int) dx + c->basew;
+ geometry.height = (int) dy + c->baseh;
+ }
+ else if(ratio > max)
+ {
+ dy = (dx * min + dy) / (max * max + 1);
+ dx = dy * min;
+ geometry.width = (int) dx + c->basew;
+ geometry.height = (int) dy + c->baseh;
+ }
+ }
+ }
+ if(c->minw && geometry.width < c->minw)
+ geometry.width = c->minw;
+ if(c->minh && geometry.height < c->minh)
+ geometry.height = c->minh;
+ if(c->maxw && geometry.width > c->maxw)
+ geometry.width = c->maxw;
+ if(c->maxh && geometry.height > c->maxh)
+ geometry.height = c->maxh;
+ if(c->incw)
+ geometry.width -= (geometry.width - c->basew) % c->incw;
+ if(c->inch)
+ geometry.height -= (geometry.height - c->baseh) % c->inch;
+
+ return geometry;
+}
+
/** Resize client window
* \param c client to resize
* \param geometry new window geometry
@@ -397,53 +522,21 @@ Bool
client_resize(Client *c, area_t geometry, Bool sizehints)
{
int new_screen;
- double dx, dy, max, min, ratio;
area_t area;
XWindowChanges wc;
- if(sizehints)
+ if(c->titlebar)
{
- if(c->minay > 0 && c->maxay > 0 && (geometry.height - c->baseh) > 0
- && (geometry.width - c->basew) > 0)
- {
- dx = (double) (geometry.width - c->basew);
- dy = (double) (geometry.height - c->baseh);
- min = (double) (c->minax) / (double) (c->minay);
- max = (double) (c->maxax) / (double) (c->maxay);
- ratio = dx / dy;
- if(max > 0 && min > 0 && ratio > 0)
- {
- if(ratio < min)
- {
- dy = (dx * min + dy) / (min * min + 1);
- dx = dy * min;
- geometry.width = (int) dx + c->basew;
- geometry.height = (int) dy + c->baseh;
- }
- else if(ratio > max)
- {
- dy = (dx * min + dy) / (max * max + 1);
- dx = dy * min;
- geometry.width = (int) dx + c->basew;
- geometry.height = (int) dy + c->baseh;
- }
- }
- }
- if(c->minw && geometry.width < c->minw)
- geometry.width = c->minw;
- if(c->minh && geometry.height < c->minh)
- geometry.height = c->minh;
- if(c->maxw && geometry.width > c->maxw)
- geometry.width = c->maxw;
- if(c->maxh && geometry.height > c->maxh)
- geometry.height = c->maxh;
- if(c->incw)
- geometry.width -= (geometry.width - c->basew) % c->incw;
- if(c->inch)
- geometry.height -= (geometry.height - c->baseh) % c->inch;
+ geometry.y += c->titlebar->geometry.height;
+ geometry.height -= c->titlebar->geometry.height;
}
+
+ if(sizehints)
+ geometry = client_geometry_sizehint(c, geometry);
+
if(geometry.width <= 0 || geometry.height <= 0)
return False;
+
/* offscreen appearance fixes */
area = get_display_area(get_phys_screen(c->screen),
NULL,
@@ -463,10 +556,22 @@ client_resize(Client *c, area_t geometry, Bool sizehints)
new_screen = screen_get_bycoord(globalconf.screens_info, c->screen, geometry.x, geometry.y);
c->geometry.x = wc.x = geometry.x;
- c->geometry.y = wc.y = geometry.y;
c->geometry.width = wc.width = geometry.width;
+ c->geometry.y = wc.y = geometry.y;
c->geometry.height = wc.height = geometry.height;
- wc.border_width = c->border;
+
+ if(c->titlebar)
+ {
+ simplewindow_move_resize(c->titlebar,
+ geometry.x,
+ geometry.y - c->titlebar->geometry.height,
+ geometry.width,
+ c->titlebar->geometry.height);
+ client_updatetitlebar(c);
+
+ c->geometry.y -= c->titlebar->geometry.height;
+ c->geometry.height += c->titlebar->geometry.height;
+ }
/* save the floating geometry if the window is floating but not
* maximized */
@@ -474,8 +579,10 @@ client_resize(Client *c, area_t geometry, Bool sizehints)
layout_get_current(new_screen)->arrange == layout_floating) && !c->ismax)
c->f_geometry = geometry;
+ printf("moving client %s to %d\n", c->name, c->geometry.y);
+
XConfigureWindow(globalconf.display, c->win,
- CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
+ CWX | CWY | CWWidth | CWHeight, &wc);
window_configure(c->win, geometry, c->border);
if(c->screen != new_screen)
@@ -547,6 +654,8 @@ client_unban(Client *c)
{
XMapWindow(globalconf.display, c->win);
window_setstate(c->win, NormalState);
+ if(c->titlebar)
+ XMapWindow(globalconf.display, c->titlebar->window);
}
void
@@ -579,6 +688,9 @@ client_unmanage(Client *c)
XSync(globalconf.display, False);
XUngrabServer(globalconf.display);
+ if(c->titlebar)
+ simplewindow_delete(c->titlebar);
+
p_delete(&c);
}
diff --git a/common/configopts.c b/common/configopts.c
index a0107674a..5d68afe1a 100644
--- a/common/configopts.c
+++ b/common/configopts.c
@@ -70,6 +70,7 @@ cfg_awesome_include(cfg_t *cfg, cfg_opt_t *opt,
cfg_opt_t general_opts[] =
{
CFG_INT((char *) "border", 1, CFGF_NONE),
+ CFG_STR((char *) "titlebar", (char *) "off", CFGF_NONE),
CFG_INT((char *) "snap", 8, CFGF_NONE),
CFG_BOOL((char *) "resize_hints", cfg_true, CFGF_NONE),
CFG_BOOL((char *) "sloppy_focus", cfg_true, CFGF_NONE),
diff --git a/common/util.c b/common/util.c
index 7eff4fb9e..d09e1f7a7 100644
--- a/common/util.c
+++ b/common/util.c
@@ -96,6 +96,20 @@ name_func_lookup(const char *funcname, const name_func_link_t *list)
return NULL;
}
+Position
+position_get_from_str(const char *pos)
+{
+ if(!a_strncmp(pos, "top", 3))
+ return Top;
+ else if(!a_strncmp(pos, "bottom", 6))
+ return Bottom;
+ else if(!a_strncmp(pos, "right", 5))
+ return Right;
+ else if(!a_strncmp(pos, "left", 4))
+ return Left;
+ return Off;
+}
+
/** \brief safe limited strcpy.
*
* Copies at most min(n-1, \c l) characters from \c src into \c dst,
diff --git a/common/util.h b/common/util.h
index cba63238b..93220853d 100644
--- a/common/util.h
+++ b/common/util.h
@@ -26,6 +26,16 @@
#include
#include
+/** A list of possible position, not sex related */
+typedef enum
+{
+ Off = 0,
+ Top,
+ Bottom,
+ Right,
+ Left
+} Position;
+
/** Link a name to a function */
typedef struct
{
@@ -228,6 +238,7 @@ void _eprint(int, const char *, const char *, ...)
void _warn(int, const char *, const char *, ...)
__attribute__ ((format(printf, 3, 4)));
+Position position_get_from_str(const char *);
double compute_new_value_from_arg(const char *, double);
void *name_func_lookup(const char *, const name_func_link_t *);
diff --git a/config.c b/config.c
index 369f42190..46661b34a 100644
--- a/config.c
+++ b/config.c
@@ -319,6 +319,7 @@ config_parse_screen(cfg_t *cfg, int screen)
virtscreen->floating_placement =
name_func_lookup(cfg_getstr(cfg_general, "floating_placement"),
FloatingPlacementList);
+ virtscreen->titlebar = position_get_from_str(cfg_getstr(cfg_general, "titlebar"));
virtscreen->mwfact_lower_limit = cfg_getfloat(cfg_general, "mwfact_lower_limit");
virtscreen->mwfact_upper_limit = cfg_getfloat(cfg_general, "mwfact_upper_limit");
@@ -378,7 +379,7 @@ config_parse_screen(cfg_t *cfg, int screen)
statusbar = p_new(Statusbar, 1);
cfgsectmp = cfg_getnsec(cfg_screen, "statusbar", i);
statusbar->position = statusbar->dposition =
- statusbar_get_position_from_str(cfg_getstr(cfgsectmp, "position"));
+ position_get_from_str(cfg_getstr(cfgsectmp, "position"));
statusbar->height = cfg_getint(cfgsectmp, "height");
statusbar->width = cfg_getint(cfgsectmp, "width");
statusbar->name = a_strdup(cfg_title(cfgsectmp));
diff --git a/event.c b/event.c
index 254248216..46d67ce85 100644
--- a/event.c
+++ b/event.c
@@ -289,8 +289,10 @@ event_handle_expose(XEvent *e)
XExposeEvent *ev = &e->xexpose;
int screen;
Statusbar *statusbar;
+ Client *c;
if(!ev->count)
+ {
for(screen = 0; screen < globalconf.screens_info->nscreen; screen++)
for(statusbar = globalconf.screens[screen].statusbar; statusbar; statusbar = statusbar->next)
if(statusbar->sw->window == ev->window)
@@ -298,6 +300,14 @@ event_handle_expose(XEvent *e)
statusbar_display(statusbar);
return;
}
+
+ for(c = globalconf.clients; c; c = c->next)
+ if(c->titlebar && c->titlebar->window == ev->window)
+ {
+ simplewindow_refresh_drawable(c->titlebar, get_phys_screen(c->screen));
+ return;
+ }
+ }
}
/** Handle XKey events
diff --git a/statusbar.c b/statusbar.c
index b45dce31b..fabb411ef 100644
--- a/statusbar.c
+++ b/statusbar.c
@@ -244,20 +244,6 @@ statusbar_refresh()
}
}
-Position
-statusbar_get_position_from_str(const char *pos)
-{
- if(!a_strncmp(pos, "off", 3))
- return Off;
- else if(!a_strncmp(pos, "bottom", 6))
- return Bottom;
- else if(!a_strncmp(pos, "right", 5))
- return Right;
- else if(!a_strncmp(pos, "left", 4))
- return Left;
- return Top;
-}
-
static Statusbar *
get_statusbar_byname(int screen, const char *name)
{
diff --git a/statusbar.h b/statusbar.h
index b0841c9d4..b0759d6a1 100644
--- a/statusbar.h
+++ b/statusbar.h
@@ -28,7 +28,6 @@ void statusbar_refresh(void);
void statusbar_preinit(Statusbar *);
void statusbar_init(Statusbar *);
void statusbar_display(Statusbar *);
-Position statusbar_get_position_from_str(const char *);
Uicb uicb_statusbar_toggle;
diff --git a/structs.h b/structs.h
index 385c49409..1c3a6d229 100644
--- a/structs.h
+++ b/structs.h
@@ -28,16 +28,6 @@
#include "common/swindow.h"
#include "common/xscreen.h"
-/** Bar possible position */
-typedef enum
-{
- Top,
- Bottom,
- Left,
- Right,
- Off
-} Position;
-
/** Rules for floating rule */
typedef enum
{
@@ -200,6 +190,8 @@ struct Client
int screen;
/** True if the client is a new one */
Bool newcomer;
+ /** Titlebar */
+ SimpleWindow *titlebar;
};
typedef struct client_node_t client_node_t;
@@ -260,6 +252,8 @@ typedef struct
typedef area_t (FloatingPlacement)(area_t, int, int);
typedef struct
{
+ /** Titlebar position */
+ Position titlebar;
/** Number of pixels to snap windows */
int snap;
/** Border size */