diff --git a/client.c b/client.c index 1a86587f..0e0547df 100644 --- a/client.c +++ b/client.c @@ -198,7 +198,7 @@ client_updatetitle(client_t *c) luaA_client_userdata_new(c); luaA_dofunction(globalconf.L, globalconf.hooks.titleupdate, 1); - titlebar_draw(c); + titlebar_draw(titlebar_getbyclient(c)); widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS); } @@ -211,7 +211,7 @@ client_unfocus(client_t *c) focus_client_push(NULL); widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS); - titlebar_draw(c); + titlebar_draw(titlebar_getbyclient(c)); } /** Ban client and unmap it @@ -220,12 +220,14 @@ client_unfocus(client_t *c) void client_ban(client_t *c) { + titlebar_t *titlebar = titlebar_getbyclient(c); + if(globalconf.focus->client == c) client_unfocus(c); xcb_unmap_window(globalconf.connection, c->win); window_setstate(c->win, XCB_WM_ICONIC_STATE); - if(c->titlebar.position && c->titlebar_sw) - xcb_unmap_window(globalconf.connection, c->titlebar_sw->window); + if(titlebar && titlebar->position && titlebar->sw) + xcb_unmap_window(globalconf.connection, titlebar->sw->window); } /** Give focus to client, or to first client if c is NULL @@ -254,7 +256,7 @@ client_focus(client_t *c, int screen) client_unban(c); /* save sel in focus history */ focus_client_push(c); - titlebar_draw(c); + titlebar_draw(titlebar_getbyclient(c)); xcb_set_input_focus(globalconf.connection, XCB_INPUT_FOCUS_POINTER_ROOT, c->win, XCB_CURRENT_TIME); /* since we're dropping EnterWindow events and sometimes the window @@ -295,6 +297,7 @@ client_raise(client_t *c) uint32_t config_win_vals[2]; client_node_t *node; layer_t layer; + titlebar_t *titlebar; config_win_vals[0] = XCB_NONE; config_win_vals[1] = XCB_STACK_MODE_BELOW; @@ -306,13 +309,15 @@ client_raise(client_t *c) if(node->client->layer == layer && client_isvisible_anyscreen(node->client)) { - if(node->client->titlebar.position && node->client->titlebar_sw) + if((titlebar = titlebar_getbyclient(node->client)) + && titlebar->position + && titlebar->sw) { xcb_configure_window(globalconf.connection, - node->client->titlebar_sw->window, + titlebar->sw->window, XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, config_win_vals); - config_win_vals[0] = node->client->titlebar_sw->window; + config_win_vals[0] = titlebar->sw->window; } xcb_configure_window(globalconf.connection, node->client->win, XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, @@ -484,11 +489,14 @@ client_resize(client_t *c, area_t geometry, bool hints) /* Values to configure a window is an array where values are * stored according to 'value_mask' */ uint32_t values[5]; + titlebar_t *titlebar; - if(!c->ismoving && !c->isfloating && layout != layout_floating) + titlebar = titlebar_getbyclient(c); + + if(titlebar && !c->ismoving && !c->isfloating && layout != layout_floating) { - titlebar_update_geometry(c, geometry); - geometry = titlebar_geometry_remove(&c->titlebar, geometry); + titlebar_update_geometry(titlebar, geometry); + geometry = titlebar_geometry_remove(titlebar, geometry); } if(hints) @@ -527,7 +535,7 @@ client_resize(client_t *c, area_t geometry, bool hints) if(c->ismoving || c->isfloating || layout_get_current(new_screen) == layout_floating) { - titlebar_update_geometry_floating(c); + titlebar_update_geometry_floating(titlebar); if(!c->ismax) c->f_geometry = geometry; } @@ -548,7 +556,7 @@ client_resize(client_t *c, area_t geometry, bool hints) /* call it again like it was floating, * we want it to be sticked to the window */ if(!c->ismoving && !c->isfloating && layout != layout_floating) - titlebar_update_geometry_floating(c); + titlebar_update_geometry_floating(titlebar); return resized; } @@ -619,16 +627,18 @@ client_saveprops(client_t *c) void client_unban(client_t *c) { + titlebar_t *titlebar = titlebar_getbyclient(c); xcb_map_window(globalconf.connection, c->win); window_setstate(c->win, XCB_WM_NORMAL_STATE); - if(c->titlebar_sw && c->titlebar.position != Off) - xcb_map_window(globalconf.connection, c->titlebar_sw->window); + if(titlebar && titlebar->sw && titlebar->position != Off) + xcb_map_window(globalconf.connection, titlebar->sw->window); } void client_unmanage(client_t *c) { tag_t *tag; + titlebar_t *titlebar; /* The server grab construct avoids race conditions. */ xcb_grab_server(globalconf.connection); @@ -653,7 +663,12 @@ client_unmanage(client_t *c) xcb_aux_sync(globalconf.connection); xcb_ungrab_server(globalconf.connection); - simplewindow_delete(&c->titlebar_sw); + if((titlebar = titlebar_getbyclient(c))) + { + simplewindow_delete(&titlebar->sw); + titlebar_list_detach(&globalconf.titlebar, titlebar); + titlebar_unref(&titlebar); + } p_delete(&c); } @@ -669,7 +684,7 @@ client_updatewmhints(client_t *c) if((c->isurgent = (wm_hints_flags & XCB_WM_X_URGENCY_HINT))) { widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS); - titlebar_draw(c); + titlebar_draw(titlebar_getbyclient(c)); /* execute hook */ luaA_client_userdata_new(c); luaA_dofunction(globalconf.L, globalconf.hooks.urgent, 1); @@ -909,24 +924,6 @@ luaA_client_border_set(lua_State *L) return 0; } -static int -luaA_client_titlebar_set(lua_State *L) -{ - client_t **c = luaL_checkudata(L, 1, "client"); - titlebar_t **t = luaL_checkudata(L, 2, "titlebar"); - - /* Copy titlebar info */ - (*c)->titlebar = **t; - titlebar_init(*c); - - if((*c)->isfloating || layout_get_current((*c)->screen) == layout_floating) - titlebar_update_geometry_floating(*c); - else - globalconf.screens[(*c)->screen].need_arrange = true; - - return 0; -} - static int luaA_client_screen_set(lua_State *L) { @@ -1161,7 +1158,6 @@ const struct luaL_reg awesome_client_meta[] = { { "name_get", luaA_client_name_get }, { "name_set", luaA_client_name_set }, - { "titlebar_set", luaA_client_titlebar_set }, { "screen_set", luaA_client_screen_set }, { "screen_get", luaA_client_screen_get }, { "border_set", luaA_client_border_set }, diff --git a/event.c b/event.c index 5f93884a..671c55b0 100644 --- a/event.c +++ b/event.c @@ -81,6 +81,7 @@ event_handle_buttonpress(void *data __attribute__ ((unused)), client_t *c; widget_node_t *w; statusbar_t *statusbar; + titlebar_t *titlebar; for(screen = 0; screen < globalconf.screens_info->nscreen; screen++) for(statusbar = globalconf.screens[screen].statusbar; statusbar; statusbar = statusbar->next) @@ -122,14 +123,35 @@ event_handle_buttonpress(void *data __attribute__ ((unused)), return 0; } - /* Check for titlebar first */ - for(c = globalconf.clients; c; c = c->next) - if(c->titlebar_sw && c->titlebar_sw->window == ev->event) + if((titlebar = titlebar_getbywin(ev->event))) + { + /* Need to transform coordinates like it was + * top/bottom */ + switch(titlebar->position) { - event_handle_mouse_button_press(c, ev->detail, ev->state, - globalconf.buttons.titlebar); - return 0; + case Right: + tmp = ev->event_y; + ev->event_y = titlebar->height - ev->event_x; + ev->event_x = tmp; + break; + case Left: + tmp = ev->event_y; + ev->event_y = ev->event_x; + ev->event_x = titlebar->width - tmp; + break; + default: + break; } + for(w = titlebar->widgets; w; w = w->next) + if(ev->event_x >= w->area.x && ev->event_x < w->area.x + w->area.width + && ev->event_y >= w->area.y && ev->event_y < w->area.y + w->area.height) + { + w->widget->button_press(w, ev, titlebar->client->screen, titlebar); + return 0; + } + /* return if no widget match */ + return 0; + } if((c = client_get_bywin(globalconf.clients, ev->event))) { @@ -188,7 +210,7 @@ event_handle_configurerequest(void *data __attribute__ ((unused)), } else { - titlebar_update_geometry_floating(c); + titlebar_update_geometry_floating(titlebar_getbyclient(c)); window_configure(c->win, geometry, c->border); } } @@ -288,16 +310,16 @@ event_handle_enternotify(void *data __attribute__ ((unused)), xcb_connection_t *connection __attribute__ ((unused)), xcb_enter_notify_event_t *ev) { - client_t *c; + client_t *c = NULL; + titlebar_t *t; if(ev->mode != XCB_NOTIFY_MODE_NORMAL || (ev->root_x == globalconf.pointer_x && ev->root_y == globalconf.pointer_y)) return 0; - for(c = globalconf.clients; c; c = c->next) - if(c->titlebar_sw && c->titlebar_sw->window == ev->event) - break; + if((t = titlebar_getbywin(ev->event))) + c = t->client; if(c || (c = client_get_bywin(globalconf.clients, ev->event))) { @@ -327,7 +349,7 @@ event_handle_expose(void *data __attribute__ ((unused)), { int screen; statusbar_t *statusbar; - client_t *c; + titlebar_t *t; if(!ev->count) { @@ -340,12 +362,8 @@ event_handle_expose(void *data __attribute__ ((unused)), return 0; } - for(c = globalconf.clients; c; c = c->next) - if(c->titlebar_sw && c->titlebar_sw->window == ev->window) - { - simplewindow_refresh_drawable(c->titlebar_sw); - return 0; - } + if((t = titlebar_getbywin(ev->window))) + simplewindow_refresh_drawable(t->sw); } return 0; diff --git a/ewmh.c b/ewmh.c index 5cd08533..4b84b85b 100644 --- a/ewmh.c +++ b/ewmh.c @@ -253,6 +253,7 @@ static void ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set) { const uint32_t raise_window_val = XCB_STACK_MODE_ABOVE; + titlebar_t *titlebar; if(state == net_wm_state_sticky) { @@ -281,10 +282,11 @@ ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set) /* restore geometry */ geometry = c->m_geometry; /* restore borders and titlebar */ - if((c->titlebar.position = c->titlebar_oldposition)) + if((titlebar = titlebar_getbyclient(c)) + && (titlebar->position = titlebar->oldposition)) { - c->titlebar.position = c->titlebar_oldposition; - xcb_map_window(globalconf.connection, c->titlebar_sw->window); + titlebar->position = titlebar->oldposition; + xcb_map_window(globalconf.connection, titlebar->sw->window); } c->noborder = false; c->ismax = false; @@ -298,10 +300,11 @@ ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set) c->m_geometry = c->geometry; c->wasfloating = c->isfloating; /* disable titlebar and borders */ - if((c->titlebar_oldposition = c->titlebar.position)) + if((titlebar = titlebar_getbyclient(c)) + && (titlebar->oldposition = titlebar->position)) { - xcb_unmap_window(globalconf.connection, c->titlebar_sw->window); - c->titlebar.position = Off; + xcb_unmap_window(globalconf.connection, titlebar->sw->window); + titlebar->position = Off; } c->ismax = true; c->oldborder = c->border; @@ -343,6 +346,8 @@ ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set) static void ewmh_process_window_type_atom(client_t *c, xcb_atom_t state) { + titlebar_t *titlebar; + if(state == net_wm_window_type_normal) { /* do nothing. this is REALLY IMPORTANT */ @@ -352,10 +357,11 @@ ewmh_process_window_type_atom(client_t *c, xcb_atom_t state) { c->skip = true; c->isfixed = true; - if(c->titlebar.position) + if((titlebar = titlebar_getbyclient(c)) + && titlebar->position && titlebar->sw) { - xcb_unmap_window(globalconf.connection, c->titlebar_sw->window); - c->titlebar.position = Off; + xcb_unmap_window(globalconf.connection, titlebar->sw->window); + titlebar->position = Off; } client_setborder(c, 0); c->noborder = true; diff --git a/mouse.c b/mouse.c index c8c194cd..73eee665 100644 --- a/mouse.c +++ b/mouse.c @@ -97,13 +97,14 @@ static area_t mouse_snapclient(client_t *c, area_t geometry, int snap) { client_t *snapper; + titlebar_t *t = titlebar_getbyclient(c); area_t snapper_geometry; area_t screen_geometry = screen_get_area(c->screen, globalconf.screens[c->screen].statusbar, &globalconf.screens[c->screen].padding); - geometry = titlebar_geometry_add(&c->titlebar, geometry); + geometry = titlebar_geometry_add(t, geometry); geometry.width += 2 * c->border; geometry.height += 2 * c->border; @@ -116,7 +117,7 @@ mouse_snapclient(client_t *c, area_t geometry, int snap) snapper_geometry = snapper->geometry; snapper_geometry.width += 2 * c->border; snapper_geometry.height += 2 * c->border; - snapper_geometry = titlebar_geometry_add(&snapper->titlebar, snapper_geometry); + snapper_geometry = titlebar_geometry_add(t, snapper_geometry); geometry = mouse_snapclienttogeometry_outside(geometry, snapper_geometry, @@ -125,7 +126,7 @@ mouse_snapclient(client_t *c, area_t geometry, int snap) geometry.width -= 2 * c->border; geometry.height -= 2 * c->border; - return titlebar_geometry_remove(&c->titlebar, geometry); + return titlebar_geometry_remove(t, geometry); } /** Redraw the resizebar. diff --git a/placement.c b/placement.c index c6b34ec5..bfa90140 100644 --- a/placement.c +++ b/placement.c @@ -73,6 +73,7 @@ placement_smart(client_t *c) area_t *screen_geometry, *arealist = NULL, *r; bool found = false; layout_t *layout; + titlebar_t *titlebar = titlebar_getbyclient(c); screen_geometry = p_new(area_t, 1); @@ -91,7 +92,7 @@ placement_smart(client_t *c) newgeometry = client->f_geometry; newgeometry.width += 2 * client->border; newgeometry.height += 2 * client->border; - newgeometry = titlebar_geometry_add(&client->titlebar, newgeometry); + newgeometry = titlebar_geometry_add(titlebar, newgeometry); area_list_remove(&arealist, &newgeometry); } @@ -119,9 +120,9 @@ placement_smart(client_t *c) newgeometry.width = c->f_geometry.width; newgeometry.height = c->f_geometry.height; - newgeometry = titlebar_geometry_add(&c->titlebar, newgeometry); + newgeometry = titlebar_geometry_add(titlebar, newgeometry); newgeometry = placement_fix_offscreen(newgeometry, c->screen, c->border); - newgeometry = titlebar_geometry_remove(&c->titlebar, newgeometry); + newgeometry = titlebar_geometry_remove(titlebar, newgeometry); area_list_wipe(&arealist); @@ -134,6 +135,7 @@ placement_under_mouse(client_t *c) xcb_query_pointer_cookie_t qp_c; xcb_query_pointer_reply_t *qp_r; area_t finalgeometry = c->f_geometry; + titlebar_t *titlebar = titlebar_getbyclient(c); qp_c = xcb_query_pointer(globalconf.connection, xcb_aux_get_screen(globalconf.connection, c->phys_screen)->root); @@ -145,9 +147,9 @@ placement_under_mouse(client_t *c) p_delete(&qp_r); } - finalgeometry = titlebar_geometry_add(&c->titlebar, finalgeometry); + finalgeometry = titlebar_geometry_add(titlebar, finalgeometry); finalgeometry = placement_fix_offscreen(finalgeometry, c->screen, c->border); - finalgeometry = titlebar_geometry_remove(&c->titlebar, finalgeometry); + finalgeometry = titlebar_geometry_remove(titlebar, finalgeometry); return finalgeometry; } diff --git a/statusbar.c b/statusbar.c index 8855d3c9..75ad2c79 100644 --- a/statusbar.c +++ b/statusbar.c @@ -42,7 +42,8 @@ statusbar_draw(statusbar_t *statusbar) if(!statusbar->position) return; - widget_render(statusbar->widgets, statusbar->ctx, statusbar->sw->drawable, + widget_render(statusbar->widgets, statusbar->ctx, statusbar->sw->gc, + statusbar->sw->drawable, statusbar->screen, statusbar->position, statusbar->sw->geometry.x, statusbar->sw->geometry.y, statusbar); diff --git a/structs.h b/structs.h index 7f2167ac..9c3433b8 100644 --- a/structs.h +++ b/structs.h @@ -47,58 +47,32 @@ typedef enum enum { CurNormal, CurResize, CurMove, CurLast }; -/** Titlebar template structure */ -typedef struct -{ - /** Ref count */ - int refcount; - /** Position */ - position_t position; - /** Alignment on window */ - alignment_t align; - /** Width and height */ - int width, height; - /** Various text used for rendering */ - char *text_normal, *text_focus, *text_urgent; -} titlebar_t; - -/** Delete a titlebar structure. - * \param t The titlebar to destroy. - */ -static inline void -titlebar_delete(titlebar_t **t) -{ - p_delete(&(*t)->text_normal); - p_delete(&(*t)->text_focus); - p_delete(&(*t)->text_urgent); - p_delete(t); -} - -DO_RCNT(titlebar_t, titlebar, titlebar_delete) - -/** Keys bindings */ +typedef struct button_t button_t; +typedef struct widget_t widget_t; +typedef struct widget_node_t widget_node_t; +typedef struct statusbar_t statusbar_t; +typedef struct client_t client_t; +typedef struct titlebar_t titlebar_t; typedef struct keybinding_t keybinding_t; -struct keybinding_t -{ - /** Ref count */ - int refcount; - /** Key modifier */ - unsigned long mod; - /** Keysym */ - xcb_keysym_t keysym; - /** Keycode */ - xcb_keycode_t keycode; - /** Lua function to execute. */ - luaA_function fct; - /** Next and previous keys */ - keybinding_t *prev, *next; -}; +typedef struct client_node_t client_node_t; +typedef struct _tag_t tag_t; +typedef struct tag_client_node_t tag_client_node_t; +typedef area_t (FloatingPlacement)(client_t *); +typedef struct awesome_t awesome_t; -DO_SLIST(keybinding_t, keybinding, p_delete) -DO_RCNT(keybinding_t, keybinding, p_delete) +/** Widget tell status code */ +typedef enum +{ + WIDGET_NOERROR = 0, + WIDGET_ERROR, + WIDGET_ERROR_NOVALUE, + WIDGET_ERROR_CUSTOM, + WIDGET_ERROR_FORMAT_FONT, + WIDGET_ERROR_FORMAT_COLOR, + WIDGET_ERROR_FORMAT_SECTION +} widget_tell_status_t; /** Mouse buttons bindings */ -typedef struct button_t button_t; struct button_t { /** Key modifiers */ @@ -113,22 +87,7 @@ struct button_t DO_SLIST(button_t, button, p_delete) -/** Widget tell status code */ -typedef enum -{ - WIDGET_NOERROR = 0, - WIDGET_ERROR, - WIDGET_ERROR_NOVALUE, - WIDGET_ERROR_CUSTOM, - WIDGET_ERROR_FORMAT_FONT, - WIDGET_ERROR_FORMAT_COLOR, - WIDGET_ERROR_FORMAT_SECTION -} widget_tell_status_t; - /** Widget */ -typedef struct widget_t widget_t; -typedef struct widget_node_t widget_node_t; -typedef struct statusbar_t statusbar_t; struct widget_t { /** Ref count */ @@ -153,16 +112,6 @@ struct widget_t bool isvisible; }; -struct widget_node_t -{ - /** The widget */ - widget_t *widget; - /** The area where the widget was drawn */ - area_t area; - /** Next and previous widget in the list */ - widget_node_t *prev, *next; -}; - /** Delete a widget structure. * \param widget The widget to destroy. */ @@ -177,6 +126,16 @@ widget_delete(widget_t **widget) DO_RCNT(widget_t, widget, widget_delete) +struct widget_node_t +{ + /** The widget */ + widget_t *widget; + /** The area where the widget was drawn */ + area_t area; + /** Next and previous widget in the list */ + widget_node_t *prev, *next; +}; + /** Delete a widget node structure. * \param node The node to destroy. */ @@ -189,6 +148,65 @@ widget_node_delete(widget_node_t **node) DO_SLIST(widget_node_t, widget_node, widget_node_delete) +/** Titlebar template structure */ +struct titlebar_t +{ + /** Ref count */ + int refcount; + /** Attached client */ + client_t *client; + /** Position */ + position_t position, oldposition; + /** Alignment on window */ + alignment_t align; + /** Widgets */ + widget_node_t *widgets; + /** Width and height */ + int width, height; + /** Titlebar window */ + simple_window_t *sw; + /** Default colors */ + struct + { + xcolor_t fg, bg; + } colors; + /** Next and previous in list */ + titlebar_t *prev, *next; +}; + +/** Delete a titlebar structure. + * \param t The titlebar to destroy. + */ +static inline void +titlebar_delete(titlebar_t **t) +{ + widget_node_list_wipe(&(*t)->widgets); + p_delete(t); +} + +DO_SLIST(titlebar_t, titlebar, titlebar_delete) +DO_RCNT(titlebar_t, titlebar, titlebar_delete) + +/** Keys bindings */ +struct keybinding_t +{ + /** Ref count */ + int refcount; + /** Key modifier */ + unsigned long mod; + /** Keysym */ + xcb_keysym_t keysym; + /** Keycode */ + xcb_keycode_t keycode; + /** Lua function to execute. */ + luaA_function fct; + /** Next and previous keys */ + keybinding_t *prev, *next; +}; + +DO_SLIST(keybinding_t, keybinding, p_delete) +DO_RCNT(keybinding_t, keybinding, p_delete) + /** Status bar */ struct statusbar_t { @@ -228,7 +246,6 @@ struct statusbar_t }; /** client_t type */ -typedef struct client_t client_t; struct client_t { /** Client name */ @@ -268,19 +285,12 @@ struct client_t int screen; /** Client physical screen */ int phys_screen; - /** Titlebar */ - titlebar_t titlebar; - /** Titlebar window */ - simple_window_t *titlebar_sw; - /** Old position */ - position_t titlebar_oldposition; /** Layer in the stacking order */ layer_t layer, oldlayer; /** Path to an icon */ char *icon_path; }; -typedef struct client_node_t client_node_t; struct client_node_t { /** The client */ @@ -290,7 +300,6 @@ struct client_node_t }; /** Tag type */ -typedef struct _tag_t tag_t; struct _tag_t { /** Ref count */ @@ -314,7 +323,6 @@ struct _tag_t }; /** Tag client link type */ -typedef struct tag_client_node_t tag_client_node_t; struct tag_client_node_t { tag_t *tag; @@ -336,8 +344,6 @@ typedef struct int right; } Padding; -typedef area_t (FloatingPlacement)(client_t *); - typedef struct { /** true if we need to arrange() */ @@ -351,7 +357,6 @@ typedef struct } screen_t; /** Main configuration structure */ -typedef struct awesome_t awesome_t; struct awesome_t { /** Connection ref */ @@ -387,8 +392,10 @@ struct awesome_t bool have_randr; /** Cursors */ xcb_cursor_t cursor[CurLast]; - /** client_ts list */ + /** Clients list */ client_t *clients; + /** Titlebar list */ + titlebar_t *titlebar; /** Path to config file */ char *configpath; /** Floating window placement algo */ diff --git a/titlebar.c b/titlebar.c index 2fe931ee..a6df2a8a 100644 --- a/titlebar.c +++ b/titlebar.c @@ -27,51 +27,63 @@ #include "titlebar.h" #include "client.h" #include "screen.h" +#include "widget.h" #include "layouts/floating.h" extern awesome_t globalconf; -static char * -titlebar_text(client_t *c) +/** Get a titlebar for a client + * \param c The client. + * \return A titlebar. + */ +titlebar_t * +titlebar_getbyclient(client_t *c) { - char *text; + titlebar_t *t; - if(globalconf.focus->client == c) - text = c->titlebar.text_focus; - else if(c->isurgent) - text = c->titlebar.text_urgent; - else - text = c->titlebar.text_normal; + for(t = globalconf.titlebar; t; t = t->next) + if(t->client == c) + return t; - return client_markup_parse(c, text, a_strlen(text)); + return NULL; } -static inline area_t -titlebar_size(client_t *c) +/** Get a titlebar which own a window. + * \param The window. + * \return A titlebar. + */ +titlebar_t * +titlebar_getbywin(xcb_window_t win) { - return draw_text_extents(globalconf.connection, globalconf.default_screen, - globalconf.font, titlebar_text(c)); + titlebar_t *t; + + for(t = globalconf.titlebar; t; t = t->next) + if(t->sw && t->sw->window == win) + return t; + + return NULL; } /** Draw the titlebar content. * \param c the client + * \todo stop duplicating the context */ void -titlebar_draw(client_t *c) +titlebar_draw(titlebar_t *titlebar) { xcb_drawable_t dw = 0; draw_context_t *ctx; area_t geometry; xcb_screen_t *s; - char *text; - if(!c->titlebar_sw) + if(!titlebar || !titlebar->sw || !titlebar->position) return; s = xcb_aux_get_screen(globalconf.connection, - c->titlebar_sw->phys_screen); + titlebar->sw->phys_screen); - switch(c->titlebar.position) + /** \todo move this in init */ + switch(titlebar->position) { case Off: return; @@ -81,54 +93,52 @@ titlebar_draw(client_t *c) xcb_create_pixmap(globalconf.connection, s->root_depth, dw, s->root, - c->titlebar_sw->geometry.height, - c->titlebar_sw->geometry.width); - ctx = draw_context_new(globalconf.connection, c->titlebar_sw->phys_screen, - c->titlebar_sw->geometry.height, - c->titlebar_sw->geometry.width, + titlebar->sw->geometry.height, + titlebar->sw->geometry.width); + ctx = draw_context_new(globalconf.connection, titlebar->sw->phys_screen, + titlebar->sw->geometry.height, + titlebar->sw->geometry.width, dw, - globalconf.colors.fg, - globalconf.colors.bg); - geometry.width = c->titlebar_sw->geometry.height; - geometry.height = c->titlebar_sw->geometry.width; + titlebar->colors.fg, + titlebar->colors.bg); + geometry.width = titlebar->sw->geometry.height; + geometry.height = titlebar->sw->geometry.width; break; default: - ctx = draw_context_new(globalconf.connection, c->titlebar_sw->phys_screen, - c->titlebar_sw->geometry.width, - c->titlebar_sw->geometry.height, - c->titlebar_sw->drawable, - globalconf.colors.fg, - globalconf.colors.bg); - geometry = c->titlebar_sw->geometry; + ctx = draw_context_new(globalconf.connection, titlebar->sw->phys_screen, + titlebar->sw->geometry.width, + titlebar->sw->geometry.height, + titlebar->sw->drawable, + titlebar->colors.fg, + titlebar->colors.bg); + geometry = titlebar->sw->geometry; break; } - text = titlebar_text(c); - geometry.x = geometry.y = 0; - draw_rectangle(ctx, geometry, 1.0, true, globalconf.colors.bg); - draw_text(ctx, globalconf.font, geometry, text); - p_delete(&text); + widget_render(titlebar->widgets, ctx, titlebar->sw->gc, titlebar->sw->drawable, + titlebar->client->screen, titlebar->position, + titlebar->sw->geometry.x, titlebar->sw->geometry.y, titlebar); - switch(c->titlebar.position) + switch(titlebar->position) { case Left: - draw_rotate(ctx, ctx->drawable, c->titlebar_sw->drawable, + draw_rotate(ctx, ctx->drawable, titlebar->sw->drawable, ctx->width, ctx->height, ctx->height, ctx->width, - - M_PI_2, 0, c->titlebar_sw->geometry.height); + - M_PI_2, 0, titlebar->sw->geometry.height); xcb_free_pixmap(globalconf.connection, dw); break; case Right: - draw_rotate(ctx, ctx->drawable, c->titlebar_sw->drawable, + draw_rotate(ctx, ctx->drawable, titlebar->sw->drawable, ctx->width, ctx->height, ctx->height, ctx->width, - M_PI_2, c->titlebar_sw->geometry.width, 0); + M_PI_2, titlebar->sw->geometry.width, 0); xcb_free_pixmap(globalconf.connection, dw); default: break; } - simplewindow_refresh_drawable(c->titlebar_sw); + simplewindow_refresh_drawable(titlebar->sw); draw_context_delete(&ctx); } @@ -137,110 +147,109 @@ titlebar_draw(client_t *c) * \param c the client */ void -titlebar_update_geometry_floating(client_t *c) +titlebar_update_geometry_floating(titlebar_t *titlebar) { int width, x_offset = 0, y_offset = 0; - if(!c->titlebar_sw) + if(!titlebar || !titlebar->sw) return; - switch(c->titlebar.position) + switch(titlebar->position) { default: return; case Off: return; case Top: - if(!c->titlebar.width) - width = c->geometry.width + 2 * c->border; + if(titlebar->width) + width = MIN(titlebar->width, titlebar->client->geometry.width); else - width = MIN(c->titlebar.width, c->geometry.width); - switch(c->titlebar.align) + width = titlebar->client->geometry.width + 2 * titlebar->client->border; + switch(titlebar->align) { default: break; case AlignRight: - x_offset = 2 * c->border + c->geometry.width - width; + x_offset = 2 * titlebar->client->border + titlebar->client->geometry.width - width; break; case AlignCenter: - x_offset = (c->geometry.width - width) / 2; + x_offset = (titlebar->client->geometry.width - width) / 2; break; } - simplewindow_move_resize(c->titlebar_sw, - c->geometry.x + x_offset, - c->geometry.y - c->titlebar_sw->geometry.height, + simplewindow_move_resize(titlebar->sw, + titlebar->client->geometry.x + x_offset, + titlebar->client->geometry.y - titlebar->sw->geometry.height, width, - c->titlebar_sw->geometry.height); + titlebar->sw->geometry.height); break; case Bottom: - if(!c->titlebar.width) - width = c->geometry.width + 2 * c->border; + if(titlebar->width) + width = MIN(titlebar->width, titlebar->client->geometry.width); else - width = MIN(c->titlebar.width, c->geometry.width); - switch(c->titlebar.align) + width = titlebar->client->geometry.width + 2 * titlebar->client->border; + switch(titlebar->align) { default: break; case AlignRight: - x_offset = 2 * c->border + c->geometry.width - width; + x_offset = 2 * titlebar->client->border + titlebar->client->geometry.width - width; break; case AlignCenter: - x_offset = (c->geometry.width - width) / 2; + x_offset = (titlebar->client->geometry.width - width) / 2; break; } - simplewindow_move_resize(c->titlebar_sw, - c->geometry.x + x_offset, - c->geometry.y + c->geometry.height + 2 * c->border, + simplewindow_move_resize(titlebar->sw, + titlebar->client->geometry.x + x_offset, + titlebar->client->geometry.y + titlebar->client->geometry.height + 2 * titlebar->client->border, width, - c->titlebar_sw->geometry.height); + titlebar->sw->geometry.height); break; case Left: - if(!c->titlebar.width) - width = c->geometry.height + 2 * c->border; + if(titlebar->width) + width = MIN(titlebar->width, titlebar->client->geometry.height); else - width = MIN(c->titlebar.width, c->geometry.height); - switch(c->titlebar.align) + width = titlebar->client->geometry.height + 2 * titlebar->client->border; + switch(titlebar->align) { default: break; case AlignRight: - y_offset = 2 * c->border + c->geometry.height - width; + y_offset = 2 * titlebar->client->border + titlebar->client->geometry.height - width; break; case AlignCenter: - y_offset = (c->geometry.height - width) / 2; + y_offset = (titlebar->client->geometry.height - width) / 2; break; } - simplewindow_move_resize(c->titlebar_sw, - c->geometry.x - c->titlebar_sw->geometry.width, - c->geometry.y + y_offset, - c->titlebar_sw->geometry.width, + simplewindow_move_resize(titlebar->sw, + titlebar->client->geometry.x - titlebar->sw->geometry.width, + titlebar->client->geometry.y + y_offset, + titlebar->sw->geometry.width, width); break; case Right: - if(!c->titlebar.width) - width = c->geometry.height + 2 * c->border; + if(titlebar->width) + width = MIN(titlebar->width, titlebar->client->geometry.height); else - width = MIN(c->titlebar.width, c->geometry.height); - switch(c->titlebar.align) + width = titlebar->client->geometry.height + 2 * titlebar->client->border; + switch(titlebar->align) { default: break; case AlignRight: - y_offset = 2 * c->border + c->geometry.height - width; + y_offset = 2 * titlebar->client->border + titlebar->client->geometry.height - width; break; case AlignCenter: - y_offset = (c->geometry.height - width) / 2; + y_offset = (titlebar->client->geometry.height - width) / 2; break; } - simplewindow_move_resize(c->titlebar_sw, - c->geometry.x + c->geometry.width + 2 * c->border, - c->geometry.y + y_offset, - c->titlebar_sw->geometry.width, + simplewindow_move_resize(titlebar->sw, + titlebar->client->geometry.x + titlebar->client->geometry.width + 2 * titlebar->client->border, + titlebar->client->geometry.y + y_offset, + titlebar->sw->geometry.width, width); break; } - - titlebar_draw(c); + titlebar_draw(titlebar); } @@ -249,112 +258,112 @@ titlebar_update_geometry_floating(client_t *c) * \param geometry the geometry the client will receive */ void -titlebar_update_geometry(client_t *c, area_t geometry) +titlebar_update_geometry(titlebar_t *titlebar, area_t geometry) { int width, x_offset = 0 , y_offset = 0; - if(!c->titlebar_sw) + if(!titlebar || !titlebar->sw) return; - switch(c->titlebar.position) + switch(titlebar->position) { default: return; case Off: return; case Top: - if(!c->titlebar.width) - width = geometry.width + 2 * c->border; + if(!titlebar->width) + width = geometry.width + 2 * titlebar->client->border; else - width = MIN(c->titlebar.width, geometry.width); - switch(c->titlebar.align) + width = MIN(titlebar->width, geometry.width); + switch(titlebar->align) { default: break; case AlignRight: - x_offset = 2 * c->border + geometry.width - width; + x_offset = 2 * titlebar->client->border + geometry.width - width; break; case AlignCenter: x_offset = (geometry.width - width) / 2; break; } - simplewindow_move_resize(c->titlebar_sw, + simplewindow_move_resize(titlebar->sw, geometry.x + x_offset, geometry.y, width, - c->titlebar_sw->geometry.height); + titlebar->sw->geometry.height); break; case Bottom: - if(!c->titlebar.width) - width = geometry.width + 2 * c->border; + if(titlebar->width) + width = geometry.width + 2 * titlebar->client->border; else - width = MIN(c->titlebar.width, geometry.width); - switch(c->titlebar.align) + width = MIN(titlebar->width, geometry.width); + switch(titlebar->align) { default: break; case AlignRight: - x_offset = 2 * c->border + geometry.width - width; + x_offset = 2 * titlebar->client->border + geometry.width - width; break; case AlignCenter: x_offset = (geometry.width - width) / 2; break; } - simplewindow_move_resize(c->titlebar_sw, + simplewindow_move_resize(titlebar->sw, geometry.x + x_offset, geometry.y + geometry.height - - c->titlebar_sw->geometry.height + 2 * c->border, + - titlebar->sw->geometry.height + 2 * titlebar->client->border, width, - c->titlebar_sw->geometry.height); + titlebar->sw->geometry.height); break; case Left: - if(!c->titlebar.width) - width = geometry.height + 2 * c->border; + if(!titlebar->width) + width = geometry.height + 2 * titlebar->client->border; else - width = MIN(c->titlebar.width, geometry.height); - switch(c->titlebar.align) + width = MIN(titlebar->width, geometry.height); + switch(titlebar->align) { default: break; case AlignRight: - y_offset = 2 * c->border + geometry.height - width; + y_offset = 2 * titlebar->client->border + geometry.height - width; break; case AlignCenter: y_offset = (geometry.height - width) / 2; break; } - simplewindow_move_resize(c->titlebar_sw, + simplewindow_move_resize(titlebar->sw, geometry.x, geometry.y + y_offset, - c->titlebar_sw->geometry.width, + titlebar->sw->geometry.width, width); break; case Right: - if(!c->titlebar.width) - width = geometry.height + 2 * c->border; + if(titlebar->width) + width = geometry.height + 2 * titlebar->client->border; else - width = MIN(c->titlebar.width, geometry.height); - switch(c->titlebar.align) + width = MIN(titlebar->width, geometry.height); + switch(titlebar->align) { default: break; case AlignRight: - y_offset = 2 * c->border + geometry.height - width; + y_offset = 2 * titlebar->client->border + geometry.height - width; break; case AlignCenter: y_offset = (geometry.height - width) / 2; break; } - simplewindow_move_resize(c->titlebar_sw, + simplewindow_move_resize(titlebar->sw, geometry.x + geometry.width - - c->titlebar_sw->geometry.width + 2 * c->border, + - titlebar->sw->geometry.width + 2 * titlebar->client->border, geometry.y + y_offset, - c->titlebar_sw->geometry.width, + titlebar->sw->geometry.width, width); break; } - titlebar_draw(c); + titlebar_draw(titlebar); } /** Set client titlebar position. @@ -362,57 +371,55 @@ titlebar_update_geometry(client_t *c, area_t geometry) * \param p The position. */ void -titlebar_init(client_t *c) +titlebar_init(titlebar_t *titlebar) { int width = 0, height = 0; - if(!c->titlebar.height) - c->titlebar.height = draw_text_extents(globalconf.connection, globalconf.default_screen, - globalconf.font, - client_markup_parse(c, - c->titlebar.text_focus, - a_strlen(c->titlebar.text_focus))).height; - switch(c->titlebar.position) + switch(titlebar->position) { default: - c->titlebar.position = Off; - if(c->titlebar_sw) - xcb_unmap_window(globalconf.connection, c->titlebar_sw->window); - return; + titlebar->position = Off; + if(titlebar->sw) + xcb_unmap_window(globalconf.connection, titlebar->sw->window); return; case Top: case Bottom: - if(!c->titlebar.width) - width = c->geometry.width + 2 * c->border; + if(titlebar->width) + width = MIN(titlebar->width, titlebar->client->geometry.width); else - width = MIN(c->titlebar.width, c->geometry.width); - height = c->titlebar.height; + width = titlebar->client->geometry.width + 2 * titlebar->client->border; + height = titlebar->height; break; case Left: case Right: - if(!c->titlebar.width) - height = c->geometry.height + 2 * c->border; + if(titlebar->width) + height = MIN(titlebar->width, titlebar->client->geometry.height); else - height = MIN(c->titlebar.width, c->geometry.height); - width = c->titlebar.height; + height = titlebar->client->geometry.height + 2 * titlebar->client->border; + width = titlebar->height; break; } /* Delete old statusbar */ - simplewindow_delete(&c->titlebar_sw); + simplewindow_delete(&titlebar->sw); - c->titlebar_sw = simplewindow_new(globalconf.connection, - c->phys_screen, 0, 0, - width, height, 0); - titlebar_draw(c); - xcb_map_window(globalconf.connection, c->titlebar_sw->window); + titlebar->sw = simplewindow_new(globalconf.connection, + titlebar->client->phys_screen, 0, 0, + width, height, 0); + titlebar_draw(titlebar); + xcb_map_window(globalconf.connection, titlebar->sw->window); } +/** Create a new titlebar. + * \param A table with values: align, position, fg, bg, width and height. + * \return A brand new titlebar. + */ static int luaA_titlebar_new(lua_State *L) { titlebar_t **tb; int objpos; + const char *color; luaA_checktable(L, 1); @@ -420,10 +427,6 @@ luaA_titlebar_new(lua_State *L) *tb = p_new(titlebar_t, 1); objpos = lua_gettop(L); - (*tb)->text_normal = a_strdup(luaA_getopt_string(L, 1, "text_normal", "