From f8d1049240b8127c2f6a266ef7db0e0dc080cfcb Mon Sep 17 00:00:00 2001 From: Martin Duquesnoy Date: Sun, 14 Dec 2008 15:43:21 +0100 Subject: [PATCH] New feature: EWMH Support ! #1 --- CMakeLists.txt | 1 + src/barwin.c | 8 +- src/client.c | 46 ++++++++-- src/draw.c | 8 +- src/event.c | 54 ++++++++++-- src/ewmh.c | 232 +++++++++++++++++++++++++++++++++++++++++++++++++ src/frame.c | 2 +- src/infobar.c | 2 +- src/init.c | 18 ++-- src/layout.c | 56 +++++------- src/mouse.c | 8 +- src/screen.c | 2 +- src/structs.h | 29 ++++++- src/tag.c | 1 + src/util.c | 26 +----- src/wmfs.c | 2 +- src/wmfs.h | 22 +++-- 17 files changed, 410 insertions(+), 107 deletions(-) create mode 100644 src/ewmh.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d9944c..e2b0971 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ set(wmfs_src src/config.c src/draw.c src/event.c + src/ewmh.c src/frame.c src/infobar.c src/init.c diff --git a/src/barwin.c b/src/barwin.c index 09a676c..b888ee4 100644 --- a/src/barwin.c +++ b/src/barwin.c @@ -68,10 +68,10 @@ barwin_create(Window parent, at.event_mask |= EnterWindowMask|LeaveWindowMask|FocusChangeMask; /* Create window */ - bw->win = XCreateWindow(dpy, parent, x, y, w, h, 0, DefaultDepth(dpy, screen), - CopyFromParent, DefaultVisual(dpy, screen), + bw->win = XCreateWindow(dpy, parent, x, y, w, h, 0, DefaultDepth(dpy, SCREEN), + CopyFromParent, DefaultVisual(dpy, SCREEN), CWOverrideRedirect | CWBackPixmap | CWEventMask, &at); - bw->dr = XCreatePixmap(dpy, parent, w, h, DefaultDepth(dpy, screen)); + bw->dr = XCreatePixmap(dpy, parent, w, h, DefaultDepth(dpy, SCREEN)); /* His border */ CWIN(bw->border.left, bw->win, 0, 0, SHADH, h, 0, CWBackPixel, color_enlight(color), &at); @@ -211,7 +211,7 @@ barwin_resize(BarWindow *bw, uint w, uint h) XFreePixmap(dpy, bw->dr); /* Frame */ - bw->dr = XCreatePixmap(dpy, root, w - SHADH, h - SHADH, DefaultDepth(dpy, screen)); + bw->dr = XCreatePixmap(dpy, ROOT, w - SHADH, h - SHADH, DefaultDepth(dpy, SCREEN)); XResizeWindow(dpy, bw->win, w, h); /* Border */ diff --git a/src/client.c b/src/client.c index 8d4cc34..f7e53b9 100644 --- a/src/client.c +++ b/src/client.c @@ -161,7 +161,7 @@ client_focus(Client *c) XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); } else - XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XSetInputFocus(dpy, ROOT, RevertToPointerRoot, CurrentTime); return; } @@ -369,7 +369,7 @@ client_manage(Window w, XWindowAttributes *wa) uint duint; Window dw; - XQueryPointer(dpy, root, &dw, &dw, &mx, &my, &dint, &dint, &duint); + XQueryPointer(dpy, ROOT, &dw, &dw, &mx, &my, &dint, &dint, &duint); mx += BORDH; my += TBARH; @@ -393,12 +393,11 @@ client_manage(Window w, XWindowAttributes *wa) my += sgeo[selscreen].y - TBARH - INFOBARH; } } - c->ogeo.x = c->geo.x = mx; c->ogeo.y = c->geo.y = my; - c->ogeo.width = c->geo.width = wa->width; c->ogeo.height = c->geo.height = wa->height; + c->tag = seltag[c->screen]; at.event_mask = PropertyChangeMask; @@ -419,6 +418,7 @@ client_manage(Window w, XWindowAttributes *wa) client_raise(c); client_focus(c); setwinstate(c->win, NormalState); + ewmh_manage_window_type(c); arrange(); return; @@ -487,7 +487,7 @@ client_moveresize(Client *c, XRectangle geo, bool r) || c->geo.width != geo.width || c->geo.height != geo.height) { - c->geo = geo; + c->geo = c->ogeo = geo; /* Set the client screen */ c->screen = screen_get_with_geo(geo.x, geo.y); @@ -501,6 +501,38 @@ client_moveresize(Client *c, XRectangle geo, bool r) return; } +/** Maximize a client + * \param c Client pointer +*/ +void +client_maximize(Client *c) +{ + CHECK(c); + + XRectangle geo; + + c->screen = screen_get_with_geo(c->geo.x, c->geo.y); + + geo.x = sgeo[c->screen].x; + geo.y = sgeo[c->screen].y; + geo.width = sgeo[c->screen].width - BORDH * 2; + geo.height = sgeo[c->screen].height - BORDH * 2; + + if(c->state_fullscreen) + { + geo.y -= TBARH + INFOBARH + BORDH; + geo.height += TBARH + INFOBARH + (BORDH * 2); + client_moveresize(c, geo, False); + XMoveResizeWindow(dpy, c->win, 0, BORDH + TBARH, c->geo.width + BORDH * 2, c->geo.height); + } + else + client_moveresize(c, geo, False); + + client_raise(c); + + return; +} + /** Get client size hints * \param c Client pointer */ @@ -580,7 +612,7 @@ client_size_hints(Client *c) void client_raise(Client *c) { - if(!c || c->max || c->tile) + if(!c || c->tile) return; XRaiseWindow(dpy, c->frame); @@ -622,7 +654,7 @@ client_unmanage(Client *c) { XGrabServer(dpy); XSetErrorHandler(errorhandlerdummy); - XReparentWindow(dpy, c->win, root, c->geo.x, c->geo.y); + XReparentWindow(dpy, c->win, ROOT, c->geo.x, c->geo.y); if(sel == c) client_focus(NULL); diff --git a/src/draw.c b/src/draw.c index d42c77d..05b0103 100644 --- a/src/draw.c +++ b/src/draw.c @@ -47,17 +47,17 @@ draw_text(Drawable d, int x, int y, char* fg, int pad, char *str) XftDraw *xftd; /* Transform X Drawable -> Xft Drawable */ - xftd = XftDrawCreate(dpy, d, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen)); + xftd = XftDrawCreate(dpy, d, DefaultVisual(dpy, SCREEN), DefaultColormap(dpy, SCREEN)); /* Alloc text color */ - XftColorAllocName(dpy, DefaultVisual(dpy, screen), - DefaultColormap(dpy, screen), fg, &xftcolor); + XftColorAllocName(dpy, DefaultVisual(dpy, SCREEN), + DefaultColormap(dpy, SCREEN), fg, &xftcolor); /* Draw the text */ XftDrawStringUtf8(xftd, &xftcolor, font, x, y, (FcChar8 *)str, strlen(str)); /* Free the text color and XftDraw */ - XftColorFree(dpy, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen), &xftcolor); + XftColorFree(dpy, DefaultVisual(dpy, SCREEN), DefaultColormap(dpy, SCREEN), &xftcolor); XftDrawDestroy(xftd); diff --git a/src/event.c b/src/event.c index a30bc1e..f53464f 100644 --- a/src/event.c +++ b/src/event.c @@ -63,7 +63,7 @@ buttonpress(XButtonEvent *ev) conf.client.mouse[i].func(conf.client.mouse[i].cmd); /* Root */ - if(ev->window == root) + if(ev->window == ROOT) for(i = 0; i < conf.root.nmouse; ++i) if(conf.root.mouse[i].tag == seltag[conf.root.mouse[i].screen] || conf.root.mouse[i].tag < 0) @@ -102,6 +102,45 @@ buttonpress(XButtonEvent *ev) return; } +/* ClientMessage handle event + *\param ev XClientMessageEvent pointer +*/ +void +clientmessageevent(XClientMessageEvent *ev) +{ + Client *c; + int i, mess_t = 0; + + if(ev->format != 32) + return; + + for(i = 0; i < net_last; ++i) + if(net_atom[i] == ev->message_type) + mess_t = i; + if(ev->window == ROOT) + { + /* Manage _NET_CURRENT_DESKTOP */ + if(mess_t == net_current_desktop) + ewmh_get_current_desktop(); + /* Manage _NET_ACTIVE_WINDOW */ + if(mess_t == net_active_window) + if((c = client_gb_win(ev->data.l[0]))) + client_focus(c); + } + + if((c = client_gb_win(ev->window))) + { + /* Manage _NET_WM_STATE */ + if(mess_t == net_wm_state) + ewmh_manage_net_wm_state(ev->data.l, c); + /* Manage _NET_CLOSE_WINDOW */ + if(mess_t == net_close_window) + client_kill(c); + } + + return; +} + /** ConfigureRequest & ConfigureNotify handle event * \param ev XEvent pointer */ @@ -246,14 +285,14 @@ grabkeys(void) uint i; KeyCode code; - XUngrabKey(dpy, AnyKey, AnyModifier, root); + XUngrabKey(dpy, AnyKey, AnyModifier, ROOT); for(i = 0; i < conf.nkeybind; ++i) { code = XKeysymToKeycode(dpy, keys[i].keysym); - XGrabKey(dpy, code, keys[i].mod, root, True, GrabModeAsync, GrabModeAsync); - XGrabKey(dpy, code, keys[i].mod|LockMask, root, True, GrabModeAsync, GrabModeAsync); - XGrabKey(dpy, code, keys[i].mod|numlockmask, root, True, GrabModeAsync, GrabModeAsync); - XGrabKey(dpy, code, keys[i].mod|LockMask|numlockmask, root, True, GrabModeAsync, GrabModeAsync); + XGrabKey(dpy, code, keys[i].mod, ROOT, True, GrabModeAsync, GrabModeAsync); + XGrabKey(dpy, code, keys[i].mod|LockMask, ROOT, True, GrabModeAsync, GrabModeAsync); + XGrabKey(dpy, code, keys[i].mod|numlockmask, ROOT, True, GrabModeAsync, GrabModeAsync); + XGrabKey(dpy, code, keys[i].mod|LockMask|numlockmask, ROOT, True, GrabModeAsync, GrabModeAsync); } return; @@ -368,12 +407,12 @@ unmapnotify(XUnmapEvent *ev) void getevent(XEvent ev) { - int st; switch (ev.type) { case ButtonPress: buttonpress(&ev.xbutton); break; + case ClientMessage: clientmessageevent(&ev.xclient); break; case ConfigureRequest: configureevent(&ev); break; case DestroyNotify: destroynotify(&ev.xdestroywindow); break; case EnterNotify: enternotify(&ev.xcrossing); break; @@ -386,6 +425,7 @@ getevent(XEvent ev) case UnmapNotify: unmapnotify(&ev.xunmap); break; } + //ewmh_get_current_desktop(); wait(&st); return; diff --git a/src/ewmh.c b/src/ewmh.c new file mode 100644 index 0000000..0fabfa5 --- /dev/null +++ b/src/ewmh.c @@ -0,0 +1,232 @@ +/* +* ewmh.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" + +/* Took From standards.freedesktop.org */ +#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ +#define _NET_WM_STATE_ADD 1 /* add/set property */ +#define _NET_WM_STATE_TOGGLE 2 /* toggle property */ + +/** Init ewmh atoms +*/ +void +ewmh_init_hints(void) +{ + net_atom[net_supported] = ATOM("_NET_SUPPORTED"); + net_atom[net_number_of_desktops] = ATOM("_NET_NUMBER_OF_DESKTOPS"); + net_atom[net_current_desktop] = ATOM("_NET_CURRENT_DESKTOP"); + net_atom[net_desktop_names] = ATOM("_NET_DESKTOP_NAMES"); + net_atom[net_active_window] = ATOM("_NET_ACTIVE_WINDOW"); + net_atom[net_close_window] = ATOM("_NET_CLOSE_WINDOW"); + net_atom[net_wm_name] = ATOM("_NET_WM_NAME"); + net_atom[net_wm_icon_name] = ATOM("_NET_WM_ICON_NAME"); + net_atom[net_wm_window_type] = ATOM("_NET_WM_WINDOW_TYPE"); + net_atom[net_wm_window_type_normal] = ATOM("_NET_WM_WINDOW_TYPE_NORMAL"); + net_atom[net_wm_window_type_dock] = ATOM("_NET_WM_WINDOW_TYPE_DOCK"); + net_atom[net_wm_window_type_splash] = ATOM("_NET_WM_WINDOW_TYPE_SPLASH"); + net_atom[net_wm_window_type_dialog] = ATOM("_NET_WM_WINDOW_TYPE_DIALOG"); + net_atom[net_wm_icon] = ATOM("_NET_WM_ICON"); + net_atom[net_wm_state] = ATOM("_NET_WM_STATE"); + net_atom[net_wm_state_sticky] = ATOM("_NET_WM_STATE_STICKY"); + net_atom[net_wm_state_skip_taskbar] = ATOM("_NET_WM_STATE_SKIP_TASKBAR"); + net_atom[net_wm_state_fullscreen] = ATOM("_NET_WM_STATE_FULLSCREEN"); + net_atom[net_wm_state_demands_attention] = ATOM("_NET_WM_STATE_DEMANDS_ATTENTION"); + + XChangeProperty(dpy, ROOT, net_atom[net_supported], XA_ATOM, 32, + PropModeReplace, (uchar*)net_atom, net_last); + + return; +} + +/** Get the number of desktop (tag) +*/ +void +ewmh_get_number_of_desktop(void) +{ + int c = 0, i; + + for(i = 0; i < screen_count(); ++i) + c += conf.ntag[i]; + + XChangeProperty(dpy, ROOT, net_atom[net_number_of_desktops], XA_CARDINAL, 32, + PropModeReplace, (uchar*)&c, 1); + + return; +} + +/** Get the current desktop +*/ +void +ewmh_get_current_desktop(void) +{ + screen_get_sel(); + + /* Get current desktop (tag) */ + XChangeProperty(dpy, ROOT, net_atom[net_current_desktop], XA_CARDINAL, 32, + PropModeReplace, (uchar*)&seltag[selscreen], 1); + + return; +} + +/** The desktop names + */ +void +ewmh_get_desktop_names(void) +{ + char *str = NULL; + int s, i, len = 0, pos = 0; + + for(s = 0 ; s < screen_count(); ++s) + for(i = 1; i < conf.ntag[s] + 1; ++i) + len += strlen(tags[s][i].name); + + str = emalloc(len + i + 1, sizeof(char*)); + + for(s = 0; s < screen_count(); ++s) + for(i = 1; i < conf.ntag[s] + 1; ++i, ++pos) + { + strncpy(str + pos, tags[s][i].name, strlen(tags[s][i].name)); + pos += strlen(tags[s][i].name); + str[pos] = '\0'; + } + + XChangeProperty(dpy, ROOT, net_atom[net_desktop_names], XA_STRING, 8, + PropModeReplace, (uchar*)str, pos); + + free(str); + + return; +} + +/** Manage _NET_WM_STATE_* ewmh + */ +void +ewmh_manage_net_wm_state(long data_l[], Client *c) +{ + /* Manage _NET_WM_STATE_FULLSCREEN */ + if(data_l[1] == net_atom[net_wm_state_fullscreen]) + { + if(data_l[0] == _NET_WM_STATE_ADD && !c->state_fullscreen) + { + c->state_fullscreen = True; + c->tmp_geo = c->geo; + if(c->free) + c->ogeo = c->geo; + client_maximize(c); + } + else if(data_l[0] == _NET_WM_STATE_REMOVE && c->state_fullscreen) + { + c->state_fullscreen = False; + client_moveresize(c, c->tmp_geo, False); + tags[selscreen][seltag[selscreen]].layout.func(); + } + } + /* Manage _NET_WM_STATE_DEMANDS_ATTENTION */ + else if(data_l[1] == net_atom[net_wm_state_demands_attention]) + { + if(data_l[0] == _NET_WM_STATE_ADD) + client_focus(c); + if(data_l[0] == _NET_WM_STATE_REMOVE) + if(c == sel) + client_focus(NULL); + } + return; +} + + +/** Manage the client hints + *\param c Client pointer +*/ +void +ewmh_manage_window_type(Client *c) +{ + Atom *atom, rf; + int i, f; + ulong n, il; + uchar *data = NULL; + + if(XGetWindowProperty(dpy, c->win, net_atom[net_wm_window_type], 0L, 0x7FFFFFFFL, + False, XA_ATOM, &rf, &f, &n, &il, &data) == Success && n) + { + atom = (Atom*)data; + for(i = 0; i < n; ++i) + { + /* Manage _NET_WM_WINDOW_TYPE_DOCK & _NET_WM_WINDOW_TYPE_SPLASH */ + if(atom[i] == net_atom[net_wm_window_type_dock] + || atom[i] == net_atom[net_wm_window_type_splash]) + { + XReparentWindow(dpy, c->win, ROOT, c->geo.x, c->geo.y); + XUnmapSubwindows(dpy, c->frame); + XUnmapWindow(dpy, c->frame); + XRaiseWindow(dpy, c->win); + } + /* MANAGE _NET_WM_WINDOW_TYPE_DIALOG */ + else if(atom[i] == net_atom[net_wm_window_type_dialog]) + { + c->free = True; + sel->tile = sel->max = sel->lmax = False; + client_moveresize(sel, sel->ogeo, True); + client_focus(c); + tags[selscreen][seltag[selscreen]].layout.func(); + } + } + XFree(data); + } + + return; +} + + +/** Get a Window WM State + * \param win Window + * \return The state +*/ +long +ewmh_get_wm_state(Window win) +{ + Atom rt; + int rf; + long ret = WithdrawnState; + ulong ir, il; + uchar *data; + + if(XGetWindowProperty(dpy, win, net_atom[net_wm_state], 0L, 2L, + False, net_atom[net_wm_state], &rt, + &rf, &ir, &il, &data) == Success && ir) + { + ret = *(long *)data; + XFree(data); + } + + return ret; +} diff --git a/src/frame.c b/src/frame.c index 7252060..fd4af9d 100644 --- a/src/frame.c +++ b/src/frame.c @@ -59,7 +59,7 @@ frame_create(Client *c) c->colors.resizecorner = conf.client.resizecorner_normal; /* Create frame window */ - CWIN(c->frame, root, + CWIN(c->frame, ROOT, c->frame_geo.x, c->frame_geo.y, c->frame_geo.width, diff --git a/src/infobar.c b/src/infobar.c index d5ae7bd..c91c2d5 100644 --- a/src/infobar.c +++ b/src/infobar.c @@ -51,7 +51,7 @@ infobar_init(void) : sgeo[sc].height - INFOBARH; /* Create infobar barwindow */ - infobar[sc].bar = barwin_create(root, sgeo[sc].x - BORDH, infobar[sc].geo.y, + infobar[sc].bar = barwin_create(ROOT, sgeo[sc].x - BORDH, infobar[sc].geo.y, sgeo[sc].width, infobar[sc].geo.height, conf.colors.bar, False); /* Create tags window */ diff --git a/src/init.c b/src/init.c index 5239b2c..651096a 100644 --- a/src/init.c +++ b/src/init.c @@ -38,13 +38,13 @@ void init(void) { /* First init */ - gc = DefaultGC(dpy, screen); - screen = DefaultScreen(dpy); + gc = DefaultGC(dpy, SCREEN); init_font(); init_cursor(); init_key(); init_root(); screen_init_geo(); + ewmh_init_hints(); infobar_init(); grabkeys(); @@ -60,11 +60,11 @@ init(void) void init_font(void) { - font = XftFontOpenName(dpy, screen, conf.font); + font = XftFontOpenName(dpy, SCREEN, conf.font); if(!font) { fprintf(stderr, "WMFS Error: Cannot initialize font\n"); - font = XftFontOpenName(dpy, screen, "sans-10"); + font = XftFontOpenName(dpy, SCREEN, "sans-10"); } } @@ -105,21 +105,19 @@ void init_root(void) { XSetWindowAttributes at; - Atom data[] = { ATOM("_NET_SUPPORTED"), ATOM("_NET_WM_NAME") }; - - root = RootWindow(dpy, screen); at.event_mask = KeyMask|ButtonMask|MouseMask |SubstructureRedirectMask|SubstructureNotifyMask |EnterWindowMask|LeaveWindowMask|StructureNotifyMask; at.cursor = cursor[CurNormal]; - XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &at); + XChangeWindowAttributes(dpy, ROOT, CWEventMask | CWCursor, &at); if(conf.root.background_command) uicb_spawn(conf.root.background_command); - XChangeProperty(dpy, root, ATOM("_NET_SUPPORTED"), XA_ATOM, 32, - PropModeReplace, (uchar*)data, NetLast); + ewmh_init_hints(); + ewmh_get_number_of_desktop(); + ewmh_get_desktop_names(); return; } diff --git a/src/layout.c b/src/layout.c index abd112c..8dfe526 100644 --- a/src/layout.c +++ b/src/layout.c @@ -137,19 +137,12 @@ void maxlayout(void) { Client *c; - XRectangle geo; - XRectangle sg = sgeo[selscreen]; for(c = nexttiled(clients); c; c = nexttiled(c->next)) { c->tile = False; c->lmax = True; - geo.x = sg.x; - geo.y = sg.y; - geo.width = sg.width - BORDH * 2; - geo.height = sg.height - BORDH * 2; - - client_moveresize(c, geo, False); + client_maximize(c); } return; @@ -163,7 +156,11 @@ maxlayout(void) Client* nexttiled(Client *c) { - for(; c && (c->max || c->free || c->screen != selscreen || ishide(c)); c = c->next); + for(;c && (c->max + || c->free + || c->screen != selscreen + || c->state_fullscreen + || ishide(c)); c = c->next); return c; } @@ -449,7 +446,7 @@ uicb_tile_switch(uicb_t cmd) screen_get_sel(); - if(!sel || sel->hint || !sel->tile) + if(!sel || sel->hint || !sel->tile || sel->state_fullscreen) return; if((c = sel) == nexttiled(clients)) CHECK((c = nexttiled(c->next))); @@ -467,51 +464,44 @@ uicb_tile_switch(uicb_t cmd) void uicb_togglefree(uicb_t cmd) { - CHECK(sel); - if(!sel || sel->screen != screen_get_sel()) + if(!sel || sel->screen != screen_get_sel() || sel->state_fullscreen) return; sel->free = !sel->free; - sel->tile = False; - sel->max = False; - sel->lmax = False; - client_moveresize(sel, sel->ogeo, True); + + if(sel->free) + { + sel->tile = sel->max = sel->lmax = False; + client_moveresize(sel, sel->ogeo, True); + } + else + sel->ogeo = sel->geo; + tags[selscreen][seltag[selscreen]].layout.func(); return; } + /** Toggle the selected client to max * \param cmd uicb_t type unused */ void uicb_togglemax(uicb_t cmd) { - XRectangle geo; - XRectangle sg = sgeo[screen_get_sel()]; - - if(!sel || ishide(sel) || sel->hint) + if(!sel || ishide(sel) || sel->hint || sel->state_fullscreen) return; + if(!sel->max) { - geo.x = sg.x; - geo.y = sg.y; - geo.width = sg.width - BORDH * 2; - geo.height = sg.height - BORDH * 2; - - client_moveresize(sel, geo, False); - client_raise(sel); + sel->tile = sel->free = False; + client_maximize(sel); sel->max = True; } else if(sel->max) { - geo.x = sel->ogeo.x; - geo.y = sel->ogeo.y; - geo.width = sel->ogeo.width; - geo.height = sel->ogeo.height; - - client_moveresize(sel, geo, False); sel->max = False; + tags[selscreen][seltag[selscreen]].layout.func(); } return; diff --git a/src/mouse.c b/src/mouse.c index e8ac0e9..fd55f00 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -49,11 +49,11 @@ mouse_move(Client *c) if(c->max || c->tile || c->lmax) return; - if(XGrabPointer(dpy, root, False, MouseMask, GrabModeAsync, GrabModeAsync, + if(XGrabPointer(dpy, ROOT, False, MouseMask, GrabModeAsync, GrabModeAsync, None, cursor[CurMove], CurrentTime) != GrabSuccess) return; - XQueryPointer(dpy, root, &dw, &dw, &mx, &my, &dint, &dint, &duint); + XQueryPointer(dpy, ROOT, &dw, &dw, &mx, &my, &dint, &dint, &duint); for(;;) { @@ -94,8 +94,8 @@ mouse_resize(Client *c) if(c->max || c->lmax || c->tile) return; - if(XGrabPointer(dpy, root, False, MouseMask, GrabModeAsync, GrabModeAsync, - None, cursor[CurResize], CurrentTime) != GrabSuccess) + if(XGrabPointer(dpy, ROOT, False, MouseMask, GrabModeAsync, GrabModeAsync, + None, cursor[CurResize], CurrentTime) != GrabSuccess) return; XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->geo.width + conf.client.borderheight, c->geo.height); diff --git a/src/screen.c b/src/screen.c index 3c03e60..82de0b8 100644 --- a/src/screen.c +++ b/src/screen.c @@ -114,7 +114,7 @@ screen_get_sel(void) Window w; int d, u, x, y; - XQueryPointer(dpy, root, &w, &w, &x, &y, &d, &d, (uint *)&u); + XQueryPointer(dpy, ROOT, &w, &w, &x, &y, &d, &d, (uint *)&u); selscreen = screen_get_with_geo(x, y); } diff --git a/src/structs.h b/src/structs.h index f8fbda5..fe0b574 100644 --- a/src/structs.h +++ b/src/structs.h @@ -48,8 +48,30 @@ typedef unsigned char uchar; /* Enum */ enum { CurNormal, CurResize, CurMove, CurLast }; -enum { WMState, WMProtocols, WMName, WMDelete, WMLast }; -enum { NetSupported, NetWMName, NetLast }; +/* Ewmh hints list */ +enum +{ + net_supported, + net_wm_name, + net_number_of_desktops, + net_current_desktop, + net_desktop_names, + net_active_window, + net_close_window, + net_wm_icon_name, + net_wm_window_type, + net_wm_window_type_normal, + net_wm_window_type_dock, + net_wm_window_type_splash, + net_wm_window_type_dialog, + net_wm_icon, + net_wm_state, + net_wm_state_sticky, + net_wm_state_skip_taskbar, + net_wm_state_fullscreen, + net_wm_state_demands_attention, + net_last +}; typedef enum { Top, Bottom, Right, Left, Center, PositionLast } Position; /* @@ -84,6 +106,7 @@ struct Client int screen; /* Window attribute */ XRectangle geo; + XRectangle tmp_geo; XRectangle frame_geo; /* Old window attribute */ XRectangle ogeo; @@ -105,7 +128,7 @@ struct Client } colors; /* Client Layout Information */ Bool max, tile, free, hide; - Bool hint, lmax, unmapped; + Bool hint, lmax, unmapped, state_fullscreen; /* Struct in chains */ Client *next; Client *prev; diff --git a/src/tag.c b/src/tag.c index dc612cf..9a2c661 100644 --- a/src/tag.c +++ b/src/tag.c @@ -72,6 +72,7 @@ uicb_tag(uicb_t cmd) seltag[selscreen] = tmp; } } + ewmh_get_current_desktop(); arrange(); client_focus(NULL); diff --git a/src/util.c b/src/util.c index ee87bfd..64b7351 100644 --- a/src/util.c +++ b/src/util.c @@ -57,7 +57,7 @@ getcolor(char *color) { XColor xcolor; - if(!XAllocNamedColor(dpy, DefaultColormap(dpy, screen), color, &xcolor, &xcolor)) + if(!XAllocNamedColor(dpy, DefaultColormap(dpy, SCREEN), color, &xcolor, &xcolor)) fprintf(stderr,"WMFS Error: cannot allocate color \"%s\"\n", color); return xcolor.pixel; } @@ -78,30 +78,6 @@ color_enlight(ulong col) } -/** Get a Window WM State - * \param win Window - * \return The state -*/ -long -getwinstate(Window win) -{ - int f; - long ret = -1; - ulong n, e; - uchar *p = NULL; - Atom at; - - if(XGetWindowProperty(dpy, win, ATOM("WM_STATE"), 0L, 2L, False, - ATOM("WM_STATE"), &at, &f, &n, &e, (uchar **)&p) != Success) - return -1; - - if(n != 0) - ret = *p; - XFree(p); - - return ret; -} - /** Round function * \param x double type * \return the round of x diff --git a/src/wmfs.c b/src/wmfs.c index 26cde84..beb20c7 100644 --- a/src/wmfs.c +++ b/src/wmfs.c @@ -199,7 +199,7 @@ scan(void) XWindowAttributes wa; Window usl, usl2, *w = NULL; - if(XQueryTree(dpy, root, &usl, &usl2, &w, &n)) + if(XQueryTree(dpy, ROOT, &usl, &usl2, &w, &n)) for(i = 0; i < n; ++i) if(XGetWindowAttributes(dpy, w[i], &wa) && !(wa.override_redirect || XGetTransientForHint(dpy, w[i], &usl)) diff --git a/src/wmfs.h b/src/wmfs.h index 9a675d5..f22af09 100644 --- a/src/wmfs.h +++ b/src/wmfs.h @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -66,8 +67,10 @@ InputOutput, CopyFromParent, mask, at); \ XSetWindowBackground(dpy, win, col); -#define MAXH DisplayHeight(dpy, screen) -#define MAXW DisplayWidth(dpy, screen) +#define SCREEN DefaultScreen(dpy) +#define ROOT RootWindow(dpy, SCREEN) +#define MAXH DisplayHeight(dpy, DefaultScreen(dpy)) +#define MAXW DisplayWidth(dpy, DefaultScreen(dpy)) #define ATOM(a) XInternAtom(dpy, a, False) #define INFOBARH font->height * 1.5 #define SHADH 1 @@ -126,6 +129,7 @@ Bool ishide(Client *c); void client_map(Client *c); void client_manage(Window w, XWindowAttributes *wa); void client_moveresize(Client *c, XRectangle geo, bool r); +void client_maximize(Client *c); void client_size_hints(Client *c); void client_raise(Client *c); void client_unhide(Client *c); @@ -136,6 +140,15 @@ void uicb_client_prev(uicb_t); void uicb_client_next(uicb_t); void uicb_client_kill(uicb_t); +/* ewmh.c */ +void ewmh_init_hints(void); +void ewmh_get_number_of_desktop(void); +void ewmh_get_current_desktop(void); +void ewmh_get_desktop_names(void); +void ewmh_manage_net_wm_state(long data_l[], Client *c); +void ewmh_manage_window_type(Client *c); +long ewmh_get_wm_state(Window win); + /* frame.c */ void frame_create(Client *c); void frame_delete(Client *c); @@ -178,8 +191,6 @@ void uicb_mouse_resize(uicb_t); ulong color_enlight(ulong col); void *emalloc(uint element, uint size); ulong getcolor(char *color); -long getwinstate(Window win); -double round(double x); void setwinstate(Window win, long state); /* Conf usage {{{ */ void* name_to_func(char *name, func_name_list_t l[]); @@ -247,8 +258,6 @@ void uicb_reload(uicb_t); /* Principal */ Display *dpy; GC gc; -Window root; -int screen; int selscreen; Conf conf; Key *keys; @@ -259,6 +268,7 @@ Cursor cursor[CurLast]; /* Fonts */ XftFont *font; +Atom net_atom[net_last]; /* InfoBar */ InfoBar *infobar;