Autodetect i3, and use IPC to switch to window.

This commit is contained in:
Qball Cow 2014-01-10 13:38:38 +01:00
parent b47f22ca51
commit e70ebf899c
3 changed files with 133 additions and 11 deletions

View File

@ -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:

View File

@ -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=<path> install` to install in a different prefix.

View File

@ -3,7 +3,7 @@
*
* MIT/X11 License
* Copyright (c) 2012 Sean Pringle <sean.pringle@gmail.com>
* Modified 2013 Qball Cow <qball@gmpclient.org>
* Modified 2013-2014 Qball Cow <qball@gmpclient.org>
*
* 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 <fcntl.h>
#include <err.h>
#include <X11/extensions/Xinerama.h>
#ifdef I3
#include <errno.h>
#include <linux/un.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <i3/ipc.h>
#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;
}