rofi/source/i3-support.c

147 lines
4.3 KiB
C

/**
* rofi
*
* MIT/X11 License
* Copyright (c) 2013-2016 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
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <xcb/xcb.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "xcb.h"
#include "rofi.h"
#include "x11-helper.h"
#include "i3-support.h"
#include "view.h"
#ifdef HAVE_I3_IPC_H
#include <i3/ipc.h>
// Path to HAVE_I3_IPC_H socket.
char *i3_socket_path = NULL;
void i3_support_focus_window ( xcb_window_t id )
{
i3_ipc_header_t head;
int s;
ssize_t t;
struct sockaddr_un remote;
size_t upm = sizeof ( remote.sun_path );
char command[upm];
if ( strlen ( i3_socket_path ) > upm ) {
fprintf ( stderr, "Socket path is too long. %zu > %zu\n", strlen ( i3_socket_path ), upm );
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;
g_strlcpy ( remote.sun_path, i3_socket_path, upm );
if ( connect ( s, ( struct sockaddr * ) &remote, sizeof ( struct sockaddr_un ) ) == -1 ) {
fprintf ( stderr, "Failed to connect to I3 (%s): %s\n", i3_socket_path, strerror ( errno ) );
close ( s );
return;
}
// Formulate command
snprintf ( command, upm, "[id=\"%u\"] focus", id );
// Prepare header.
memcpy ( head.magic, I3_IPC_MAGIC, 6 );
head.size = strlen ( command );
head.type = I3_IPC_MESSAGE_TYPE_COMMAND;
// Send header.
t = send ( s, &head, sizeof ( i3_ipc_header_t ), 0 );
if ( t == -1 ) {
char *msg = g_strdup_printf ( "Failed to send message header to i3: %s\n", strerror ( errno ) );
rofi_view_error_dialog ( msg, FALSE );
g_free ( msg );
close ( s );
return;
}
// Send message
t = send ( s, command, strlen ( command ), 0 );
if ( t == -1 ) {
char *msg = g_strdup_printf ( "Failed to send message body to i3: %s\n", strerror ( errno ) );
rofi_view_error_dialog ( msg, FALSE );
g_free ( msg );
close ( s );
return;
}
// Receive header.
t = recv ( s, &head, sizeof ( head ), 0 );
if ( t == sizeof ( head ) ) {
t = recv ( s, command, head.size, 0 );
if ( t == head.size ) {
// Response.
}
}
close ( s );
}
int i3_support_initialize ( xcb_stuff *xcb )
{
// If we where initialized, clean this first.
i3_support_free_internals ();
// Get atom for I3_SOCKET_PATH
i3_socket_path = window_get_text_prop ( xcb_stuff_get_root_window ( xcb ), netatoms[I3_SOCKET_PATH] );
// If we find it, go into i3 mode.
return ( i3_socket_path != NULL ) ? TRUE : FALSE;
}
void i3_support_free_internals ( void )
{
g_free ( i3_socket_path );
i3_socket_path = NULL;
}
#else
void i3_support_focus_window ( G_GNUC_UNUSED xcb_window_t id )
{
fprintf ( stderr, "Trying to control i3, when i3 support is not enabled.\n" );
abort ();
}
void i3_support_free_internals ( void )
{
}
int i3_support_initialize ( G_GNUC_UNUSED xcb_stuff *xcb )
{
return FALSE;
}
#endif // HAVE_I3_IPC_H