Skip to content
This repository has been archived by the owner on Apr 18, 2023. It is now read-only.

Commit

Permalink
Add initial version of i3-input, an interactive tool for sending IPC …
Browse files Browse the repository at this point in the history
…commands
  • Loading branch information
stapelberg committed Sep 20, 2009
1 parent 0e8b87e commit ca9b52b
Show file tree
Hide file tree
Showing 12 changed files with 22,046 additions and 1 deletion.
7 changes: 6 additions & 1 deletion Makefile
Expand Up @@ -19,6 +19,8 @@ all: src/cfgparse.y.o src/cfgparse.yy.o ${FILES}
echo ""
echo "SUBDIR i3-msg"
$(MAKE) TOPDIR=$(TOPDIR) -C i3-msg
echo "SUBDIR i3-input"
$(MAKE) TOPDIR=$(TOPDIR) -C i3-input

src/cfgparse.yy.o: src/cfgparse.l
echo "LEX $<"
Expand All @@ -39,13 +41,14 @@ install: all
test -e $(DESTDIR)/etc/i3/config || $(INSTALL) -m 0644 i3.config $(DESTDIR)/etc/i3/config
$(INSTALL) -m 0644 i3.desktop $(DESTDIR)/usr/share/xsessions/
$(MAKE) TOPDIR=$(TOPDIR) -C i3-msg install
$(MAKE) TOPDIR=$(TOPDIR) -C i3-input install

dist: distclean
[ ! -d i3-${VERSION} ] || rm -rf i3-${VERSION}
[ ! -e i3-${VERSION}.tar.bz2 ] || rm i3-${VERSION}.tar.bz2
mkdir i3-${VERSION}
cp DEPENDS GOALS LICENSE PACKAGE-MAINTAINER TODO RELEASE-NOTES-${VERSION} i3.config i3.desktop pseudo-doc.doxygen Makefile i3-${VERSION}
cp -r src i3-msg include man i3-${VERSION}
cp -r src i3-msg i3-input include man i3-${VERSION}
# Only copy toplevel documentation (important stuff)
mkdir i3-${VERSION}/docs
find docs -maxdepth 1 -type f ! -name "*.xcf" -exec cp '{}' i3-${VERSION}/docs \;
Expand All @@ -62,7 +65,9 @@ clean:
$(MAKE) -C docs clean
$(MAKE) -C man clean
$(MAKE) TOPDIR=$(TOPDIR) -C i3-msg clean
$(MAKE) TOPDIR=$(TOPDIR) -C i3-input clean

distclean: clean
rm -f i3
$(MAKE) TOPDIR=$(TOPDIR) -C i3-msg distclean
$(MAKE) TOPDIR=$(TOPDIR) -C i3-input distclean
28 changes: 28 additions & 0 deletions i3-input/Makefile
@@ -0,0 +1,28 @@
# Default value so one can compile i3-input standalone
TOPDIR=..

include $(TOPDIR)/common.mk

# Depend on the object files of all source-files in src/*.c and on all header files
FILES=$(patsubst %.c,%.o,$(wildcard *.c))
HEADERS=$(wildcard *.h)

# Depend on the specific file (.c for each .o) and on all headers
%.o: %.c ${HEADERS}
echo "CC $<"
$(CC) $(CFLAGS) -c -o $@ $<

all: ${FILES}
echo "LINK i3-input"
$(CC) -o i3-input ${FILES} $(LDFLAGS)

install: all
echo "INSTALL"
$(INSTALL) -d -m 0755 $(DESTDIR)/usr/bin
$(INSTALL) -m 0755 i3-input $(DESTDIR)/usr/bin/

clean:
rm -f *.o

distclean: clean
rm -f i3-input
19,336 changes: 19,336 additions & 0 deletions i3-input/UnicodeData.txt

Large diffs are not rendered by default.

178 changes: 178 additions & 0 deletions i3-input/convmap.pl
@@ -0,0 +1,178 @@
#!/usr/bin/perl
# Generate keysym2ucs.c file
#
# $XFree86: xc/programs/xterm/unicode/convmap.pl,v 1.5 2000/01/24 22:22:05 dawes Exp $

