minimal tab support

This commit is contained in:
Julien Danjou 2007-10-15 16:27:48 +02:00
parent fa98171d0b
commit 14ea2dc0ae
10 changed files with 225 additions and 14 deletions

View File

@ -3,7 +3,7 @@
include config.mk include config.mk
SRC = client.c draw.c event.c layout.c awesome.c tag.c util.c config.c screen.c statusbar.c uicb.c SRC = client.c draw.c event.c layout.c awesome.c tag.c util.c config.c screen.c statusbar.c uicb.c tab.c
OBJ = ${SRC:.c=.o} ${LAYOUTS:.c=.o} OBJ = ${SRC:.c=.o} ${LAYOUTS:.c=.o}
all: options awesome all: options awesome

View File

@ -18,6 +18,7 @@ colors
focus_border = "#6666ff" focus_border = "#6666ff"
focus_bg = "#6666ff" focus_bg = "#6666ff"
focus_fg = "#ffffff" focus_fg = "#ffffff"
tab_border = "#ff0000"
} }
statusbar statusbar
@ -559,4 +560,28 @@ keys
command = "toggletag" command = "toggletag"
arg = "9" arg = "9"
} }
key
{
modkey = {"Mod4"}
key = "u"
command = "viewprevtab"
}
key
{
modkey = {"Mod4"}
key = "i"
command = "viewnexttab"
}
key
{
modkey = {"Mod4", "Control"}
key = "u"
command = "untab"
}
key
{
modkey = {"Mod4", "Control"}
key = "i"
command = "tab"
}
} }

View File

