From df2a8e1b1dfd406158d5bdac2a88eefb09f01b8d Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Fri, 14 Dec 2007 21:51:54 +0100 Subject: [PATCH] add a focus history --- Makefile | 2 +- awesome.c | 2 ++ client.c | 65 ++++++++++++++++++--------------- config.h | 11 ++++-- event.c | 2 +- focus.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++ focus.h | 32 +++++++++++++++++ layout.c | 20 ++++++----- mouse.c | 4 +-- screen.c | 7 ++-- statusbar.c | 2 +- tag.c | 12 +++---- 12 files changed, 205 insertions(+), 56 deletions(-) create mode 100644 focus.c create mode 100644 focus.h diff --git a/Makefile b/Makefile index 494ca748b..c59fbd4c3 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ include config.mk -SRC = client.c draw.c event.c layout.c awesome.c tag.c util.c xutil.c config.c screen.c statusbar.c uicb.c window.c rules.c mouse.c awesome-client-common.c +SRC = focus.c client.c draw.c event.c layout.c awesome.c tag.c util.c xutil.c config.c screen.c statusbar.c uicb.c window.c rules.c mouse.c awesome-client-common.c OBJ = ${SRC:.c=.o} ${LAYOUTS:.c=.o} DOCS = awesome.1.txt awesome-client.1.txt diff --git a/awesome.c b/awesome.c index 4cdd29479..90c05fd62 100644 --- a/awesome.c +++ b/awesome.c @@ -46,6 +46,7 @@ #include "uicb.h" #include "window.h" #include "client.h" +#include "focus.h" #include "awesome-client.h" static int (*xerrorxlib) (Display *, XErrorEvent *); @@ -339,6 +340,7 @@ main(int argc, char *argv[]) /* allocate stuff */ awesomeconf = p_new(awesome_config, 1); awesomeconf->screens = p_new(VirtScreen, get_screen_count(dpy)); + focus_add_client(&awesomeconf->focus, NULL); /* store display */ awesomeconf->display = dpy; parse_config(confpath, awesomeconf); diff --git a/client.c b/client.c index f9e7e072c..8dabf604c 100644 --- a/client.c +++ b/client.c @@ -32,6 +32,7 @@ #include "xutil.h" #include "statusbar.h" #include "window.h" +#include "focus.h" #include "layouts/floating.h" /** Load windows properties, restoring client's tag @@ -195,24 +196,22 @@ client_detach(Client **head, Client *c) void focus(Client *c, Bool selscreen, awesome_config *awesomeconf, int screen) { - Tag *tag, *curtag = get_current_tag(awesomeconf->screens[screen]); + /* unfocus current selected client */ + if(awesomeconf->focus->client) + { + window_grabbuttons(awesomeconf->focus->client->display, awesomeconf->focus->client->phys_screen, + awesomeconf->focus->client->win, False, True, awesomeconf->buttons.root, + awesomeconf->buttons.client, awesomeconf->numlockmask); + XSetWindowBorder(awesomeconf->focus->client->display, awesomeconf->focus->client->win, + awesomeconf->screens[screen].colors_normal[ColBorder].pixel); + window_settrans(awesomeconf->focus->client->display, awesomeconf->focus->client->win, + awesomeconf->screens[screen].opacity_unfocused); + } /* if c is NULL or invisible, take next client in the stack */ if((!c && selscreen) || (c && !client_isvisible(c, &awesomeconf->screens[screen], screen))) for(c = awesomeconf->clients; c && !client_isvisible(c, &awesomeconf->screens[screen], screen); c = c->next); - /* XXX unfocus other tags clients, this is a bit too much */ - for(tag = awesomeconf->screens[screen].tags; tag; tag = tag->next) - if(tag->client_sel) - { - window_grabbuttons(tag->client_sel->display, tag->client_sel->phys_screen, - tag->client_sel->win, False, True, awesomeconf->buttons.root, - awesomeconf->buttons.client, awesomeconf->numlockmask); - XSetWindowBorder(tag->client_sel->display, tag->client_sel->win, - awesomeconf->screens[screen].colors_normal[ColBorder].pixel); - window_settrans(tag->client_sel->display, tag->client_sel->win, - awesomeconf->screens[screen].opacity_unfocused); - } if(c) { XSetWindowBorder(awesomeconf->display, c->win, awesomeconf->screens[screen].colors_selected[ColBorder].pixel); @@ -220,20 +219,29 @@ focus(Client *c, Bool selscreen, awesome_config *awesomeconf, int screen) True, True, awesomeconf->buttons.root, awesomeconf->buttons.client, awesomeconf->numlockmask); } + if(!selscreen) return; - curtag->client_sel = c; + + /* save old sel in focus history */ + focus_add_client(&awesomeconf->focus, c); + statusbar_draw(awesomeconf, screen); - if(curtag->client_sel) + + if(awesomeconf->focus->client) { - XSetInputFocus(curtag->client_sel->display, curtag->client_sel->win, RevertToPointerRoot, CurrentTime); + XSetInputFocus(awesomeconf->focus->client->display, + awesomeconf->focus->client->win, RevertToPointerRoot, CurrentTime); for(c = awesomeconf->clients; c; c = c->next) - if(c != curtag->client_sel) - window_settrans(awesomeconf->display, curtag->client_sel->win, awesomeconf->screens[screen].opacity_unfocused); - window_settrans(awesomeconf->display, curtag->client_sel->win, -1); + if(c != awesomeconf->focus->client) + window_settrans(awesomeconf->display, awesomeconf->focus->client->win, + awesomeconf->screens[screen].opacity_unfocused); + window_settrans(awesomeconf->display, awesomeconf->focus->client->win, -1); } else - XSetInputFocus(awesomeconf->display, RootWindow(awesomeconf->display, get_phys_screen(awesomeconf->display, screen)), RevertToPointerRoot, CurrentTime); + XSetInputFocus(awesomeconf->display, + RootWindow(awesomeconf->display, get_phys_screen(awesomeconf->display, screen)), + RevertToPointerRoot, CurrentTime); } /** Manage a new client @@ -486,8 +494,9 @@ client_unmanage(Client *c, long state, awesome_config *awesomeconf) XGrabServer(c->display); XConfigureWindow(c->display, c->win, CWBorderWidth, &wc); /* restore border */ client_detach(&awesomeconf->clients, c); - if(get_current_tag(awesomeconf->screens[c->screen])->client_sel == c) + if(awesomeconf->focus->client == c) focus(NULL, True, awesomeconf, c->screen); + focus_delete_client(&awesomeconf->focus, c); for(tag = awesomeconf->screens[c->screen].tags; tag; tag = tag->next) untag_client(&awesomeconf->screens[c->screen].tclink, c, tag); XUngrabButton(c->display, AnyButton, AnyModifier, c->win); @@ -589,7 +598,7 @@ client_isvisible(Client *c, VirtScreen *scr, int screen) */ void uicb_client_settrans(awesome_config *awesomeconf, - int screen, + int screen __attribute__ ((unused)), const char *arg) { double delta = 100.0, current_opacity = 100.0; @@ -599,7 +608,7 @@ uicb_client_settrans(awesome_config *awesomeconf, unsigned long n, left; unsigned int current_opacity_raw = 0; int set_prop = 0; - Client *sel = get_current_tag(awesomeconf->screens[screen])->client_sel; + Client *sel = awesomeconf->focus->client; if(!sel) return; @@ -656,7 +665,7 @@ uicb_client_swapnext(awesome_config *awesomeconf, int screen, const char *arg __attribute__ ((unused))) { - Client *next, *sel = get_current_tag(awesomeconf->screens[screen])->client_sel; + Client *next, *sel = awesomeconf->focus->client; if(!sel) return; @@ -676,7 +685,7 @@ uicb_client_swapprev(awesome_config *awesomeconf, int screen, const char *arg __attribute__ ((unused))) { - Client *prev, *sel = get_current_tag(awesomeconf->screens[screen])->client_sel; + Client *prev, *sel = awesomeconf->focus->client; if(!sel) return; @@ -701,7 +710,7 @@ uicb_client_moveresize(awesome_config *awesomeconf, int mx, my, dx, dy, nmx, nmy; unsigned int dui; Window dummy; - Client *sel = get_current_tag(awesomeconf->screens[screen])->client_sel; + Client *sel = awesomeconf->focus->client; if(get_current_layout(awesomeconf->screens[screen])->arrange != layout_floating) if(!sel || !sel->isfloating || sel->isfixed || !arg) @@ -735,11 +744,11 @@ uicb_client_moveresize(awesome_config *awesomeconf, */ void uicb_client_kill(awesome_config *awesomeconf, - int screen, + int screen __attribute__ ((unused)), const char *arg __attribute__ ((unused))) { XEvent ev; - Client *sel = get_current_tag(awesomeconf->screens[screen])->client_sel; + Client *sel = awesomeconf->focus->client; if(!sel) return; diff --git a/config.h b/config.h index 2cf1c9459..087ae0a4e 100644 --- a/config.h +++ b/config.h @@ -132,6 +132,13 @@ struct Client int phys_screen; }; +typedef struct FocusList FocusList; +struct FocusList +{ + Client *client; + FocusList *prev; +}; + /** Tag type */ typedef struct Tag Tag; struct Tag @@ -144,8 +151,6 @@ struct Tag Bool was_selected; /** Current tag layout */ Layout *layout; - /** Selected client on this tag */ - Client *client_sel; /** Master width factor */ double mwfact; /** Number of master windows */ @@ -243,6 +248,8 @@ struct awesome_config Client *clients; /** Path to config file */ char *configpath; + /** Selected clients on this tag */ + FocusList *focus; }; void parse_config(const char *, awesome_config *); diff --git a/event.c b/event.c index 11bb07598..f770c962d 100644 --- a/event.c +++ b/event.c @@ -365,7 +365,7 @@ handle_event_propertynotify(XEvent * e, awesome_config *awesomeconf) if(ev->atom == XA_WM_NAME || ev->atom == XInternAtom(c->display, "_NET_WM_NAME", False)) { client_updatetitle(c); - if(c == get_current_tag(awesomeconf->screens[c->screen])->client_sel) + if(c == awesomeconf->focus->client) statusbar_draw(awesomeconf, c->screen); } } diff --git a/focus.c b/focus.c new file mode 100644 index 000000000..f6528792e --- /dev/null +++ b/focus.c @@ -0,0 +1,102 @@ +/* + * focus.c - focus management + * + * Copyright © 2007 Julien Danjou + * + * 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 "util.h" +#include "tag.h" +#include "focus.h" + +static FocusList * +focus_get_node_by_client(FocusList *head, Client *c) +{ + FocusList *fh; + + for(fh = head; fh; fh = fh->prev) + if(fh->client == c) + return fh; + + return NULL; +} + +static FocusList * +focus_detach_node(FocusList **head, FocusList *fl) +{ + FocusList *tmp; + + if(*head == fl) + *head = fl->prev; + else + { + for(tmp = *head; tmp && tmp->prev != fl; tmp = tmp->prev); + tmp->prev = fl->prev; + } + + return fl; +} + +static FocusList * +focus_attach_node(FocusList **head, FocusList *fl) +{ + FocusList *old_head; + + old_head = *head; + *head = fl; + fl->prev = old_head; + + return fl; +} + +void +focus_add_client(FocusList **head, Client *c) +{ + FocusList *new_fh; + + /* if we don't find this node, create a new one */ + if(!(new_fh = focus_get_node_by_client(*head, c))) + { + new_fh = p_new(FocusList, 1); + new_fh->client = c; + } + else /* if we've got a node, detach it */ + focus_detach_node(head, new_fh); + + focus_attach_node(head, new_fh); +} + +void +focus_delete_client(FocusList **head, Client *c) +{ + FocusList *target = focus_detach_node(head, focus_get_node_by_client(*head, c)); + p_delete(&target); +} + +Client * +focus_get_latest_client_for_tag(FocusList *head, TagClientLink *tc, Tag *t) +{ + FocusList *fl; + + for(fl = head; fl; fl = fl->prev) + if(is_client_tagged(tc, fl->client, t)) + return fl->client; + + return NULL; +} + +// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 diff --git a/focus.h b/focus.h new file mode 100644 index 000000000..9ecee1443 --- /dev/null +++ b/focus.h @@ -0,0 +1,32 @@ +/* + * focus.h - focus management header + * + * Copyright © 2007 Julien Danjou + * + * 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_FOCUS_H +#define AWESOME_FOCUS_H + +#include "config.h" + +void focus_add_client(FocusList **, Client *); +void focus_delete_client(FocusList **, Client *); +Client * focus_get_latest_client_for_tag(FocusList *, TagClientLink *, Tag *); + +#endif +// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 diff --git a/layout.c b/layout.c index 143251ffb..7d326f6fe 100644 --- a/layout.c +++ b/layout.c @@ -27,6 +27,7 @@ #include "tag.h" #include "util.h" #include "xutil.h" +#include "focus.h" #include "statusbar.h" #include "layouts/floating.h" @@ -66,7 +67,8 @@ arrange(awesome_config *awesomeconf, int screen) } curtag->layout->arrange(awesomeconf, screen); - focus(curtag->client_sel, True, awesomeconf, screen); + focus(focus_get_latest_client_for_tag(awesomeconf->focus, awesomeconf->screens[screen].tclink, curtag), + True, awesomeconf, screen); restack(awesomeconf, screen); } @@ -86,7 +88,7 @@ uicb_client_focusnext(awesome_config * awesomeconf, int screen, const char *arg __attribute__ ((unused))) { - Client *c, *sel = get_current_tag(awesomeconf->screens[screen])->client_sel; + Client *c, *sel = awesomeconf->focus->client; if(!sel) return; @@ -105,7 +107,7 @@ uicb_client_focusprev(awesome_config *awesomeconf, int screen, const char *arg __attribute__ ((unused))) { - Client *c, *sel = get_current_tag(awesomeconf->screens[screen])->client_sel; + Client *c, *sel = awesomeconf->focus->client; if(!sel) return; @@ -149,7 +151,7 @@ loadawesomeprops(awesome_config *awesomeconf, int screen) void restack(awesome_config *awesomeconf, int screen) { - Client *c, *sel = get_current_tag(awesomeconf->screens[screen])->client_sel; + Client *c, *sel = awesomeconf->focus->client; XEvent ev; XWindowChanges wc; @@ -235,7 +237,7 @@ uicb_tag_setlayout(awesome_config * awesomeconf, if(tag->selected) tag->layout = l; - if(get_current_tag(awesomeconf->screens[screen])->client_sel) + if(awesomeconf->focus->client) arrange(awesomeconf, screen); else statusbar_draw(awesomeconf, screen); @@ -246,7 +248,7 @@ uicb_tag_setlayout(awesome_config * awesomeconf, static void maximize(int x, int y, int w, int h, awesome_config *awesomeconf, int screen) { - Client *sel = get_current_tag(awesomeconf->screens[screen])->client_sel; + Client *sel = awesomeconf->focus->client; if(!sel) return; @@ -284,7 +286,7 @@ uicb_client_toggleverticalmax(awesome_config *awesomeconf, int screen, const char *arg __attribute__ ((unused))) { - Client *sel = get_current_tag(awesomeconf->screens[screen])->client_sel; + Client *sel = awesomeconf->focus->client; ScreenInfo *si = get_screen_info(awesomeconf->display, screen, &awesomeconf->screens[screen].statusbar, &awesomeconf->screens[screen].padding); if(sel) @@ -302,7 +304,7 @@ uicb_client_togglehorizontalmax(awesome_config *awesomeconf, int screen, const char *arg __attribute__ ((unused))) { - Client *sel = get_current_tag(awesomeconf->screens[screen])->client_sel; + Client *sel = awesomeconf->focus->client; ScreenInfo *si = get_screen_info(awesomeconf->display, screen, &awesomeconf->screens[screen].statusbar, &awesomeconf->screens[screen].padding); if(sel) @@ -319,7 +321,7 @@ uicb_client_zoom(awesome_config *awesomeconf, int screen, const char *arg __attribute__ ((unused))) { - Client *sel = get_current_tag(awesomeconf->screens[screen])->client_sel; + Client *sel = awesomeconf->focus->client; if(awesomeconf->clients == sel) for(sel = sel->next; sel && !client_isvisible(sel, &awesomeconf->screens[screen], screen); sel = sel->next); diff --git a/mouse.c b/mouse.c index a3ba0dd64..8a15a22e5 100644 --- a/mouse.c +++ b/mouse.c @@ -36,7 +36,7 @@ uicb_client_movemouse(awesome_config *awesomeconf, int screen, const char *arg _ Window dummy; XEvent ev; ScreenInfo *si; - Client *c = get_current_tag(awesomeconf->screens[screen])->client_sel; + Client *c = awesomeconf->focus->client; if(!c) return; @@ -96,7 +96,7 @@ uicb_client_resizemouse(awesome_config *awesomeconf, int screen, const char *arg { int ocx, ocy, nw, nh; XEvent ev; - Client *c = get_current_tag(awesomeconf->screens[screen])->client_sel; + Client *c = awesomeconf->focus->client; if(!c) return; diff --git a/screen.c b/screen.c index 3595519ed..f69f627c4 100644 --- a/screen.c +++ b/screen.c @@ -261,8 +261,7 @@ uicb_screen_focus(awesome_config *awesomeconf, int screen, const char *arg) if (new_screen > (numscreens - 1)) new_screen = 0; - focus(get_current_tag(awesomeconf->screens[new_screen])->client_sel, - True, awesomeconf, new_screen); + focus(awesomeconf->focus->client, True, awesomeconf, new_screen); move_mouse_pointer_to_screen(awesomeconf->display, new_screen); } @@ -274,11 +273,11 @@ uicb_screen_focus(awesome_config *awesomeconf, int screen, const char *arg) */ void uicb_client_movetoscreen(awesome_config * awesomeconf, - int screen, + int screen __attribute__ ((unused)), const char *arg) { int new_screen, prev_screen; - Client *sel = get_current_tag(awesomeconf->screens[screen])->client_sel; + Client *sel = awesomeconf->focus->client; if(!sel || !XineramaIsActive(awesomeconf->display)) return; diff --git a/statusbar.c b/statusbar.c index 820e22d4b..08a2c22f5 100644 --- a/statusbar.c +++ b/statusbar.c @@ -51,7 +51,7 @@ void statusbar_draw(awesome_config *awesomeconf, int screen) { int z, x = 0, y = 0, w; - Client *sel = get_current_tag(awesomeconf->screens[screen])->client_sel; + Client *sel = awesomeconf->focus->client; Drawable drawable; int phys_screen = get_phys_screen(awesomeconf->display, screen); Tag *tag; diff --git a/tag.c b/tag.c index 7098503b3..cad96a163 100644 --- a/tag.c +++ b/tag.c @@ -75,11 +75,7 @@ untag_client(TagClientLink **head, Client *c, Tag *t) for(tc = *head; tc; tc = tc->next) if(tc->client == c && tc->tag == t) - { detach_tagclientlink(head, tc); - if(t->client_sel == c) - t->client_sel = NULL; - } } Bool @@ -144,7 +140,7 @@ uicb_client_tag(awesome_config *awesomeconf, { int tag_id = -1; Tag *tag, *target_tag; - Client *sel = get_current_tag(awesomeconf->screens[screen])->client_sel; + Client *sel = awesomeconf->focus->client; if(!sel) return; @@ -181,8 +177,8 @@ uicb_client_togglefloating(awesome_config * awesomeconf, int screen, const char *arg __attribute__ ((unused))) { - Client *sel = get_current_tag(awesomeconf->screens[screen])->client_sel; - + Client *sel = awesomeconf->focus->client; + if(!sel) return; @@ -206,7 +202,7 @@ uicb_client_toggletag(awesome_config *awesomeconf, int screen, const char *arg) { - Client *sel = get_current_tag(awesomeconf->screens[screen])->client_sel; + Client *sel = awesomeconf->focus->client; int i; Tag *tag, *target_tag;