sub utf8 ($) {
my $c = shift(@_);

if ($c < 0x80) {
return sprintf("%c", $c);
} elsif ($c < 0x800) {
return sprintf("%c%c", 0xc0 | ($c >> 6), 0x80 | ($c & 0x3f));
} elsif ($c < 0x10000) {
return sprintf("%c%c%c",
0xe0 | ($c >> 12),
0x80 | (($c >> 6) & 0x3f),
0x80 | ( $c & 0x3f));
} elsif ($c < 0x200000) {
return sprintf("%c%c%c%c",
0xf0 | ($c >> 18),
0x80 | (($c >> 12) & 0x3f),
0x80 | (($c >> 6) & 0x3f),
0x80 | ( $c & 0x3f));
} elsif ($c < 0x4000000) {
return sprintf("%c%c%c%c%c",
0xf8 | ($c >> 24),
0x80 | (($c >> 18) & 0x3f),
0x80 | (($c >> 12) & 0x3f),
0x80 | (($c >> 6) & 0x3f),
0x80 | ( $c & 0x3f));

} elsif ($c < 0x80000000) {
return sprintf("%c%c%c%c%c%c",
0xfe | ($c >> 30),
0x80 | (($c >> 24) & 0x3f),
0x80 | (($c >> 18) & 0x3f),
0x80 | (($c >> 12) & 0x3f),
0x80 | (($c >> 6) & 0x3f),
0x80 | ( $c & 0x3f));
} else {
return utf8(0xfffd);
}
}

$unicodedata = "UnicodeData.txt";

# read list of all Unicode names
if (!open(UDATA, $unicodedata) && !open(UDATA, "$unicodedata")) {
die ("Can't open Unicode database '$unicodedata':\n$!\n\n" .
"Please make sure that you have downloaded the file\n" .
"ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData-Latest.txt\n");
}
while (<UDATA>) {
if (/^([0-9,A-F]{4});([^;]*);([^;]*);([^;]*);([^;]*);([^;]*);([^;]*);([^;]*);([^;]*);([^;]*);([^;]*);([^;]*);([^;]*);([^;]*);([^;]*)$/) {
$name{hex($1)} = $2;
} else {
next;
die("Syntax error in line '$_' in file '$unicodedata'");
}
}
close(UDATA);

