From e70ebf899c05b418c0497427fcec6c9b15673ae7 Mon Sep 17 00:00:00 2001 From: Qball Cow Date: Fri, 10 Jan 2014 13:38:38 +0100 Subject: [PATCH] Autodetect i3, and use IPC to switch to window. --- Makefile | 6 +++ README.md | 19 ++++++-- simpleswitcher.c | 119 +++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 133 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 372a96ea..e992b783 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,12 @@ ifeq (${LDADD},${EMPTY}) $(error Failed to find the required dependencies: x11, xinerama, xft) endif +I3?=$(shell which i3) +ifneq (${I3},${EMPTY}) +$(info I3 mode is enabled) +CFLAGS+=-DI3 +endif + all: normal normal: diff --git a/README.md b/README.md index 53293aee..cc194e5b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # simpleswitcher A popup window switcher roughly based on [superswitcher](http://code.google.com/p/superswitcher/), requiring only xlib and xft. +This version is based on the version from [Sean +Pringle](http://github.com/seanpringle/simpleswitcher). All credit for this great tool should to to him. * Switcher centered on screen (or monitor for multi-head). @@ -16,10 +18,21 @@ A popup window switcher roughly based on [superswitcher](http://code.google.com/ * Runs in background or once-off. -Hackish support for the I3 window manager: +If compiled with I3 support, it should autodetect if I3 window manager is running. - For i3, run with -i3 +Usage +----- e.g. - bindsym $mod+Tab exec simpleswitcher -i3 -now -font "snap-10" -fg "#505050" -bg "#000000" -hlfg "#ffb964" -hlbg "#000000" -o 85 + bindsym $mod+Tab exec simpleswitcher -now -font "snap-10" -fg "#505050" -bg "#000000" -hlfg "#ffb964" -hlbg "#000000" -o 85 + + +Compilation +----------- + +Type `make I3=` to disable compiling with i3 support. +If during compilation it complains about not finding i3/ipc.h either disable i3 support +or install the headers. + +Type `make PREFIX= install` to install in a different prefix. diff --git a/simpleswitcher.c b/simpleswitcher.c index b93b192e..81c38deb 100644 --- a/simpleswitcher.c +++ b/simpleswitcher.c @@ -3,7 +3,7 @@ * * MIT/X11 License * Copyright (c) 2012 Sean Pringle - * Modified 2013 Qball Cow + * Modified 2013-2014 Qball Cow * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -48,6 +48,14 @@ #include #include #include +#ifdef I3 +#include +#include +#include +#include +#include +#endif + #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) @@ -57,6 +65,7 @@ #define OPAQUE 0xffffffff #define OPACITY "_NET_WM_WINDOW_OPACITY" +#define I3_SOCKET_PATH_PROP "I3_SOCKET_PATH" static void* allocate( unsigned long bytes ) { @@ -125,6 +134,67 @@ static inline void tokenize_free( char **ip ) free( ip ); } +#ifdef I3 +// Path to I3 socket. +char *i3_socket_path = NULL; +// Focus window on I3 window manager. +static void focus_window_i3( const char *socket_path, int id ) +{ + int s, t, len; + struct sockaddr_un remote; + + if ( strlen( socket_path ) > UNIX_PATH_MAX ) { + fprintf( stderr, "Socket path is to long. %ld > %d\n", strlen( socket_path ), UNIX_PATH_MAX ); + return; + } + + if ( ( s = socket( AF_UNIX, SOCK_STREAM, 0 ) ) == -1 ) { + fprintf( stderr, "Failed to open connection to I3: %s\n", strerror( errno ) ); + return; + } + + remote.sun_family = AF_UNIX; + strcpy( remote.sun_path, socket_path ); + len = strlen( remote.sun_path ) + sizeof( remote.sun_family ); + + if ( connect( s, ( struct sockaddr * )&remote, len ) == -1 ) { + fprintf( stderr, "Failed to connect to I3 (%s): %s\n", socket_path,strerror( errno ) ); + close( s ); + return ; + } + + + // Formulate command + { + i3_ipc_header_t head; + char command[128]; + snprintf( command, 128, "[id=\"%d\"] focus", id ); + // Prepare header. + memcpy( head.magic, I3_IPC_MAGIC, 6 ); + head.size = strlen( command ); + head.type = I3_IPC_MESSAGE_TYPE_COMMAND; + // Send header. + send( s, &head, sizeof( head ),0 ); + // Send message + send( s, command, strlen( command ),0 ); + } + { + i3_ipc_header_t head; + char reply[128]; + // Receive header. + t = recv( s, &head, sizeof( head ),0 ); + + if ( t == sizeof( head ) ) { + t= recv( s, reply, head.size, 0 ); + reply[t] = '\0'; + printf( "%s\n", reply ); + } + } + + close( s ); +} +#endif + void catch_exit( __attribute__( ( unused ) ) int sig ) { while ( 0 < waitpid( -1, NULL, WNOHANG ) ); @@ -368,7 +438,9 @@ unsigned int config_window_placement; unsigned int config_menu_bw; unsigned int config_window_opacity; unsigned int config_zeltak_mode; -unsigned int config_i3_mode; +#ifdef I3 +int config_i3_mode = 0; +#endif // allocate a pixel value for an X named color static unsigned int color_get( const char *const name ) @@ -950,10 +1022,13 @@ void run_switcher( int fmode ) && !client_has_state( c, netatoms[_NET_WM_STATE_SKIP_PAGER] ) && !client_has_state( c, netatoms[_NET_WM_STATE_SKIP_TASKBAR] ) ) { classfield = MAX( classfield, strlen( c->class ) ); +#ifdef I3 // In i3 mode, skip the i3bar completely. if ( config_i3_mode && strstr( c->class, "i3bar" ) != NULL ) continue; +#endif + winlist_append( ids, c->window, NULL ); } } @@ -982,13 +1057,14 @@ void run_switcher( int fmode ) int n = menu( list, &input, "> ", 1, &time ); if ( n >= 0 && list[n] ) { +#ifdef I3 + if ( config_i3_mode ) { // Hack for i3. - char array[128]; - snprintf( array,128,"i3-msg [id=\"%d\"] focus",( int )( ids->array[n] ) ); - printf( "Executing: %s\n", array ); - exec_cmd( array ); - } else { + focus_window_i3( i3_socket_path,ids->array[n] ); + } else +#endif + { if ( isdigit( list[n][0] ) ) { // TODO: get rid of strtol window_send_message( root, root, netatoms[_NET_CURRENT_DESKTOP], strtol( list[n], NULL, 10 )-1, @@ -1142,11 +1218,33 @@ int main( int argc, char *argv[] ) config_window_opacity = find_arg_int( ac, av, "-o", 100 ); config_zeltak_mode = ( find_arg( ac, av, "-zeltak" ) >= 0 ); - config_i3_mode = ( find_arg( ac, av, "-i3" ) >= 0 ); + +#ifdef I3 + // Check for i3 + { + config_i3_mode = 0; + Atom atom = XInternAtom( display, I3_SOCKET_PATH_PROP,True ); + + if ( atom != None ) { + i3_socket_path = window_get_text_prop( root, atom ); + + if ( i3_socket_path != NULL ) { + printf( "Auto detected I3 running, switching to I3 mode: %s\n", + i3_socket_path ); + config_i3_mode = 1; + } + } + } +#endif // flags to run immediately and exit if ( find_arg( ac, av, "-now" ) >= 0 ) { run_switcher( NOFORK ); +#ifdef I3 + + if ( i3_socket_path != NULL ) free( i3_socket_path ); + +#endif exit( EXIT_SUCCESS ); } @@ -1174,5 +1272,10 @@ int main( int argc, char *argv[] ) if ( ev.type == KeyPress ) handle_keypress( &ev ); } +#ifdef I3 + + if ( i3_socket_path != NULL ) free( i3_socket_path ); + +#endif return EXIT_SUCCESS; }