diff --git a/CMakeLists.txt b/CMakeLists.txt index f33d28a..306fa9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ set(wmfs_src src/infobar.c src/init.c src/layout.c + src/menu.c src/mouse.c src/screen.c src/tag.c diff --git a/src/config.c b/src/config.c index 13de07a..386412b 100644 --- a/src/config.c +++ b/src/config.c @@ -64,7 +64,8 @@ conf_init_func_list(void) {"screen_next", uicb_screen_next }, {"screen_prev", uicb_screen_prev }, {"reload", uicb_reload }, - {"launcher", uicb_launcher } + {"launcher", uicb_launcher }, + {"set_layout", uicb_set_layout } }; func_list = emalloc(LEN(tmp_list), sizeof(func_name_list_t)); @@ -154,7 +155,7 @@ conf_root_section(cfg_t *cfg_r) void conf_client_section(cfg_t *cfg_c) { - /* Client misc */ + /* Client misc */ conf.client.borderheight = (cfg_getint(cfg_c, "border_height")) ? cfg_getint(cfg_c, "border_height") : 1; conf.client.place_at_mouse = cfg_getbool(cfg_c, "place_at_mouse"); conf.client.bordernormal = getcolor(alias_to_str(cfg_getstr(cfg_c, "border_normal"))); @@ -195,6 +196,9 @@ conf_layout_section(cfg_t *cfg_l) conf.colors.layout_fg = strdup(alias_to_str(cfg_getstr(cfg_l, "fg"))); conf.colors.layout_bg = getcolor(alias_to_str(cfg_getstr(cfg_l, "bg"))); + if(strcmp(strdup(alias_to_str(cfg_getstr(cfg_l, "system"))), "menu") == 0) + conf.layout_system = True; + if((conf.nlayout = cfg_size(cfg_l, "layout")) > NUM_OF_LAYOUT || !(conf.nlayout = cfg_size(cfg_l, "layout"))) { @@ -204,6 +208,9 @@ conf_layout_section(cfg_t *cfg_l) conf.layout[0].func = tile; } + if(conf.layout_system) + menu_init(&menulayout, conf.nlayout); + if(!conf.layout[0].symbol && !conf.layout[0].func) { @@ -218,6 +225,11 @@ conf_layout_section(cfg_t *cfg_l) } else { + if(conf.layout_system) + menu_new_item(&menulayout.item[i], + strdup(alias_to_str(cfg_getstr(cfgtmp, "symbol"))), + uicb_set_layout, strdup(cfg_getstr(cfgtmp, "type"))); + conf.layout[i].symbol = strdup(alias_to_str(cfg_getstr(cfgtmp, "symbol"))); conf.layout[i].func = name_to_func(strdup(cfg_getstr(cfgtmp, "type")), layout_list); } diff --git a/src/config_struct.h b/src/config_struct.h index 3dca6bb..062c66f 100644 --- a/src/config_struct.h +++ b/src/config_struct.h @@ -107,6 +107,7 @@ cfg_opt_t layouts_opts[] = CFG_STR("fg", "#FFFFFF", CFGF_NONE), CFG_STR("bg", "#292929", CFGF_NONE), CFG_BOOL("border", cfg_false, CFGF_NONE), + CFG_STR("system", "menu", CFGF_NONE), CFG_SEC("layout", layout_opts, CFGF_MULTI), CFG_END() }; diff --git a/src/draw.c b/src/draw.c index 05b0103..402d0d2 100644 --- a/src/draw.c +++ b/src/draw.c @@ -99,3 +99,5 @@ textw(const char *text) return gl.width + font->descent; } + + diff --git a/src/event.c b/src/event.c index 1ec91b2..66452c2 100644 --- a/src/event.c +++ b/src/event.c @@ -85,11 +85,25 @@ buttonpress(XButtonEvent *ev) /* Layout button */ if(ev->window == infobar[selscreen].layout_button->win) - switch(ev->button) + { + if(conf.layout_system && + (ev->button == Button1 || ev->button == Button3)) /* True -> menu */ { - case Button1: case Button4: layoutswitch(True); break; - case Button3: case Button5: layoutswitch(False); break; + int y = infobar[selscreen].layout_button->geo.y + INFOBARH; + if(infobar[selscreen].geo.y != sgeo[selscreen].y - (INFOBARH + TBARH)) + y = infobar[selscreen].geo.y - (INFOBARH * menulayout.nitem) - SHADH; + + menu_draw(menulayout, infobar[selscreen].layout_button->geo.x, y); } + else + { + switch(ev->button) + { + case Button1: case Button4: layoutswitch(True); break; + case Button3: case Button5: layoutswitch(False); break; + } + } + } return; } diff --git a/src/infobar.c b/src/infobar.c index f3e6cc7..c1d4e3e 100644 --- a/src/infobar.c +++ b/src/infobar.c @@ -214,22 +214,25 @@ uicb_launcher(uicb_t cmd) char buf[512] = { 0 }; int pos = 0; int lrun = 1; - BarWindow *launch = barwin_create(infobar[screen_get_sel()].bar->win, + + screen_get_sel(); + + BarWindow *launch = barwin_create(infobar[selscreen].bar->win, /* X */ (infobar[selscreen].layout_button->geo.x + textw(tags[selscreen][seltag[selscreen]].layout.symbol) + PAD), /* Y */ - 0, + SHADH, /* WIDTH */ - (sgeo[selscreen].width + (sgeo[0].width - (infobar[selscreen].layout_button->geo.x - + textw(tags[selscreen][seltag[selscreen]].layout.symbol) + PAD)), + + textw(tags[selscreen][seltag[selscreen]].layout.symbol) + PAD) - SHADH), /* HEIGHT */ - infobar[selscreen].geo.height, + infobar[selscreen].geo.height - SHADH, /* COLOR */ conf.colors.bar, conf.colors.text, /* OPTION */ - False, False, False); + False, False, True); barwin_map(launch); barwin_refresh_color(launch); /* Draw Prompt */ diff --git a/src/layout.c b/src/layout.c index 111f116..000da02 100644 --- a/src/layout.c +++ b/src/layout.c @@ -505,3 +505,37 @@ uicb_togglemax(uicb_t cmd) return; } + +/** Set the layout + * \param cmd uicb_t type +*/ +void +uicb_set_layout(uicb_t cmd) +{ + int i = -1; + + screen_get_sel(); + + if(strcmp(cmd, "tile_right") == 0 + || strcmp(cmd, "tile") == 0) + i = 0; + else if(strcmp(cmd, "tile_left") == 0) + i = 1; + else if(strcmp(cmd, "tile_top") == 0) + i = 2; + else if(strcmp(cmd, "tile_bottom") == 0) + i = 3; + else if(strcmp(cmd, "tile_grid") == 0) + i = 4; + else if(strcmp(cmd, "max") == 0) + i = 5; + else if(strcmp(cmd, "free") == 0) + i = 6; + + if(i >= 0) + tags[selscreen][seltag[selscreen]].layout = conf.layout[i]; + + arrange(selscreen); + + return; +} diff --git a/src/menu.c b/src/menu.c new file mode 100644 index 0000000..a26e81f --- /dev/null +++ b/src/menu.c @@ -0,0 +1,150 @@ +/* +* menu.c +* Copyright © 2008 Martin Duquesnoy +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following disclaimer +* in the documentation and/or other materials provided with the +* distribution. +* * Neither the name of the nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "wmfs.h" + +void +menu_init(Menu *menu, int nitem) +{ + menu->nitem = nitem; + menu->item = emalloc(sizeof(MenuItem), nitem); + + return; +} + +void +menu_new_item(MenuItem *mi, char *name, void *func, char *cmd) +{ + mi->name = name; + mi->func = func; + mi->cmd = cmd; + + return; +} + +void +menu_draw(Menu menu, int x, int y) +{ + int i, width; + int r = 1; + XEvent ev; + BarWindow *item[menu.nitem]; + BarWindow *frame; + + width = menu_get_longer_string(menu.item, menu.nitem); + + /* Frame barwin */ + frame = barwin_create(ROOT, x, y, width + SHADH, + menu.nitem * INFOBARH + SHADH, + conf.colors.bar, conf.colors.text, + False, False, True); + + barwin_map(frame); + barwin_map_subwin(frame); + barwin_refresh_color(frame); + + for(i = 0; i < menu.nitem; ++i) + { + item[i] = barwin_create(frame->win, + SHADH, + (i * INFOBARH) + SHADH, + width - SHADH, + INFOBARH, + conf.colors.bar, + conf.colors.text, + True, False, False); + barwin_map(item[i]); + barwin_map_subwin(frame); + barwin_refresh_color(item[i]); + barwin_refresh(item[i]); + + barwin_draw_text(item[i], ((width / 2) - (textw(menu.item[i].name) / 2)), font->height, menu.item[i].name); + } + + while(r) + { + switch(ev.type) + { + case ButtonPress: + /* Execute the function linked with the item */ + for(i = 0; i < menu.nitem; ++i) + if(ev.xbutton.window == item[i]->win + && ev.xbutton.button == Button1) + if(menu.item[i].func) + menu.item[i].func(menu.item[i].cmd); + r = 0; + break; + case EnterNotify: + /* For focus an item with the mousw */ + for(i = 0; i < menu.nitem; ++i) + { + if(ev.xcrossing.window == item[i]->win) + { + item[i]->fg = conf.colors.tagselfg; + item[i]->bg = conf.colors.tagselbg; + } + else + { + item[i]->fg = conf.colors.text; + item[i]->bg = conf.colors.bar; + } + + barwin_refresh_color(item[i]); + barwin_draw_text(item[i], ((width / 2) - (textw(menu.item[i].name) / 2)), font->height, menu.item[i].name); + barwin_refresh(item[i]); + } + break; + default: + getevent(ev); + break; + } + XNextEvent(dpy, &ev); + } + + for(i = 0; i < menu.nitem; ++i) + barwin_delete(item[i]); + barwin_delete(frame); + + return; +} + +int +menu_get_longer_string(MenuItem *mt, int nitem) +{ + int i, l = 0; + + for(i = 0; i < nitem; ++i) + if(textw(mt[i].name) > l) + l = textw(mt[i].name); + + return l + PAD; +} diff --git a/src/structs.h b/src/structs.h index 4a34c0a..d3d1bf4 100644 --- a/src/structs.h +++ b/src/structs.h @@ -200,6 +200,24 @@ typedef struct Layout layout; } Tag; +/* Menu Item Struct */ +typedef struct +{ + char *name; + void (*func)(uicb_t); + uicb_t cmd; +} MenuItem; + +/* Menu Struct */ +typedef struct +{ + int specified_pos, x, y; + /* Number of item */ + int nitem; + /* Item */ + MenuItem *item; +} Menu; + /* Alias struct */ typedef struct { @@ -267,6 +285,7 @@ typedef struct Layout layout[NUM_OF_LAYOUT]; int *ntag; Bool tag_round; + Bool layout_system; /* Switch: False, Menu: True. */ int nkeybind; int nbutton; int nlayout; diff --git a/src/util.c b/src/util.c index ffe99bb..a7eb7aa 100644 --- a/src/util.c +++ b/src/util.c @@ -180,6 +180,20 @@ alias_to_str(char *conf_choice) } /* }}} */ +/** Get the mouse pointer position. +*/ +XRectangle +get_mouse_pos(void) +{ + Window dum; + int d, u; + XRectangle ret; + + XQueryPointer(dpy, ROOT, &dum, &dum, (int*)&ret.x, (int*)&ret.y, &d, &d, (uint *)&u); + + return ret; +} + /** Execute a sh command * \param cmd Command */ diff --git a/src/wmfs.h b/src/wmfs.h index 22df3f4..7980170 100644 --- a/src/wmfs.h +++ b/src/wmfs.h @@ -95,7 +95,6 @@ BarWindow *barwin_create(Window parent, Bool entermask, Bool stipple, Bool border); - void barwin_draw_text(BarWindow *bw, int x, int y, char *text); void barwin_delete(BarWindow *bw); void barwin_delete_subwin(BarWindow *bw); @@ -194,6 +193,12 @@ void maprequest(XMapRequestEvent *ev); void propertynotify(XPropertyEvent *ev); void getevent(XEvent ev); +/* menu.c */ +void menu_init(Menu *menu, int nitem); +void menu_new_item(MenuItem *mi, char *name, void *func, char *cmd); +void menu_draw(Menu menu, int x, int y); +int menu_get_longer_string(MenuItem *mt, int nitem); + /* mouse.c */ void mouse_move(Client *c); void mouse_resize(Client *c); @@ -213,6 +218,7 @@ uint char_to_button(char *name, name_to_uint_t blist[]); Layout layout_name_to_struct(Layout lt[], char *name, int n, func_name_list_t llist[]); char* alias_to_str(char *conf_choice); /* }}} */ +XRectangle get_mouse_pos(void); void uicb_spawn(uicb_t); /* tag.c */ @@ -223,7 +229,7 @@ void uicb_tag_next(uicb_t); void uicb_tag_prev(uicb_t); void uicb_tagtransfert(uicb_t); -/* screen */ +/* screen.c */ int screen_count(void); XRectangle screen_get_geo(int s); int screen_get_with_geo(int x, int y); @@ -254,6 +260,8 @@ void uicb_layout_prev(uicb_t); void uicb_layout_next(uicb_t); void uicb_set_mwfact(uicb_t); void uicb_set_nmaster(uicb_t); +void uicb_set_layout(uicb_t cmd); + /* init.c */ void init(void); @@ -295,6 +303,7 @@ Atom net_atom[net_last]; InfoBar *infobar; Tag **tags; int *seltag; +Menu menulayout; /* Important Client */ Client *clients; diff --git a/wmfsrc b/wmfsrc index 76d3cec..3a3260c 100644 --- a/wmfsrc +++ b/wmfsrc @@ -27,6 +27,9 @@ layouts # Border around the layout button border = true + + system = "menu" # menu or switch + # Tiling layouts layout { type = "tile_right" symbol = "RIGHT" } layout { type = "tile_left" symbol = "LEFT" }