# read mapping (from http://wsinwp07.win.tue.nl:1234/unicode/keysym.map)
open(LIST, "<keysym.map") || die ("Can't open map file:\n$!\n");
while (<LIST>) {
if (/^0x([0-9a-f]{4})\s+U([0-9a-f]{4})\s*(\#.*)?$/){
$keysym = hex($1);
$ucs = hex($2);
$keysym_to_ucs{$keysym} = $ucs;
} elsif (/^\s*\#/ || /^\s*$/) {
} else {
die("Syntax error in 'list' in line\n$_\n");
}
}
close(LIST);

# read entries in keysymdef.h
open(LIST, "</usr/include/X11/keysymdef.h") || die ("Can't open keysymdef.h:\n$!\n");
while (<LIST>) {
if (/^\#define\s+XK_([A-Za-z_0-9]+)\s+0x([0-9a-fA-F]+)\s*(\/.*)?$/) {
next if /\/\* deprecated \*\//;
$keysymname = $1;
$keysym = hex($2);
$keysym_to_keysymname{$keysym} = $keysymname;
}
}
close(LIST);

print <<EOT;
/* \$XFree86\$
* This module converts keysym values into the corresponding ISO 10646-1
* (UCS, Unicode) values.
*
* The array keysymtab[] contains pairs of X11 keysym values for graphical
* characters and the corresponding Unicode value. The function
* keysym2ucs() maps a keysym onto a Unicode value using a binary search,
* therefore keysymtab[] must remain SORTED by keysym value.
*
* The keysym -> UTF-8 conversion will hopefully one day be provided
* by Xlib via XmbLookupString() and should ideally not have to be
* done in X applications. But we are not there yet.
*
* We allow to represent any UCS character in the range U+00000000 to
* U+00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff.
* This admittedly does not cover the entire 31-bit space of UCS, but
* it does cover all of the characters up to U+10FFFF, which can be
* represented by UTF-16, and more, and it is very unlikely that higher
* UCS codes will ever be assigned by ISO. So to get Unicode character
* U+ABCD you can directly use keysym 0x1000abcd.
*
* NOTE: The comments in the table below contain the actual character
* encoded in UTF-8, so for viewing and editing best use an editor in
* UTF-8 mode.
*
* Author: Markus G. Kuhn <mkuhn\@acm.org>, University of Cambridge, June 1999
*
* Special thanks to Richard Verhoeven <river\@win.tue.nl> for preparing
* an initial draft of the mapping table.
*
* This software is in the public domain. Share and enjoy!
*/
#include <keysym2ucs.h>
struct codepair {
unsigned short keysym;
unsigned short ucs;
} keysymtab[] = {
EOT

for $keysym (sort {$a <=> $b} keys(%keysym_to_keysymname)) {
$ucs = $keysym_to_ucs{$keysym};
next if $keysym >= 0xf000 || $keysym < 0x100;
if ($ucs) {
printf(" { 0x%04x, 0x%04x }, /*%28s %s %s */\n",
$keysym, $ucs, $keysym_to_keysymname{$keysym}, utf8($ucs),
defined($name{$ucs}) ? $name{$ucs} : "???" );
} else {
printf("/* 0x%04x %39s ? ??? */\n",
$keysym, $keysym_to_keysymname{$keysym});
}
}

print <<EOT;
};
long keysym2ucs(KeySym keysym)
{
int min = 0;
int max = sizeof(keysymtab) / sizeof(struct codepair) - 1;
int mid;
/* first check for Latin-1 characters (1:1 mapping) */
if ((keysym >= 0x0020 && keysym <= 0x007e) ||
(keysym >= 0x00a0 && keysym <= 0x00ff))
return keysym;
/* also check for directly encoded 24-bit UCS characters */
if ((keysym & 0xff000000) == 0x01000000)
return keysym & 0x00ffffff;
/* binary search in table */
while (max >= min) {
mid = (min + max) / 2;
if (keysymtab[mid].keysym < keysym)
min = mid + 1;
else if (keysymtab[mid].keysym > keysym)
max = mid - 1;
else {
/* found it */
return keysymtab[mid].ucs;
}
}
/* no matching Unicode value found */
return -1;
}
EOT
18 changes: 18 additions & 0 deletions i3-input/i3-input.h
@@ -0,0 +1,18 @@
#ifndef _I3_INPUT
#define _I3_INPUT

#include <err.h>

#define die(...) errx(EXIT_FAILURE, __VA_ARGS__);

char *convert_ucs_to_utf8(char *input);
uint32_t get_colorpixel(xcb_connection_t *conn, char *hex);
uint32_t get_mode_switch_mask(xcb_connection_t *conn);
int connect_ipc(char *socket_path);
void ipc_send_message(int sockfd, uint32_t message_size,
uint32_t message_type, uint8_t *payload);
xcb_window_t open_input_window(xcb_connection_t *conn, uint32_t width, uint32_t height);
int get_font_id(xcb_connection_t *conn, char *pattern, int *font_height);
void xcb_change_gc_single(xcb_connection_t *conn, xcb_gcontext_t gc, uint32_t mask, uint32_t value);

#endif
68 changes: 68 additions & 0 deletions i3-input/ipc.c
@@ -0,0 +1,68 @@
/*
* vim:ts=8:expandtab
*
* i3 - an improved dynamic tiling window manager
*
* © 2009 Michael Stapelberg and contributors
*
* See file LICENSE for license information.
*
*/
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <err.h>

/*
* Formats a message (payload) of the given size and type and sends it to i3 via
* the given socket file descriptor.
*
*/
void ipc_send_message(int sockfd, uint32_t message_size,
uint32_t message_type, uint8_t *payload) {
int buffer_size = strlen("i3-ipc") + sizeof(uint32_t) + sizeof(uint32_t) + message_size;
char msg[buffer_size];
char *walk = msg;

strcpy(walk, "i3-ipc");
walk += strlen("i3-ipc");
memcpy(walk, &message_size, sizeof(uint32_t));
walk += sizeof(uint32_t);
memcpy(walk, &message_type, sizeof(uint32_t));
walk += sizeof(uint32_t);
memcpy(walk, payload, message_size);

int sent_bytes = 0;
int bytes_to_go = buffer_size;
while (sent_bytes < bytes_to_go) {
int n = write(sockfd, msg + sent_bytes, bytes_to_go);
if (n == -1)
err(EXIT_FAILURE, "write() failed");

sent_bytes += n;
bytes_to_go -= n;
}
}

/*
* Connects to the i3 IPC socket and returns the file descriptor for the
* socket. die()s if anything goes wrong.
*
*/
int connect_ipc(char *socket_path) {
int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);
if (sockfd == -1)
err(EXIT_FAILURE, "Could not create socket");

struct sockaddr_un addr;
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_LOCAL;
strcpy(addr.sun_path, socket_path);
if (connect(sockfd, (const struct sockaddr*)&addr, sizeof(struct sockaddr_un)) < 0)
err(EXIT_FAILURE, "Could not connect to i3");

return sockfd;
}

0 comments on commit ca9b52b

Please sign in to comment.