diff --git a/CMakeLists.txt b/CMakeLists.txt index f47316c..21345e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,10 +51,10 @@ set(wmfs_src add_executable(wmfs ${wmfs_src}) # Set the version -set(VERSION "WMFS-200910") +set(VERSION "WMFS-201001") # FLAGS -set(CFLAGS "-g -Wall -ansi") +set(CFLAGS "-g -Wall -lpthread -ansi") set(CMAKE_C_FLAGS ${CFLAGS}) # Linker FLAGS diff --git a/rc/status.sh b/rc/status.sh new file mode 100755 index 0000000..bd07953 --- /dev/null +++ b/rc/status.sh @@ -0,0 +1,13 @@ +#!/bin/sh +#WMFS status.sh example file +#Will be executed if put in ~/.config/wmfs/ +#Timing adjustable in wmfsrc (misc -> status_timing) + +statustext() +{ + local DATE=`date` + + wmfs -s "$DATE" +} + +statustext diff --git a/src/client.c b/src/client.c index 34d5254..9bed5d0 100644 --- a/src/client.c +++ b/src/client.c @@ -193,6 +193,33 @@ uicb_client_swap_prev(uicb_t cmd) return; } +/** Set the client c above + *\param c Client pointer +*/ +void +client_above(Client *c) +{ + XRectangle geo = { 0 }; + + if(c->flags & AboveFlag) + return; + + c->flags |= AboveFlag; + + geo.height = spgeo[c->screen].height * 0.75; + geo.width = spgeo[c->screen].width * 0.75; + + geo.y = spgeo[c->screen].y + (spgeo[c->screen].height / 2) - (geo.height / 2); + geo.x = spgeo[c->screen].x + (spgeo[c->screen].width / 2)- (geo.width / 2); + + client_moveresize(c, geo, tags[c->screen][c->tag].resizehint); + client_raise(c); + + tags[c->screen][c->tag].layout.func(c->screen); + + return; +} + /** Set the focus to a client * \param c Client pointer */ @@ -207,15 +234,18 @@ client_focus(Client *c) sel->colors.frame = conf.client.bordernormal; sel->colors.fg = conf.titlebar.fg_normal; sel->colors.resizecorner = conf.client.resizecorner_normal; + if(TBARH - BORDH && sel->titlebar->stipple) sel->titlebar->stipple_color = conf.titlebar.stipple.colors.normal; + + if(sel->flags & AboveFlag) + sel->flags &= ~AboveFlag; + frame_update(sel); mouse_grabbuttons(sel, False); } - sel = c; - - if(c) + if((sel = c)) { c->colors.frame = conf.client.borderfocus; c->colors.fg = conf.titlebar.fg_focus; @@ -235,6 +265,10 @@ client_focus(Client *c) client_raise(c); } + if(tags[sel->screen][sel->tag].abovefc + && !conf.focus_fmouse) + client_above(sel); + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); } else @@ -558,7 +592,7 @@ client_manage(Window w, XWindowAttributes *wa, Bool ar) if(ar) arrange(c->screen, True); - if(conf.client.set_new_win_master) + if(!conf.client.set_new_win_master) layout_set_client_master(c); return c; @@ -842,7 +876,7 @@ client_update_attributes(Client *c) void client_raise(Client *c) { - if(!c || (c->flags & TileFlag)) + if(!c || ((c->flags & TileFlag) && !(c->flags & AboveFlag))) return; XRaiseWindow(dpy, c->frame); @@ -883,6 +917,8 @@ void client_unmanage(Client *c) { Client *c_next = NULL; + Bool b = False; + int i; XGrabServer(dpy); XSetErrorHandler(errorhandlerdummy); @@ -900,7 +936,11 @@ client_unmanage(Client *c) ewmh_get_client_list(); /* Arrange */ - if(c->tag == seltag[selscreen] && c->screen == selscreen) + for(i = 0; i < screen_count() && !b; ++i) + if(c->tag == seltag[i]) + b = True; + + if(b) tags[c->screen][c->tag].layout.func(c->screen); else { diff --git a/src/config.c b/src/config.c index 5829cec..d59b6fe 100644 --- a/src/config.c +++ b/src/config.c @@ -63,6 +63,7 @@ func_name_list_t tmp_func_list[] = {"mouse_resize", uicb_mouse_resize }, {"client_raise", uicb_client_raise }, {"toggle_free", uicb_togglefree }, + {"toggle_abovefc", uicb_toggle_abovefc }, {"screen_select", uicb_screen_select }, {"screen_next", uicb_screen_next }, {"screen_prev", uicb_screen_prev }, @@ -135,11 +136,12 @@ conf_misc_section(char *src) cfg_set_sauv(src); - conf.font = get_opt(src, "sans-9", "font").str; - conf.raisefocus = get_opt(src, "false", "raisefocus").bool; - conf.raiseswitch = get_opt(src, "false", "raiseswitch").bool; - conf.focus_fmouse = get_opt(src, "true", "focus_follow_mouse").bool; - pad = get_opt(src, "12", "pad").num; + conf.font = get_opt(src, "sans-9", "font").str; + conf.raisefocus = get_opt(src, "false", "raisefocus").bool; + conf.raiseswitch = get_opt(src, "false", "raiseswitch").bool; + conf.focus_fmouse = get_opt(src, "true", "focus_follow_mouse").bool; + conf.status_timing = get_opt(src, "1", "status_timing").num; + pad = get_opt(src, "12", "pad").num; if(pad > 24 || pad < 1) { @@ -150,6 +152,12 @@ conf_misc_section(char *src) conf.pad = pad; + if(conf.status_timing <= 0) + { + warnx("configuration : status_timing value (%d) incorrect.", conf.status_timing); + conf.status_timing = 1; + } + return; } @@ -206,7 +214,7 @@ conf_client_section(char *src) conf.client.resizecorner_normal = getcolor(get_opt(src, "#222222", "resize_corner_normal").str); conf.client.resizecorner_focus = getcolor(get_opt(src, "#DDDDDD", "resize_corner_focus").str); conf.client.mod |= char_to_modkey(get_opt(src, "Alt", "modifier").str, key_list); - conf.client.set_new_win_master = get_opt(src, "false", "set_new_win_master").bool; + conf.client.set_new_win_master = get_opt(src, "true", "set_new_win_master").bool; if((conf.client.nmouse = get_size_sec(src, "mouse"))) { @@ -369,7 +377,7 @@ conf_tag_section(char *src) * MAXTAG (32) print an error and create only one. */ Tag default_tag = { "WMFS", NULL, 0, 1, - 0.50, 1, False, False, IB_Top, + 0.50, 1, False, False, False, IB_Top, layout_name_to_struct(conf.layout, "tile_right", conf.nlayout, layout_list) }; cfg_set_sauv(src); @@ -413,6 +421,7 @@ conf_tag_section(char *src) tags[k][conf.ntag[k]].mwfact = get_opt(cfgtmp, "0.65", "mwfact").fnum; tags[k][conf.ntag[k]].nmaster = get_opt(cfgtmp, "1", "nmaster").num; tags[k][conf.ntag[k]].resizehint = get_opt(cfgtmp, "false", "resizehint").bool; + tags[k][conf.ntag[k]].abovefc = get_opt(cfgtmp, "false", "abovefc").bool; tags[k][conf.ntag[k]].layers = 1; tmp = _strdup(get_opt(cfgtmp, "top", "infobar_position").str); diff --git a/src/event.c b/src/event.c index 96465e1..ddc0566 100644 --- a/src/event.c +++ b/src/event.c @@ -151,7 +151,7 @@ clientmessageevent(XClientMessageEvent *ev) if(ev->format != 32) return; - for(i = 0; i < net_last; ++i) + for(i = 0; i < net_last + screen_count(); ++i) if(net_atom[i] == ev->message_type) mess_t = i; @@ -231,6 +231,10 @@ clientmessageevent(XClientMessageEvent *ev) screen_get_sel(); } + if(mess_t == wmfs_update_status + && estatus) + spawn(status_path); + return; } @@ -253,7 +257,7 @@ configureevent(XConfigureRequestEvent *ev) CHECK(!(c->flags & FSSFlag)); } - if((c= client_gb_win(ev->window))) + if((c = client_gb_win(ev->window))) { if(ev->value_mask & CWX) c->geo.x = ev->x + BORDH; @@ -264,7 +268,8 @@ configureevent(XConfigureRequestEvent *ev) if(ev->value_mask & CWHeight) c->geo.height = ev->height; - client_moveresize(c, c->geo, False); + if(c->flags & FreeFlag) + client_moveresize(c, c->geo, False); } else { @@ -316,14 +321,15 @@ enternotify(XCrossingEvent *ev) if(conf.focus_fmouse) { if((c = client_gb_win(ev->window)) - || (c = client_gb_frame(ev->window)) - || (c = client_gb_titlebar(ev->window)) - || (c = client_gb_button(ev->window, &n))) + || (c = client_gb_frame(ev->window)) + || (c = client_gb_titlebar(ev->window)) + || (c = client_gb_button(ev->window, &n))) client_focus(c); else client_focus(NULL); } + return; } diff --git a/src/ewmh.c b/src/ewmh.c index ff5ccac..e4178ac 100644 --- a/src/ewmh.c +++ b/src/ewmh.c @@ -47,7 +47,7 @@ ewmh_init_hints(void) char class[] = "wmfs", st[64]; long pid = (long)getpid(); - net_atom = emalloc(net_last + screen_count() + 1, sizeof(Atom)); + net_atom = emalloc(net_last + screen_count(), sizeof(Atom)); /* EWMH hints */ net_atom[net_supported] = ATOM("_NET_SUPPORTED"); @@ -80,6 +80,7 @@ ewmh_init_hints(void) /* WMFS hints */ net_atom[wmfs_running] = ATOM("_WMFS_RUNNING"); net_atom[wmfs_update_hints] = ATOM("_WMFS_UPDATE_HINTS"); + net_atom[wmfs_update_status] = ATOM("_WMFS_UPDATE_STATUS"); net_atom[wmfs_set_screen] = ATOM("_WMFS_SET_SCREEN"); net_atom[wmfs_screen_count] = ATOM("_WMFS_SCREEN_COUNT"); net_atom[wmfs_current_tag] = ATOM("_WMFS_CURRENT_TAG"); @@ -98,9 +99,8 @@ ewmh_init_hints(void) net_atom[wmfs_statustext + j] = ATOM(st); } - XChangeProperty(dpy, ROOT, net_atom[net_supported], XA_ATOM, 32, - PropModeReplace, (uchar*)net_atom, net_last); + PropModeReplace, (uchar*)net_atom, net_last + screen_count()); XChangeProperty(dpy, ROOT, net_atom[wmfs_running], XA_CARDINAL, 32, PropModeReplace, (uchar*)&i, 1); diff --git a/src/init.c b/src/init.c index e88f768..ae58bb4 100644 --- a/src/init.c +++ b/src/init.c @@ -48,6 +48,7 @@ init(void) init_root(); screen_init_geo(); infobar_init(); + init_status(); ewmh_update_current_tag_prop(); grabkeys(); @@ -189,4 +190,38 @@ init_layout(void) return; } +/** Init statustext shell script + */ +void +init_status(void) +{ + int fd; + struct stat st; + + status_path = emalloc(strlen(getenv("HOME")) + strlen(DEF_STATUS) + 2, sizeof(char)); + + sprintf(status_path, "%s/"DEF_STATUS, getenv("HOME")); + + if(!(fd = open(status_path, O_RDONLY))) + { + free(status_path); + + return; + } + + stat(status_path, &st); + + if(st.st_mode & S_IXUSR) + { + estatus = True; + system(status_path); + } + else + warnx("status.sh file present in wmfs directory can't be executed, try 'chmod +x %s'.", + status_path); + + close(fd); + + return; +} diff --git a/src/layout.c b/src/layout.c index 3bd7316..7704029 100644 --- a/src/layout.c +++ b/src/layout.c @@ -168,6 +168,7 @@ tiled_client(int screen, Client *c) for(;c && ((c->flags & MaxFlag) || (c->flags & FreeFlag) || (c->flags & FSSFlag) + || (c->flags & AboveFlag) || c->screen != screen || ishide(c, screen)); c = c->next); @@ -830,6 +831,35 @@ uicb_toggle_resizehint(uicb_t cmd) return; } +/** Toggle abovefc option + *\param cmd uicb_t type + */ +void +uicb_toggle_abovefc(uicb_t cmd) +{ + Client *c; + + screen_get_sel(); + + if(!(tags[selscreen][seltag[selscreen]].abovefc = !tags[selscreen][seltag[selscreen]].abovefc)) + { + for(c = clients; c; c = c->next) + if(c->flags & AboveFlag + && c->screen == selscreen + && c->tag == seltag[selscreen]) + { + c->flags &= ~AboveFlag; + break; + } + + tags[selscreen][seltag[selscreen]].layout.func(selscreen); + } + + client_focus(sel); + + return; +} + /** Set the layout * \param cmd uicb_t type */ diff --git a/src/structs.h b/src/structs.h index 150e2b5..e5190f3 100644 --- a/src/structs.h +++ b/src/structs.h @@ -48,6 +48,7 @@ #define UnmapFlag (1 << 6) #define HintFlag (1 << 7) #define FSSFlag (1 << 8) +#define AboveFlag (1 << 9) /* XEMBED messages */ #define XEMBED_MAPPED (1 << 0) @@ -119,6 +120,7 @@ enum /* WMFS HINTS */ wmfs_running, wmfs_update_hints, + wmfs_update_status, wmfs_current_tag, wmfs_current_screen, wmfs_current_layout, @@ -248,6 +250,7 @@ typedef struct int nmaster; Bool resizehint; Bool request_update; + Bool abovefc; int barpos; Layout layout; } Tag; @@ -319,6 +322,7 @@ typedef struct Bool raiseswitch; Bool focus_fmouse; uint pad; + int status_timing; struct { /* diff --git a/src/wmfs.c b/src/wmfs.c index 134f900..1b768b6 100644 --- a/src/wmfs.c +++ b/src/wmfs.c @@ -136,15 +136,53 @@ quit(void) return; } +void * +thread_process(void *arg) +{ + XEvent ev; + + /* X event loop */ + if(!(int*)arg) + { + while(!exiting && !XNextEvent(dpy, &ev)) + getevent(ev); + + pthread_exit(0); + } + + /* Status checking loop with timing */ + else + { + while(!exiting) + { + spawn(status_path); + sleep(conf.status_timing); + } + + pthread_exit(0); + } +} + /** WMFS main loop. */ void mainloop(void) { XEvent ev; + pthread_t evloop, evstatus; + void *ret; - while(!exiting && !XNextEvent(dpy, &ev)) - getevent(ev); + if(!estatus) + while(!exiting && !XNextEvent(dpy, &ev)) + getevent(ev); + else + { + pthread_create(&evloop, NULL, thread_process, "1"); + pthread_create(&evstatus, NULL, thread_process, NULL); + + (void)pthread_join(evloop, &ret); + (void)pthread_join(evstatus, &ret); + } return; } @@ -347,6 +385,23 @@ set_statustext(int s, char *str) return; } +/** Update status script by ewmh hint + */ +void +update_status(void) +{ + long data[5]; + + if(!check_wmfs_running()) + return; + + data[4] = True; + + send_client_event(data, "_WMFS_UPDATE_STATUS"); + + return; +} + /** Signal handle function */ void @@ -368,12 +423,12 @@ int main(int argc, char **argv) { int i; - char *ol = "csgV"; + char *ol = "csgVS"; argv_global = _strdup(argv[0]); sprintf(conf.confpath, "%s/"DEF_CONF, getenv("HOME")); - while((i = getopt(argc, argv, "hvic:s:g:C:V:")) != -1) + while((i = getopt(argc, argv, "hviSc:s:g:C:V:")) != -1) { /* For options who need WMFS running */ @@ -384,12 +439,13 @@ main(int argc, char **argv) { case 'h': default: - printf("usage: %s [-ihv] [-C ] [-c ] [-g ] [-s ] [-V ] [-c ] [-g ] [-s ] [-V Load a configuration file\n" " -c Execute an uicb function to control WMFS\n" " -g Show information about wmfs status\n" " -s Set the bar(s) statustext\n" " -V Manage WMFS with vi-like command\n" + " -S Update status script\n" " -h Show this page\n" " -i Show informations\n" " -v Show WMFS version\n", argv[0]); @@ -402,7 +458,7 @@ main(int argc, char **argv) break; case 'v': - printf("WMFS version : "WMFS_VERSION".\n" + printf("WMFS version : "WMFS_VERSION"\n" " Compilation settings :\n" " - Flags : "WMFS_COMPILE_FLAGS"\n" " - Linked Libs : "WMFS_LINKED_LIBS"\n" @@ -410,6 +466,12 @@ main(int argc, char **argv) exit(EXIT_SUCCESS); break; + case 'S': + update_status(); + XCloseDisplay(dpy); + exit(EXIT_SUCCESS); + break; + case 'C': strcpy(conf.confpath, optarg); break; diff --git a/src/wmfs.h b/src/wmfs.h index 5b75d91..d3bbc35 100644 --- a/src/wmfs.h +++ b/src/wmfs.h @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -84,6 +85,7 @@ #define RESHW (6 * BORDH) #define BUTTONWH (TBARH / 2) #define DEF_CONF ".config/wmfs/wmfsrc" +#define DEF_STATUS ".config/wmfs/status.sh" #define PAD conf.pad #define CWIN(win, parent, x, y, w, h, b, mask, col, at) \ @@ -140,6 +142,7 @@ void uicb_infobar_togglepos(uicb_t); void client_attach(Client *c); void client_configure(Client *c); void client_detach(Client *c); +void client_above(Client *c); void client_focus(Client *c); Client* client_get_next(void); Client* client_get_prev(void); @@ -301,6 +304,7 @@ void uicb_set_mwfact(uicb_t); void uicb_set_nmaster(uicb_t); void uicb_set_layout(uicb_t); void uicb_toggle_resizehint(uicb_t); +void uicb_toggle_abovefc(uicb_t cmd); void uicb_set_layer(uicb_t cmd); void uicb_set_client_layer(uicb_t cmd); void layout_set_client_master(Client *c); @@ -314,6 +318,7 @@ void init_gc(void); void init_cursor(void); void init_key(void); void init_geometry(void); +void init_status(void); /* getinfo.c */ void getinfo_tag(void); @@ -330,11 +335,13 @@ void viwmfs(int argc, char **argv); int errorhandler(Display *d, XErrorEvent *event); int errorhandlerdummy(Display *d, XErrorEvent *event); void quit(void); +void *thread_process(void *arg); void mainloop(void); void scan(void); Bool check_wmfs_running(void); void exec_uicb_function(char *func, char *cmd); void set_statustext(int s, char *str); +void update_status(void); void handle_signal(int signum); void uicb_quit(uicb_t); void uicb_reload(uicb_t); @@ -347,12 +354,13 @@ GC gc, gc_stipple; int selscreen; Conf conf; Key *keys; -Bool exiting; +Bool exiting, estatus; XRectangle *sgeo; XRectangle *spgeo; Cursor cursor[CurLast]; -char *argv_global; +char *argv_global, *status_path; int xrandr_event; +uint timing; /* Fonts */ XftFont *font; diff --git a/wmfs.1 b/wmfs.1 index 7f0a3f9..5721d96 100644 --- a/wmfs.1 +++ b/wmfs.1 @@ -13,7 +13,7 @@ .SH "NAME" wmfs \- Window Manager From Scratch .SH "SYNOPSIS" -\fBwmfs\fR [\fB\-ihv\fR] [\fB\-C \fR] [\fB\-c \fR] [\fB\-g \fR] [\fB\-s \fR] [\fB\-V \fR] +\fBwmfs\fR [\fB\-ihvS\fR] [\fB\-C \fR] [\fB\-c \fR] [\fB\-g \fR] [\fB\-s \fR] [\fB\-V \fR] .sp .SH "DESCRIPTION" \fBWMFS\fR is a basic, lightweight and dynamic tiling windows manager for X\&. @@ -45,6 +45,11 @@ Set the bar(s) statustext. If the screen number is not specified, the string wil Manage WMFS with vi-like command\&. .RE .PP +\fB\-S\fR +.RS 4 +Update status script\&. +.RE +.PP \fB\-v\fR .RS 4 Print version information to standard output, then exit\&.