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 */