@ -320,7 +320,10 @@ focus(Display *disp, Client * c, Bool selscreen, awesome_config *awesomeconf)
drawstatusbar(disp, awesomeconf); drawstatusbar(disp, awesomeconf);
if(*awesomeconf->client_sel) if(*awesomeconf->client_sel)
{ {
XSetWindowBorder(awesomeconf->display, (*awesomeconf->client_sel)->win, awesomeconf->colors_selected[ColBorder].pixel); if((*awesomeconf->client_sel)->tab.next || (*awesomeconf->client_sel)->tab.prev)
XSetWindowBorder(awesomeconf->display, (*awesomeconf->client_sel)->win, awesomeconf->colors_tab[ColBorder].pixel);
else
XSetWindowBorder(awesomeconf->display, (*awesomeconf->client_sel)->win, awesomeconf->colors_selected[ColBorder].pixel);
XSetInputFocus(awesomeconf->display, (*awesomeconf->client_sel)->win, RevertToPointerRoot, CurrentTime); XSetInputFocus(awesomeconf->display, (*awesomeconf->client_sel)->win, RevertToPointerRoot, CurrentTime);
for(c = *awesomeconf->clients; c; c = c->next) for(c = *awesomeconf->clients; c; c = c->next)
if(c != *awesomeconf->client_sel) if(c != *awesomeconf->client_sel)
@ -388,6 +391,7 @@ manage(Display *disp, Window w, XWindowAttributes *wa, awesome_config *awesomeco
c->oldborder = wa->border_width; c->oldborder = wa->border_width;
c->display = disp; c->display = disp;
c->phys_screen = get_phys_screen(c->display, c->screen); c->phys_screen = get_phys_screen(c->display, c->screen);
c->tab.isvisible = True;
screen_info = get_screen_info(c->display, c->screen, NULL); screen_info = get_screen_info(c->display, c->screen, NULL);
if(c->w == screen_info[c->screen].width && c->h == screen_info[c->screen].height) if(c->w == screen_info[c->screen].width && c->h == screen_info[c->screen].height)
{ {

View File

@ -33,6 +33,7 @@
#include "tag.h" #include "tag.h"
#include "statusbar.h" #include "statusbar.h"
#include "layout.h" #include "layout.h"
#include "tab.h"
#include "layouts/tile.h" #include "layouts/tile.h"
#include "layouts/floating.h" #include "layouts/floating.h"
#include "layouts/max.h" #include "layouts/max.h"
@ -91,6 +92,11 @@ const NameFuncLink UicbList[] = {
/* statusbar.c */ /* statusbar.c */
{"togglebar", uicb_togglebar}, {"togglebar", uicb_togglebar},
{"setstatustext", uicb_setstatustext}, {"setstatustext", uicb_setstatustext},
/* tab.c */
{"tab", uicb_tab},
{"untab", uicb_untab},
{"viewnexttab", uicb_viewnexttab},
{"viewprevtab", uicb_viewprevtab},
{NULL, NULL} {NULL, NULL}
}; };
@ -161,6 +167,7 @@ parse_config(Display * disp, int scr,const char *confpatharg, awesome_config *aw
CFG_STR((char *) "focus_border", (char *) "#6666ff", CFGF_NONE), CFG_STR((char *) "focus_border", (char *) "#6666ff", CFGF_NONE),
CFG_STR((char *) "focus_bg", (char *) "#6666ff", CFGF_NONE), CFG_STR((char *) "focus_bg", (char *) "#6666ff", CFGF_NONE),
CFG_STR((char *) "focus_fg", (char *) "#ffffff", CFGF_NONE), CFG_STR((char *) "focus_fg", (char *) "#ffffff", CFGF_NONE),
CFG_STR((char *) "tab_border", (char *) "#ff0000", CFGF_NONE),
CFG_END() CFG_END()
}; };
static cfg_opt_t statusbar_opts[] = static cfg_opt_t statusbar_opts[] =
@ -291,6 +298,7 @@ parse_config(Display * disp, int scr,const char *confpatharg, awesome_config *aw
awesomeconf->colors_selected[ColBorder] = initxcolor(disp, awesomeconf->phys_screen, cfg_getstr(cfg_colors, "focus_border")); awesomeconf->colors_selected[ColBorder] = initxcolor(disp, awesomeconf->phys_screen, cfg_getstr(cfg_colors, "focus_border"));
awesomeconf->colors_selected[ColBG] = initxcolor(disp, awesomeconf->phys_screen, cfg_getstr(cfg_colors, "focus_bg")); awesomeconf->colors_selected[ColBG] = initxcolor(disp, awesomeconf->phys_screen, cfg_getstr(cfg_colors, "focus_bg"));
awesomeconf->colors_selected[ColFG] = initxcolor(disp, awesomeconf->phys_screen, cfg_getstr(cfg_colors, "focus_fg")); awesomeconf->colors_selected[ColFG] = initxcolor(disp, awesomeconf->phys_screen, cfg_getstr(cfg_colors, "focus_fg"));
awesomeconf->colors_tab[ColBorder] = initxcolor(disp, awesomeconf->phys_screen, cfg_getstr(cfg_colors, "tab_border"));
/* Statusbar */ /* Statusbar */
tmp = cfg_getstr(cfg_statusbar, "position"); tmp = cfg_getstr(cfg_statusbar, "position");

View File

@ -115,6 +115,17 @@ struct Client
Client *next; Client *next;
/** Previous client */ /** Previous client */
Client *prev; Client *prev;
/** Tabs support */
struct
{
/** Next client in tab */
Client *next;
/** Previous client in tab */
Client *prev;
/** True if client is the visible one */
Bool isvisible;
/** True if client is tabbed */
} tab;
/** Window of the client */ /** Window of the client */
Window win; Window win;
/** Client display */ /** Client display */
@ -190,6 +201,8 @@ struct awesome_config
XColor colors_normal[ColLast]; XColor colors_normal[ColLast];
/** Selected colors */ /** Selected colors */
XColor colors_selected[ColLast]; XColor colors_selected[ColLast];
/** Tabbed colors */
XColor colors_tab[ColLast];
/** Cursors */ /** Cursors */
Cursor cursor[CurLast]; Cursor cursor[CurLast];
/** Font */ /** Font */

22
event.c
View File

@ -38,8 +38,8 @@
#define CLEANMASK(mask, screen) (mask & ~(awesomeconf[screen].numlockmask | LockMask)) #define CLEANMASK(mask, screen) (mask & ~(awesomeconf[screen].numlockmask | LockMask))
#define MOUSEMASK (BUTTONMASK | PointerMotionMask) #define MOUSEMASK (BUTTONMASK | PointerMotionMask)
static Client * Client *
getclient(Client **list, Window w) get_client_bywin(Client **list, Window w)
{ {
Client *c; Client *c;
@ -195,7 +195,7 @@ handle_event_buttonpress(XEvent * e, awesome_config *awesomeconf)
return; return;
} }
if((c = getclient(awesomeconf->clients, ev->window))) if((c = get_client_bywin(awesomeconf->clients, ev->window)))
{ {
focus(c->display, c, ev->same_screen, &awesomeconf[c->screen]); focus(c->display, c, ev->same_screen, &awesomeconf[c->screen]);
if(CLEANMASK(ev->state, c->screen) != awesomeconf[c->screen].modkey) if(CLEANMASK(ev->state, c->screen) != awesomeconf[c->screen].modkey)
@ -255,7 +255,7 @@ handle_event_configurerequest(XEvent * e, awesome_config *awesomeconf)
XConfigureRequestEvent *ev = &e->xconfigurerequest; XConfigureRequestEvent *ev = &e->xconfigurerequest;
XWindowChanges wc; XWindowChanges wc;
if((c = getclient(awesomeconf->clients, ev->window))) if((c = get_client_bywin(awesomeconf->clients, ev->window)))
{ {
c->ismax = False; c->ismax = False;
if(ev->value_mask & CWBorderWidth) if(ev->value_mask & CWBorderWidth)
@ -338,7 +338,7 @@ handle_event_destroynotify(XEvent * e, awesome_config *awesomeconf)
Client *c; Client *c;
XDestroyWindowEvent *ev = &e->xdestroywindow; XDestroyWindowEvent *ev = &e->xdestroywindow;
if((c = getclient(awesomeconf->clients, ev->window))) if((c = get_client_bywin(awesomeconf->clients, ev->window)))
unmanage(c, WithdrawnState, &awesomeconf[c->screen]); unmanage(c, WithdrawnState, &awesomeconf[c->screen]);
} }
@ -351,7 +351,7 @@ handle_event_enternotify(XEvent * e, awesome_config *awesomeconf)
if(ev->mode != NotifyNormal || ev->detail == NotifyInferior) if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
return; return;
if((c = getclient(awesomeconf->clients, ev->window))) if((c = get_client_bywin(awesomeconf->clients, ev->window)))
{ {
if(!*awesomeconf->client_sel || *awesomeconf->client_sel != c) if(!*awesomeconf->client_sel || *awesomeconf->client_sel != c)
{ {
@ -444,7 +444,7 @@ handle_event_maprequest(XEvent * e, awesome_config *awesomeconf)
return; return;
if(wa.override_redirect) if(wa.override_redirect)
return; return;
if(!getclient(awesomeconf->clients, ev->window)) if(!get_client_bywin(awesomeconf->clients, ev->window))
{ {
for(screen = 0; wa.screen != ScreenOfDisplay(e->xany.display, screen); screen++); for(screen = 0; wa.screen != ScreenOfDisplay(e->xany.display, screen); screen++);
if(screen == 0) if(screen == 0)
@ -469,13 +469,13 @@ handle_event_propertynotify(XEvent * e, awesome_config *awesomeconf)
if(ev->state == PropertyDelete) if(ev->state == PropertyDelete)
return; /* ignore */ return; /* ignore */
if((c = getclient(awesomeconf->clients, ev->window))) if((c = get_client_bywin(awesomeconf->clients, ev->window)))
{ {
switch (ev->atom) switch (ev->atom)
{ {
case XA_WM_TRANSIENT_FOR: case XA_WM_TRANSIENT_FOR:
XGetTransientForHint(e->xany.display, c->win, &trans); XGetTransientForHint(e->xany.display, c->win, &trans);
if(!c->isfloating && (c->isfloating = (getclient(awesomeconf->clients, trans) != NULL))) if(!c->isfloating && (c->isfloating = (get_client_bywin(awesomeconf->clients, trans) != NULL)))
arrange(e->xany.display, &awesomeconf[c->screen]); arrange(e->xany.display, &awesomeconf[c->screen]);
break; break;
case XA_WM_NORMAL_HINTS: case XA_WM_NORMAL_HINTS:
@ -497,7 +497,7 @@ handle_event_unmapnotify(XEvent * e, awesome_config *awesomeconf)
Client *c; Client *c;
XUnmapEvent *ev = &e->xunmap; XUnmapEvent *ev = &e->xunmap;
if((c = getclient(awesomeconf->clients, ev->window)) if((c = get_client_bywin(awesomeconf->clients, ev->window))
&& ev->event == RootWindow(e->xany.display, c->phys_screen) && (ev->send_event || !c->unmapped)) && ev->event == RootWindow(e->xany.display, c->phys_screen) && (ev->send_event || !c->unmapped))
unmanage(c, WithdrawnState, &awesomeconf[c->screen]); unmanage(c, WithdrawnState, &awesomeconf[c->screen]);
} }
@ -507,7 +507,7 @@ handle_event_shape(XEvent * e,
awesome_config *awesomeconf __attribute__ ((unused))) awesome_config *awesomeconf __attribute__ ((unused)))
{ {
XShapeEvent *ev = (XShapeEvent *) e; XShapeEvent *ev = (XShapeEvent *) e;
Client *c = getclient(awesomeconf->clients, ev->window); Client *c = get_client_bywin(awesomeconf->clients, ev->window);
if(c) if(c)
set_shape(c); set_shape(c);

View File

@ -24,6 +24,7 @@
#include "config.h" #include "config.h"
Client * get_client_bywin(Client **list, Window w);
void grabkeys(Display *, int, awesome_config *); /* grab all keys defined in config */ void grabkeys(Display *, int, awesome_config *); /* grab all keys defined in config */
void handle_event_buttonpress(XEvent *, awesome_config *); void handle_event_buttonpress(XEvent *, awesome_config *);

127
tab.c Normal file
View File

@ -0,0 +1,127 @@
/*
* tab.c - tab management
*
* Copyright © 2007 Julien Danjou <julien@danjou.info>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "tab.h"
#include "event.h"
#include "layout.h"
void
uicb_tab(awesome_config *awesomeconf,
const char *arg __attribute__ ((unused)))
{
Window dummy, child;
int x1, y1, di;
unsigned int dui;
XEvent ev;
Client *sel = *awesomeconf->client_sel, *c = NULL, *tmp;
if(XGrabPointer(awesomeconf->display, RootWindow(awesomeconf->display, awesomeconf->phys_screen),
False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None,
awesomeconf[awesomeconf->screen].cursor[CurMove], CurrentTime) != GrabSuccess)
return;
for(;;)
{
XMaskEvent(awesomeconf->display, ButtonPressMask, &ev);
if(ev.type == ButtonPress)
{
XUngrabPointer(awesomeconf->display, CurrentTime);
break;
}
}
XQueryPointer(awesomeconf->display,
RootWindow(awesomeconf->display, awesomeconf->phys_screen),
&dummy, &child, &x1, &y1, &di, &di, &dui);
if((c = get_client_bywin(awesomeconf->clients, child))
&& c != sel)
{
/* take the last tabbed window */
for(tmp = sel; tmp->tab.next; tmp = tmp->tab.next);
tmp->tab.next = c;
c->tab.prev = tmp;
c->tab.isvisible = False;
arrange(awesomeconf->display, awesomeconf);
}
}
void
uicb_untab(awesome_config *awesomeconf,
const char *arg __attribute__ ((unused)))
{
Client *tmp, *sel = *awesomeconf->client_sel;
if(!sel)
return;
if(sel->tab.next)
sel->tab.next->tab.isvisible = True;
else if(sel->tab.prev)
sel->tab.prev->tab.isvisible = True;
sel->tab.isvisible = True;
if(sel->tab.next)
sel->tab.next->tab.prev = sel->tab.prev;
tmp = sel->tab.next;
sel->tab.next = NULL;
if(sel->tab.prev)
sel->tab.prev->tab.next = tmp;
sel->tab.prev = NULL;
arrange(awesomeconf->display, awesomeconf);
}
void
uicb_viewnexttab(awesome_config *awesomeconf,
const char *arg __attribute__ ((unused)))
{
Client *sel = *awesomeconf->client_sel;
if(!sel || !sel->tab.next)
return;
sel->tab.isvisible = False;
sel->tab.next->tab.isvisible = True;
arrange(awesomeconf->display, awesomeconf);
focus(awesomeconf->display, sel->tab.next, True, awesomeconf);
}
void
uicb_viewprevtab(awesome_config *awesomeconf,
const char *arg __attribute__ ((unused)))
{
Client *sel = *awesomeconf->client_sel;
if(!sel || !sel->tab.prev)
return;
sel->tab.isvisible = False;
sel->tab.prev->tab.isvisible = True;
arrange(awesomeconf->display, awesomeconf);
focus(awesomeconf->display, sel->tab.prev, True, awesomeconf);
}
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99

33
tab.h Normal file
View File

@ -0,0 +1,33 @@
/*
* tab.h - tab management header
*
* Copyright © 2007 Julien Danjou <julien@danjou.info>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef AWESOME_TAB_H
#define AWESOME_TAB_H
#include "common.h"
UICB_PROTO(uicb_tab);
UICB_PROTO(uicb_untab);
UICB_PROTO(uicb_viewnexttab);
UICB_PROTO(uicb_viewprevtab);
#endif
// vim: filetype=c:expandtab:shiftwidth=6:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99

2
tag.c
View File

@ -129,7 +129,7 @@ isvisible(Client * c, int screen, Tag * tags, int ntags)
{ {
int i; int i;
if(c->screen != screen) if(c->screen != screen || !c->tab.isvisible)
return False; return False;
for(i = 0; i < ntags; i++) for(i = 0; i < ntags; i++)