diff --git a/README.md b/README.md index 26cdee4..aecd4bf 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ Refer to [https://dwm.suckless.org/](https://dwm.suckless.org/) for details on t ### Changelog: +2019-10-10 - Added mdpcontrol patch + 2019-10-08 - Added columns layout and fakefullscreen patch 2019-10-07 - Added sortscreens and dwmc patches, fixed minor cross-compatibility issues for combo, holdbar, leftlayout, hidevacanttags, taggrid and activetagindicatorbar @@ -159,6 +161,9 @@ Refer to [https://dwm.suckless.org/](https://dwm.suckless.org/) for details on t - [maximize](https://dwm.suckless.org/patches/maximize/) - adds helper functions for maximizing, horizontally and vertically, floating windows using keybindings + - [mdpcontrol](https://dwm.suckless.org/patches/mpdcontrol/) + - adds keyboard bindings to control MDP (Music Player Daemon) + - monitorrules - adds rules per monitor, e.g. have default layouts per monitor - the use case for this is if the second monitor is vertical (i.e. rotated) then you may want to use a different default layout for this monitor than what is used for the main monitor (for example normal vertical split for main monitor and horizontal split for the second) diff --git a/config.def.h b/config.def.h index 41c23d5..8217e30 100644 --- a/config.def.h +++ b/config.def.h @@ -573,6 +573,11 @@ static Key keys[] = { { MODKEY|ControlMask, XK_comma, cyclelayout, {.i = -1 } }, { MODKEY|ControlMask, XK_period, cyclelayout, {.i = +1 } }, #endif // CYCLELAYOUTS_PATCH + #if MDPCONTROL_PATCH + { MODKEY, XK_F1, mpdchange, {.i = -1} }, + { MODKEY, XK_F2, mpdchange, {.i = +1} }, + { MODKEY, XK_Escape, mpdcontrol, {0} }, + #endif // MDPCONTROL_PATCH TAGKEYS( XK_1, 0) TAGKEYS( XK_2, 1) TAGKEYS( XK_3, 2) diff --git a/config.mk b/config.mk index 3cb1518..856d8ca 100644 --- a/config.mk +++ b/config.mk @@ -20,9 +20,13 @@ FREETYPEINC = /usr/include/freetype2 # OpenBSD (uncomment) #FREETYPEINC = ${X11INC}/freetype2 +# Uncomment this for the mdpcontrol patch / MDPCONTROL_PATCH +#LMPDCLIENT = -lmpdclient + # includes and libs INCS = -I${X11INC} -I${FREETYPEINC} -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lXrender +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lXrender ${LMPDCLIENT} + # flags CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} diff --git a/patch/include.c b/patch/include.c index d881deb..e86b053 100644 --- a/patch/include.c +++ b/patch/include.c @@ -68,6 +68,10 @@ #include "maximize.c" #endif +#if MDPCONTROL_PATCH +#include "mdpcontrol.c" +#endif + #if MOVESTACK_PATCH #include "movestack.c" #endif diff --git a/patch/include.h b/patch/include.h index 65feac9..c38f849 100644 --- a/patch/include.h +++ b/patch/include.h @@ -68,6 +68,10 @@ #include "maximize.h" #endif +#if MDPCONTROL_PATCH +#include "mdpcontrol.h" +#endif + #if MOVESTACK_PATCH #include "movestack.h" #endif diff --git a/patch/mdpcontrol.c b/patch/mdpcontrol.c new file mode 100644 index 0000000..b0d7352 --- /dev/null +++ b/patch/mdpcontrol.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include + +#include + +#define MPDHOST "localhost" +#define MPDPORT 6600 + +struct mpd_connection *get_conn(){ + struct mpd_connection *conn; + + conn = mpd_connection_new(MPDHOST, MPDPORT, 1000); + + if(mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS){ + fprintf(stderr, "Could not connect to mpd: %s\n", mpd_connection_get_error_message(conn)); + + mpd_connection_free(conn); + return NULL; + } + + return conn; +} + +void mpdchange(const Arg *direction){ + struct mpd_connection *conn; + + conn = get_conn(); + + if(conn == NULL){ + return; + } + + if(direction->i > 0){ + mpd_run_next(conn); + } + else{ + mpd_run_previous(conn); + } + + mpd_connection_free(conn); +} + +char *get_regerror(int errcode, regex_t *compiled){ + size_t length = regerror(errcode, compiled, NULL, 0); + char *buffer = malloc(length); + (void) regerror(errcode, compiled, buffer, length); + + return buffer; +} + +void mpdcontrol(){ + struct mpd_connection *conn; + struct mpd_status *status; + struct mpd_song *song; + enum mpd_state state; + + const char *filename; + + regex_t expr; + + conn = get_conn(); + + if(conn == NULL){ + return; + } + + status = mpd_run_status(conn); + + if(status == NULL){ + fprintf(stderr, "Could not get mpd status: %s\n", mpd_status_get_error(status)); + + mpd_status_free(status); + mpd_connection_free(conn); + return; + } + + state = mpd_status_get_state(status); + + if(state == MPD_STATE_STOP || state == MPD_STATE_PAUSE){ + mpd_run_play(conn); + mpd_status_free(status); + mpd_connection_free(conn); + } + else if(state != MPD_STATE_UNKNOWN){ //playing some music + song = mpd_run_current_song(conn); + + if(song == NULL){ + fprintf(stderr, "Error fetching current song!\n"); + + mpd_song_free(song); + mpd_status_free(status); + mpd_connection_free(conn); + return; + } + + filename = mpd_song_get_uri(song); + + int errcode = regcomp(&expr, "^[[:alnum:]]+://", REG_EXTENDED|REG_NOSUB); + if(errcode != 0){ + char *err = get_regerror(errcode, &expr); + fprintf(stderr, "Could not compile regexp: %s\n", err); + + mpd_song_free(song); + mpd_status_free(status); + mpd_connection_free(conn); + free(err); + regfree(&expr); + return; + } + + int matchcode = regexec(&expr, filename, 0, NULL, 0); + + if(matchcode == 0){ + if(strstr(filename, "file://") == filename){ //match just at the start of the filename + //this means that mpd is playing a file outside the music_dir, + //but on disk, so we can safely pause + mpd_run_toggle_pause(conn); + } + else{ + mpd_run_stop(conn); + } + } + else if(matchcode == REG_NOMATCH){ + mpd_run_toggle_pause(conn); + } + else{ + char *err = get_regerror(matchcode, &expr); + fprintf(stderr, "Error while matching regexp: %s\n", err); + + free(err); + } + + regfree(&expr); + mpd_song_free(song); + mpd_status_free(status); + mpd_connection_free(conn); + } +} \ No newline at end of file diff --git a/patch/mdpcontrol.h b/patch/mdpcontrol.h new file mode 100644 index 0000000..b8825d4 --- /dev/null +++ b/patch/mdpcontrol.h @@ -0,0 +1,2 @@ +static void mpdchange(const Arg *direction); +static void mpdcontrol(); \ No newline at end of file diff --git a/patches.h b/patches.h index 5d86161..62269e6 100644 --- a/patches.h +++ b/patches.h @@ -224,6 +224,14 @@ */ #define MAXIMIZE_PATCH 0 +/* Control Music Player Daemon via keybinds. + * This patch depends on an additional library lmdpclient so if you want to enable this + * then you will also have to append -lmpdclient to the LIBS configuration in config.mk. + * A placeholder has been added there for reference. + * https://dwm.suckless.org/patches/mpdcontrol/ + */ +#define MDPCONTROL_PATCH 0 + /* Adds rules per monitor, e.g. have default layouts per monitor. * The use case for this is if the second monitor is vertical (i.e. rotated) then * you may want to use a different default layout for this monitor than what is